[PATCH] s390: dasd extended error reporting

The DASD extended error reporting is a facility that allows to get detailed
information about certain problems in the DASD I/O.  This information can be
used to implement fail-over applications that can recover these problems.

Signed-off-by: Stefan Weinhuber <wein@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 9e0b371..f32f744 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -151,6 +151,8 @@
 static inline void
 dasd_state_known_to_new(struct dasd_device * device)
 {
+	/* Disable extended error reporting for this device. */
+	dasd_eer_disable(device);
 	/* Forget the discipline information. */
 	if (device->discipline)
 		module_put(device->discipline->owner);
@@ -892,6 +894,9 @@
 	struct dasd_ccw_req *cqr;
 	struct list_head *l, *n;
 
+	/* First of all start sense subsystem status request. */
+	dasd_eer_snss(device);
+
 	device->stopped &= ~DASD_STOPPED_PENDING;
 
         /* restart all 'running' IO on queue */
@@ -1111,6 +1116,19 @@
 			}
 			goto restart;
 		}
+
+		/* First of all call extended error reporting. */
+		if (dasd_eer_enabled(device) &&
+		    cqr->status == DASD_CQR_FAILED) {
+			dasd_eer_write(device, cqr, DASD_EER_FATALERROR);
+
+			/* restart request  */
+			cqr->status = DASD_CQR_QUEUED;
+			cqr->retries = 255;
+			device->stopped |= DASD_STOPPED_QUIESCE;
+			goto restart;
+		}
+
 		/* Process finished ERP request. */
 		if (cqr->refers) {
 			__dasd_process_erp(device, cqr);
@@ -1248,7 +1266,8 @@
 	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
         /* check FAILFAST */
 	if (device->stopped & ~DASD_STOPPED_PENDING &&
-	    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags)) {
+	    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+	    (!dasd_eer_enabled(device))) {
 		cqr->status = DASD_CQR_FAILED;
 		dasd_schedule_bh(device);
 	}
@@ -1807,6 +1826,7 @@
 #ifdef CONFIG_PROC_FS
 	dasd_proc_exit();
 #endif
+	dasd_eer_exit();
         if (dasd_page_cache != NULL) {
 		kmem_cache_destroy(dasd_page_cache);
 		dasd_page_cache = NULL;
@@ -2003,6 +2023,9 @@
 	switch (event) {
 	case CIO_GONE:
 	case CIO_NO_PATH:
+		/* First of all call extended error reporting. */
+		dasd_eer_write(device, NULL, DASD_EER_NOPATH);
+
 		if (device->state < DASD_STATE_BASIC)
 			break;
 		/* Device is active. We want to keep it. */
@@ -2060,6 +2083,7 @@
 	put_driver(drv);
 }
 
+
 static int __init
 dasd_init(void)
 {
@@ -2092,6 +2116,9 @@
 	rc = dasd_parse();
 	if (rc)
 		goto failed;
+	rc = dasd_eer_init();
+	if (rc)
+		goto failed;
 #ifdef CONFIG_PROC_FS
 	rc = dasd_proc_init();
 	if (rc)