aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_3990_erp.c
diff options
context:
space:
mode:
authorStefan Weinhuber <wein@de.ibm.com>2009-12-07 06:51:51 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2009-12-07 06:51:34 -0500
commiteb6e199bef288611157b8198c25d12b32bf058d0 (patch)
tree80737a2703a9f4d09cee2410342aeccb281413ae /drivers/s390/block/dasd_3990_erp.c
parent626350b63ef2cd447023d3dc2a34eaa7ca01bfff (diff)
[S390] dasd: improve error recovery for internal I/O
Most of the error conditions reported by a FICON storage server indicate situations which can be recovered. Sometimes the host just needs to retry an I/O request, but sometimes the recovery is more complex and requires the device driver to wait, choose a different path, etc. The DASD device driver has a fully featured error recovery for normal block layer I/O, but not for internal I/O request which are for example used during the device bring up. This can lead to situations where the IPL of a system fails because DASD devices are not properly recognized. This patch will extend the internal I/O handling to use the existing error recovery procedures. Signed-off-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block/dasd_3990_erp.c')
-rw-r--r--drivers/s390/block/dasd_3990_erp.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 316eb1256a99..44796ba4eb9b 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -69,8 +69,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
69 * processing until the started timer has expired or an related 69 * processing until the started timer has expired or an related
70 * interrupt was received. 70 * interrupt was received.
71 */ 71 */
72static void 72static void dasd_3990_erp_block_queue(struct dasd_ccw_req *erp, int expires)
73dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
74{ 73{
75 74
76 struct dasd_device *device = erp->startdev; 75 struct dasd_device *device = erp->startdev;
@@ -80,10 +79,13 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
80 "blocking request queue for %is", expires/HZ); 79 "blocking request queue for %is", expires/HZ);
81 80
82 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); 81 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
83 device->stopped |= DASD_STOPPED_PENDING; 82 dasd_device_set_stop_bits(device, DASD_STOPPED_PENDING);
84 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); 83 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
85 erp->status = DASD_CQR_FILLED; 84 erp->status = DASD_CQR_FILLED;
86 dasd_block_set_timer(device->block, expires); 85 if (erp->block)
86 dasd_block_set_timer(erp->block, expires);
87 else
88 dasd_device_set_timer(device, expires);
87} 89}
88 90
89/* 91/*
@@ -242,9 +244,13 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
242 * DESCRIPTION 244 * DESCRIPTION
243 * Setup ERP to do the ERP action 1 (see Reference manual). 245 * Setup ERP to do the ERP action 1 (see Reference manual).
244 * Repeat the operation on a different channel path. 246 * Repeat the operation on a different channel path.
245 * If all alternate paths have been tried, the request is posted with a 247 * As deviation from the recommended recovery action, we reset the path mask
246 * permanent error. 248 * after we have tried each path and go through all paths a second time.
247 * Note: duplex handling is not implemented (yet). 249 * This will cover situations where only one path at a time is actually down,
250 * but all paths fail and recover just with the same sequence and timing as
251 * we try to use them (flapping links).
252 * If all alternate paths have been tried twice, the request is posted with
253 * a permanent error.
248 * 254 *
249 * PARAMETER 255 * PARAMETER
250 * erp pointer to the current ERP 256 * erp pointer to the current ERP
@@ -253,17 +259,25 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
253 * erp pointer to the ERP 259 * erp pointer to the ERP
254 * 260 *
255 */ 261 */
256static struct dasd_ccw_req * 262static struct dasd_ccw_req *dasd_3990_erp_action_1_sec(struct dasd_ccw_req *erp)
257dasd_3990_erp_action_1(struct dasd_ccw_req * erp)
258{ 263{
264 erp->function = dasd_3990_erp_action_1_sec;
265 dasd_3990_erp_alternate_path(erp);
266 return erp;
267}
259 268
269static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp)
270{
260 erp->function = dasd_3990_erp_action_1; 271 erp->function = dasd_3990_erp_action_1;
261
262 dasd_3990_erp_alternate_path(erp); 272 dasd_3990_erp_alternate_path(erp);
263 273 if (erp->status == DASD_CQR_FAILED) {
274 erp->status = DASD_CQR_FILLED;
275 erp->retries = 10;
276 erp->lpm = LPM_ANYPATH;
277 erp->function = dasd_3990_erp_action_1_sec;
278 }
264 return erp; 279 return erp;
265 280} /* end dasd_3990_erp_action_1(b) */
266} /* end dasd_3990_erp_action_1 */
267 281
268/* 282/*
269 * DASD_3990_ERP_ACTION_4 283 * DASD_3990_ERP_ACTION_4
@@ -2294,6 +2308,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
2294 return cqr; 2308 return cqr;
2295 } 2309 }
2296 2310
2311 ccw = cqr->cpaddr;
2297 if (cqr->cpmode == 1) { 2312 if (cqr->cpmode == 1) {
2298 /* make a shallow copy of the original tcw but set new tsb */ 2313 /* make a shallow copy of the original tcw but set new tsb */
2299 erp->cpmode = 1; 2314 erp->cpmode = 1;
@@ -2302,6 +2317,9 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
2302 tsb = (struct tsb *) &tcw[1]; 2317 tsb = (struct tsb *) &tcw[1];
2303 *tcw = *((struct tcw *)cqr->cpaddr); 2318 *tcw = *((struct tcw *)cqr->cpaddr);
2304 tcw->tsb = (long)tsb; 2319 tcw->tsb = (long)tsb;
2320 } else if (ccw->cmd_code == DASD_ECKD_CCW_PSF) {
2321 /* PSF cannot be chained from NOOP/TIC */
2322 erp->cpaddr = cqr->cpaddr;
2305 } else { 2323 } else {
2306 /* initialize request with default TIC to current ERP/CQR */ 2324 /* initialize request with default TIC to current ERP/CQR */
2307 ccw = erp->cpaddr; 2325 ccw = erp->cpaddr;
@@ -2486,6 +2504,8 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
2486 2504
2487 erp = dasd_3990_erp_action_1(erp); 2505 erp = dasd_3990_erp_action_1(erp);
2488 2506
2507 } else if (erp->function == dasd_3990_erp_action_1_sec) {
2508 erp = dasd_3990_erp_action_1_sec(erp);
2489 } else if (erp->function == dasd_3990_erp_action_5) { 2509 } else if (erp->function == dasd_3990_erp_action_5) {
2490 2510
2491 /* retries have not been successful */ 2511 /* retries have not been successful */