diff options
author | Stefan Haberland <stefan.haberland@de.ibm.com> | 2014-07-18 14:26:01 +0200 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-07-22 09:26:23 +0200 |
commit | 29b8dd9d4274bca6526e4bb8d4f46dec1f4c15c9 (patch) | |
tree | 631cb92a24223b571ea534f28ea7ec0a2950480b /drivers/s390/block/dasd_eckd.c | |
parent | dasd: fix list_del corruption during format (diff) | |
download | linux-29b8dd9d4274bca6526e4bb8d4f46dec1f4c15c9.tar.xz linux-29b8dd9d4274bca6526e4bb8d4f46dec1f4c15c9.zip |
dasd: fix error recovery for alias devices during format
Kernel panic or a hanging device during format if an alias device is
set offline or I/O errors occur.
Omit the error recovery procedure for alias devices and do retries on
the base device with full erp.
Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 39748fda6e1f..e74e5f7b431d 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2061,11 +2061,12 @@ dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo) static struct dasd_ccw_req * dasd_eckd_build_format(struct dasd_device *base, - struct format_data_t *fdata) + struct format_data_t *fdata, + int enable_PAV) { struct dasd_eckd_private *base_priv; struct dasd_eckd_private *start_priv; - struct dasd_device *startdev; + struct dasd_device *startdev = NULL; struct dasd_ccw_req *fcp; struct eckd_count *ect; struct ch_t address; @@ -2079,7 +2080,9 @@ dasd_eckd_build_format(struct dasd_device *base, int nr_tracks; int use_prefix; - startdev = dasd_alias_get_start_dev(base); + if (enable_PAV) + startdev = dasd_alias_get_start_dev(base); + if (!startdev) startdev = base; @@ -2309,6 +2312,7 @@ dasd_eckd_build_format(struct dasd_device *base, fcp->startdev = startdev; fcp->memdev = startdev; + fcp->basedev = base; fcp->retries = 256; fcp->expires = startdev->default_expires * HZ; fcp->buildclk = get_tod_clock(); @@ -2319,7 +2323,8 @@ dasd_eckd_build_format(struct dasd_device *base, static int dasd_eckd_format_device(struct dasd_device *base, - struct format_data_t *fdata) + struct format_data_t *fdata, + int enable_PAV) { struct dasd_ccw_req *cqr, *n; struct dasd_block *block; @@ -2327,7 +2332,7 @@ dasd_eckd_format_device(struct dasd_device *base, struct list_head format_queue; struct dasd_device *device; int old_stop, format_step; - int step, rc = 0; + int step, rc = 0, sleep_rc; block = base->block; private = (struct dasd_eckd_private *) base->private; @@ -2361,11 +2366,11 @@ dasd_eckd_format_device(struct dasd_device *base, } INIT_LIST_HEAD(&format_queue); - old_stop = fdata->stop_unit; + old_stop = fdata->stop_unit; while (fdata->start_unit <= 1) { fdata->stop_unit = fdata->start_unit; - cqr = dasd_eckd_build_format(base, fdata); + cqr = dasd_eckd_build_format(base, fdata, enable_PAV); list_add(&cqr->blocklist, &format_queue); fdata->stop_unit = old_stop; @@ -2383,7 +2388,7 @@ retry: if (step > format_step) fdata->stop_unit = fdata->start_unit + format_step - 1; - cqr = dasd_eckd_build_format(base, fdata); + cqr = dasd_eckd_build_format(base, fdata, enable_PAV); if (IS_ERR(cqr)) { if (PTR_ERR(cqr) == -ENOMEM) { /* @@ -2403,7 +2408,7 @@ retry: } sleep: - dasd_sleep_on_queue(&format_queue); + sleep_rc = dasd_sleep_on_queue(&format_queue); list_for_each_entry_safe(cqr, n, &format_queue, blocklist) { device = cqr->startdev; @@ -2415,6 +2420,9 @@ sleep: private->count--; } + if (sleep_rc) + return sleep_rc; + /* * in case of ENOMEM we need to retry after * first requests are finished |