aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r--drivers/s390/block/dasd.c122
1 files changed, 108 insertions, 14 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index ef4c687e7c01..08c88fcd8963 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -7,7 +7,6 @@
7 * Bugreports.to..: <Linux390@de.ibm.com> 7 * Bugreports.to..: <Linux390@de.ibm.com>
8 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 8 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
9 * 9 *
10 * $Revision: 1.172 $
11 */ 10 */
12 11
13#include <linux/config.h> 12#include <linux/config.h>
@@ -19,6 +18,7 @@
19#include <linux/slab.h> 18#include <linux/slab.h>
20#include <linux/buffer_head.h> 19#include <linux/buffer_head.h>
21#include <linux/hdreg.h> 20#include <linux/hdreg.h>
21#include <linux/notifier.h>
22 22
23#include <asm/ccwdev.h> 23#include <asm/ccwdev.h>
24#include <asm/ebcdic.h> 24#include <asm/ebcdic.h>
@@ -58,6 +58,7 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
58static void dasd_flush_ccw_queue(struct dasd_device *, int); 58static void dasd_flush_ccw_queue(struct dasd_device *, int);
59static void dasd_tasklet(struct dasd_device *); 59static void dasd_tasklet(struct dasd_device *);
60static void do_kick_device(void *data); 60static void do_kick_device(void *data);
61static void dasd_disable_eer(struct dasd_device *device);
61 62
62/* 63/*
63 * SECTION: Operations on the device structure. 64 * SECTION: Operations on the device structure.
@@ -152,6 +153,8 @@ dasd_state_new_to_known(struct dasd_device *device)
152static inline void 153static inline void
153dasd_state_known_to_new(struct dasd_device * device) 154dasd_state_known_to_new(struct dasd_device * device)
154{ 155{
156 /* disable extended error reporting for this device */
157 dasd_disable_eer(device);
155 /* Forget the discipline information. */ 158 /* Forget the discipline information. */
156 device->discipline = NULL; 159 device->discipline = NULL;
157 device->state = DASD_STATE_NEW; 160 device->state = DASD_STATE_NEW;
@@ -675,11 +678,8 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
675 rc = ccw_device_clear(device->cdev, (long) cqr); 678 rc = ccw_device_clear(device->cdev, (long) cqr);
676 switch (rc) { 679 switch (rc) {
677 case 0: /* termination successful */ 680 case 0: /* termination successful */
678 if (cqr->retries > 0) { 681 cqr->retries--;
679 cqr->retries--; 682 cqr->status = DASD_CQR_CLEAR;
680 cqr->status = DASD_CQR_CLEAR;
681 } else
682 cqr->status = DASD_CQR_FAILED;
683 cqr->stopclk = get_clock(); 683 cqr->stopclk = get_clock();
684 DBF_DEV_EVENT(DBF_DEBUG, device, 684 DBF_DEV_EVENT(DBF_DEBUG, device,
685 "terminate cqr %p successful", 685 "terminate cqr %p successful",
@@ -871,6 +871,9 @@ dasd_handle_state_change_pending(struct dasd_device *device)
871 struct dasd_ccw_req *cqr; 871 struct dasd_ccw_req *cqr;
872 struct list_head *l, *n; 872 struct list_head *l, *n;
873 873
874 /* first of all call extended error reporting */
875 dasd_write_eer_trigger(DASD_EER_STATECHANGE, device, NULL);
876
874 device->stopped &= ~DASD_STOPPED_PENDING; 877 device->stopped &= ~DASD_STOPPED_PENDING;
875 878
876 /* restart all 'running' IO on queue */ 879 /* restart all 'running' IO on queue */
@@ -1090,6 +1093,19 @@ restart:
1090 } 1093 }
1091 goto restart; 1094 goto restart;
1092 } 1095 }
1096
1097 /* first of all call extended error reporting */
1098 if (device->eer && cqr->status == DASD_CQR_FAILED) {
1099 dasd_write_eer_trigger(DASD_EER_FATALERROR,
1100 device, cqr);
1101
1102 /* restart request */
1103 cqr->status = DASD_CQR_QUEUED;
1104 cqr->retries = 255;
1105 device->stopped |= DASD_STOPPED_QUIESCE;
1106 goto restart;
1107 }
1108
1093 /* Process finished ERP request. */ 1109 /* Process finished ERP request. */
1094 if (cqr->refers) { 1110 if (cqr->refers) {
1095 __dasd_process_erp(device, cqr); 1111 __dasd_process_erp(device, cqr);
@@ -1227,7 +1243,8 @@ __dasd_start_head(struct dasd_device * device)
1227 cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); 1243 cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
1228 /* check FAILFAST */ 1244 /* check FAILFAST */
1229 if (device->stopped & ~DASD_STOPPED_PENDING && 1245 if (device->stopped & ~DASD_STOPPED_PENDING &&
1230 test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags)) { 1246 test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
1247 (!device->eer)) {
1231 cqr->status = DASD_CQR_FAILED; 1248 cqr->status = DASD_CQR_FAILED;
1232 dasd_schedule_bh(device); 1249 dasd_schedule_bh(device);
1233 } 1250 }
@@ -1308,7 +1325,7 @@ dasd_tasklet(struct dasd_device * device)
1308 /* Now call the callback function of requests with final status */ 1325 /* Now call the callback function of requests with final status */
1309 list_for_each_safe(l, n, &final_queue) { 1326 list_for_each_safe(l, n, &final_queue) {
1310 cqr = list_entry(l, struct dasd_ccw_req, list); 1327 cqr = list_entry(l, struct dasd_ccw_req, list);
1311 list_del(&cqr->list); 1328 list_del_init(&cqr->list);
1312 if (cqr->callback != NULL) 1329 if (cqr->callback != NULL)
1313 (cqr->callback)(cqr, cqr->callback_data); 1330 (cqr->callback)(cqr, cqr->callback_data);
1314 } 1331 }
@@ -1393,7 +1410,9 @@ _wait_for_wakeup(struct dasd_ccw_req *cqr)
1393 1410
1394 device = cqr->device; 1411 device = cqr->device;
1395 spin_lock_irq(get_ccwdev_lock(device->cdev)); 1412 spin_lock_irq(get_ccwdev_lock(device->cdev));
1396 rc = cqr->status == DASD_CQR_DONE || cqr->status == DASD_CQR_FAILED; 1413 rc = ((cqr->status == DASD_CQR_DONE ||
1414 cqr->status == DASD_CQR_FAILED) &&
1415 list_empty(&cqr->list));
1397 spin_unlock_irq(get_ccwdev_lock(device->cdev)); 1416 spin_unlock_irq(get_ccwdev_lock(device->cdev));
1398 return rc; 1417 return rc;
1399} 1418}
@@ -1457,15 +1476,37 @@ dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
1457 while (!finished) { 1476 while (!finished) {
1458 rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr)); 1477 rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
1459 if (rc != -ERESTARTSYS) { 1478 if (rc != -ERESTARTSYS) {
1460 /* Request status is either done or failed. */ 1479 /* Request is final (done or failed) */
1461 rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; 1480 rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
1462 break; 1481 break;
1463 } 1482 }
1464 spin_lock_irq(get_ccwdev_lock(device->cdev)); 1483 spin_lock_irq(get_ccwdev_lock(device->cdev));
1465 if (cqr->status == DASD_CQR_IN_IO && 1484 switch (cqr->status) {
1466 device->discipline->term_IO(cqr) == 0) { 1485 case DASD_CQR_IN_IO:
1467 list_del(&cqr->list); 1486 /* terminate runnig cqr */
1487 if (device->discipline->term_IO) {
1488 cqr->retries = -1;
1489 device->discipline->term_IO(cqr);
1490 /*nished =
1491 * wait (non-interruptible) for final status
1492 * because signal ist still pending
1493 */
1494 spin_unlock_irq(get_ccwdev_lock(device->cdev));
1495 wait_event(wait_q, _wait_for_wakeup(cqr));
1496 spin_lock_irq(get_ccwdev_lock(device->cdev));
1497 rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
1498 finished = 1;
1499 }
1500 break;
1501 case DASD_CQR_QUEUED:
1502 /* request */
1503 list_del_init(&cqr->list);
1504 rc = -EIO;
1468 finished = 1; 1505 finished = 1;
1506 break;
1507 default:
1508 /* cqr with 'non-interruptable' status - just wait */
1509 break;
1469 } 1510 }
1470 spin_unlock_irq(get_ccwdev_lock(device->cdev)); 1511 spin_unlock_irq(get_ccwdev_lock(device->cdev));
1471 } 1512 }
@@ -1945,6 +1986,9 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
1945 switch (event) { 1986 switch (event) {
1946 case CIO_GONE: 1987 case CIO_GONE:
1947 case CIO_NO_PATH: 1988 case CIO_NO_PATH:
1989 /* first of all call extended error reporting */
1990 dasd_write_eer_trigger(DASD_EER_NOPATH, device, NULL);
1991
1948 if (device->state < DASD_STATE_BASIC) 1992 if (device->state < DASD_STATE_BASIC)
1949 break; 1993 break;
1950 /* Device is active. We want to keep it. */ 1994 /* Device is active. We want to keep it. */
@@ -2002,6 +2046,51 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
2002 put_driver(drv); 2046 put_driver(drv);
2003} 2047}
2004 2048
2049/*
2050 * notifications for extended error reports
2051 */
2052static struct notifier_block *dasd_eer_chain;
2053
2054int
2055dasd_register_eer_notifier(struct notifier_block *nb)
2056{
2057 return notifier_chain_register(&dasd_eer_chain, nb);
2058}
2059
2060int
2061dasd_unregister_eer_notifier(struct notifier_block *nb)
2062{
2063 return notifier_chain_unregister(&dasd_eer_chain, nb);
2064}
2065
2066/*
2067 * Notify the registered error reporting module of a problem
2068 */
2069void
2070dasd_write_eer_trigger(unsigned int id, struct dasd_device *device,
2071 struct dasd_ccw_req *cqr)
2072{
2073 if (device->eer) {
2074 struct dasd_eer_trigger temp;
2075 temp.id = id;
2076 temp.device = device;
2077 temp.cqr = cqr;
2078 notifier_call_chain(&dasd_eer_chain, DASD_EER_TRIGGER,
2079 (void *)&temp);
2080 }
2081}
2082
2083/*
2084 * Tell the registered error reporting module to disable error reporting for
2085 * a given device and to cleanup any private data structures on that device.
2086 */
2087static void
2088dasd_disable_eer(struct dasd_device *device)
2089{
2090 notifier_call_chain(&dasd_eer_chain, DASD_EER_DISABLE, (void *)device);
2091}
2092
2093
2005static int __init 2094static int __init
2006dasd_init(void) 2095dasd_init(void)
2007{ 2096{
@@ -2083,6 +2172,11 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online);
2083EXPORT_SYMBOL_GPL(dasd_generic_set_offline); 2172EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
2084EXPORT_SYMBOL_GPL(dasd_generic_auto_online); 2173EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
2085 2174
2175EXPORT_SYMBOL(dasd_register_eer_notifier);
2176EXPORT_SYMBOL(dasd_unregister_eer_notifier);
2177EXPORT_SYMBOL(dasd_write_eer_trigger);
2178
2179
2086/* 2180/*
2087 * Overrides for Emacs so that we follow Linus's tabbing style. 2181 * Overrides for Emacs so that we follow Linus's tabbing style.
2088 * Emacs will notice this stuff at the end of the file and automatically 2182 * Emacs will notice this stuff at the end of the file and automatically