diff options
Diffstat (limited to 'drivers/s390/block')
-rw-r--r-- | drivers/s390/block/dasd.c | 207 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 46 | ||||
-rw-r--r-- | drivers/s390/block/dasd_alias.c | 15 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 72 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 3 | ||||
-rw-r--r-- | drivers/s390/block/dasd_ioctl.c | 4 |
6 files changed, 253 insertions, 94 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 329115a4d4b3..4f211c175b55 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -63,6 +63,7 @@ static void do_restore_device(struct work_struct *); | |||
63 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); | 63 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); |
64 | static void dasd_device_timeout(unsigned long); | 64 | static void dasd_device_timeout(unsigned long); |
65 | static void dasd_block_timeout(unsigned long); | 65 | static void dasd_block_timeout(unsigned long); |
66 | static void __dasd_process_erp(struct dasd_device *, struct dasd_ccw_req *); | ||
66 | 67 | ||
67 | /* | 68 | /* |
68 | * SECTION: Operations on the device structure. | 69 | * SECTION: Operations on the device structure. |
@@ -959,7 +960,7 @@ static void dasd_device_timeout(unsigned long ptr) | |||
959 | device = (struct dasd_device *) ptr; | 960 | device = (struct dasd_device *) ptr; |
960 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 961 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
961 | /* re-activate request queue */ | 962 | /* re-activate request queue */ |
962 | device->stopped &= ~DASD_STOPPED_PENDING; | 963 | dasd_device_remove_stop_bits(device, DASD_STOPPED_PENDING); |
963 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 964 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
964 | dasd_schedule_device_bh(device); | 965 | dasd_schedule_device_bh(device); |
965 | } | 966 | } |
@@ -1022,7 +1023,7 @@ void dasd_generic_handle_state_change(struct dasd_device *device) | |||
1022 | /* First of all start sense subsystem status request. */ | 1023 | /* First of all start sense subsystem status request. */ |
1023 | dasd_eer_snss(device); | 1024 | dasd_eer_snss(device); |
1024 | 1025 | ||
1025 | device->stopped &= ~DASD_STOPPED_PENDING; | 1026 | dasd_device_remove_stop_bits(device, DASD_STOPPED_PENDING); |
1026 | dasd_schedule_device_bh(device); | 1027 | dasd_schedule_device_bh(device); |
1027 | if (device->block) | 1028 | if (device->block) |
1028 | dasd_schedule_block_bh(device->block); | 1029 | dasd_schedule_block_bh(device->block); |
@@ -1404,6 +1405,20 @@ void dasd_schedule_device_bh(struct dasd_device *device) | |||
1404 | tasklet_hi_schedule(&device->tasklet); | 1405 | tasklet_hi_schedule(&device->tasklet); |
1405 | } | 1406 | } |
1406 | 1407 | ||
1408 | void dasd_device_set_stop_bits(struct dasd_device *device, int bits) | ||
1409 | { | ||
1410 | device->stopped |= bits; | ||
1411 | } | ||
1412 | EXPORT_SYMBOL_GPL(dasd_device_set_stop_bits); | ||
1413 | |||
1414 | void dasd_device_remove_stop_bits(struct dasd_device *device, int bits) | ||
1415 | { | ||
1416 | device->stopped &= ~bits; | ||
1417 | if (!device->stopped) | ||
1418 | wake_up(&generic_waitq); | ||
1419 | } | ||
1420 | EXPORT_SYMBOL_GPL(dasd_device_remove_stop_bits); | ||
1421 | |||
1407 | /* | 1422 | /* |
1408 | * Queue a request to the head of the device ccw_queue. | 1423 | * Queue a request to the head of the device ccw_queue. |
1409 | * Start the I/O if possible. | 1424 | * Start the I/O if possible. |
@@ -1464,58 +1479,135 @@ static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr) | |||
1464 | } | 1479 | } |
1465 | 1480 | ||
1466 | /* | 1481 | /* |
1467 | * Queue a request to the tail of the device ccw_queue and wait for | 1482 | * checks if error recovery is necessary, returns 1 if yes, 0 otherwise. |
1468 | * it's completion. | ||
1469 | */ | 1483 | */ |
1470 | int dasd_sleep_on(struct dasd_ccw_req *cqr) | 1484 | static int __dasd_sleep_on_erp(struct dasd_ccw_req *cqr) |
1471 | { | 1485 | { |
1472 | struct dasd_device *device; | 1486 | struct dasd_device *device; |
1473 | int rc; | 1487 | dasd_erp_fn_t erp_fn; |
1474 | 1488 | ||
1489 | if (cqr->status == DASD_CQR_FILLED) | ||
1490 | return 0; | ||
1475 | device = cqr->startdev; | 1491 | device = cqr->startdev; |
1492 | if (test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) { | ||
1493 | if (cqr->status == DASD_CQR_TERMINATED) { | ||
1494 | device->discipline->handle_terminated_request(cqr); | ||
1495 | return 1; | ||
1496 | } | ||
1497 | if (cqr->status == DASD_CQR_NEED_ERP) { | ||
1498 | erp_fn = device->discipline->erp_action(cqr); | ||
1499 | erp_fn(cqr); | ||
1500 | return 1; | ||
1501 | } | ||
1502 | if (cqr->status == DASD_CQR_FAILED) | ||
1503 | dasd_log_sense(cqr, &cqr->irb); | ||
1504 | if (cqr->refers) { | ||
1505 | __dasd_process_erp(device, cqr); | ||
1506 | return 1; | ||
1507 | } | ||
1508 | } | ||
1509 | return 0; | ||
1510 | } | ||
1476 | 1511 | ||
1477 | cqr->callback = dasd_wakeup_cb; | 1512 | static int __dasd_sleep_on_loop_condition(struct dasd_ccw_req *cqr) |
1478 | cqr->callback_data = (void *) &generic_waitq; | 1513 | { |
1479 | dasd_add_request_tail(cqr); | 1514 | if (test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) { |
1480 | wait_event(generic_waitq, _wait_for_wakeup(cqr)); | 1515 | if (cqr->refers) /* erp is not done yet */ |
1516 | return 1; | ||
1517 | return ((cqr->status != DASD_CQR_DONE) && | ||
1518 | (cqr->status != DASD_CQR_FAILED)); | ||
1519 | } else | ||
1520 | return (cqr->status == DASD_CQR_FILLED); | ||
1521 | } | ||
1481 | 1522 | ||
1482 | if (cqr->status == DASD_CQR_DONE) | 1523 | static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) |
1524 | { | ||
1525 | struct dasd_device *device; | ||
1526 | int rc; | ||
1527 | struct list_head ccw_queue; | ||
1528 | struct dasd_ccw_req *cqr; | ||
1529 | |||
1530 | INIT_LIST_HEAD(&ccw_queue); | ||
1531 | maincqr->status = DASD_CQR_FILLED; | ||
1532 | device = maincqr->startdev; | ||
1533 | list_add(&maincqr->blocklist, &ccw_queue); | ||
1534 | for (cqr = maincqr; __dasd_sleep_on_loop_condition(cqr); | ||
1535 | cqr = list_first_entry(&ccw_queue, | ||
1536 | struct dasd_ccw_req, blocklist)) { | ||
1537 | |||
1538 | if (__dasd_sleep_on_erp(cqr)) | ||
1539 | continue; | ||
1540 | if (cqr->status != DASD_CQR_FILLED) /* could be failed */ | ||
1541 | continue; | ||
1542 | |||
1543 | /* Non-temporary stop condition will trigger fail fast */ | ||
1544 | if (device->stopped & ~DASD_STOPPED_PENDING && | ||
1545 | test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && | ||
1546 | (!dasd_eer_enabled(device))) { | ||
1547 | cqr->status = DASD_CQR_FAILED; | ||
1548 | continue; | ||
1549 | } | ||
1550 | |||
1551 | /* Don't try to start requests if device is stopped */ | ||
1552 | if (interruptible) { | ||
1553 | rc = wait_event_interruptible( | ||
1554 | generic_waitq, !(device->stopped)); | ||
1555 | if (rc == -ERESTARTSYS) { | ||
1556 | cqr->status = DASD_CQR_FAILED; | ||
1557 | maincqr->intrc = rc; | ||
1558 | continue; | ||
1559 | } | ||
1560 | } else | ||
1561 | wait_event(generic_waitq, !(device->stopped)); | ||
1562 | |||
1563 | cqr->callback = dasd_wakeup_cb; | ||
1564 | cqr->callback_data = (void *) &generic_waitq; | ||
1565 | dasd_add_request_tail(cqr); | ||
1566 | if (interruptible) { | ||
1567 | rc = wait_event_interruptible( | ||
1568 | generic_waitq, _wait_for_wakeup(cqr)); | ||
1569 | if (rc == -ERESTARTSYS) { | ||
1570 | dasd_cancel_req(cqr); | ||
1571 | /* wait (non-interruptible) for final status */ | ||
1572 | wait_event(generic_waitq, | ||
1573 | _wait_for_wakeup(cqr)); | ||
1574 | cqr->status = DASD_CQR_FAILED; | ||
1575 | maincqr->intrc = rc; | ||
1576 | continue; | ||
1577 | } | ||
1578 | } else | ||
1579 | wait_event(generic_waitq, _wait_for_wakeup(cqr)); | ||
1580 | } | ||
1581 | |||
1582 | maincqr->endclk = get_clock(); | ||
1583 | if ((maincqr->status != DASD_CQR_DONE) && | ||
1584 | (maincqr->intrc != -ERESTARTSYS)) | ||
1585 | dasd_log_sense(maincqr, &maincqr->irb); | ||
1586 | if (maincqr->status == DASD_CQR_DONE) | ||
1483 | rc = 0; | 1587 | rc = 0; |
1484 | else if (cqr->intrc) | 1588 | else if (maincqr->intrc) |
1485 | rc = cqr->intrc; | 1589 | rc = maincqr->intrc; |
1486 | else | 1590 | else |
1487 | rc = -EIO; | 1591 | rc = -EIO; |
1488 | return rc; | 1592 | return rc; |
1489 | } | 1593 | } |
1490 | 1594 | ||
1491 | /* | 1595 | /* |
1596 | * Queue a request to the tail of the device ccw_queue and wait for | ||
1597 | * it's completion. | ||
1598 | */ | ||
1599 | int dasd_sleep_on(struct dasd_ccw_req *cqr) | ||
1600 | { | ||
1601 | return _dasd_sleep_on(cqr, 0); | ||
1602 | } | ||
1603 | |||
1604 | /* | ||
1492 | * Queue a request to the tail of the device ccw_queue and wait | 1605 | * Queue a request to the tail of the device ccw_queue and wait |
1493 | * interruptible for it's completion. | 1606 | * interruptible for it's completion. |
1494 | */ | 1607 | */ |
1495 | int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) | 1608 | int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) |
1496 | { | 1609 | { |
1497 | struct dasd_device *device; | 1610 | return _dasd_sleep_on(cqr, 1); |
1498 | int rc; | ||
1499 | |||
1500 | device = cqr->startdev; | ||
1501 | cqr->callback = dasd_wakeup_cb; | ||
1502 | cqr->callback_data = (void *) &generic_waitq; | ||
1503 | dasd_add_request_tail(cqr); | ||
1504 | rc = wait_event_interruptible(generic_waitq, _wait_for_wakeup(cqr)); | ||
1505 | if (rc == -ERESTARTSYS) { | ||
1506 | dasd_cancel_req(cqr); | ||
1507 | /* wait (non-interruptible) for final status */ | ||
1508 | wait_event(generic_waitq, _wait_for_wakeup(cqr)); | ||
1509 | cqr->intrc = rc; | ||
1510 | } | ||
1511 | |||
1512 | if (cqr->status == DASD_CQR_DONE) | ||
1513 | rc = 0; | ||
1514 | else if (cqr->intrc) | ||
1515 | rc = cqr->intrc; | ||
1516 | else | ||
1517 | rc = -EIO; | ||
1518 | return rc; | ||
1519 | } | 1611 | } |
1520 | 1612 | ||
1521 | /* | 1613 | /* |
@@ -1629,7 +1721,7 @@ static void dasd_block_timeout(unsigned long ptr) | |||
1629 | block = (struct dasd_block *) ptr; | 1721 | block = (struct dasd_block *) ptr; |
1630 | spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags); | 1722 | spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags); |
1631 | /* re-activate request queue */ | 1723 | /* re-activate request queue */ |
1632 | block->base->stopped &= ~DASD_STOPPED_PENDING; | 1724 | dasd_device_remove_stop_bits(block->base, DASD_STOPPED_PENDING); |
1633 | spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags); | 1725 | spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags); |
1634 | dasd_schedule_block_bh(block); | 1726 | dasd_schedule_block_bh(block); |
1635 | } | 1727 | } |
@@ -1656,11 +1748,10 @@ void dasd_block_clear_timer(struct dasd_block *block) | |||
1656 | /* | 1748 | /* |
1657 | * Process finished error recovery ccw. | 1749 | * Process finished error recovery ccw. |
1658 | */ | 1750 | */ |
1659 | static inline void __dasd_block_process_erp(struct dasd_block *block, | 1751 | static void __dasd_process_erp(struct dasd_device *device, |
1660 | struct dasd_ccw_req *cqr) | 1752 | struct dasd_ccw_req *cqr) |
1661 | { | 1753 | { |
1662 | dasd_erp_fn_t erp_fn; | 1754 | dasd_erp_fn_t erp_fn; |
1663 | struct dasd_device *device = block->base; | ||
1664 | 1755 | ||
1665 | if (cqr->status == DASD_CQR_DONE) | 1756 | if (cqr->status == DASD_CQR_DONE) |
1666 | DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful"); | 1757 | DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful"); |
@@ -1724,9 +1815,12 @@ static void __dasd_process_request_queue(struct dasd_block *block) | |||
1724 | */ | 1815 | */ |
1725 | if (!list_empty(&block->ccw_queue)) | 1816 | if (!list_empty(&block->ccw_queue)) |
1726 | break; | 1817 | break; |
1727 | spin_lock_irqsave(get_ccwdev_lock(basedev->cdev), flags); | 1818 | spin_lock_irqsave( |
1728 | basedev->stopped |= DASD_STOPPED_PENDING; | 1819 | get_ccwdev_lock(basedev->cdev), flags); |
1729 | spin_unlock_irqrestore(get_ccwdev_lock(basedev->cdev), flags); | 1820 | dasd_device_set_stop_bits(basedev, |
1821 | DASD_STOPPED_PENDING); | ||
1822 | spin_unlock_irqrestore( | ||
1823 | get_ccwdev_lock(basedev->cdev), flags); | ||
1730 | dasd_block_set_timer(block, HZ/2); | 1824 | dasd_block_set_timer(block, HZ/2); |
1731 | break; | 1825 | break; |
1732 | } | 1826 | } |
@@ -1812,7 +1906,7 @@ restart: | |||
1812 | cqr->status = DASD_CQR_FILLED; | 1906 | cqr->status = DASD_CQR_FILLED; |
1813 | cqr->retries = 255; | 1907 | cqr->retries = 255; |
1814 | spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); | 1908 | spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); |
1815 | base->stopped |= DASD_STOPPED_QUIESCE; | 1909 | dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE); |
1816 | spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), | 1910 | spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), |
1817 | flags); | 1911 | flags); |
1818 | goto restart; | 1912 | goto restart; |
@@ -1820,7 +1914,7 @@ restart: | |||
1820 | 1914 | ||
1821 | /* Process finished ERP request. */ | 1915 | /* Process finished ERP request. */ |
1822 | if (cqr->refers) { | 1916 | if (cqr->refers) { |
1823 | __dasd_block_process_erp(block, cqr); | 1917 | __dasd_process_erp(base, cqr); |
1824 | goto restart; | 1918 | goto restart; |
1825 | } | 1919 | } |
1826 | 1920 | ||
@@ -1951,7 +2045,7 @@ restart_cb: | |||
1951 | /* Process finished ERP request. */ | 2045 | /* Process finished ERP request. */ |
1952 | if (cqr->refers) { | 2046 | if (cqr->refers) { |
1953 | spin_lock_bh(&block->queue_lock); | 2047 | spin_lock_bh(&block->queue_lock); |
1954 | __dasd_block_process_erp(block, cqr); | 2048 | __dasd_process_erp(block->base, cqr); |
1955 | spin_unlock_bh(&block->queue_lock); | 2049 | spin_unlock_bh(&block->queue_lock); |
1956 | /* restart list_for_xx loop since dasd_process_erp | 2050 | /* restart list_for_xx loop since dasd_process_erp |
1957 | * might remove multiple elements */ | 2051 | * might remove multiple elements */ |
@@ -2410,16 +2504,16 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) | |||
2410 | cqr->status = DASD_CQR_QUEUED; | 2504 | cqr->status = DASD_CQR_QUEUED; |
2411 | cqr->retries++; | 2505 | cqr->retries++; |
2412 | } | 2506 | } |
2413 | device->stopped |= DASD_STOPPED_DC_WAIT; | 2507 | dasd_device_set_stop_bits(device, DASD_STOPPED_DC_WAIT); |
2414 | dasd_device_clear_timer(device); | 2508 | dasd_device_clear_timer(device); |
2415 | dasd_schedule_device_bh(device); | 2509 | dasd_schedule_device_bh(device); |
2416 | ret = 1; | 2510 | ret = 1; |
2417 | break; | 2511 | break; |
2418 | case CIO_OPER: | 2512 | case CIO_OPER: |
2419 | /* FIXME: add a sanity check. */ | 2513 | /* FIXME: add a sanity check. */ |
2420 | device->stopped &= ~DASD_STOPPED_DC_WAIT; | 2514 | dasd_device_remove_stop_bits(device, DASD_STOPPED_DC_WAIT); |
2421 | if (device->stopped & DASD_UNRESUMED_PM) { | 2515 | if (device->stopped & DASD_UNRESUMED_PM) { |
2422 | device->stopped &= ~DASD_UNRESUMED_PM; | 2516 | dasd_device_remove_stop_bits(device, DASD_UNRESUMED_PM); |
2423 | dasd_restore_device(device); | 2517 | dasd_restore_device(device); |
2424 | ret = 1; | 2518 | ret = 1; |
2425 | break; | 2519 | break; |
@@ -2444,7 +2538,7 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev) | |||
2444 | if (IS_ERR(device)) | 2538 | if (IS_ERR(device)) |
2445 | return PTR_ERR(device); | 2539 | return PTR_ERR(device); |
2446 | /* disallow new I/O */ | 2540 | /* disallow new I/O */ |
2447 | device->stopped |= DASD_STOPPED_PM; | 2541 | dasd_device_set_stop_bits(device, DASD_STOPPED_PM); |
2448 | /* clear active requests */ | 2542 | /* clear active requests */ |
2449 | INIT_LIST_HEAD(&freeze_queue); | 2543 | INIT_LIST_HEAD(&freeze_queue); |
2450 | spin_lock_irq(get_ccwdev_lock(cdev)); | 2544 | spin_lock_irq(get_ccwdev_lock(cdev)); |
@@ -2496,14 +2590,18 @@ int dasd_generic_restore_device(struct ccw_device *cdev) | |||
2496 | return PTR_ERR(device); | 2590 | return PTR_ERR(device); |
2497 | 2591 | ||
2498 | /* allow new IO again */ | 2592 | /* allow new IO again */ |
2499 | device->stopped &= ~DASD_STOPPED_PM; | 2593 | dasd_device_remove_stop_bits(device, |
2500 | device->stopped &= ~DASD_UNRESUMED_PM; | 2594 | (DASD_STOPPED_PM | DASD_UNRESUMED_PM)); |
2501 | 2595 | ||
2502 | dasd_schedule_device_bh(device); | 2596 | dasd_schedule_device_bh(device); |
2503 | 2597 | ||
2504 | if (device->discipline->restore) | 2598 | /* |
2599 | * call discipline restore function | ||
2600 | * if device is stopped do nothing e.g. for disconnected devices | ||
2601 | */ | ||
2602 | if (device->discipline->restore && !(device->stopped)) | ||
2505 | rc = device->discipline->restore(device); | 2603 | rc = device->discipline->restore(device); |
2506 | if (rc) | 2604 | if (rc || device->stopped) |
2507 | /* | 2605 | /* |
2508 | * if the resume failed for the DASD we put it in | 2606 | * if the resume failed for the DASD we put it in |
2509 | * an UNRESUMED stop state | 2607 | * an UNRESUMED stop state |
@@ -2553,8 +2651,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, | |||
2553 | cqr->startdev = device; | 2651 | cqr->startdev = device; |
2554 | cqr->memdev = device; | 2652 | cqr->memdev = device; |
2555 | cqr->expires = 10*HZ; | 2653 | cqr->expires = 10*HZ; |
2556 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 2654 | cqr->retries = 256; |
2557 | cqr->retries = 2; | ||
2558 | cqr->buildclk = get_clock(); | 2655 | cqr->buildclk = get_clock(); |
2559 | cqr->status = DASD_CQR_FILLED; | 2656 | cqr->status = DASD_CQR_FILLED; |
2560 | return cqr; | 2657 | return cqr; |
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 | */ |
72 | static void | 72 | static void dasd_3990_erp_block_queue(struct dasd_ccw_req *erp, int expires) |
73 | dasd_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 | */ |
256 | static struct dasd_ccw_req * | 262 | static struct dasd_ccw_req *dasd_3990_erp_action_1_sec(struct dasd_ccw_req *erp) |
257 | dasd_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 | ||
269 | static 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 */ |
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 70a008c00522..cdc6c049c353 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
@@ -755,11 +755,11 @@ static void __stop_device_on_lcu(struct dasd_device *device, | |||
755 | { | 755 | { |
756 | /* If pos == device then device is already locked! */ | 756 | /* If pos == device then device is already locked! */ |
757 | if (pos == device) { | 757 | if (pos == device) { |
758 | pos->stopped |= DASD_STOPPED_SU; | 758 | dasd_device_set_stop_bits(pos, DASD_STOPPED_SU); |
759 | return; | 759 | return; |
760 | } | 760 | } |
761 | spin_lock(get_ccwdev_lock(pos->cdev)); | 761 | spin_lock(get_ccwdev_lock(pos->cdev)); |
762 | pos->stopped |= DASD_STOPPED_SU; | 762 | dasd_device_set_stop_bits(pos, DASD_STOPPED_SU); |
763 | spin_unlock(get_ccwdev_lock(pos->cdev)); | 763 | spin_unlock(get_ccwdev_lock(pos->cdev)); |
764 | } | 764 | } |
765 | 765 | ||
@@ -793,26 +793,26 @@ static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu) | |||
793 | 793 | ||
794 | list_for_each_entry(device, &lcu->active_devices, alias_list) { | 794 | list_for_each_entry(device, &lcu->active_devices, alias_list) { |
795 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 795 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
796 | device->stopped &= ~DASD_STOPPED_SU; | 796 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); |
797 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 797 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
798 | } | 798 | } |
799 | 799 | ||
800 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { | 800 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { |
801 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 801 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
802 | device->stopped &= ~DASD_STOPPED_SU; | 802 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); |
803 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 803 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
804 | } | 804 | } |
805 | 805 | ||
806 | list_for_each_entry(pavgroup, &lcu->grouplist, group) { | 806 | list_for_each_entry(pavgroup, &lcu->grouplist, group) { |
807 | list_for_each_entry(device, &pavgroup->baselist, alias_list) { | 807 | list_for_each_entry(device, &pavgroup->baselist, alias_list) { |
808 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 808 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
809 | device->stopped &= ~DASD_STOPPED_SU; | 809 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); |
810 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | 810 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), |
811 | flags); | 811 | flags); |
812 | } | 812 | } |
813 | list_for_each_entry(device, &pavgroup->aliaslist, alias_list) { | 813 | list_for_each_entry(device, &pavgroup->aliaslist, alias_list) { |
814 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 814 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
815 | device->stopped &= ~DASD_STOPPED_SU; | 815 | dasd_device_remove_stop_bits(device, DASD_STOPPED_SU); |
816 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | 816 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), |
817 | flags); | 817 | flags); |
818 | } | 818 | } |
@@ -836,7 +836,8 @@ static void summary_unit_check_handling_work(struct work_struct *work) | |||
836 | 836 | ||
837 | /* 2. reset summary unit check */ | 837 | /* 2. reset summary unit check */ |
838 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | 838 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
839 | device->stopped &= ~(DASD_STOPPED_SU | DASD_STOPPED_PENDING); | 839 | dasd_device_remove_stop_bits(device, |
840 | (DASD_STOPPED_SU | DASD_STOPPED_PENDING)); | ||
840 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | 841 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
841 | reset_summary_unit_check(lcu, device, suc_data->reason); | 842 | reset_summary_unit_check(lcu, device, suc_data->reason); |
842 | 843 | ||
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index abb2ec836ee8..39ffc84712f0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -77,6 +77,11 @@ MODULE_DEVICE_TABLE(ccw, dasd_eckd_ids); | |||
77 | 77 | ||
78 | static struct ccw_driver dasd_eckd_driver; /* see below */ | 78 | static struct ccw_driver dasd_eckd_driver; /* see below */ |
79 | 79 | ||
80 | #define INIT_CQR_OK 0 | ||
81 | #define INIT_CQR_UNFORMATTED 1 | ||
82 | #define INIT_CQR_ERROR 2 | ||
83 | |||
84 | |||
80 | /* initial attempt at a probe function. this can be simplified once | 85 | /* initial attempt at a probe function. this can be simplified once |
81 | * the other detection code is gone */ | 86 | * the other detection code is gone */ |
82 | static int | 87 | static int |
@@ -749,8 +754,7 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, | |||
749 | cqr->block = NULL; | 754 | cqr->block = NULL; |
750 | cqr->expires = 10*HZ; | 755 | cqr->expires = 10*HZ; |
751 | cqr->lpm = lpm; | 756 | cqr->lpm = lpm; |
752 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 757 | cqr->retries = 256; |
753 | cqr->retries = 2; | ||
754 | cqr->buildclk = get_clock(); | 758 | cqr->buildclk = get_clock(); |
755 | cqr->status = DASD_CQR_FILLED; | 759 | cqr->status = DASD_CQR_FILLED; |
756 | return cqr; | 760 | return cqr; |
@@ -949,8 +953,7 @@ static int dasd_eckd_read_features(struct dasd_device *device) | |||
949 | cqr->startdev = device; | 953 | cqr->startdev = device; |
950 | cqr->memdev = device; | 954 | cqr->memdev = device; |
951 | cqr->block = NULL; | 955 | cqr->block = NULL; |
952 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 956 | cqr->retries = 256; |
953 | cqr->retries = 5; | ||
954 | cqr->expires = 10 * HZ; | 957 | cqr->expires = 10 * HZ; |
955 | 958 | ||
956 | /* Prepare for Read Subsystem Data */ | 959 | /* Prepare for Read Subsystem Data */ |
@@ -1025,6 +1028,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, | |||
1025 | cqr->startdev = device; | 1028 | cqr->startdev = device; |
1026 | cqr->memdev = device; | 1029 | cqr->memdev = device; |
1027 | cqr->block = NULL; | 1030 | cqr->block = NULL; |
1031 | cqr->retries = 256; | ||
1028 | cqr->expires = 10*HZ; | 1032 | cqr->expires = 10*HZ; |
1029 | cqr->buildclk = get_clock(); | 1033 | cqr->buildclk = get_clock(); |
1030 | cqr->status = DASD_CQR_FILLED; | 1034 | cqr->status = DASD_CQR_FILLED; |
@@ -1068,6 +1072,7 @@ static int dasd_eckd_validate_server(struct dasd_device *device) | |||
1068 | else | 1072 | else |
1069 | enable_pav = 1; | 1073 | enable_pav = 1; |
1070 | rc = dasd_eckd_psf_ssc(device, enable_pav); | 1074 | rc = dasd_eckd_psf_ssc(device, enable_pav); |
1075 | |||
1071 | /* may be requested feature is not available on server, | 1076 | /* may be requested feature is not available on server, |
1072 | * therefore just report error and go ahead */ | 1077 | * therefore just report error and go ahead */ |
1073 | private = (struct dasd_eckd_private *) device->private; | 1078 | private = (struct dasd_eckd_private *) device->private; |
@@ -1265,12 +1270,29 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) | |||
1265 | cqr->block = NULL; | 1270 | cqr->block = NULL; |
1266 | cqr->startdev = device; | 1271 | cqr->startdev = device; |
1267 | cqr->memdev = device; | 1272 | cqr->memdev = device; |
1268 | cqr->retries = 0; | 1273 | cqr->retries = 255; |
1269 | cqr->buildclk = get_clock(); | 1274 | cqr->buildclk = get_clock(); |
1270 | cqr->status = DASD_CQR_FILLED; | 1275 | cqr->status = DASD_CQR_FILLED; |
1271 | return cqr; | 1276 | return cqr; |
1272 | } | 1277 | } |
1273 | 1278 | ||
1279 | /* differentiate between 'no record found' and any other error */ | ||
1280 | static int dasd_eckd_analysis_evaluation(struct dasd_ccw_req *init_cqr) | ||
1281 | { | ||
1282 | char *sense; | ||
1283 | if (init_cqr->status == DASD_CQR_DONE) | ||
1284 | return INIT_CQR_OK; | ||
1285 | else if (init_cqr->status == DASD_CQR_NEED_ERP || | ||
1286 | init_cqr->status == DASD_CQR_FAILED) { | ||
1287 | sense = dasd_get_sense(&init_cqr->irb); | ||
1288 | if (sense && (sense[1] & SNS1_NO_REC_FOUND)) | ||
1289 | return INIT_CQR_UNFORMATTED; | ||
1290 | else | ||
1291 | return INIT_CQR_ERROR; | ||
1292 | } else | ||
1293 | return INIT_CQR_ERROR; | ||
1294 | } | ||
1295 | |||
1274 | /* | 1296 | /* |
1275 | * This is the callback function for the init_analysis cqr. It saves | 1297 | * This is the callback function for the init_analysis cqr. It saves |
1276 | * the status of the initial analysis ccw before it frees it and kicks | 1298 | * the status of the initial analysis ccw before it frees it and kicks |
@@ -1278,21 +1300,20 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) | |||
1278 | * dasd_eckd_do_analysis again (if the devices has not been marked | 1300 | * dasd_eckd_do_analysis again (if the devices has not been marked |
1279 | * for deletion in the meantime). | 1301 | * for deletion in the meantime). |
1280 | */ | 1302 | */ |
1281 | static void | 1303 | static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, |
1282 | dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data) | 1304 | void *data) |
1283 | { | 1305 | { |
1284 | struct dasd_eckd_private *private; | 1306 | struct dasd_eckd_private *private; |
1285 | struct dasd_device *device; | 1307 | struct dasd_device *device; |
1286 | 1308 | ||
1287 | device = init_cqr->startdev; | 1309 | device = init_cqr->startdev; |
1288 | private = (struct dasd_eckd_private *) device->private; | 1310 | private = (struct dasd_eckd_private *) device->private; |
1289 | private->init_cqr_status = init_cqr->status; | 1311 | private->init_cqr_status = dasd_eckd_analysis_evaluation(init_cqr); |
1290 | dasd_sfree_request(init_cqr, device); | 1312 | dasd_sfree_request(init_cqr, device); |
1291 | dasd_kick_device(device); | 1313 | dasd_kick_device(device); |
1292 | } | 1314 | } |
1293 | 1315 | ||
1294 | static int | 1316 | static int dasd_eckd_start_analysis(struct dasd_block *block) |
1295 | dasd_eckd_start_analysis(struct dasd_block *block) | ||
1296 | { | 1317 | { |
1297 | struct dasd_eckd_private *private; | 1318 | struct dasd_eckd_private *private; |
1298 | struct dasd_ccw_req *init_cqr; | 1319 | struct dasd_ccw_req *init_cqr; |
@@ -1304,27 +1325,44 @@ dasd_eckd_start_analysis(struct dasd_block *block) | |||
1304 | init_cqr->callback = dasd_eckd_analysis_callback; | 1325 | init_cqr->callback = dasd_eckd_analysis_callback; |
1305 | init_cqr->callback_data = NULL; | 1326 | init_cqr->callback_data = NULL; |
1306 | init_cqr->expires = 5*HZ; | 1327 | init_cqr->expires = 5*HZ; |
1328 | /* first try without ERP, so we can later handle unformatted | ||
1329 | * devices as special case | ||
1330 | */ | ||
1331 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &init_cqr->flags); | ||
1332 | init_cqr->retries = 0; | ||
1307 | dasd_add_request_head(init_cqr); | 1333 | dasd_add_request_head(init_cqr); |
1308 | return -EAGAIN; | 1334 | return -EAGAIN; |
1309 | } | 1335 | } |
1310 | 1336 | ||
1311 | static int | 1337 | static int dasd_eckd_end_analysis(struct dasd_block *block) |
1312 | dasd_eckd_end_analysis(struct dasd_block *block) | ||
1313 | { | 1338 | { |
1314 | struct dasd_device *device; | 1339 | struct dasd_device *device; |
1315 | struct dasd_eckd_private *private; | 1340 | struct dasd_eckd_private *private; |
1316 | struct eckd_count *count_area; | 1341 | struct eckd_count *count_area; |
1317 | unsigned int sb, blk_per_trk; | 1342 | unsigned int sb, blk_per_trk; |
1318 | int status, i; | 1343 | int status, i; |
1344 | struct dasd_ccw_req *init_cqr; | ||
1319 | 1345 | ||
1320 | device = block->base; | 1346 | device = block->base; |
1321 | private = (struct dasd_eckd_private *) device->private; | 1347 | private = (struct dasd_eckd_private *) device->private; |
1322 | status = private->init_cqr_status; | 1348 | status = private->init_cqr_status; |
1323 | private->init_cqr_status = -1; | 1349 | private->init_cqr_status = -1; |
1324 | if (status != DASD_CQR_DONE) { | 1350 | if (status == INIT_CQR_ERROR) { |
1325 | dev_warn(&device->cdev->dev, | 1351 | /* try again, this time with full ERP */ |
1326 | "The DASD is not formatted\n"); | 1352 | init_cqr = dasd_eckd_analysis_ccw(device); |
1353 | dasd_sleep_on(init_cqr); | ||
1354 | status = dasd_eckd_analysis_evaluation(init_cqr); | ||
1355 | dasd_sfree_request(init_cqr, device); | ||
1356 | } | ||
1357 | |||
1358 | if (status == INIT_CQR_UNFORMATTED) { | ||
1359 | dev_warn(&device->cdev->dev, "The DASD is not formatted\n"); | ||
1327 | return -EMEDIUMTYPE; | 1360 | return -EMEDIUMTYPE; |
1361 | } else if (status == INIT_CQR_ERROR) { | ||
1362 | dev_err(&device->cdev->dev, | ||
1363 | "Detecting the DASD disk layout failed because " | ||
1364 | "of an I/O error\n"); | ||
1365 | return -EIO; | ||
1328 | } | 1366 | } |
1329 | 1367 | ||
1330 | private->uses_cdl = 1; | 1368 | private->uses_cdl = 1; |
@@ -1616,8 +1654,7 @@ dasd_eckd_format_device(struct dasd_device * device, | |||
1616 | } | 1654 | } |
1617 | fcp->startdev = device; | 1655 | fcp->startdev = device; |
1618 | fcp->memdev = device; | 1656 | fcp->memdev = device; |
1619 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags); | 1657 | fcp->retries = 256; |
1620 | fcp->retries = 5; /* set retry counter to enable default ERP */ | ||
1621 | fcp->buildclk = get_clock(); | 1658 | fcp->buildclk = get_clock(); |
1622 | fcp->status = DASD_CQR_FILLED; | 1659 | fcp->status = DASD_CQR_FILLED; |
1623 | return fcp; | 1660 | return fcp; |
@@ -2699,6 +2736,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp) | |||
2699 | cqr->startdev = device; | 2736 | cqr->startdev = device; |
2700 | cqr->memdev = device; | 2737 | cqr->memdev = device; |
2701 | cqr->retries = 0; | 2738 | cqr->retries = 0; |
2739 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | ||
2702 | cqr->expires = 10 * HZ; | 2740 | cqr->expires = 10 * HZ; |
2703 | 2741 | ||
2704 | /* Prepare for Read Subsystem Data */ | 2742 | /* Prepare for Read Subsystem Data */ |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 8afd9fa00875..8c2ea045188e 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -595,6 +595,9 @@ int dasd_generic_restore_device(struct ccw_device *); | |||
595 | int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); | 595 | int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); |
596 | char *dasd_get_sense(struct irb *); | 596 | char *dasd_get_sense(struct irb *); |
597 | 597 | ||
598 | void dasd_device_set_stop_bits(struct dasd_device *, int); | ||
599 | void dasd_device_remove_stop_bits(struct dasd_device *, int); | ||
600 | |||
598 | /* externals in dasd_devmap.c */ | 601 | /* externals in dasd_devmap.c */ |
599 | extern int dasd_max_devindex; | 602 | extern int dasd_max_devindex; |
600 | extern int dasd_probeonly; | 603 | extern int dasd_probeonly; |
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index f756a1b0c57a..478bcdb90b6f 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
@@ -101,7 +101,7 @@ static int dasd_ioctl_quiesce(struct dasd_block *block) | |||
101 | pr_info("%s: The DASD has been put in the quiesce " | 101 | pr_info("%s: The DASD has been put in the quiesce " |
102 | "state\n", dev_name(&base->cdev->dev)); | 102 | "state\n", dev_name(&base->cdev->dev)); |
103 | spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); | 103 | spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); |
104 | base->stopped |= DASD_STOPPED_QUIESCE; | 104 | dasd_device_set_stop_bits(base, DASD_STOPPED_QUIESCE); |
105 | spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); | 105 | spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); |
106 | return 0; | 106 | return 0; |
107 | } | 107 | } |
@@ -122,7 +122,7 @@ static int dasd_ioctl_resume(struct dasd_block *block) | |||
122 | pr_info("%s: I/O operations have been resumed " | 122 | pr_info("%s: I/O operations have been resumed " |
123 | "on the DASD\n", dev_name(&base->cdev->dev)); | 123 | "on the DASD\n", dev_name(&base->cdev->dev)); |
124 | spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); | 124 | spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); |
125 | base->stopped &= ~DASD_STOPPED_QUIESCE; | 125 | dasd_device_remove_stop_bits(base, DASD_STOPPED_QUIESCE); |
126 | spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); | 126 | spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); |
127 | 127 | ||
128 | dasd_schedule_block_bh(block); | 128 | dasd_schedule_block_bh(block); |