From e5fd91f1ef340da553f7a79da9540c3db711c937 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Tue, 8 Sep 2015 01:01:14 -0300 Subject: Linux-libre 4.2-gnu --- drivers/s390/block/dasd.c | 53 +++++++++++++++++++++++++++++++++++------ drivers/s390/block/dasd_alias.c | 3 ++- drivers/s390/block/dasd_genhd.c | 19 ++++----------- 3 files changed, 53 insertions(+), 22 deletions(-) (limited to 'drivers/s390/block') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 57fd66357..f73d2f579 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -38,6 +38,8 @@ */ #define DASD_CHANQ_MAX_SIZE 4 +#define DASD_DIAG_MOD "dasd_diag_mod" + /* * SECTION: exported variables of dasd.c */ @@ -1860,6 +1862,33 @@ static void __dasd_device_check_expire(struct dasd_device *device) } } +/* + * return 1 when device is not eligible for IO + */ +static int __dasd_device_is_unusable(struct dasd_device *device, + struct dasd_ccw_req *cqr) +{ + int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM); + + if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) { + /* dasd is being set offline. */ + return 1; + } + if (device->stopped) { + if (device->stopped & mask) { + /* stopped and CQR will not change that. */ + return 1; + } + if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) { + /* CQR is not able to change device to + * operational. */ + return 1; + } + /* CQR required to get device operational. */ + } + return 0; +} + /* * Take a look at the first request on the ccw queue and check * if it needs to be started. @@ -1874,13 +1903,8 @@ static void __dasd_device_start_head(struct dasd_device *device) cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); if (cqr->status != DASD_CQR_QUEUED) return; - /* when device is stopped, return request to previous layer - * exception: only the disconnect or unresumed bits are set and the - * cqr is a path verification request - */ - if (device->stopped && - !(!(device->stopped & ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM)) - && test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))) { + /* if device is not usable return request to upper layer */ + if (__dasd_device_is_unusable(device, cqr)) { cqr->intrc = -EAGAIN; cqr->status = DASD_CQR_CLEARED; dasd_schedule_device_bh(device); @@ -3300,6 +3324,21 @@ int dasd_generic_set_online(struct ccw_device *cdev, discipline = base_discipline; if (device->features & DASD_FEATURE_USEDIAG) { if (!dasd_diag_discipline_pointer) { + /* Try to load the required module. */ + rc = request_module(DASD_DIAG_MOD); + if (rc) { + pr_warn("%s Setting the DASD online failed " + "because the required module %s " + "could not be loaded (rc=%d)\n", + dev_name(&cdev->dev), DASD_DIAG_MOD, + rc); + dasd_delete_device(device); + return -ENODEV; + } + } + /* Module init could have failed, so check again here after + * request_module(). */ + if (!dasd_diag_discipline_pointer) { pr_warn("%s Setting the DASD online failed because of missing DIAG discipline\n", dev_name(&cdev->dev)); dasd_delete_device(device); diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index a2597e683..ee3a6faae 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -699,7 +699,8 @@ struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device) struct dasd_device, alias_list); spin_unlock_irqrestore(&lcu->lock, flags); alias_priv = (struct dasd_eckd_private *) alias_device->private; - if ((alias_priv->count < private->count) && !alias_device->stopped) + if ((alias_priv->count < private->count) && !alias_device->stopped && + !test_bit(DASD_FLAG_OFFLINE, &alias_device->flags)) return alias_device; else return NULL; diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 90f39f79f..ef1d9fb06 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -99,9 +99,8 @@ void dasd_gendisk_free(struct dasd_block *block) int dasd_scan_partitions(struct dasd_block *block) { struct block_device *bdev; - int retry, rc; + int rc; - retry = 5; bdev = bdget_disk(block->gdp, 0); if (!bdev) { DBF_DEV_EVENT(DBF_ERR, block->base, "%s", @@ -116,19 +115,11 @@ int dasd_scan_partitions(struct dasd_block *block) rc); return -ENODEV; } - /* - * See fs/partition/check.c:register_disk,rescan_partitions - * Can't call rescan_partitions directly. Use ioctl. - */ - rc = ioctl_by_bdev(bdev, BLKRRPART, 0); - while (rc == -EBUSY && retry > 0) { - schedule(); - rc = ioctl_by_bdev(bdev, BLKRRPART, 0); - retry--; + + rc = blkdev_reread_part(bdev); + if (rc) DBF_DEV_EVENT(DBF_ERR, block->base, - "scan partitions error, retry %d rc %d", - retry, rc); - } + "scan partitions error, rc %d", rc); /* * Since the matching blkdev_put call to the blkdev_get in -- cgit v1.2.3-54-g00ecf