Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 151101
b: refs/heads/master
c: d41dd12
h: refs/heads/master
i:
  151099: 4ff4abf
v: v3
  • Loading branch information
Stefan Haberland authored and Martin Schwidefsky committed Jun 16, 2009
1 parent 551216f commit 85dad44
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 20 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ad285ae9fc6b9c0058f2a558b43fe8817685ebfa
refs/heads/master: d41dd122acf960db78c9ddc87684b43751dd36d9
109 changes: 107 additions & 2 deletions trunk/drivers/s390/block/dasd.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
* Carsten Otte <Cotte@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
* Copyright IBM Corp. 1999, 2009
*/

#define KMSG_COMPONENT "dasd"
Expand Down Expand Up @@ -61,6 +60,7 @@ static int dasd_flush_block_queue(struct dasd_block *);
static void dasd_device_tasklet(struct dasd_device *);
static void dasd_block_tasklet(struct dasd_block *);
static void do_kick_device(struct work_struct *);
static void do_restore_device(struct work_struct *);
static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
static void dasd_device_timeout(unsigned long);
static void dasd_block_timeout(unsigned long);
Expand Down Expand Up @@ -109,6 +109,7 @@ struct dasd_device *dasd_alloc_device(void)
device->timer.function = dasd_device_timeout;
device->timer.data = (unsigned long) device;
INIT_WORK(&device->kick_work, do_kick_device);
INIT_WORK(&device->restore_device, do_restore_device);
device->state = DASD_STATE_NEW;
device->target = DASD_STATE_NEW;

Expand Down Expand Up @@ -511,6 +512,25 @@ void dasd_kick_device(struct dasd_device *device)
schedule_work(&device->kick_work);
}

/*
* dasd_restore_device will schedule a call do do_restore_device to the kernel
* event daemon.
*/
static void do_restore_device(struct work_struct *work)
{
struct dasd_device *device = container_of(work, struct dasd_device,
restore_device);
device->cdev->drv->restore(device->cdev);
dasd_put_device(device);
}

void dasd_restore_device(struct dasd_device *device)
{
dasd_get_device(device);
/* queue call to dasd_restore_device to the kernel event daemon. */
schedule_work(&device->restore_device);
}

/*
* Set the target state for a device and starts the state change.
*/
Expand Down Expand Up @@ -908,6 +928,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
"start_IO: -EIO device gone, retry");
break;
case -EINVAL:
/* most likely caused in power management context */
DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
"start_IO: -EINVAL device currently "
"not accessible");
break;
default:
/* internal error 11 - unknown rc */
snprintf(errorstring, ERRORLENGTH, "11 %d", rc);
Expand Down Expand Up @@ -2400,6 +2426,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
case CIO_OPER:
/* FIXME: add a sanity check. */
device->stopped &= ~DASD_STOPPED_DC_WAIT;
if (device->stopped & DASD_UNRESUMED_PM) {
device->stopped &= ~DASD_UNRESUMED_PM;
dasd_restore_device(device);
ret = 1;
break;
}
dasd_schedule_device_bh(device);
if (device->block)
dasd_schedule_block_bh(device->block);
Expand All @@ -2410,6 +2442,79 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
return ret;
}

int dasd_generic_pm_freeze(struct ccw_device *cdev)
{
struct dasd_ccw_req *cqr, *n;
int rc;
struct list_head freeze_queue;
struct dasd_device *device = dasd_device_from_cdev(cdev);

if (IS_ERR(device))
return PTR_ERR(device);
/* disallow new I/O */
device->stopped |= DASD_STOPPED_PM;
/* clear active requests */
INIT_LIST_HEAD(&freeze_queue);
spin_lock_irq(get_ccwdev_lock(cdev));
rc = 0;
list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
/* Check status and move request to flush_queue */
if (cqr->status == DASD_CQR_IN_IO) {
rc = device->discipline->term_IO(cqr);
if (rc) {
/* unable to terminate requeust */
dev_err(&device->cdev->dev,
"Unable to terminate request %p "
"on suspend\n", cqr);
spin_unlock_irq(get_ccwdev_lock(cdev));
dasd_put_device(device);
return rc;
}
}
list_move_tail(&cqr->devlist, &freeze_queue);
}

spin_unlock_irq(get_ccwdev_lock(cdev));

list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) {
wait_event(dasd_flush_wq,
(cqr->status != DASD_CQR_CLEAR_PENDING));
if (cqr->status == DASD_CQR_CLEARED)
cqr->status = DASD_CQR_QUEUED;
}
/* move freeze_queue to start of the ccw_queue */
spin_lock_irq(get_ccwdev_lock(cdev));
list_splice_tail(&freeze_queue, &device->ccw_queue);
spin_unlock_irq(get_ccwdev_lock(cdev));

if (device->discipline->freeze)
rc = device->discipline->freeze(device);

dasd_put_device(device);
return rc;
}
EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze);

int dasd_generic_restore_device(struct ccw_device *cdev)
{
struct dasd_device *device = dasd_device_from_cdev(cdev);
int rc = 0;

if (IS_ERR(device))
return PTR_ERR(device);

dasd_schedule_device_bh(device);
if (device->block)
dasd_schedule_block_bh(device->block);

if (device->discipline->restore)
rc = device->discipline->restore(device);

dasd_put_device(device);
return rc;
}
EXPORT_SYMBOL_GPL(dasd_generic_restore_device);

static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
void *rdc_buffer,
int rdc_buffer_size,
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/s390/block/dasd_devmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
spin_unlock(&dasd_devmap_lock);
return 0;
}
EXPORT_SYMBOL_GPL(dasd_get_uid);

/*
* Register the given device unique identifier into devmap struct.
Expand Down
108 changes: 95 additions & 13 deletions trunk/drivers/s390/block/dasd_eckd.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
* Carsten Otte <Cotte@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* Copyright IBM Corp. 1999, 2009
* EMC Symmetrix ioctl Copyright EMC Corporation, 2008
* Author.........: Nigel Hislop <hislop_nigel@emc.com>
*
*/

#define KMSG_COMPONENT "dasd"
Expand Down Expand Up @@ -104,17 +103,6 @@ dasd_eckd_set_online(struct ccw_device *cdev)
return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
}

static struct ccw_driver dasd_eckd_driver = {
.name = "dasd-eckd",
.owner = THIS_MODULE,
.ids = dasd_eckd_ids,
.probe = dasd_eckd_probe,
.remove = dasd_generic_remove,
.set_offline = dasd_generic_set_offline,
.set_online = dasd_eckd_set_online,
.notify = dasd_generic_notify,
};

static const int sizes_trk0[] = { 28, 148, 84 };
#define LABEL_SIZE 140

Expand Down Expand Up @@ -3236,6 +3224,98 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
dasd_eckd_dump_sense_ccw(device, req, irb);
}

int dasd_eckd_pm_freeze(struct dasd_device *device)
{
/*
* the device should be disconnected from our LCU structure
* on restore we will reconnect it and reread LCU specific
* information like PAV support that might have changed
*/
dasd_alias_remove_device(device);
dasd_alias_disconnect_device_from_lcu(device);

return 0;
}

int dasd_eckd_restore_device(struct dasd_device *device)
{
struct dasd_eckd_private *private;
int is_known, rc;
struct dasd_uid temp_uid;

/* allow new IO again */
device->stopped &= ~DASD_STOPPED_PM;

private = (struct dasd_eckd_private *) device->private;

/* Read Configuration Data */
rc = dasd_eckd_read_conf(device);
if (rc)
goto out_err;

/* Generate device unique id and register in devmap */
rc = dasd_eckd_generate_uid(device, &private->uid);
dasd_get_uid(device->cdev, &temp_uid);
if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0)
dev_err(&device->cdev->dev, "The UID of the DASD has changed\n");
if (rc)
goto out_err;
dasd_set_uid(device->cdev, &private->uid);

/* register lcu with alias handling, enable PAV if this is a new lcu */
is_known = dasd_alias_make_device_known_to_lcu(device);
if (is_known < 0)
return is_known;
if (!is_known) {
/* new lcu found */
rc = dasd_eckd_validate_server(device); /* will switch pav on */
if (rc)
goto out_err;
}

/* Read Feature Codes */
rc = dasd_eckd_read_features(device);
if (rc)
goto out_err;

/* Read Device Characteristics */
memset(&private->rdc_data, 0, sizeof(private->rdc_data));
rc = dasd_generic_read_dev_chars(device, "ECKD",
&private->rdc_data, 64);
if (rc) {
DBF_EVENT(DBF_WARNING,
"Read device characteristics failed, rc=%d for "
"device: %s", rc, dev_name(&device->cdev->dev));
goto out_err;
}

/* add device to alias management */
dasd_alias_add_device(device);

return 0;

out_err:
/*
* if the resume failed for the DASD we put it in
* an UNRESUMED stop state
*/
device->stopped |= DASD_UNRESUMED_PM;
return 0;
}

static struct ccw_driver dasd_eckd_driver = {
.name = "dasd-eckd",
.owner = THIS_MODULE,
.ids = dasd_eckd_ids,
.probe = dasd_eckd_probe,
.remove = dasd_generic_remove,
.set_offline = dasd_generic_set_offline,
.set_online = dasd_eckd_set_online,
.notify = dasd_generic_notify,
.freeze = dasd_generic_pm_freeze,
.thaw = dasd_generic_restore_device,
.restore = dasd_generic_restore_device,
};

/*
* max_blocks is dependent on the amount of storage that is available
Expand Down Expand Up @@ -3274,6 +3354,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
.dump_sense_dbf = dasd_eckd_dump_sense_dbf,
.fill_info = dasd_eckd_fill_info,
.ioctl = dasd_eckd_ioctl,
.freeze = dasd_eckd_pm_freeze,
.restore = dasd_eckd_restore_device,
};

static int __init
Expand Down
6 changes: 4 additions & 2 deletions trunk/drivers/s390/block/dasd_fba.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
* File...........: linux/drivers/s390/block/dasd_fba.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
* Copyright IBM Corp. 1999, 2009
*/

#define KMSG_COMPONENT "dasd"
Expand Down Expand Up @@ -75,6 +74,9 @@ static struct ccw_driver dasd_fba_driver = {
.set_offline = dasd_generic_set_offline,
.set_online = dasd_fba_set_online,
.notify = dasd_generic_notify,
.freeze = dasd_generic_pm_freeze,
.thaw = dasd_generic_restore_device,
.restore = dasd_generic_restore_device,
};

static void
Expand Down
13 changes: 11 additions & 2 deletions trunk/drivers/s390/block/dasd_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
* Horst Hummel <Horst.Hummel@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
* Copyright IBM Corp. 1999, 2009
*/

#ifndef DASD_INT_H
Expand Down Expand Up @@ -295,6 +294,10 @@ struct dasd_discipline {
int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
int (*ioctl) (struct dasd_block *, unsigned int, void __user *);

/* suspend/resume functions */
int (*freeze) (struct dasd_device *);
int (*restore) (struct dasd_device *);
};

extern struct dasd_discipline *dasd_diag_discipline_pointer;
Expand Down Expand Up @@ -367,6 +370,7 @@ struct dasd_device {
atomic_t tasklet_scheduled;
struct tasklet_struct tasklet;
struct work_struct kick_work;
struct work_struct restore_device;
struct timer_list timer;

debug_info_t *debug_area;
Expand Down Expand Up @@ -410,6 +414,8 @@ struct dasd_block {
#define DASD_STOPPED_PENDING 4 /* long busy */
#define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */
#define DASD_STOPPED_SU 16 /* summary unit check handling */
#define DASD_STOPPED_PM 32 /* pm state transition */
#define DASD_UNRESUMED_PM 64 /* pm resume failed state */

/* per device flags */
#define DASD_FLAG_OFFLINE 3 /* device is in offline processing */
Expand Down Expand Up @@ -556,6 +562,7 @@ void dasd_free_block(struct dasd_block *);
void dasd_enable_device(struct dasd_device *);
void dasd_set_target_state(struct dasd_device *, int);
void dasd_kick_device(struct dasd_device *);
void dasd_restore_device(struct dasd_device *);

void dasd_add_request_head(struct dasd_ccw_req *);
void dasd_add_request_tail(struct dasd_ccw_req *);
Expand All @@ -578,6 +585,8 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int);
void dasd_generic_handle_state_change(struct dasd_device *);
int dasd_generic_pm_freeze(struct ccw_device *);
int dasd_generic_restore_device(struct ccw_device *);

int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int);
char *dasd_get_sense(struct irb *);
Expand Down

0 comments on commit 85dad44

Please sign in to comment.