diff options
Diffstat (limited to 'drivers/s390')
69 files changed, 3283 insertions, 840 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d1815272c435..e5b84db0aa03 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -5,8 +5,7 @@ | |||
5 | * Carsten Otte <Cotte@de.ibm.com> | 5 | * Carsten Otte <Cotte@de.ibm.com> |
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
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 | * Copyright IBM Corp. 1999, 2009 |
9 | * | ||
10 | */ | 9 | */ |
11 | 10 | ||
12 | #define KMSG_COMPONENT "dasd" | 11 | #define KMSG_COMPONENT "dasd" |
@@ -61,6 +60,7 @@ static int dasd_flush_block_queue(struct dasd_block *); | |||
61 | static void dasd_device_tasklet(struct dasd_device *); | 60 | static void dasd_device_tasklet(struct dasd_device *); |
62 | static void dasd_block_tasklet(struct dasd_block *); | 61 | static void dasd_block_tasklet(struct dasd_block *); |
63 | static void do_kick_device(struct work_struct *); | 62 | static void do_kick_device(struct work_struct *); |
63 | static void do_restore_device(struct work_struct *); | ||
64 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); | 64 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); |
65 | static void dasd_device_timeout(unsigned long); | 65 | static void dasd_device_timeout(unsigned long); |
66 | static void dasd_block_timeout(unsigned long); | 66 | static void dasd_block_timeout(unsigned long); |
@@ -109,6 +109,7 @@ struct dasd_device *dasd_alloc_device(void) | |||
109 | device->timer.function = dasd_device_timeout; | 109 | device->timer.function = dasd_device_timeout; |
110 | device->timer.data = (unsigned long) device; | 110 | device->timer.data = (unsigned long) device; |
111 | INIT_WORK(&device->kick_work, do_kick_device); | 111 | INIT_WORK(&device->kick_work, do_kick_device); |
112 | INIT_WORK(&device->restore_device, do_restore_device); | ||
112 | device->state = DASD_STATE_NEW; | 113 | device->state = DASD_STATE_NEW; |
113 | device->target = DASD_STATE_NEW; | 114 | device->target = DASD_STATE_NEW; |
114 | 115 | ||
@@ -512,6 +513,25 @@ void dasd_kick_device(struct dasd_device *device) | |||
512 | } | 513 | } |
513 | 514 | ||
514 | /* | 515 | /* |
516 | * dasd_restore_device will schedule a call do do_restore_device to the kernel | ||
517 | * event daemon. | ||
518 | */ | ||
519 | static void do_restore_device(struct work_struct *work) | ||
520 | { | ||
521 | struct dasd_device *device = container_of(work, struct dasd_device, | ||
522 | restore_device); | ||
523 | device->cdev->drv->restore(device->cdev); | ||
524 | dasd_put_device(device); | ||
525 | } | ||
526 | |||
527 | void dasd_restore_device(struct dasd_device *device) | ||
528 | { | ||
529 | dasd_get_device(device); | ||
530 | /* queue call to dasd_restore_device to the kernel event daemon. */ | ||
531 | schedule_work(&device->restore_device); | ||
532 | } | ||
533 | |||
534 | /* | ||
515 | * Set the target state for a device and starts the state change. | 535 | * Set the target state for a device and starts the state change. |
516 | */ | 536 | */ |
517 | void dasd_set_target_state(struct dasd_device *device, int target) | 537 | void dasd_set_target_state(struct dasd_device *device, int target) |
@@ -603,7 +623,7 @@ static void dasd_profile_end(struct dasd_block *block, | |||
603 | if (dasd_profile_level != DASD_PROFILE_ON) | 623 | if (dasd_profile_level != DASD_PROFILE_ON) |
604 | return; | 624 | return; |
605 | 625 | ||
606 | sectors = req->nr_sectors; | 626 | sectors = blk_rq_sectors(req); |
607 | if (!cqr->buildclk || !cqr->startclk || | 627 | if (!cqr->buildclk || !cqr->startclk || |
608 | !cqr->stopclk || !cqr->endclk || | 628 | !cqr->stopclk || !cqr->endclk || |
609 | !sectors) | 629 | !sectors) |
@@ -851,8 +871,10 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
851 | 871 | ||
852 | /* Check the cqr */ | 872 | /* Check the cqr */ |
853 | rc = dasd_check_cqr(cqr); | 873 | rc = dasd_check_cqr(cqr); |
854 | if (rc) | 874 | if (rc) { |
875 | cqr->intrc = rc; | ||
855 | return rc; | 876 | return rc; |
877 | } | ||
856 | device = (struct dasd_device *) cqr->startdev; | 878 | device = (struct dasd_device *) cqr->startdev; |
857 | if (cqr->retries < 0) { | 879 | if (cqr->retries < 0) { |
858 | /* internal error 14 - start_IO run out of retries */ | 880 | /* internal error 14 - start_IO run out of retries */ |
@@ -906,6 +928,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
906 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 928 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", |
907 | "start_IO: -EIO device gone, retry"); | 929 | "start_IO: -EIO device gone, retry"); |
908 | break; | 930 | break; |
931 | case -EINVAL: | ||
932 | /* most likely caused in power management context */ | ||
933 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | ||
934 | "start_IO: -EINVAL device currently " | ||
935 | "not accessible"); | ||
936 | break; | ||
909 | default: | 937 | default: |
910 | /* internal error 11 - unknown rc */ | 938 | /* internal error 11 - unknown rc */ |
911 | snprintf(errorstring, ERRORLENGTH, "11 %d", rc); | 939 | snprintf(errorstring, ERRORLENGTH, "11 %d", rc); |
@@ -915,6 +943,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
915 | BUG(); | 943 | BUG(); |
916 | break; | 944 | break; |
917 | } | 945 | } |
946 | cqr->intrc = rc; | ||
918 | return rc; | 947 | return rc; |
919 | } | 948 | } |
920 | 949 | ||
@@ -1454,8 +1483,12 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr) | |||
1454 | dasd_add_request_tail(cqr); | 1483 | dasd_add_request_tail(cqr); |
1455 | wait_event(generic_waitq, _wait_for_wakeup(cqr)); | 1484 | wait_event(generic_waitq, _wait_for_wakeup(cqr)); |
1456 | 1485 | ||
1457 | /* Request status is either done or failed. */ | 1486 | if (cqr->status == DASD_CQR_DONE) |
1458 | rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; | 1487 | rc = 0; |
1488 | else if (cqr->intrc) | ||
1489 | rc = cqr->intrc; | ||
1490 | else | ||
1491 | rc = -EIO; | ||
1459 | return rc; | 1492 | return rc; |
1460 | } | 1493 | } |
1461 | 1494 | ||
@@ -1477,8 +1510,15 @@ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) | |||
1477 | dasd_cancel_req(cqr); | 1510 | dasd_cancel_req(cqr); |
1478 | /* wait (non-interruptible) for final status */ | 1511 | /* wait (non-interruptible) for final status */ |
1479 | wait_event(generic_waitq, _wait_for_wakeup(cqr)); | 1512 | wait_event(generic_waitq, _wait_for_wakeup(cqr)); |
1513 | cqr->intrc = rc; | ||
1480 | } | 1514 | } |
1481 | rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; | 1515 | |
1516 | if (cqr->status == DASD_CQR_DONE) | ||
1517 | rc = 0; | ||
1518 | else if (cqr->intrc) | ||
1519 | rc = cqr->intrc; | ||
1520 | else | ||
1521 | rc = -EIO; | ||
1482 | return rc; | 1522 | return rc; |
1483 | } | 1523 | } |
1484 | 1524 | ||
@@ -1523,8 +1563,12 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) | |||
1523 | 1563 | ||
1524 | wait_event(generic_waitq, _wait_for_wakeup(cqr)); | 1564 | wait_event(generic_waitq, _wait_for_wakeup(cqr)); |
1525 | 1565 | ||
1526 | /* Request status is either done or failed. */ | 1566 | if (cqr->status == DASD_CQR_DONE) |
1527 | rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; | 1567 | rc = 0; |
1568 | else if (cqr->intrc) | ||
1569 | rc = cqr->intrc; | ||
1570 | else | ||
1571 | rc = -EIO; | ||
1528 | return rc; | 1572 | return rc; |
1529 | } | 1573 | } |
1530 | 1574 | ||
@@ -1614,15 +1658,6 @@ void dasd_block_clear_timer(struct dasd_block *block) | |||
1614 | } | 1658 | } |
1615 | 1659 | ||
1616 | /* | 1660 | /* |
1617 | * posts the buffer_cache about a finalized request | ||
1618 | */ | ||
1619 | static inline void dasd_end_request(struct request *req, int error) | ||
1620 | { | ||
1621 | if (__blk_end_request(req, error, blk_rq_bytes(req))) | ||
1622 | BUG(); | ||
1623 | } | ||
1624 | |||
1625 | /* | ||
1626 | * Process finished error recovery ccw. | 1661 | * Process finished error recovery ccw. |
1627 | */ | 1662 | */ |
1628 | static inline void __dasd_block_process_erp(struct dasd_block *block, | 1663 | static inline void __dasd_block_process_erp(struct dasd_block *block, |
@@ -1665,18 +1700,14 @@ static void __dasd_process_request_queue(struct dasd_block *block) | |||
1665 | if (basedev->state < DASD_STATE_READY) | 1700 | if (basedev->state < DASD_STATE_READY) |
1666 | return; | 1701 | return; |
1667 | /* Now we try to fetch requests from the request queue */ | 1702 | /* Now we try to fetch requests from the request queue */ |
1668 | while (!blk_queue_plugged(queue) && | 1703 | while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) { |
1669 | elv_next_request(queue)) { | ||
1670 | |||
1671 | req = elv_next_request(queue); | ||
1672 | |||
1673 | if (basedev->features & DASD_FEATURE_READONLY && | 1704 | if (basedev->features & DASD_FEATURE_READONLY && |
1674 | rq_data_dir(req) == WRITE) { | 1705 | rq_data_dir(req) == WRITE) { |
1675 | DBF_DEV_EVENT(DBF_ERR, basedev, | 1706 | DBF_DEV_EVENT(DBF_ERR, basedev, |
1676 | "Rejecting write request %p", | 1707 | "Rejecting write request %p", |
1677 | req); | 1708 | req); |
1678 | blkdev_dequeue_request(req); | 1709 | blk_start_request(req); |
1679 | dasd_end_request(req, -EIO); | 1710 | __blk_end_request_all(req, -EIO); |
1680 | continue; | 1711 | continue; |
1681 | } | 1712 | } |
1682 | cqr = basedev->discipline->build_cp(basedev, block, req); | 1713 | cqr = basedev->discipline->build_cp(basedev, block, req); |
@@ -1704,8 +1735,8 @@ static void __dasd_process_request_queue(struct dasd_block *block) | |||
1704 | "CCW creation failed (rc=%ld) " | 1735 | "CCW creation failed (rc=%ld) " |
1705 | "on request %p", | 1736 | "on request %p", |
1706 | PTR_ERR(cqr), req); | 1737 | PTR_ERR(cqr), req); |
1707 | blkdev_dequeue_request(req); | 1738 | blk_start_request(req); |
1708 | dasd_end_request(req, -EIO); | 1739 | __blk_end_request_all(req, -EIO); |
1709 | continue; | 1740 | continue; |
1710 | } | 1741 | } |
1711 | /* | 1742 | /* |
@@ -1714,7 +1745,7 @@ static void __dasd_process_request_queue(struct dasd_block *block) | |||
1714 | */ | 1745 | */ |
1715 | cqr->callback_data = (void *) req; | 1746 | cqr->callback_data = (void *) req; |
1716 | cqr->status = DASD_CQR_FILLED; | 1747 | cqr->status = DASD_CQR_FILLED; |
1717 | blkdev_dequeue_request(req); | 1748 | blk_start_request(req); |
1718 | list_add_tail(&cqr->blocklist, &block->ccw_queue); | 1749 | list_add_tail(&cqr->blocklist, &block->ccw_queue); |
1719 | dasd_profile_start(block, cqr, req); | 1750 | dasd_profile_start(block, cqr, req); |
1720 | } | 1751 | } |
@@ -1731,7 +1762,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr) | |||
1731 | status = cqr->block->base->discipline->free_cp(cqr, req); | 1762 | status = cqr->block->base->discipline->free_cp(cqr, req); |
1732 | if (status <= 0) | 1763 | if (status <= 0) |
1733 | error = status ? status : -EIO; | 1764 | error = status ? status : -EIO; |
1734 | dasd_end_request(req, error); | 1765 | __blk_end_request_all(req, error); |
1735 | } | 1766 | } |
1736 | 1767 | ||
1737 | /* | 1768 | /* |
@@ -2003,7 +2034,7 @@ static void dasd_setup_queue(struct dasd_block *block) | |||
2003 | { | 2034 | { |
2004 | int max; | 2035 | int max; |
2005 | 2036 | ||
2006 | blk_queue_hardsect_size(block->request_queue, block->bp_block); | 2037 | blk_queue_logical_block_size(block->request_queue, block->bp_block); |
2007 | max = block->base->discipline->max_blocks << block->s2b_shift; | 2038 | max = block->base->discipline->max_blocks << block->s2b_shift; |
2008 | blk_queue_max_sectors(block->request_queue, max); | 2039 | blk_queue_max_sectors(block->request_queue, max); |
2009 | blk_queue_max_phys_segments(block->request_queue, -1L); | 2040 | blk_queue_max_phys_segments(block->request_queue, -1L); |
@@ -2038,10 +2069,8 @@ static void dasd_flush_request_queue(struct dasd_block *block) | |||
2038 | return; | 2069 | return; |
2039 | 2070 | ||
2040 | spin_lock_irq(&block->request_queue_lock); | 2071 | spin_lock_irq(&block->request_queue_lock); |
2041 | while ((req = elv_next_request(block->request_queue))) { | 2072 | while ((req = blk_fetch_request(block->request_queue))) |
2042 | blkdev_dequeue_request(req); | 2073 | __blk_end_request_all(req, -EIO); |
2043 | dasd_end_request(req, -EIO); | ||
2044 | } | ||
2045 | spin_unlock_irq(&block->request_queue_lock); | 2074 | spin_unlock_irq(&block->request_queue_lock); |
2046 | } | 2075 | } |
2047 | 2076 | ||
@@ -2397,6 +2426,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) | |||
2397 | case CIO_OPER: | 2426 | case CIO_OPER: |
2398 | /* FIXME: add a sanity check. */ | 2427 | /* FIXME: add a sanity check. */ |
2399 | device->stopped &= ~DASD_STOPPED_DC_WAIT; | 2428 | device->stopped &= ~DASD_STOPPED_DC_WAIT; |
2429 | if (device->stopped & DASD_UNRESUMED_PM) { | ||
2430 | device->stopped &= ~DASD_UNRESUMED_PM; | ||
2431 | dasd_restore_device(device); | ||
2432 | ret = 1; | ||
2433 | break; | ||
2434 | } | ||
2400 | dasd_schedule_device_bh(device); | 2435 | dasd_schedule_device_bh(device); |
2401 | if (device->block) | 2436 | if (device->block) |
2402 | dasd_schedule_block_bh(device->block); | 2437 | dasd_schedule_block_bh(device->block); |
@@ -2407,6 +2442,79 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) | |||
2407 | return ret; | 2442 | return ret; |
2408 | } | 2443 | } |
2409 | 2444 | ||
2445 | int dasd_generic_pm_freeze(struct ccw_device *cdev) | ||
2446 | { | ||
2447 | struct dasd_ccw_req *cqr, *n; | ||
2448 | int rc; | ||
2449 | struct list_head freeze_queue; | ||
2450 | struct dasd_device *device = dasd_device_from_cdev(cdev); | ||
2451 | |||
2452 | if (IS_ERR(device)) | ||
2453 | return PTR_ERR(device); | ||
2454 | /* disallow new I/O */ | ||
2455 | device->stopped |= DASD_STOPPED_PM; | ||
2456 | /* clear active requests */ | ||
2457 | INIT_LIST_HEAD(&freeze_queue); | ||
2458 | spin_lock_irq(get_ccwdev_lock(cdev)); | ||
2459 | rc = 0; | ||
2460 | list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) { | ||
2461 | /* Check status and move request to flush_queue */ | ||
2462 | if (cqr->status == DASD_CQR_IN_IO) { | ||
2463 | rc = device->discipline->term_IO(cqr); | ||
2464 | if (rc) { | ||
2465 | /* unable to terminate requeust */ | ||
2466 | dev_err(&device->cdev->dev, | ||
2467 | "Unable to terminate request %p " | ||
2468 | "on suspend\n", cqr); | ||
2469 | spin_unlock_irq(get_ccwdev_lock(cdev)); | ||
2470 | dasd_put_device(device); | ||
2471 | return rc; | ||
2472 | } | ||
2473 | } | ||
2474 | list_move_tail(&cqr->devlist, &freeze_queue); | ||
2475 | } | ||
2476 | |||
2477 | spin_unlock_irq(get_ccwdev_lock(cdev)); | ||
2478 | |||
2479 | list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) { | ||
2480 | wait_event(dasd_flush_wq, | ||
2481 | (cqr->status != DASD_CQR_CLEAR_PENDING)); | ||
2482 | if (cqr->status == DASD_CQR_CLEARED) | ||
2483 | cqr->status = DASD_CQR_QUEUED; | ||
2484 | } | ||
2485 | /* move freeze_queue to start of the ccw_queue */ | ||
2486 | spin_lock_irq(get_ccwdev_lock(cdev)); | ||
2487 | list_splice_tail(&freeze_queue, &device->ccw_queue); | ||
2488 | spin_unlock_irq(get_ccwdev_lock(cdev)); | ||
2489 | |||
2490 | if (device->discipline->freeze) | ||
2491 | rc = device->discipline->freeze(device); | ||
2492 | |||
2493 | dasd_put_device(device); | ||
2494 | return rc; | ||
2495 | } | ||
2496 | EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze); | ||
2497 | |||
2498 | int dasd_generic_restore_device(struct ccw_device *cdev) | ||
2499 | { | ||
2500 | struct dasd_device *device = dasd_device_from_cdev(cdev); | ||
2501 | int rc = 0; | ||
2502 | |||
2503 | if (IS_ERR(device)) | ||
2504 | return PTR_ERR(device); | ||
2505 | |||
2506 | dasd_schedule_device_bh(device); | ||
2507 | if (device->block) | ||
2508 | dasd_schedule_block_bh(device->block); | ||
2509 | |||
2510 | if (device->discipline->restore) | ||
2511 | rc = device->discipline->restore(device); | ||
2512 | |||
2513 | dasd_put_device(device); | ||
2514 | return rc; | ||
2515 | } | ||
2516 | EXPORT_SYMBOL_GPL(dasd_generic_restore_device); | ||
2517 | |||
2410 | static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, | 2518 | static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, |
2411 | void *rdc_buffer, | 2519 | void *rdc_buffer, |
2412 | int rdc_buffer_size, | 2520 | int rdc_buffer_size, |
@@ -2442,12 +2550,12 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, | |||
2442 | 2550 | ||
2443 | 2551 | ||
2444 | int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, | 2552 | int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, |
2445 | void **rdc_buffer, int rdc_buffer_size) | 2553 | void *rdc_buffer, int rdc_buffer_size) |
2446 | { | 2554 | { |
2447 | int ret; | 2555 | int ret; |
2448 | struct dasd_ccw_req *cqr; | 2556 | struct dasd_ccw_req *cqr; |
2449 | 2557 | ||
2450 | cqr = dasd_generic_build_rdc(device, *rdc_buffer, rdc_buffer_size, | 2558 | cqr = dasd_generic_build_rdc(device, rdc_buffer, rdc_buffer_size, |
2451 | magic); | 2559 | magic); |
2452 | if (IS_ERR(cqr)) | 2560 | if (IS_ERR(cqr)) |
2453 | return PTR_ERR(cqr); | 2561 | return PTR_ERR(cqr); |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index e77666c8e6c0..4cac5b54f26a 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -1098,6 +1098,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) | |||
1098 | spin_unlock(&dasd_devmap_lock); | 1098 | spin_unlock(&dasd_devmap_lock); |
1099 | return 0; | 1099 | return 0; |
1100 | } | 1100 | } |
1101 | EXPORT_SYMBOL_GPL(dasd_get_uid); | ||
1101 | 1102 | ||
1102 | /* | 1103 | /* |
1103 | * Register the given device unique identifier into devmap struct. | 1104 | * Register the given device unique identifier into devmap struct. |
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index b9a7f7733446..644086ba2ede 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c | |||
@@ -202,6 +202,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr) | |||
202 | rc = -EIO; | 202 | rc = -EIO; |
203 | break; | 203 | break; |
204 | } | 204 | } |
205 | cqr->intrc = rc; | ||
205 | return rc; | 206 | return rc; |
206 | } | 207 | } |
207 | 208 | ||
@@ -505,8 +506,9 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, | |||
505 | return ERR_PTR(-EINVAL); | 506 | return ERR_PTR(-EINVAL); |
506 | blksize = block->bp_block; | 507 | blksize = block->bp_block; |
507 | /* Calculate record id of first and last block. */ | 508 | /* Calculate record id of first and last block. */ |
508 | first_rec = req->sector >> block->s2b_shift; | 509 | first_rec = blk_rq_pos(req) >> block->s2b_shift; |
509 | last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift; | 510 | last_rec = |
511 | (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; | ||
510 | /* Check struct bio and count the number of blocks for the request. */ | 512 | /* Check struct bio and count the number of blocks for the request. */ |
511 | count = 0; | 513 | count = 0; |
512 | rq_for_each_segment(bv, req, iter) { | 514 | rq_for_each_segment(bv, req, iter) { |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index cb52da033f06..1c28ec3e4ccb 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -5,10 +5,9 @@ | |||
5 | * Carsten Otte <Cotte@de.ibm.com> | 5 | * Carsten Otte <Cotte@de.ibm.com> |
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
7 | * Bugreports.to..: <Linux390@de.ibm.com> | 7 | * Bugreports.to..: <Linux390@de.ibm.com> |
8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 8 | * Copyright IBM Corp. 1999, 2009 |
9 | * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 | 9 | * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 |
10 | * Author.........: Nigel Hislop <hislop_nigel@emc.com> | 10 | * Author.........: Nigel Hislop <hislop_nigel@emc.com> |
11 | * | ||
12 | */ | 11 | */ |
13 | 12 | ||
14 | #define KMSG_COMPONENT "dasd" | 13 | #define KMSG_COMPONENT "dasd" |
@@ -104,17 +103,6 @@ dasd_eckd_set_online(struct ccw_device *cdev) | |||
104 | return dasd_generic_set_online(cdev, &dasd_eckd_discipline); | 103 | return dasd_generic_set_online(cdev, &dasd_eckd_discipline); |
105 | } | 104 | } |
106 | 105 | ||
107 | static struct ccw_driver dasd_eckd_driver = { | ||
108 | .name = "dasd-eckd", | ||
109 | .owner = THIS_MODULE, | ||
110 | .ids = dasd_eckd_ids, | ||
111 | .probe = dasd_eckd_probe, | ||
112 | .remove = dasd_generic_remove, | ||
113 | .set_offline = dasd_generic_set_offline, | ||
114 | .set_online = dasd_eckd_set_online, | ||
115 | .notify = dasd_generic_notify, | ||
116 | }; | ||
117 | |||
118 | static const int sizes_trk0[] = { 28, 148, 84 }; | 106 | static const int sizes_trk0[] = { 28, 148, 84 }; |
119 | #define LABEL_SIZE 140 | 107 | #define LABEL_SIZE 140 |
120 | 108 | ||
@@ -1097,20 +1085,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1097 | { | 1085 | { |
1098 | struct dasd_eckd_private *private; | 1086 | struct dasd_eckd_private *private; |
1099 | struct dasd_block *block; | 1087 | struct dasd_block *block; |
1100 | void *rdc_data; | ||
1101 | int is_known, rc; | 1088 | int is_known, rc; |
1102 | 1089 | ||
1103 | private = (struct dasd_eckd_private *) device->private; | 1090 | private = (struct dasd_eckd_private *) device->private; |
1104 | if (private == NULL) { | 1091 | if (!private) { |
1105 | private = kzalloc(sizeof(struct dasd_eckd_private), | 1092 | private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); |
1106 | GFP_KERNEL | GFP_DMA); | 1093 | if (!private) { |
1107 | if (private == NULL) { | ||
1108 | dev_warn(&device->cdev->dev, | 1094 | dev_warn(&device->cdev->dev, |
1109 | "Allocating memory for private DASD data " | 1095 | "Allocating memory for private DASD data " |
1110 | "failed\n"); | 1096 | "failed\n"); |
1111 | return -ENOMEM; | 1097 | return -ENOMEM; |
1112 | } | 1098 | } |
1113 | device->private = (void *) private; | 1099 | device->private = (void *) private; |
1100 | } else { | ||
1101 | memset(private, 0, sizeof(*private)); | ||
1114 | } | 1102 | } |
1115 | /* Invalidate status of initial analysis. */ | 1103 | /* Invalidate status of initial analysis. */ |
1116 | private->init_cqr_status = -1; | 1104 | private->init_cqr_status = -1; |
@@ -1161,9 +1149,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1161 | goto out_err3; | 1149 | goto out_err3; |
1162 | 1150 | ||
1163 | /* Read Device Characteristics */ | 1151 | /* Read Device Characteristics */ |
1164 | rdc_data = (void *) &(private->rdc_data); | 1152 | rc = dasd_generic_read_dev_chars(device, "ECKD", &private->rdc_data, |
1165 | memset(rdc_data, 0, sizeof(rdc_data)); | 1153 | 64); |
1166 | rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64); | ||
1167 | if (rc) { | 1154 | if (rc) { |
1168 | DBF_EVENT(DBF_WARNING, | 1155 | DBF_EVENT(DBF_WARNING, |
1169 | "Read device characteristics failed, rc=%d for " | 1156 | "Read device characteristics failed, rc=%d for " |
@@ -1183,7 +1170,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1183 | private->rdc_data.dev_model, | 1170 | private->rdc_data.dev_model, |
1184 | private->rdc_data.cu_type, | 1171 | private->rdc_data.cu_type, |
1185 | private->rdc_data.cu_model.model, | 1172 | private->rdc_data.cu_model.model, |
1186 | private->real_cyl, | 1173 | private->real_cyl, |
1187 | private->rdc_data.trk_per_cyl, | 1174 | private->rdc_data.trk_per_cyl, |
1188 | private->rdc_data.sec_per_trk); | 1175 | private->rdc_data.sec_per_trk); |
1189 | return 0; | 1176 | return 0; |
@@ -2336,9 +2323,10 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
2336 | { | 2323 | { |
2337 | int tpm, cmdrtd, cmdwtd; | 2324 | int tpm, cmdrtd, cmdwtd; |
2338 | int use_prefix; | 2325 | int use_prefix; |
2339 | 2326 | #if defined(CONFIG_64BIT) | |
2340 | struct dasd_eckd_private *private; | ||
2341 | int fcx_in_css, fcx_in_gneq, fcx_in_features; | 2327 | int fcx_in_css, fcx_in_gneq, fcx_in_features; |
2328 | #endif | ||
2329 | struct dasd_eckd_private *private; | ||
2342 | struct dasd_device *basedev; | 2330 | struct dasd_device *basedev; |
2343 | sector_t first_rec, last_rec; | 2331 | sector_t first_rec, last_rec; |
2344 | sector_t first_trk, last_trk; | 2332 | sector_t first_trk, last_trk; |
@@ -2354,18 +2342,22 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
2354 | blksize = block->bp_block; | 2342 | blksize = block->bp_block; |
2355 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); | 2343 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); |
2356 | /* Calculate record id of first and last block. */ | 2344 | /* Calculate record id of first and last block. */ |
2357 | first_rec = first_trk = req->sector >> block->s2b_shift; | 2345 | first_rec = first_trk = blk_rq_pos(req) >> block->s2b_shift; |
2358 | first_offs = sector_div(first_trk, blk_per_trk); | 2346 | first_offs = sector_div(first_trk, blk_per_trk); |
2359 | last_rec = last_trk = | 2347 | last_rec = last_trk = |
2360 | (req->sector + req->nr_sectors - 1) >> block->s2b_shift; | 2348 | (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; |
2361 | last_offs = sector_div(last_trk, blk_per_trk); | 2349 | last_offs = sector_div(last_trk, blk_per_trk); |
2362 | cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); | 2350 | cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); |
2363 | 2351 | ||
2364 | /* is transport mode supported ? */ | 2352 | /* is transport mode supported? */ |
2353 | #if defined(CONFIG_64BIT) | ||
2365 | fcx_in_css = css_general_characteristics.fcx; | 2354 | fcx_in_css = css_general_characteristics.fcx; |
2366 | fcx_in_gneq = private->gneq->reserved2[7] & 0x04; | 2355 | fcx_in_gneq = private->gneq->reserved2[7] & 0x04; |
2367 | fcx_in_features = private->features.feature[40] & 0x80; | 2356 | fcx_in_features = private->features.feature[40] & 0x80; |
2368 | tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; | 2357 | tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; |
2358 | #else | ||
2359 | tpm = 0; | ||
2360 | #endif | ||
2369 | 2361 | ||
2370 | /* is read track data and write track data in command mode supported? */ | 2362 | /* is read track data and write track data in command mode supported? */ |
2371 | cmdrtd = private->features.feature[9] & 0x20; | 2363 | cmdrtd = private->features.feature[9] & 0x20; |
@@ -2420,7 +2412,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) | |||
2420 | private = (struct dasd_eckd_private *) cqr->block->base->private; | 2412 | private = (struct dasd_eckd_private *) cqr->block->base->private; |
2421 | blksize = cqr->block->bp_block; | 2413 | blksize = cqr->block->bp_block; |
2422 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); | 2414 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); |
2423 | recid = req->sector >> cqr->block->s2b_shift; | 2415 | recid = blk_rq_pos(req) >> cqr->block->s2b_shift; |
2424 | ccw = cqr->cpaddr; | 2416 | ccw = cqr->cpaddr; |
2425 | /* Skip over define extent & locate record. */ | 2417 | /* Skip over define extent & locate record. */ |
2426 | ccw++; | 2418 | ccw++; |
@@ -3013,8 +3005,9 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, | |||
3013 | " I/O status report for device %s:\n", | 3005 | " I/O status report for device %s:\n", |
3014 | dev_name(&device->cdev->dev)); | 3006 | dev_name(&device->cdev->dev)); |
3015 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3007 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
3016 | " in req: %p CS: 0x%02X DS: 0x%02X\n", req, | 3008 | " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n", |
3017 | scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw)); | 3009 | req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), |
3010 | scsw_cc(&irb->scsw), req->intrc); | ||
3018 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3011 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
3019 | " device %s: Failing CCW: %p\n", | 3012 | " device %s: Failing CCW: %p\n", |
3020 | dev_name(&device->cdev->dev), | 3013 | dev_name(&device->cdev->dev), |
@@ -3115,9 +3108,10 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, | |||
3115 | " I/O status report for device %s:\n", | 3108 | " I/O status report for device %s:\n", |
3116 | dev_name(&device->cdev->dev)); | 3109 | dev_name(&device->cdev->dev)); |
3117 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3110 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
3118 | " in req: %p CS: 0x%02X DS: 0x%02X " | 3111 | " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d " |
3119 | "fcxs: 0x%02X schxs: 0x%02X\n", req, | 3112 | "fcxs: 0x%02X schxs: 0x%02X\n", req, |
3120 | scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), | 3113 | scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), |
3114 | scsw_cc(&irb->scsw), req->intrc, | ||
3121 | irb->scsw.tm.fcxs, irb->scsw.tm.schxs); | 3115 | irb->scsw.tm.fcxs, irb->scsw.tm.schxs); |
3122 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 3116 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
3123 | " device %s: Failing TCW: %p\n", | 3117 | " device %s: Failing TCW: %p\n", |
@@ -3230,6 +3224,98 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, | |||
3230 | dasd_eckd_dump_sense_ccw(device, req, irb); | 3224 | dasd_eckd_dump_sense_ccw(device, req, irb); |
3231 | } | 3225 | } |
3232 | 3226 | ||
3227 | int dasd_eckd_pm_freeze(struct dasd_device *device) | ||
3228 | { | ||
3229 | /* | ||
3230 | * the device should be disconnected from our LCU structure | ||
3231 | * on restore we will reconnect it and reread LCU specific | ||
3232 | * information like PAV support that might have changed | ||
3233 | */ | ||
3234 | dasd_alias_remove_device(device); | ||
3235 | dasd_alias_disconnect_device_from_lcu(device); | ||
3236 | |||
3237 | return 0; | ||
3238 | } | ||
3239 | |||
3240 | int dasd_eckd_restore_device(struct dasd_device *device) | ||
3241 | { | ||
3242 | struct dasd_eckd_private *private; | ||
3243 | int is_known, rc; | ||
3244 | struct dasd_uid temp_uid; | ||
3245 | |||
3246 | /* allow new IO again */ | ||
3247 | device->stopped &= ~DASD_STOPPED_PM; | ||
3248 | |||
3249 | private = (struct dasd_eckd_private *) device->private; | ||
3250 | |||
3251 | /* Read Configuration Data */ | ||
3252 | rc = dasd_eckd_read_conf(device); | ||
3253 | if (rc) | ||
3254 | goto out_err; | ||
3255 | |||
3256 | /* Generate device unique id and register in devmap */ | ||
3257 | rc = dasd_eckd_generate_uid(device, &private->uid); | ||
3258 | dasd_get_uid(device->cdev, &temp_uid); | ||
3259 | if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) | ||
3260 | dev_err(&device->cdev->dev, "The UID of the DASD has changed\n"); | ||
3261 | if (rc) | ||
3262 | goto out_err; | ||
3263 | dasd_set_uid(device->cdev, &private->uid); | ||
3264 | |||
3265 | /* register lcu with alias handling, enable PAV if this is a new lcu */ | ||
3266 | is_known = dasd_alias_make_device_known_to_lcu(device); | ||
3267 | if (is_known < 0) | ||
3268 | return is_known; | ||
3269 | if (!is_known) { | ||
3270 | /* new lcu found */ | ||
3271 | rc = dasd_eckd_validate_server(device); /* will switch pav on */ | ||
3272 | if (rc) | ||
3273 | goto out_err; | ||
3274 | } | ||
3275 | |||
3276 | /* Read Feature Codes */ | ||
3277 | rc = dasd_eckd_read_features(device); | ||
3278 | if (rc) | ||
3279 | goto out_err; | ||
3280 | |||
3281 | /* Read Device Characteristics */ | ||
3282 | memset(&private->rdc_data, 0, sizeof(private->rdc_data)); | ||
3283 | rc = dasd_generic_read_dev_chars(device, "ECKD", | ||
3284 | &private->rdc_data, 64); | ||
3285 | if (rc) { | ||
3286 | DBF_EVENT(DBF_WARNING, | ||
3287 | "Read device characteristics failed, rc=%d for " | ||
3288 | "device: %s", rc, dev_name(&device->cdev->dev)); | ||
3289 | goto out_err; | ||
3290 | } | ||
3291 | |||
3292 | /* add device to alias management */ | ||
3293 | dasd_alias_add_device(device); | ||
3294 | |||
3295 | return 0; | ||
3296 | |||
3297 | out_err: | ||
3298 | /* | ||
3299 | * if the resume failed for the DASD we put it in | ||
3300 | * an UNRESUMED stop state | ||
3301 | */ | ||
3302 | device->stopped |= DASD_UNRESUMED_PM; | ||
3303 | return 0; | ||
3304 | } | ||
3305 | |||
3306 | static struct ccw_driver dasd_eckd_driver = { | ||
3307 | .name = "dasd-eckd", | ||
3308 | .owner = THIS_MODULE, | ||
3309 | .ids = dasd_eckd_ids, | ||
3310 | .probe = dasd_eckd_probe, | ||
3311 | .remove = dasd_generic_remove, | ||
3312 | .set_offline = dasd_generic_set_offline, | ||
3313 | .set_online = dasd_eckd_set_online, | ||
3314 | .notify = dasd_generic_notify, | ||
3315 | .freeze = dasd_generic_pm_freeze, | ||
3316 | .thaw = dasd_generic_restore_device, | ||
3317 | .restore = dasd_generic_restore_device, | ||
3318 | }; | ||
3233 | 3319 | ||
3234 | /* | 3320 | /* |
3235 | * max_blocks is dependent on the amount of storage that is available | 3321 | * max_blocks is dependent on the amount of storage that is available |
@@ -3268,13 +3354,21 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
3268 | .dump_sense_dbf = dasd_eckd_dump_sense_dbf, | 3354 | .dump_sense_dbf = dasd_eckd_dump_sense_dbf, |
3269 | .fill_info = dasd_eckd_fill_info, | 3355 | .fill_info = dasd_eckd_fill_info, |
3270 | .ioctl = dasd_eckd_ioctl, | 3356 | .ioctl = dasd_eckd_ioctl, |
3357 | .freeze = dasd_eckd_pm_freeze, | ||
3358 | .restore = dasd_eckd_restore_device, | ||
3271 | }; | 3359 | }; |
3272 | 3360 | ||
3273 | static int __init | 3361 | static int __init |
3274 | dasd_eckd_init(void) | 3362 | dasd_eckd_init(void) |
3275 | { | 3363 | { |
3364 | int ret; | ||
3365 | |||
3276 | ASCEBC(dasd_eckd_discipline.ebcname, 4); | 3366 | ASCEBC(dasd_eckd_discipline.ebcname, 4); |
3277 | return ccw_driver_register(&dasd_eckd_driver); | 3367 | ret = ccw_driver_register(&dasd_eckd_driver); |
3368 | if (!ret) | ||
3369 | wait_for_device_probe(); | ||
3370 | |||
3371 | return ret; | ||
3278 | } | 3372 | } |
3279 | 3373 | ||
3280 | static void __exit | 3374 | static void __exit |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index a3eb6fd14673..e21ee735f926 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * File...........: linux/drivers/s390/block/dasd_fba.c | 2 | * File...........: linux/drivers/s390/block/dasd_fba.c |
3 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> | 3 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> |
4 | * Bugreports.to..: <Linux390@de.ibm.com> | 4 | * Bugreports.to..: <Linux390@de.ibm.com> |
5 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 5 | * Copyright IBM Corp. 1999, 2009 |
6 | * | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #define KMSG_COMPONENT "dasd" | 8 | #define KMSG_COMPONENT "dasd" |
@@ -75,6 +74,9 @@ static struct ccw_driver dasd_fba_driver = { | |||
75 | .set_offline = dasd_generic_set_offline, | 74 | .set_offline = dasd_generic_set_offline, |
76 | .set_online = dasd_fba_set_online, | 75 | .set_online = dasd_fba_set_online, |
77 | .notify = dasd_generic_notify, | 76 | .notify = dasd_generic_notify, |
77 | .freeze = dasd_generic_pm_freeze, | ||
78 | .thaw = dasd_generic_restore_device, | ||
79 | .restore = dasd_generic_restore_device, | ||
78 | }; | 80 | }; |
79 | 81 | ||
80 | static void | 82 | static void |
@@ -122,20 +124,20 @@ dasd_fba_check_characteristics(struct dasd_device *device) | |||
122 | struct dasd_block *block; | 124 | struct dasd_block *block; |
123 | struct dasd_fba_private *private; | 125 | struct dasd_fba_private *private; |
124 | struct ccw_device *cdev = device->cdev; | 126 | struct ccw_device *cdev = device->cdev; |
125 | void *rdc_data; | ||
126 | int rc; | 127 | int rc; |
127 | 128 | ||
128 | private = (struct dasd_fba_private *) device->private; | 129 | private = (struct dasd_fba_private *) device->private; |
129 | if (private == NULL) { | 130 | if (!private) { |
130 | private = kzalloc(sizeof(struct dasd_fba_private), | 131 | private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); |
131 | GFP_KERNEL | GFP_DMA); | 132 | if (!private) { |
132 | if (private == NULL) { | ||
133 | dev_warn(&device->cdev->dev, | 133 | dev_warn(&device->cdev->dev, |
134 | "Allocating memory for private DASD " | 134 | "Allocating memory for private DASD " |
135 | "data failed\n"); | 135 | "data failed\n"); |
136 | return -ENOMEM; | 136 | return -ENOMEM; |
137 | } | 137 | } |
138 | device->private = (void *) private; | 138 | device->private = (void *) private; |
139 | } else { | ||
140 | memset(private, 0, sizeof(*private)); | ||
139 | } | 141 | } |
140 | block = dasd_alloc_block(); | 142 | block = dasd_alloc_block(); |
141 | if (IS_ERR(block)) { | 143 | if (IS_ERR(block)) { |
@@ -150,8 +152,8 @@ dasd_fba_check_characteristics(struct dasd_device *device) | |||
150 | block->base = device; | 152 | block->base = device; |
151 | 153 | ||
152 | /* Read Device Characteristics */ | 154 | /* Read Device Characteristics */ |
153 | rdc_data = (void *) &(private->rdc_data); | 155 | rc = dasd_generic_read_dev_chars(device, "FBA ", &private->rdc_data, |
154 | rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32); | 156 | 32); |
155 | if (rc) { | 157 | if (rc) { |
156 | DBF_EVENT(DBF_WARNING, "Read device characteristics returned " | 158 | DBF_EVENT(DBF_WARNING, "Read device characteristics returned " |
157 | "error %d for device: %s", | 159 | "error %d for device: %s", |
@@ -270,8 +272,9 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, | |||
270 | return ERR_PTR(-EINVAL); | 272 | return ERR_PTR(-EINVAL); |
271 | blksize = block->bp_block; | 273 | blksize = block->bp_block; |
272 | /* Calculate record id of first and last block. */ | 274 | /* Calculate record id of first and last block. */ |
273 | first_rec = req->sector >> block->s2b_shift; | 275 | first_rec = blk_rq_pos(req) >> block->s2b_shift; |
274 | last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift; | 276 | last_rec = |
277 | (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; | ||
275 | /* Check struct bio and count the number of blocks for the request. */ | 278 | /* Check struct bio and count the number of blocks for the request. */ |
276 | count = 0; | 279 | count = 0; |
277 | cidaw = 0; | 280 | cidaw = 0; |
@@ -309,7 +312,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, | |||
309 | ccw = cqr->cpaddr; | 312 | ccw = cqr->cpaddr; |
310 | /* First ccw is define extent. */ | 313 | /* First ccw is define extent. */ |
311 | define_extent(ccw++, cqr->data, rq_data_dir(req), | 314 | define_extent(ccw++, cqr->data, rq_data_dir(req), |
312 | block->bp_block, req->sector, req->nr_sectors); | 315 | block->bp_block, blk_rq_pos(req), blk_rq_sectors(req)); |
313 | /* Build locate_record + read/write ccws. */ | 316 | /* Build locate_record + read/write ccws. */ |
314 | idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data)); | 317 | idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data)); |
315 | LO_data = (struct LO_fba_data *) (idaws + cidaw); | 318 | LO_data = (struct LO_fba_data *) (idaws + cidaw); |
@@ -603,8 +606,14 @@ static struct dasd_discipline dasd_fba_discipline = { | |||
603 | static int __init | 606 | static int __init |
604 | dasd_fba_init(void) | 607 | dasd_fba_init(void) |
605 | { | 608 | { |
609 | int ret; | ||
610 | |||
606 | ASCEBC(dasd_fba_discipline.ebcname, 4); | 611 | ASCEBC(dasd_fba_discipline.ebcname, 4); |
607 | return ccw_driver_register(&dasd_fba_driver); | 612 | ret = ccw_driver_register(&dasd_fba_driver); |
613 | if (!ret) | ||
614 | wait_for_device_probe(); | ||
615 | |||
616 | return ret; | ||
608 | } | 617 | } |
609 | 618 | ||
610 | static void __exit | 619 | static void __exit |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index c1e487f774c6..fd63b2f2bda9 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -4,8 +4,7 @@ | |||
4 | * Horst Hummel <Horst.Hummel@de.ibm.com> | 4 | * Horst Hummel <Horst.Hummel@de.ibm.com> |
5 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 5 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
6 | * Bugreports.to..: <Linux390@de.ibm.com> | 6 | * Bugreports.to..: <Linux390@de.ibm.com> |
7 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 7 | * Copyright IBM Corp. 1999, 2009 |
8 | * | ||
9 | */ | 8 | */ |
10 | 9 | ||
11 | #ifndef DASD_INT_H | 10 | #ifndef DASD_INT_H |
@@ -173,6 +172,7 @@ struct dasd_ccw_req { | |||
173 | void *data; /* pointer to data area */ | 172 | void *data; /* pointer to data area */ |
174 | 173 | ||
175 | /* these are important for recovering erroneous requests */ | 174 | /* these are important for recovering erroneous requests */ |
175 | int intrc; /* internal error, e.g. from start_IO */ | ||
176 | struct irb irb; /* device status in case of an error */ | 176 | struct irb irb; /* device status in case of an error */ |
177 | struct dasd_ccw_req *refers; /* ERP-chain queueing. */ | 177 | struct dasd_ccw_req *refers; /* ERP-chain queueing. */ |
178 | void *function; /* originating ERP action */ | 178 | void *function; /* originating ERP action */ |
@@ -294,6 +294,10 @@ struct dasd_discipline { | |||
294 | int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); | 294 | int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); |
295 | int (*fill_info) (struct dasd_device *, struct dasd_information2_t *); | 295 | int (*fill_info) (struct dasd_device *, struct dasd_information2_t *); |
296 | int (*ioctl) (struct dasd_block *, unsigned int, void __user *); | 296 | int (*ioctl) (struct dasd_block *, unsigned int, void __user *); |
297 | |||
298 | /* suspend/resume functions */ | ||
299 | int (*freeze) (struct dasd_device *); | ||
300 | int (*restore) (struct dasd_device *); | ||
297 | }; | 301 | }; |
298 | 302 | ||
299 | extern struct dasd_discipline *dasd_diag_discipline_pointer; | 303 | extern struct dasd_discipline *dasd_diag_discipline_pointer; |
@@ -366,6 +370,7 @@ struct dasd_device { | |||
366 | atomic_t tasklet_scheduled; | 370 | atomic_t tasklet_scheduled; |
367 | struct tasklet_struct tasklet; | 371 | struct tasklet_struct tasklet; |
368 | struct work_struct kick_work; | 372 | struct work_struct kick_work; |
373 | struct work_struct restore_device; | ||
369 | struct timer_list timer; | 374 | struct timer_list timer; |
370 | 375 | ||
371 | debug_info_t *debug_area; | 376 | debug_info_t *debug_area; |
@@ -409,6 +414,8 @@ struct dasd_block { | |||
409 | #define DASD_STOPPED_PENDING 4 /* long busy */ | 414 | #define DASD_STOPPED_PENDING 4 /* long busy */ |
410 | #define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ | 415 | #define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ |
411 | #define DASD_STOPPED_SU 16 /* summary unit check handling */ | 416 | #define DASD_STOPPED_SU 16 /* summary unit check handling */ |
417 | #define DASD_STOPPED_PM 32 /* pm state transition */ | ||
418 | #define DASD_UNRESUMED_PM 64 /* pm resume failed state */ | ||
412 | 419 | ||
413 | /* per device flags */ | 420 | /* per device flags */ |
414 | #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ | 421 | #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ |
@@ -555,6 +562,7 @@ void dasd_free_block(struct dasd_block *); | |||
555 | void dasd_enable_device(struct dasd_device *); | 562 | void dasd_enable_device(struct dasd_device *); |
556 | void dasd_set_target_state(struct dasd_device *, int); | 563 | void dasd_set_target_state(struct dasd_device *, int); |
557 | void dasd_kick_device(struct dasd_device *); | 564 | void dasd_kick_device(struct dasd_device *); |
565 | void dasd_restore_device(struct dasd_device *); | ||
558 | 566 | ||
559 | void dasd_add_request_head(struct dasd_ccw_req *); | 567 | void dasd_add_request_head(struct dasd_ccw_req *); |
560 | void dasd_add_request_tail(struct dasd_ccw_req *); | 568 | void dasd_add_request_tail(struct dasd_ccw_req *); |
@@ -577,8 +585,10 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); | |||
577 | int dasd_generic_set_offline (struct ccw_device *cdev); | 585 | int dasd_generic_set_offline (struct ccw_device *cdev); |
578 | int dasd_generic_notify(struct ccw_device *, int); | 586 | int dasd_generic_notify(struct ccw_device *, int); |
579 | void dasd_generic_handle_state_change(struct dasd_device *); | 587 | void dasd_generic_handle_state_change(struct dasd_device *); |
588 | int dasd_generic_pm_freeze(struct ccw_device *); | ||
589 | int dasd_generic_restore_device(struct ccw_device *); | ||
580 | 590 | ||
581 | int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int); | 591 | int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int); |
582 | char *dasd_get_sense(struct irb *); | 592 | char *dasd_get_sense(struct irb *); |
583 | 593 | ||
584 | /* externals in dasd_devmap.c */ | 594 | /* externals in dasd_devmap.c */ |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index cfdcf1aed33c..016f9e9d2591 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -14,10 +14,11 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
17 | #include <asm/extmem.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <linux/completion.h> | 17 | #include <linux/completion.h> |
20 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/platform_device.h> | ||
20 | #include <asm/extmem.h> | ||
21 | #include <asm/io.h> | ||
21 | 22 | ||
22 | #define DCSSBLK_NAME "dcssblk" | 23 | #define DCSSBLK_NAME "dcssblk" |
23 | #define DCSSBLK_MINORS_PER_DISK 1 | 24 | #define DCSSBLK_MINORS_PER_DISK 1 |
@@ -127,7 +128,7 @@ dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info) | |||
127 | found = 0; | 128 | found = 0; |
128 | // test if minor available | 129 | // test if minor available |
129 | list_for_each_entry(entry, &dcssblk_devices, lh) | 130 | list_for_each_entry(entry, &dcssblk_devices, lh) |
130 | if (minor == MINOR(disk_devt(entry->gd))) | 131 | if (minor == entry->gd->first_minor) |
131 | found++; | 132 | found++; |
132 | if (!found) break; // got unused minor | 133 | if (!found) break; // got unused minor |
133 | } | 134 | } |
@@ -602,7 +603,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
602 | dev_info->gd->private_data = dev_info; | 603 | dev_info->gd->private_data = dev_info; |
603 | dev_info->gd->driverfs_dev = &dev_info->dev; | 604 | dev_info->gd->driverfs_dev = &dev_info->dev; |
604 | blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); | 605 | blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); |
605 | blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); | 606 | blk_queue_logical_block_size(dev_info->dcssblk_queue, 4096); |
606 | 607 | ||
607 | seg_byte_size = (dev_info->end - dev_info->start + 1); | 608 | seg_byte_size = (dev_info->end - dev_info->start + 1); |
608 | set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors | 609 | set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors |
@@ -625,7 +626,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
625 | if (rc) | 626 | if (rc) |
626 | goto release_gd; | 627 | goto release_gd; |
627 | sprintf(dev_info->gd->disk_name, "dcssblk%d", | 628 | sprintf(dev_info->gd->disk_name, "dcssblk%d", |
628 | MINOR(disk_devt(dev_info->gd))); | 629 | dev_info->gd->first_minor); |
629 | list_add_tail(&dev_info->lh, &dcssblk_devices); | 630 | list_add_tail(&dev_info->lh, &dcssblk_devices); |
630 | 631 | ||
631 | if (!try_module_get(THIS_MODULE)) { | 632 | if (!try_module_get(THIS_MODULE)) { |
@@ -940,11 +941,94 @@ dcssblk_check_params(void) | |||
940 | } | 941 | } |
941 | 942 | ||
942 | /* | 943 | /* |
944 | * Suspend / Resume | ||
945 | */ | ||
946 | static int dcssblk_freeze(struct device *dev) | ||
947 | { | ||
948 | struct dcssblk_dev_info *dev_info; | ||
949 | int rc = 0; | ||
950 | |||
951 | list_for_each_entry(dev_info, &dcssblk_devices, lh) { | ||
952 | switch (dev_info->segment_type) { | ||
953 | case SEG_TYPE_SR: | ||
954 | case SEG_TYPE_ER: | ||
955 | case SEG_TYPE_SC: | ||
956 | if (!dev_info->is_shared) | ||
957 | rc = -EINVAL; | ||
958 | break; | ||
959 | default: | ||
960 | rc = -EINVAL; | ||
961 | break; | ||
962 | } | ||
963 | if (rc) | ||
964 | break; | ||
965 | } | ||
966 | if (rc) | ||
967 | pr_err("Suspend failed because device %s is writeable.\n", | ||
968 | dev_info->segment_name); | ||
969 | return rc; | ||
970 | } | ||
971 | |||
972 | static int dcssblk_restore(struct device *dev) | ||
973 | { | ||
974 | struct dcssblk_dev_info *dev_info; | ||
975 | struct segment_info *entry; | ||
976 | unsigned long start, end; | ||
977 | int rc = 0; | ||
978 | |||
979 | list_for_each_entry(dev_info, &dcssblk_devices, lh) { | ||
980 | list_for_each_entry(entry, &dev_info->seg_list, lh) { | ||
981 | segment_unload(entry->segment_name); | ||
982 | rc = segment_load(entry->segment_name, SEGMENT_SHARED, | ||
983 | &start, &end); | ||
984 | if (rc < 0) { | ||
985 | // TODO in_use check ? | ||
986 | segment_warning(rc, entry->segment_name); | ||
987 | goto out_panic; | ||
988 | } | ||
989 | if (start != entry->start || end != entry->end) { | ||
990 | pr_err("Mismatch of start / end address after " | ||
991 | "resuming device %s\n", | ||
992 | entry->segment_name); | ||
993 | goto out_panic; | ||
994 | } | ||
995 | } | ||
996 | } | ||
997 | return 0; | ||
998 | out_panic: | ||
999 | panic("fatal dcssblk resume error\n"); | ||
1000 | } | ||
1001 | |||
1002 | static int dcssblk_thaw(struct device *dev) | ||
1003 | { | ||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | static struct dev_pm_ops dcssblk_pm_ops = { | ||
1008 | .freeze = dcssblk_freeze, | ||
1009 | .thaw = dcssblk_thaw, | ||
1010 | .restore = dcssblk_restore, | ||
1011 | }; | ||
1012 | |||
1013 | static struct platform_driver dcssblk_pdrv = { | ||
1014 | .driver = { | ||
1015 | .name = "dcssblk", | ||
1016 | .owner = THIS_MODULE, | ||
1017 | .pm = &dcssblk_pm_ops, | ||
1018 | }, | ||
1019 | }; | ||
1020 | |||
1021 | static struct platform_device *dcssblk_pdev; | ||
1022 | |||
1023 | |||
1024 | /* | ||
943 | * The init/exit functions. | 1025 | * The init/exit functions. |
944 | */ | 1026 | */ |
945 | static void __exit | 1027 | static void __exit |
946 | dcssblk_exit(void) | 1028 | dcssblk_exit(void) |
947 | { | 1029 | { |
1030 | platform_device_unregister(dcssblk_pdev); | ||
1031 | platform_driver_unregister(&dcssblk_pdrv); | ||
948 | root_device_unregister(dcssblk_root_dev); | 1032 | root_device_unregister(dcssblk_root_dev); |
949 | unregister_blkdev(dcssblk_major, DCSSBLK_NAME); | 1033 | unregister_blkdev(dcssblk_major, DCSSBLK_NAME); |
950 | } | 1034 | } |
@@ -954,30 +1038,44 @@ dcssblk_init(void) | |||
954 | { | 1038 | { |
955 | int rc; | 1039 | int rc; |
956 | 1040 | ||
957 | dcssblk_root_dev = root_device_register("dcssblk"); | 1041 | rc = platform_driver_register(&dcssblk_pdrv); |
958 | if (IS_ERR(dcssblk_root_dev)) | 1042 | if (rc) |
959 | return PTR_ERR(dcssblk_root_dev); | ||
960 | rc = device_create_file(dcssblk_root_dev, &dev_attr_add); | ||
961 | if (rc) { | ||
962 | root_device_unregister(dcssblk_root_dev); | ||
963 | return rc; | 1043 | return rc; |
1044 | |||
1045 | dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL, | ||
1046 | 0); | ||
1047 | if (IS_ERR(dcssblk_pdev)) { | ||
1048 | rc = PTR_ERR(dcssblk_pdev); | ||
1049 | goto out_pdrv; | ||
964 | } | 1050 | } |
965 | rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); | 1051 | |
966 | if (rc) { | 1052 | dcssblk_root_dev = root_device_register("dcssblk"); |
967 | root_device_unregister(dcssblk_root_dev); | 1053 | if (IS_ERR(dcssblk_root_dev)) { |
968 | return rc; | 1054 | rc = PTR_ERR(dcssblk_root_dev); |
1055 | goto out_pdev; | ||
969 | } | 1056 | } |
1057 | rc = device_create_file(dcssblk_root_dev, &dev_attr_add); | ||
1058 | if (rc) | ||
1059 | goto out_root; | ||
1060 | rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); | ||
1061 | if (rc) | ||
1062 | goto out_root; | ||
970 | rc = register_blkdev(0, DCSSBLK_NAME); | 1063 | rc = register_blkdev(0, DCSSBLK_NAME); |
971 | if (rc < 0) { | 1064 | if (rc < 0) |
972 | root_device_unregister(dcssblk_root_dev); | 1065 | goto out_root; |
973 | return rc; | ||
974 | } | ||
975 | dcssblk_major = rc; | 1066 | dcssblk_major = rc; |
976 | init_rwsem(&dcssblk_devices_sem); | 1067 | init_rwsem(&dcssblk_devices_sem); |
977 | 1068 | ||
978 | dcssblk_check_params(); | 1069 | dcssblk_check_params(); |
979 | |||
980 | return 0; | 1070 | return 0; |
1071 | |||
1072 | out_root: | ||
1073 | root_device_unregister(dcssblk_root_dev); | ||
1074 | out_pdev: | ||
1075 | platform_device_unregister(dcssblk_pdev); | ||
1076 | out_pdrv: | ||
1077 | platform_driver_unregister(&dcssblk_pdrv); | ||
1078 | return rc; | ||
981 | } | 1079 | } |
982 | 1080 | ||
983 | module_init(dcssblk_init); | 1081 | module_init(dcssblk_init); |
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 76814f3e898a..2e9e1ecd6d82 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c | |||
@@ -39,7 +39,10 @@ | |||
39 | #include <linux/hdreg.h> /* HDIO_GETGEO */ | 39 | #include <linux/hdreg.h> /* HDIO_GETGEO */ |
40 | #include <linux/sysdev.h> | 40 | #include <linux/sysdev.h> |
41 | #include <linux/bio.h> | 41 | #include <linux/bio.h> |
42 | #include <linux/suspend.h> | ||
43 | #include <linux/platform_device.h> | ||
42 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
45 | #include <asm/checksum.h> | ||
43 | 46 | ||
44 | #define XPRAM_NAME "xpram" | 47 | #define XPRAM_NAME "xpram" |
45 | #define XPRAM_DEVS 1 /* one partition */ | 48 | #define XPRAM_DEVS 1 /* one partition */ |
@@ -48,6 +51,7 @@ | |||
48 | typedef struct { | 51 | typedef struct { |
49 | unsigned int size; /* size of xpram segment in pages */ | 52 | unsigned int size; /* size of xpram segment in pages */ |
50 | unsigned int offset; /* start page of xpram segment */ | 53 | unsigned int offset; /* start page of xpram segment */ |
54 | unsigned int csum; /* partition checksum for suspend */ | ||
51 | } xpram_device_t; | 55 | } xpram_device_t; |
52 | 56 | ||
53 | static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; | 57 | static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; |
@@ -138,7 +142,7 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index) | |||
138 | /* | 142 | /* |
139 | * Check if xpram is available. | 143 | * Check if xpram is available. |
140 | */ | 144 | */ |
141 | static int __init xpram_present(void) | 145 | static int xpram_present(void) |
142 | { | 146 | { |
143 | unsigned long mem_page; | 147 | unsigned long mem_page; |
144 | int rc; | 148 | int rc; |
@@ -154,7 +158,7 @@ static int __init xpram_present(void) | |||
154 | /* | 158 | /* |
155 | * Return index of the last available xpram page. | 159 | * Return index of the last available xpram page. |
156 | */ | 160 | */ |
157 | static unsigned long __init xpram_highest_page_index(void) | 161 | static unsigned long xpram_highest_page_index(void) |
158 | { | 162 | { |
159 | unsigned int page_index, add_bit; | 163 | unsigned int page_index, add_bit; |
160 | unsigned long mem_page; | 164 | unsigned long mem_page; |
@@ -343,7 +347,7 @@ static int __init xpram_setup_blkdev(void) | |||
343 | goto out; | 347 | goto out; |
344 | } | 348 | } |
345 | blk_queue_make_request(xpram_queues[i], xpram_make_request); | 349 | blk_queue_make_request(xpram_queues[i], xpram_make_request); |
346 | blk_queue_hardsect_size(xpram_queues[i], 4096); | 350 | blk_queue_logical_block_size(xpram_queues[i], 4096); |
347 | } | 351 | } |
348 | 352 | ||
349 | /* | 353 | /* |
@@ -383,6 +387,106 @@ out: | |||
383 | } | 387 | } |
384 | 388 | ||
385 | /* | 389 | /* |
390 | * Save checksums for all partitions. | ||
391 | */ | ||
392 | static int xpram_save_checksums(void) | ||
393 | { | ||
394 | unsigned long mem_page; | ||
395 | int rc, i; | ||
396 | |||
397 | rc = 0; | ||
398 | mem_page = (unsigned long) __get_free_page(GFP_KERNEL); | ||
399 | if (!mem_page) | ||
400 | return -ENOMEM; | ||
401 | for (i = 0; i < xpram_devs; i++) { | ||
402 | rc = xpram_page_in(mem_page, xpram_devices[i].offset); | ||
403 | if (rc) | ||
404 | goto fail; | ||
405 | xpram_devices[i].csum = csum_partial((const void *) mem_page, | ||
406 | PAGE_SIZE, 0); | ||
407 | } | ||
408 | fail: | ||
409 | free_page(mem_page); | ||
410 | return rc ? -ENXIO : 0; | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * Verify checksums for all partitions. | ||
415 | */ | ||
416 | static int xpram_validate_checksums(void) | ||
417 | { | ||
418 | unsigned long mem_page; | ||
419 | unsigned int csum; | ||
420 | int rc, i; | ||
421 | |||
422 | rc = 0; | ||
423 | mem_page = (unsigned long) __get_free_page(GFP_KERNEL); | ||
424 | if (!mem_page) | ||
425 | return -ENOMEM; | ||
426 | for (i = 0; i < xpram_devs; i++) { | ||
427 | rc = xpram_page_in(mem_page, xpram_devices[i].offset); | ||
428 | if (rc) | ||
429 | goto fail; | ||
430 | csum = csum_partial((const void *) mem_page, PAGE_SIZE, 0); | ||
431 | if (xpram_devices[i].csum != csum) { | ||
432 | rc = -EINVAL; | ||
433 | goto fail; | ||
434 | } | ||
435 | } | ||
436 | fail: | ||
437 | free_page(mem_page); | ||
438 | return rc ? -ENXIO : 0; | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * Resume failed: Print error message and call panic. | ||
443 | */ | ||
444 | static void xpram_resume_error(const char *message) | ||
445 | { | ||
446 | pr_err("Resume error: %s\n", message); | ||
447 | panic("xpram resume error\n"); | ||
448 | } | ||
449 | |||
450 | /* | ||
451 | * Check if xpram setup changed between suspend and resume. | ||
452 | */ | ||
453 | static int xpram_restore(struct device *dev) | ||
454 | { | ||
455 | if (!xpram_pages) | ||
456 | return 0; | ||
457 | if (xpram_present() != 0) | ||
458 | xpram_resume_error("xpram disappeared"); | ||
459 | if (xpram_pages != xpram_highest_page_index() + 1) | ||
460 | xpram_resume_error("Size of xpram changed"); | ||
461 | if (xpram_validate_checksums()) | ||
462 | xpram_resume_error("Data of xpram changed"); | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | /* | ||
467 | * Save necessary state in suspend. | ||
468 | */ | ||
469 | static int xpram_freeze(struct device *dev) | ||
470 | { | ||
471 | return xpram_save_checksums(); | ||
472 | } | ||
473 | |||
474 | static struct dev_pm_ops xpram_pm_ops = { | ||
475 | .freeze = xpram_freeze, | ||
476 | .restore = xpram_restore, | ||
477 | }; | ||
478 | |||
479 | static struct platform_driver xpram_pdrv = { | ||
480 | .driver = { | ||
481 | .name = XPRAM_NAME, | ||
482 | .owner = THIS_MODULE, | ||
483 | .pm = &xpram_pm_ops, | ||
484 | }, | ||
485 | }; | ||
486 | |||
487 | static struct platform_device *xpram_pdev; | ||
488 | |||
489 | /* | ||
386 | * Finally, the init/exit functions. | 490 | * Finally, the init/exit functions. |
387 | */ | 491 | */ |
388 | static void __exit xpram_exit(void) | 492 | static void __exit xpram_exit(void) |
@@ -394,6 +498,8 @@ static void __exit xpram_exit(void) | |||
394 | put_disk(xpram_disks[i]); | 498 | put_disk(xpram_disks[i]); |
395 | } | 499 | } |
396 | unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); | 500 | unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); |
501 | platform_device_unregister(xpram_pdev); | ||
502 | platform_driver_unregister(&xpram_pdrv); | ||
397 | } | 503 | } |
398 | 504 | ||
399 | static int __init xpram_init(void) | 505 | static int __init xpram_init(void) |
@@ -411,7 +517,24 @@ static int __init xpram_init(void) | |||
411 | rc = xpram_setup_sizes(xpram_pages); | 517 | rc = xpram_setup_sizes(xpram_pages); |
412 | if (rc) | 518 | if (rc) |
413 | return rc; | 519 | return rc; |
414 | return xpram_setup_blkdev(); | 520 | rc = platform_driver_register(&xpram_pdrv); |
521 | if (rc) | ||
522 | return rc; | ||
523 | xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0); | ||
524 | if (IS_ERR(xpram_pdev)) { | ||
525 | rc = PTR_ERR(xpram_pdev); | ||
526 | goto fail_platform_driver_unregister; | ||
527 | } | ||
528 | rc = xpram_setup_blkdev(); | ||
529 | if (rc) | ||
530 | goto fail_platform_device_unregister; | ||
531 | return 0; | ||
532 | |||
533 | fail_platform_device_unregister: | ||
534 | platform_device_unregister(xpram_pdev); | ||
535 | fail_platform_driver_unregister: | ||
536 | platform_driver_unregister(&xpram_pdrv); | ||
537 | return rc; | ||
415 | } | 538 | } |
416 | 539 | ||
417 | module_init(xpram_init); | 540 | module_init(xpram_init); |
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 9ab06e0dad40..04dc734805c6 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
@@ -1,14 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/con3215.c | 2 | * 3215 line mode terminal driver. |
3 | * 3215 line mode terminal driver. | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 1999, 2009 |
6 | * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> |
7 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), | ||
8 | * | 6 | * |
9 | * Updated: | 7 | * Updated: |
10 | * Aug-2000: Added tab support | 8 | * Aug-2000: Added tab support |
11 | * Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu) | 9 | * Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu> |
12 | */ | 10 | */ |
13 | 11 | ||
14 | #include <linux/module.h> | 12 | #include <linux/module.h> |
@@ -56,6 +54,7 @@ | |||
56 | #define RAW3215_CLOSING 32 /* set while in close process */ | 54 | #define RAW3215_CLOSING 32 /* set while in close process */ |
57 | #define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */ | 55 | #define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */ |
58 | #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ | 56 | #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ |
57 | #define RAW3215_FROZEN 256 /* set if 3215 is frozen for suspend */ | ||
59 | 58 | ||
60 | #define TAB_STOP_SIZE 8 /* tab stop size */ | 59 | #define TAB_STOP_SIZE 8 /* tab stop size */ |
61 | 60 | ||
@@ -111,8 +110,8 @@ static struct tty_driver *tty3215_driver; | |||
111 | /* | 110 | /* |
112 | * Get a request structure from the free list | 111 | * Get a request structure from the free list |
113 | */ | 112 | */ |
114 | static inline struct raw3215_req * | 113 | static inline struct raw3215_req *raw3215_alloc_req(void) |
115 | raw3215_alloc_req(void) { | 114 | { |
116 | struct raw3215_req *req; | 115 | struct raw3215_req *req; |
117 | unsigned long flags; | 116 | unsigned long flags; |
118 | 117 | ||
@@ -126,8 +125,8 @@ raw3215_alloc_req(void) { | |||
126 | /* | 125 | /* |
127 | * Put a request structure back to the free list | 126 | * Put a request structure back to the free list |
128 | */ | 127 | */ |
129 | static inline void | 128 | static inline void raw3215_free_req(struct raw3215_req *req) |
130 | raw3215_free_req(struct raw3215_req *req) { | 129 | { |
131 | unsigned long flags; | 130 | unsigned long flags; |
132 | 131 | ||
133 | if (req->type == RAW3215_FREE) | 132 | if (req->type == RAW3215_FREE) |
@@ -145,8 +144,7 @@ raw3215_free_req(struct raw3215_req *req) { | |||
145 | * because a 3215 terminal won't accept a new read before the old one is | 144 | * because a 3215 terminal won't accept a new read before the old one is |
146 | * completed. | 145 | * completed. |
147 | */ | 146 | */ |
148 | static void | 147 | static void raw3215_mk_read_req(struct raw3215_info *raw) |
149 | raw3215_mk_read_req(struct raw3215_info *raw) | ||
150 | { | 148 | { |
151 | struct raw3215_req *req; | 149 | struct raw3215_req *req; |
152 | struct ccw1 *ccw; | 150 | struct ccw1 *ccw; |
@@ -174,8 +172,7 @@ raw3215_mk_read_req(struct raw3215_info *raw) | |||
174 | * buffer to the 3215 device. If a queued write exists it is replaced by | 172 | * buffer to the 3215 device. If a queued write exists it is replaced by |
175 | * the new, probably lengthened request. | 173 | * the new, probably lengthened request. |
176 | */ | 174 | */ |
177 | static void | 175 | static void raw3215_mk_write_req(struct raw3215_info *raw) |
178 | raw3215_mk_write_req(struct raw3215_info *raw) | ||
179 | { | 176 | { |
180 | struct raw3215_req *req; | 177 | struct raw3215_req *req; |
181 | struct ccw1 *ccw; | 178 | struct ccw1 *ccw; |
@@ -251,8 +248,7 @@ raw3215_mk_write_req(struct raw3215_info *raw) | |||
251 | /* | 248 | /* |
252 | * Start a read or a write request | 249 | * Start a read or a write request |
253 | */ | 250 | */ |
254 | static void | 251 | static void raw3215_start_io(struct raw3215_info *raw) |
255 | raw3215_start_io(struct raw3215_info *raw) | ||
256 | { | 252 | { |
257 | struct raw3215_req *req; | 253 | struct raw3215_req *req; |
258 | int res; | 254 | int res; |
@@ -290,8 +286,7 @@ raw3215_start_io(struct raw3215_info *raw) | |||
290 | /* | 286 | /* |
291 | * Function to start a delayed output after RAW3215_TIMEOUT seconds | 287 | * Function to start a delayed output after RAW3215_TIMEOUT seconds |
292 | */ | 288 | */ |
293 | static void | 289 | static void raw3215_timeout(unsigned long __data) |
294 | raw3215_timeout(unsigned long __data) | ||
295 | { | 290 | { |
296 | struct raw3215_info *raw = (struct raw3215_info *) __data; | 291 | struct raw3215_info *raw = (struct raw3215_info *) __data; |
297 | unsigned long flags; | 292 | unsigned long flags; |
@@ -300,8 +295,10 @@ raw3215_timeout(unsigned long __data) | |||
300 | if (raw->flags & RAW3215_TIMER_RUNS) { | 295 | if (raw->flags & RAW3215_TIMER_RUNS) { |
301 | del_timer(&raw->timer); | 296 | del_timer(&raw->timer); |
302 | raw->flags &= ~RAW3215_TIMER_RUNS; | 297 | raw->flags &= ~RAW3215_TIMER_RUNS; |
303 | raw3215_mk_write_req(raw); | 298 | if (!(raw->flags & RAW3215_FROZEN)) { |
304 | raw3215_start_io(raw); | 299 | raw3215_mk_write_req(raw); |
300 | raw3215_start_io(raw); | ||
301 | } | ||
305 | } | 302 | } |
306 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | 303 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
307 | } | 304 | } |
@@ -312,10 +309,9 @@ raw3215_timeout(unsigned long __data) | |||
312 | * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not | 309 | * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not |
313 | * done immediately a timer is started with a delay of RAW3215_TIMEOUT. | 310 | * done immediately a timer is started with a delay of RAW3215_TIMEOUT. |
314 | */ | 311 | */ |
315 | static inline void | 312 | static inline void raw3215_try_io(struct raw3215_info *raw) |
316 | raw3215_try_io(struct raw3215_info *raw) | ||
317 | { | 313 | { |
318 | if (!(raw->flags & RAW3215_ACTIVE)) | 314 | if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN)) |
319 | return; | 315 | return; |
320 | if (raw->queued_read != NULL) | 316 | if (raw->queued_read != NULL) |
321 | raw3215_start_io(raw); | 317 | raw3215_start_io(raw); |
@@ -359,8 +355,8 @@ static void raw3215_next_io(struct raw3215_info *raw) | |||
359 | /* | 355 | /* |
360 | * Interrupt routine, called from common io layer | 356 | * Interrupt routine, called from common io layer |
361 | */ | 357 | */ |
362 | static void | 358 | static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, |
363 | raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | 359 | struct irb *irb) |
364 | { | 360 | { |
365 | struct raw3215_info *raw; | 361 | struct raw3215_info *raw; |
366 | struct raw3215_req *req; | 362 | struct raw3215_req *req; |
@@ -368,7 +364,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
368 | int cstat, dstat; | 364 | int cstat, dstat; |
369 | int count; | 365 | int count; |
370 | 366 | ||
371 | raw = cdev->dev.driver_data; | 367 | raw = dev_get_drvdata(&cdev->dev); |
372 | req = (struct raw3215_req *) intparm; | 368 | req = (struct raw3215_req *) intparm; |
373 | cstat = irb->scsw.cmd.cstat; | 369 | cstat = irb->scsw.cmd.cstat; |
374 | dstat = irb->scsw.cmd.dstat; | 370 | dstat = irb->scsw.cmd.dstat; |
@@ -459,14 +455,40 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
459 | } | 455 | } |
460 | 456 | ||
461 | /* | 457 | /* |
458 | * Drop the oldest line from the output buffer. | ||
459 | */ | ||
460 | static void raw3215_drop_line(struct raw3215_info *raw) | ||
461 | { | ||
462 | int ix; | ||
463 | char ch; | ||
464 | |||
465 | BUG_ON(raw->written != 0); | ||
466 | ix = (raw->head - raw->count) & (RAW3215_BUFFER_SIZE - 1); | ||
467 | while (raw->count > 0) { | ||
468 | ch = raw->buffer[ix]; | ||
469 | ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1); | ||
470 | raw->count--; | ||
471 | if (ch == 0x15) | ||
472 | break; | ||
473 | } | ||
474 | raw->head = ix; | ||
475 | } | ||
476 | |||
477 | /* | ||
462 | * Wait until length bytes are available int the output buffer. | 478 | * Wait until length bytes are available int the output buffer. |
463 | * Has to be called with the s390irq lock held. Can be called | 479 | * Has to be called with the s390irq lock held. Can be called |
464 | * disabled. | 480 | * disabled. |
465 | */ | 481 | */ |
466 | static void | 482 | static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) |
467 | raw3215_make_room(struct raw3215_info *raw, unsigned int length) | ||
468 | { | 483 | { |
469 | while (RAW3215_BUFFER_SIZE - raw->count < length) { | 484 | while (RAW3215_BUFFER_SIZE - raw->count < length) { |
485 | /* While console is frozen for suspend we have no other | ||
486 | * choice but to drop message from the buffer to make | ||
487 | * room for even more messages. */ | ||
488 | if (raw->flags & RAW3215_FROZEN) { | ||
489 | raw3215_drop_line(raw); | ||
490 | continue; | ||
491 | } | ||
470 | /* there might be a request pending */ | 492 | /* there might be a request pending */ |
471 | raw->flags |= RAW3215_FLUSHING; | 493 | raw->flags |= RAW3215_FLUSHING; |
472 | raw3215_mk_write_req(raw); | 494 | raw3215_mk_write_req(raw); |
@@ -488,8 +510,8 @@ raw3215_make_room(struct raw3215_info *raw, unsigned int length) | |||
488 | /* | 510 | /* |
489 | * String write routine for 3215 devices | 511 | * String write routine for 3215 devices |
490 | */ | 512 | */ |
491 | static void | 513 | static void raw3215_write(struct raw3215_info *raw, const char *str, |
492 | raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) | 514 | unsigned int length) |
493 | { | 515 | { |
494 | unsigned long flags; | 516 | unsigned long flags; |
495 | int c, count; | 517 | int c, count; |
@@ -529,8 +551,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) | |||
529 | /* | 551 | /* |
530 | * Put character routine for 3215 devices | 552 | * Put character routine for 3215 devices |
531 | */ | 553 | */ |
532 | static void | 554 | static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch) |
533 | raw3215_putchar(struct raw3215_info *raw, unsigned char ch) | ||
534 | { | 555 | { |
535 | unsigned long flags; | 556 | unsigned long flags; |
536 | unsigned int length, i; | 557 | unsigned int length, i; |
@@ -566,8 +587,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch) | |||
566 | * Flush routine, it simply sets the flush flag and tries to start | 587 | * Flush routine, it simply sets the flush flag and tries to start |
567 | * pending IO. | 588 | * pending IO. |
568 | */ | 589 | */ |
569 | static void | 590 | static void raw3215_flush_buffer(struct raw3215_info *raw) |
570 | raw3215_flush_buffer(struct raw3215_info *raw) | ||
571 | { | 591 | { |
572 | unsigned long flags; | 592 | unsigned long flags; |
573 | 593 | ||
@@ -583,8 +603,7 @@ raw3215_flush_buffer(struct raw3215_info *raw) | |||
583 | /* | 603 | /* |
584 | * Fire up a 3215 device. | 604 | * Fire up a 3215 device. |
585 | */ | 605 | */ |
586 | static int | 606 | static int raw3215_startup(struct raw3215_info *raw) |
587 | raw3215_startup(struct raw3215_info *raw) | ||
588 | { | 607 | { |
589 | unsigned long flags; | 608 | unsigned long flags; |
590 | 609 | ||
@@ -602,8 +621,7 @@ raw3215_startup(struct raw3215_info *raw) | |||
602 | /* | 621 | /* |
603 | * Shutdown a 3215 device. | 622 | * Shutdown a 3215 device. |
604 | */ | 623 | */ |
605 | static void | 624 | static void raw3215_shutdown(struct raw3215_info *raw) |
606 | raw3215_shutdown(struct raw3215_info *raw) | ||
607 | { | 625 | { |
608 | DECLARE_WAITQUEUE(wait, current); | 626 | DECLARE_WAITQUEUE(wait, current); |
609 | unsigned long flags; | 627 | unsigned long flags; |
@@ -628,14 +646,13 @@ raw3215_shutdown(struct raw3215_info *raw) | |||
628 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | 646 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
629 | } | 647 | } |
630 | 648 | ||
631 | static int | 649 | static int raw3215_probe (struct ccw_device *cdev) |
632 | raw3215_probe (struct ccw_device *cdev) | ||
633 | { | 650 | { |
634 | struct raw3215_info *raw; | 651 | struct raw3215_info *raw; |
635 | int line; | 652 | int line; |
636 | 653 | ||
637 | /* Console is special. */ | 654 | /* Console is special. */ |
638 | if (raw3215[0] && (cdev->dev.driver_data == raw3215[0])) | 655 | if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev))) |
639 | return 0; | 656 | return 0; |
640 | raw = kmalloc(sizeof(struct raw3215_info) + | 657 | raw = kmalloc(sizeof(struct raw3215_info) + |
641 | RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); | 658 | RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); |
@@ -669,44 +686,41 @@ raw3215_probe (struct ccw_device *cdev) | |||
669 | } | 686 | } |
670 | init_waitqueue_head(&raw->empty_wait); | 687 | init_waitqueue_head(&raw->empty_wait); |
671 | 688 | ||
672 | cdev->dev.driver_data = raw; | 689 | dev_set_drvdata(&cdev->dev, raw); |
673 | cdev->handler = raw3215_irq; | 690 | cdev->handler = raw3215_irq; |
674 | 691 | ||
675 | return 0; | 692 | return 0; |
676 | } | 693 | } |
677 | 694 | ||
678 | static void | 695 | static void raw3215_remove (struct ccw_device *cdev) |
679 | raw3215_remove (struct ccw_device *cdev) | ||
680 | { | 696 | { |
681 | struct raw3215_info *raw; | 697 | struct raw3215_info *raw; |
682 | 698 | ||
683 | ccw_device_set_offline(cdev); | 699 | ccw_device_set_offline(cdev); |
684 | raw = cdev->dev.driver_data; | 700 | raw = dev_get_drvdata(&cdev->dev); |
685 | if (raw) { | 701 | if (raw) { |
686 | cdev->dev.driver_data = NULL; | 702 | dev_set_drvdata(&cdev->dev, NULL); |
687 | kfree(raw->buffer); | 703 | kfree(raw->buffer); |
688 | kfree(raw); | 704 | kfree(raw); |
689 | } | 705 | } |
690 | } | 706 | } |
691 | 707 | ||
692 | static int | 708 | static int raw3215_set_online (struct ccw_device *cdev) |
693 | raw3215_set_online (struct ccw_device *cdev) | ||
694 | { | 709 | { |
695 | struct raw3215_info *raw; | 710 | struct raw3215_info *raw; |
696 | 711 | ||
697 | raw = cdev->dev.driver_data; | 712 | raw = dev_get_drvdata(&cdev->dev); |
698 | if (!raw) | 713 | if (!raw) |
699 | return -ENODEV; | 714 | return -ENODEV; |
700 | 715 | ||
701 | return raw3215_startup(raw); | 716 | return raw3215_startup(raw); |
702 | } | 717 | } |
703 | 718 | ||
704 | static int | 719 | static int raw3215_set_offline (struct ccw_device *cdev) |
705 | raw3215_set_offline (struct ccw_device *cdev) | ||
706 | { | 720 | { |
707 | struct raw3215_info *raw; | 721 | struct raw3215_info *raw; |
708 | 722 | ||
709 | raw = cdev->dev.driver_data; | 723 | raw = dev_get_drvdata(&cdev->dev); |
710 | if (!raw) | 724 | if (!raw) |
711 | return -ENODEV; | 725 | return -ENODEV; |
712 | 726 | ||
@@ -715,6 +729,36 @@ raw3215_set_offline (struct ccw_device *cdev) | |||
715 | return 0; | 729 | return 0; |
716 | } | 730 | } |
717 | 731 | ||
732 | static int raw3215_pm_stop(struct ccw_device *cdev) | ||
733 | { | ||
734 | struct raw3215_info *raw; | ||
735 | unsigned long flags; | ||
736 | |||
737 | /* Empty the output buffer, then prevent new I/O. */ | ||
738 | raw = cdev->dev.driver_data; | ||
739 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | ||
740 | raw3215_make_room(raw, RAW3215_BUFFER_SIZE); | ||
741 | raw->flags |= RAW3215_FROZEN; | ||
742 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | ||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | static int raw3215_pm_start(struct ccw_device *cdev) | ||
747 | { | ||
748 | struct raw3215_info *raw; | ||
749 | unsigned long flags; | ||
750 | |||
751 | /* Allow I/O again and flush output buffer. */ | ||
752 | raw = cdev->dev.driver_data; | ||
753 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | ||
754 | raw->flags &= ~RAW3215_FROZEN; | ||
755 | raw->flags |= RAW3215_FLUSHING; | ||
756 | raw3215_try_io(raw); | ||
757 | raw->flags &= ~RAW3215_FLUSHING; | ||
758 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | ||
759 | return 0; | ||
760 | } | ||
761 | |||
718 | static struct ccw_device_id raw3215_id[] = { | 762 | static struct ccw_device_id raw3215_id[] = { |
719 | { CCW_DEVICE(0x3215, 0) }, | 763 | { CCW_DEVICE(0x3215, 0) }, |
720 | { /* end of list */ }, | 764 | { /* end of list */ }, |
@@ -728,14 +772,17 @@ static struct ccw_driver raw3215_ccw_driver = { | |||
728 | .remove = &raw3215_remove, | 772 | .remove = &raw3215_remove, |
729 | .set_online = &raw3215_set_online, | 773 | .set_online = &raw3215_set_online, |
730 | .set_offline = &raw3215_set_offline, | 774 | .set_offline = &raw3215_set_offline, |
775 | .freeze = &raw3215_pm_stop, | ||
776 | .thaw = &raw3215_pm_start, | ||
777 | .restore = &raw3215_pm_start, | ||
731 | }; | 778 | }; |
732 | 779 | ||
733 | #ifdef CONFIG_TN3215_CONSOLE | 780 | #ifdef CONFIG_TN3215_CONSOLE |
734 | /* | 781 | /* |
735 | * Write a string to the 3215 console | 782 | * Write a string to the 3215 console |
736 | */ | 783 | */ |
737 | static void | 784 | static void con3215_write(struct console *co, const char *str, |
738 | con3215_write(struct console *co, const char *str, unsigned int count) | 785 | unsigned int count) |
739 | { | 786 | { |
740 | struct raw3215_info *raw; | 787 | struct raw3215_info *raw; |
741 | int i; | 788 | int i; |
@@ -768,13 +815,17 @@ static struct tty_driver *con3215_device(struct console *c, int *index) | |||
768 | * panic() calls con3215_flush through a panic_notifier | 815 | * panic() calls con3215_flush through a panic_notifier |
769 | * before the system enters a disabled, endless loop. | 816 | * before the system enters a disabled, endless loop. |
770 | */ | 817 | */ |
771 | static void | 818 | static void con3215_flush(void) |
772 | con3215_flush(void) | ||
773 | { | 819 | { |
774 | struct raw3215_info *raw; | 820 | struct raw3215_info *raw; |
775 | unsigned long flags; | 821 | unsigned long flags; |
776 | 822 | ||
777 | raw = raw3215[0]; /* console 3215 is the first one */ | 823 | raw = raw3215[0]; /* console 3215 is the first one */ |
824 | if (raw->flags & RAW3215_FROZEN) | ||
825 | /* The console is still frozen for suspend. */ | ||
826 | if (ccw_device_force_console()) | ||
827 | /* Forcing didn't work, no panic message .. */ | ||
828 | return; | ||
778 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | 829 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
779 | raw3215_make_room(raw, RAW3215_BUFFER_SIZE); | 830 | raw3215_make_room(raw, RAW3215_BUFFER_SIZE); |
780 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | 831 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
@@ -811,8 +862,7 @@ static struct console con3215 = { | |||
811 | * 3215 console initialization code called from console_init(). | 862 | * 3215 console initialization code called from console_init(). |
812 | * NOTE: This is called before kmalloc is available. | 863 | * NOTE: This is called before kmalloc is available. |
813 | */ | 864 | */ |
814 | static int __init | 865 | static int __init con3215_init(void) |
815 | con3215_init(void) | ||
816 | { | 866 | { |
817 | struct ccw_device *cdev; | 867 | struct ccw_device *cdev; |
818 | struct raw3215_info *raw; | 868 | struct raw3215_info *raw; |
@@ -848,7 +898,7 @@ con3215_init(void) | |||
848 | raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE); | 898 | raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE); |
849 | raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE); | 899 | raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE); |
850 | raw->cdev = cdev; | 900 | raw->cdev = cdev; |
851 | cdev->dev.driver_data = raw; | 901 | dev_set_drvdata(&cdev->dev, raw); |
852 | cdev->handler = raw3215_irq; | 902 | cdev->handler = raw3215_irq; |
853 | 903 | ||
854 | raw->flags |= RAW3215_FIXED; | 904 | raw->flags |= RAW3215_FIXED; |
@@ -875,8 +925,7 @@ console_initcall(con3215_init); | |||
875 | * | 925 | * |
876 | * This routine is called whenever a 3215 tty is opened. | 926 | * This routine is called whenever a 3215 tty is opened. |
877 | */ | 927 | */ |
878 | static int | 928 | static int tty3215_open(struct tty_struct *tty, struct file * filp) |
879 | tty3215_open(struct tty_struct *tty, struct file * filp) | ||
880 | { | 929 | { |
881 | struct raw3215_info *raw; | 930 | struct raw3215_info *raw; |
882 | int retval, line; | 931 | int retval, line; |
@@ -909,8 +958,7 @@ tty3215_open(struct tty_struct *tty, struct file * filp) | |||
909 | * This routine is called when the 3215 tty is closed. We wait | 958 | * This routine is called when the 3215 tty is closed. We wait |
910 | * for the remaining request to be completed. Then we clean up. | 959 | * for the remaining request to be completed. Then we clean up. |
911 | */ | 960 | */ |
912 | static void | 961 | static void tty3215_close(struct tty_struct *tty, struct file * filp) |
913 | tty3215_close(struct tty_struct *tty, struct file * filp) | ||
914 | { | 962 | { |
915 | struct raw3215_info *raw; | 963 | struct raw3215_info *raw; |
916 | 964 | ||
@@ -927,8 +975,7 @@ tty3215_close(struct tty_struct *tty, struct file * filp) | |||
927 | /* | 975 | /* |
928 | * Returns the amount of free space in the output buffer. | 976 | * Returns the amount of free space in the output buffer. |
929 | */ | 977 | */ |
930 | static int | 978 | static int tty3215_write_room(struct tty_struct *tty) |
931 | tty3215_write_room(struct tty_struct *tty) | ||
932 | { | 979 | { |
933 | struct raw3215_info *raw; | 980 | struct raw3215_info *raw; |
934 | 981 | ||
@@ -944,9 +991,8 @@ tty3215_write_room(struct tty_struct *tty) | |||
944 | /* | 991 | /* |
945 | * String write routine for 3215 ttys | 992 | * String write routine for 3215 ttys |
946 | */ | 993 | */ |
947 | static int | 994 | static int tty3215_write(struct tty_struct * tty, |
948 | tty3215_write(struct tty_struct * tty, | 995 | const unsigned char *buf, int count) |
949 | const unsigned char *buf, int count) | ||
950 | { | 996 | { |
951 | struct raw3215_info *raw; | 997 | struct raw3215_info *raw; |
952 | 998 | ||
@@ -960,8 +1006,7 @@ tty3215_write(struct tty_struct * tty, | |||
960 | /* | 1006 | /* |
961 | * Put character routine for 3215 ttys | 1007 | * Put character routine for 3215 ttys |
962 | */ | 1008 | */ |
963 | static int | 1009 | static int tty3215_put_char(struct tty_struct *tty, unsigned char ch) |
964 | tty3215_put_char(struct tty_struct *tty, unsigned char ch) | ||
965 | { | 1010 | { |
966 | struct raw3215_info *raw; | 1011 | struct raw3215_info *raw; |
967 | 1012 | ||
@@ -972,16 +1017,14 @@ tty3215_put_char(struct tty_struct *tty, unsigned char ch) | |||
972 | return 1; | 1017 | return 1; |
973 | } | 1018 | } |
974 | 1019 | ||
975 | static void | 1020 | static void tty3215_flush_chars(struct tty_struct *tty) |
976 | tty3215_flush_chars(struct tty_struct *tty) | ||
977 | { | 1021 | { |
978 | } | 1022 | } |
979 | 1023 | ||
980 | /* | 1024 | /* |
981 | * Returns the number of characters in the output buffer | 1025 | * Returns the number of characters in the output buffer |
982 | */ | 1026 | */ |
983 | static int | 1027 | static int tty3215_chars_in_buffer(struct tty_struct *tty) |
984 | tty3215_chars_in_buffer(struct tty_struct *tty) | ||
985 | { | 1028 | { |
986 | struct raw3215_info *raw; | 1029 | struct raw3215_info *raw; |
987 | 1030 | ||
@@ -989,8 +1032,7 @@ tty3215_chars_in_buffer(struct tty_struct *tty) | |||
989 | return raw->count; | 1032 | return raw->count; |
990 | } | 1033 | } |
991 | 1034 | ||
992 | static void | 1035 | static void tty3215_flush_buffer(struct tty_struct *tty) |
993 | tty3215_flush_buffer(struct tty_struct *tty) | ||
994 | { | 1036 | { |
995 | struct raw3215_info *raw; | 1037 | struct raw3215_info *raw; |
996 | 1038 | ||
@@ -1002,9 +1044,8 @@ tty3215_flush_buffer(struct tty_struct *tty) | |||
1002 | /* | 1044 | /* |
1003 | * Currently we don't have any io controls for 3215 ttys | 1045 | * Currently we don't have any io controls for 3215 ttys |
1004 | */ | 1046 | */ |
1005 | static int | 1047 | static int tty3215_ioctl(struct tty_struct *tty, struct file * file, |
1006 | tty3215_ioctl(struct tty_struct *tty, struct file * file, | 1048 | unsigned int cmd, unsigned long arg) |
1007 | unsigned int cmd, unsigned long arg) | ||
1008 | { | 1049 | { |
1009 | if (tty->flags & (1 << TTY_IO_ERROR)) | 1050 | if (tty->flags & (1 << TTY_IO_ERROR)) |
1010 | return -EIO; | 1051 | return -EIO; |
@@ -1019,8 +1060,7 @@ tty3215_ioctl(struct tty_struct *tty, struct file * file, | |||
1019 | /* | 1060 | /* |
1020 | * Disable reading from a 3215 tty | 1061 | * Disable reading from a 3215 tty |
1021 | */ | 1062 | */ |
1022 | static void | 1063 | static void tty3215_throttle(struct tty_struct * tty) |
1023 | tty3215_throttle(struct tty_struct * tty) | ||
1024 | { | 1064 | { |
1025 | struct raw3215_info *raw; | 1065 | struct raw3215_info *raw; |
1026 | 1066 | ||
@@ -1031,8 +1071,7 @@ tty3215_throttle(struct tty_struct * tty) | |||
1031 | /* | 1071 | /* |
1032 | * Enable reading from a 3215 tty | 1072 | * Enable reading from a 3215 tty |
1033 | */ | 1073 | */ |
1034 | static void | 1074 | static void tty3215_unthrottle(struct tty_struct * tty) |
1035 | tty3215_unthrottle(struct tty_struct * tty) | ||
1036 | { | 1075 | { |
1037 | struct raw3215_info *raw; | 1076 | struct raw3215_info *raw; |
1038 | unsigned long flags; | 1077 | unsigned long flags; |
@@ -1049,8 +1088,7 @@ tty3215_unthrottle(struct tty_struct * tty) | |||
1049 | /* | 1088 | /* |
1050 | * Disable writing to a 3215 tty | 1089 | * Disable writing to a 3215 tty |
1051 | */ | 1090 | */ |
1052 | static void | 1091 | static void tty3215_stop(struct tty_struct *tty) |
1053 | tty3215_stop(struct tty_struct *tty) | ||
1054 | { | 1092 | { |
1055 | struct raw3215_info *raw; | 1093 | struct raw3215_info *raw; |
1056 | 1094 | ||
@@ -1061,8 +1099,7 @@ tty3215_stop(struct tty_struct *tty) | |||
1061 | /* | 1099 | /* |
1062 | * Enable writing to a 3215 tty | 1100 | * Enable writing to a 3215 tty |
1063 | */ | 1101 | */ |
1064 | static void | 1102 | static void tty3215_start(struct tty_struct *tty) |
1065 | tty3215_start(struct tty_struct *tty) | ||
1066 | { | 1103 | { |
1067 | struct raw3215_info *raw; | 1104 | struct raw3215_info *raw; |
1068 | unsigned long flags; | 1105 | unsigned long flags; |
@@ -1096,8 +1133,7 @@ static const struct tty_operations tty3215_ops = { | |||
1096 | * 3215 tty registration code called from tty_init(). | 1133 | * 3215 tty registration code called from tty_init(). |
1097 | * Most kernel services (incl. kmalloc) are available at this poimt. | 1134 | * Most kernel services (incl. kmalloc) are available at this poimt. |
1098 | */ | 1135 | */ |
1099 | static int __init | 1136 | static int __init tty3215_init(void) |
1100 | tty3215_init(void) | ||
1101 | { | 1137 | { |
1102 | struct tty_driver *driver; | 1138 | struct tty_driver *driver; |
1103 | int ret; | 1139 | int ret; |
@@ -1142,8 +1178,7 @@ tty3215_init(void) | |||
1142 | return 0; | 1178 | return 0; |
1143 | } | 1179 | } |
1144 | 1180 | ||
1145 | static void __exit | 1181 | static void __exit tty3215_exit(void) |
1146 | tty3215_exit(void) | ||
1147 | { | 1182 | { |
1148 | tty_unregister_driver(tty3215_driver); | 1183 | tty_unregister_driver(tty3215_driver); |
1149 | put_tty_driver(tty3215_driver); | 1184 | put_tty_driver(tty3215_driver); |
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index d028d2ee83dd..44d02e371c04 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/con3270.c | 2 | * IBM/3270 Driver - console view. |
3 | * IBM/3270 Driver - console view. | ||
4 | * | 3 | * |
5 | * Author(s): | 4 | * Author(s): |
6 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) | 5 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) |
7 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 7 | * Copyright IBM Corp. 2003, 2009 |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
@@ -64,7 +63,7 @@ static struct con3270 *condev; | |||
64 | #define CON_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */ | 63 | #define CON_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */ |
65 | #define CON_UPDATE_LIST 2 /* Update lines in tty3270->update. */ | 64 | #define CON_UPDATE_LIST 2 /* Update lines in tty3270->update. */ |
66 | #define CON_UPDATE_STATUS 4 /* Update status line. */ | 65 | #define CON_UPDATE_STATUS 4 /* Update status line. */ |
67 | #define CON_UPDATE_ALL 7 | 66 | #define CON_UPDATE_ALL 8 /* Recreate screen. */ |
68 | 67 | ||
69 | static void con3270_update(struct con3270 *); | 68 | static void con3270_update(struct con3270 *); |
70 | 69 | ||
@@ -73,18 +72,10 @@ static void con3270_update(struct con3270 *); | |||
73 | */ | 72 | */ |
74 | static void con3270_set_timer(struct con3270 *cp, int expires) | 73 | static void con3270_set_timer(struct con3270 *cp, int expires) |
75 | { | 74 | { |
76 | if (expires == 0) { | 75 | if (expires == 0) |
77 | if (timer_pending(&cp->timer)) | 76 | del_timer(&cp->timer); |
78 | del_timer(&cp->timer); | 77 | else |
79 | return; | 78 | mod_timer(&cp->timer, jiffies + expires); |
80 | } | ||
81 | if (timer_pending(&cp->timer) && | ||
82 | mod_timer(&cp->timer, jiffies + expires)) | ||
83 | return; | ||
84 | cp->timer.function = (void (*)(unsigned long)) con3270_update; | ||
85 | cp->timer.data = (unsigned long) cp; | ||
86 | cp->timer.expires = jiffies + expires; | ||
87 | add_timer(&cp->timer); | ||
88 | } | 79 | } |
89 | 80 | ||
90 | /* | 81 | /* |
@@ -225,6 +216,12 @@ con3270_update(struct con3270 *cp) | |||
225 | 216 | ||
226 | spin_lock_irqsave(&cp->view.lock, flags); | 217 | spin_lock_irqsave(&cp->view.lock, flags); |
227 | updated = 0; | 218 | updated = 0; |
219 | if (cp->update_flags & CON_UPDATE_ALL) { | ||
220 | con3270_rebuild_update(cp); | ||
221 | con3270_update_status(cp); | ||
222 | cp->update_flags = CON_UPDATE_ERASE | CON_UPDATE_LIST | | ||
223 | CON_UPDATE_STATUS; | ||
224 | } | ||
228 | if (cp->update_flags & CON_UPDATE_ERASE) { | 225 | if (cp->update_flags & CON_UPDATE_ERASE) { |
229 | /* Use erase write alternate to initialize display. */ | 226 | /* Use erase write alternate to initialize display. */ |
230 | raw3270_request_set_cmd(wrq, TC_EWRITEA); | 227 | raw3270_request_set_cmd(wrq, TC_EWRITEA); |
@@ -302,7 +299,6 @@ con3270_read_tasklet(struct raw3270_request *rrq) | |||
302 | deactivate = 1; | 299 | deactivate = 1; |
303 | break; | 300 | break; |
304 | case 0x6d: /* clear: start from scratch. */ | 301 | case 0x6d: /* clear: start from scratch. */ |
305 | con3270_rebuild_update(cp); | ||
306 | cp->update_flags = CON_UPDATE_ALL; | 302 | cp->update_flags = CON_UPDATE_ALL; |
307 | con3270_set_timer(cp, 1); | 303 | con3270_set_timer(cp, 1); |
308 | break; | 304 | break; |
@@ -382,30 +378,21 @@ con3270_issue_read(struct con3270 *cp) | |||
382 | static int | 378 | static int |
383 | con3270_activate(struct raw3270_view *view) | 379 | con3270_activate(struct raw3270_view *view) |
384 | { | 380 | { |
385 | unsigned long flags; | ||
386 | struct con3270 *cp; | 381 | struct con3270 *cp; |
387 | 382 | ||
388 | cp = (struct con3270 *) view; | 383 | cp = (struct con3270 *) view; |
389 | spin_lock_irqsave(&cp->view.lock, flags); | ||
390 | cp->nr_up = 0; | ||
391 | con3270_rebuild_update(cp); | ||
392 | con3270_update_status(cp); | ||
393 | cp->update_flags = CON_UPDATE_ALL; | 384 | cp->update_flags = CON_UPDATE_ALL; |
394 | con3270_set_timer(cp, 1); | 385 | con3270_set_timer(cp, 1); |
395 | spin_unlock_irqrestore(&cp->view.lock, flags); | ||
396 | return 0; | 386 | return 0; |
397 | } | 387 | } |
398 | 388 | ||
399 | static void | 389 | static void |
400 | con3270_deactivate(struct raw3270_view *view) | 390 | con3270_deactivate(struct raw3270_view *view) |
401 | { | 391 | { |
402 | unsigned long flags; | ||
403 | struct con3270 *cp; | 392 | struct con3270 *cp; |
404 | 393 | ||
405 | cp = (struct con3270 *) view; | 394 | cp = (struct con3270 *) view; |
406 | spin_lock_irqsave(&cp->view.lock, flags); | ||
407 | del_timer(&cp->timer); | 395 | del_timer(&cp->timer); |
408 | spin_unlock_irqrestore(&cp->view.lock, flags); | ||
409 | } | 396 | } |
410 | 397 | ||
411 | static int | 398 | static int |
@@ -504,6 +491,7 @@ con3270_write(struct console *co, const char *str, unsigned int count) | |||
504 | con3270_cline_end(cp); | 491 | con3270_cline_end(cp); |
505 | } | 492 | } |
506 | /* Setup timer to output current console buffer after 1/10 second */ | 493 | /* Setup timer to output current console buffer after 1/10 second */ |
494 | cp->nr_up = 0; | ||
507 | if (cp->view.dev && !timer_pending(&cp->timer)) | 495 | if (cp->view.dev && !timer_pending(&cp->timer)) |
508 | con3270_set_timer(cp, HZ/10); | 496 | con3270_set_timer(cp, HZ/10); |
509 | spin_unlock_irqrestore(&cp->view.lock,flags); | 497 | spin_unlock_irqrestore(&cp->view.lock,flags); |
@@ -541,6 +529,7 @@ con3270_flush(void) | |||
541 | cp = condev; | 529 | cp = condev; |
542 | if (!cp->view.dev) | 530 | if (!cp->view.dev) |
543 | return; | 531 | return; |
532 | raw3270_pm_unfreeze(&cp->view); | ||
544 | spin_lock_irqsave(&cp->view.lock, flags); | 533 | spin_lock_irqsave(&cp->view.lock, flags); |
545 | con3270_wait_write(cp); | 534 | con3270_wait_write(cp); |
546 | cp->nr_up = 0; | 535 | cp->nr_up = 0; |
@@ -624,7 +613,8 @@ con3270_init(void) | |||
624 | 613 | ||
625 | INIT_LIST_HEAD(&condev->lines); | 614 | INIT_LIST_HEAD(&condev->lines); |
626 | INIT_LIST_HEAD(&condev->update); | 615 | INIT_LIST_HEAD(&condev->update); |
627 | init_timer(&condev->timer); | 616 | setup_timer(&condev->timer, (void (*)(unsigned long)) con3270_update, |
617 | (unsigned long) condev); | ||
628 | tasklet_init(&condev->readlet, | 618 | tasklet_init(&condev->readlet, |
629 | (void (*)(unsigned long)) con3270_read_tasklet, | 619 | (void (*)(unsigned long)) con3270_read_tasklet, |
630 | (unsigned long) condev->read); | 620 | (unsigned long) condev->read); |
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 40759c33477d..097d3846a828 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/fs3270.c | 2 | * IBM/3270 Driver - fullscreen driver. |
3 | * IBM/3270 Driver - fullscreen driver. | ||
4 | * | 3 | * |
5 | * Author(s): | 4 | * Author(s): |
6 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) | 5 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) |
7 | * Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 7 | * Copyright IBM Corp. 2003, 2009 |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
@@ -399,6 +398,11 @@ fs3270_free_view(struct raw3270_view *view) | |||
399 | static void | 398 | static void |
400 | fs3270_release(struct raw3270_view *view) | 399 | fs3270_release(struct raw3270_view *view) |
401 | { | 400 | { |
401 | struct fs3270 *fp; | ||
402 | |||
403 | fp = (struct fs3270 *) view; | ||
404 | if (fp->fs_pid) | ||
405 | kill_pid(fp->fs_pid, SIGHUP, 1); | ||
402 | } | 406 | } |
403 | 407 | ||
404 | /* View to a 3270 device. Can be console, tty or fullscreen. */ | 408 | /* View to a 3270 device. Can be console, tty or fullscreen. */ |
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 97e63cf46944..75a8831eebbc 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c | |||
@@ -1,10 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/monreader.c | ||
3 | * | ||
4 | * Character device driver for reading z/VM *MONITOR service records. | 2 | * Character device driver for reading z/VM *MONITOR service records. |
5 | * | 3 | * |
6 | * Copyright IBM Corp. 2004, 2008 | 4 | * Copyright IBM Corp. 2004, 2009 |
7 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> | 5 | * |
6 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> | ||
8 | */ | 7 | */ |
9 | 8 | ||
10 | #define KMSG_COMPONENT "monreader" | 9 | #define KMSG_COMPONENT "monreader" |
@@ -22,6 +21,7 @@ | |||
22 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
23 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
24 | #include <linux/poll.h> | 23 | #include <linux/poll.h> |
24 | #include <linux/device.h> | ||
25 | #include <net/iucv/iucv.h> | 25 | #include <net/iucv/iucv.h> |
26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
27 | #include <asm/ebcdic.h> | 27 | #include <asm/ebcdic.h> |
@@ -78,6 +78,7 @@ static u8 user_data_sever[16] = { | |||
78 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 78 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | static struct device *monreader_device; | ||
81 | 82 | ||
82 | /****************************************************************************** | 83 | /****************************************************************************** |
83 | * helper functions * | 84 | * helper functions * |
@@ -319,11 +320,12 @@ static int mon_open(struct inode *inode, struct file *filp) | |||
319 | goto out_path; | 320 | goto out_path; |
320 | } | 321 | } |
321 | filp->private_data = monpriv; | 322 | filp->private_data = monpriv; |
323 | monreader_device->driver_data = monpriv; | ||
322 | unlock_kernel(); | 324 | unlock_kernel(); |
323 | return nonseekable_open(inode, filp); | 325 | return nonseekable_open(inode, filp); |
324 | 326 | ||
325 | out_path: | 327 | out_path: |
326 | kfree(monpriv->path); | 328 | iucv_path_free(monpriv->path); |
327 | out_priv: | 329 | out_priv: |
328 | mon_free_mem(monpriv); | 330 | mon_free_mem(monpriv); |
329 | out_use: | 331 | out_use: |
@@ -341,10 +343,13 @@ static int mon_close(struct inode *inode, struct file *filp) | |||
341 | /* | 343 | /* |
342 | * Close IUCV connection and unregister | 344 | * Close IUCV connection and unregister |
343 | */ | 345 | */ |
344 | rc = iucv_path_sever(monpriv->path, user_data_sever); | 346 | if (monpriv->path) { |
345 | if (rc) | 347 | rc = iucv_path_sever(monpriv->path, user_data_sever); |
346 | pr_warning("Disconnecting the z/VM *MONITOR system service " | 348 | if (rc) |
347 | "failed with rc=%i\n", rc); | 349 | pr_warning("Disconnecting the z/VM *MONITOR system " |
350 | "service failed with rc=%i\n", rc); | ||
351 | iucv_path_free(monpriv->path); | ||
352 | } | ||
348 | 353 | ||
349 | atomic_set(&monpriv->iucv_severed, 0); | 354 | atomic_set(&monpriv->iucv_severed, 0); |
350 | atomic_set(&monpriv->iucv_connected, 0); | 355 | atomic_set(&monpriv->iucv_connected, 0); |
@@ -452,6 +457,94 @@ static struct miscdevice mon_dev = { | |||
452 | .minor = MISC_DYNAMIC_MINOR, | 457 | .minor = MISC_DYNAMIC_MINOR, |
453 | }; | 458 | }; |
454 | 459 | ||
460 | |||
461 | /****************************************************************************** | ||
462 | * suspend / resume * | ||
463 | *****************************************************************************/ | ||
464 | static int monreader_freeze(struct device *dev) | ||
465 | { | ||
466 | struct mon_private *monpriv = dev->driver_data; | ||
467 | int rc; | ||
468 | |||
469 | if (!monpriv) | ||
470 | return 0; | ||
471 | if (monpriv->path) { | ||
472 | rc = iucv_path_sever(monpriv->path, user_data_sever); | ||
473 | if (rc) | ||
474 | pr_warning("Disconnecting the z/VM *MONITOR system " | ||
475 | "service failed with rc=%i\n", rc); | ||
476 | iucv_path_free(monpriv->path); | ||
477 | } | ||
478 | atomic_set(&monpriv->iucv_severed, 0); | ||
479 | atomic_set(&monpriv->iucv_connected, 0); | ||
480 | atomic_set(&monpriv->read_ready, 0); | ||
481 | atomic_set(&monpriv->msglim_count, 0); | ||
482 | monpriv->write_index = 0; | ||
483 | monpriv->read_index = 0; | ||
484 | monpriv->path = NULL; | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int monreader_thaw(struct device *dev) | ||
489 | { | ||
490 | struct mon_private *monpriv = dev->driver_data; | ||
491 | int rc; | ||
492 | |||
493 | if (!monpriv) | ||
494 | return 0; | ||
495 | rc = -ENOMEM; | ||
496 | monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); | ||
497 | if (!monpriv->path) | ||
498 | goto out; | ||
499 | rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, | ||
500 | MON_SERVICE, NULL, user_data_connect, monpriv); | ||
501 | if (rc) { | ||
502 | pr_err("Connecting to the z/VM *MONITOR system service " | ||
503 | "failed with rc=%i\n", rc); | ||
504 | goto out_path; | ||
505 | } | ||
506 | wait_event(mon_conn_wait_queue, | ||
507 | atomic_read(&monpriv->iucv_connected) || | ||
508 | atomic_read(&monpriv->iucv_severed)); | ||
509 | if (atomic_read(&monpriv->iucv_severed)) | ||
510 | goto out_path; | ||
511 | return 0; | ||
512 | out_path: | ||
513 | rc = -EIO; | ||
514 | iucv_path_free(monpriv->path); | ||
515 | monpriv->path = NULL; | ||
516 | out: | ||
517 | atomic_set(&monpriv->iucv_severed, 1); | ||
518 | return rc; | ||
519 | } | ||
520 | |||
521 | static int monreader_restore(struct device *dev) | ||
522 | { | ||
523 | int rc; | ||
524 | |||
525 | segment_unload(mon_dcss_name); | ||
526 | rc = segment_load(mon_dcss_name, SEGMENT_SHARED, | ||
527 | &mon_dcss_start, &mon_dcss_end); | ||
528 | if (rc < 0) { | ||
529 | segment_warning(rc, mon_dcss_name); | ||
530 | panic("fatal monreader resume error: no monitor dcss\n"); | ||
531 | } | ||
532 | return monreader_thaw(dev); | ||
533 | } | ||
534 | |||
535 | static struct dev_pm_ops monreader_pm_ops = { | ||
536 | .freeze = monreader_freeze, | ||
537 | .thaw = monreader_thaw, | ||
538 | .restore = monreader_restore, | ||
539 | }; | ||
540 | |||
541 | static struct device_driver monreader_driver = { | ||
542 | .name = "monreader", | ||
543 | .bus = &iucv_bus, | ||
544 | .pm = &monreader_pm_ops, | ||
545 | }; | ||
546 | |||
547 | |||
455 | /****************************************************************************** | 548 | /****************************************************************************** |
456 | * module init/exit * | 549 | * module init/exit * |
457 | *****************************************************************************/ | 550 | *****************************************************************************/ |
@@ -475,16 +568,33 @@ static int __init mon_init(void) | |||
475 | return rc; | 568 | return rc; |
476 | } | 569 | } |
477 | 570 | ||
571 | rc = driver_register(&monreader_driver); | ||
572 | if (rc) | ||
573 | goto out_iucv; | ||
574 | monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
575 | if (!monreader_device) | ||
576 | goto out_driver; | ||
577 | dev_set_name(monreader_device, "monreader-dev"); | ||
578 | monreader_device->bus = &iucv_bus; | ||
579 | monreader_device->parent = iucv_root; | ||
580 | monreader_device->driver = &monreader_driver; | ||
581 | monreader_device->release = (void (*)(struct device *))kfree; | ||
582 | rc = device_register(monreader_device); | ||
583 | if (rc) { | ||
584 | kfree(monreader_device); | ||
585 | goto out_driver; | ||
586 | } | ||
587 | |||
478 | rc = segment_type(mon_dcss_name); | 588 | rc = segment_type(mon_dcss_name); |
479 | if (rc < 0) { | 589 | if (rc < 0) { |
480 | segment_warning(rc, mon_dcss_name); | 590 | segment_warning(rc, mon_dcss_name); |
481 | goto out_iucv; | 591 | goto out_device; |
482 | } | 592 | } |
483 | if (rc != SEG_TYPE_SC) { | 593 | if (rc != SEG_TYPE_SC) { |
484 | pr_err("The specified *MONITOR DCSS %s does not have the " | 594 | pr_err("The specified *MONITOR DCSS %s does not have the " |
485 | "required type SC\n", mon_dcss_name); | 595 | "required type SC\n", mon_dcss_name); |
486 | rc = -EINVAL; | 596 | rc = -EINVAL; |
487 | goto out_iucv; | 597 | goto out_device; |
488 | } | 598 | } |
489 | 599 | ||
490 | rc = segment_load(mon_dcss_name, SEGMENT_SHARED, | 600 | rc = segment_load(mon_dcss_name, SEGMENT_SHARED, |
@@ -492,7 +602,7 @@ static int __init mon_init(void) | |||
492 | if (rc < 0) { | 602 | if (rc < 0) { |
493 | segment_warning(rc, mon_dcss_name); | 603 | segment_warning(rc, mon_dcss_name); |
494 | rc = -EINVAL; | 604 | rc = -EINVAL; |
495 | goto out_iucv; | 605 | goto out_device; |
496 | } | 606 | } |
497 | dcss_mkname(mon_dcss_name, &user_data_connect[8]); | 607 | dcss_mkname(mon_dcss_name, &user_data_connect[8]); |
498 | 608 | ||
@@ -503,6 +613,10 @@ static int __init mon_init(void) | |||
503 | 613 | ||
504 | out: | 614 | out: |
505 | segment_unload(mon_dcss_name); | 615 | segment_unload(mon_dcss_name); |
616 | out_device: | ||
617 | device_unregister(monreader_device); | ||
618 | out_driver: | ||
619 | driver_unregister(&monreader_driver); | ||
506 | out_iucv: | 620 | out_iucv: |
507 | iucv_unregister(&monreader_iucv_handler, 1); | 621 | iucv_unregister(&monreader_iucv_handler, 1); |
508 | return rc; | 622 | return rc; |
@@ -512,6 +626,8 @@ static void __exit mon_exit(void) | |||
512 | { | 626 | { |
513 | segment_unload(mon_dcss_name); | 627 | segment_unload(mon_dcss_name); |
514 | WARN_ON(misc_deregister(&mon_dev) != 0); | 628 | WARN_ON(misc_deregister(&mon_dev) != 0); |
629 | device_unregister(monreader_device); | ||
630 | driver_unregister(&monreader_driver); | ||
515 | iucv_unregister(&monreader_iucv_handler, 1); | 631 | iucv_unregister(&monreader_iucv_handler, 1); |
516 | return; | 632 | return; |
517 | } | 633 | } |
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index c7d7483bab9a..66fb8eba93f4 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/monwriter.c | ||
3 | * | ||
4 | * Character device driver for writing z/VM *MONITOR service records. | 2 | * Character device driver for writing z/VM *MONITOR service records. |
5 | * | 3 | * |
6 | * Copyright (C) IBM Corp. 2006 | 4 | * Copyright IBM Corp. 2006, 2009 |
7 | * | 5 | * |
8 | * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com> | 6 | * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com> |
9 | */ | 7 | */ |
@@ -22,6 +20,7 @@ | |||
22 | #include <linux/ctype.h> | 20 | #include <linux/ctype.h> |
23 | #include <linux/poll.h> | 21 | #include <linux/poll.h> |
24 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/platform_device.h> | ||
25 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
26 | #include <asm/ebcdic.h> | 25 | #include <asm/ebcdic.h> |
27 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -40,7 +39,10 @@ struct mon_buf { | |||
40 | char *data; | 39 | char *data; |
41 | }; | 40 | }; |
42 | 41 | ||
42 | static LIST_HEAD(mon_priv_list); | ||
43 | |||
43 | struct mon_private { | 44 | struct mon_private { |
45 | struct list_head priv_list; | ||
44 | struct list_head list; | 46 | struct list_head list; |
45 | struct monwrite_hdr hdr; | 47 | struct monwrite_hdr hdr; |
46 | size_t hdr_to_read; | 48 | size_t hdr_to_read; |
@@ -188,6 +190,7 @@ static int monwrite_open(struct inode *inode, struct file *filp) | |||
188 | monpriv->hdr_to_read = sizeof(monpriv->hdr); | 190 | monpriv->hdr_to_read = sizeof(monpriv->hdr); |
189 | mutex_init(&monpriv->thread_mutex); | 191 | mutex_init(&monpriv->thread_mutex); |
190 | filp->private_data = monpriv; | 192 | filp->private_data = monpriv; |
193 | list_add_tail(&monpriv->priv_list, &mon_priv_list); | ||
191 | unlock_kernel(); | 194 | unlock_kernel(); |
192 | return nonseekable_open(inode, filp); | 195 | return nonseekable_open(inode, filp); |
193 | } | 196 | } |
@@ -206,6 +209,7 @@ static int monwrite_close(struct inode *inode, struct file *filp) | |||
206 | kfree(entry->data); | 209 | kfree(entry->data); |
207 | kfree(entry); | 210 | kfree(entry); |
208 | } | 211 | } |
212 | list_del(&monpriv->priv_list); | ||
209 | kfree(monpriv); | 213 | kfree(monpriv); |
210 | return 0; | 214 | return 0; |
211 | } | 215 | } |
@@ -281,20 +285,102 @@ static struct miscdevice mon_dev = { | |||
281 | }; | 285 | }; |
282 | 286 | ||
283 | /* | 287 | /* |
288 | * suspend/resume | ||
289 | */ | ||
290 | |||
291 | static int monwriter_freeze(struct device *dev) | ||
292 | { | ||
293 | struct mon_private *monpriv; | ||
294 | struct mon_buf *monbuf; | ||
295 | |||
296 | list_for_each_entry(monpriv, &mon_priv_list, priv_list) { | ||
297 | list_for_each_entry(monbuf, &monpriv->list, list) { | ||
298 | if (monbuf->hdr.mon_function != MONWRITE_GEN_EVENT) | ||
299 | monwrite_diag(&monbuf->hdr, monbuf->data, | ||
300 | APPLDATA_STOP_REC); | ||
301 | } | ||
302 | } | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int monwriter_restore(struct device *dev) | ||
307 | { | ||
308 | struct mon_private *monpriv; | ||
309 | struct mon_buf *monbuf; | ||
310 | |||
311 | list_for_each_entry(monpriv, &mon_priv_list, priv_list) { | ||
312 | list_for_each_entry(monbuf, &monpriv->list, list) { | ||
313 | if (monbuf->hdr.mon_function == MONWRITE_START_INTERVAL) | ||
314 | monwrite_diag(&monbuf->hdr, monbuf->data, | ||
315 | APPLDATA_START_INTERVAL_REC); | ||
316 | if (monbuf->hdr.mon_function == MONWRITE_START_CONFIG) | ||
317 | monwrite_diag(&monbuf->hdr, monbuf->data, | ||
318 | APPLDATA_START_CONFIG_REC); | ||
319 | } | ||
320 | } | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int monwriter_thaw(struct device *dev) | ||
325 | { | ||
326 | return monwriter_restore(dev); | ||
327 | } | ||
328 | |||
329 | static struct dev_pm_ops monwriter_pm_ops = { | ||
330 | .freeze = monwriter_freeze, | ||
331 | .thaw = monwriter_thaw, | ||
332 | .restore = monwriter_restore, | ||
333 | }; | ||
334 | |||
335 | static struct platform_driver monwriter_pdrv = { | ||
336 | .driver = { | ||
337 | .name = "monwriter", | ||
338 | .owner = THIS_MODULE, | ||
339 | .pm = &monwriter_pm_ops, | ||
340 | }, | ||
341 | }; | ||
342 | |||
343 | static struct platform_device *monwriter_pdev; | ||
344 | |||
345 | /* | ||
284 | * module init/exit | 346 | * module init/exit |
285 | */ | 347 | */ |
286 | 348 | ||
287 | static int __init mon_init(void) | 349 | static int __init mon_init(void) |
288 | { | 350 | { |
289 | if (MACHINE_IS_VM) | 351 | int rc; |
290 | return misc_register(&mon_dev); | 352 | |
291 | else | 353 | if (!MACHINE_IS_VM) |
292 | return -ENODEV; | 354 | return -ENODEV; |
355 | |||
356 | rc = platform_driver_register(&monwriter_pdrv); | ||
357 | if (rc) | ||
358 | return rc; | ||
359 | |||
360 | monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL, | ||
361 | 0); | ||
362 | if (IS_ERR(monwriter_pdev)) { | ||
363 | rc = PTR_ERR(monwriter_pdev); | ||
364 | goto out_driver; | ||
365 | } | ||
366 | |||
367 | rc = misc_register(&mon_dev); | ||
368 | if (rc) | ||
369 | goto out_device; | ||
370 | return 0; | ||
371 | |||
372 | out_device: | ||
373 | platform_device_unregister(monwriter_pdev); | ||
374 | out_driver: | ||
375 | platform_driver_unregister(&monwriter_pdrv); | ||
376 | return rc; | ||
293 | } | 377 | } |
294 | 378 | ||
295 | static void __exit mon_exit(void) | 379 | static void __exit mon_exit(void) |
296 | { | 380 | { |
297 | WARN_ON(misc_deregister(&mon_dev) != 0); | 381 | WARN_ON(misc_deregister(&mon_dev) != 0); |
382 | platform_device_unregister(monwriter_pdev); | ||
383 | platform_driver_unregister(&monwriter_pdrv); | ||
298 | } | 384 | } |
299 | 385 | ||
300 | module_init(mon_init); | 386 | module_init(mon_init); |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 0b15cf107ec9..acab7b2dfe8a 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/raw3270.c | 2 | * IBM/3270 Driver - core functions. |
3 | * IBM/3270 Driver - core functions. | ||
4 | * | 3 | * |
5 | * Author(s): | 4 | * Author(s): |
6 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) | 5 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) |
7 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 7 | * Copyright IBM Corp. 2003, 2009 |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
@@ -61,6 +60,7 @@ struct raw3270 { | |||
61 | #define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */ | 60 | #define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */ |
62 | #define RAW3270_FLAGS_READY 4 /* Device is useable by views */ | 61 | #define RAW3270_FLAGS_READY 4 /* Device is useable by views */ |
63 | #define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */ | 62 | #define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */ |
63 | #define RAW3270_FLAGS_FROZEN 16 /* set if 3270 is frozen for suspend */ | ||
64 | 64 | ||
65 | /* Semaphore to protect global data of raw3270 (devices, views, etc). */ | 65 | /* Semaphore to protect global data of raw3270 (devices, views, etc). */ |
66 | static DEFINE_MUTEX(raw3270_mutex); | 66 | static DEFINE_MUTEX(raw3270_mutex); |
@@ -306,7 +306,8 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq) | |||
306 | 306 | ||
307 | spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags); | 307 | spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags); |
308 | rp = view->dev; | 308 | rp = view->dev; |
309 | if (!rp || rp->view != view) | 309 | if (!rp || rp->view != view || |
310 | test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
310 | rc = -EACCES; | 311 | rc = -EACCES; |
311 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | 312 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) |
312 | rc = -ENODEV; | 313 | rc = -ENODEV; |
@@ -323,7 +324,8 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq) | |||
323 | int rc; | 324 | int rc; |
324 | 325 | ||
325 | rp = view->dev; | 326 | rp = view->dev; |
326 | if (!rp || rp->view != view) | 327 | if (!rp || rp->view != view || |
328 | test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
327 | rc = -EACCES; | 329 | rc = -EACCES; |
328 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | 330 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) |
329 | rc = -ENODEV; | 331 | rc = -ENODEV; |
@@ -355,7 +357,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
355 | struct raw3270_request *rq; | 357 | struct raw3270_request *rq; |
356 | int rc; | 358 | int rc; |
357 | 359 | ||
358 | rp = (struct raw3270 *) cdev->dev.driver_data; | 360 | rp = dev_get_drvdata(&cdev->dev); |
359 | if (!rp) | 361 | if (!rp) |
360 | return; | 362 | return; |
361 | rq = (struct raw3270_request *) intparm; | 363 | rq = (struct raw3270_request *) intparm; |
@@ -764,7 +766,8 @@ raw3270_reset(struct raw3270_view *view) | |||
764 | int rc; | 766 | int rc; |
765 | 767 | ||
766 | rp = view->dev; | 768 | rp = view->dev; |
767 | if (!rp || rp->view != view) | 769 | if (!rp || rp->view != view || |
770 | test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
768 | rc = -EACCES; | 771 | rc = -EACCES; |
769 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | 772 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) |
770 | rc = -ENODEV; | 773 | rc = -ENODEV; |
@@ -828,7 +831,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc) | |||
828 | if (rp->minor == -1) | 831 | if (rp->minor == -1) |
829 | return -EUSERS; | 832 | return -EUSERS; |
830 | rp->cdev = cdev; | 833 | rp->cdev = cdev; |
831 | cdev->dev.driver_data = rp; | 834 | dev_set_drvdata(&cdev->dev, rp); |
832 | cdev->handler = raw3270_irq; | 835 | cdev->handler = raw3270_irq; |
833 | return 0; | 836 | return 0; |
834 | } | 837 | } |
@@ -922,6 +925,8 @@ raw3270_activate_view(struct raw3270_view *view) | |||
922 | rc = 0; | 925 | rc = 0; |
923 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | 926 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) |
924 | rc = -ENODEV; | 927 | rc = -ENODEV; |
928 | else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
929 | rc = -EACCES; | ||
925 | else { | 930 | else { |
926 | oldview = NULL; | 931 | oldview = NULL; |
927 | if (rp->view) { | 932 | if (rp->view) { |
@@ -969,7 +974,8 @@ raw3270_deactivate_view(struct raw3270_view *view) | |||
969 | list_del_init(&view->list); | 974 | list_del_init(&view->list); |
970 | list_add_tail(&view->list, &rp->view_list); | 975 | list_add_tail(&view->list, &rp->view_list); |
971 | /* Try to activate another view. */ | 976 | /* Try to activate another view. */ |
972 | if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { | 977 | if (test_bit(RAW3270_FLAGS_READY, &rp->flags) && |
978 | !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { | ||
973 | list_for_each_entry(view, &rp->view_list, list) { | 979 | list_for_each_entry(view, &rp->view_list, list) { |
974 | rp->view = view; | 980 | rp->view = view; |
975 | if (view->fn->activate(view) == 0) | 981 | if (view->fn->activate(view) == 0) |
@@ -1068,7 +1074,8 @@ raw3270_del_view(struct raw3270_view *view) | |||
1068 | rp->view = NULL; | 1074 | rp->view = NULL; |
1069 | } | 1075 | } |
1070 | list_del_init(&view->list); | 1076 | list_del_init(&view->list); |
1071 | if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) { | 1077 | if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) && |
1078 | !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { | ||
1072 | /* Try to activate another view. */ | 1079 | /* Try to activate another view. */ |
1073 | list_for_each_entry(nv, &rp->view_list, list) { | 1080 | list_for_each_entry(nv, &rp->view_list, list) { |
1074 | if (nv->fn->activate(nv) == 0) { | 1081 | if (nv->fn->activate(nv) == 0) { |
@@ -1105,7 +1112,7 @@ raw3270_delete_device(struct raw3270 *rp) | |||
1105 | /* Disconnect from ccw_device. */ | 1112 | /* Disconnect from ccw_device. */ |
1106 | cdev = rp->cdev; | 1113 | cdev = rp->cdev; |
1107 | rp->cdev = NULL; | 1114 | rp->cdev = NULL; |
1108 | cdev->dev.driver_data = NULL; | 1115 | dev_set_drvdata(&cdev->dev, NULL); |
1109 | cdev->handler = NULL; | 1116 | cdev->handler = NULL; |
1110 | 1117 | ||
1111 | /* Put ccw_device structure. */ | 1118 | /* Put ccw_device structure. */ |
@@ -1129,7 +1136,7 @@ static ssize_t | |||
1129 | raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf) | 1136 | raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf) |
1130 | { | 1137 | { |
1131 | return snprintf(buf, PAGE_SIZE, "%i\n", | 1138 | return snprintf(buf, PAGE_SIZE, "%i\n", |
1132 | ((struct raw3270 *) dev->driver_data)->model); | 1139 | ((struct raw3270 *) dev_get_drvdata(dev))->model); |
1133 | } | 1140 | } |
1134 | static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL); | 1141 | static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL); |
1135 | 1142 | ||
@@ -1137,7 +1144,7 @@ static ssize_t | |||
1137 | raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf) | 1144 | raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf) |
1138 | { | 1145 | { |
1139 | return snprintf(buf, PAGE_SIZE, "%i\n", | 1146 | return snprintf(buf, PAGE_SIZE, "%i\n", |
1140 | ((struct raw3270 *) dev->driver_data)->rows); | 1147 | ((struct raw3270 *) dev_get_drvdata(dev))->rows); |
1141 | } | 1148 | } |
1142 | static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL); | 1149 | static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL); |
1143 | 1150 | ||
@@ -1145,7 +1152,7 @@ static ssize_t | |||
1145 | raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf) | 1152 | raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf) |
1146 | { | 1153 | { |
1147 | return snprintf(buf, PAGE_SIZE, "%i\n", | 1154 | return snprintf(buf, PAGE_SIZE, "%i\n", |
1148 | ((struct raw3270 *) dev->driver_data)->cols); | 1155 | ((struct raw3270 *) dev_get_drvdata(dev))->cols); |
1149 | } | 1156 | } |
1150 | static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL); | 1157 | static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL); |
1151 | 1158 | ||
@@ -1282,7 +1289,7 @@ raw3270_remove (struct ccw_device *cdev) | |||
1282 | struct raw3270_view *v; | 1289 | struct raw3270_view *v; |
1283 | struct raw3270_notifier *np; | 1290 | struct raw3270_notifier *np; |
1284 | 1291 | ||
1285 | rp = cdev->dev.driver_data; | 1292 | rp = dev_get_drvdata(&cdev->dev); |
1286 | /* | 1293 | /* |
1287 | * _remove is the opposite of _probe; it's probe that | 1294 | * _remove is the opposite of _probe; it's probe that |
1288 | * should set up rp. raw3270_remove gets entered for | 1295 | * should set up rp. raw3270_remove gets entered for |
@@ -1330,13 +1337,65 @@ raw3270_set_offline (struct ccw_device *cdev) | |||
1330 | { | 1337 | { |
1331 | struct raw3270 *rp; | 1338 | struct raw3270 *rp; |
1332 | 1339 | ||
1333 | rp = cdev->dev.driver_data; | 1340 | rp = dev_get_drvdata(&cdev->dev); |
1334 | if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) | 1341 | if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) |
1335 | return -EBUSY; | 1342 | return -EBUSY; |
1336 | raw3270_remove(cdev); | 1343 | raw3270_remove(cdev); |
1337 | return 0; | 1344 | return 0; |
1338 | } | 1345 | } |
1339 | 1346 | ||
1347 | static int raw3270_pm_stop(struct ccw_device *cdev) | ||
1348 | { | ||
1349 | struct raw3270 *rp; | ||
1350 | struct raw3270_view *view; | ||
1351 | unsigned long flags; | ||
1352 | |||
1353 | rp = cdev->dev.driver_data; | ||
1354 | if (!rp) | ||
1355 | return 0; | ||
1356 | spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); | ||
1357 | if (rp->view) | ||
1358 | rp->view->fn->deactivate(rp->view); | ||
1359 | if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) { | ||
1360 | /* | ||
1361 | * Release tty and fullscreen for all non-console | ||
1362 | * devices. | ||
1363 | */ | ||
1364 | list_for_each_entry(view, &rp->view_list, list) { | ||
1365 | if (view->fn->release) | ||
1366 | view->fn->release(view); | ||
1367 | } | ||
1368 | } | ||
1369 | set_bit(RAW3270_FLAGS_FROZEN, &rp->flags); | ||
1370 | spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); | ||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | static int raw3270_pm_start(struct ccw_device *cdev) | ||
1375 | { | ||
1376 | struct raw3270 *rp; | ||
1377 | unsigned long flags; | ||
1378 | |||
1379 | rp = cdev->dev.driver_data; | ||
1380 | if (!rp) | ||
1381 | return 0; | ||
1382 | spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); | ||
1383 | clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags); | ||
1384 | if (rp->view) | ||
1385 | rp->view->fn->activate(rp->view); | ||
1386 | spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); | ||
1387 | return 0; | ||
1388 | } | ||
1389 | |||
1390 | void raw3270_pm_unfreeze(struct raw3270_view *view) | ||
1391 | { | ||
1392 | struct raw3270 *rp; | ||
1393 | |||
1394 | rp = view->dev; | ||
1395 | if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
1396 | ccw_device_force_console(); | ||
1397 | } | ||
1398 | |||
1340 | static struct ccw_device_id raw3270_id[] = { | 1399 | static struct ccw_device_id raw3270_id[] = { |
1341 | { CCW_DEVICE(0x3270, 0) }, | 1400 | { CCW_DEVICE(0x3270, 0) }, |
1342 | { CCW_DEVICE(0x3271, 0) }, | 1401 | { CCW_DEVICE(0x3271, 0) }, |
@@ -1360,6 +1419,9 @@ static struct ccw_driver raw3270_ccw_driver = { | |||
1360 | .remove = &raw3270_remove, | 1419 | .remove = &raw3270_remove, |
1361 | .set_online = &raw3270_set_online, | 1420 | .set_online = &raw3270_set_online, |
1362 | .set_offline = &raw3270_set_offline, | 1421 | .set_offline = &raw3270_set_offline, |
1422 | .freeze = &raw3270_pm_stop, | ||
1423 | .thaw = &raw3270_pm_start, | ||
1424 | .restore = &raw3270_pm_start, | ||
1363 | }; | 1425 | }; |
1364 | 1426 | ||
1365 | static int | 1427 | static int |
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h index 90beaa80a782..ed34eb2199cc 100644 --- a/drivers/s390/char/raw3270.h +++ b/drivers/s390/char/raw3270.h | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/raw3270.h | 2 | * IBM/3270 Driver |
3 | * IBM/3270 Driver | ||
4 | * | 3 | * |
5 | * Author(s): | 4 | * Author(s): |
6 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) | 5 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) |
7 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 7 | * Copyright IBM Corp. 2003, 2009 |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <asm/idals.h> | 10 | #include <asm/idals.h> |
@@ -195,6 +194,7 @@ void raw3270_wait_cons_dev(struct raw3270 *); | |||
195 | /* Notifier for device addition/removal */ | 194 | /* Notifier for device addition/removal */ |
196 | int raw3270_register_notifier(void (*notifier)(int, int)); | 195 | int raw3270_register_notifier(void (*notifier)(int, int)); |
197 | void raw3270_unregister_notifier(void (*notifier)(int, int)); | 196 | void raw3270_unregister_notifier(void (*notifier)(int, int)); |
197 | void raw3270_pm_unfreeze(struct raw3270_view *); | ||
198 | 198 | ||
199 | /* | 199 | /* |
200 | * Little memory allocator for string objects. | 200 | * Little memory allocator for string objects. |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 4377e93a43d7..a983f5086788 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp.c | 2 | * core function to access sclp interface |
3 | * core function to access sclp interface | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 1999, 2009 |
6 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * |
7 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | 6 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/module.h> | 10 | #include <linux/module.h> |
@@ -16,6 +15,9 @@ | |||
16 | #include <linux/reboot.h> | 15 | #include <linux/reboot.h> |
17 | #include <linux/jiffies.h> | 16 | #include <linux/jiffies.h> |
18 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/suspend.h> | ||
19 | #include <linux/completion.h> | ||
20 | #include <linux/platform_device.h> | ||
19 | #include <asm/types.h> | 21 | #include <asm/types.h> |
20 | #include <asm/s390_ext.h> | 22 | #include <asm/s390_ext.h> |
21 | 23 | ||
@@ -47,6 +49,16 @@ static struct sclp_req sclp_init_req; | |||
47 | static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); | 49 | static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); |
48 | static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); | 50 | static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); |
49 | 51 | ||
52 | /* Suspend request */ | ||
53 | static DECLARE_COMPLETION(sclp_request_queue_flushed); | ||
54 | |||
55 | static void sclp_suspend_req_cb(struct sclp_req *req, void *data) | ||
56 | { | ||
57 | complete(&sclp_request_queue_flushed); | ||
58 | } | ||
59 | |||
60 | static struct sclp_req sclp_suspend_req; | ||
61 | |||
50 | /* Timer for request retries. */ | 62 | /* Timer for request retries. */ |
51 | static struct timer_list sclp_request_timer; | 63 | static struct timer_list sclp_request_timer; |
52 | 64 | ||
@@ -84,6 +96,12 @@ static volatile enum sclp_mask_state_t { | |||
84 | sclp_mask_state_initializing | 96 | sclp_mask_state_initializing |
85 | } sclp_mask_state = sclp_mask_state_idle; | 97 | } sclp_mask_state = sclp_mask_state_idle; |
86 | 98 | ||
99 | /* Internal state: is the driver suspended? */ | ||
100 | static enum sclp_suspend_state_t { | ||
101 | sclp_suspend_state_running, | ||
102 | sclp_suspend_state_suspended, | ||
103 | } sclp_suspend_state = sclp_suspend_state_running; | ||
104 | |||
87 | /* Maximum retry counts */ | 105 | /* Maximum retry counts */ |
88 | #define SCLP_INIT_RETRY 3 | 106 | #define SCLP_INIT_RETRY 3 |
89 | #define SCLP_MASK_RETRY 3 | 107 | #define SCLP_MASK_RETRY 3 |
@@ -211,6 +229,8 @@ sclp_process_queue(void) | |||
211 | del_timer(&sclp_request_timer); | 229 | del_timer(&sclp_request_timer); |
212 | while (!list_empty(&sclp_req_queue)) { | 230 | while (!list_empty(&sclp_req_queue)) { |
213 | req = list_entry(sclp_req_queue.next, struct sclp_req, list); | 231 | req = list_entry(sclp_req_queue.next, struct sclp_req, list); |
232 | if (!req->sccb) | ||
233 | goto do_post; | ||
214 | rc = __sclp_start_request(req); | 234 | rc = __sclp_start_request(req); |
215 | if (rc == 0) | 235 | if (rc == 0) |
216 | break; | 236 | break; |
@@ -222,6 +242,7 @@ sclp_process_queue(void) | |||
222 | sclp_request_timeout, 0); | 242 | sclp_request_timeout, 0); |
223 | break; | 243 | break; |
224 | } | 244 | } |
245 | do_post: | ||
225 | /* Post-processing for aborted request */ | 246 | /* Post-processing for aborted request */ |
226 | list_del(&req->list); | 247 | list_del(&req->list); |
227 | if (req->callback) { | 248 | if (req->callback) { |
@@ -233,6 +254,19 @@ sclp_process_queue(void) | |||
233 | spin_unlock_irqrestore(&sclp_lock, flags); | 254 | spin_unlock_irqrestore(&sclp_lock, flags); |
234 | } | 255 | } |
235 | 256 | ||
257 | static int __sclp_can_add_request(struct sclp_req *req) | ||
258 | { | ||
259 | if (req == &sclp_suspend_req || req == &sclp_init_req) | ||
260 | return 1; | ||
261 | if (sclp_suspend_state != sclp_suspend_state_running) | ||
262 | return 0; | ||
263 | if (sclp_init_state != sclp_init_state_initialized) | ||
264 | return 0; | ||
265 | if (sclp_activation_state != sclp_activation_state_active) | ||
266 | return 0; | ||
267 | return 1; | ||
268 | } | ||
269 | |||
236 | /* Queue a new request. Return zero on success, non-zero otherwise. */ | 270 | /* Queue a new request. Return zero on success, non-zero otherwise. */ |
237 | int | 271 | int |
238 | sclp_add_request(struct sclp_req *req) | 272 | sclp_add_request(struct sclp_req *req) |
@@ -241,9 +275,7 @@ sclp_add_request(struct sclp_req *req) | |||
241 | int rc; | 275 | int rc; |
242 | 276 | ||
243 | spin_lock_irqsave(&sclp_lock, flags); | 277 | spin_lock_irqsave(&sclp_lock, flags); |
244 | if ((sclp_init_state != sclp_init_state_initialized || | 278 | if (!__sclp_can_add_request(req)) { |
245 | sclp_activation_state != sclp_activation_state_active) && | ||
246 | req != &sclp_init_req) { | ||
247 | spin_unlock_irqrestore(&sclp_lock, flags); | 279 | spin_unlock_irqrestore(&sclp_lock, flags); |
248 | return -EIO; | 280 | return -EIO; |
249 | } | 281 | } |
@@ -254,10 +286,16 @@ sclp_add_request(struct sclp_req *req) | |||
254 | /* Start if request is first in list */ | 286 | /* Start if request is first in list */ |
255 | if (sclp_running_state == sclp_running_state_idle && | 287 | if (sclp_running_state == sclp_running_state_idle && |
256 | req->list.prev == &sclp_req_queue) { | 288 | req->list.prev == &sclp_req_queue) { |
289 | if (!req->sccb) { | ||
290 | list_del(&req->list); | ||
291 | rc = -ENODATA; | ||
292 | goto out; | ||
293 | } | ||
257 | rc = __sclp_start_request(req); | 294 | rc = __sclp_start_request(req); |
258 | if (rc) | 295 | if (rc) |
259 | list_del(&req->list); | 296 | list_del(&req->list); |
260 | } | 297 | } |
298 | out: | ||
261 | spin_unlock_irqrestore(&sclp_lock, flags); | 299 | spin_unlock_irqrestore(&sclp_lock, flags); |
262 | return rc; | 300 | return rc; |
263 | } | 301 | } |
@@ -560,6 +598,7 @@ sclp_register(struct sclp_register *reg) | |||
560 | /* Trigger initial state change callback */ | 598 | /* Trigger initial state change callback */ |
561 | reg->sclp_receive_mask = 0; | 599 | reg->sclp_receive_mask = 0; |
562 | reg->sclp_send_mask = 0; | 600 | reg->sclp_send_mask = 0; |
601 | reg->pm_event_posted = 0; | ||
563 | list_add(®->list, &sclp_reg_list); | 602 | list_add(®->list, &sclp_reg_list); |
564 | spin_unlock_irqrestore(&sclp_lock, flags); | 603 | spin_unlock_irqrestore(&sclp_lock, flags); |
565 | rc = sclp_init_mask(1); | 604 | rc = sclp_init_mask(1); |
@@ -880,20 +919,134 @@ static struct notifier_block sclp_reboot_notifier = { | |||
880 | .notifier_call = sclp_reboot_event | 919 | .notifier_call = sclp_reboot_event |
881 | }; | 920 | }; |
882 | 921 | ||
922 | /* | ||
923 | * Suspend/resume SCLP notifier implementation | ||
924 | */ | ||
925 | |||
926 | static void sclp_pm_event(enum sclp_pm_event sclp_pm_event, int rollback) | ||
927 | { | ||
928 | struct sclp_register *reg; | ||
929 | unsigned long flags; | ||
930 | |||
931 | if (!rollback) { | ||
932 | spin_lock_irqsave(&sclp_lock, flags); | ||
933 | list_for_each_entry(reg, &sclp_reg_list, list) | ||
934 | reg->pm_event_posted = 0; | ||
935 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
936 | } | ||
937 | do { | ||
938 | spin_lock_irqsave(&sclp_lock, flags); | ||
939 | list_for_each_entry(reg, &sclp_reg_list, list) { | ||
940 | if (rollback && reg->pm_event_posted) | ||
941 | goto found; | ||
942 | if (!rollback && !reg->pm_event_posted) | ||
943 | goto found; | ||
944 | } | ||
945 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
946 | return; | ||
947 | found: | ||
948 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
949 | if (reg->pm_event_fn) | ||
950 | reg->pm_event_fn(reg, sclp_pm_event); | ||
951 | reg->pm_event_posted = rollback ? 0 : 1; | ||
952 | } while (1); | ||
953 | } | ||
954 | |||
955 | /* | ||
956 | * Susend/resume callbacks for platform device | ||
957 | */ | ||
958 | |||
959 | static int sclp_freeze(struct device *dev) | ||
960 | { | ||
961 | unsigned long flags; | ||
962 | int rc; | ||
963 | |||
964 | sclp_pm_event(SCLP_PM_EVENT_FREEZE, 0); | ||
965 | |||
966 | spin_lock_irqsave(&sclp_lock, flags); | ||
967 | sclp_suspend_state = sclp_suspend_state_suspended; | ||
968 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
969 | |||
970 | /* Init supend data */ | ||
971 | memset(&sclp_suspend_req, 0, sizeof(sclp_suspend_req)); | ||
972 | sclp_suspend_req.callback = sclp_suspend_req_cb; | ||
973 | sclp_suspend_req.status = SCLP_REQ_FILLED; | ||
974 | init_completion(&sclp_request_queue_flushed); | ||
975 | |||
976 | rc = sclp_add_request(&sclp_suspend_req); | ||
977 | if (rc == 0) | ||
978 | wait_for_completion(&sclp_request_queue_flushed); | ||
979 | else if (rc != -ENODATA) | ||
980 | goto fail_thaw; | ||
981 | |||
982 | rc = sclp_deactivate(); | ||
983 | if (rc) | ||
984 | goto fail_thaw; | ||
985 | return 0; | ||
986 | |||
987 | fail_thaw: | ||
988 | spin_lock_irqsave(&sclp_lock, flags); | ||
989 | sclp_suspend_state = sclp_suspend_state_running; | ||
990 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
991 | sclp_pm_event(SCLP_PM_EVENT_THAW, 1); | ||
992 | return rc; | ||
993 | } | ||
994 | |||
995 | static int sclp_undo_suspend(enum sclp_pm_event event) | ||
996 | { | ||
997 | unsigned long flags; | ||
998 | int rc; | ||
999 | |||
1000 | rc = sclp_reactivate(); | ||
1001 | if (rc) | ||
1002 | return rc; | ||
1003 | |||
1004 | spin_lock_irqsave(&sclp_lock, flags); | ||
1005 | sclp_suspend_state = sclp_suspend_state_running; | ||
1006 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
1007 | |||
1008 | sclp_pm_event(event, 0); | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | static int sclp_thaw(struct device *dev) | ||
1013 | { | ||
1014 | return sclp_undo_suspend(SCLP_PM_EVENT_THAW); | ||
1015 | } | ||
1016 | |||
1017 | static int sclp_restore(struct device *dev) | ||
1018 | { | ||
1019 | return sclp_undo_suspend(SCLP_PM_EVENT_RESTORE); | ||
1020 | } | ||
1021 | |||
1022 | static struct dev_pm_ops sclp_pm_ops = { | ||
1023 | .freeze = sclp_freeze, | ||
1024 | .thaw = sclp_thaw, | ||
1025 | .restore = sclp_restore, | ||
1026 | }; | ||
1027 | |||
1028 | static struct platform_driver sclp_pdrv = { | ||
1029 | .driver = { | ||
1030 | .name = "sclp", | ||
1031 | .owner = THIS_MODULE, | ||
1032 | .pm = &sclp_pm_ops, | ||
1033 | }, | ||
1034 | }; | ||
1035 | |||
1036 | static struct platform_device *sclp_pdev; | ||
1037 | |||
883 | /* Initialize SCLP driver. Return zero if driver is operational, non-zero | 1038 | /* Initialize SCLP driver. Return zero if driver is operational, non-zero |
884 | * otherwise. */ | 1039 | * otherwise. */ |
885 | static int | 1040 | static int |
886 | sclp_init(void) | 1041 | sclp_init(void) |
887 | { | 1042 | { |
888 | unsigned long flags; | 1043 | unsigned long flags; |
889 | int rc; | 1044 | int rc = 0; |
890 | 1045 | ||
891 | spin_lock_irqsave(&sclp_lock, flags); | 1046 | spin_lock_irqsave(&sclp_lock, flags); |
892 | /* Check for previous or running initialization */ | 1047 | /* Check for previous or running initialization */ |
893 | if (sclp_init_state != sclp_init_state_uninitialized) { | 1048 | if (sclp_init_state != sclp_init_state_uninitialized) |
894 | spin_unlock_irqrestore(&sclp_lock, flags); | 1049 | goto fail_unlock; |
895 | return 0; | ||
896 | } | ||
897 | sclp_init_state = sclp_init_state_initializing; | 1050 | sclp_init_state = sclp_init_state_initializing; |
898 | /* Set up variables */ | 1051 | /* Set up variables */ |
899 | INIT_LIST_HEAD(&sclp_req_queue); | 1052 | INIT_LIST_HEAD(&sclp_req_queue); |
@@ -904,27 +1057,17 @@ sclp_init(void) | |||
904 | spin_unlock_irqrestore(&sclp_lock, flags); | 1057 | spin_unlock_irqrestore(&sclp_lock, flags); |
905 | rc = sclp_check_interface(); | 1058 | rc = sclp_check_interface(); |
906 | spin_lock_irqsave(&sclp_lock, flags); | 1059 | spin_lock_irqsave(&sclp_lock, flags); |
907 | if (rc) { | 1060 | if (rc) |
908 | sclp_init_state = sclp_init_state_uninitialized; | 1061 | goto fail_init_state_uninitialized; |
909 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
910 | return rc; | ||
911 | } | ||
912 | /* Register reboot handler */ | 1062 | /* Register reboot handler */ |
913 | rc = register_reboot_notifier(&sclp_reboot_notifier); | 1063 | rc = register_reboot_notifier(&sclp_reboot_notifier); |
914 | if (rc) { | 1064 | if (rc) |
915 | sclp_init_state = sclp_init_state_uninitialized; | 1065 | goto fail_init_state_uninitialized; |
916 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
917 | return rc; | ||
918 | } | ||
919 | /* Register interrupt handler */ | 1066 | /* Register interrupt handler */ |
920 | rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler, | 1067 | rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler, |
921 | &ext_int_info_hwc); | 1068 | &ext_int_info_hwc); |
922 | if (rc) { | 1069 | if (rc) |
923 | unregister_reboot_notifier(&sclp_reboot_notifier); | 1070 | goto fail_unregister_reboot_notifier; |
924 | sclp_init_state = sclp_init_state_uninitialized; | ||
925 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
926 | return rc; | ||
927 | } | ||
928 | sclp_init_state = sclp_init_state_initialized; | 1071 | sclp_init_state = sclp_init_state_initialized; |
929 | spin_unlock_irqrestore(&sclp_lock, flags); | 1072 | spin_unlock_irqrestore(&sclp_lock, flags); |
930 | /* Enable service-signal external interruption - needs to happen with | 1073 | /* Enable service-signal external interruption - needs to happen with |
@@ -932,11 +1075,56 @@ sclp_init(void) | |||
932 | ctl_set_bit(0, 9); | 1075 | ctl_set_bit(0, 9); |
933 | sclp_init_mask(1); | 1076 | sclp_init_mask(1); |
934 | return 0; | 1077 | return 0; |
1078 | |||
1079 | fail_unregister_reboot_notifier: | ||
1080 | unregister_reboot_notifier(&sclp_reboot_notifier); | ||
1081 | fail_init_state_uninitialized: | ||
1082 | sclp_init_state = sclp_init_state_uninitialized; | ||
1083 | fail_unlock: | ||
1084 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
1085 | return rc; | ||
935 | } | 1086 | } |
936 | 1087 | ||
1088 | /* | ||
1089 | * SCLP panic notifier: If we are suspended, we thaw SCLP in order to be able | ||
1090 | * to print the panic message. | ||
1091 | */ | ||
1092 | static int sclp_panic_notify(struct notifier_block *self, | ||
1093 | unsigned long event, void *data) | ||
1094 | { | ||
1095 | if (sclp_suspend_state == sclp_suspend_state_suspended) | ||
1096 | sclp_undo_suspend(SCLP_PM_EVENT_THAW); | ||
1097 | return NOTIFY_OK; | ||
1098 | } | ||
1099 | |||
1100 | static struct notifier_block sclp_on_panic_nb = { | ||
1101 | .notifier_call = sclp_panic_notify, | ||
1102 | .priority = SCLP_PANIC_PRIO, | ||
1103 | }; | ||
1104 | |||
937 | static __init int sclp_initcall(void) | 1105 | static __init int sclp_initcall(void) |
938 | { | 1106 | { |
1107 | int rc; | ||
1108 | |||
1109 | rc = platform_driver_register(&sclp_pdrv); | ||
1110 | if (rc) | ||
1111 | return rc; | ||
1112 | sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); | ||
1113 | rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; | ||
1114 | if (rc) | ||
1115 | goto fail_platform_driver_unregister; | ||
1116 | rc = atomic_notifier_chain_register(&panic_notifier_list, | ||
1117 | &sclp_on_panic_nb); | ||
1118 | if (rc) | ||
1119 | goto fail_platform_device_unregister; | ||
1120 | |||
939 | return sclp_init(); | 1121 | return sclp_init(); |
1122 | |||
1123 | fail_platform_device_unregister: | ||
1124 | platform_device_unregister(sclp_pdev); | ||
1125 | fail_platform_driver_unregister: | ||
1126 | platform_driver_unregister(&sclp_pdrv); | ||
1127 | return rc; | ||
940 | } | 1128 | } |
941 | 1129 | ||
942 | arch_initcall(sclp_initcall); | 1130 | arch_initcall(sclp_initcall); |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index bac80e856f97..60e7cb07095b 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -1,10 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp.h | 2 | * Copyright IBM Corp. 1999, 2009 |
3 | * | 3 | * |
4 | * S390 version | 4 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
5 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
6 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | ||
7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
8 | */ | 6 | */ |
9 | 7 | ||
10 | #ifndef __SCLP_H__ | 8 | #ifndef __SCLP_H__ |
@@ -17,7 +15,7 @@ | |||
17 | 15 | ||
18 | /* maximum number of pages concerning our own memory management */ | 16 | /* maximum number of pages concerning our own memory management */ |
19 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) | 17 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) |
20 | #define MAX_CONSOLE_PAGES 4 | 18 | #define MAX_CONSOLE_PAGES 6 |
21 | 19 | ||
22 | #define EVTYP_OPCMD 0x01 | 20 | #define EVTYP_OPCMD 0x01 |
23 | #define EVTYP_MSG 0x02 | 21 | #define EVTYP_MSG 0x02 |
@@ -68,6 +66,15 @@ typedef unsigned int sclp_cmdw_t; | |||
68 | 66 | ||
69 | #define GDS_KEY_SELFDEFTEXTMSG 0x31 | 67 | #define GDS_KEY_SELFDEFTEXTMSG 0x31 |
70 | 68 | ||
69 | enum sclp_pm_event { | ||
70 | SCLP_PM_EVENT_FREEZE, | ||
71 | SCLP_PM_EVENT_THAW, | ||
72 | SCLP_PM_EVENT_RESTORE, | ||
73 | }; | ||
74 | |||
75 | #define SCLP_PANIC_PRIO 1 | ||
76 | #define SCLP_PANIC_PRIO_CLIENT 0 | ||
77 | |||
71 | typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ | 78 | typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ |
72 | 79 | ||
73 | struct sccb_header { | 80 | struct sccb_header { |
@@ -134,6 +141,10 @@ struct sclp_register { | |||
134 | void (*state_change_fn)(struct sclp_register *); | 141 | void (*state_change_fn)(struct sclp_register *); |
135 | /* called for events in cp_receive_mask/sclp_receive_mask */ | 142 | /* called for events in cp_receive_mask/sclp_receive_mask */ |
136 | void (*receiver_fn)(struct evbuf_header *); | 143 | void (*receiver_fn)(struct evbuf_header *); |
144 | /* called for power management events */ | ||
145 | void (*pm_event_fn)(struct sclp_register *, enum sclp_pm_event); | ||
146 | /* pm event posted flag */ | ||
147 | int pm_event_posted; | ||
137 | }; | 148 | }; |
138 | 149 | ||
139 | /* externals from sclp.c */ | 150 | /* externals from sclp.c */ |
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 77ab6e34a100..5cc11c636d38 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c | |||
@@ -1,9 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_cmd.c | 2 | * Copyright IBM Corp. 2007, 2009 |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, |
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, | 5 | * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
6 | * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #define KMSG_COMPONENT "sclp_cmd" | 8 | #define KMSG_COMPONENT "sclp_cmd" |
@@ -12,11 +11,13 @@ | |||
12 | #include <linux/completion.h> | 11 | #include <linux/completion.h> |
13 | #include <linux/init.h> | 12 | #include <linux/init.h> |
14 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/err.h> | ||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include <linux/mmzone.h> | 18 | #include <linux/mmzone.h> |
19 | #include <linux/memory.h> | 19 | #include <linux/memory.h> |
20 | #include <linux/platform_device.h> | ||
20 | #include <asm/chpid.h> | 21 | #include <asm/chpid.h> |
21 | #include <asm/sclp.h> | 22 | #include <asm/sclp.h> |
22 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
@@ -292,6 +293,7 @@ static DEFINE_MUTEX(sclp_mem_mutex); | |||
292 | static LIST_HEAD(sclp_mem_list); | 293 | static LIST_HEAD(sclp_mem_list); |
293 | static u8 sclp_max_storage_id; | 294 | static u8 sclp_max_storage_id; |
294 | static unsigned long sclp_storage_ids[256 / BITS_PER_LONG]; | 295 | static unsigned long sclp_storage_ids[256 / BITS_PER_LONG]; |
296 | static int sclp_mem_state_changed; | ||
295 | 297 | ||
296 | struct memory_increment { | 298 | struct memory_increment { |
297 | struct list_head list; | 299 | struct list_head list; |
@@ -450,6 +452,8 @@ static int sclp_mem_notifier(struct notifier_block *nb, | |||
450 | rc = -EINVAL; | 452 | rc = -EINVAL; |
451 | break; | 453 | break; |
452 | } | 454 | } |
455 | if (!rc) | ||
456 | sclp_mem_state_changed = 1; | ||
453 | mutex_unlock(&sclp_mem_mutex); | 457 | mutex_unlock(&sclp_mem_mutex); |
454 | return rc ? NOTIFY_BAD : NOTIFY_OK; | 458 | return rc ? NOTIFY_BAD : NOTIFY_OK; |
455 | } | 459 | } |
@@ -525,6 +529,14 @@ static void __init insert_increment(u16 rn, int standby, int assigned) | |||
525 | list_add(&new_incr->list, prev); | 529 | list_add(&new_incr->list, prev); |
526 | } | 530 | } |
527 | 531 | ||
532 | static int sclp_mem_freeze(struct device *dev) | ||
533 | { | ||
534 | if (!sclp_mem_state_changed) | ||
535 | return 0; | ||
536 | pr_err("Memory hotplug state changed, suspend refused.\n"); | ||
537 | return -EPERM; | ||
538 | } | ||
539 | |||
528 | struct read_storage_sccb { | 540 | struct read_storage_sccb { |
529 | struct sccb_header header; | 541 | struct sccb_header header; |
530 | u16 max_id; | 542 | u16 max_id; |
@@ -534,8 +546,20 @@ struct read_storage_sccb { | |||
534 | u32 entries[0]; | 546 | u32 entries[0]; |
535 | } __packed; | 547 | } __packed; |
536 | 548 | ||
549 | static struct dev_pm_ops sclp_mem_pm_ops = { | ||
550 | .freeze = sclp_mem_freeze, | ||
551 | }; | ||
552 | |||
553 | static struct platform_driver sclp_mem_pdrv = { | ||
554 | .driver = { | ||
555 | .name = "sclp_mem", | ||
556 | .pm = &sclp_mem_pm_ops, | ||
557 | }, | ||
558 | }; | ||
559 | |||
537 | static int __init sclp_detect_standby_memory(void) | 560 | static int __init sclp_detect_standby_memory(void) |
538 | { | 561 | { |
562 | struct platform_device *sclp_pdev; | ||
539 | struct read_storage_sccb *sccb; | 563 | struct read_storage_sccb *sccb; |
540 | int i, id, assigned, rc; | 564 | int i, id, assigned, rc; |
541 | 565 | ||
@@ -588,7 +612,17 @@ static int __init sclp_detect_standby_memory(void) | |||
588 | rc = register_memory_notifier(&sclp_mem_nb); | 612 | rc = register_memory_notifier(&sclp_mem_nb); |
589 | if (rc) | 613 | if (rc) |
590 | goto out; | 614 | goto out; |
615 | rc = platform_driver_register(&sclp_mem_pdrv); | ||
616 | if (rc) | ||
617 | goto out; | ||
618 | sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0); | ||
619 | rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; | ||
620 | if (rc) | ||
621 | goto out_driver; | ||
591 | sclp_add_standby_memory(); | 622 | sclp_add_standby_memory(); |
623 | goto out; | ||
624 | out_driver: | ||
625 | platform_driver_unregister(&sclp_mem_pdrv); | ||
592 | out: | 626 | out: |
593 | free_page((unsigned long) sccb); | 627 | free_page((unsigned long) sccb); |
594 | return rc; | 628 | return rc; |
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 9a25c4bd1421..336811a77672 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c | |||
@@ -1,11 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_con.c | 2 | * SCLP line mode console driver |
3 | * SCLP line mode console driver | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 1999, 2009 |
6 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
7 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | 6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
9 | */ | 7 | */ |
10 | 8 | ||
11 | #include <linux/kmod.h> | 9 | #include <linux/kmod.h> |
@@ -32,13 +30,14 @@ static spinlock_t sclp_con_lock; | |||
32 | static struct list_head sclp_con_pages; | 30 | static struct list_head sclp_con_pages; |
33 | /* List of full struct sclp_buffer structures ready for output */ | 31 | /* List of full struct sclp_buffer structures ready for output */ |
34 | static struct list_head sclp_con_outqueue; | 32 | static struct list_head sclp_con_outqueue; |
35 | /* Counter how many buffers are emitted (max 1) and how many */ | ||
36 | /* are on the output queue. */ | ||
37 | static int sclp_con_buffer_count; | ||
38 | /* Pointer to current console buffer */ | 33 | /* Pointer to current console buffer */ |
39 | static struct sclp_buffer *sclp_conbuf; | 34 | static struct sclp_buffer *sclp_conbuf; |
40 | /* Timer for delayed output of console messages */ | 35 | /* Timer for delayed output of console messages */ |
41 | static struct timer_list sclp_con_timer; | 36 | static struct timer_list sclp_con_timer; |
37 | /* Suspend mode flag */ | ||
38 | static int sclp_con_suspended; | ||
39 | /* Flag that output queue is currently running */ | ||
40 | static int sclp_con_queue_running; | ||
42 | 41 | ||
43 | /* Output format for console messages */ | 42 | /* Output format for console messages */ |
44 | static unsigned short sclp_con_columns; | 43 | static unsigned short sclp_con_columns; |
@@ -53,42 +52,71 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc) | |||
53 | do { | 52 | do { |
54 | page = sclp_unmake_buffer(buffer); | 53 | page = sclp_unmake_buffer(buffer); |
55 | spin_lock_irqsave(&sclp_con_lock, flags); | 54 | spin_lock_irqsave(&sclp_con_lock, flags); |
55 | |||
56 | /* Remove buffer from outqueue */ | 56 | /* Remove buffer from outqueue */ |
57 | list_del(&buffer->list); | 57 | list_del(&buffer->list); |
58 | sclp_con_buffer_count--; | ||
59 | list_add_tail((struct list_head *) page, &sclp_con_pages); | 58 | list_add_tail((struct list_head *) page, &sclp_con_pages); |
59 | |||
60 | /* Check if there is a pending buffer on the out queue. */ | 60 | /* Check if there is a pending buffer on the out queue. */ |
61 | buffer = NULL; | 61 | buffer = NULL; |
62 | if (!list_empty(&sclp_con_outqueue)) | 62 | if (!list_empty(&sclp_con_outqueue)) |
63 | buffer = list_entry(sclp_con_outqueue.next, | 63 | buffer = list_first_entry(&sclp_con_outqueue, |
64 | struct sclp_buffer, list); | 64 | struct sclp_buffer, list); |
65 | if (!buffer || sclp_con_suspended) { | ||
66 | sclp_con_queue_running = 0; | ||
67 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
68 | break; | ||
69 | } | ||
65 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 70 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
66 | } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback)); | 71 | } while (sclp_emit_buffer(buffer, sclp_conbuf_callback)); |
67 | } | 72 | } |
68 | 73 | ||
69 | static void | 74 | /* |
70 | sclp_conbuf_emit(void) | 75 | * Finalize and emit first pending buffer. |
76 | */ | ||
77 | static void sclp_conbuf_emit(void) | ||
71 | { | 78 | { |
72 | struct sclp_buffer* buffer; | 79 | struct sclp_buffer* buffer; |
73 | unsigned long flags; | 80 | unsigned long flags; |
74 | int count; | ||
75 | int rc; | 81 | int rc; |
76 | 82 | ||
77 | spin_lock_irqsave(&sclp_con_lock, flags); | 83 | spin_lock_irqsave(&sclp_con_lock, flags); |
78 | buffer = sclp_conbuf; | 84 | if (sclp_conbuf) |
85 | list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue); | ||
79 | sclp_conbuf = NULL; | 86 | sclp_conbuf = NULL; |
80 | if (buffer == NULL) { | 87 | if (sclp_con_queue_running || sclp_con_suspended) |
81 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 88 | goto out_unlock; |
82 | return; | 89 | if (list_empty(&sclp_con_outqueue)) |
83 | } | 90 | goto out_unlock; |
84 | list_add_tail(&buffer->list, &sclp_con_outqueue); | 91 | buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer, |
85 | count = sclp_con_buffer_count++; | 92 | list); |
93 | sclp_con_queue_running = 1; | ||
86 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 94 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
87 | if (count) | 95 | |
88 | return; | ||
89 | rc = sclp_emit_buffer(buffer, sclp_conbuf_callback); | 96 | rc = sclp_emit_buffer(buffer, sclp_conbuf_callback); |
90 | if (rc) | 97 | if (rc) |
91 | sclp_conbuf_callback(buffer, rc); | 98 | sclp_conbuf_callback(buffer, rc); |
99 | return; | ||
100 | out_unlock: | ||
101 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Wait until out queue is empty | ||
106 | */ | ||
107 | static void sclp_console_sync_queue(void) | ||
108 | { | ||
109 | unsigned long flags; | ||
110 | |||
111 | spin_lock_irqsave(&sclp_con_lock, flags); | ||
112 | if (timer_pending(&sclp_con_timer)) | ||
113 | del_timer_sync(&sclp_con_timer); | ||
114 | while (sclp_con_queue_running) { | ||
115 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
116 | sclp_sync_wait(); | ||
117 | spin_lock_irqsave(&sclp_con_lock, flags); | ||
118 | } | ||
119 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
92 | } | 120 | } |
93 | 121 | ||
94 | /* | 122 | /* |
@@ -123,6 +151,8 @@ sclp_console_write(struct console *console, const char *message, | |||
123 | /* make sure we have a console output buffer */ | 151 | /* make sure we have a console output buffer */ |
124 | if (sclp_conbuf == NULL) { | 152 | if (sclp_conbuf == NULL) { |
125 | while (list_empty(&sclp_con_pages)) { | 153 | while (list_empty(&sclp_con_pages)) { |
154 | if (sclp_con_suspended) | ||
155 | goto out; | ||
126 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 156 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
127 | sclp_sync_wait(); | 157 | sclp_sync_wait(); |
128 | spin_lock_irqsave(&sclp_con_lock, flags); | 158 | spin_lock_irqsave(&sclp_con_lock, flags); |
@@ -157,6 +187,7 @@ sclp_console_write(struct console *console, const char *message, | |||
157 | sclp_con_timer.expires = jiffies + HZ/10; | 187 | sclp_con_timer.expires = jiffies + HZ/10; |
158 | add_timer(&sclp_con_timer); | 188 | add_timer(&sclp_con_timer); |
159 | } | 189 | } |
190 | out: | ||
160 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 191 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
161 | } | 192 | } |
162 | 193 | ||
@@ -168,30 +199,43 @@ sclp_console_device(struct console *c, int *index) | |||
168 | } | 199 | } |
169 | 200 | ||
170 | /* | 201 | /* |
171 | * This routine is called from panic when the kernel | 202 | * Make sure that all buffers will be flushed to the SCLP. |
172 | * is going to give up. We have to make sure that all buffers | ||
173 | * will be flushed to the SCLP. | ||
174 | */ | 203 | */ |
175 | static void | 204 | static void |
176 | sclp_console_flush(void) | 205 | sclp_console_flush(void) |
177 | { | 206 | { |
207 | sclp_conbuf_emit(); | ||
208 | sclp_console_sync_queue(); | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Resume console: If there are cached messages, emit them. | ||
213 | */ | ||
214 | static void sclp_console_resume(void) | ||
215 | { | ||
178 | unsigned long flags; | 216 | unsigned long flags; |
179 | 217 | ||
218 | spin_lock_irqsave(&sclp_con_lock, flags); | ||
219 | sclp_con_suspended = 0; | ||
220 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
180 | sclp_conbuf_emit(); | 221 | sclp_conbuf_emit(); |
222 | } | ||
223 | |||
224 | /* | ||
225 | * Suspend console: Set suspend flag and flush console | ||
226 | */ | ||
227 | static void sclp_console_suspend(void) | ||
228 | { | ||
229 | unsigned long flags; | ||
230 | |||
181 | spin_lock_irqsave(&sclp_con_lock, flags); | 231 | spin_lock_irqsave(&sclp_con_lock, flags); |
182 | if (timer_pending(&sclp_con_timer)) | 232 | sclp_con_suspended = 1; |
183 | del_timer(&sclp_con_timer); | ||
184 | while (sclp_con_buffer_count > 0) { | ||
185 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
186 | sclp_sync_wait(); | ||
187 | spin_lock_irqsave(&sclp_con_lock, flags); | ||
188 | } | ||
189 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 233 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
234 | sclp_console_flush(); | ||
190 | } | 235 | } |
191 | 236 | ||
192 | static int | 237 | static int sclp_console_notify(struct notifier_block *self, |
193 | sclp_console_notify(struct notifier_block *self, | 238 | unsigned long event, void *data) |
194 | unsigned long event, void *data) | ||
195 | { | 239 | { |
196 | sclp_console_flush(); | 240 | sclp_console_flush(); |
197 | return NOTIFY_OK; | 241 | return NOTIFY_OK; |
@@ -199,7 +243,7 @@ sclp_console_notify(struct notifier_block *self, | |||
199 | 243 | ||
200 | static struct notifier_block on_panic_nb = { | 244 | static struct notifier_block on_panic_nb = { |
201 | .notifier_call = sclp_console_notify, | 245 | .notifier_call = sclp_console_notify, |
202 | .priority = 1, | 246 | .priority = SCLP_PANIC_PRIO_CLIENT, |
203 | }; | 247 | }; |
204 | 248 | ||
205 | static struct notifier_block on_reboot_nb = { | 249 | static struct notifier_block on_reboot_nb = { |
@@ -221,6 +265,22 @@ static struct console sclp_console = | |||
221 | }; | 265 | }; |
222 | 266 | ||
223 | /* | 267 | /* |
268 | * This function is called for SCLP suspend and resume events. | ||
269 | */ | ||
270 | void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) | ||
271 | { | ||
272 | switch (sclp_pm_event) { | ||
273 | case SCLP_PM_EVENT_FREEZE: | ||
274 | sclp_console_suspend(); | ||
275 | break; | ||
276 | case SCLP_PM_EVENT_RESTORE: | ||
277 | case SCLP_PM_EVENT_THAW: | ||
278 | sclp_console_resume(); | ||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* | ||
224 | * called by console_init() in drivers/char/tty_io.c at boot-time. | 284 | * called by console_init() in drivers/char/tty_io.c at boot-time. |
225 | */ | 285 | */ |
226 | static int __init | 286 | static int __init |
@@ -243,7 +303,6 @@ sclp_console_init(void) | |||
243 | } | 303 | } |
244 | INIT_LIST_HEAD(&sclp_con_outqueue); | 304 | INIT_LIST_HEAD(&sclp_con_outqueue); |
245 | spin_lock_init(&sclp_con_lock); | 305 | spin_lock_init(&sclp_con_lock); |
246 | sclp_con_buffer_count = 0; | ||
247 | sclp_conbuf = NULL; | 306 | sclp_conbuf = NULL; |
248 | init_timer(&sclp_con_timer); | 307 | init_timer(&sclp_con_timer); |
249 | 308 | ||
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 710af42603f8..4be63be73445 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_rw.c | 2 | * driver: reading from and writing to system console on S/390 via SCLP |
3 | * driver: reading from and writing to system console on S/390 via SCLP | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 1999, 2009 |
6 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * |
7 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | 6 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/kmod.h> | 10 | #include <linux/kmod.h> |
@@ -26,9 +25,16 @@ | |||
26 | */ | 25 | */ |
27 | #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer)) | 26 | #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer)) |
28 | 27 | ||
28 | static void sclp_rw_pm_event(struct sclp_register *reg, | ||
29 | enum sclp_pm_event sclp_pm_event) | ||
30 | { | ||
31 | sclp_console_pm_event(sclp_pm_event); | ||
32 | } | ||
33 | |||
29 | /* Event type structure for write message and write priority message */ | 34 | /* Event type structure for write message and write priority message */ |
30 | static struct sclp_register sclp_rw_event = { | 35 | static struct sclp_register sclp_rw_event = { |
31 | .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK | 36 | .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK, |
37 | .pm_event_fn = sclp_rw_pm_event, | ||
32 | }; | 38 | }; |
33 | 39 | ||
34 | /* | 40 | /* |
diff --git a/drivers/s390/char/sclp_rw.h b/drivers/s390/char/sclp_rw.h index 6aa7a6948bc9..85f491ea929c 100644 --- a/drivers/s390/char/sclp_rw.h +++ b/drivers/s390/char/sclp_rw.h | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_rw.h | 2 | * interface to the SCLP-read/write driver |
3 | * interface to the SCLP-read/write driver | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corporation 1999, 2009 |
6 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * |
7 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | 6 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #ifndef __SCLP_RW_H__ | 10 | #ifndef __SCLP_RW_H__ |
@@ -93,4 +92,5 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short); | |||
93 | void sclp_set_htab(struct sclp_buffer *, unsigned short); | 92 | void sclp_set_htab(struct sclp_buffer *, unsigned short); |
94 | int sclp_chars_in_buffer(struct sclp_buffer *); | 93 | int sclp_chars_in_buffer(struct sclp_buffer *); |
95 | 94 | ||
95 | void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event); | ||
96 | #endif /* __SCLP_RW_H__ */ | 96 | #endif /* __SCLP_RW_H__ */ |
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index a839aa531d7c..5518e24946aa 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c | |||
@@ -1,10 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_vt220.c | 2 | * SCLP VT220 terminal driver. |
3 | * SCLP VT220 terminal driver. | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 2003, 2009 |
6 | * Copyright IBM Corp. 2003,2008 | 5 | * |
7 | * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com> | 6 | * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com> |
8 | */ | 7 | */ |
9 | 8 | ||
10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
@@ -69,8 +68,11 @@ static struct list_head sclp_vt220_empty; | |||
69 | /* List of pending requests */ | 68 | /* List of pending requests */ |
70 | static struct list_head sclp_vt220_outqueue; | 69 | static struct list_head sclp_vt220_outqueue; |
71 | 70 | ||
72 | /* Number of requests in outqueue */ | 71 | /* Suspend mode flag */ |
73 | static int sclp_vt220_outqueue_count; | 72 | static int sclp_vt220_suspended; |
73 | |||
74 | /* Flag that output queue is currently running */ | ||
75 | static int sclp_vt220_queue_running; | ||
74 | 76 | ||
75 | /* Timer used for delaying write requests to merge subsequent messages into | 77 | /* Timer used for delaying write requests to merge subsequent messages into |
76 | * a single buffer */ | 78 | * a single buffer */ |
@@ -92,6 +94,8 @@ static int __initdata sclp_vt220_init_count; | |||
92 | static int sclp_vt220_flush_later; | 94 | static int sclp_vt220_flush_later; |
93 | 95 | ||
94 | static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf); | 96 | static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf); |
97 | static void sclp_vt220_pm_event_fn(struct sclp_register *reg, | ||
98 | enum sclp_pm_event sclp_pm_event); | ||
95 | static int __sclp_vt220_emit(struct sclp_vt220_request *request); | 99 | static int __sclp_vt220_emit(struct sclp_vt220_request *request); |
96 | static void sclp_vt220_emit_current(void); | 100 | static void sclp_vt220_emit_current(void); |
97 | 101 | ||
@@ -100,7 +104,8 @@ static struct sclp_register sclp_vt220_register = { | |||
100 | .send_mask = EVTYP_VT220MSG_MASK, | 104 | .send_mask = EVTYP_VT220MSG_MASK, |
101 | .receive_mask = EVTYP_VT220MSG_MASK, | 105 | .receive_mask = EVTYP_VT220MSG_MASK, |
102 | .state_change_fn = NULL, | 106 | .state_change_fn = NULL, |
103 | .receiver_fn = sclp_vt220_receiver_fn | 107 | .receiver_fn = sclp_vt220_receiver_fn, |
108 | .pm_event_fn = sclp_vt220_pm_event_fn, | ||
104 | }; | 109 | }; |
105 | 110 | ||
106 | 111 | ||
@@ -120,15 +125,19 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request) | |||
120 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 125 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
121 | /* Move request from outqueue to empty queue */ | 126 | /* Move request from outqueue to empty queue */ |
122 | list_del(&request->list); | 127 | list_del(&request->list); |
123 | sclp_vt220_outqueue_count--; | ||
124 | list_add_tail((struct list_head *) page, &sclp_vt220_empty); | 128 | list_add_tail((struct list_head *) page, &sclp_vt220_empty); |
125 | /* Check if there is a pending buffer on the out queue. */ | 129 | /* Check if there is a pending buffer on the out queue. */ |
126 | request = NULL; | 130 | request = NULL; |
127 | if (!list_empty(&sclp_vt220_outqueue)) | 131 | if (!list_empty(&sclp_vt220_outqueue)) |
128 | request = list_entry(sclp_vt220_outqueue.next, | 132 | request = list_entry(sclp_vt220_outqueue.next, |
129 | struct sclp_vt220_request, list); | 133 | struct sclp_vt220_request, list); |
134 | if (!request || sclp_vt220_suspended) { | ||
135 | sclp_vt220_queue_running = 0; | ||
136 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
137 | break; | ||
138 | } | ||
130 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 139 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
131 | } while (request && __sclp_vt220_emit(request)); | 140 | } while (__sclp_vt220_emit(request)); |
132 | if (request == NULL && sclp_vt220_flush_later) | 141 | if (request == NULL && sclp_vt220_flush_later) |
133 | sclp_vt220_emit_current(); | 142 | sclp_vt220_emit_current(); |
134 | /* Check if the tty needs a wake up call */ | 143 | /* Check if the tty needs a wake up call */ |
@@ -212,26 +221,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request) | |||
212 | } | 221 | } |
213 | 222 | ||
214 | /* | 223 | /* |
215 | * Queue and emit given request. | 224 | * Queue and emit current request. |
216 | */ | ||
217 | static void | ||
218 | sclp_vt220_emit(struct sclp_vt220_request *request) | ||
219 | { | ||
220 | unsigned long flags; | ||
221 | int count; | ||
222 | |||
223 | spin_lock_irqsave(&sclp_vt220_lock, flags); | ||
224 | list_add_tail(&request->list, &sclp_vt220_outqueue); | ||
225 | count = sclp_vt220_outqueue_count++; | ||
226 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
227 | /* Emit only the first buffer immediately - callback takes care of | ||
228 | * the rest */ | ||
229 | if (count == 0 && __sclp_vt220_emit(request)) | ||
230 | sclp_vt220_process_queue(request); | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Queue and emit current request. Return zero on success, non-zero otherwise. | ||
235 | */ | 225 | */ |
236 | static void | 226 | static void |
237 | sclp_vt220_emit_current(void) | 227 | sclp_vt220_emit_current(void) |
@@ -241,22 +231,33 @@ sclp_vt220_emit_current(void) | |||
241 | struct sclp_vt220_sccb *sccb; | 231 | struct sclp_vt220_sccb *sccb; |
242 | 232 | ||
243 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 233 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
244 | request = NULL; | 234 | if (sclp_vt220_current_request) { |
245 | if (sclp_vt220_current_request != NULL) { | ||
246 | sccb = (struct sclp_vt220_sccb *) | 235 | sccb = (struct sclp_vt220_sccb *) |
247 | sclp_vt220_current_request->sclp_req.sccb; | 236 | sclp_vt220_current_request->sclp_req.sccb; |
248 | /* Only emit buffers with content */ | 237 | /* Only emit buffers with content */ |
249 | if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) { | 238 | if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) { |
250 | request = sclp_vt220_current_request; | 239 | list_add_tail(&sclp_vt220_current_request->list, |
240 | &sclp_vt220_outqueue); | ||
251 | sclp_vt220_current_request = NULL; | 241 | sclp_vt220_current_request = NULL; |
252 | if (timer_pending(&sclp_vt220_timer)) | 242 | if (timer_pending(&sclp_vt220_timer)) |
253 | del_timer(&sclp_vt220_timer); | 243 | del_timer(&sclp_vt220_timer); |
254 | } | 244 | } |
255 | sclp_vt220_flush_later = 0; | 245 | sclp_vt220_flush_later = 0; |
256 | } | 246 | } |
247 | if (sclp_vt220_queue_running || sclp_vt220_suspended) | ||
248 | goto out_unlock; | ||
249 | if (list_empty(&sclp_vt220_outqueue)) | ||
250 | goto out_unlock; | ||
251 | request = list_first_entry(&sclp_vt220_outqueue, | ||
252 | struct sclp_vt220_request, list); | ||
253 | sclp_vt220_queue_running = 1; | ||
254 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
255 | |||
256 | if (__sclp_vt220_emit(request)) | ||
257 | sclp_vt220_process_queue(request); | ||
258 | return; | ||
259 | out_unlock: | ||
257 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 260 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
258 | if (request != NULL) | ||
259 | sclp_vt220_emit(request); | ||
260 | } | 261 | } |
261 | 262 | ||
262 | #define SCLP_NORMAL_WRITE 0x00 | 263 | #define SCLP_NORMAL_WRITE 0x00 |
@@ -396,7 +397,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, | |||
396 | if (sclp_vt220_current_request == NULL) { | 397 | if (sclp_vt220_current_request == NULL) { |
397 | while (list_empty(&sclp_vt220_empty)) { | 398 | while (list_empty(&sclp_vt220_empty)) { |
398 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 399 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
399 | if (may_fail) | 400 | if (may_fail || sclp_vt220_suspended) |
400 | goto out; | 401 | goto out; |
401 | else | 402 | else |
402 | sclp_sync_wait(); | 403 | sclp_sync_wait(); |
@@ -531,7 +532,7 @@ sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch) | |||
531 | static void | 532 | static void |
532 | sclp_vt220_flush_chars(struct tty_struct *tty) | 533 | sclp_vt220_flush_chars(struct tty_struct *tty) |
533 | { | 534 | { |
534 | if (sclp_vt220_outqueue_count == 0) | 535 | if (!sclp_vt220_queue_running) |
535 | sclp_vt220_emit_current(); | 536 | sclp_vt220_emit_current(); |
536 | else | 537 | else |
537 | sclp_vt220_flush_later = 1; | 538 | sclp_vt220_flush_later = 1; |
@@ -635,7 +636,6 @@ static int __init __sclp_vt220_init(int num_pages) | |||
635 | init_timer(&sclp_vt220_timer); | 636 | init_timer(&sclp_vt220_timer); |
636 | sclp_vt220_current_request = NULL; | 637 | sclp_vt220_current_request = NULL; |
637 | sclp_vt220_buffered_chars = 0; | 638 | sclp_vt220_buffered_chars = 0; |
638 | sclp_vt220_outqueue_count = 0; | ||
639 | sclp_vt220_tty = NULL; | 639 | sclp_vt220_tty = NULL; |
640 | sclp_vt220_flush_later = 0; | 640 | sclp_vt220_flush_later = 0; |
641 | 641 | ||
@@ -736,7 +736,7 @@ static void __sclp_vt220_flush_buffer(void) | |||
736 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 736 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
737 | if (timer_pending(&sclp_vt220_timer)) | 737 | if (timer_pending(&sclp_vt220_timer)) |
738 | del_timer(&sclp_vt220_timer); | 738 | del_timer(&sclp_vt220_timer); |
739 | while (sclp_vt220_outqueue_count > 0) { | 739 | while (sclp_vt220_queue_running) { |
740 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 740 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
741 | sclp_sync_wait(); | 741 | sclp_sync_wait(); |
742 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 742 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
@@ -744,6 +744,46 @@ static void __sclp_vt220_flush_buffer(void) | |||
744 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 744 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
745 | } | 745 | } |
746 | 746 | ||
747 | /* | ||
748 | * Resume console: If there are cached messages, emit them. | ||
749 | */ | ||
750 | static void sclp_vt220_resume(void) | ||
751 | { | ||
752 | unsigned long flags; | ||
753 | |||
754 | spin_lock_irqsave(&sclp_vt220_lock, flags); | ||
755 | sclp_vt220_suspended = 0; | ||
756 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
757 | sclp_vt220_emit_current(); | ||
758 | } | ||
759 | |||
760 | /* | ||
761 | * Suspend console: Set suspend flag and flush console | ||
762 | */ | ||
763 | static void sclp_vt220_suspend(void) | ||
764 | { | ||
765 | unsigned long flags; | ||
766 | |||
767 | spin_lock_irqsave(&sclp_vt220_lock, flags); | ||
768 | sclp_vt220_suspended = 1; | ||
769 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
770 | __sclp_vt220_flush_buffer(); | ||
771 | } | ||
772 | |||
773 | static void sclp_vt220_pm_event_fn(struct sclp_register *reg, | ||
774 | enum sclp_pm_event sclp_pm_event) | ||
775 | { | ||
776 | switch (sclp_pm_event) { | ||
777 | case SCLP_PM_EVENT_FREEZE: | ||
778 | sclp_vt220_suspend(); | ||
779 | break; | ||
780 | case SCLP_PM_EVENT_RESTORE: | ||
781 | case SCLP_PM_EVENT_THAW: | ||
782 | sclp_vt220_resume(); | ||
783 | break; | ||
784 | } | ||
785 | } | ||
786 | |||
747 | static int | 787 | static int |
748 | sclp_vt220_notify(struct notifier_block *self, | 788 | sclp_vt220_notify(struct notifier_block *self, |
749 | unsigned long event, void *data) | 789 | unsigned long event, void *data) |
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index 5469e099597e..a26333774701 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * tape device driver for 3480/3490E/3590 tapes. | 3 | * tape device driver for 3480/3490E/3590 tapes. |
4 | * | 4 | * |
5 | * S390 and zSeries version | 5 | * S390 and zSeries version |
6 | * Copyright IBM Corp. 2001,2006 | 6 | * Copyright IBM Corp. 2001, 2009 |
7 | * Author(s): Carsten Otte <cotte@de.ibm.com> | 7 | * Author(s): Carsten Otte <cotte@de.ibm.com> |
8 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> | 8 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> |
9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
@@ -286,6 +286,7 @@ extern void tape_state_set(struct tape_device *, enum tape_state); | |||
286 | 286 | ||
287 | extern int tape_generic_online(struct tape_device *, struct tape_discipline *); | 287 | extern int tape_generic_online(struct tape_device *, struct tape_discipline *); |
288 | extern int tape_generic_offline(struct ccw_device *); | 288 | extern int tape_generic_offline(struct ccw_device *); |
289 | extern int tape_generic_pm_suspend(struct ccw_device *); | ||
289 | 290 | ||
290 | /* Externals from tape_devmap.c */ | 291 | /* Externals from tape_devmap.c */ |
291 | extern int tape_generic_probe(struct ccw_device *); | 292 | extern int tape_generic_probe(struct ccw_device *); |
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 5f8e8ef43dd3..5a519fac37b7 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * drivers/s390/char/tape_34xx.c | 2 | * drivers/s390/char/tape_34xx.c |
3 | * tape device discipline for 3480/3490 tapes. | 3 | * tape device discipline for 3480/3490 tapes. |
4 | * | 4 | * |
5 | * Copyright (C) IBM Corp. 2001,2006 | 5 | * Copyright IBM Corp. 2001, 2009 |
6 | * Author(s): Carsten Otte <cotte@de.ibm.com> | 6 | * Author(s): Carsten Otte <cotte@de.ibm.com> |
7 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> | 7 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
@@ -1134,7 +1134,7 @@ tape_34xx_bread(struct tape_device *device, struct request *req) | |||
1134 | /* Setup ccws. */ | 1134 | /* Setup ccws. */ |
1135 | request->op = TO_BLOCK; | 1135 | request->op = TO_BLOCK; |
1136 | start_block = (struct tape_34xx_block_id *) request->cpdata; | 1136 | start_block = (struct tape_34xx_block_id *) request->cpdata; |
1137 | start_block->block = req->sector >> TAPEBLOCK_HSEC_S2B; | 1137 | start_block->block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B; |
1138 | DBF_EVENT(6, "start_block = %i\n", start_block->block); | 1138 | DBF_EVENT(6, "start_block = %i\n", start_block->block); |
1139 | 1139 | ||
1140 | ccw = request->cpaddr; | 1140 | ccw = request->cpaddr; |
@@ -1289,7 +1289,7 @@ static int | |||
1289 | tape_34xx_online(struct ccw_device *cdev) | 1289 | tape_34xx_online(struct ccw_device *cdev) |
1290 | { | 1290 | { |
1291 | return tape_generic_online( | 1291 | return tape_generic_online( |
1292 | cdev->dev.driver_data, | 1292 | dev_get_drvdata(&cdev->dev), |
1293 | &tape_discipline_34xx | 1293 | &tape_discipline_34xx |
1294 | ); | 1294 | ); |
1295 | } | 1295 | } |
@@ -1302,6 +1302,7 @@ static struct ccw_driver tape_34xx_driver = { | |||
1302 | .remove = tape_generic_remove, | 1302 | .remove = tape_generic_remove, |
1303 | .set_online = tape_34xx_online, | 1303 | .set_online = tape_34xx_online, |
1304 | .set_offline = tape_generic_offline, | 1304 | .set_offline = tape_generic_offline, |
1305 | .freeze = tape_generic_pm_suspend, | ||
1305 | }; | 1306 | }; |
1306 | 1307 | ||
1307 | static int | 1308 | static int |
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 823b05bd0dd7..418f72dd39b4 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * drivers/s390/char/tape_3590.c | 2 | * drivers/s390/char/tape_3590.c |
3 | * tape device discipline for 3590 tapes. | 3 | * tape device discipline for 3590 tapes. |
4 | * | 4 | * |
5 | * Copyright IBM Corp. 2001,2006 | 5 | * Copyright IBM Corp. 2001, 2009 |
6 | * Author(s): Stefan Bader <shbader@de.ibm.com> | 6 | * Author(s): Stefan Bader <shbader@de.ibm.com> |
7 | * Michael Holzheu <holzheu@de.ibm.com> | 7 | * Michael Holzheu <holzheu@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
@@ -633,7 +633,7 @@ tape_3590_bread(struct tape_device *device, struct request *req) | |||
633 | struct req_iterator iter; | 633 | struct req_iterator iter; |
634 | 634 | ||
635 | DBF_EVENT(6, "xBREDid:"); | 635 | DBF_EVENT(6, "xBREDid:"); |
636 | start_block = req->sector >> TAPEBLOCK_HSEC_S2B; | 636 | start_block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B; |
637 | DBF_EVENT(6, "start_block = %i\n", start_block); | 637 | DBF_EVENT(6, "start_block = %i\n", start_block); |
638 | 638 | ||
639 | rq_for_each_segment(bv, req, iter) | 639 | rq_for_each_segment(bv, req, iter) |
@@ -1703,7 +1703,7 @@ static struct ccw_device_id tape_3590_ids[] = { | |||
1703 | static int | 1703 | static int |
1704 | tape_3590_online(struct ccw_device *cdev) | 1704 | tape_3590_online(struct ccw_device *cdev) |
1705 | { | 1705 | { |
1706 | return tape_generic_online(cdev->dev.driver_data, | 1706 | return tape_generic_online(dev_get_drvdata(&cdev->dev), |
1707 | &tape_discipline_3590); | 1707 | &tape_discipline_3590); |
1708 | } | 1708 | } |
1709 | 1709 | ||
@@ -1715,6 +1715,7 @@ static struct ccw_driver tape_3590_driver = { | |||
1715 | .remove = tape_generic_remove, | 1715 | .remove = tape_generic_remove, |
1716 | .set_offline = tape_generic_offline, | 1716 | .set_offline = tape_generic_offline, |
1717 | .set_online = tape_3590_online, | 1717 | .set_online = tape_3590_online, |
1718 | .freeze = tape_generic_pm_suspend, | ||
1718 | }; | 1719 | }; |
1719 | 1720 | ||
1720 | /* | 1721 | /* |
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index f32e89e7c4f2..47ff695255ea 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c | |||
@@ -74,13 +74,6 @@ tapeblock_trigger_requeue(struct tape_device *device) | |||
74 | * Post finished request. | 74 | * Post finished request. |
75 | */ | 75 | */ |
76 | static void | 76 | static void |
77 | tapeblock_end_request(struct request *req, int error) | ||
78 | { | ||
79 | if (blk_end_request(req, error, blk_rq_bytes(req))) | ||
80 | BUG(); | ||
81 | } | ||
82 | |||
83 | static void | ||
84 | __tapeblock_end_request(struct tape_request *ccw_req, void *data) | 77 | __tapeblock_end_request(struct tape_request *ccw_req, void *data) |
85 | { | 78 | { |
86 | struct tape_device *device; | 79 | struct tape_device *device; |
@@ -90,17 +83,17 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data) | |||
90 | 83 | ||
91 | device = ccw_req->device; | 84 | device = ccw_req->device; |
92 | req = (struct request *) data; | 85 | req = (struct request *) data; |
93 | tapeblock_end_request(req, (ccw_req->rc == 0) ? 0 : -EIO); | 86 | blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO); |
94 | if (ccw_req->rc == 0) | 87 | if (ccw_req->rc == 0) |
95 | /* Update position. */ | 88 | /* Update position. */ |
96 | device->blk_data.block_position = | 89 | device->blk_data.block_position = |
97 | (req->sector + req->nr_sectors) >> TAPEBLOCK_HSEC_S2B; | 90 | (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B; |
98 | else | 91 | else |
99 | /* We lost the position information due to an error. */ | 92 | /* We lost the position information due to an error. */ |
100 | device->blk_data.block_position = -1; | 93 | device->blk_data.block_position = -1; |
101 | device->discipline->free_bread(ccw_req); | 94 | device->discipline->free_bread(ccw_req); |
102 | if (!list_empty(&device->req_queue) || | 95 | if (!list_empty(&device->req_queue) || |
103 | elv_next_request(device->blk_data.request_queue)) | 96 | blk_peek_request(device->blk_data.request_queue)) |
104 | tapeblock_trigger_requeue(device); | 97 | tapeblock_trigger_requeue(device); |
105 | } | 98 | } |
106 | 99 | ||
@@ -118,7 +111,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req) | |||
118 | ccw_req = device->discipline->bread(device, req); | 111 | ccw_req = device->discipline->bread(device, req); |
119 | if (IS_ERR(ccw_req)) { | 112 | if (IS_ERR(ccw_req)) { |
120 | DBF_EVENT(1, "TBLOCK: bread failed\n"); | 113 | DBF_EVENT(1, "TBLOCK: bread failed\n"); |
121 | tapeblock_end_request(req, -EIO); | 114 | blk_end_request_all(req, -EIO); |
122 | return PTR_ERR(ccw_req); | 115 | return PTR_ERR(ccw_req); |
123 | } | 116 | } |
124 | ccw_req->callback = __tapeblock_end_request; | 117 | ccw_req->callback = __tapeblock_end_request; |
@@ -131,7 +124,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req) | |||
131 | * Start/enqueueing failed. No retries in | 124 | * Start/enqueueing failed. No retries in |
132 | * this case. | 125 | * this case. |
133 | */ | 126 | */ |
134 | tapeblock_end_request(req, -EIO); | 127 | blk_end_request_all(req, -EIO); |
135 | device->discipline->free_bread(ccw_req); | 128 | device->discipline->free_bread(ccw_req); |
136 | } | 129 | } |
137 | 130 | ||
@@ -169,19 +162,16 @@ tapeblock_requeue(struct work_struct *work) { | |||
169 | spin_lock_irq(&device->blk_data.request_queue_lock); | 162 | spin_lock_irq(&device->blk_data.request_queue_lock); |
170 | while ( | 163 | while ( |
171 | !blk_queue_plugged(queue) && | 164 | !blk_queue_plugged(queue) && |
172 | elv_next_request(queue) && | 165 | (req = blk_fetch_request(queue)) && |
173 | nr_queued < TAPEBLOCK_MIN_REQUEUE | 166 | nr_queued < TAPEBLOCK_MIN_REQUEUE |
174 | ) { | 167 | ) { |
175 | req = elv_next_request(queue); | ||
176 | if (rq_data_dir(req) == WRITE) { | 168 | if (rq_data_dir(req) == WRITE) { |
177 | DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); | 169 | DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); |
178 | blkdev_dequeue_request(req); | ||
179 | spin_unlock_irq(&device->blk_data.request_queue_lock); | 170 | spin_unlock_irq(&device->blk_data.request_queue_lock); |
180 | tapeblock_end_request(req, -EIO); | 171 | blk_end_request_all(req, -EIO); |
181 | spin_lock_irq(&device->blk_data.request_queue_lock); | 172 | spin_lock_irq(&device->blk_data.request_queue_lock); |
182 | continue; | 173 | continue; |
183 | } | 174 | } |
184 | blkdev_dequeue_request(req); | ||
185 | nr_queued++; | 175 | nr_queued++; |
186 | spin_unlock_irq(&device->blk_data.request_queue_lock); | 176 | spin_unlock_irq(&device->blk_data.request_queue_lock); |
187 | rc = tapeblock_start_request(device, req); | 177 | rc = tapeblock_start_request(device, req); |
@@ -232,7 +222,7 @@ tapeblock_setup_device(struct tape_device * device) | |||
232 | if (rc) | 222 | if (rc) |
233 | goto cleanup_queue; | 223 | goto cleanup_queue; |
234 | 224 | ||
235 | blk_queue_hardsect_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); | 225 | blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); |
236 | blk_queue_max_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC); | 226 | blk_queue_max_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC); |
237 | blk_queue_max_phys_segments(blkdat->request_queue, -1L); | 227 | blk_queue_max_phys_segments(blkdat->request_queue, -1L); |
238 | blk_queue_max_hw_segments(blkdat->request_queue, -1L); | 228 | blk_queue_max_hw_segments(blkdat->request_queue, -1L); |
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 8a109f3b69c6..595aa04cfd01 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * basic function of the tape device driver | 3 | * basic function of the tape device driver |
4 | * | 4 | * |
5 | * S390 and zSeries version | 5 | * S390 and zSeries version |
6 | * Copyright IBM Corp. 2001,2006 | 6 | * Copyright IBM Corp. 2001, 2009 |
7 | * Author(s): Carsten Otte <cotte@de.ibm.com> | 7 | * Author(s): Carsten Otte <cotte@de.ibm.com> |
8 | * Michael Holzheu <holzheu@de.ibm.com> | 8 | * Michael Holzheu <holzheu@de.ibm.com> |
9 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> | 9 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> |
@@ -92,7 +92,7 @@ tape_medium_state_show(struct device *dev, struct device_attribute *attr, char * | |||
92 | { | 92 | { |
93 | struct tape_device *tdev; | 93 | struct tape_device *tdev; |
94 | 94 | ||
95 | tdev = (struct tape_device *) dev->driver_data; | 95 | tdev = dev_get_drvdata(dev); |
96 | return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->medium_state); | 96 | return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->medium_state); |
97 | } | 97 | } |
98 | 98 | ||
@@ -104,7 +104,7 @@ tape_first_minor_show(struct device *dev, struct device_attribute *attr, char *b | |||
104 | { | 104 | { |
105 | struct tape_device *tdev; | 105 | struct tape_device *tdev; |
106 | 106 | ||
107 | tdev = (struct tape_device *) dev->driver_data; | 107 | tdev = dev_get_drvdata(dev); |
108 | return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->first_minor); | 108 | return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->first_minor); |
109 | } | 109 | } |
110 | 110 | ||
@@ -116,7 +116,7 @@ tape_state_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
116 | { | 116 | { |
117 | struct tape_device *tdev; | 117 | struct tape_device *tdev; |
118 | 118 | ||
119 | tdev = (struct tape_device *) dev->driver_data; | 119 | tdev = dev_get_drvdata(dev); |
120 | return scnprintf(buf, PAGE_SIZE, "%s\n", (tdev->first_minor < 0) ? | 120 | return scnprintf(buf, PAGE_SIZE, "%s\n", (tdev->first_minor < 0) ? |
121 | "OFFLINE" : tape_state_verbose[tdev->tape_state]); | 121 | "OFFLINE" : tape_state_verbose[tdev->tape_state]); |
122 | } | 122 | } |
@@ -130,7 +130,7 @@ tape_operation_show(struct device *dev, struct device_attribute *attr, char *buf | |||
130 | struct tape_device *tdev; | 130 | struct tape_device *tdev; |
131 | ssize_t rc; | 131 | ssize_t rc; |
132 | 132 | ||
133 | tdev = (struct tape_device *) dev->driver_data; | 133 | tdev = dev_get_drvdata(dev); |
134 | if (tdev->first_minor < 0) | 134 | if (tdev->first_minor < 0) |
135 | return scnprintf(buf, PAGE_SIZE, "N/A\n"); | 135 | return scnprintf(buf, PAGE_SIZE, "N/A\n"); |
136 | 136 | ||
@@ -156,7 +156,7 @@ tape_blocksize_show(struct device *dev, struct device_attribute *attr, char *buf | |||
156 | { | 156 | { |
157 | struct tape_device *tdev; | 157 | struct tape_device *tdev; |
158 | 158 | ||
159 | tdev = (struct tape_device *) dev->driver_data; | 159 | tdev = dev_get_drvdata(dev); |
160 | 160 | ||
161 | return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->char_data.block_size); | 161 | return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->char_data.block_size); |
162 | } | 162 | } |
@@ -380,6 +380,55 @@ tape_cleanup_device(struct tape_device *device) | |||
380 | } | 380 | } |
381 | 381 | ||
382 | /* | 382 | /* |
383 | * Suspend device. | ||
384 | * | ||
385 | * Called by the common I/O layer if the drive should be suspended on user | ||
386 | * request. We refuse to suspend if the device is loaded or in use for the | ||
387 | * following reason: | ||
388 | * While the Linux guest is suspended, it might be logged off which causes | ||
389 | * devices to be detached. Tape devices are automatically rewound and unloaded | ||
390 | * during DETACH processing (unless the tape device was attached with the | ||
391 | * NOASSIGN or MULTIUSER option). After rewind/unload, there is no way to | ||
392 | * resume the original state of the tape device, since we would need to | ||
393 | * manually re-load the cartridge which was active at suspend time. | ||
394 | */ | ||
395 | int tape_generic_pm_suspend(struct ccw_device *cdev) | ||
396 | { | ||
397 | struct tape_device *device; | ||
398 | |||
399 | device = cdev->dev.driver_data; | ||
400 | if (!device) { | ||
401 | return -ENODEV; | ||
402 | } | ||
403 | |||
404 | DBF_LH(3, "(%08x): tape_generic_pm_suspend(%p)\n", | ||
405 | device->cdev_id, device); | ||
406 | |||
407 | if (device->medium_state != MS_UNLOADED) { | ||
408 | pr_err("A cartridge is loaded in tape device %s, " | ||
409 | "refusing to suspend\n", dev_name(&cdev->dev)); | ||
410 | return -EBUSY; | ||
411 | } | ||
412 | |||
413 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
414 | switch (device->tape_state) { | ||
415 | case TS_INIT: | ||
416 | case TS_NOT_OPER: | ||
417 | case TS_UNUSED: | ||
418 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
419 | break; | ||
420 | default: | ||
421 | pr_err("Tape device %s is busy, refusing to " | ||
422 | "suspend\n", dev_name(&cdev->dev)); | ||
423 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
424 | return -EBUSY; | ||
425 | } | ||
426 | |||
427 | DBF_LH(3, "(%08x): Drive suspended.\n", device->cdev_id); | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | /* | ||
383 | * Set device offline. | 432 | * Set device offline. |
384 | * | 433 | * |
385 | * Called by the common I/O layer if the drive should set offline on user | 434 | * Called by the common I/O layer if the drive should set offline on user |
@@ -391,7 +440,7 @@ tape_generic_offline(struct ccw_device *cdev) | |||
391 | { | 440 | { |
392 | struct tape_device *device; | 441 | struct tape_device *device; |
393 | 442 | ||
394 | device = cdev->dev.driver_data; | 443 | device = dev_get_drvdata(&cdev->dev); |
395 | if (!device) { | 444 | if (!device) { |
396 | return -ENODEV; | 445 | return -ENODEV; |
397 | } | 446 | } |
@@ -534,7 +583,7 @@ tape_generic_probe(struct ccw_device *cdev) | |||
534 | tape_put_device(device); | 583 | tape_put_device(device); |
535 | return ret; | 584 | return ret; |
536 | } | 585 | } |
537 | cdev->dev.driver_data = device; | 586 | dev_set_drvdata(&cdev->dev, device); |
538 | cdev->handler = __tape_do_irq; | 587 | cdev->handler = __tape_do_irq; |
539 | device->cdev = cdev; | 588 | device->cdev = cdev; |
540 | ccw_device_get_id(cdev, &dev_id); | 589 | ccw_device_get_id(cdev, &dev_id); |
@@ -573,7 +622,7 @@ tape_generic_remove(struct ccw_device *cdev) | |||
573 | { | 622 | { |
574 | struct tape_device * device; | 623 | struct tape_device * device; |
575 | 624 | ||
576 | device = cdev->dev.driver_data; | 625 | device = dev_get_drvdata(&cdev->dev); |
577 | if (!device) { | 626 | if (!device) { |
578 | return; | 627 | return; |
579 | } | 628 | } |
@@ -613,9 +662,9 @@ tape_generic_remove(struct ccw_device *cdev) | |||
613 | tape_cleanup_device(device); | 662 | tape_cleanup_device(device); |
614 | } | 663 | } |
615 | 664 | ||
616 | if (cdev->dev.driver_data != NULL) { | 665 | if (!dev_get_drvdata(&cdev->dev)) { |
617 | sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group); | 666 | sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group); |
618 | cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data); | 667 | dev_set_drvdata(&cdev->dev, tape_put_device(dev_get_drvdata(&cdev->dev))); |
619 | } | 668 | } |
620 | } | 669 | } |
621 | 670 | ||
@@ -1011,7 +1060,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
1011 | struct tape_request *request; | 1060 | struct tape_request *request; |
1012 | int rc; | 1061 | int rc; |
1013 | 1062 | ||
1014 | device = (struct tape_device *) cdev->dev.driver_data; | 1063 | device = dev_get_drvdata(&cdev->dev); |
1015 | if (device == NULL) { | 1064 | if (device == NULL) { |
1016 | return; | 1065 | return; |
1017 | } | 1066 | } |
@@ -1273,6 +1322,7 @@ EXPORT_SYMBOL(tape_generic_remove); | |||
1273 | EXPORT_SYMBOL(tape_generic_probe); | 1322 | EXPORT_SYMBOL(tape_generic_probe); |
1274 | EXPORT_SYMBOL(tape_generic_online); | 1323 | EXPORT_SYMBOL(tape_generic_online); |
1275 | EXPORT_SYMBOL(tape_generic_offline); | 1324 | EXPORT_SYMBOL(tape_generic_offline); |
1325 | EXPORT_SYMBOL(tape_generic_pm_suspend); | ||
1276 | EXPORT_SYMBOL(tape_put_device); | 1326 | EXPORT_SYMBOL(tape_put_device); |
1277 | EXPORT_SYMBOL(tape_get_device_reference); | 1327 | EXPORT_SYMBOL(tape_get_device_reference); |
1278 | EXPORT_SYMBOL(tape_state_verbose); | 1328 | EXPORT_SYMBOL(tape_state_verbose); |
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index a7fe6302c982..38385677c653 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c | |||
@@ -112,7 +112,7 @@ struct tty3270 { | |||
112 | #define TTY_UPDATE_LIST 2 /* Update lines in tty3270->update. */ | 112 | #define TTY_UPDATE_LIST 2 /* Update lines in tty3270->update. */ |
113 | #define TTY_UPDATE_INPUT 4 /* Update input line. */ | 113 | #define TTY_UPDATE_INPUT 4 /* Update input line. */ |
114 | #define TTY_UPDATE_STATUS 8 /* Update status line. */ | 114 | #define TTY_UPDATE_STATUS 8 /* Update status line. */ |
115 | #define TTY_UPDATE_ALL 15 | 115 | #define TTY_UPDATE_ALL 16 /* Recreate screen. */ |
116 | 116 | ||
117 | static void tty3270_update(struct tty3270 *); | 117 | static void tty3270_update(struct tty3270 *); |
118 | 118 | ||
@@ -121,19 +121,10 @@ static void tty3270_update(struct tty3270 *); | |||
121 | */ | 121 | */ |
122 | static void tty3270_set_timer(struct tty3270 *tp, int expires) | 122 | static void tty3270_set_timer(struct tty3270 *tp, int expires) |
123 | { | 123 | { |
124 | if (expires == 0) { | 124 | if (expires == 0) |
125 | if (timer_pending(&tp->timer) && del_timer(&tp->timer)) | 125 | del_timer(&tp->timer); |
126 | raw3270_put_view(&tp->view); | 126 | else |
127 | return; | 127 | mod_timer(&tp->timer, jiffies + expires); |
128 | } | ||
129 | if (timer_pending(&tp->timer) && | ||
130 | mod_timer(&tp->timer, jiffies + expires)) | ||
131 | return; | ||
132 | raw3270_get_view(&tp->view); | ||
133 | tp->timer.function = (void (*)(unsigned long)) tty3270_update; | ||
134 | tp->timer.data = (unsigned long) tp; | ||
135 | tp->timer.expires = jiffies + expires; | ||
136 | add_timer(&tp->timer); | ||
137 | } | 128 | } |
138 | 129 | ||
139 | /* | 130 | /* |
@@ -337,7 +328,6 @@ tty3270_write_callback(struct raw3270_request *rq, void *data) | |||
337 | tp = (struct tty3270 *) rq->view; | 328 | tp = (struct tty3270 *) rq->view; |
338 | if (rq->rc != 0) { | 329 | if (rq->rc != 0) { |
339 | /* Write wasn't successfull. Refresh all. */ | 330 | /* Write wasn't successfull. Refresh all. */ |
340 | tty3270_rebuild_update(tp); | ||
341 | tp->update_flags = TTY_UPDATE_ALL; | 331 | tp->update_flags = TTY_UPDATE_ALL; |
342 | tty3270_set_timer(tp, 1); | 332 | tty3270_set_timer(tp, 1); |
343 | } | 333 | } |
@@ -366,6 +356,12 @@ tty3270_update(struct tty3270 *tp) | |||
366 | 356 | ||
367 | spin_lock(&tp->view.lock); | 357 | spin_lock(&tp->view.lock); |
368 | updated = 0; | 358 | updated = 0; |
359 | if (tp->update_flags & TTY_UPDATE_ALL) { | ||
360 | tty3270_rebuild_update(tp); | ||
361 | tty3270_update_status(tp); | ||
362 | tp->update_flags = TTY_UPDATE_ERASE | TTY_UPDATE_LIST | | ||
363 | TTY_UPDATE_INPUT | TTY_UPDATE_STATUS; | ||
364 | } | ||
369 | if (tp->update_flags & TTY_UPDATE_ERASE) { | 365 | if (tp->update_flags & TTY_UPDATE_ERASE) { |
370 | /* Use erase write alternate to erase display. */ | 366 | /* Use erase write alternate to erase display. */ |
371 | raw3270_request_set_cmd(wrq, TC_EWRITEA); | 367 | raw3270_request_set_cmd(wrq, TC_EWRITEA); |
@@ -425,7 +421,6 @@ tty3270_update(struct tty3270 *tp) | |||
425 | xchg(&tp->write, wrq); | 421 | xchg(&tp->write, wrq); |
426 | } | 422 | } |
427 | spin_unlock(&tp->view.lock); | 423 | spin_unlock(&tp->view.lock); |
428 | raw3270_put_view(&tp->view); | ||
429 | } | 424 | } |
430 | 425 | ||
431 | /* | 426 | /* |
@@ -570,7 +565,6 @@ tty3270_read_tasklet(struct raw3270_request *rrq) | |||
570 | tty3270_set_timer(tp, 1); | 565 | tty3270_set_timer(tp, 1); |
571 | } else if (tp->input->string[0] == 0x6d) { | 566 | } else if (tp->input->string[0] == 0x6d) { |
572 | /* Display has been cleared. Redraw. */ | 567 | /* Display has been cleared. Redraw. */ |
573 | tty3270_rebuild_update(tp); | ||
574 | tp->update_flags = TTY_UPDATE_ALL; | 568 | tp->update_flags = TTY_UPDATE_ALL; |
575 | tty3270_set_timer(tp, 1); | 569 | tty3270_set_timer(tp, 1); |
576 | } | 570 | } |
@@ -641,22 +635,20 @@ static int | |||
641 | tty3270_activate(struct raw3270_view *view) | 635 | tty3270_activate(struct raw3270_view *view) |
642 | { | 636 | { |
643 | struct tty3270 *tp; | 637 | struct tty3270 *tp; |
644 | unsigned long flags; | ||
645 | 638 | ||
646 | tp = (struct tty3270 *) view; | 639 | tp = (struct tty3270 *) view; |
647 | spin_lock_irqsave(&tp->view.lock, flags); | ||
648 | tp->nr_up = 0; | ||
649 | tty3270_rebuild_update(tp); | ||
650 | tty3270_update_status(tp); | ||
651 | tp->update_flags = TTY_UPDATE_ALL; | 640 | tp->update_flags = TTY_UPDATE_ALL; |
652 | tty3270_set_timer(tp, 1); | 641 | tty3270_set_timer(tp, 1); |
653 | spin_unlock_irqrestore(&tp->view.lock, flags); | ||
654 | return 0; | 642 | return 0; |
655 | } | 643 | } |
656 | 644 | ||
657 | static void | 645 | static void |
658 | tty3270_deactivate(struct raw3270_view *view) | 646 | tty3270_deactivate(struct raw3270_view *view) |
659 | { | 647 | { |
648 | struct tty3270 *tp; | ||
649 | |||
650 | tp = (struct tty3270 *) view; | ||
651 | del_timer(&tp->timer); | ||
660 | } | 652 | } |
661 | 653 | ||
662 | static int | 654 | static int |
@@ -743,6 +735,7 @@ tty3270_free_view(struct tty3270 *tp) | |||
743 | { | 735 | { |
744 | int pages; | 736 | int pages; |
745 | 737 | ||
738 | del_timer_sync(&tp->timer); | ||
746 | kbd_free(tp->kbd); | 739 | kbd_free(tp->kbd); |
747 | raw3270_request_free(tp->kreset); | 740 | raw3270_request_free(tp->kreset); |
748 | raw3270_request_free(tp->read); | 741 | raw3270_request_free(tp->read); |
@@ -889,7 +882,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp) | |||
889 | INIT_LIST_HEAD(&tp->update); | 882 | INIT_LIST_HEAD(&tp->update); |
890 | INIT_LIST_HEAD(&tp->rcl_lines); | 883 | INIT_LIST_HEAD(&tp->rcl_lines); |
891 | tp->rcl_max = 20; | 884 | tp->rcl_max = 20; |
892 | init_timer(&tp->timer); | 885 | setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update, |
886 | (unsigned long) tp); | ||
893 | tasklet_init(&tp->readlet, | 887 | tasklet_init(&tp->readlet, |
894 | (void (*)(unsigned long)) tty3270_read_tasklet, | 888 | (void (*)(unsigned long)) tty3270_read_tasklet, |
895 | (unsigned long) tp->read); | 889 | (unsigned long) tp->read); |
@@ -1754,14 +1748,6 @@ static const struct tty_operations tty3270_ops = { | |||
1754 | .set_termios = tty3270_set_termios | 1748 | .set_termios = tty3270_set_termios |
1755 | }; | 1749 | }; |
1756 | 1750 | ||
1757 | static void tty3270_notifier(int index, int active) | ||
1758 | { | ||
1759 | if (active) | ||
1760 | tty_register_device(tty3270_driver, index, NULL); | ||
1761 | else | ||
1762 | tty_unregister_device(tty3270_driver, index); | ||
1763 | } | ||
1764 | |||
1765 | /* | 1751 | /* |
1766 | * 3270 tty registration code called from tty_init(). | 1752 | * 3270 tty registration code called from tty_init(). |
1767 | * Most kernel services (incl. kmalloc) are available at this poimt. | 1753 | * Most kernel services (incl. kmalloc) are available at this poimt. |
@@ -1796,12 +1782,6 @@ static int __init tty3270_init(void) | |||
1796 | return ret; | 1782 | return ret; |
1797 | } | 1783 | } |
1798 | tty3270_driver = driver; | 1784 | tty3270_driver = driver; |
1799 | ret = raw3270_register_notifier(tty3270_notifier); | ||
1800 | if (ret) { | ||
1801 | put_tty_driver(driver); | ||
1802 | return ret; | ||
1803 | |||
1804 | } | ||
1805 | return 0; | 1785 | return 0; |
1806 | } | 1786 | } |
1807 | 1787 | ||
@@ -1810,7 +1790,6 @@ tty3270_exit(void) | |||
1810 | { | 1790 | { |
1811 | struct tty_driver *driver; | 1791 | struct tty_driver *driver; |
1812 | 1792 | ||
1813 | raw3270_unregister_notifier(tty3270_notifier); | ||
1814 | driver = tty3270_driver; | 1793 | driver = tty3270_driver; |
1815 | tty3270_driver = NULL; | 1794 | tty3270_driver = NULL; |
1816 | tty_unregister_driver(driver); | 1795 | tty_unregister_driver(driver); |
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index d8a2289fcb69..411cfa3c7719 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * character device driver for reading z/VM system service records | 3 | * character device driver for reading z/VM system service records |
4 | * | 4 | * |
5 | * | 5 | * |
6 | * Copyright 2004 IBM Corporation | 6 | * Copyright IBM Corp. 2004, 2009 |
7 | * character device driver for reading z/VM system service records, | 7 | * character device driver for reading z/VM system service records, |
8 | * Version 1.0 | 8 | * Version 1.0 |
9 | * Author(s): Xenia Tkatschow <xenia@us.ibm.com> | 9 | * Author(s): Xenia Tkatschow <xenia@us.ibm.com> |
@@ -504,7 +504,7 @@ static ssize_t vmlogrdr_autopurge_store(struct device * dev, | |||
504 | struct device_attribute *attr, | 504 | struct device_attribute *attr, |
505 | const char * buf, size_t count) | 505 | const char * buf, size_t count) |
506 | { | 506 | { |
507 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 507 | struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); |
508 | ssize_t ret = count; | 508 | ssize_t ret = count; |
509 | 509 | ||
510 | switch (buf[0]) { | 510 | switch (buf[0]) { |
@@ -525,7 +525,7 @@ static ssize_t vmlogrdr_autopurge_show(struct device *dev, | |||
525 | struct device_attribute *attr, | 525 | struct device_attribute *attr, |
526 | char *buf) | 526 | char *buf) |
527 | { | 527 | { |
528 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 528 | struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); |
529 | return sprintf(buf, "%u\n", priv->autopurge); | 529 | return sprintf(buf, "%u\n", priv->autopurge); |
530 | } | 530 | } |
531 | 531 | ||
@@ -541,7 +541,7 @@ static ssize_t vmlogrdr_purge_store(struct device * dev, | |||
541 | 541 | ||
542 | char cp_command[80]; | 542 | char cp_command[80]; |
543 | char cp_response[80]; | 543 | char cp_response[80]; |
544 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 544 | struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); |
545 | 545 | ||
546 | if (buf[0] != '1') | 546 | if (buf[0] != '1') |
547 | return -EINVAL; | 547 | return -EINVAL; |
@@ -578,7 +578,7 @@ static ssize_t vmlogrdr_autorecording_store(struct device *dev, | |||
578 | struct device_attribute *attr, | 578 | struct device_attribute *attr, |
579 | const char *buf, size_t count) | 579 | const char *buf, size_t count) |
580 | { | 580 | { |
581 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 581 | struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); |
582 | ssize_t ret = count; | 582 | ssize_t ret = count; |
583 | 583 | ||
584 | switch (buf[0]) { | 584 | switch (buf[0]) { |
@@ -599,7 +599,7 @@ static ssize_t vmlogrdr_autorecording_show(struct device *dev, | |||
599 | struct device_attribute *attr, | 599 | struct device_attribute *attr, |
600 | char *buf) | 600 | char *buf) |
601 | { | 601 | { |
602 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 602 | struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); |
603 | return sprintf(buf, "%u\n", priv->autorecording); | 603 | return sprintf(buf, "%u\n", priv->autorecording); |
604 | } | 604 | } |
605 | 605 | ||
@@ -612,7 +612,7 @@ static ssize_t vmlogrdr_recording_store(struct device * dev, | |||
612 | struct device_attribute *attr, | 612 | struct device_attribute *attr, |
613 | const char * buf, size_t count) | 613 | const char * buf, size_t count) |
614 | { | 614 | { |
615 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 615 | struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); |
616 | ssize_t ret; | 616 | ssize_t ret; |
617 | 617 | ||
618 | switch (buf[0]) { | 618 | switch (buf[0]) { |
@@ -660,6 +660,29 @@ static struct attribute *vmlogrdr_attrs[] = { | |||
660 | NULL, | 660 | NULL, |
661 | }; | 661 | }; |
662 | 662 | ||
663 | static int vmlogrdr_pm_prepare(struct device *dev) | ||
664 | { | ||
665 | int rc; | ||
666 | struct vmlogrdr_priv_t *priv = dev->driver_data; | ||
667 | |||
668 | rc = 0; | ||
669 | if (priv) { | ||
670 | spin_lock_bh(&priv->priv_lock); | ||
671 | if (priv->dev_in_use) | ||
672 | rc = -EBUSY; | ||
673 | spin_unlock_bh(&priv->priv_lock); | ||
674 | } | ||
675 | if (rc) | ||
676 | pr_err("vmlogrdr: device %s is busy. Refuse to suspend.\n", | ||
677 | dev_name(dev)); | ||
678 | return rc; | ||
679 | } | ||
680 | |||
681 | |||
682 | static struct dev_pm_ops vmlogrdr_pm_ops = { | ||
683 | .prepare = vmlogrdr_pm_prepare, | ||
684 | }; | ||
685 | |||
663 | static struct attribute_group vmlogrdr_attr_group = { | 686 | static struct attribute_group vmlogrdr_attr_group = { |
664 | .attrs = vmlogrdr_attrs, | 687 | .attrs = vmlogrdr_attrs, |
665 | }; | 688 | }; |
@@ -668,6 +691,7 @@ static struct class *vmlogrdr_class; | |||
668 | static struct device_driver vmlogrdr_driver = { | 691 | static struct device_driver vmlogrdr_driver = { |
669 | .name = "vmlogrdr", | 692 | .name = "vmlogrdr", |
670 | .bus = &iucv_bus, | 693 | .bus = &iucv_bus, |
694 | .pm = &vmlogrdr_pm_ops, | ||
671 | }; | 695 | }; |
672 | 696 | ||
673 | 697 | ||
@@ -729,6 +753,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) | |||
729 | dev->bus = &iucv_bus; | 753 | dev->bus = &iucv_bus; |
730 | dev->parent = iucv_root; | 754 | dev->parent = iucv_root; |
731 | dev->driver = &vmlogrdr_driver; | 755 | dev->driver = &vmlogrdr_driver; |
756 | dev->driver_data = priv; | ||
732 | /* | 757 | /* |
733 | * The release function could be called after the | 758 | * The release function could be called after the |
734 | * module has been unloaded. It's _only_ task is to | 759 | * module has been unloaded. It's _only_ task is to |
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 5dcef81fc9d9..7d9e67cb6471 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Linux driver for System z and s390 unit record devices | 2 | * Linux driver for System z and s390 unit record devices |
3 | * (z/VM virtual punch, reader, printer) | 3 | * (z/VM virtual punch, reader, printer) |
4 | * | 4 | * |
5 | * Copyright IBM Corp. 2001, 2007 | 5 | * Copyright IBM Corp. 2001, 2009 |
6 | * Authors: Malcolm Beattie <beattiem@uk.ibm.com> | 6 | * Authors: Malcolm Beattie <beattiem@uk.ibm.com> |
7 | * Michael Holzheu <holzheu@de.ibm.com> | 7 | * Michael Holzheu <holzheu@de.ibm.com> |
8 | * Frank Munzert <munzert@de.ibm.com> | 8 | * Frank Munzert <munzert@de.ibm.com> |
@@ -60,6 +60,7 @@ static int ur_probe(struct ccw_device *cdev); | |||
60 | static void ur_remove(struct ccw_device *cdev); | 60 | static void ur_remove(struct ccw_device *cdev); |
61 | static int ur_set_online(struct ccw_device *cdev); | 61 | static int ur_set_online(struct ccw_device *cdev); |
62 | static int ur_set_offline(struct ccw_device *cdev); | 62 | static int ur_set_offline(struct ccw_device *cdev); |
63 | static int ur_pm_suspend(struct ccw_device *cdev); | ||
63 | 64 | ||
64 | static struct ccw_driver ur_driver = { | 65 | static struct ccw_driver ur_driver = { |
65 | .name = "vmur", | 66 | .name = "vmur", |
@@ -69,6 +70,7 @@ static struct ccw_driver ur_driver = { | |||
69 | .remove = ur_remove, | 70 | .remove = ur_remove, |
70 | .set_online = ur_set_online, | 71 | .set_online = ur_set_online, |
71 | .set_offline = ur_set_offline, | 72 | .set_offline = ur_set_offline, |
73 | .freeze = ur_pm_suspend, | ||
72 | }; | 74 | }; |
73 | 75 | ||
74 | static DEFINE_MUTEX(vmur_mutex); | 76 | static DEFINE_MUTEX(vmur_mutex); |
@@ -78,11 +80,11 @@ static DEFINE_MUTEX(vmur_mutex); | |||
78 | * | 80 | * |
79 | * Each ur device (urd) contains a reference to its corresponding ccw device | 81 | * Each ur device (urd) contains a reference to its corresponding ccw device |
80 | * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the | 82 | * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the |
81 | * ur device using the cdev->dev.driver_data pointer. | 83 | * ur device using dev_get_drvdata(&cdev->dev) pointer. |
82 | * | 84 | * |
83 | * urd references: | 85 | * urd references: |
84 | * - ur_probe gets a urd reference, ur_remove drops the reference | 86 | * - ur_probe gets a urd reference, ur_remove drops the reference |
85 | * (cdev->dev.driver_data) | 87 | * dev_get_drvdata(&cdev->dev) |
86 | * - ur_open gets a urd reference, ur_relase drops the reference | 88 | * - ur_open gets a urd reference, ur_relase drops the reference |
87 | * (urf->urd) | 89 | * (urf->urd) |
88 | * | 90 | * |
@@ -90,7 +92,7 @@ static DEFINE_MUTEX(vmur_mutex); | |||
90 | * - urdev_alloc get a cdev reference (urd->cdev) | 92 | * - urdev_alloc get a cdev reference (urd->cdev) |
91 | * - urdev_free drops the cdev reference (urd->cdev) | 93 | * - urdev_free drops the cdev reference (urd->cdev) |
92 | * | 94 | * |
93 | * Setting and clearing of cdev->dev.driver_data is protected by the ccwdev lock | 95 | * Setting and clearing of dev_get_drvdata(&cdev->dev) is protected by the ccwdev lock |
94 | */ | 96 | */ |
95 | static struct urdev *urdev_alloc(struct ccw_device *cdev) | 97 | static struct urdev *urdev_alloc(struct ccw_device *cdev) |
96 | { | 98 | { |
@@ -129,7 +131,7 @@ static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev) | |||
129 | unsigned long flags; | 131 | unsigned long flags; |
130 | 132 | ||
131 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); | 133 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); |
132 | urd = cdev->dev.driver_data; | 134 | urd = dev_get_drvdata(&cdev->dev); |
133 | if (urd) | 135 | if (urd) |
134 | urdev_get(urd); | 136 | urdev_get(urd); |
135 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); | 137 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); |
@@ -158,6 +160,28 @@ static void urdev_put(struct urdev *urd) | |||
158 | } | 160 | } |
159 | 161 | ||
160 | /* | 162 | /* |
163 | * State and contents of ur devices can be changed by class D users issuing | ||
164 | * CP commands such as PURGE or TRANSFER, while the Linux guest is suspended. | ||
165 | * Also the Linux guest might be logged off, which causes all active spool | ||
166 | * files to be closed. | ||
167 | * So we cannot guarantee that spool files are still the same when the Linux | ||
168 | * guest is resumed. In order to avoid unpredictable results at resume time | ||
169 | * we simply refuse to suspend if a ur device node is open. | ||
170 | */ | ||
171 | static int ur_pm_suspend(struct ccw_device *cdev) | ||
172 | { | ||
173 | struct urdev *urd = cdev->dev.driver_data; | ||
174 | |||
175 | TRACE("ur_pm_suspend: cdev=%p\n", cdev); | ||
176 | if (urd->open_flag) { | ||
177 | pr_err("Unit record device %s is busy, %s refusing to " | ||
178 | "suspend.\n", dev_name(&cdev->dev), ur_banner); | ||
179 | return -EBUSY; | ||
180 | } | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | /* | ||
161 | * Low-level functions to do I/O to a ur device. | 185 | * Low-level functions to do I/O to a ur device. |
162 | * alloc_chan_prog | 186 | * alloc_chan_prog |
163 | * free_chan_prog | 187 | * free_chan_prog |
@@ -286,7 +310,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
286 | TRACE("ur_int_handler: unsolicited interrupt\n"); | 310 | TRACE("ur_int_handler: unsolicited interrupt\n"); |
287 | return; | 311 | return; |
288 | } | 312 | } |
289 | urd = cdev->dev.driver_data; | 313 | urd = dev_get_drvdata(&cdev->dev); |
290 | BUG_ON(!urd); | 314 | BUG_ON(!urd); |
291 | /* On special conditions irb is an error pointer */ | 315 | /* On special conditions irb is an error pointer */ |
292 | if (IS_ERR(irb)) | 316 | if (IS_ERR(irb)) |
@@ -832,7 +856,7 @@ static int ur_probe(struct ccw_device *cdev) | |||
832 | goto fail_remove_attr; | 856 | goto fail_remove_attr; |
833 | } | 857 | } |
834 | spin_lock_irq(get_ccwdev_lock(cdev)); | 858 | spin_lock_irq(get_ccwdev_lock(cdev)); |
835 | cdev->dev.driver_data = urd; | 859 | dev_set_drvdata(&cdev->dev, urd); |
836 | spin_unlock_irq(get_ccwdev_lock(cdev)); | 860 | spin_unlock_irq(get_ccwdev_lock(cdev)); |
837 | 861 | ||
838 | mutex_unlock(&vmur_mutex); | 862 | mutex_unlock(&vmur_mutex); |
@@ -972,8 +996,8 @@ static void ur_remove(struct ccw_device *cdev) | |||
972 | ur_remove_attributes(&cdev->dev); | 996 | ur_remove_attributes(&cdev->dev); |
973 | 997 | ||
974 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); | 998 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); |
975 | urdev_put(cdev->dev.driver_data); | 999 | urdev_put(dev_get_drvdata(&cdev->dev)); |
976 | cdev->dev.driver_data = NULL; | 1000 | dev_set_drvdata(&cdev->dev, NULL); |
977 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); | 1001 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); |
978 | 1002 | ||
979 | mutex_unlock(&vmur_mutex); | 1003 | mutex_unlock(&vmur_mutex); |
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 21a2a829bf4e..cb7854c10c04 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c | |||
@@ -1,17 +1,23 @@ | |||
1 | /* | 1 | /* |
2 | * Watchdog implementation based on z/VM Watchdog Timer API | 2 | * Watchdog implementation based on z/VM Watchdog Timer API |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2004,2009 | ||
5 | * | ||
4 | * The user space watchdog daemon can use this driver as | 6 | * The user space watchdog daemon can use this driver as |
5 | * /dev/vmwatchdog to have z/VM execute the specified CP | 7 | * /dev/vmwatchdog to have z/VM execute the specified CP |
6 | * command when the timeout expires. The default command is | 8 | * command when the timeout expires. The default command is |
7 | * "IPL", which which cause an immediate reboot. | 9 | * "IPL", which which cause an immediate reboot. |
8 | */ | 10 | */ |
11 | #define KMSG_COMPONENT "vmwatchdog" | ||
12 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
13 | |||
9 | #include <linux/init.h> | 14 | #include <linux/init.h> |
10 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
11 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
12 | #include <linux/miscdevice.h> | 17 | #include <linux/miscdevice.h> |
13 | #include <linux/module.h> | 18 | #include <linux/module.h> |
14 | #include <linux/moduleparam.h> | 19 | #include <linux/moduleparam.h> |
20 | #include <linux/suspend.h> | ||
15 | #include <linux/watchdog.h> | 21 | #include <linux/watchdog.h> |
16 | #include <linux/smp_lock.h> | 22 | #include <linux/smp_lock.h> |
17 | 23 | ||
@@ -43,6 +49,9 @@ static unsigned int vmwdt_interval = 60; | |||
43 | static unsigned long vmwdt_is_open; | 49 | static unsigned long vmwdt_is_open; |
44 | static int vmwdt_expect_close; | 50 | static int vmwdt_expect_close; |
45 | 51 | ||
52 | #define VMWDT_OPEN 0 /* devnode is open or suspend in progress */ | ||
53 | #define VMWDT_RUNNING 1 /* The watchdog is armed */ | ||
54 | |||
46 | enum vmwdt_func { | 55 | enum vmwdt_func { |
47 | /* function codes */ | 56 | /* function codes */ |
48 | wdt_init = 0, | 57 | wdt_init = 0, |
@@ -92,6 +101,7 @@ static int vmwdt_keepalive(void) | |||
92 | EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); | 101 | EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); |
93 | 102 | ||
94 | func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; | 103 | func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; |
104 | set_bit(VMWDT_RUNNING, &vmwdt_is_open); | ||
95 | ret = __diag288(func, vmwdt_interval, ebc_cmd, len); | 105 | ret = __diag288(func, vmwdt_interval, ebc_cmd, len); |
96 | WARN_ON(ret != 0); | 106 | WARN_ON(ret != 0); |
97 | kfree(ebc_cmd); | 107 | kfree(ebc_cmd); |
@@ -102,6 +112,7 @@ static int vmwdt_disable(void) | |||
102 | { | 112 | { |
103 | int ret = __diag288(wdt_cancel, 0, "", 0); | 113 | int ret = __diag288(wdt_cancel, 0, "", 0); |
104 | WARN_ON(ret != 0); | 114 | WARN_ON(ret != 0); |
115 | clear_bit(VMWDT_RUNNING, &vmwdt_is_open); | ||
105 | return ret; | 116 | return ret; |
106 | } | 117 | } |
107 | 118 | ||
@@ -123,13 +134,13 @@ static int vmwdt_open(struct inode *i, struct file *f) | |||
123 | { | 134 | { |
124 | int ret; | 135 | int ret; |
125 | lock_kernel(); | 136 | lock_kernel(); |
126 | if (test_and_set_bit(0, &vmwdt_is_open)) { | 137 | if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { |
127 | unlock_kernel(); | 138 | unlock_kernel(); |
128 | return -EBUSY; | 139 | return -EBUSY; |
129 | } | 140 | } |
130 | ret = vmwdt_keepalive(); | 141 | ret = vmwdt_keepalive(); |
131 | if (ret) | 142 | if (ret) |
132 | clear_bit(0, &vmwdt_is_open); | 143 | clear_bit(VMWDT_OPEN, &vmwdt_is_open); |
133 | unlock_kernel(); | 144 | unlock_kernel(); |
134 | return ret ? ret : nonseekable_open(i, f); | 145 | return ret ? ret : nonseekable_open(i, f); |
135 | } | 146 | } |
@@ -139,7 +150,7 @@ static int vmwdt_close(struct inode *i, struct file *f) | |||
139 | if (vmwdt_expect_close == 42) | 150 | if (vmwdt_expect_close == 42) |
140 | vmwdt_disable(); | 151 | vmwdt_disable(); |
141 | vmwdt_expect_close = 0; | 152 | vmwdt_expect_close = 0; |
142 | clear_bit(0, &vmwdt_is_open); | 153 | clear_bit(VMWDT_OPEN, &vmwdt_is_open); |
143 | return 0; | 154 | return 0; |
144 | } | 155 | } |
145 | 156 | ||
@@ -223,6 +234,57 @@ static ssize_t vmwdt_write(struct file *f, const char __user *buf, | |||
223 | return count; | 234 | return count; |
224 | } | 235 | } |
225 | 236 | ||
237 | static int vmwdt_resume(void) | ||
238 | { | ||
239 | clear_bit(VMWDT_OPEN, &vmwdt_is_open); | ||
240 | return NOTIFY_DONE; | ||
241 | } | ||
242 | |||
243 | /* | ||
244 | * It makes no sense to go into suspend while the watchdog is running. | ||
245 | * Depending on the memory size, the watchdog might trigger, while we | ||
246 | * are still saving the memory. | ||
247 | * We reuse the open flag to ensure that suspend and watchdog open are | ||
248 | * exclusive operations | ||
249 | */ | ||
250 | static int vmwdt_suspend(void) | ||
251 | { | ||
252 | if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { | ||
253 | pr_err("The watchdog is in use. " | ||
254 | "This prevents hibernation or suspend.\n"); | ||
255 | return NOTIFY_BAD; | ||
256 | } | ||
257 | if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) { | ||
258 | clear_bit(VMWDT_OPEN, &vmwdt_is_open); | ||
259 | pr_err("The watchdog is running. " | ||
260 | "This prevents hibernation or suspend.\n"); | ||
261 | return NOTIFY_BAD; | ||
262 | } | ||
263 | return NOTIFY_DONE; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * This function is called for suspend and resume. | ||
268 | */ | ||
269 | static int vmwdt_power_event(struct notifier_block *this, unsigned long event, | ||
270 | void *ptr) | ||
271 | { | ||
272 | switch (event) { | ||
273 | case PM_POST_HIBERNATION: | ||
274 | case PM_POST_SUSPEND: | ||
275 | return vmwdt_resume(); | ||
276 | case PM_HIBERNATION_PREPARE: | ||
277 | case PM_SUSPEND_PREPARE: | ||
278 | return vmwdt_suspend(); | ||
279 | default: | ||
280 | return NOTIFY_DONE; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static struct notifier_block vmwdt_power_notifier = { | ||
285 | .notifier_call = vmwdt_power_event, | ||
286 | }; | ||
287 | |||
226 | static const struct file_operations vmwdt_fops = { | 288 | static const struct file_operations vmwdt_fops = { |
227 | .open = &vmwdt_open, | 289 | .open = &vmwdt_open, |
228 | .release = &vmwdt_close, | 290 | .release = &vmwdt_close, |
@@ -244,12 +306,21 @@ static int __init vmwdt_init(void) | |||
244 | ret = vmwdt_probe(); | 306 | ret = vmwdt_probe(); |
245 | if (ret) | 307 | if (ret) |
246 | return ret; | 308 | return ret; |
247 | return misc_register(&vmwdt_dev); | 309 | ret = register_pm_notifier(&vmwdt_power_notifier); |
310 | if (ret) | ||
311 | return ret; | ||
312 | ret = misc_register(&vmwdt_dev); | ||
313 | if (ret) { | ||
314 | unregister_pm_notifier(&vmwdt_power_notifier); | ||
315 | return ret; | ||
316 | } | ||
317 | return 0; | ||
248 | } | 318 | } |
249 | module_init(vmwdt_init); | 319 | module_init(vmwdt_init); |
250 | 320 | ||
251 | static void __exit vmwdt_exit(void) | 321 | static void __exit vmwdt_exit(void) |
252 | { | 322 | { |
253 | WARN_ON(misc_deregister(&vmwdt_dev) != 0); | 323 | unregister_pm_notifier(&vmwdt_power_notifier); |
324 | misc_deregister(&vmwdt_dev); | ||
254 | } | 325 | } |
255 | module_exit(vmwdt_exit); | 326 | module_exit(vmwdt_exit); |
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 22ce765d537e..a5a62f1f7747 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/ccwgroup.c | ||
3 | * bus driver for ccwgroup | 2 | * bus driver for ccwgroup |
4 | * | 3 | * |
5 | * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, | 4 | * Copyright IBM Corp. 2002, 2009 |
6 | * IBM Corporation | 5 | * |
7 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) | 6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) |
8 | * Cornelia Huck (cornelia.huck@de.ibm.com) | 7 | * Cornelia Huck (cornelia.huck@de.ibm.com) |
9 | */ | 8 | */ |
10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
11 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
@@ -501,6 +500,74 @@ static void ccwgroup_shutdown(struct device *dev) | |||
501 | gdrv->shutdown(gdev); | 500 | gdrv->shutdown(gdev); |
502 | } | 501 | } |
503 | 502 | ||
503 | static int ccwgroup_pm_prepare(struct device *dev) | ||
504 | { | ||
505 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
506 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
507 | |||
508 | /* Fail while device is being set online/offline. */ | ||
509 | if (atomic_read(&gdev->onoff)) | ||
510 | return -EAGAIN; | ||
511 | |||
512 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
513 | return 0; | ||
514 | |||
515 | return gdrv->prepare ? gdrv->prepare(gdev) : 0; | ||
516 | } | ||
517 | |||
518 | static void ccwgroup_pm_complete(struct device *dev) | ||
519 | { | ||
520 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
521 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); | ||
522 | |||
523 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
524 | return; | ||
525 | |||
526 | if (gdrv->complete) | ||
527 | gdrv->complete(gdev); | ||
528 | } | ||
529 | |||
530 | static int ccwgroup_pm_freeze(struct device *dev) | ||
531 | { | ||
532 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
533 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
534 | |||
535 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
536 | return 0; | ||
537 | |||
538 | return gdrv->freeze ? gdrv->freeze(gdev) : 0; | ||
539 | } | ||
540 | |||
541 | static int ccwgroup_pm_thaw(struct device *dev) | ||
542 | { | ||
543 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
544 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
545 | |||
546 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
547 | return 0; | ||
548 | |||
549 | return gdrv->thaw ? gdrv->thaw(gdev) : 0; | ||
550 | } | ||
551 | |||
552 | static int ccwgroup_pm_restore(struct device *dev) | ||
553 | { | ||
554 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
555 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
556 | |||
557 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
558 | return 0; | ||
559 | |||
560 | return gdrv->restore ? gdrv->restore(gdev) : 0; | ||
561 | } | ||
562 | |||
563 | static struct dev_pm_ops ccwgroup_pm_ops = { | ||
564 | .prepare = ccwgroup_pm_prepare, | ||
565 | .complete = ccwgroup_pm_complete, | ||
566 | .freeze = ccwgroup_pm_freeze, | ||
567 | .thaw = ccwgroup_pm_thaw, | ||
568 | .restore = ccwgroup_pm_restore, | ||
569 | }; | ||
570 | |||
504 | static struct bus_type ccwgroup_bus_type = { | 571 | static struct bus_type ccwgroup_bus_type = { |
505 | .name = "ccwgroup", | 572 | .name = "ccwgroup", |
506 | .match = ccwgroup_bus_match, | 573 | .match = ccwgroup_bus_match, |
@@ -508,6 +575,7 @@ static struct bus_type ccwgroup_bus_type = { | |||
508 | .probe = ccwgroup_probe, | 575 | .probe = ccwgroup_probe, |
509 | .remove = ccwgroup_remove, | 576 | .remove = ccwgroup_remove, |
510 | .shutdown = ccwgroup_shutdown, | 577 | .shutdown = ccwgroup_shutdown, |
578 | .pm = &ccwgroup_pm_ops, | ||
511 | }; | 579 | }; |
512 | 580 | ||
513 | 581 | ||
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 883f16f96f22..1ecd3e567648 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -549,8 +549,7 @@ cleanup: | |||
549 | return ret; | 549 | return ret; |
550 | } | 550 | } |
551 | 551 | ||
552 | static int | 552 | int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) |
553 | __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) | ||
554 | { | 553 | { |
555 | struct { | 554 | struct { |
556 | struct chsc_header request; | 555 | struct chsc_header request; |
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index ba59bceace98..425e8f89a6c5 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -90,6 +90,7 @@ extern void chsc_free_sei_area(void); | |||
90 | extern int chsc_enable_facility(int); | 90 | extern int chsc_enable_facility(int); |
91 | struct channel_subsystem; | 91 | struct channel_subsystem; |
92 | extern int chsc_secm(struct channel_subsystem *, int); | 92 | extern int chsc_secm(struct channel_subsystem *, int); |
93 | int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page); | ||
93 | 94 | ||
94 | int chsc_chp_vary(struct chp_id chpid, int on); | 95 | int chsc_chp_vary(struct chp_id chpid, int on); |
95 | int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, | 96 | int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, |
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 93eca1731b81..cc5144b6f9d9 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for s390 chsc subchannels | 2 | * Driver for s390 chsc subchannels |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2008 | 4 | * Copyright IBM Corp. 2008, 2009 |
5 | * | ||
5 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | 6 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
6 | * | 7 | * |
7 | */ | 8 | */ |
@@ -112,6 +113,31 @@ static void chsc_subchannel_shutdown(struct subchannel *sch) | |||
112 | cio_disable_subchannel(sch); | 113 | cio_disable_subchannel(sch); |
113 | } | 114 | } |
114 | 115 | ||
116 | static int chsc_subchannel_prepare(struct subchannel *sch) | ||
117 | { | ||
118 | int cc; | ||
119 | struct schib schib; | ||
120 | /* | ||
121 | * Don't allow suspend while the subchannel is not idle | ||
122 | * since we don't have a way to clear the subchannel and | ||
123 | * cannot disable it with a request running. | ||
124 | */ | ||
125 | cc = stsch(sch->schid, &schib); | ||
126 | if (!cc && scsw_stctl(&schib.scsw)) | ||
127 | return -EAGAIN; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int chsc_subchannel_freeze(struct subchannel *sch) | ||
132 | { | ||
133 | return cio_disable_subchannel(sch); | ||
134 | } | ||
135 | |||
136 | static int chsc_subchannel_restore(struct subchannel *sch) | ||
137 | { | ||
138 | return cio_enable_subchannel(sch, (u32)(unsigned long)sch); | ||
139 | } | ||
140 | |||
115 | static struct css_device_id chsc_subchannel_ids[] = { | 141 | static struct css_device_id chsc_subchannel_ids[] = { |
116 | { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, }, | 142 | { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, }, |
117 | { /* end of list */ }, | 143 | { /* end of list */ }, |
@@ -125,6 +151,10 @@ static struct css_driver chsc_subchannel_driver = { | |||
125 | .probe = chsc_subchannel_probe, | 151 | .probe = chsc_subchannel_probe, |
126 | .remove = chsc_subchannel_remove, | 152 | .remove = chsc_subchannel_remove, |
127 | .shutdown = chsc_subchannel_shutdown, | 153 | .shutdown = chsc_subchannel_shutdown, |
154 | .prepare = chsc_subchannel_prepare, | ||
155 | .freeze = chsc_subchannel_freeze, | ||
156 | .thaw = chsc_subchannel_restore, | ||
157 | .restore = chsc_subchannel_restore, | ||
128 | .name = "chsc_subchannel", | 158 | .name = "chsc_subchannel", |
129 | }; | 159 | }; |
130 | 160 | ||
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 2aebb9823044..5ec7789bd9d8 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #define KMSG_COMPONENT "cio" | 12 | #define KMSG_COMPONENT "cio" |
13 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 13 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
14 | 14 | ||
15 | #include <linux/ftrace.h> | ||
15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
16 | #include <linux/init.h> | 17 | #include <linux/init.h> |
17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
@@ -28,7 +29,7 @@ | |||
28 | #include <asm/chpid.h> | 29 | #include <asm/chpid.h> |
29 | #include <asm/airq.h> | 30 | #include <asm/airq.h> |
30 | #include <asm/isc.h> | 31 | #include <asm/isc.h> |
31 | #include <asm/cpu.h> | 32 | #include <asm/cputime.h> |
32 | #include <asm/fcx.h> | 33 | #include <asm/fcx.h> |
33 | #include <asm/nmi.h> | 34 | #include <asm/nmi.h> |
34 | #include <asm/crw.h> | 35 | #include <asm/crw.h> |
@@ -626,8 +627,7 @@ out: | |||
626 | * handlers). | 627 | * handlers). |
627 | * | 628 | * |
628 | */ | 629 | */ |
629 | void | 630 | void __irq_entry do_IRQ(struct pt_regs *regs) |
630 | do_IRQ (struct pt_regs *regs) | ||
631 | { | 631 | { |
632 | struct tpi_info *tpi_info; | 632 | struct tpi_info *tpi_info; |
633 | struct subchannel *sch; | 633 | struct subchannel *sch; |
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index dc98b2c63862..30f516111307 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c | |||
@@ -1204,6 +1204,11 @@ static ssize_t cmb_enable_store(struct device *dev, | |||
1204 | 1204 | ||
1205 | DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); | 1205 | DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); |
1206 | 1206 | ||
1207 | int ccw_set_cmf(struct ccw_device *cdev, int enable) | ||
1208 | { | ||
1209 | return cmbops->set(cdev, enable ? 2 : 0); | ||
1210 | } | ||
1211 | |||
1207 | /** | 1212 | /** |
1208 | * enable_cmf() - switch on the channel measurement for a specific device | 1213 | * enable_cmf() - switch on the channel measurement for a specific device |
1209 | * @cdev: The ccw device to be enabled | 1214 | * @cdev: The ccw device to be enabled |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0085d8901792..85d43c6bcb66 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/css.c | 2 | * driver for channel subsystem |
3 | * driver for channel subsystem | ||
4 | * | 3 | * |
5 | * Copyright IBM Corp. 2002,2008 | 4 | * Copyright IBM Corp. 2002, 2009 |
6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) | 5 | * |
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | 6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) |
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | ||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #define KMSG_COMPONENT "cio" | 10 | #define KMSG_COMPONENT "cio" |
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/list.h> | 18 | #include <linux/list.h> |
19 | #include <linux/reboot.h> | 19 | #include <linux/reboot.h> |
20 | #include <linux/suspend.h> | ||
20 | #include <asm/isc.h> | 21 | #include <asm/isc.h> |
21 | #include <asm/crw.h> | 22 | #include <asm/crw.h> |
22 | 23 | ||
@@ -780,6 +781,79 @@ static struct notifier_block css_reboot_notifier = { | |||
780 | }; | 781 | }; |
781 | 782 | ||
782 | /* | 783 | /* |
784 | * Since the css devices are neither on a bus nor have a class | ||
785 | * nor have a special device type, we cannot stop/restart channel | ||
786 | * path measurements via the normal suspend/resume callbacks, but have | ||
787 | * to use notifiers. | ||
788 | */ | ||
789 | static int css_power_event(struct notifier_block *this, unsigned long event, | ||
790 | void *ptr) | ||
791 | { | ||
792 | void *secm_area; | ||
793 | int ret, i; | ||
794 | |||
795 | switch (event) { | ||
796 | case PM_HIBERNATION_PREPARE: | ||
797 | case PM_SUSPEND_PREPARE: | ||
798 | ret = NOTIFY_DONE; | ||
799 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
800 | struct channel_subsystem *css; | ||
801 | |||
802 | css = channel_subsystems[i]; | ||
803 | mutex_lock(&css->mutex); | ||
804 | if (!css->cm_enabled) { | ||
805 | mutex_unlock(&css->mutex); | ||
806 | continue; | ||
807 | } | ||
808 | secm_area = (void *)get_zeroed_page(GFP_KERNEL | | ||
809 | GFP_DMA); | ||
810 | if (secm_area) { | ||
811 | if (__chsc_do_secm(css, 0, secm_area)) | ||
812 | ret = NOTIFY_BAD; | ||
813 | free_page((unsigned long)secm_area); | ||
814 | } else | ||
815 | ret = NOTIFY_BAD; | ||
816 | |||
817 | mutex_unlock(&css->mutex); | ||
818 | } | ||
819 | break; | ||
820 | case PM_POST_HIBERNATION: | ||
821 | case PM_POST_SUSPEND: | ||
822 | ret = NOTIFY_DONE; | ||
823 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
824 | struct channel_subsystem *css; | ||
825 | |||
826 | css = channel_subsystems[i]; | ||
827 | mutex_lock(&css->mutex); | ||
828 | if (!css->cm_enabled) { | ||
829 | mutex_unlock(&css->mutex); | ||
830 | continue; | ||
831 | } | ||
832 | secm_area = (void *)get_zeroed_page(GFP_KERNEL | | ||
833 | GFP_DMA); | ||
834 | if (secm_area) { | ||
835 | if (__chsc_do_secm(css, 1, secm_area)) | ||
836 | ret = NOTIFY_BAD; | ||
837 | free_page((unsigned long)secm_area); | ||
838 | } else | ||
839 | ret = NOTIFY_BAD; | ||
840 | |||
841 | mutex_unlock(&css->mutex); | ||
842 | } | ||
843 | /* search for subchannels, which appeared during hibernation */ | ||
844 | css_schedule_reprobe(); | ||
845 | break; | ||
846 | default: | ||
847 | ret = NOTIFY_DONE; | ||
848 | } | ||
849 | return ret; | ||
850 | |||
851 | } | ||
852 | static struct notifier_block css_power_notifier = { | ||
853 | .notifier_call = css_power_event, | ||
854 | }; | ||
855 | |||
856 | /* | ||
783 | * Now that the driver core is running, we can setup our channel subsystem. | 857 | * Now that the driver core is running, we can setup our channel subsystem. |
784 | * The struct subchannel's are created during probing (except for the | 858 | * The struct subchannel's are created during probing (except for the |
785 | * static console subchannel). | 859 | * static console subchannel). |
@@ -852,6 +926,11 @@ init_channel_subsystem (void) | |||
852 | ret = register_reboot_notifier(&css_reboot_notifier); | 926 | ret = register_reboot_notifier(&css_reboot_notifier); |
853 | if (ret) | 927 | if (ret) |
854 | goto out_unregister; | 928 | goto out_unregister; |
929 | ret = register_pm_notifier(&css_power_notifier); | ||
930 | if (ret) { | ||
931 | unregister_reboot_notifier(&css_reboot_notifier); | ||
932 | goto out_unregister; | ||
933 | } | ||
855 | css_init_done = 1; | 934 | css_init_done = 1; |
856 | 935 | ||
857 | /* Enable default isc for I/O subchannels. */ | 936 | /* Enable default isc for I/O subchannels. */ |
@@ -953,6 +1032,73 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
953 | return ret; | 1032 | return ret; |
954 | } | 1033 | } |
955 | 1034 | ||
1035 | static int css_pm_prepare(struct device *dev) | ||
1036 | { | ||
1037 | struct subchannel *sch = to_subchannel(dev); | ||
1038 | struct css_driver *drv; | ||
1039 | |||
1040 | if (mutex_is_locked(&sch->reg_mutex)) | ||
1041 | return -EAGAIN; | ||
1042 | if (!sch->dev.driver) | ||
1043 | return 0; | ||
1044 | drv = to_cssdriver(sch->dev.driver); | ||
1045 | /* Notify drivers that they may not register children. */ | ||
1046 | return drv->prepare ? drv->prepare(sch) : 0; | ||
1047 | } | ||
1048 | |||
1049 | static void css_pm_complete(struct device *dev) | ||
1050 | { | ||
1051 | struct subchannel *sch = to_subchannel(dev); | ||
1052 | struct css_driver *drv; | ||
1053 | |||
1054 | if (!sch->dev.driver) | ||
1055 | return; | ||
1056 | drv = to_cssdriver(sch->dev.driver); | ||
1057 | if (drv->complete) | ||
1058 | drv->complete(sch); | ||
1059 | } | ||
1060 | |||
1061 | static int css_pm_freeze(struct device *dev) | ||
1062 | { | ||
1063 | struct subchannel *sch = to_subchannel(dev); | ||
1064 | struct css_driver *drv; | ||
1065 | |||
1066 | if (!sch->dev.driver) | ||
1067 | return 0; | ||
1068 | drv = to_cssdriver(sch->dev.driver); | ||
1069 | return drv->freeze ? drv->freeze(sch) : 0; | ||
1070 | } | ||
1071 | |||
1072 | static int css_pm_thaw(struct device *dev) | ||
1073 | { | ||
1074 | struct subchannel *sch = to_subchannel(dev); | ||
1075 | struct css_driver *drv; | ||
1076 | |||
1077 | if (!sch->dev.driver) | ||
1078 | return 0; | ||
1079 | drv = to_cssdriver(sch->dev.driver); | ||
1080 | return drv->thaw ? drv->thaw(sch) : 0; | ||
1081 | } | ||
1082 | |||
1083 | static int css_pm_restore(struct device *dev) | ||
1084 | { | ||
1085 | struct subchannel *sch = to_subchannel(dev); | ||
1086 | struct css_driver *drv; | ||
1087 | |||
1088 | if (!sch->dev.driver) | ||
1089 | return 0; | ||
1090 | drv = to_cssdriver(sch->dev.driver); | ||
1091 | return drv->restore ? drv->restore(sch) : 0; | ||
1092 | } | ||
1093 | |||
1094 | static struct dev_pm_ops css_pm_ops = { | ||
1095 | .prepare = css_pm_prepare, | ||
1096 | .complete = css_pm_complete, | ||
1097 | .freeze = css_pm_freeze, | ||
1098 | .thaw = css_pm_thaw, | ||
1099 | .restore = css_pm_restore, | ||
1100 | }; | ||
1101 | |||
956 | struct bus_type css_bus_type = { | 1102 | struct bus_type css_bus_type = { |
957 | .name = "css", | 1103 | .name = "css", |
958 | .match = css_bus_match, | 1104 | .match = css_bus_match, |
@@ -960,6 +1106,7 @@ struct bus_type css_bus_type = { | |||
960 | .remove = css_remove, | 1106 | .remove = css_remove, |
961 | .shutdown = css_shutdown, | 1107 | .shutdown = css_shutdown, |
962 | .uevent = css_uevent, | 1108 | .uevent = css_uevent, |
1109 | .pm = &css_pm_ops, | ||
963 | }; | 1110 | }; |
964 | 1111 | ||
965 | /** | 1112 | /** |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 57ebf120f825..9763eeec7458 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -70,6 +70,11 @@ struct chp_link; | |||
70 | * @probe: function called on probe | 70 | * @probe: function called on probe |
71 | * @remove: function called on remove | 71 | * @remove: function called on remove |
72 | * @shutdown: called at device shutdown | 72 | * @shutdown: called at device shutdown |
73 | * @prepare: prepare for pm state transition | ||
74 | * @complete: undo work done in @prepare | ||
75 | * @freeze: callback for freezing during hibernation snapshotting | ||
76 | * @thaw: undo work done in @freeze | ||
77 | * @restore: callback for restoring after hibernation | ||
73 | * @name: name of the device driver | 78 | * @name: name of the device driver |
74 | */ | 79 | */ |
75 | struct css_driver { | 80 | struct css_driver { |
@@ -82,6 +87,11 @@ struct css_driver { | |||
82 | int (*probe)(struct subchannel *); | 87 | int (*probe)(struct subchannel *); |
83 | int (*remove)(struct subchannel *); | 88 | int (*remove)(struct subchannel *); |
84 | void (*shutdown)(struct subchannel *); | 89 | void (*shutdown)(struct subchannel *); |
90 | int (*prepare) (struct subchannel *); | ||
91 | void (*complete) (struct subchannel *); | ||
92 | int (*freeze)(struct subchannel *); | ||
93 | int (*thaw) (struct subchannel *); | ||
94 | int (*restore)(struct subchannel *); | ||
85 | const char *name; | 95 | const char *name; |
86 | }; | 96 | }; |
87 | 97 | ||
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 35441fa16be1..3c57c1a18bb8 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -138,6 +138,19 @@ static struct css_device_id io_subchannel_ids[] = { | |||
138 | }; | 138 | }; |
139 | MODULE_DEVICE_TABLE(css, io_subchannel_ids); | 139 | MODULE_DEVICE_TABLE(css, io_subchannel_ids); |
140 | 140 | ||
141 | static int io_subchannel_prepare(struct subchannel *sch) | ||
142 | { | ||
143 | struct ccw_device *cdev; | ||
144 | /* | ||
145 | * Don't allow suspend while a ccw device registration | ||
146 | * is still outstanding. | ||
147 | */ | ||
148 | cdev = sch_get_cdev(sch); | ||
149 | if (cdev && !device_is_registered(&cdev->dev)) | ||
150 | return -EAGAIN; | ||
151 | return 0; | ||
152 | } | ||
153 | |||
141 | static struct css_driver io_subchannel_driver = { | 154 | static struct css_driver io_subchannel_driver = { |
142 | .owner = THIS_MODULE, | 155 | .owner = THIS_MODULE, |
143 | .subchannel_type = io_subchannel_ids, | 156 | .subchannel_type = io_subchannel_ids, |
@@ -148,6 +161,7 @@ static struct css_driver io_subchannel_driver = { | |||
148 | .probe = io_subchannel_probe, | 161 | .probe = io_subchannel_probe, |
149 | .remove = io_subchannel_remove, | 162 | .remove = io_subchannel_remove, |
150 | .shutdown = io_subchannel_shutdown, | 163 | .shutdown = io_subchannel_shutdown, |
164 | .prepare = io_subchannel_prepare, | ||
151 | }; | 165 | }; |
152 | 166 | ||
153 | struct workqueue_struct *ccw_device_work; | 167 | struct workqueue_struct *ccw_device_work; |
@@ -1775,6 +1789,15 @@ ccw_device_probe_console(void) | |||
1775 | return &console_cdev; | 1789 | return &console_cdev; |
1776 | } | 1790 | } |
1777 | 1791 | ||
1792 | static int ccw_device_pm_restore(struct device *dev); | ||
1793 | |||
1794 | int ccw_device_force_console(void) | ||
1795 | { | ||
1796 | if (!console_cdev_in_use) | ||
1797 | return -ENODEV; | ||
1798 | return ccw_device_pm_restore(&console_cdev.dev); | ||
1799 | } | ||
1800 | EXPORT_SYMBOL_GPL(ccw_device_force_console); | ||
1778 | 1801 | ||
1779 | const char *cio_get_console_cdev_name(struct subchannel *sch) | 1802 | const char *cio_get_console_cdev_name(struct subchannel *sch) |
1780 | { | 1803 | { |
@@ -1895,6 +1918,242 @@ static void ccw_device_shutdown(struct device *dev) | |||
1895 | disable_cmf(cdev); | 1918 | disable_cmf(cdev); |
1896 | } | 1919 | } |
1897 | 1920 | ||
1921 | static int ccw_device_pm_prepare(struct device *dev) | ||
1922 | { | ||
1923 | struct ccw_device *cdev = to_ccwdev(dev); | ||
1924 | |||
1925 | if (work_pending(&cdev->private->kick_work)) | ||
1926 | return -EAGAIN; | ||
1927 | /* Fail while device is being set online/offline. */ | ||
1928 | if (atomic_read(&cdev->private->onoff)) | ||
1929 | return -EAGAIN; | ||
1930 | |||
1931 | if (cdev->online && cdev->drv && cdev->drv->prepare) | ||
1932 | return cdev->drv->prepare(cdev); | ||
1933 | |||
1934 | return 0; | ||
1935 | } | ||
1936 | |||
1937 | static void ccw_device_pm_complete(struct device *dev) | ||
1938 | { | ||
1939 | struct ccw_device *cdev = to_ccwdev(dev); | ||
1940 | |||
1941 | if (cdev->online && cdev->drv && cdev->drv->complete) | ||
1942 | cdev->drv->complete(cdev); | ||
1943 | } | ||
1944 | |||
1945 | static int ccw_device_pm_freeze(struct device *dev) | ||
1946 | { | ||
1947 | struct ccw_device *cdev = to_ccwdev(dev); | ||
1948 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
1949 | int ret, cm_enabled; | ||
1950 | |||
1951 | /* Fail suspend while device is in transistional state. */ | ||
1952 | if (!dev_fsm_final_state(cdev)) | ||
1953 | return -EAGAIN; | ||
1954 | if (!cdev->online) | ||
1955 | return 0; | ||
1956 | if (cdev->drv && cdev->drv->freeze) { | ||
1957 | ret = cdev->drv->freeze(cdev); | ||
1958 | if (ret) | ||
1959 | return ret; | ||
1960 | } | ||
1961 | |||
1962 | spin_lock_irq(sch->lock); | ||
1963 | cm_enabled = cdev->private->cmb != NULL; | ||
1964 | spin_unlock_irq(sch->lock); | ||
1965 | if (cm_enabled) { | ||
1966 | /* Don't have the css write on memory. */ | ||
1967 | ret = ccw_set_cmf(cdev, 0); | ||
1968 | if (ret) | ||
1969 | return ret; | ||
1970 | } | ||
1971 | /* From here on, disallow device driver I/O. */ | ||
1972 | spin_lock_irq(sch->lock); | ||
1973 | ret = cio_disable_subchannel(sch); | ||
1974 | spin_unlock_irq(sch->lock); | ||
1975 | |||
1976 | return ret; | ||
1977 | } | ||
1978 | |||
1979 | static int ccw_device_pm_thaw(struct device *dev) | ||
1980 | { | ||
1981 | struct ccw_device *cdev = to_ccwdev(dev); | ||
1982 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
1983 | int ret, cm_enabled; | ||
1984 | |||
1985 | if (!cdev->online) | ||
1986 | return 0; | ||
1987 | |||
1988 | spin_lock_irq(sch->lock); | ||
1989 | /* Allow device driver I/O again. */ | ||
1990 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); | ||
1991 | cm_enabled = cdev->private->cmb != NULL; | ||
1992 | spin_unlock_irq(sch->lock); | ||
1993 | if (ret) | ||
1994 | return ret; | ||
1995 | |||
1996 | if (cm_enabled) { | ||
1997 | ret = ccw_set_cmf(cdev, 1); | ||
1998 | if (ret) | ||
1999 | return ret; | ||
2000 | } | ||
2001 | |||
2002 | if (cdev->drv && cdev->drv->thaw) | ||
2003 | ret = cdev->drv->thaw(cdev); | ||
2004 | |||
2005 | return ret; | ||
2006 | } | ||
2007 | |||
2008 | static void __ccw_device_pm_restore(struct ccw_device *cdev) | ||
2009 | { | ||
2010 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
2011 | int ret; | ||
2012 | |||
2013 | if (cio_is_console(sch->schid)) | ||
2014 | goto out; | ||
2015 | /* | ||
2016 | * While we were sleeping, devices may have gone or become | ||
2017 | * available again. Kick re-detection. | ||
2018 | */ | ||
2019 | spin_lock_irq(sch->lock); | ||
2020 | cdev->private->flags.resuming = 1; | ||
2021 | ret = ccw_device_recognition(cdev); | ||
2022 | spin_unlock_irq(sch->lock); | ||
2023 | if (ret) { | ||
2024 | CIO_MSG_EVENT(0, "Couldn't start recognition for device " | ||
2025 | "%s (ret=%d)\n", dev_name(&cdev->dev), ret); | ||
2026 | spin_lock_irq(sch->lock); | ||
2027 | cdev->private->state = DEV_STATE_DISCONNECTED; | ||
2028 | spin_unlock_irq(sch->lock); | ||
2029 | /* notify driver after the resume cb */ | ||
2030 | goto out; | ||
2031 | } | ||
2032 | wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) || | ||
2033 | cdev->private->state == DEV_STATE_DISCONNECTED); | ||
2034 | |||
2035 | out: | ||
2036 | cdev->private->flags.resuming = 0; | ||
2037 | } | ||
2038 | |||
2039 | static int resume_handle_boxed(struct ccw_device *cdev) | ||
2040 | { | ||
2041 | cdev->private->state = DEV_STATE_BOXED; | ||
2042 | if (ccw_device_notify(cdev, CIO_BOXED)) | ||
2043 | return 0; | ||
2044 | ccw_device_schedule_sch_unregister(cdev); | ||
2045 | return -ENODEV; | ||
2046 | } | ||
2047 | |||
2048 | static int resume_handle_disc(struct ccw_device *cdev) | ||
2049 | { | ||
2050 | cdev->private->state = DEV_STATE_DISCONNECTED; | ||
2051 | if (ccw_device_notify(cdev, CIO_GONE)) | ||
2052 | return 0; | ||
2053 | ccw_device_schedule_sch_unregister(cdev); | ||
2054 | return -ENODEV; | ||
2055 | } | ||
2056 | |||
2057 | static int ccw_device_pm_restore(struct device *dev) | ||
2058 | { | ||
2059 | struct ccw_device *cdev = to_ccwdev(dev); | ||
2060 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
2061 | int ret = 0, cm_enabled; | ||
2062 | |||
2063 | __ccw_device_pm_restore(cdev); | ||
2064 | spin_lock_irq(sch->lock); | ||
2065 | if (cio_is_console(sch->schid)) { | ||
2066 | cio_enable_subchannel(sch, (u32)(addr_t)sch); | ||
2067 | spin_unlock_irq(sch->lock); | ||
2068 | goto out_restore; | ||
2069 | } | ||
2070 | cdev->private->flags.donotify = 0; | ||
2071 | /* check recognition results */ | ||
2072 | switch (cdev->private->state) { | ||
2073 | case DEV_STATE_OFFLINE: | ||
2074 | break; | ||
2075 | case DEV_STATE_BOXED: | ||
2076 | ret = resume_handle_boxed(cdev); | ||
2077 | spin_unlock_irq(sch->lock); | ||
2078 | if (ret) | ||
2079 | goto out; | ||
2080 | goto out_restore; | ||
2081 | case DEV_STATE_DISCONNECTED: | ||
2082 | goto out_disc_unlock; | ||
2083 | default: | ||
2084 | goto out_unreg_unlock; | ||
2085 | } | ||
2086 | /* check if the device id has changed */ | ||
2087 | if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { | ||
2088 | CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from " | ||
2089 | "%04x to %04x)\n", dev_name(&sch->dev), | ||
2090 | cdev->private->dev_id.devno, | ||
2091 | sch->schib.pmcw.dev); | ||
2092 | goto out_unreg_unlock; | ||
2093 | } | ||
2094 | /* check if the device type has changed */ | ||
2095 | if (!ccw_device_test_sense_data(cdev)) { | ||
2096 | ccw_device_update_sense_data(cdev); | ||
2097 | PREPARE_WORK(&cdev->private->kick_work, | ||
2098 | ccw_device_do_unbind_bind); | ||
2099 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
2100 | ret = -ENODEV; | ||
2101 | goto out_unlock; | ||
2102 | } | ||
2103 | if (!cdev->online) { | ||
2104 | ret = 0; | ||
2105 | goto out_unlock; | ||
2106 | } | ||
2107 | ret = ccw_device_online(cdev); | ||
2108 | if (ret) | ||
2109 | goto out_disc_unlock; | ||
2110 | |||
2111 | cm_enabled = cdev->private->cmb != NULL; | ||
2112 | spin_unlock_irq(sch->lock); | ||
2113 | |||
2114 | wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); | ||
2115 | if (cdev->private->state != DEV_STATE_ONLINE) { | ||
2116 | spin_lock_irq(sch->lock); | ||
2117 | goto out_disc_unlock; | ||
2118 | } | ||
2119 | if (cm_enabled) { | ||
2120 | ret = ccw_set_cmf(cdev, 1); | ||
2121 | if (ret) { | ||
2122 | CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed " | ||
2123 | "(rc=%d)\n", dev_name(&cdev->dev), ret); | ||
2124 | ret = 0; | ||
2125 | } | ||
2126 | } | ||
2127 | |||
2128 | out_restore: | ||
2129 | if (cdev->online && cdev->drv && cdev->drv->restore) | ||
2130 | ret = cdev->drv->restore(cdev); | ||
2131 | out: | ||
2132 | return ret; | ||
2133 | |||
2134 | out_disc_unlock: | ||
2135 | ret = resume_handle_disc(cdev); | ||
2136 | spin_unlock_irq(sch->lock); | ||
2137 | if (ret) | ||
2138 | return ret; | ||
2139 | goto out_restore; | ||
2140 | |||
2141 | out_unreg_unlock: | ||
2142 | ccw_device_schedule_sch_unregister(cdev); | ||
2143 | ret = -ENODEV; | ||
2144 | out_unlock: | ||
2145 | spin_unlock_irq(sch->lock); | ||
2146 | return ret; | ||
2147 | } | ||
2148 | |||
2149 | static struct dev_pm_ops ccw_pm_ops = { | ||
2150 | .prepare = ccw_device_pm_prepare, | ||
2151 | .complete = ccw_device_pm_complete, | ||
2152 | .freeze = ccw_device_pm_freeze, | ||
2153 | .thaw = ccw_device_pm_thaw, | ||
2154 | .restore = ccw_device_pm_restore, | ||
2155 | }; | ||
2156 | |||
1898 | struct bus_type ccw_bus_type = { | 2157 | struct bus_type ccw_bus_type = { |
1899 | .name = "ccw", | 2158 | .name = "ccw", |
1900 | .match = ccw_bus_match, | 2159 | .match = ccw_bus_match, |
@@ -1902,6 +2161,7 @@ struct bus_type ccw_bus_type = { | |||
1902 | .probe = ccw_device_probe, | 2161 | .probe = ccw_device_probe, |
1903 | .remove = ccw_device_remove, | 2162 | .remove = ccw_device_remove, |
1904 | .shutdown = ccw_device_shutdown, | 2163 | .shutdown = ccw_device_shutdown, |
2164 | .pm = &ccw_pm_ops, | ||
1905 | }; | 2165 | }; |
1906 | 2166 | ||
1907 | /** | 2167 | /** |
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index f1cbbd94ad4e..e3975107a578 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -87,6 +87,8 @@ int ccw_device_is_orphan(struct ccw_device *); | |||
87 | int ccw_device_recognition(struct ccw_device *); | 87 | int ccw_device_recognition(struct ccw_device *); |
88 | int ccw_device_online(struct ccw_device *); | 88 | int ccw_device_online(struct ccw_device *); |
89 | int ccw_device_offline(struct ccw_device *); | 89 | int ccw_device_offline(struct ccw_device *); |
90 | void ccw_device_update_sense_data(struct ccw_device *); | ||
91 | int ccw_device_test_sense_data(struct ccw_device *); | ||
90 | void ccw_device_schedule_sch_unregister(struct ccw_device *); | 92 | void ccw_device_schedule_sch_unregister(struct ccw_device *); |
91 | int ccw_purge_blacklisted(void); | 93 | int ccw_purge_blacklisted(void); |
92 | 94 | ||
@@ -133,5 +135,6 @@ extern struct bus_type ccw_bus_type; | |||
133 | void retry_set_schib(struct ccw_device *cdev); | 135 | void retry_set_schib(struct ccw_device *cdev); |
134 | void cmf_retry_copy_block(struct ccw_device *); | 136 | void cmf_retry_copy_block(struct ccw_device *); |
135 | int cmf_reenable(struct ccw_device *); | 137 | int cmf_reenable(struct ccw_device *); |
138 | int ccw_set_cmf(struct ccw_device *cdev, int enable); | ||
136 | extern struct device_attribute dev_attr_cmb_enable; | 139 | extern struct device_attribute dev_attr_cmb_enable; |
137 | #endif | 140 | #endif |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index e46049261561..3db88c52d287 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -177,29 +177,21 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) | |||
177 | panic("Can't stop i/o on subchannel.\n"); | 177 | panic("Can't stop i/o on subchannel.\n"); |
178 | } | 178 | } |
179 | 179 | ||
180 | static int | 180 | void ccw_device_update_sense_data(struct ccw_device *cdev) |
181 | ccw_device_handle_oper(struct ccw_device *cdev) | ||
182 | { | 181 | { |
183 | struct subchannel *sch; | 182 | memset(&cdev->id, 0, sizeof(cdev->id)); |
183 | cdev->id.cu_type = cdev->private->senseid.cu_type; | ||
184 | cdev->id.cu_model = cdev->private->senseid.cu_model; | ||
185 | cdev->id.dev_type = cdev->private->senseid.dev_type; | ||
186 | cdev->id.dev_model = cdev->private->senseid.dev_model; | ||
187 | } | ||
184 | 188 | ||
185 | sch = to_subchannel(cdev->dev.parent); | 189 | int ccw_device_test_sense_data(struct ccw_device *cdev) |
186 | cdev->private->flags.recog_done = 1; | 190 | { |
187 | /* | 191 | return cdev->id.cu_type == cdev->private->senseid.cu_type && |
188 | * Check if cu type and device type still match. If | 192 | cdev->id.cu_model == cdev->private->senseid.cu_model && |
189 | * not, it is certainly another device and we have to | 193 | cdev->id.dev_type == cdev->private->senseid.dev_type && |
190 | * de- and re-register. | 194 | cdev->id.dev_model == cdev->private->senseid.dev_model; |
191 | */ | ||
192 | if (cdev->id.cu_type != cdev->private->senseid.cu_type || | ||
193 | cdev->id.cu_model != cdev->private->senseid.cu_model || | ||
194 | cdev->id.dev_type != cdev->private->senseid.dev_type || | ||
195 | cdev->id.dev_model != cdev->private->senseid.dev_model) { | ||
196 | PREPARE_WORK(&cdev->private->kick_work, | ||
197 | ccw_device_do_unbind_bind); | ||
198 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
199 | return 0; | ||
200 | } | ||
201 | cdev->private->flags.donotify = 1; | ||
202 | return 1; | ||
203 | } | 195 | } |
204 | 196 | ||
205 | /* | 197 | /* |
@@ -233,7 +225,7 @@ static void | |||
233 | ccw_device_recog_done(struct ccw_device *cdev, int state) | 225 | ccw_device_recog_done(struct ccw_device *cdev, int state) |
234 | { | 226 | { |
235 | struct subchannel *sch; | 227 | struct subchannel *sch; |
236 | int notify, old_lpm, same_dev; | 228 | int old_lpm; |
237 | 229 | ||
238 | sch = to_subchannel(cdev->dev.parent); | 230 | sch = to_subchannel(cdev->dev.parent); |
239 | 231 | ||
@@ -263,8 +255,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
263 | wake_up(&cdev->private->wait_q); | 255 | wake_up(&cdev->private->wait_q); |
264 | return; | 256 | return; |
265 | } | 257 | } |
266 | notify = 0; | 258 | if (cdev->private->flags.resuming) { |
267 | same_dev = 0; /* Keep the compiler quiet... */ | 259 | cdev->private->state = state; |
260 | cdev->private->flags.recog_done = 1; | ||
261 | wake_up(&cdev->private->wait_q); | ||
262 | return; | ||
263 | } | ||
268 | switch (state) { | 264 | switch (state) { |
269 | case DEV_STATE_NOT_OPER: | 265 | case DEV_STATE_NOT_OPER: |
270 | CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " | 266 | CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " |
@@ -273,34 +269,31 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
273 | sch->schid.ssid, sch->schid.sch_no); | 269 | sch->schid.ssid, sch->schid.sch_no); |
274 | break; | 270 | break; |
275 | case DEV_STATE_OFFLINE: | 271 | case DEV_STATE_OFFLINE: |
276 | if (cdev->online) { | 272 | if (!cdev->online) { |
277 | same_dev = ccw_device_handle_oper(cdev); | 273 | ccw_device_update_sense_data(cdev); |
278 | notify = 1; | 274 | /* Issue device info message. */ |
275 | CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " | ||
276 | "CU Type/Mod = %04X/%02X, Dev Type/Mod " | ||
277 | "= %04X/%02X\n", | ||
278 | cdev->private->dev_id.ssid, | ||
279 | cdev->private->dev_id.devno, | ||
280 | cdev->id.cu_type, cdev->id.cu_model, | ||
281 | cdev->id.dev_type, cdev->id.dev_model); | ||
282 | break; | ||
279 | } | 283 | } |
280 | /* fill out sense information */ | 284 | cdev->private->state = DEV_STATE_OFFLINE; |
281 | memset(&cdev->id, 0, sizeof(cdev->id)); | 285 | cdev->private->flags.recog_done = 1; |
282 | cdev->id.cu_type = cdev->private->senseid.cu_type; | 286 | if (ccw_device_test_sense_data(cdev)) { |
283 | cdev->id.cu_model = cdev->private->senseid.cu_model; | 287 | cdev->private->flags.donotify = 1; |
284 | cdev->id.dev_type = cdev->private->senseid.dev_type; | 288 | ccw_device_online(cdev); |
285 | cdev->id.dev_model = cdev->private->senseid.dev_model; | 289 | wake_up(&cdev->private->wait_q); |
286 | if (notify) { | 290 | } else { |
287 | cdev->private->state = DEV_STATE_OFFLINE; | 291 | ccw_device_update_sense_data(cdev); |
288 | if (same_dev) { | 292 | PREPARE_WORK(&cdev->private->kick_work, |
289 | /* Get device online again. */ | 293 | ccw_device_do_unbind_bind); |
290 | ccw_device_online(cdev); | 294 | queue_work(ccw_device_work, &cdev->private->kick_work); |
291 | wake_up(&cdev->private->wait_q); | ||
292 | } | ||
293 | return; | ||
294 | } | 295 | } |
295 | /* Issue device info message. */ | 296 | return; |
296 | CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " | ||
297 | "CU Type/Mod = %04X/%02X, Dev Type/Mod = " | ||
298 | "%04X/%02X\n", | ||
299 | cdev->private->dev_id.ssid, | ||
300 | cdev->private->dev_id.devno, | ||
301 | cdev->id.cu_type, cdev->id.cu_model, | ||
302 | cdev->id.dev_type, cdev->id.dev_model); | ||
303 | break; | ||
304 | case DEV_STATE_BOXED: | 297 | case DEV_STATE_BOXED: |
305 | CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " | 298 | CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " |
306 | " subchannel 0.%x.%04x\n", | 299 | " subchannel 0.%x.%04x\n", |
@@ -502,9 +495,6 @@ ccw_device_recognition(struct ccw_device *cdev) | |||
502 | struct subchannel *sch; | 495 | struct subchannel *sch; |
503 | int ret; | 496 | int ret; |
504 | 497 | ||
505 | if ((cdev->private->state != DEV_STATE_NOT_OPER) && | ||
506 | (cdev->private->state != DEV_STATE_BOXED)) | ||
507 | return -EINVAL; | ||
508 | sch = to_subchannel(cdev->dev.parent); | 498 | sch = to_subchannel(cdev->dev.parent); |
509 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); | 499 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); |
510 | if (ret != 0) | 500 | if (ret != 0) |
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 151754d54745..2d0efee8a290 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c | |||
@@ -1,10 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/device_ops.c | 2 | * Copyright IBM Corp. 2002, 2009 |
3 | * | 3 | * |
4 | * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, | 4 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
5 | * IBM Corporation | 5 | * Cornelia Huck (cornelia.huck@de.ibm.com) |
6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | ||
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | ||
8 | */ | 6 | */ |
9 | #include <linux/module.h> | 7 | #include <linux/module.h> |
10 | #include <linux/init.h> | 8 | #include <linux/init.h> |
@@ -114,16 +112,17 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) | |||
114 | struct subchannel *sch; | 112 | struct subchannel *sch; |
115 | int ret; | 113 | int ret; |
116 | 114 | ||
117 | if (!cdev) | 115 | if (!cdev || !cdev->dev.parent) |
118 | return -ENODEV; | 116 | return -ENODEV; |
117 | sch = to_subchannel(cdev->dev.parent); | ||
118 | if (!sch->schib.pmcw.ena) | ||
119 | return -EINVAL; | ||
119 | if (cdev->private->state == DEV_STATE_NOT_OPER) | 120 | if (cdev->private->state == DEV_STATE_NOT_OPER) |
120 | return -ENODEV; | 121 | return -ENODEV; |
121 | if (cdev->private->state != DEV_STATE_ONLINE && | 122 | if (cdev->private->state != DEV_STATE_ONLINE && |
122 | cdev->private->state != DEV_STATE_W4SENSE) | 123 | cdev->private->state != DEV_STATE_W4SENSE) |
123 | return -EINVAL; | 124 | return -EINVAL; |
124 | sch = to_subchannel(cdev->dev.parent); | 125 | |
125 | if (!sch) | ||
126 | return -ENODEV; | ||
127 | ret = cio_clear(sch); | 126 | ret = cio_clear(sch); |
128 | if (ret == 0) | 127 | if (ret == 0) |
129 | cdev->private->intparm = intparm; | 128 | cdev->private->intparm = intparm; |
@@ -161,11 +160,11 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, | |||
161 | struct subchannel *sch; | 160 | struct subchannel *sch; |
162 | int ret; | 161 | int ret; |
163 | 162 | ||
164 | if (!cdev) | 163 | if (!cdev || !cdev->dev.parent) |
165 | return -ENODEV; | 164 | return -ENODEV; |
166 | sch = to_subchannel(cdev->dev.parent); | 165 | sch = to_subchannel(cdev->dev.parent); |
167 | if (!sch) | 166 | if (!sch->schib.pmcw.ena) |
168 | return -ENODEV; | 167 | return -EINVAL; |
169 | if (cdev->private->state == DEV_STATE_NOT_OPER) | 168 | if (cdev->private->state == DEV_STATE_NOT_OPER) |
170 | return -ENODEV; | 169 | return -ENODEV; |
171 | if (cdev->private->state == DEV_STATE_VERIFY || | 170 | if (cdev->private->state == DEV_STATE_VERIFY || |
@@ -339,16 +338,17 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) | |||
339 | struct subchannel *sch; | 338 | struct subchannel *sch; |
340 | int ret; | 339 | int ret; |
341 | 340 | ||
342 | if (!cdev) | 341 | if (!cdev || !cdev->dev.parent) |
343 | return -ENODEV; | 342 | return -ENODEV; |
343 | sch = to_subchannel(cdev->dev.parent); | ||
344 | if (!sch->schib.pmcw.ena) | ||
345 | return -EINVAL; | ||
344 | if (cdev->private->state == DEV_STATE_NOT_OPER) | 346 | if (cdev->private->state == DEV_STATE_NOT_OPER) |
345 | return -ENODEV; | 347 | return -ENODEV; |
346 | if (cdev->private->state != DEV_STATE_ONLINE && | 348 | if (cdev->private->state != DEV_STATE_ONLINE && |
347 | cdev->private->state != DEV_STATE_W4SENSE) | 349 | cdev->private->state != DEV_STATE_W4SENSE) |
348 | return -EINVAL; | 350 | return -EINVAL; |
349 | sch = to_subchannel(cdev->dev.parent); | 351 | |
350 | if (!sch) | ||
351 | return -ENODEV; | ||
352 | ret = cio_halt(sch); | 352 | ret = cio_halt(sch); |
353 | if (ret == 0) | 353 | if (ret == 0) |
354 | cdev->private->intparm = intparm; | 354 | cdev->private->intparm = intparm; |
@@ -372,11 +372,11 @@ int ccw_device_resume(struct ccw_device *cdev) | |||
372 | { | 372 | { |
373 | struct subchannel *sch; | 373 | struct subchannel *sch; |
374 | 374 | ||
375 | if (!cdev) | 375 | if (!cdev || !cdev->dev.parent) |
376 | return -ENODEV; | 376 | return -ENODEV; |
377 | sch = to_subchannel(cdev->dev.parent); | 377 | sch = to_subchannel(cdev->dev.parent); |
378 | if (!sch) | 378 | if (!sch->schib.pmcw.ena) |
379 | return -ENODEV; | 379 | return -EINVAL; |
380 | if (cdev->private->state == DEV_STATE_NOT_OPER) | 380 | if (cdev->private->state == DEV_STATE_NOT_OPER) |
381 | return -ENODEV; | 381 | return -ENODEV; |
382 | if (cdev->private->state != DEV_STATE_ONLINE || | 382 | if (cdev->private->state != DEV_STATE_ONLINE || |
@@ -471,11 +471,11 @@ __u8 ccw_device_get_path_mask(struct ccw_device *cdev) | |||
471 | { | 471 | { |
472 | struct subchannel *sch; | 472 | struct subchannel *sch; |
473 | 473 | ||
474 | sch = to_subchannel(cdev->dev.parent); | 474 | if (!cdev->dev.parent) |
475 | if (!sch) | ||
476 | return 0; | 475 | return 0; |
477 | else | 476 | |
478 | return sch->lpm; | 477 | sch = to_subchannel(cdev->dev.parent); |
478 | return sch->lpm; | ||
479 | } | 479 | } |
480 | 480 | ||
481 | /* | 481 | /* |
@@ -588,6 +588,8 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, | |||
588 | int rc; | 588 | int rc; |
589 | 589 | ||
590 | sch = to_subchannel(cdev->dev.parent); | 590 | sch = to_subchannel(cdev->dev.parent); |
591 | if (!sch->schib.pmcw.ena) | ||
592 | return -EINVAL; | ||
591 | if (cdev->private->state != DEV_STATE_ONLINE) | 593 | if (cdev->private->state != DEV_STATE_ONLINE) |
592 | return -EIO; | 594 | return -EIO; |
593 | /* Adjust requested path mask to excluded varied off paths. */ | 595 | /* Adjust requested path mask to excluded varied off paths. */ |
@@ -677,6 +679,8 @@ int ccw_device_tm_intrg(struct ccw_device *cdev) | |||
677 | { | 679 | { |
678 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | 680 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
679 | 681 | ||
682 | if (!sch->schib.pmcw.ena) | ||
683 | return -EINVAL; | ||
680 | if (cdev->private->state != DEV_STATE_ONLINE) | 684 | if (cdev->private->state != DEV_STATE_ONLINE) |
681 | return -EIO; | 685 | return -EIO; |
682 | if (!scsw_is_tm(&sch->schib.scsw) || | 686 | if (!scsw_is_tm(&sch->schib.scsw) || |
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index c4f3e7c9a854..0b8f381bd20e 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h | |||
@@ -107,6 +107,7 @@ struct ccw_device_private { | |||
107 | unsigned int recog_done:1; /* dev. recog. complete */ | 107 | unsigned int recog_done:1; /* dev. recog. complete */ |
108 | unsigned int fake_irb:1; /* deliver faked irb */ | 108 | unsigned int fake_irb:1; /* deliver faked irb */ |
109 | unsigned int intretry:1; /* retry internal operation */ | 109 | unsigned int intretry:1; /* retry internal operation */ |
110 | unsigned int resuming:1; /* recognition while resume */ | ||
110 | } __attribute__((packed)) flags; | 111 | } __attribute__((packed)) flags; |
111 | unsigned long intparm; /* user interruption parameter */ | 112 | unsigned long intparm; /* user interruption parameter */ |
112 | struct qdio_irq *qdio_data; | 113 | struct qdio_irq *qdio_data; |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index accd957454e7..d79cf5bf0e62 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -881,42 +881,26 @@ no_handler: | |||
881 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); | 881 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); |
882 | } | 882 | } |
883 | 883 | ||
884 | static int qdio_establish_check_errors(struct ccw_device *cdev, int cstat, | 884 | static void qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, |
885 | int dstat) | 885 | int dstat) |
886 | { | 886 | { |
887 | struct qdio_irq *irq_ptr = cdev->private->qdio_data; | 887 | struct qdio_irq *irq_ptr = cdev->private->qdio_data; |
888 | 888 | ||
889 | if (cstat || (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { | 889 | DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq"); |
890 | DBF_ERROR("EQ:ck con"); | ||
891 | goto error; | ||
892 | } | ||
893 | 890 | ||
894 | if (!(dstat & DEV_STAT_DEV_END)) { | 891 | if (cstat) |
895 | DBF_ERROR("EQ:no dev"); | ||
896 | goto error; | 892 | goto error; |
897 | } | 893 | if (dstat & ~(DEV_STAT_DEV_END | DEV_STAT_CHN_END)) |
898 | |||
899 | if (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) { | ||
900 | DBF_ERROR("EQ: bad io"); | ||
901 | goto error; | 894 | goto error; |
902 | } | 895 | if (!(dstat & DEV_STAT_DEV_END)) |
903 | return 0; | 896 | goto error; |
897 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED); | ||
898 | return; | ||
899 | |||
904 | error: | 900 | error: |
905 | DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no); | 901 | DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no); |
906 | DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); | 902 | DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); |
907 | |||
908 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); | 903 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); |
909 | return 1; | ||
910 | } | ||
911 | |||
912 | static void qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, | ||
913 | int dstat) | ||
914 | { | ||
915 | struct qdio_irq *irq_ptr = cdev->private->qdio_data; | ||
916 | |||
917 | DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq"); | ||
918 | if (!qdio_establish_check_errors(cdev, cstat, dstat)) | ||
919 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED); | ||
920 | } | 904 | } |
921 | 905 | ||
922 | /* qdio interrupt handler */ | 906 | /* qdio interrupt handler */ |
@@ -946,7 +930,6 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
946 | } | 930 | } |
947 | } | 931 | } |
948 | qdio_irq_check_sense(irq_ptr, irb); | 932 | qdio_irq_check_sense(irq_ptr, irb); |
949 | |||
950 | cstat = irb->scsw.cmd.cstat; | 933 | cstat = irb->scsw.cmd.cstat; |
951 | dstat = irb->scsw.cmd.dstat; | 934 | dstat = irb->scsw.cmd.dstat; |
952 | 935 | ||
@@ -954,22 +937,19 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
954 | case QDIO_IRQ_STATE_INACTIVE: | 937 | case QDIO_IRQ_STATE_INACTIVE: |
955 | qdio_establish_handle_irq(cdev, cstat, dstat); | 938 | qdio_establish_handle_irq(cdev, cstat, dstat); |
956 | break; | 939 | break; |
957 | |||
958 | case QDIO_IRQ_STATE_CLEANUP: | 940 | case QDIO_IRQ_STATE_CLEANUP: |
959 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); | 941 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); |
960 | break; | 942 | break; |
961 | |||
962 | case QDIO_IRQ_STATE_ESTABLISHED: | 943 | case QDIO_IRQ_STATE_ESTABLISHED: |
963 | case QDIO_IRQ_STATE_ACTIVE: | 944 | case QDIO_IRQ_STATE_ACTIVE: |
964 | if (cstat & SCHN_STAT_PCI) { | 945 | if (cstat & SCHN_STAT_PCI) { |
965 | qdio_int_handler_pci(irq_ptr); | 946 | qdio_int_handler_pci(irq_ptr); |
966 | return; | 947 | return; |
967 | } | 948 | } |
968 | if ((cstat & ~SCHN_STAT_PCI) || dstat) { | 949 | if (cstat || dstat) |
969 | qdio_handle_activate_check(cdev, intparm, cstat, | 950 | qdio_handle_activate_check(cdev, intparm, cstat, |
970 | dstat); | 951 | dstat); |
971 | break; | 952 | break; |
972 | } | ||
973 | default: | 953 | default: |
974 | WARN_ON(1); | 954 | WARN_ON(1); |
975 | } | 955 | } |
@@ -1514,7 +1494,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, | |||
1514 | 1494 | ||
1515 | if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) || | 1495 | if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) || |
1516 | (count > QDIO_MAX_BUFFERS_PER_Q) || | 1496 | (count > QDIO_MAX_BUFFERS_PER_Q) || |
1517 | (q_nr > QDIO_MAX_QUEUES_PER_IRQ)) | 1497 | (q_nr >= QDIO_MAX_QUEUES_PER_IRQ)) |
1518 | return -EINVAL; | 1498 | return -EINVAL; |
1519 | 1499 | ||
1520 | if (!count) | 1500 | if (!count) |
diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c index 136d0f0b1e93..eff943923c6f 100644 --- a/drivers/s390/cio/qdio_perf.c +++ b/drivers/s390/cio/qdio_perf.c | |||
@@ -25,18 +25,6 @@ struct qdio_perf_stats perf_stats; | |||
25 | static struct proc_dir_entry *qdio_perf_pde; | 25 | static struct proc_dir_entry *qdio_perf_pde; |
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | inline void qdio_perf_stat_inc(atomic_long_t *count) | ||
29 | { | ||
30 | if (qdio_performance_stats) | ||
31 | atomic_long_inc(count); | ||
32 | } | ||
33 | |||
34 | inline void qdio_perf_stat_dec(atomic_long_t *count) | ||
35 | { | ||
36 | if (qdio_performance_stats) | ||
37 | atomic_long_dec(count); | ||
38 | } | ||
39 | |||
40 | /* | 28 | /* |
41 | * procfs functions | 29 | * procfs functions |
42 | */ | 30 | */ |
diff --git a/drivers/s390/cio/qdio_perf.h b/drivers/s390/cio/qdio_perf.h index 7821ac4fa517..ff4504ce1e3c 100644 --- a/drivers/s390/cio/qdio_perf.h +++ b/drivers/s390/cio/qdio_perf.h | |||
@@ -9,7 +9,6 @@ | |||
9 | #define QDIO_PERF_H | 9 | #define QDIO_PERF_H |
10 | 10 | ||
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/device.h> | ||
13 | #include <asm/atomic.h> | 12 | #include <asm/atomic.h> |
14 | 13 | ||
15 | struct qdio_perf_stats { | 14 | struct qdio_perf_stats { |
@@ -50,10 +49,13 @@ struct qdio_perf_stats { | |||
50 | extern struct qdio_perf_stats perf_stats; | 49 | extern struct qdio_perf_stats perf_stats; |
51 | extern int qdio_performance_stats; | 50 | extern int qdio_performance_stats; |
52 | 51 | ||
52 | static inline void qdio_perf_stat_inc(atomic_long_t *count) | ||
53 | { | ||
54 | if (qdio_performance_stats) | ||
55 | atomic_long_inc(count); | ||
56 | } | ||
57 | |||
53 | int qdio_setup_perf_stats(void); | 58 | int qdio_setup_perf_stats(void); |
54 | void qdio_remove_perf_stats(void); | 59 | void qdio_remove_perf_stats(void); |
55 | 60 | ||
56 | extern void qdio_perf_stat_inc(atomic_long_t *count); | ||
57 | extern void qdio_perf_stat_dec(atomic_long_t *count); | ||
58 | |||
59 | #endif | 61 | #endif |
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index cbc8566fab70..e38e5d306faf 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -173,8 +173,9 @@ static void kvm_notify(struct virtqueue *vq) | |||
173 | * this device and sets it up. | 173 | * this device and sets it up. |
174 | */ | 174 | */ |
175 | static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, | 175 | static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, |
176 | unsigned index, | 176 | unsigned index, |
177 | void (*callback)(struct virtqueue *vq)) | 177 | void (*callback)(struct virtqueue *vq), |
178 | const char *name) | ||
178 | { | 179 | { |
179 | struct kvm_device *kdev = to_kvmdev(vdev); | 180 | struct kvm_device *kdev = to_kvmdev(vdev); |
180 | struct kvm_vqconfig *config; | 181 | struct kvm_vqconfig *config; |
@@ -194,7 +195,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, | |||
194 | 195 | ||
195 | vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN, | 196 | vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN, |
196 | vdev, (void *) config->address, | 197 | vdev, (void *) config->address, |
197 | kvm_notify, callback); | 198 | kvm_notify, callback, name); |
198 | if (!vq) { | 199 | if (!vq) { |
199 | err = -ENOMEM; | 200 | err = -ENOMEM; |
200 | goto unmap; | 201 | goto unmap; |
@@ -226,6 +227,38 @@ static void kvm_del_vq(struct virtqueue *vq) | |||
226 | KVM_S390_VIRTIO_RING_ALIGN)); | 227 | KVM_S390_VIRTIO_RING_ALIGN)); |
227 | } | 228 | } |
228 | 229 | ||
230 | static void kvm_del_vqs(struct virtio_device *vdev) | ||
231 | { | ||
232 | struct virtqueue *vq, *n; | ||
233 | |||
234 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) | ||
235 | kvm_del_vq(vq); | ||
236 | } | ||
237 | |||
238 | static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, | ||
239 | struct virtqueue *vqs[], | ||
240 | vq_callback_t *callbacks[], | ||
241 | const char *names[]) | ||
242 | { | ||
243 | struct kvm_device *kdev = to_kvmdev(vdev); | ||
244 | int i; | ||
245 | |||
246 | /* We must have this many virtqueues. */ | ||
247 | if (nvqs > kdev->desc->num_vq) | ||
248 | return -ENOENT; | ||
249 | |||
250 | for (i = 0; i < nvqs; ++i) { | ||
251 | vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]); | ||
252 | if (IS_ERR(vqs[i])) | ||
253 | goto error; | ||
254 | } | ||
255 | return 0; | ||
256 | |||
257 | error: | ||
258 | kvm_del_vqs(vdev); | ||
259 | return PTR_ERR(vqs[i]); | ||
260 | } | ||
261 | |||
229 | /* | 262 | /* |
230 | * The config ops structure as defined by virtio config | 263 | * The config ops structure as defined by virtio config |
231 | */ | 264 | */ |
@@ -237,8 +270,8 @@ static struct virtio_config_ops kvm_vq_configspace_ops = { | |||
237 | .get_status = kvm_get_status, | 270 | .get_status = kvm_get_status, |
238 | .set_status = kvm_set_status, | 271 | .set_status = kvm_set_status, |
239 | .reset = kvm_reset, | 272 | .reset = kvm_reset, |
240 | .find_vq = kvm_find_vq, | 273 | .find_vqs = kvm_find_vqs, |
241 | .del_vq = kvm_del_vq, | 274 | .del_vqs = kvm_del_vqs, |
242 | }; | 275 | }; |
243 | 276 | ||
244 | /* | 277 | /* |
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index a7745c82b4ae..cb909a5b5047 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig | |||
@@ -8,7 +8,7 @@ config LCS | |||
8 | Select this option if you want to use LCS networking on IBM System z. | 8 | Select this option if you want to use LCS networking on IBM System z. |
9 | This device driver supports Token Ring (IEEE 802.5), | 9 | This device driver supports Token Ring (IEEE 802.5), |
10 | FDDI (IEEE 802.7) and Ethernet. | 10 | FDDI (IEEE 802.7) and Ethernet. |
11 | To compile as a module, choose M. The module name is lcs.ko. | 11 | To compile as a module, choose M. The module name is lcs. |
12 | If you do not know what it is, it's safe to choose Y. | 12 | If you do not know what it is, it's safe to choose Y. |
13 | 13 | ||
14 | config CTCM | 14 | config CTCM |
@@ -21,7 +21,7 @@ config CTCM | |||
21 | It also supports virtual CTCs when running under VM. | 21 | It also supports virtual CTCs when running under VM. |
22 | This driver also supports channel-to-channel MPC SNA devices. | 22 | This driver also supports channel-to-channel MPC SNA devices. |
23 | MPC is an SNA protocol device used by Communication Server for Linux. | 23 | MPC is an SNA protocol device used by Communication Server for Linux. |
24 | To compile as a module, choose M. The module name is ctcm.ko. | 24 | To compile as a module, choose M. The module name is ctcm. |
25 | To compile into the kernel, choose Y. | 25 | To compile into the kernel, choose Y. |
26 | If you do not need any channel-to-channel connection, choose N. | 26 | If you do not need any channel-to-channel connection, choose N. |
27 | 27 | ||
@@ -34,7 +34,7 @@ config NETIUCV | |||
34 | link between VM guests. Using ifconfig a point-to-point connection | 34 | link between VM guests. Using ifconfig a point-to-point connection |
35 | can be established to the Linux on IBM System z | 35 | can be established to the Linux on IBM System z |
36 | running on the other VM guest. To compile as a module, choose M. | 36 | running on the other VM guest. To compile as a module, choose M. |
37 | The module name is netiucv.ko. If unsure, choose Y. | 37 | The module name is netiucv. If unsure, choose Y. |
38 | 38 | ||
39 | config SMSGIUCV | 39 | config SMSGIUCV |
40 | tristate "IUCV special message support (VM only)" | 40 | tristate "IUCV special message support (VM only)" |
@@ -50,7 +50,7 @@ config CLAW | |||
50 | This driver supports channel attached CLAW devices. | 50 | This driver supports channel attached CLAW devices. |
51 | CLAW is Common Link Access for Workstation. Common devices | 51 | CLAW is Common Link Access for Workstation. Common devices |
52 | that use CLAW are RS/6000s, Cisco Routers (CIP) and 3172 devices. | 52 | that use CLAW are RS/6000s, Cisco Routers (CIP) and 3172 devices. |
53 | To compile as a module, choose M. The module name is claw.ko. | 53 | To compile as a module, choose M. The module name is claw. |
54 | To compile into the kernel, choose Y. | 54 | To compile into the kernel, choose Y. |
55 | 55 | ||
56 | config QETH | 56 | config QETH |
@@ -65,14 +65,14 @@ config QETH | |||
65 | <http://www.ibm.com/developerworks/linux/linux390> | 65 | <http://www.ibm.com/developerworks/linux/linux390> |
66 | 66 | ||
67 | To compile this driver as a module, choose M. | 67 | To compile this driver as a module, choose M. |
68 | The module name is qeth.ko. | 68 | The module name is qeth. |
69 | 69 | ||
70 | config QETH_L2 | 70 | config QETH_L2 |
71 | tristate "qeth layer 2 device support" | 71 | tristate "qeth layer 2 device support" |
72 | depends on QETH | 72 | depends on QETH |
73 | help | 73 | help |
74 | Select this option to be able to run qeth devices in layer 2 mode. | 74 | Select this option to be able to run qeth devices in layer 2 mode. |
75 | To compile as a module, choose M. The module name is qeth_l2.ko. | 75 | To compile as a module, choose M. The module name is qeth_l2. |
76 | If unsure, choose y. | 76 | If unsure, choose y. |
77 | 77 | ||
78 | config QETH_L3 | 78 | config QETH_L3 |
@@ -80,7 +80,7 @@ config QETH_L3 | |||
80 | depends on QETH | 80 | depends on QETH |
81 | help | 81 | help |
82 | Select this option to be able to run qeth devices in layer 3 mode. | 82 | Select this option to be able to run qeth devices in layer 3 mode. |
83 | To compile as a module choose M. The module name is qeth_l3.ko. | 83 | To compile as a module choose M. The module name is qeth_l3. |
84 | If unsure, choose Y. | 84 | If unsure, choose Y. |
85 | 85 | ||
86 | config QETH_IPV6 | 86 | config QETH_IPV6 |
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 30a43cc79e76..f370f8d460a7 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
@@ -3,12 +3,12 @@ | |||
3 | * ESCON CLAW network driver | 3 | * ESCON CLAW network driver |
4 | * | 4 | * |
5 | * Linux for zSeries version | 5 | * Linux for zSeries version |
6 | * Copyright (C) 2002,2005 IBM Corporation | 6 | * Copyright IBM Corp. 2002, 2009 |
7 | * Author(s) Original code written by: | 7 | * Author(s) Original code written by: |
8 | * Kazuo Iimura (iimura@jp.ibm.com) | 8 | * Kazuo Iimura <iimura@jp.ibm.com> |
9 | * Rewritten by | 9 | * Rewritten by |
10 | * Andy Richter (richtera@us.ibm.com) | 10 | * Andy Richter <richtera@us.ibm.com> |
11 | * Marc Price (mwprice@us.ibm.com) | 11 | * Marc Price <mwprice@us.ibm.com> |
12 | * | 12 | * |
13 | * sysfs parms: | 13 | * sysfs parms: |
14 | * group x.x.rrrr,x.x.wwww | 14 | * group x.x.rrrr,x.x.wwww |
@@ -253,6 +253,11 @@ static void claw_free_wrt_buf(struct net_device *dev); | |||
253 | /* Functions for unpack reads */ | 253 | /* Functions for unpack reads */ |
254 | static void unpack_read(struct net_device *dev); | 254 | static void unpack_read(struct net_device *dev); |
255 | 255 | ||
256 | static int claw_pm_prepare(struct ccwgroup_device *gdev) | ||
257 | { | ||
258 | return -EPERM; | ||
259 | } | ||
260 | |||
256 | /* ccwgroup table */ | 261 | /* ccwgroup table */ |
257 | 262 | ||
258 | static struct ccwgroup_driver claw_group_driver = { | 263 | static struct ccwgroup_driver claw_group_driver = { |
@@ -264,6 +269,7 @@ static struct ccwgroup_driver claw_group_driver = { | |||
264 | .remove = claw_remove_device, | 269 | .remove = claw_remove_device, |
265 | .set_online = claw_new_device, | 270 | .set_online = claw_new_device, |
266 | .set_offline = claw_shutdown_device, | 271 | .set_offline = claw_shutdown_device, |
272 | .prepare = claw_pm_prepare, | ||
267 | }; | 273 | }; |
268 | 274 | ||
269 | /* | 275 | /* |
@@ -284,7 +290,7 @@ claw_probe(struct ccwgroup_device *cgdev) | |||
284 | if (!get_device(&cgdev->dev)) | 290 | if (!get_device(&cgdev->dev)) |
285 | return -ENODEV; | 291 | return -ENODEV; |
286 | privptr = kzalloc(sizeof(struct claw_privbk), GFP_KERNEL); | 292 | privptr = kzalloc(sizeof(struct claw_privbk), GFP_KERNEL); |
287 | cgdev->dev.driver_data = privptr; | 293 | dev_set_drvdata(&cgdev->dev, privptr); |
288 | if (privptr == NULL) { | 294 | if (privptr == NULL) { |
289 | probe_error(cgdev); | 295 | probe_error(cgdev); |
290 | put_device(&cgdev->dev); | 296 | put_device(&cgdev->dev); |
@@ -338,12 +344,6 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) | |||
338 | 344 | ||
339 | CLAW_DBF_TEXT(4, trace, "claw_tx"); | 345 | CLAW_DBF_TEXT(4, trace, "claw_tx"); |
340 | p_ch=&privptr->channel[WRITE]; | 346 | p_ch=&privptr->channel[WRITE]; |
341 | if (skb == NULL) { | ||
342 | privptr->stats.tx_dropped++; | ||
343 | privptr->stats.tx_errors++; | ||
344 | CLAW_DBF_TEXT_(2, trace, "clawtx%d", -EIO); | ||
345 | return -EIO; | ||
346 | } | ||
347 | spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags); | 347 | spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags); |
348 | rc=claw_hw_tx( skb, dev, 1 ); | 348 | rc=claw_hw_tx( skb, dev, 1 ); |
349 | spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); | 349 | spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); |
@@ -597,14 +597,14 @@ claw_irq_handler(struct ccw_device *cdev, | |||
597 | 597 | ||
598 | CLAW_DBF_TEXT(4, trace, "clawirq"); | 598 | CLAW_DBF_TEXT(4, trace, "clawirq"); |
599 | /* Bypass all 'unsolicited interrupts' */ | 599 | /* Bypass all 'unsolicited interrupts' */ |
600 | if (!cdev->dev.driver_data) { | 600 | privptr = dev_get_drvdata(&cdev->dev); |
601 | if (!privptr) { | ||
601 | dev_warn(&cdev->dev, "An uninitialized CLAW device received an" | 602 | dev_warn(&cdev->dev, "An uninitialized CLAW device received an" |
602 | " IRQ, c-%02x d-%02x\n", | 603 | " IRQ, c-%02x d-%02x\n", |
603 | irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); | 604 | irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); |
604 | CLAW_DBF_TEXT(2, trace, "badirq"); | 605 | CLAW_DBF_TEXT(2, trace, "badirq"); |
605 | return; | 606 | return; |
606 | } | 607 | } |
607 | privptr = (struct claw_privbk *)cdev->dev.driver_data; | ||
608 | 608 | ||
609 | /* Try to extract channel from driver data. */ | 609 | /* Try to extract channel from driver data. */ |
610 | if (privptr->channel[READ].cdev == cdev) | 610 | if (privptr->channel[READ].cdev == cdev) |
@@ -1986,9 +1986,9 @@ probe_error( struct ccwgroup_device *cgdev) | |||
1986 | struct claw_privbk *privptr; | 1986 | struct claw_privbk *privptr; |
1987 | 1987 | ||
1988 | CLAW_DBF_TEXT(4, trace, "proberr"); | 1988 | CLAW_DBF_TEXT(4, trace, "proberr"); |
1989 | privptr = (struct claw_privbk *) cgdev->dev.driver_data; | 1989 | privptr = dev_get_drvdata(&cgdev->dev); |
1990 | if (privptr != NULL) { | 1990 | if (privptr != NULL) { |
1991 | cgdev->dev.driver_data = NULL; | 1991 | dev_set_drvdata(&cgdev->dev, NULL); |
1992 | kfree(privptr->p_env); | 1992 | kfree(privptr->p_env); |
1993 | kfree(privptr->p_mtc_envelope); | 1993 | kfree(privptr->p_mtc_envelope); |
1994 | kfree(privptr); | 1994 | kfree(privptr); |
@@ -2917,9 +2917,9 @@ claw_new_device(struct ccwgroup_device *cgdev) | |||
2917 | dev_info(&cgdev->dev, "add for %s\n", | 2917 | dev_info(&cgdev->dev, "add for %s\n", |
2918 | dev_name(&cgdev->cdev[READ]->dev)); | 2918 | dev_name(&cgdev->cdev[READ]->dev)); |
2919 | CLAW_DBF_TEXT(2, setup, "new_dev"); | 2919 | CLAW_DBF_TEXT(2, setup, "new_dev"); |
2920 | privptr = cgdev->dev.driver_data; | 2920 | privptr = dev_get_drvdata(&cgdev->dev); |
2921 | cgdev->cdev[READ]->dev.driver_data = privptr; | 2921 | dev_set_drvdata(&cgdev->cdev[READ]->dev, privptr); |
2922 | cgdev->cdev[WRITE]->dev.driver_data = privptr; | 2922 | dev_set_drvdata(&cgdev->cdev[WRITE]->dev, privptr); |
2923 | if (!privptr) | 2923 | if (!privptr) |
2924 | return -ENODEV; | 2924 | return -ENODEV; |
2925 | p_env = privptr->p_env; | 2925 | p_env = privptr->p_env; |
@@ -2956,9 +2956,9 @@ claw_new_device(struct ccwgroup_device *cgdev) | |||
2956 | goto out; | 2956 | goto out; |
2957 | } | 2957 | } |
2958 | dev->ml_priv = privptr; | 2958 | dev->ml_priv = privptr; |
2959 | cgdev->dev.driver_data = privptr; | 2959 | dev_set_drvdata(&cgdev->dev, privptr); |
2960 | cgdev->cdev[READ]->dev.driver_data = privptr; | 2960 | dev_set_drvdata(&cgdev->cdev[READ]->dev, privptr); |
2961 | cgdev->cdev[WRITE]->dev.driver_data = privptr; | 2961 | dev_set_drvdata(&cgdev->cdev[WRITE]->dev, privptr); |
2962 | /* sysfs magic */ | 2962 | /* sysfs magic */ |
2963 | SET_NETDEV_DEV(dev, &cgdev->dev); | 2963 | SET_NETDEV_DEV(dev, &cgdev->dev); |
2964 | if (register_netdev(dev) != 0) { | 2964 | if (register_netdev(dev) != 0) { |
@@ -3024,7 +3024,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev) | |||
3024 | int ret; | 3024 | int ret; |
3025 | 3025 | ||
3026 | CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); | 3026 | CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); |
3027 | priv = cgdev->dev.driver_data; | 3027 | priv = dev_get_drvdata(&cgdev->dev); |
3028 | if (!priv) | 3028 | if (!priv) |
3029 | return -ENODEV; | 3029 | return -ENODEV; |
3030 | ndev = priv->channel[READ].ndev; | 3030 | ndev = priv->channel[READ].ndev; |
@@ -3054,7 +3054,7 @@ claw_remove_device(struct ccwgroup_device *cgdev) | |||
3054 | 3054 | ||
3055 | BUG_ON(!cgdev); | 3055 | BUG_ON(!cgdev); |
3056 | CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); | 3056 | CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); |
3057 | priv = cgdev->dev.driver_data; | 3057 | priv = dev_get_drvdata(&cgdev->dev); |
3058 | BUG_ON(!priv); | 3058 | BUG_ON(!priv); |
3059 | dev_info(&cgdev->dev, " will be removed.\n"); | 3059 | dev_info(&cgdev->dev, " will be removed.\n"); |
3060 | if (cgdev->state == CCWGROUP_ONLINE) | 3060 | if (cgdev->state == CCWGROUP_ONLINE) |
@@ -3069,9 +3069,9 @@ claw_remove_device(struct ccwgroup_device *cgdev) | |||
3069 | kfree(priv->channel[1].irb); | 3069 | kfree(priv->channel[1].irb); |
3070 | priv->channel[1].irb=NULL; | 3070 | priv->channel[1].irb=NULL; |
3071 | kfree(priv); | 3071 | kfree(priv); |
3072 | cgdev->dev.driver_data=NULL; | 3072 | dev_set_drvdata(&cgdev->dev, NULL); |
3073 | cgdev->cdev[READ]->dev.driver_data = NULL; | 3073 | dev_set_drvdata(&cgdev->cdev[READ]->dev, NULL); |
3074 | cgdev->cdev[WRITE]->dev.driver_data = NULL; | 3074 | dev_set_drvdata(&cgdev->cdev[WRITE]->dev, NULL); |
3075 | put_device(&cgdev->dev); | 3075 | put_device(&cgdev->dev); |
3076 | 3076 | ||
3077 | return; | 3077 | return; |
@@ -3087,7 +3087,7 @@ claw_hname_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
3087 | struct claw_privbk *priv; | 3087 | struct claw_privbk *priv; |
3088 | struct claw_env * p_env; | 3088 | struct claw_env * p_env; |
3089 | 3089 | ||
3090 | priv = dev->driver_data; | 3090 | priv = dev_get_drvdata(dev); |
3091 | if (!priv) | 3091 | if (!priv) |
3092 | return -ENODEV; | 3092 | return -ENODEV; |
3093 | p_env = priv->p_env; | 3093 | p_env = priv->p_env; |
@@ -3101,7 +3101,7 @@ claw_hname_write(struct device *dev, struct device_attribute *attr, | |||
3101 | struct claw_privbk *priv; | 3101 | struct claw_privbk *priv; |
3102 | struct claw_env * p_env; | 3102 | struct claw_env * p_env; |
3103 | 3103 | ||
3104 | priv = dev->driver_data; | 3104 | priv = dev_get_drvdata(dev); |
3105 | if (!priv) | 3105 | if (!priv) |
3106 | return -ENODEV; | 3106 | return -ENODEV; |
3107 | p_env = priv->p_env; | 3107 | p_env = priv->p_env; |
@@ -3125,7 +3125,7 @@ claw_adname_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
3125 | struct claw_privbk *priv; | 3125 | struct claw_privbk *priv; |
3126 | struct claw_env * p_env; | 3126 | struct claw_env * p_env; |
3127 | 3127 | ||
3128 | priv = dev->driver_data; | 3128 | priv = dev_get_drvdata(dev); |
3129 | if (!priv) | 3129 | if (!priv) |
3130 | return -ENODEV; | 3130 | return -ENODEV; |
3131 | p_env = priv->p_env; | 3131 | p_env = priv->p_env; |
@@ -3139,7 +3139,7 @@ claw_adname_write(struct device *dev, struct device_attribute *attr, | |||
3139 | struct claw_privbk *priv; | 3139 | struct claw_privbk *priv; |
3140 | struct claw_env * p_env; | 3140 | struct claw_env * p_env; |
3141 | 3141 | ||
3142 | priv = dev->driver_data; | 3142 | priv = dev_get_drvdata(dev); |
3143 | if (!priv) | 3143 | if (!priv) |
3144 | return -ENODEV; | 3144 | return -ENODEV; |
3145 | p_env = priv->p_env; | 3145 | p_env = priv->p_env; |
@@ -3163,7 +3163,7 @@ claw_apname_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
3163 | struct claw_privbk *priv; | 3163 | struct claw_privbk *priv; |
3164 | struct claw_env * p_env; | 3164 | struct claw_env * p_env; |
3165 | 3165 | ||
3166 | priv = dev->driver_data; | 3166 | priv = dev_get_drvdata(dev); |
3167 | if (!priv) | 3167 | if (!priv) |
3168 | return -ENODEV; | 3168 | return -ENODEV; |
3169 | p_env = priv->p_env; | 3169 | p_env = priv->p_env; |
@@ -3178,7 +3178,7 @@ claw_apname_write(struct device *dev, struct device_attribute *attr, | |||
3178 | struct claw_privbk *priv; | 3178 | struct claw_privbk *priv; |
3179 | struct claw_env * p_env; | 3179 | struct claw_env * p_env; |
3180 | 3180 | ||
3181 | priv = dev->driver_data; | 3181 | priv = dev_get_drvdata(dev); |
3182 | if (!priv) | 3182 | if (!priv) |
3183 | return -ENODEV; | 3183 | return -ENODEV; |
3184 | p_env = priv->p_env; | 3184 | p_env = priv->p_env; |
@@ -3212,7 +3212,7 @@ claw_wbuff_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
3212 | struct claw_privbk *priv; | 3212 | struct claw_privbk *priv; |
3213 | struct claw_env * p_env; | 3213 | struct claw_env * p_env; |
3214 | 3214 | ||
3215 | priv = dev->driver_data; | 3215 | priv = dev_get_drvdata(dev); |
3216 | if (!priv) | 3216 | if (!priv) |
3217 | return -ENODEV; | 3217 | return -ENODEV; |
3218 | p_env = priv->p_env; | 3218 | p_env = priv->p_env; |
@@ -3227,7 +3227,7 @@ claw_wbuff_write(struct device *dev, struct device_attribute *attr, | |||
3227 | struct claw_env * p_env; | 3227 | struct claw_env * p_env; |
3228 | int nnn,max; | 3228 | int nnn,max; |
3229 | 3229 | ||
3230 | priv = dev->driver_data; | 3230 | priv = dev_get_drvdata(dev); |
3231 | if (!priv) | 3231 | if (!priv) |
3232 | return -ENODEV; | 3232 | return -ENODEV; |
3233 | p_env = priv->p_env; | 3233 | p_env = priv->p_env; |
@@ -3254,7 +3254,7 @@ claw_rbuff_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
3254 | struct claw_privbk *priv; | 3254 | struct claw_privbk *priv; |
3255 | struct claw_env * p_env; | 3255 | struct claw_env * p_env; |
3256 | 3256 | ||
3257 | priv = dev->driver_data; | 3257 | priv = dev_get_drvdata(dev); |
3258 | if (!priv) | 3258 | if (!priv) |
3259 | return -ENODEV; | 3259 | return -ENODEV; |
3260 | p_env = priv->p_env; | 3260 | p_env = priv->p_env; |
@@ -3269,7 +3269,7 @@ claw_rbuff_write(struct device *dev, struct device_attribute *attr, | |||
3269 | struct claw_env *p_env; | 3269 | struct claw_env *p_env; |
3270 | int nnn,max; | 3270 | int nnn,max; |
3271 | 3271 | ||
3272 | priv = dev->driver_data; | 3272 | priv = dev_get_drvdata(dev); |
3273 | if (!priv) | 3273 | if (!priv) |
3274 | return -ENODEV; | 3274 | return -ENODEV; |
3275 | p_env = priv->p_env; | 3275 | p_env = priv->p_env; |
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 77f4033a0f4f..222e47394437 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/ctcm_main.c | 2 | * drivers/s390/net/ctcm_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2001, 2007 | 4 | * Copyright IBM Corp. 2001, 2009 |
5 | * Author(s): | 5 | * Author(s): |
6 | * Original CTC driver(s): | 6 | * Original CTC driver(s): |
7 | * Fritz Elfert (felfert@millenux.com) | 7 | * Fritz Elfert (felfert@millenux.com) |
@@ -1677,10 +1677,8 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) | |||
1677 | BUG_ON(priv == NULL); | 1677 | BUG_ON(priv == NULL); |
1678 | 1678 | ||
1679 | CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, | 1679 | CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, |
1680 | "removing device %s, r/w = %s/%s, proto : %d", | 1680 | "removing device %p, proto : %d", |
1681 | priv->channel[READ]->netdev->name, | 1681 | cgdev, priv->protocol); |
1682 | priv->channel[READ]->id, priv->channel[WRITE]->id, | ||
1683 | priv->protocol); | ||
1684 | 1682 | ||
1685 | if (cgdev->state == CCWGROUP_ONLINE) | 1683 | if (cgdev->state == CCWGROUP_ONLINE) |
1686 | ctcm_shutdown_device(cgdev); | 1684 | ctcm_shutdown_device(cgdev); |
@@ -1690,6 +1688,38 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) | |||
1690 | put_device(&cgdev->dev); | 1688 | put_device(&cgdev->dev); |
1691 | } | 1689 | } |
1692 | 1690 | ||
1691 | static int ctcm_pm_suspend(struct ccwgroup_device *gdev) | ||
1692 | { | ||
1693 | struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); | ||
1694 | |||
1695 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1696 | return 0; | ||
1697 | netif_device_detach(priv->channel[READ]->netdev); | ||
1698 | ctcm_close(priv->channel[READ]->netdev); | ||
1699 | ccw_device_set_offline(gdev->cdev[1]); | ||
1700 | ccw_device_set_offline(gdev->cdev[0]); | ||
1701 | return 0; | ||
1702 | } | ||
1703 | |||
1704 | static int ctcm_pm_resume(struct ccwgroup_device *gdev) | ||
1705 | { | ||
1706 | struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); | ||
1707 | int rc; | ||
1708 | |||
1709 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1710 | return 0; | ||
1711 | rc = ccw_device_set_online(gdev->cdev[1]); | ||
1712 | if (rc) | ||
1713 | goto err_out; | ||
1714 | rc = ccw_device_set_online(gdev->cdev[0]); | ||
1715 | if (rc) | ||
1716 | goto err_out; | ||
1717 | ctcm_open(priv->channel[READ]->netdev); | ||
1718 | err_out: | ||
1719 | netif_device_attach(priv->channel[READ]->netdev); | ||
1720 | return rc; | ||
1721 | } | ||
1722 | |||
1693 | static struct ccwgroup_driver ctcm_group_driver = { | 1723 | static struct ccwgroup_driver ctcm_group_driver = { |
1694 | .owner = THIS_MODULE, | 1724 | .owner = THIS_MODULE, |
1695 | .name = CTC_DRIVER_NAME, | 1725 | .name = CTC_DRIVER_NAME, |
@@ -1699,6 +1729,9 @@ static struct ccwgroup_driver ctcm_group_driver = { | |||
1699 | .remove = ctcm_remove_device, | 1729 | .remove = ctcm_remove_device, |
1700 | .set_online = ctcm_new_device, | 1730 | .set_online = ctcm_new_device, |
1701 | .set_offline = ctcm_shutdown_device, | 1731 | .set_offline = ctcm_shutdown_device, |
1732 | .freeze = ctcm_pm_suspend, | ||
1733 | .thaw = ctcm_pm_resume, | ||
1734 | .restore = ctcm_pm_resume, | ||
1702 | }; | 1735 | }; |
1703 | 1736 | ||
1704 | 1737 | ||
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index a45bc24eb5f9..8c675905448b 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -1,15 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/net/lcs.c | ||
3 | * | ||
4 | * Linux for S/390 Lan Channel Station Network Driver | 2 | * Linux for S/390 Lan Channel Station Network Driver |
5 | * | 3 | * |
6 | * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, | 4 | * Copyright IBM Corp. 1999, 2009 |
7 | * IBM Corporation | 5 | * Author(s): Original Code written by |
8 | * Author(s): Original Code written by | 6 | * DJ Barrow <djbarrow@de.ibm.com,barrow_dj@yahoo.com> |
9 | * DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) | 7 | * Rewritten by |
10 | * Rewritten by | 8 | * Frank Pavlic <fpavlic@de.ibm.com> and |
11 | * Frank Pavlic (fpavlic@de.ibm.com) and | 9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
12 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
13 | * | 10 | * |
14 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -1939,7 +1936,7 @@ lcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1939 | { | 1936 | { |
1940 | struct lcs_card *card; | 1937 | struct lcs_card *card; |
1941 | 1938 | ||
1942 | card = (struct lcs_card *)dev->driver_data; | 1939 | card = dev_get_drvdata(dev); |
1943 | 1940 | ||
1944 | if (!card) | 1941 | if (!card) |
1945 | return 0; | 1942 | return 0; |
@@ -1956,7 +1953,7 @@ lcs_portno_store (struct device *dev, struct device_attribute *attr, const char | |||
1956 | struct lcs_card *card; | 1953 | struct lcs_card *card; |
1957 | int value; | 1954 | int value; |
1958 | 1955 | ||
1959 | card = (struct lcs_card *)dev->driver_data; | 1956 | card = dev_get_drvdata(dev); |
1960 | 1957 | ||
1961 | if (!card) | 1958 | if (!card) |
1962 | return 0; | 1959 | return 0; |
@@ -1990,7 +1987,7 @@ lcs_timeout_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
1990 | { | 1987 | { |
1991 | struct lcs_card *card; | 1988 | struct lcs_card *card; |
1992 | 1989 | ||
1993 | card = (struct lcs_card *)dev->driver_data; | 1990 | card = dev_get_drvdata(dev); |
1994 | 1991 | ||
1995 | return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0; | 1992 | return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0; |
1996 | } | 1993 | } |
@@ -2001,7 +1998,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char | |||
2001 | struct lcs_card *card; | 1998 | struct lcs_card *card; |
2002 | int value; | 1999 | int value; |
2003 | 2000 | ||
2004 | card = (struct lcs_card *)dev->driver_data; | 2001 | card = dev_get_drvdata(dev); |
2005 | 2002 | ||
2006 | if (!card) | 2003 | if (!card) |
2007 | return 0; | 2004 | return 0; |
@@ -2020,7 +2017,7 @@ static ssize_t | |||
2020 | lcs_dev_recover_store(struct device *dev, struct device_attribute *attr, | 2017 | lcs_dev_recover_store(struct device *dev, struct device_attribute *attr, |
2021 | const char *buf, size_t count) | 2018 | const char *buf, size_t count) |
2022 | { | 2019 | { |
2023 | struct lcs_card *card = dev->driver_data; | 2020 | struct lcs_card *card = dev_get_drvdata(dev); |
2024 | char *tmp; | 2021 | char *tmp; |
2025 | int i; | 2022 | int i; |
2026 | 2023 | ||
@@ -2073,7 +2070,7 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev) | |||
2073 | put_device(&ccwgdev->dev); | 2070 | put_device(&ccwgdev->dev); |
2074 | return ret; | 2071 | return ret; |
2075 | } | 2072 | } |
2076 | ccwgdev->dev.driver_data = card; | 2073 | dev_set_drvdata(&ccwgdev->dev, card); |
2077 | ccwgdev->cdev[0]->handler = lcs_irq; | 2074 | ccwgdev->cdev[0]->handler = lcs_irq; |
2078 | ccwgdev->cdev[1]->handler = lcs_irq; | 2075 | ccwgdev->cdev[1]->handler = lcs_irq; |
2079 | card->gdev = ccwgdev; | 2076 | card->gdev = ccwgdev; |
@@ -2090,7 +2087,7 @@ lcs_register_netdev(struct ccwgroup_device *ccwgdev) | |||
2090 | struct lcs_card *card; | 2087 | struct lcs_card *card; |
2091 | 2088 | ||
2092 | LCS_DBF_TEXT(2, setup, "regnetdv"); | 2089 | LCS_DBF_TEXT(2, setup, "regnetdv"); |
2093 | card = (struct lcs_card *)ccwgdev->dev.driver_data; | 2090 | card = dev_get_drvdata(&ccwgdev->dev); |
2094 | if (card->dev->reg_state != NETREG_UNINITIALIZED) | 2091 | if (card->dev->reg_state != NETREG_UNINITIALIZED) |
2095 | return 0; | 2092 | return 0; |
2096 | SET_NETDEV_DEV(card->dev, &ccwgdev->dev); | 2093 | SET_NETDEV_DEV(card->dev, &ccwgdev->dev); |
@@ -2123,7 +2120,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) | |||
2123 | enum lcs_dev_states recover_state; | 2120 | enum lcs_dev_states recover_state; |
2124 | int rc; | 2121 | int rc; |
2125 | 2122 | ||
2126 | card = (struct lcs_card *)ccwgdev->dev.driver_data; | 2123 | card = dev_get_drvdata(&ccwgdev->dev); |
2127 | if (!card) | 2124 | if (!card) |
2128 | return -ENODEV; | 2125 | return -ENODEV; |
2129 | 2126 | ||
@@ -2229,7 +2226,7 @@ __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode) | |||
2229 | int ret; | 2226 | int ret; |
2230 | 2227 | ||
2231 | LCS_DBF_TEXT(3, setup, "shtdndev"); | 2228 | LCS_DBF_TEXT(3, setup, "shtdndev"); |
2232 | card = (struct lcs_card *)ccwgdev->dev.driver_data; | 2229 | card = dev_get_drvdata(&ccwgdev->dev); |
2233 | if (!card) | 2230 | if (!card) |
2234 | return -ENODEV; | 2231 | return -ENODEV; |
2235 | if (recovery_mode == 0) { | 2232 | if (recovery_mode == 0) { |
@@ -2296,7 +2293,7 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) | |||
2296 | { | 2293 | { |
2297 | struct lcs_card *card; | 2294 | struct lcs_card *card; |
2298 | 2295 | ||
2299 | card = (struct lcs_card *)ccwgdev->dev.driver_data; | 2296 | card = dev_get_drvdata(&ccwgdev->dev); |
2300 | if (!card) | 2297 | if (!card) |
2301 | return; | 2298 | return; |
2302 | 2299 | ||
@@ -2313,6 +2310,60 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) | |||
2313 | put_device(&ccwgdev->dev); | 2310 | put_device(&ccwgdev->dev); |
2314 | } | 2311 | } |
2315 | 2312 | ||
2313 | static int lcs_pm_suspend(struct lcs_card *card) | ||
2314 | { | ||
2315 | if (card->dev) | ||
2316 | netif_device_detach(card->dev); | ||
2317 | lcs_set_allowed_threads(card, 0); | ||
2318 | lcs_wait_for_threads(card, 0xffffffff); | ||
2319 | if (card->state != DEV_STATE_DOWN) | ||
2320 | __lcs_shutdown_device(card->gdev, 1); | ||
2321 | return 0; | ||
2322 | } | ||
2323 | |||
2324 | static int lcs_pm_resume(struct lcs_card *card) | ||
2325 | { | ||
2326 | int rc = 0; | ||
2327 | |||
2328 | if (card->state == DEV_STATE_RECOVER) | ||
2329 | rc = lcs_new_device(card->gdev); | ||
2330 | if (card->dev) | ||
2331 | netif_device_attach(card->dev); | ||
2332 | if (rc) { | ||
2333 | dev_warn(&card->gdev->dev, "The lcs device driver " | ||
2334 | "failed to recover the device\n"); | ||
2335 | } | ||
2336 | return rc; | ||
2337 | } | ||
2338 | |||
2339 | static int lcs_prepare(struct ccwgroup_device *gdev) | ||
2340 | { | ||
2341 | return 0; | ||
2342 | } | ||
2343 | |||
2344 | static void lcs_complete(struct ccwgroup_device *gdev) | ||
2345 | { | ||
2346 | return; | ||
2347 | } | ||
2348 | |||
2349 | static int lcs_freeze(struct ccwgroup_device *gdev) | ||
2350 | { | ||
2351 | struct lcs_card *card = dev_get_drvdata(&gdev->dev); | ||
2352 | return lcs_pm_suspend(card); | ||
2353 | } | ||
2354 | |||
2355 | static int lcs_thaw(struct ccwgroup_device *gdev) | ||
2356 | { | ||
2357 | struct lcs_card *card = dev_get_drvdata(&gdev->dev); | ||
2358 | return lcs_pm_resume(card); | ||
2359 | } | ||
2360 | |||
2361 | static int lcs_restore(struct ccwgroup_device *gdev) | ||
2362 | { | ||
2363 | struct lcs_card *card = dev_get_drvdata(&gdev->dev); | ||
2364 | return lcs_pm_resume(card); | ||
2365 | } | ||
2366 | |||
2316 | /** | 2367 | /** |
2317 | * LCS ccwgroup driver registration | 2368 | * LCS ccwgroup driver registration |
2318 | */ | 2369 | */ |
@@ -2325,6 +2376,11 @@ static struct ccwgroup_driver lcs_group_driver = { | |||
2325 | .remove = lcs_remove_device, | 2376 | .remove = lcs_remove_device, |
2326 | .set_online = lcs_new_device, | 2377 | .set_online = lcs_new_device, |
2327 | .set_offline = lcs_shutdown_device, | 2378 | .set_offline = lcs_shutdown_device, |
2379 | .prepare = lcs_prepare, | ||
2380 | .complete = lcs_complete, | ||
2381 | .freeze = lcs_freeze, | ||
2382 | .thaw = lcs_thaw, | ||
2383 | .restore = lcs_restore, | ||
2328 | }; | 2384 | }; |
2329 | 2385 | ||
2330 | /** | 2386 | /** |
diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index d58fea52557d..6d668642af27 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h | |||
@@ -34,8 +34,8 @@ static inline int lcs_dbf_passes(debug_info_t *dbf_grp, int level) | |||
34 | * sysfs related stuff | 34 | * sysfs related stuff |
35 | */ | 35 | */ |
36 | #define CARD_FROM_DEV(cdev) \ | 36 | #define CARD_FROM_DEV(cdev) \ |
37 | (struct lcs_card *) \ | 37 | (struct lcs_card *) dev_get_drvdata( \ |
38 | ((struct ccwgroup_device *)cdev->dev.driver_data)->dev.driver_data; | 38 | &((struct ccwgroup_device *)dev_get_drvdata(&cdev->dev))->dev); |
39 | /** | 39 | /** |
40 | * CCW commands used in this driver | 40 | * CCW commands used in this driver |
41 | */ | 41 | */ |
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index be716e45f7ac..52574ce797b2 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
@@ -1,11 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV network driver | 2 | * IUCV network driver |
3 | * | 3 | * |
4 | * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2001, 2009 |
5 | * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | ||
6 | * | 5 | * |
7 | * Sysfs integration and all bugs therein by Cornelia Huck | 6 | * Author(s): |
8 | * (cornelia.huck@de.ibm.com) | 7 | * Original netiucv driver: |
8 | * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | ||
9 | * Sysfs integration and all bugs therein: | ||
10 | * Cornelia Huck (cornelia.huck@de.ibm.com) | ||
11 | * PM functions: | ||
12 | * Ursula Braun (ursula.braun@de.ibm.com) | ||
9 | * | 13 | * |
10 | * Documentation used: | 14 | * Documentation used: |
11 | * the source of the original IUCV driver by: | 15 | * the source of the original IUCV driver by: |
@@ -149,10 +153,27 @@ PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | |||
149 | 153 | ||
150 | #define PRINTK_HEADER " iucv: " /* for debugging */ | 154 | #define PRINTK_HEADER " iucv: " /* for debugging */ |
151 | 155 | ||
156 | /* dummy device to make sure netiucv_pm functions are called */ | ||
157 | static struct device *netiucv_dev; | ||
158 | |||
159 | static int netiucv_pm_prepare(struct device *); | ||
160 | static void netiucv_pm_complete(struct device *); | ||
161 | static int netiucv_pm_freeze(struct device *); | ||
162 | static int netiucv_pm_restore_thaw(struct device *); | ||
163 | |||
164 | static struct dev_pm_ops netiucv_pm_ops = { | ||
165 | .prepare = netiucv_pm_prepare, | ||
166 | .complete = netiucv_pm_complete, | ||
167 | .freeze = netiucv_pm_freeze, | ||
168 | .thaw = netiucv_pm_restore_thaw, | ||
169 | .restore = netiucv_pm_restore_thaw, | ||
170 | }; | ||
171 | |||
152 | static struct device_driver netiucv_driver = { | 172 | static struct device_driver netiucv_driver = { |
153 | .owner = THIS_MODULE, | 173 | .owner = THIS_MODULE, |
154 | .name = "netiucv", | 174 | .name = "netiucv", |
155 | .bus = &iucv_bus, | 175 | .bus = &iucv_bus, |
176 | .pm = &netiucv_pm_ops, | ||
156 | }; | 177 | }; |
157 | 178 | ||
158 | static int netiucv_callback_connreq(struct iucv_path *, | 179 | static int netiucv_callback_connreq(struct iucv_path *, |
@@ -233,6 +254,7 @@ struct netiucv_priv { | |||
233 | fsm_instance *fsm; | 254 | fsm_instance *fsm; |
234 | struct iucv_connection *conn; | 255 | struct iucv_connection *conn; |
235 | struct device *dev; | 256 | struct device *dev; |
257 | int pm_state; | ||
236 | }; | 258 | }; |
237 | 259 | ||
238 | /** | 260 | /** |
@@ -1265,6 +1287,72 @@ static int netiucv_close(struct net_device *dev) | |||
1265 | return 0; | 1287 | return 0; |
1266 | } | 1288 | } |
1267 | 1289 | ||
1290 | static int netiucv_pm_prepare(struct device *dev) | ||
1291 | { | ||
1292 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1293 | return 0; | ||
1294 | } | ||
1295 | |||
1296 | static void netiucv_pm_complete(struct device *dev) | ||
1297 | { | ||
1298 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1299 | return; | ||
1300 | } | ||
1301 | |||
1302 | /** | ||
1303 | * netiucv_pm_freeze() - Freeze PM callback | ||
1304 | * @dev: netiucv device | ||
1305 | * | ||
1306 | * close open netiucv interfaces | ||
1307 | */ | ||
1308 | static int netiucv_pm_freeze(struct device *dev) | ||
1309 | { | ||
1310 | struct netiucv_priv *priv = dev->driver_data; | ||
1311 | struct net_device *ndev = NULL; | ||
1312 | int rc = 0; | ||
1313 | |||
1314 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1315 | if (priv && priv->conn) | ||
1316 | ndev = priv->conn->netdev; | ||
1317 | if (!ndev) | ||
1318 | goto out; | ||
1319 | netif_device_detach(ndev); | ||
1320 | priv->pm_state = fsm_getstate(priv->fsm); | ||
1321 | rc = netiucv_close(ndev); | ||
1322 | out: | ||
1323 | return rc; | ||
1324 | } | ||
1325 | |||
1326 | /** | ||
1327 | * netiucv_pm_restore_thaw() - Thaw and restore PM callback | ||
1328 | * @dev: netiucv device | ||
1329 | * | ||
1330 | * re-open netiucv interfaces closed during freeze | ||
1331 | */ | ||
1332 | static int netiucv_pm_restore_thaw(struct device *dev) | ||
1333 | { | ||
1334 | struct netiucv_priv *priv = dev->driver_data; | ||
1335 | struct net_device *ndev = NULL; | ||
1336 | int rc = 0; | ||
1337 | |||
1338 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1339 | if (priv && priv->conn) | ||
1340 | ndev = priv->conn->netdev; | ||
1341 | if (!ndev) | ||
1342 | goto out; | ||
1343 | switch (priv->pm_state) { | ||
1344 | case DEV_STATE_RUNNING: | ||
1345 | case DEV_STATE_STARTWAIT: | ||
1346 | rc = netiucv_open(ndev); | ||
1347 | break; | ||
1348 | default: | ||
1349 | break; | ||
1350 | } | ||
1351 | netif_device_attach(ndev); | ||
1352 | out: | ||
1353 | return rc; | ||
1354 | } | ||
1355 | |||
1268 | /** | 1356 | /** |
1269 | * Start transmission of a packet. | 1357 | * Start transmission of a packet. |
1270 | * Called from generic network device layer. | 1358 | * Called from generic network device layer. |
@@ -1315,9 +1403,9 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) | |||
1315 | return NETDEV_TX_BUSY; | 1403 | return NETDEV_TX_BUSY; |
1316 | } | 1404 | } |
1317 | dev->trans_start = jiffies; | 1405 | dev->trans_start = jiffies; |
1318 | rc = netiucv_transmit_skb(privptr->conn, skb) != 0; | 1406 | rc = netiucv_transmit_skb(privptr->conn, skb); |
1319 | netiucv_clear_busy(dev); | 1407 | netiucv_clear_busy(dev); |
1320 | return rc; | 1408 | return rc ? NETDEV_TX_BUSY : NETDEV_TX_OK; |
1321 | } | 1409 | } |
1322 | 1410 | ||
1323 | /** | 1411 | /** |
@@ -1364,7 +1452,7 @@ static int netiucv_change_mtu(struct net_device * dev, int new_mtu) | |||
1364 | static ssize_t user_show(struct device *dev, struct device_attribute *attr, | 1452 | static ssize_t user_show(struct device *dev, struct device_attribute *attr, |
1365 | char *buf) | 1453 | char *buf) |
1366 | { | 1454 | { |
1367 | struct netiucv_priv *priv = dev->driver_data; | 1455 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1368 | 1456 | ||
1369 | IUCV_DBF_TEXT(trace, 5, __func__); | 1457 | IUCV_DBF_TEXT(trace, 5, __func__); |
1370 | return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); | 1458 | return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); |
@@ -1373,7 +1461,7 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr, | |||
1373 | static ssize_t user_write(struct device *dev, struct device_attribute *attr, | 1461 | static ssize_t user_write(struct device *dev, struct device_attribute *attr, |
1374 | const char *buf, size_t count) | 1462 | const char *buf, size_t count) |
1375 | { | 1463 | { |
1376 | struct netiucv_priv *priv = dev->driver_data; | 1464 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1377 | struct net_device *ndev = priv->conn->netdev; | 1465 | struct net_device *ndev = priv->conn->netdev; |
1378 | char *p; | 1466 | char *p; |
1379 | char *tmp; | 1467 | char *tmp; |
@@ -1430,7 +1518,8 @@ static DEVICE_ATTR(user, 0644, user_show, user_write); | |||
1430 | 1518 | ||
1431 | static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, | 1519 | static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, |
1432 | char *buf) | 1520 | char *buf) |
1433 | { struct netiucv_priv *priv = dev->driver_data; | 1521 | { |
1522 | struct netiucv_priv *priv = dev_get_drvdata(dev); | ||
1434 | 1523 | ||
1435 | IUCV_DBF_TEXT(trace, 5, __func__); | 1524 | IUCV_DBF_TEXT(trace, 5, __func__); |
1436 | return sprintf(buf, "%d\n", priv->conn->max_buffsize); | 1525 | return sprintf(buf, "%d\n", priv->conn->max_buffsize); |
@@ -1439,7 +1528,7 @@ static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, | |||
1439 | static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, | 1528 | static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, |
1440 | const char *buf, size_t count) | 1529 | const char *buf, size_t count) |
1441 | { | 1530 | { |
1442 | struct netiucv_priv *priv = dev->driver_data; | 1531 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1443 | struct net_device *ndev = priv->conn->netdev; | 1532 | struct net_device *ndev = priv->conn->netdev; |
1444 | char *e; | 1533 | char *e; |
1445 | int bs1; | 1534 | int bs1; |
@@ -1487,7 +1576,7 @@ static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); | |||
1487 | static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, | 1576 | static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, |
1488 | char *buf) | 1577 | char *buf) |
1489 | { | 1578 | { |
1490 | struct netiucv_priv *priv = dev->driver_data; | 1579 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1491 | 1580 | ||
1492 | IUCV_DBF_TEXT(trace, 5, __func__); | 1581 | IUCV_DBF_TEXT(trace, 5, __func__); |
1493 | return sprintf(buf, "%s\n", fsm_getstate_str(priv->fsm)); | 1582 | return sprintf(buf, "%s\n", fsm_getstate_str(priv->fsm)); |
@@ -1498,7 +1587,7 @@ static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); | |||
1498 | static ssize_t conn_fsm_show (struct device *dev, | 1587 | static ssize_t conn_fsm_show (struct device *dev, |
1499 | struct device_attribute *attr, char *buf) | 1588 | struct device_attribute *attr, char *buf) |
1500 | { | 1589 | { |
1501 | struct netiucv_priv *priv = dev->driver_data; | 1590 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1502 | 1591 | ||
1503 | IUCV_DBF_TEXT(trace, 5, __func__); | 1592 | IUCV_DBF_TEXT(trace, 5, __func__); |
1504 | return sprintf(buf, "%s\n", fsm_getstate_str(priv->conn->fsm)); | 1593 | return sprintf(buf, "%s\n", fsm_getstate_str(priv->conn->fsm)); |
@@ -1509,7 +1598,7 @@ static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); | |||
1509 | static ssize_t maxmulti_show (struct device *dev, | 1598 | static ssize_t maxmulti_show (struct device *dev, |
1510 | struct device_attribute *attr, char *buf) | 1599 | struct device_attribute *attr, char *buf) |
1511 | { | 1600 | { |
1512 | struct netiucv_priv *priv = dev->driver_data; | 1601 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1513 | 1602 | ||
1514 | IUCV_DBF_TEXT(trace, 5, __func__); | 1603 | IUCV_DBF_TEXT(trace, 5, __func__); |
1515 | return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); | 1604 | return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); |
@@ -1519,7 +1608,7 @@ static ssize_t maxmulti_write (struct device *dev, | |||
1519 | struct device_attribute *attr, | 1608 | struct device_attribute *attr, |
1520 | const char *buf, size_t count) | 1609 | const char *buf, size_t count) |
1521 | { | 1610 | { |
1522 | struct netiucv_priv *priv = dev->driver_data; | 1611 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1523 | 1612 | ||
1524 | IUCV_DBF_TEXT(trace, 4, __func__); | 1613 | IUCV_DBF_TEXT(trace, 4, __func__); |
1525 | priv->conn->prof.maxmulti = 0; | 1614 | priv->conn->prof.maxmulti = 0; |
@@ -1531,7 +1620,7 @@ static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); | |||
1531 | static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, | 1620 | static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, |
1532 | char *buf) | 1621 | char *buf) |
1533 | { | 1622 | { |
1534 | struct netiucv_priv *priv = dev->driver_data; | 1623 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1535 | 1624 | ||
1536 | IUCV_DBF_TEXT(trace, 5, __func__); | 1625 | IUCV_DBF_TEXT(trace, 5, __func__); |
1537 | return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); | 1626 | return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); |
@@ -1540,7 +1629,7 @@ static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, | |||
1540 | static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, | 1629 | static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, |
1541 | const char *buf, size_t count) | 1630 | const char *buf, size_t count) |
1542 | { | 1631 | { |
1543 | struct netiucv_priv *priv = dev->driver_data; | 1632 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1544 | 1633 | ||
1545 | IUCV_DBF_TEXT(trace, 4, __func__); | 1634 | IUCV_DBF_TEXT(trace, 4, __func__); |
1546 | priv->conn->prof.maxcqueue = 0; | 1635 | priv->conn->prof.maxcqueue = 0; |
@@ -1552,7 +1641,7 @@ static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); | |||
1552 | static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, | 1641 | static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, |
1553 | char *buf) | 1642 | char *buf) |
1554 | { | 1643 | { |
1555 | struct netiucv_priv *priv = dev->driver_data; | 1644 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1556 | 1645 | ||
1557 | IUCV_DBF_TEXT(trace, 5, __func__); | 1646 | IUCV_DBF_TEXT(trace, 5, __func__); |
1558 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); | 1647 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); |
@@ -1561,7 +1650,7 @@ static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, | |||
1561 | static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, | 1650 | static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, |
1562 | const char *buf, size_t count) | 1651 | const char *buf, size_t count) |
1563 | { | 1652 | { |
1564 | struct netiucv_priv *priv = dev->driver_data; | 1653 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1565 | 1654 | ||
1566 | IUCV_DBF_TEXT(trace, 4, __func__); | 1655 | IUCV_DBF_TEXT(trace, 4, __func__); |
1567 | priv->conn->prof.doios_single = 0; | 1656 | priv->conn->prof.doios_single = 0; |
@@ -1573,7 +1662,7 @@ static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); | |||
1573 | static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, | 1662 | static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, |
1574 | char *buf) | 1663 | char *buf) |
1575 | { | 1664 | { |
1576 | struct netiucv_priv *priv = dev->driver_data; | 1665 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1577 | 1666 | ||
1578 | IUCV_DBF_TEXT(trace, 5, __func__); | 1667 | IUCV_DBF_TEXT(trace, 5, __func__); |
1579 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); | 1668 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); |
@@ -1582,7 +1671,7 @@ static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, | |||
1582 | static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, | 1671 | static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, |
1583 | const char *buf, size_t count) | 1672 | const char *buf, size_t count) |
1584 | { | 1673 | { |
1585 | struct netiucv_priv *priv = dev->driver_data; | 1674 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1586 | 1675 | ||
1587 | IUCV_DBF_TEXT(trace, 5, __func__); | 1676 | IUCV_DBF_TEXT(trace, 5, __func__); |
1588 | priv->conn->prof.doios_multi = 0; | 1677 | priv->conn->prof.doios_multi = 0; |
@@ -1594,7 +1683,7 @@ static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); | |||
1594 | static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, | 1683 | static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, |
1595 | char *buf) | 1684 | char *buf) |
1596 | { | 1685 | { |
1597 | struct netiucv_priv *priv = dev->driver_data; | 1686 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1598 | 1687 | ||
1599 | IUCV_DBF_TEXT(trace, 5, __func__); | 1688 | IUCV_DBF_TEXT(trace, 5, __func__); |
1600 | return sprintf(buf, "%ld\n", priv->conn->prof.txlen); | 1689 | return sprintf(buf, "%ld\n", priv->conn->prof.txlen); |
@@ -1603,7 +1692,7 @@ static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, | |||
1603 | static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, | 1692 | static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, |
1604 | const char *buf, size_t count) | 1693 | const char *buf, size_t count) |
1605 | { | 1694 | { |
1606 | struct netiucv_priv *priv = dev->driver_data; | 1695 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1607 | 1696 | ||
1608 | IUCV_DBF_TEXT(trace, 4, __func__); | 1697 | IUCV_DBF_TEXT(trace, 4, __func__); |
1609 | priv->conn->prof.txlen = 0; | 1698 | priv->conn->prof.txlen = 0; |
@@ -1615,7 +1704,7 @@ static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); | |||
1615 | static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, | 1704 | static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, |
1616 | char *buf) | 1705 | char *buf) |
1617 | { | 1706 | { |
1618 | struct netiucv_priv *priv = dev->driver_data; | 1707 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1619 | 1708 | ||
1620 | IUCV_DBF_TEXT(trace, 5, __func__); | 1709 | IUCV_DBF_TEXT(trace, 5, __func__); |
1621 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); | 1710 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); |
@@ -1624,7 +1713,7 @@ static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, | |||
1624 | static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, | 1713 | static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, |
1625 | const char *buf, size_t count) | 1714 | const char *buf, size_t count) |
1626 | { | 1715 | { |
1627 | struct netiucv_priv *priv = dev->driver_data; | 1716 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1628 | 1717 | ||
1629 | IUCV_DBF_TEXT(trace, 4, __func__); | 1718 | IUCV_DBF_TEXT(trace, 4, __func__); |
1630 | priv->conn->prof.tx_time = 0; | 1719 | priv->conn->prof.tx_time = 0; |
@@ -1636,7 +1725,7 @@ static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); | |||
1636 | static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, | 1725 | static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, |
1637 | char *buf) | 1726 | char *buf) |
1638 | { | 1727 | { |
1639 | struct netiucv_priv *priv = dev->driver_data; | 1728 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1640 | 1729 | ||
1641 | IUCV_DBF_TEXT(trace, 5, __func__); | 1730 | IUCV_DBF_TEXT(trace, 5, __func__); |
1642 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); | 1731 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); |
@@ -1645,7 +1734,7 @@ static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, | |||
1645 | static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, | 1734 | static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, |
1646 | const char *buf, size_t count) | 1735 | const char *buf, size_t count) |
1647 | { | 1736 | { |
1648 | struct netiucv_priv *priv = dev->driver_data; | 1737 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1649 | 1738 | ||
1650 | IUCV_DBF_TEXT(trace, 4, __func__); | 1739 | IUCV_DBF_TEXT(trace, 4, __func__); |
1651 | priv->conn->prof.tx_pending = 0; | 1740 | priv->conn->prof.tx_pending = 0; |
@@ -1657,7 +1746,7 @@ static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); | |||
1657 | static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, | 1746 | static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, |
1658 | char *buf) | 1747 | char *buf) |
1659 | { | 1748 | { |
1660 | struct netiucv_priv *priv = dev->driver_data; | 1749 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1661 | 1750 | ||
1662 | IUCV_DBF_TEXT(trace, 5, __func__); | 1751 | IUCV_DBF_TEXT(trace, 5, __func__); |
1663 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); | 1752 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); |
@@ -1666,7 +1755,7 @@ static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, | |||
1666 | static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, | 1755 | static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, |
1667 | const char *buf, size_t count) | 1756 | const char *buf, size_t count) |
1668 | { | 1757 | { |
1669 | struct netiucv_priv *priv = dev->driver_data; | 1758 | struct netiucv_priv *priv = dev_get_drvdata(dev); |
1670 | 1759 | ||
1671 | IUCV_DBF_TEXT(trace, 4, __func__); | 1760 | IUCV_DBF_TEXT(trace, 4, __func__); |
1672 | priv->conn->prof.tx_max_pending = 0; | 1761 | priv->conn->prof.tx_max_pending = 0; |
@@ -1731,7 +1820,6 @@ static int netiucv_register_device(struct net_device *ndev) | |||
1731 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 1820 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); |
1732 | int ret; | 1821 | int ret; |
1733 | 1822 | ||
1734 | |||
1735 | IUCV_DBF_TEXT(trace, 3, __func__); | 1823 | IUCV_DBF_TEXT(trace, 3, __func__); |
1736 | 1824 | ||
1737 | if (dev) { | 1825 | if (dev) { |
@@ -1758,7 +1846,7 @@ static int netiucv_register_device(struct net_device *ndev) | |||
1758 | if (ret) | 1846 | if (ret) |
1759 | goto out_unreg; | 1847 | goto out_unreg; |
1760 | priv->dev = dev; | 1848 | priv->dev = dev; |
1761 | dev->driver_data = priv; | 1849 | dev_set_drvdata(dev, priv); |
1762 | return 0; | 1850 | return 0; |
1763 | 1851 | ||
1764 | out_unreg: | 1852 | out_unreg: |
@@ -2100,6 +2188,7 @@ static void __exit netiucv_exit(void) | |||
2100 | netiucv_unregister_device(dev); | 2188 | netiucv_unregister_device(dev); |
2101 | } | 2189 | } |
2102 | 2190 | ||
2191 | device_unregister(netiucv_dev); | ||
2103 | driver_unregister(&netiucv_driver); | 2192 | driver_unregister(&netiucv_driver); |
2104 | iucv_unregister(&netiucv_handler, 1); | 2193 | iucv_unregister(&netiucv_handler, 1); |
2105 | iucv_unregister_dbf_views(); | 2194 | iucv_unregister_dbf_views(); |
@@ -2125,10 +2214,25 @@ static int __init netiucv_init(void) | |||
2125 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); | 2214 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); |
2126 | goto out_iucv; | 2215 | goto out_iucv; |
2127 | } | 2216 | } |
2128 | 2217 | /* establish dummy device */ | |
2218 | netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
2219 | if (!netiucv_dev) { | ||
2220 | rc = -ENOMEM; | ||
2221 | goto out_driver; | ||
2222 | } | ||
2223 | dev_set_name(netiucv_dev, "netiucv"); | ||
2224 | netiucv_dev->bus = &iucv_bus; | ||
2225 | netiucv_dev->parent = iucv_root; | ||
2226 | netiucv_dev->release = (void (*)(struct device *))kfree; | ||
2227 | netiucv_dev->driver = &netiucv_driver; | ||
2228 | rc = device_register(netiucv_dev); | ||
2229 | if (rc) | ||
2230 | goto out_driver; | ||
2129 | netiucv_banner(); | 2231 | netiucv_banner(); |
2130 | return rc; | 2232 | return rc; |
2131 | 2233 | ||
2234 | out_driver: | ||
2235 | driver_unregister(&netiucv_driver); | ||
2132 | out_iucv: | 2236 | out_iucv: |
2133 | iucv_unregister(&netiucv_handler, 1); | 2237 | iucv_unregister(&netiucv_handler, 1); |
2134 | out_dbf: | 2238 | out_dbf: |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c827d69b5a91..d53621c4acbb 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/qeth_core_main.c | 2 | * drivers/s390/net/qeth_core_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | 5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
6 | * Frank Pavlic <fpavlic@de.ibm.com>, | 6 | * Frank Pavlic <fpavlic@de.ibm.com>, |
7 | * Thomas Spatzier <tspat@de.ibm.com>, | 7 | * Thomas Spatzier <tspat@de.ibm.com>, |
@@ -952,6 +952,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, | |||
952 | buf->buffer->element[i].addr = NULL; | 952 | buf->buffer->element[i].addr = NULL; |
953 | buf->buffer->element[i].flags = 0; | 953 | buf->buffer->element[i].flags = 0; |
954 | } | 954 | } |
955 | buf->buffer->element[15].flags = 0; | ||
955 | buf->next_element_to_fill = 0; | 956 | buf->next_element_to_fill = 0; |
956 | atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); | 957 | atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); |
957 | } | 958 | } |
@@ -1140,6 +1141,8 @@ static int qeth_setup_card(struct qeth_card *card) | |||
1140 | card->ipato.enabled = 0; | 1141 | card->ipato.enabled = 0; |
1141 | card->ipato.invert4 = 0; | 1142 | card->ipato.invert4 = 0; |
1142 | card->ipato.invert6 = 0; | 1143 | card->ipato.invert6 = 0; |
1144 | if (card->info.type == QETH_CARD_TYPE_IQD) | ||
1145 | card->options.checksum_type = NO_CHECKSUMMING; | ||
1143 | /* init QDIO stuff */ | 1146 | /* init QDIO stuff */ |
1144 | qeth_init_qdio_info(card); | 1147 | qeth_init_qdio_info(card); |
1145 | return 0; | 1148 | return 0; |
@@ -2934,8 +2937,8 @@ int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) | |||
2934 | if (card->info.type == QETH_CARD_TYPE_OSN) | 2937 | if (card->info.type == QETH_CARD_TYPE_OSN) |
2935 | return cast_type; | 2938 | return cast_type; |
2936 | 2939 | ||
2937 | if (skb->dst && skb->dst->neighbour) { | 2940 | if (skb_dst(skb) && skb_dst(skb)->neighbour) { |
2938 | cast_type = skb->dst->neighbour->type; | 2941 | cast_type = skb_dst(skb)->neighbour->type; |
2939 | if ((cast_type == RTN_BROADCAST) || | 2942 | if ((cast_type == RTN_BROADCAST) || |
2940 | (cast_type == RTN_MULTICAST) || | 2943 | (cast_type == RTN_MULTICAST) || |
2941 | (cast_type == RTN_ANYCAST)) | 2944 | (cast_type == RTN_ANYCAST)) |
@@ -4192,6 +4195,50 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev) | |||
4192 | card->discipline.ccwgdriver->shutdown(gdev); | 4195 | card->discipline.ccwgdriver->shutdown(gdev); |
4193 | } | 4196 | } |
4194 | 4197 | ||
4198 | static int qeth_core_prepare(struct ccwgroup_device *gdev) | ||
4199 | { | ||
4200 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4201 | if (card->discipline.ccwgdriver && | ||
4202 | card->discipline.ccwgdriver->prepare) | ||
4203 | return card->discipline.ccwgdriver->prepare(gdev); | ||
4204 | return 0; | ||
4205 | } | ||
4206 | |||
4207 | static void qeth_core_complete(struct ccwgroup_device *gdev) | ||
4208 | { | ||
4209 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4210 | if (card->discipline.ccwgdriver && | ||
4211 | card->discipline.ccwgdriver->complete) | ||
4212 | card->discipline.ccwgdriver->complete(gdev); | ||
4213 | } | ||
4214 | |||
4215 | static int qeth_core_freeze(struct ccwgroup_device *gdev) | ||
4216 | { | ||
4217 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4218 | if (card->discipline.ccwgdriver && | ||
4219 | card->discipline.ccwgdriver->freeze) | ||
4220 | return card->discipline.ccwgdriver->freeze(gdev); | ||
4221 | return 0; | ||
4222 | } | ||
4223 | |||
4224 | static int qeth_core_thaw(struct ccwgroup_device *gdev) | ||
4225 | { | ||
4226 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4227 | if (card->discipline.ccwgdriver && | ||
4228 | card->discipline.ccwgdriver->thaw) | ||
4229 | return card->discipline.ccwgdriver->thaw(gdev); | ||
4230 | return 0; | ||
4231 | } | ||
4232 | |||
4233 | static int qeth_core_restore(struct ccwgroup_device *gdev) | ||
4234 | { | ||
4235 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4236 | if (card->discipline.ccwgdriver && | ||
4237 | card->discipline.ccwgdriver->restore) | ||
4238 | return card->discipline.ccwgdriver->restore(gdev); | ||
4239 | return 0; | ||
4240 | } | ||
4241 | |||
4195 | static struct ccwgroup_driver qeth_core_ccwgroup_driver = { | 4242 | static struct ccwgroup_driver qeth_core_ccwgroup_driver = { |
4196 | .owner = THIS_MODULE, | 4243 | .owner = THIS_MODULE, |
4197 | .name = "qeth", | 4244 | .name = "qeth", |
@@ -4201,6 +4248,11 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = { | |||
4201 | .set_online = qeth_core_set_online, | 4248 | .set_online = qeth_core_set_online, |
4202 | .set_offline = qeth_core_set_offline, | 4249 | .set_offline = qeth_core_set_offline, |
4203 | .shutdown = qeth_core_shutdown, | 4250 | .shutdown = qeth_core_shutdown, |
4251 | .prepare = qeth_core_prepare, | ||
4252 | .complete = qeth_core_complete, | ||
4253 | .freeze = qeth_core_freeze, | ||
4254 | .thaw = qeth_core_thaw, | ||
4255 | .restore = qeth_core_restore, | ||
4204 | }; | 4256 | }; |
4205 | 4257 | ||
4206 | static ssize_t | 4258 | static ssize_t |
diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index 06f4de1f0507..ec24901c802c 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c | |||
@@ -181,6 +181,8 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = { | |||
181 | {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, | 181 | {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, |
182 | {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"}, | 182 | {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"}, |
183 | {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"}, | 183 | {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"}, |
184 | {IPA_RC_L2_MAC_NOT_AUTH_BY_HYP, "L2 mac not authorized by hypervisor"}, | ||
185 | {IPA_RC_L2_MAC_NOT_AUTH_BY_ADP, "L2 mac not authorized by adapter"}, | ||
184 | {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"}, | 186 | {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"}, |
185 | {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, | 187 | {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, |
186 | {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, | 188 | {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, |
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 18548822e37c..eecb2ee62e85 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h | |||
@@ -168,6 +168,8 @@ enum qeth_ipa_return_codes { | |||
168 | IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, | 168 | IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, |
169 | IPA_RC_L2_DUP_LAYER3_MAC = 0x200a, | 169 | IPA_RC_L2_DUP_LAYER3_MAC = 0x200a, |
170 | IPA_RC_L2_GMAC_NOT_FOUND = 0x200b, | 170 | IPA_RC_L2_GMAC_NOT_FOUND = 0x200b, |
171 | IPA_RC_L2_MAC_NOT_AUTH_BY_HYP = 0x200c, | ||
172 | IPA_RC_L2_MAC_NOT_AUTH_BY_ADP = 0x200d, | ||
171 | IPA_RC_L2_MAC_NOT_FOUND = 0x2010, | 173 | IPA_RC_L2_MAC_NOT_FOUND = 0x2010, |
172 | IPA_RC_L2_INVALID_VLAN_ID = 0x2015, | 174 | IPA_RC_L2_INVALID_VLAN_ID = 0x2015, |
173 | IPA_RC_L2_DUP_VLAN_ID = 0x2016, | 175 | IPA_RC_L2_DUP_VLAN_ID = 0x2016, |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 172031baedc1..691cecd03b83 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/qeth_l2_main.c | 2 | * drivers/s390/net/qeth_l2_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | 5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
6 | * Frank Pavlic <fpavlic@de.ibm.com>, | 6 | * Frank Pavlic <fpavlic@de.ibm.com>, |
7 | * Thomas Spatzier <tspat@de.ibm.com>, | 7 | * Thomas Spatzier <tspat@de.ibm.com>, |
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/mii.h> | 20 | #include <linux/mii.h> |
21 | #include <linux/ip.h> | 21 | #include <linux/ip.h> |
22 | #include <linux/list.h> | ||
22 | 23 | ||
23 | #include "qeth_core.h" | 24 | #include "qeth_core.h" |
24 | 25 | ||
@@ -130,7 +131,7 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card, | |||
130 | cmd = (struct qeth_ipa_cmd *) data; | 131 | cmd = (struct qeth_ipa_cmd *) data; |
131 | mac = &cmd->data.setdelmac.mac[0]; | 132 | mac = &cmd->data.setdelmac.mac[0]; |
132 | /* MAC already registered, needed in couple/uncouple case */ | 133 | /* MAC already registered, needed in couple/uncouple case */ |
133 | if (cmd->hdr.return_code == 0x2005) { | 134 | if (cmd->hdr.return_code == IPA_RC_L2_DUP_MAC) { |
134 | QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", | 135 | QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", |
135 | mac, QETH_CARD_IFNAME(card)); | 136 | mac, QETH_CARD_IFNAME(card)); |
136 | cmd->hdr.return_code = 0; | 137 | cmd->hdr.return_code = 0; |
@@ -502,6 +503,30 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, | |||
502 | if (cmd->hdr.return_code) { | 503 | if (cmd->hdr.return_code) { |
503 | QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code); | 504 | QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code); |
504 | card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; | 505 | card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; |
506 | switch (cmd->hdr.return_code) { | ||
507 | case IPA_RC_L2_DUP_MAC: | ||
508 | case IPA_RC_L2_DUP_LAYER3_MAC: | ||
509 | dev_warn(&card->gdev->dev, | ||
510 | "MAC address " | ||
511 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | ||
512 | "already exists\n", | ||
513 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
514 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
515 | card->dev->dev_addr[4], card->dev->dev_addr[5]); | ||
516 | break; | ||
517 | case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: | ||
518 | case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: | ||
519 | dev_warn(&card->gdev->dev, | ||
520 | "MAC address " | ||
521 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | ||
522 | "is not authorized\n", | ||
523 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
524 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
525 | card->dev->dev_addr[4], card->dev->dev_addr[5]); | ||
526 | break; | ||
527 | default: | ||
528 | break; | ||
529 | } | ||
505 | cmd->hdr.return_code = -EIO; | 530 | cmd->hdr.return_code = -EIO; |
506 | } else { | 531 | } else { |
507 | card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; | 532 | card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; |
@@ -616,6 +641,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) | |||
616 | { | 641 | { |
617 | struct qeth_card *card = dev->ml_priv; | 642 | struct qeth_card *card = dev->ml_priv; |
618 | struct dev_addr_list *dm; | 643 | struct dev_addr_list *dm; |
644 | struct netdev_hw_addr *ha; | ||
619 | 645 | ||
620 | if (card->info.type == QETH_CARD_TYPE_OSN) | 646 | if (card->info.type == QETH_CARD_TYPE_OSN) |
621 | return ; | 647 | return ; |
@@ -629,8 +655,8 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) | |||
629 | for (dm = dev->mc_list; dm; dm = dm->next) | 655 | for (dm = dev->mc_list; dm; dm = dm->next) |
630 | qeth_l2_add_mc(card, dm->da_addr, 0); | 656 | qeth_l2_add_mc(card, dm->da_addr, 0); |
631 | 657 | ||
632 | for (dm = dev->uc_list; dm; dm = dm->next) | 658 | list_for_each_entry(ha, &dev->uc.list, list) |
633 | qeth_l2_add_mc(card, dm->da_addr, 1); | 659 | qeth_l2_add_mc(card, ha->addr, 1); |
634 | 660 | ||
635 | spin_unlock_bh(&card->mclock); | 661 | spin_unlock_bh(&card->mclock); |
636 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | 662 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) |
@@ -839,6 +865,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) | |||
839 | { | 865 | { |
840 | struct qeth_card *card = dev_get_drvdata(&cgdev->dev); | 866 | struct qeth_card *card = dev_get_drvdata(&cgdev->dev); |
841 | 867 | ||
868 | qeth_set_allowed_threads(card, 0, 1); | ||
842 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | 869 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); |
843 | 870 | ||
844 | if (cgdev->state == CCWGROUP_ONLINE) { | 871 | if (cgdev->state == CCWGROUP_ONLINE) { |
@@ -974,8 +1001,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
974 | dev_warn(&card->gdev->dev, | 1001 | dev_warn(&card->gdev->dev, |
975 | "The LAN is offline\n"); | 1002 | "The LAN is offline\n"); |
976 | card->lan_online = 0; | 1003 | card->lan_online = 0; |
1004 | return 0; | ||
977 | } | 1005 | } |
978 | return rc; | 1006 | goto out_remove; |
979 | } else | 1007 | } else |
980 | card->lan_online = 1; | 1008 | card->lan_online = 1; |
981 | 1009 | ||
@@ -1113,12 +1141,62 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev) | |||
1113 | qeth_clear_qdio_buffers(card); | 1141 | qeth_clear_qdio_buffers(card); |
1114 | } | 1142 | } |
1115 | 1143 | ||
1144 | static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev) | ||
1145 | { | ||
1146 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
1147 | |||
1148 | if (card->dev) | ||
1149 | netif_device_detach(card->dev); | ||
1150 | qeth_set_allowed_threads(card, 0, 1); | ||
1151 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | ||
1152 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1153 | return 0; | ||
1154 | if (card->state == CARD_STATE_UP) { | ||
1155 | card->use_hard_stop = 1; | ||
1156 | __qeth_l2_set_offline(card->gdev, 1); | ||
1157 | } else | ||
1158 | __qeth_l2_set_offline(card->gdev, 0); | ||
1159 | return 0; | ||
1160 | } | ||
1161 | |||
1162 | static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) | ||
1163 | { | ||
1164 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
1165 | int rc = 0; | ||
1166 | |||
1167 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1168 | goto out; | ||
1169 | |||
1170 | if (card->state == CARD_STATE_RECOVER) { | ||
1171 | rc = __qeth_l2_set_online(card->gdev, 1); | ||
1172 | if (rc) { | ||
1173 | if (card->dev) { | ||
1174 | rtnl_lock(); | ||
1175 | dev_close(card->dev); | ||
1176 | rtnl_unlock(); | ||
1177 | } | ||
1178 | } | ||
1179 | } else | ||
1180 | rc = __qeth_l2_set_online(card->gdev, 0); | ||
1181 | out: | ||
1182 | qeth_set_allowed_threads(card, 0xffffffff, 0); | ||
1183 | if (card->dev) | ||
1184 | netif_device_attach(card->dev); | ||
1185 | if (rc) | ||
1186 | dev_warn(&card->gdev->dev, "The qeth device driver " | ||
1187 | "failed to recover an error on the device\n"); | ||
1188 | return rc; | ||
1189 | } | ||
1190 | |||
1116 | struct ccwgroup_driver qeth_l2_ccwgroup_driver = { | 1191 | struct ccwgroup_driver qeth_l2_ccwgroup_driver = { |
1117 | .probe = qeth_l2_probe_device, | 1192 | .probe = qeth_l2_probe_device, |
1118 | .remove = qeth_l2_remove_device, | 1193 | .remove = qeth_l2_remove_device, |
1119 | .set_online = qeth_l2_set_online, | 1194 | .set_online = qeth_l2_set_online, |
1120 | .set_offline = qeth_l2_set_offline, | 1195 | .set_offline = qeth_l2_set_offline, |
1121 | .shutdown = qeth_l2_shutdown, | 1196 | .shutdown = qeth_l2_shutdown, |
1197 | .freeze = qeth_l2_pm_suspend, | ||
1198 | .thaw = qeth_l2_pm_resume, | ||
1199 | .restore = qeth_l2_pm_resume, | ||
1122 | }; | 1200 | }; |
1123 | EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); | 1201 | EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); |
1124 | 1202 | ||
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 0ba3817cb6a7..54872406864e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/qeth_l3_main.c | 2 | * drivers/s390/net/qeth_l3_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | 5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
6 | * Frank Pavlic <fpavlic@de.ibm.com>, | 6 | * Frank Pavlic <fpavlic@de.ibm.com>, |
7 | * Thomas Spatzier <tspat@de.ibm.com>, | 7 | * Thomas Spatzier <tspat@de.ibm.com>, |
@@ -1920,16 +1920,22 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, | |||
1920 | hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); | 1920 | hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); |
1921 | } | 1921 | } |
1922 | 1922 | ||
1923 | skb->ip_summed = card->options.checksum_type; | 1923 | switch (card->options.checksum_type) { |
1924 | if (card->options.checksum_type == HW_CHECKSUMMING) { | 1924 | case SW_CHECKSUMMING: |
1925 | skb->ip_summed = CHECKSUM_NONE; | ||
1926 | break; | ||
1927 | case NO_CHECKSUMMING: | ||
1928 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1929 | break; | ||
1930 | case HW_CHECKSUMMING: | ||
1925 | if ((hdr->hdr.l3.ext_flags & | 1931 | if ((hdr->hdr.l3.ext_flags & |
1926 | (QETH_HDR_EXT_CSUM_HDR_REQ | | 1932 | (QETH_HDR_EXT_CSUM_HDR_REQ | |
1927 | QETH_HDR_EXT_CSUM_TRANSP_REQ)) == | 1933 | QETH_HDR_EXT_CSUM_TRANSP_REQ)) == |
1928 | (QETH_HDR_EXT_CSUM_HDR_REQ | | 1934 | (QETH_HDR_EXT_CSUM_HDR_REQ | |
1929 | QETH_HDR_EXT_CSUM_TRANSP_REQ)) | 1935 | QETH_HDR_EXT_CSUM_TRANSP_REQ)) |
1930 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1936 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1931 | else | 1937 | else |
1932 | skb->ip_summed = SW_CHECKSUMMING; | 1938 | skb->ip_summed = CHECKSUM_NONE; |
1933 | } | 1939 | } |
1934 | 1940 | ||
1935 | return vlan_id; | 1941 | return vlan_id; |
@@ -2543,9 +2549,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | |||
2543 | /* IPv4 */ | 2549 | /* IPv4 */ |
2544 | hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); | 2550 | hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); |
2545 | memset(hdr->hdr.l3.dest_addr, 0, 12); | 2551 | memset(hdr->hdr.l3.dest_addr, 0, 12); |
2546 | if ((skb->dst) && (skb->dst->neighbour)) { | 2552 | if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { |
2547 | *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = | 2553 | *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = |
2548 | *((u32 *) skb->dst->neighbour->primary_key); | 2554 | *((u32 *) skb_dst(skb)->neighbour->primary_key); |
2549 | } else { | 2555 | } else { |
2550 | /* fill in destination address used in ip header */ | 2556 | /* fill in destination address used in ip header */ |
2551 | *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = | 2557 | *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = |
@@ -2556,9 +2562,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | |||
2556 | hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); | 2562 | hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); |
2557 | if (card->info.type == QETH_CARD_TYPE_IQD) | 2563 | if (card->info.type == QETH_CARD_TYPE_IQD) |
2558 | hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; | 2564 | hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; |
2559 | if ((skb->dst) && (skb->dst->neighbour)) { | 2565 | if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { |
2560 | memcpy(hdr->hdr.l3.dest_addr, | 2566 | memcpy(hdr->hdr.l3.dest_addr, |
2561 | skb->dst->neighbour->primary_key, 16); | 2567 | skb_dst(skb)->neighbour->primary_key, 16); |
2562 | } else { | 2568 | } else { |
2563 | /* fill in destination address used in ip header */ | 2569 | /* fill in destination address used in ip header */ |
2564 | memcpy(hdr->hdr.l3.dest_addr, | 2570 | memcpy(hdr->hdr.l3.dest_addr, |
@@ -3006,6 +3012,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) | |||
3006 | card->dev->features |= NETIF_F_HW_VLAN_TX | | 3012 | card->dev->features |= NETIF_F_HW_VLAN_TX | |
3007 | NETIF_F_HW_VLAN_RX | | 3013 | NETIF_F_HW_VLAN_RX | |
3008 | NETIF_F_HW_VLAN_FILTER; | 3014 | NETIF_F_HW_VLAN_FILTER; |
3015 | card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
3009 | 3016 | ||
3010 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); | 3017 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); |
3011 | return register_netdev(card->dev); | 3018 | return register_netdev(card->dev); |
@@ -3070,6 +3077,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) | |||
3070 | { | 3077 | { |
3071 | struct qeth_card *card = dev_get_drvdata(&cgdev->dev); | 3078 | struct qeth_card *card = dev_get_drvdata(&cgdev->dev); |
3072 | 3079 | ||
3080 | qeth_set_allowed_threads(card, 0, 1); | ||
3073 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | 3081 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); |
3074 | 3082 | ||
3075 | if (cgdev->state == CCWGROUP_ONLINE) { | 3083 | if (cgdev->state == CCWGROUP_ONLINE) { |
@@ -3141,8 +3149,9 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3141 | dev_warn(&card->gdev->dev, | 3149 | dev_warn(&card->gdev->dev, |
3142 | "The LAN is offline\n"); | 3150 | "The LAN is offline\n"); |
3143 | card->lan_online = 0; | 3151 | card->lan_online = 0; |
3152 | return 0; | ||
3144 | } | 3153 | } |
3145 | return rc; | 3154 | goto out_remove; |
3146 | } else | 3155 | } else |
3147 | card->lan_online = 1; | 3156 | card->lan_online = 1; |
3148 | qeth_set_large_send(card, card->options.large_send); | 3157 | qeth_set_large_send(card, card->options.large_send); |
@@ -3274,12 +3283,62 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev) | |||
3274 | qeth_clear_qdio_buffers(card); | 3283 | qeth_clear_qdio_buffers(card); |
3275 | } | 3284 | } |
3276 | 3285 | ||
3286 | static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev) | ||
3287 | { | ||
3288 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
3289 | |||
3290 | if (card->dev) | ||
3291 | netif_device_detach(card->dev); | ||
3292 | qeth_set_allowed_threads(card, 0, 1); | ||
3293 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | ||
3294 | if (gdev->state == CCWGROUP_OFFLINE) | ||
3295 | return 0; | ||
3296 | if (card->state == CARD_STATE_UP) { | ||
3297 | card->use_hard_stop = 1; | ||
3298 | __qeth_l3_set_offline(card->gdev, 1); | ||
3299 | } else | ||
3300 | __qeth_l3_set_offline(card->gdev, 0); | ||
3301 | return 0; | ||
3302 | } | ||
3303 | |||
3304 | static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) | ||
3305 | { | ||
3306 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
3307 | int rc = 0; | ||
3308 | |||
3309 | if (gdev->state == CCWGROUP_OFFLINE) | ||
3310 | goto out; | ||
3311 | |||
3312 | if (card->state == CARD_STATE_RECOVER) { | ||
3313 | rc = __qeth_l3_set_online(card->gdev, 1); | ||
3314 | if (rc) { | ||
3315 | if (card->dev) { | ||
3316 | rtnl_lock(); | ||
3317 | dev_close(card->dev); | ||
3318 | rtnl_unlock(); | ||
3319 | } | ||
3320 | } | ||
3321 | } else | ||
3322 | rc = __qeth_l3_set_online(card->gdev, 0); | ||
3323 | out: | ||
3324 | qeth_set_allowed_threads(card, 0xffffffff, 0); | ||
3325 | if (card->dev) | ||
3326 | netif_device_attach(card->dev); | ||
3327 | if (rc) | ||
3328 | dev_warn(&card->gdev->dev, "The qeth device driver " | ||
3329 | "failed to recover an error on the device\n"); | ||
3330 | return rc; | ||
3331 | } | ||
3332 | |||
3277 | struct ccwgroup_driver qeth_l3_ccwgroup_driver = { | 3333 | struct ccwgroup_driver qeth_l3_ccwgroup_driver = { |
3278 | .probe = qeth_l3_probe_device, | 3334 | .probe = qeth_l3_probe_device, |
3279 | .remove = qeth_l3_remove_device, | 3335 | .remove = qeth_l3_remove_device, |
3280 | .set_online = qeth_l3_set_online, | 3336 | .set_online = qeth_l3_set_online, |
3281 | .set_offline = qeth_l3_set_offline, | 3337 | .set_offline = qeth_l3_set_offline, |
3282 | .shutdown = qeth_l3_shutdown, | 3338 | .shutdown = qeth_l3_shutdown, |
3339 | .freeze = qeth_l3_pm_suspend, | ||
3340 | .thaw = qeth_l3_pm_resume, | ||
3341 | .restore = qeth_l3_pm_resume, | ||
3283 | }; | 3342 | }; |
3284 | EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); | 3343 | EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); |
3285 | 3344 | ||
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 164e090c2625..e76a320d373b 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV special message driver | 2 | * IUCV special message driver |
3 | * | 3 | * |
4 | * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2003, 2009 |
5 | * | ||
5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | 6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
@@ -40,6 +41,8 @@ MODULE_AUTHOR | |||
40 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); | 41 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); |
41 | 42 | ||
42 | static struct iucv_path *smsg_path; | 43 | static struct iucv_path *smsg_path; |
44 | /* dummy device used as trigger for PM functions */ | ||
45 | static struct device *smsg_dev; | ||
43 | 46 | ||
44 | static DEFINE_SPINLOCK(smsg_list_lock); | 47 | static DEFINE_SPINLOCK(smsg_list_lock); |
45 | static LIST_HEAD(smsg_list); | 48 | static LIST_HEAD(smsg_list); |
@@ -132,14 +135,51 @@ void smsg_unregister_callback(char *prefix, | |||
132 | kfree(cb); | 135 | kfree(cb); |
133 | } | 136 | } |
134 | 137 | ||
138 | static int smsg_pm_freeze(struct device *dev) | ||
139 | { | ||
140 | #ifdef CONFIG_PM_DEBUG | ||
141 | printk(KERN_WARNING "smsg_pm_freeze\n"); | ||
142 | #endif | ||
143 | if (smsg_path) | ||
144 | iucv_path_sever(smsg_path, NULL); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int smsg_pm_restore_thaw(struct device *dev) | ||
149 | { | ||
150 | int rc; | ||
151 | |||
152 | #ifdef CONFIG_PM_DEBUG | ||
153 | printk(KERN_WARNING "smsg_pm_restore_thaw\n"); | ||
154 | #endif | ||
155 | if (smsg_path) { | ||
156 | memset(smsg_path, 0, sizeof(*smsg_path)); | ||
157 | smsg_path->msglim = 255; | ||
158 | smsg_path->flags = 0; | ||
159 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", | ||
160 | NULL, NULL, NULL); | ||
161 | printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc); | ||
162 | } | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static struct dev_pm_ops smsg_pm_ops = { | ||
167 | .freeze = smsg_pm_freeze, | ||
168 | .thaw = smsg_pm_restore_thaw, | ||
169 | .restore = smsg_pm_restore_thaw, | ||
170 | }; | ||
171 | |||
135 | static struct device_driver smsg_driver = { | 172 | static struct device_driver smsg_driver = { |
173 | .owner = THIS_MODULE, | ||
136 | .name = "SMSGIUCV", | 174 | .name = "SMSGIUCV", |
137 | .bus = &iucv_bus, | 175 | .bus = &iucv_bus, |
176 | .pm = &smsg_pm_ops, | ||
138 | }; | 177 | }; |
139 | 178 | ||
140 | static void __exit smsg_exit(void) | 179 | static void __exit smsg_exit(void) |
141 | { | 180 | { |
142 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); | 181 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
182 | device_unregister(smsg_dev); | ||
143 | iucv_unregister(&smsg_handler, 1); | 183 | iucv_unregister(&smsg_handler, 1); |
144 | driver_unregister(&smsg_driver); | 184 | driver_unregister(&smsg_driver); |
145 | } | 185 | } |
@@ -166,12 +206,29 @@ static int __init smsg_init(void) | |||
166 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", | 206 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", |
167 | NULL, NULL, NULL); | 207 | NULL, NULL, NULL); |
168 | if (rc) | 208 | if (rc) |
169 | goto out_free; | 209 | goto out_free_path; |
210 | smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
211 | if (!smsg_dev) { | ||
212 | rc = -ENOMEM; | ||
213 | goto out_free_path; | ||
214 | } | ||
215 | dev_set_name(smsg_dev, "smsg_iucv"); | ||
216 | smsg_dev->bus = &iucv_bus; | ||
217 | smsg_dev->parent = iucv_root; | ||
218 | smsg_dev->release = (void (*)(struct device *))kfree; | ||
219 | smsg_dev->driver = &smsg_driver; | ||
220 | rc = device_register(smsg_dev); | ||
221 | if (rc) | ||
222 | goto out_free_dev; | ||
223 | |||
170 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); | 224 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
171 | return 0; | 225 | return 0; |
172 | 226 | ||
173 | out_free: | 227 | out_free_dev: |
228 | kfree(smsg_dev); | ||
229 | out_free_path: | ||
174 | iucv_path_free(smsg_path); | 230 | iucv_path_free(smsg_path); |
231 | smsg_path = NULL; | ||
175 | out_register: | 232 | out_register: |
176 | iucv_unregister(&smsg_handler, 1); | 233 | iucv_unregister(&smsg_handler, 1); |
177 | out_driver: | 234 | out_driver: |
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 3ac27ee47396..2ccbd185a5fb 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -470,6 +470,12 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
470 | if (!adapter) | 470 | if (!adapter) |
471 | return -ENOMEM; | 471 | return -ENOMEM; |
472 | 472 | ||
473 | adapter->gs = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL); | ||
474 | if (!adapter->gs) { | ||
475 | kfree(adapter); | ||
476 | return -ENOMEM; | ||
477 | } | ||
478 | |||
473 | ccw_device->handler = NULL; | 479 | ccw_device->handler = NULL; |
474 | adapter->ccw_device = ccw_device; | 480 | adapter->ccw_device = ccw_device; |
475 | atomic_set(&adapter->refcount, 0); | 481 | atomic_set(&adapter->refcount, 0); |
@@ -523,8 +529,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
523 | goto sysfs_failed; | 529 | goto sysfs_failed; |
524 | 530 | ||
525 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 531 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); |
526 | 532 | zfcp_fc_wka_ports_init(adapter); | |
527 | zfcp_fc_nameserver_init(adapter); | ||
528 | 533 | ||
529 | if (!zfcp_adapter_scsi_register(adapter)) | 534 | if (!zfcp_adapter_scsi_register(adapter)) |
530 | return 0; | 535 | return 0; |
@@ -571,6 +576,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
571 | kfree(adapter->req_list); | 576 | kfree(adapter->req_list); |
572 | kfree(adapter->fc_stats); | 577 | kfree(adapter->fc_stats); |
573 | kfree(adapter->stats_reset_data); | 578 | kfree(adapter->stats_reset_data); |
579 | kfree(adapter->gs); | ||
574 | kfree(adapter); | 580 | kfree(adapter); |
575 | } | 581 | } |
576 | 582 | ||
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 733fe3bf6285..d9da5c42ccbe 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c | |||
@@ -11,6 +11,54 @@ | |||
11 | 11 | ||
12 | #include "zfcp_ext.h" | 12 | #include "zfcp_ext.h" |
13 | 13 | ||
14 | #define ZFCP_MODEL_PRIV 0x4 | ||
15 | |||
16 | static int zfcp_ccw_suspend(struct ccw_device *cdev) | ||
17 | |||
18 | { | ||
19 | struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); | ||
20 | |||
21 | down(&zfcp_data.config_sema); | ||
22 | |||
23 | zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); | ||
24 | zfcp_erp_wait(adapter); | ||
25 | |||
26 | up(&zfcp_data.config_sema); | ||
27 | |||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | static int zfcp_ccw_activate(struct ccw_device *cdev) | ||
32 | |||
33 | { | ||
34 | struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); | ||
35 | |||
36 | zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, | ||
37 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); | ||
38 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, | ||
39 | "ccresu2", NULL); | ||
40 | zfcp_erp_wait(adapter); | ||
41 | flush_work(&adapter->scan_work); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static struct ccw_device_id zfcp_ccw_device_id[] = { | ||
47 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, | ||
48 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) }, | ||
49 | {}, | ||
50 | }; | ||
51 | MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); | ||
52 | |||
53 | /** | ||
54 | * zfcp_ccw_priv_sch - check if subchannel is privileged | ||
55 | * @adapter: Adapter/Subchannel to check | ||
56 | */ | ||
57 | int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter) | ||
58 | { | ||
59 | return adapter->ccw_device->id.dev_model == ZFCP_MODEL_PRIV; | ||
60 | } | ||
61 | |||
14 | /** | 62 | /** |
15 | * zfcp_ccw_probe - probe function of zfcp driver | 63 | * zfcp_ccw_probe - probe function of zfcp driver |
16 | * @ccw_device: pointer to belonging ccw device | 64 | * @ccw_device: pointer to belonging ccw device |
@@ -176,8 +224,8 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | |||
176 | "ccnoti4", NULL); | 224 | "ccnoti4", NULL); |
177 | break; | 225 | break; |
178 | case CIO_BOXED: | 226 | case CIO_BOXED: |
179 | dev_warn(&adapter->ccw_device->dev, | 227 | dev_warn(&adapter->ccw_device->dev, "The FCP device " |
180 | "The ccw device did not respond in time.\n"); | 228 | "did not respond within the specified time\n"); |
181 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); | 229 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); |
182 | break; | 230 | break; |
183 | } | 231 | } |
@@ -199,14 +247,6 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) | |||
199 | up(&zfcp_data.config_sema); | 247 | up(&zfcp_data.config_sema); |
200 | } | 248 | } |
201 | 249 | ||
202 | static struct ccw_device_id zfcp_ccw_device_id[] = { | ||
203 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, | ||
204 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x4) }, /* priv. */ | ||
205 | {}, | ||
206 | }; | ||
207 | |||
208 | MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); | ||
209 | |||
210 | static struct ccw_driver zfcp_ccw_driver = { | 250 | static struct ccw_driver zfcp_ccw_driver = { |
211 | .owner = THIS_MODULE, | 251 | .owner = THIS_MODULE, |
212 | .name = "zfcp", | 252 | .name = "zfcp", |
@@ -217,6 +257,9 @@ static struct ccw_driver zfcp_ccw_driver = { | |||
217 | .set_offline = zfcp_ccw_set_offline, | 257 | .set_offline = zfcp_ccw_set_offline, |
218 | .notify = zfcp_ccw_notify, | 258 | .notify = zfcp_ccw_notify, |
219 | .shutdown = zfcp_ccw_shutdown, | 259 | .shutdown = zfcp_ccw_shutdown, |
260 | .freeze = zfcp_ccw_suspend, | ||
261 | .thaw = zfcp_ccw_activate, | ||
262 | .restore = zfcp_ccw_activate, | ||
220 | }; | 263 | }; |
221 | 264 | ||
222 | /** | 265 | /** |
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 0a1a5dd8d018..b99b87ce5a39 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -163,7 +163,7 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) | |||
163 | } | 163 | } |
164 | 164 | ||
165 | response->fsf_command = fsf_req->fsf_command; | 165 | response->fsf_command = fsf_req->fsf_command; |
166 | response->fsf_reqid = (unsigned long)fsf_req; | 166 | response->fsf_reqid = fsf_req->req_id; |
167 | response->fsf_seqno = fsf_req->seq_no; | 167 | response->fsf_seqno = fsf_req->seq_no; |
168 | response->fsf_issued = fsf_req->issued; | 168 | response->fsf_issued = fsf_req->issued; |
169 | response->fsf_prot_status = qtcb->prefix.prot_status; | 169 | response->fsf_prot_status = qtcb->prefix.prot_status; |
@@ -737,7 +737,7 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) | |||
737 | spin_lock_irqsave(&adapter->san_dbf_lock, flags); | 737 | spin_lock_irqsave(&adapter->san_dbf_lock, flags); |
738 | memset(r, 0, sizeof(*r)); | 738 | memset(r, 0, sizeof(*r)); |
739 | strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE); | 739 | strncpy(r->tag, "octc", ZFCP_DBF_TAG_SIZE); |
740 | r->fsf_reqid = (unsigned long)fsf_req; | 740 | r->fsf_reqid = fsf_req->req_id; |
741 | r->fsf_seqno = fsf_req->seq_no; | 741 | r->fsf_seqno = fsf_req->seq_no; |
742 | r->s_id = fc_host_port_id(adapter->scsi_host); | 742 | r->s_id = fc_host_port_id(adapter->scsi_host); |
743 | r->d_id = wka_port->d_id; | 743 | r->d_id = wka_port->d_id; |
@@ -773,7 +773,7 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) | |||
773 | spin_lock_irqsave(&adapter->san_dbf_lock, flags); | 773 | spin_lock_irqsave(&adapter->san_dbf_lock, flags); |
774 | memset(r, 0, sizeof(*r)); | 774 | memset(r, 0, sizeof(*r)); |
775 | strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE); | 775 | strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE); |
776 | r->fsf_reqid = (unsigned long)fsf_req; | 776 | r->fsf_reqid = fsf_req->req_id; |
777 | r->fsf_seqno = fsf_req->seq_no; | 777 | r->fsf_seqno = fsf_req->seq_no; |
778 | r->s_id = wka_port->d_id; | 778 | r->s_id = wka_port->d_id; |
779 | r->d_id = fc_host_port_id(adapter->scsi_host); | 779 | r->d_id = fc_host_port_id(adapter->scsi_host); |
@@ -803,7 +803,7 @@ static void zfcp_san_dbf_event_els(const char *tag, int level, | |||
803 | spin_lock_irqsave(&adapter->san_dbf_lock, flags); | 803 | spin_lock_irqsave(&adapter->san_dbf_lock, flags); |
804 | memset(rec, 0, sizeof(*rec)); | 804 | memset(rec, 0, sizeof(*rec)); |
805 | strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); | 805 | strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); |
806 | rec->fsf_reqid = (unsigned long)fsf_req; | 806 | rec->fsf_reqid = fsf_req->req_id; |
807 | rec->fsf_seqno = fsf_req->seq_no; | 807 | rec->fsf_seqno = fsf_req->seq_no; |
808 | rec->s_id = s_id; | 808 | rec->s_id = s_id; |
809 | rec->d_id = d_id; | 809 | rec->d_id = d_id; |
@@ -965,7 +965,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, | |||
965 | ZFCP_DBF_SCSI_FCP_SNS_INFO); | 965 | ZFCP_DBF_SCSI_FCP_SNS_INFO); |
966 | } | 966 | } |
967 | 967 | ||
968 | rec->fsf_reqid = (unsigned long)fsf_req; | 968 | rec->fsf_reqid = fsf_req->req_id; |
969 | rec->fsf_seqno = fsf_req->seq_no; | 969 | rec->fsf_seqno = fsf_req->seq_no; |
970 | rec->fsf_issued = fsf_req->issued; | 970 | rec->fsf_issued = fsf_req->issued; |
971 | } | 971 | } |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 4c362a9069f0..49d0532bca1c 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/syscalls.h> | 22 | #include <linux/syscalls.h> |
23 | #include <linux/scatterlist.h> | 23 | #include <linux/scatterlist.h> |
24 | #include <linux/ioctl.h> | 24 | #include <linux/ioctl.h> |
25 | #include <scsi/fc/fc_fs.h> | ||
26 | #include <scsi/fc/fc_gs.h> | ||
25 | #include <scsi/scsi.h> | 27 | #include <scsi/scsi.h> |
26 | #include <scsi/scsi_tcq.h> | 28 | #include <scsi/scsi_tcq.h> |
27 | #include <scsi/scsi_cmnd.h> | 29 | #include <scsi/scsi_cmnd.h> |
@@ -29,6 +31,7 @@ | |||
29 | #include <scsi/scsi_host.h> | 31 | #include <scsi/scsi_host.h> |
30 | #include <scsi/scsi_transport.h> | 32 | #include <scsi/scsi_transport.h> |
31 | #include <scsi/scsi_transport_fc.h> | 33 | #include <scsi/scsi_transport_fc.h> |
34 | #include <scsi/scsi_bsg_fc.h> | ||
32 | #include <asm/ccwdev.h> | 35 | #include <asm/ccwdev.h> |
33 | #include <asm/qdio.h> | 36 | #include <asm/qdio.h> |
34 | #include <asm/debug.h> | 37 | #include <asm/debug.h> |
@@ -47,13 +50,6 @@ | |||
47 | 50 | ||
48 | /********************* CIO/QDIO SPECIFIC DEFINES *****************************/ | 51 | /********************* CIO/QDIO SPECIFIC DEFINES *****************************/ |
49 | 52 | ||
50 | /* Adapter Identification Parameters */ | ||
51 | #define ZFCP_CONTROL_UNIT_TYPE 0x1731 | ||
52 | #define ZFCP_CONTROL_UNIT_MODEL 0x03 | ||
53 | #define ZFCP_DEVICE_TYPE 0x1732 | ||
54 | #define ZFCP_DEVICE_MODEL 0x03 | ||
55 | #define ZFCP_DEVICE_MODEL_PRIV 0x04 | ||
56 | |||
57 | /* DMQ bug workaround: don't use last SBALE */ | 53 | /* DMQ bug workaround: don't use last SBALE */ |
58 | #define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) | 54 | #define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) |
59 | 55 | ||
@@ -235,11 +231,6 @@ struct zfcp_ls_adisc { | |||
235 | 231 | ||
236 | /* FC-PH/FC-GS well-known address identifiers for generic services */ | 232 | /* FC-PH/FC-GS well-known address identifiers for generic services */ |
237 | #define ZFCP_DID_WKA 0xFFFFF0 | 233 | #define ZFCP_DID_WKA 0xFFFFF0 |
238 | #define ZFCP_DID_MANAGEMENT_SERVICE 0xFFFFFA | ||
239 | #define ZFCP_DID_TIME_SERVICE 0xFFFFFB | ||
240 | #define ZFCP_DID_DIRECTORY_SERVICE 0xFFFFFC | ||
241 | #define ZFCP_DID_ALIAS_SERVICE 0xFFFFF8 | ||
242 | #define ZFCP_DID_KEY_DISTRIBUTION_SERVICE 0xFFFFF7 | ||
243 | 234 | ||
244 | /* remote port status */ | 235 | /* remote port status */ |
245 | #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 | 236 | #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 |
@@ -383,6 +374,14 @@ struct zfcp_wka_port { | |||
383 | struct delayed_work work; | 374 | struct delayed_work work; |
384 | }; | 375 | }; |
385 | 376 | ||
377 | struct zfcp_wka_ports { | ||
378 | struct zfcp_wka_port ms; /* management service */ | ||
379 | struct zfcp_wka_port ts; /* time service */ | ||
380 | struct zfcp_wka_port ds; /* directory service */ | ||
381 | struct zfcp_wka_port as; /* alias service */ | ||
382 | struct zfcp_wka_port ks; /* key distribution service */ | ||
383 | }; | ||
384 | |||
386 | struct zfcp_qdio_queue { | 385 | struct zfcp_qdio_queue { |
387 | struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; | 386 | struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; |
388 | u8 first; /* index of next free bfr in queue */ | 387 | u8 first; /* index of next free bfr in queue */ |
@@ -468,7 +467,7 @@ struct zfcp_adapter { | |||
468 | actions */ | 467 | actions */ |
469 | u32 erp_low_mem_count; /* nr of erp actions waiting | 468 | u32 erp_low_mem_count; /* nr of erp actions waiting |
470 | for memory */ | 469 | for memory */ |
471 | struct zfcp_wka_port nsp; /* adapter's nameserver */ | 470 | struct zfcp_wka_ports *gs; /* generic services */ |
472 | debug_info_t *rec_dbf; | 471 | debug_info_t *rec_dbf; |
473 | debug_info_t *hba_dbf; | 472 | debug_info_t *hba_dbf; |
474 | debug_info_t *san_dbf; /* debug feature areas */ | 473 | debug_info_t *san_dbf; /* debug feature areas */ |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index fdc9b4352a64..8030e25152fb 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -719,7 +719,7 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) | |||
719 | zfcp_qdio_close(adapter); | 719 | zfcp_qdio_close(adapter); |
720 | zfcp_fsf_req_dismiss_all(adapter); | 720 | zfcp_fsf_req_dismiss_all(adapter); |
721 | adapter->fsf_req_seq_no = 0; | 721 | adapter->fsf_req_seq_no = 0; |
722 | zfcp_fc_wka_port_force_offline(&adapter->nsp); | 722 | zfcp_fc_wka_port_force_offline(&adapter->gs->ds); |
723 | /* all ports and units are closed */ | 723 | /* all ports and units are closed */ |
724 | zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, | 724 | zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, |
725 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); | 725 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); |
@@ -880,6 +880,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) | |||
880 | zfcp_port_put(port); | 880 | zfcp_port_put(port); |
881 | return ZFCP_ERP_CONTINUES; | 881 | return ZFCP_ERP_CONTINUES; |
882 | } | 882 | } |
883 | /* fall through */ | ||
883 | case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: | 884 | case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: |
884 | if (!port->d_id) | 885 | if (!port->d_id) |
885 | return ZFCP_ERP_FAILED; | 886 | return ZFCP_ERP_FAILED; |
@@ -894,8 +895,13 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) | |||
894 | act->step = ZFCP_ERP_STEP_PORT_CLOSING; | 895 | act->step = ZFCP_ERP_STEP_PORT_CLOSING; |
895 | return ZFCP_ERP_CONTINUES; | 896 | return ZFCP_ERP_CONTINUES; |
896 | } | 897 | } |
897 | /* fall through otherwise */ | ||
898 | } | 898 | } |
899 | if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { | ||
900 | port->d_id = 0; | ||
901 | _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL); | ||
902 | return ZFCP_ERP_EXIT; | ||
903 | } | ||
904 | /* fall through otherwise */ | ||
899 | } | 905 | } |
900 | return ZFCP_ERP_FAILED; | 906 | return ZFCP_ERP_FAILED; |
901 | } | 907 | } |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 2e31b536548c..3044c6010306 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -27,6 +27,7 @@ extern int zfcp_sg_setup_table(struct scatterlist *, int); | |||
27 | 27 | ||
28 | /* zfcp_ccw.c */ | 28 | /* zfcp_ccw.c */ |
29 | extern int zfcp_ccw_register(void); | 29 | extern int zfcp_ccw_register(void); |
30 | extern int zfcp_ccw_priv_sch(struct zfcp_adapter *); | ||
30 | extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); | 31 | extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); |
31 | 32 | ||
32 | /* zfcp_cfdc.c */ | 33 | /* zfcp_cfdc.c */ |
@@ -105,8 +106,12 @@ extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); | |||
105 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); | 106 | extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); |
106 | extern void zfcp_test_link(struct zfcp_port *); | 107 | extern void zfcp_test_link(struct zfcp_port *); |
107 | extern void zfcp_fc_link_test_work(struct work_struct *); | 108 | extern void zfcp_fc_link_test_work(struct work_struct *); |
108 | extern void zfcp_fc_nameserver_init(struct zfcp_adapter *); | ||
109 | extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); | 109 | extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); |
110 | extern void zfcp_fc_wka_ports_init(struct zfcp_adapter *); | ||
111 | extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *); | ||
112 | extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *); | ||
113 | extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); | ||
114 | |||
110 | 115 | ||
111 | /* zfcp_fsf.c */ | 116 | /* zfcp_fsf.c */ |
112 | extern int zfcp_fsf_open_port(struct zfcp_erp_action *); | 117 | extern int zfcp_fsf_open_port(struct zfcp_erp_action *); |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 19ae0842047c..2f0705d76b72 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -116,18 +116,17 @@ static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port) | |||
116 | { | 116 | { |
117 | if (atomic_dec_return(&wka_port->refcount) != 0) | 117 | if (atomic_dec_return(&wka_port->refcount) != 0) |
118 | return; | 118 | return; |
119 | /* wait 10 miliseconds, other reqs might pop in */ | 119 | /* wait 10 milliseconds, other reqs might pop in */ |
120 | schedule_delayed_work(&wka_port->work, HZ / 100); | 120 | schedule_delayed_work(&wka_port->work, HZ / 100); |
121 | } | 121 | } |
122 | 122 | ||
123 | void zfcp_fc_nameserver_init(struct zfcp_adapter *adapter) | 123 | static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id, |
124 | struct zfcp_adapter *adapter) | ||
124 | { | 125 | { |
125 | struct zfcp_wka_port *wka_port = &adapter->nsp; | ||
126 | |||
127 | init_waitqueue_head(&wka_port->completion_wq); | 126 | init_waitqueue_head(&wka_port->completion_wq); |
128 | 127 | ||
129 | wka_port->adapter = adapter; | 128 | wka_port->adapter = adapter; |
130 | wka_port->d_id = ZFCP_DID_DIRECTORY_SERVICE; | 129 | wka_port->d_id = d_id; |
131 | 130 | ||
132 | wka_port->status = ZFCP_WKA_PORT_OFFLINE; | 131 | wka_port->status = ZFCP_WKA_PORT_OFFLINE; |
133 | atomic_set(&wka_port->refcount, 0); | 132 | atomic_set(&wka_port->refcount, 0); |
@@ -143,6 +142,17 @@ void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) | |||
143 | mutex_unlock(&wka->mutex); | 142 | mutex_unlock(&wka->mutex); |
144 | } | 143 | } |
145 | 144 | ||
145 | void zfcp_fc_wka_ports_init(struct zfcp_adapter *adapter) | ||
146 | { | ||
147 | struct zfcp_wka_ports *gs = adapter->gs; | ||
148 | |||
149 | zfcp_fc_wka_port_init(&gs->ms, FC_FID_MGMT_SERV, adapter); | ||
150 | zfcp_fc_wka_port_init(&gs->ts, FC_FID_TIME_SERV, adapter); | ||
151 | zfcp_fc_wka_port_init(&gs->ds, FC_FID_DIR_SERV, adapter); | ||
152 | zfcp_fc_wka_port_init(&gs->as, FC_FID_ALIASES, adapter); | ||
153 | zfcp_fc_wka_port_init(&gs->ks, FC_FID_SEC_KEY, adapter); | ||
154 | } | ||
155 | |||
146 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, | 156 | static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, |
147 | struct fcp_rscn_element *elem) | 157 | struct fcp_rscn_element *elem) |
148 | { | 158 | { |
@@ -150,9 +160,14 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, | |||
150 | struct zfcp_port *port; | 160 | struct zfcp_port *port; |
151 | 161 | ||
152 | read_lock_irqsave(&zfcp_data.config_lock, flags); | 162 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
153 | list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) | 163 | list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { |
154 | if ((port->d_id & range) == (elem->nport_did & range)) | 164 | if ((port->d_id & range) == (elem->nport_did & range)) |
155 | zfcp_test_link(port); | 165 | zfcp_test_link(port); |
166 | if (!port->d_id) | ||
167 | zfcp_erp_port_reopen(port, | ||
168 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
169 | "fcrscn1", NULL); | ||
170 | } | ||
156 | 171 | ||
157 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | 172 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
158 | } | 173 | } |
@@ -277,7 +292,7 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, | |||
277 | 292 | ||
278 | /* setup parameters for send generic command */ | 293 | /* setup parameters for send generic command */ |
279 | gid_pn->port = erp_action->port; | 294 | gid_pn->port = erp_action->port; |
280 | gid_pn->ct.wka_port = &adapter->nsp; | 295 | gid_pn->ct.wka_port = &adapter->gs->ds; |
281 | gid_pn->ct.handler = zfcp_fc_ns_handler; | 296 | gid_pn->ct.handler = zfcp_fc_ns_handler; |
282 | gid_pn->ct.handler_data = (unsigned long) &compl_rec; | 297 | gid_pn->ct.handler_data = (unsigned long) &compl_rec; |
283 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; | 298 | gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; |
@@ -324,13 +339,13 @@ int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action) | |||
324 | 339 | ||
325 | memset(gid_pn, 0, sizeof(*gid_pn)); | 340 | memset(gid_pn, 0, sizeof(*gid_pn)); |
326 | 341 | ||
327 | ret = zfcp_wka_port_get(&adapter->nsp); | 342 | ret = zfcp_wka_port_get(&adapter->gs->ds); |
328 | if (ret) | 343 | if (ret) |
329 | goto out; | 344 | goto out; |
330 | 345 | ||
331 | ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn); | 346 | ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn); |
332 | 347 | ||
333 | zfcp_wka_port_put(&adapter->nsp); | 348 | zfcp_wka_port_put(&adapter->gs->ds); |
334 | out: | 349 | out: |
335 | mempool_free(gid_pn, adapter->pool.data_gid_pn); | 350 | mempool_free(gid_pn, adapter->pool.data_gid_pn); |
336 | return ret; | 351 | return ret; |
@@ -520,7 +535,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | |||
520 | req->fc4_type = ZFCP_CT_SCSI_FCP; | 535 | req->fc4_type = ZFCP_CT_SCSI_FCP; |
521 | 536 | ||
522 | /* prepare zfcp_send_ct */ | 537 | /* prepare zfcp_send_ct */ |
523 | ct->wka_port = &adapter->nsp; | 538 | ct->wka_port = &adapter->gs->ds; |
524 | ct->handler = zfcp_fc_ns_handler; | 539 | ct->handler = zfcp_fc_ns_handler; |
525 | ct->handler_data = (unsigned long)&compl_rec; | 540 | ct->handler_data = (unsigned long)&compl_rec; |
526 | ct->timeout = 10; | 541 | ct->timeout = 10; |
@@ -639,7 +654,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) | |||
639 | fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) | 654 | fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) |
640 | return 0; | 655 | return 0; |
641 | 656 | ||
642 | ret = zfcp_wka_port_get(&adapter->nsp); | 657 | ret = zfcp_wka_port_get(&adapter->gs->ds); |
643 | if (ret) | 658 | if (ret) |
644 | return ret; | 659 | return ret; |
645 | 660 | ||
@@ -661,7 +676,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) | |||
661 | } | 676 | } |
662 | zfcp_free_sg_env(gpn_ft, buf_num); | 677 | zfcp_free_sg_env(gpn_ft, buf_num); |
663 | out: | 678 | out: |
664 | zfcp_wka_port_put(&adapter->nsp); | 679 | zfcp_wka_port_put(&adapter->gs->ds); |
665 | return ret; | 680 | return ret; |
666 | } | 681 | } |
667 | 682 | ||
@@ -670,3 +685,158 @@ void _zfcp_scan_ports_later(struct work_struct *work) | |||
670 | { | 685 | { |
671 | zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); | 686 | zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); |
672 | } | 687 | } |
688 | |||
689 | struct zfcp_els_fc_job { | ||
690 | struct zfcp_send_els els; | ||
691 | struct fc_bsg_job *job; | ||
692 | }; | ||
693 | |||
694 | static void zfcp_fc_generic_els_handler(unsigned long data) | ||
695 | { | ||
696 | struct zfcp_els_fc_job *els_fc_job = (struct zfcp_els_fc_job *) data; | ||
697 | struct fc_bsg_job *job = els_fc_job->job; | ||
698 | struct fc_bsg_reply *reply = job->reply; | ||
699 | |||
700 | if (els_fc_job->els.status) { | ||
701 | /* request rejected or timed out */ | ||
702 | reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_REJECT; | ||
703 | goto out; | ||
704 | } | ||
705 | |||
706 | reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; | ||
707 | reply->reply_payload_rcv_len = job->reply_payload.payload_len; | ||
708 | |||
709 | out: | ||
710 | job->state_flags = FC_RQST_STATE_DONE; | ||
711 | job->job_done(job); | ||
712 | kfree(els_fc_job); | ||
713 | } | ||
714 | |||
715 | int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) | ||
716 | { | ||
717 | struct zfcp_els_fc_job *els_fc_job; | ||
718 | struct fc_rport *rport = job->rport; | ||
719 | struct Scsi_Host *shost; | ||
720 | struct zfcp_adapter *adapter; | ||
721 | struct zfcp_port *port; | ||
722 | u8 *port_did; | ||
723 | |||
724 | shost = rport ? rport_to_shost(rport) : job->shost; | ||
725 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; | ||
726 | |||
727 | if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN)) | ||
728 | return -EINVAL; | ||
729 | |||
730 | els_fc_job = kzalloc(sizeof(struct zfcp_els_fc_job), GFP_KERNEL); | ||
731 | if (!els_fc_job) | ||
732 | return -ENOMEM; | ||
733 | |||
734 | els_fc_job->els.adapter = adapter; | ||
735 | if (rport) { | ||
736 | read_lock_irq(&zfcp_data.config_lock); | ||
737 | port = rport->dd_data; | ||
738 | if (port) | ||
739 | els_fc_job->els.d_id = port->d_id; | ||
740 | read_unlock_irq(&zfcp_data.config_lock); | ||
741 | if (!port) { | ||
742 | kfree(els_fc_job); | ||
743 | return -EINVAL; | ||
744 | } | ||
745 | } else { | ||
746 | port_did = job->request->rqst_data.h_els.port_id; | ||
747 | els_fc_job->els.d_id = (port_did[0] << 16) + | ||
748 | (port_did[1] << 8) + port_did[2]; | ||
749 | } | ||
750 | |||
751 | els_fc_job->els.req = job->request_payload.sg_list; | ||
752 | els_fc_job->els.resp = job->reply_payload.sg_list; | ||
753 | els_fc_job->els.handler = zfcp_fc_generic_els_handler; | ||
754 | els_fc_job->els.handler_data = (unsigned long) els_fc_job; | ||
755 | els_fc_job->job = job; | ||
756 | |||
757 | return zfcp_fsf_send_els(&els_fc_job->els); | ||
758 | } | ||
759 | |||
760 | struct zfcp_ct_fc_job { | ||
761 | struct zfcp_send_ct ct; | ||
762 | struct fc_bsg_job *job; | ||
763 | }; | ||
764 | |||
765 | static void zfcp_fc_generic_ct_handler(unsigned long data) | ||
766 | { | ||
767 | struct zfcp_ct_fc_job *ct_fc_job = (struct zfcp_ct_fc_job *) data; | ||
768 | struct fc_bsg_job *job = ct_fc_job->job; | ||
769 | |||
770 | job->reply->reply_data.ctels_reply.status = ct_fc_job->ct.status ? | ||
771 | FC_CTELS_STATUS_REJECT : FC_CTELS_STATUS_OK; | ||
772 | job->reply->reply_payload_rcv_len = job->reply_payload.payload_len; | ||
773 | job->state_flags = FC_RQST_STATE_DONE; | ||
774 | job->job_done(job); | ||
775 | |||
776 | zfcp_wka_port_put(ct_fc_job->ct.wka_port); | ||
777 | |||
778 | kfree(ct_fc_job); | ||
779 | } | ||
780 | |||
781 | int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) | ||
782 | { | ||
783 | int ret; | ||
784 | u8 gs_type; | ||
785 | struct fc_rport *rport = job->rport; | ||
786 | struct Scsi_Host *shost; | ||
787 | struct zfcp_adapter *adapter; | ||
788 | struct zfcp_ct_fc_job *ct_fc_job; | ||
789 | u32 preamble_word1; | ||
790 | |||
791 | shost = rport ? rport_to_shost(rport) : job->shost; | ||
792 | |||
793 | adapter = (struct zfcp_adapter *)shost->hostdata[0]; | ||
794 | if (!(atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN)) | ||
795 | return -EINVAL; | ||
796 | |||
797 | ct_fc_job = kzalloc(sizeof(struct zfcp_ct_fc_job), GFP_KERNEL); | ||
798 | if (!ct_fc_job) | ||
799 | return -ENOMEM; | ||
800 | |||
801 | preamble_word1 = job->request->rqst_data.r_ct.preamble_word1; | ||
802 | gs_type = (preamble_word1 & 0xff000000) >> 24; | ||
803 | |||
804 | switch (gs_type) { | ||
805 | case FC_FST_ALIAS: | ||
806 | ct_fc_job->ct.wka_port = &adapter->gs->as; | ||
807 | break; | ||
808 | case FC_FST_MGMT: | ||
809 | ct_fc_job->ct.wka_port = &adapter->gs->ms; | ||
810 | break; | ||
811 | case FC_FST_TIME: | ||
812 | ct_fc_job->ct.wka_port = &adapter->gs->ts; | ||
813 | break; | ||
814 | case FC_FST_DIR: | ||
815 | ct_fc_job->ct.wka_port = &adapter->gs->ds; | ||
816 | break; | ||
817 | default: | ||
818 | kfree(ct_fc_job); | ||
819 | return -EINVAL; /* no such service */ | ||
820 | } | ||
821 | |||
822 | ret = zfcp_wka_port_get(ct_fc_job->ct.wka_port); | ||
823 | if (ret) { | ||
824 | kfree(ct_fc_job); | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | ct_fc_job->ct.req = job->request_payload.sg_list; | ||
829 | ct_fc_job->ct.resp = job->reply_payload.sg_list; | ||
830 | ct_fc_job->ct.timeout = ZFCP_FSF_REQUEST_TIMEOUT; | ||
831 | ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler; | ||
832 | ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job; | ||
833 | ct_fc_job->ct.completion = NULL; | ||
834 | ct_fc_job->job = job; | ||
835 | |||
836 | ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL, NULL); | ||
837 | if (ret) { | ||
838 | kfree(ct_fc_job); | ||
839 | zfcp_wka_port_put(ct_fc_job->ct.wka_port); | ||
840 | } | ||
841 | return ret; | ||
842 | } | ||
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 74dee32afba8..c57658f3d34f 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -526,6 +526,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) | |||
526 | break; | 526 | break; |
527 | case FSF_TOPO_AL: | 527 | case FSF_TOPO_AL: |
528 | fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; | 528 | fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; |
529 | /* fall through */ | ||
529 | default: | 530 | default: |
530 | dev_err(&adapter->ccw_device->dev, | 531 | dev_err(&adapter->ccw_device->dev, |
531 | "Unknown or unsupported arbitrated loop " | 532 | "Unknown or unsupported arbitrated loop " |
@@ -897,6 +898,7 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) | |||
897 | switch (fsq->word[0]) { | 898 | switch (fsq->word[0]) { |
898 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: | 899 | case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: |
899 | zfcp_test_link(unit->port); | 900 | zfcp_test_link(unit->port); |
901 | /* fall through */ | ||
900 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: | 902 | case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: |
901 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 903 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
902 | break; | 904 | break; |
@@ -993,6 +995,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) | |||
993 | break; | 995 | break; |
994 | case FSF_PORT_HANDLE_NOT_VALID: | 996 | case FSF_PORT_HANDLE_NOT_VALID: |
995 | zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req); | 997 | zfcp_erp_adapter_reopen(adapter, 0, "fsscth1", req); |
998 | /* fall through */ | ||
996 | case FSF_GENERIC_COMMAND_REJECTED: | 999 | case FSF_GENERIC_COMMAND_REJECTED: |
997 | case FSF_PAYLOAD_SIZE_MISMATCH: | 1000 | case FSF_PAYLOAD_SIZE_MISMATCH: |
998 | case FSF_REQUEST_SIZE_TOO_LARGE: | 1001 | case FSF_REQUEST_SIZE_TOO_LARGE: |
@@ -1143,7 +1146,8 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) | |||
1143 | case FSF_RESPONSE_SIZE_TOO_LARGE: | 1146 | case FSF_RESPONSE_SIZE_TOO_LARGE: |
1144 | break; | 1147 | break; |
1145 | case FSF_ACCESS_DENIED: | 1148 | case FSF_ACCESS_DENIED: |
1146 | zfcp_fsf_access_denied_port(req, port); | 1149 | if (port) |
1150 | zfcp_fsf_access_denied_port(req, port); | ||
1147 | break; | 1151 | break; |
1148 | case FSF_SBAL_MISMATCH: | 1152 | case FSF_SBAL_MISMATCH: |
1149 | /* should never occure, avoided in zfcp_fsf_send_els */ | 1153 | /* should never occure, avoided in zfcp_fsf_send_els */ |
@@ -1399,7 +1403,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) | |||
1399 | struct fsf_plogi *plogi; | 1403 | struct fsf_plogi *plogi; |
1400 | 1404 | ||
1401 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) | 1405 | if (req->status & ZFCP_STATUS_FSFREQ_ERROR) |
1402 | return; | 1406 | goto out; |
1403 | 1407 | ||
1404 | switch (header->fsf_status) { | 1408 | switch (header->fsf_status) { |
1405 | case FSF_PORT_ALREADY_OPEN: | 1409 | case FSF_PORT_ALREADY_OPEN: |
@@ -1461,6 +1465,9 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) | |||
1461 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1465 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1462 | break; | 1466 | break; |
1463 | } | 1467 | } |
1468 | |||
1469 | out: | ||
1470 | zfcp_port_put(port); | ||
1464 | } | 1471 | } |
1465 | 1472 | ||
1466 | /** | 1473 | /** |
@@ -1473,6 +1480,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) | |||
1473 | struct qdio_buffer_element *sbale; | 1480 | struct qdio_buffer_element *sbale; |
1474 | struct zfcp_adapter *adapter = erp_action->adapter; | 1481 | struct zfcp_adapter *adapter = erp_action->adapter; |
1475 | struct zfcp_fsf_req *req; | 1482 | struct zfcp_fsf_req *req; |
1483 | struct zfcp_port *port = erp_action->port; | ||
1476 | int retval = -EIO; | 1484 | int retval = -EIO; |
1477 | 1485 | ||
1478 | spin_lock_bh(&adapter->req_q_lock); | 1486 | spin_lock_bh(&adapter->req_q_lock); |
@@ -1493,16 +1501,18 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) | |||
1493 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; | 1501 | sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; |
1494 | 1502 | ||
1495 | req->handler = zfcp_fsf_open_port_handler; | 1503 | req->handler = zfcp_fsf_open_port_handler; |
1496 | req->qtcb->bottom.support.d_id = erp_action->port->d_id; | 1504 | req->qtcb->bottom.support.d_id = port->d_id; |
1497 | req->data = erp_action->port; | 1505 | req->data = port; |
1498 | req->erp_action = erp_action; | 1506 | req->erp_action = erp_action; |
1499 | erp_action->fsf_req = req; | 1507 | erp_action->fsf_req = req; |
1508 | zfcp_port_get(port); | ||
1500 | 1509 | ||
1501 | zfcp_fsf_start_erp_timer(req); | 1510 | zfcp_fsf_start_erp_timer(req); |
1502 | retval = zfcp_fsf_req_send(req); | 1511 | retval = zfcp_fsf_req_send(req); |
1503 | if (retval) { | 1512 | if (retval) { |
1504 | zfcp_fsf_req_free(req); | 1513 | zfcp_fsf_req_free(req); |
1505 | erp_action->fsf_req = NULL; | 1514 | erp_action->fsf_req = NULL; |
1515 | zfcp_port_put(port); | ||
1506 | } | 1516 | } |
1507 | out: | 1517 | out: |
1508 | spin_unlock_bh(&adapter->req_q_lock); | 1518 | spin_unlock_bh(&adapter->req_q_lock); |
@@ -1590,8 +1600,10 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) | |||
1590 | case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: | 1600 | case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: |
1591 | dev_warn(&req->adapter->ccw_device->dev, | 1601 | dev_warn(&req->adapter->ccw_device->dev, |
1592 | "Opening WKA port 0x%x failed\n", wka_port->d_id); | 1602 | "Opening WKA port 0x%x failed\n", wka_port->d_id); |
1603 | /* fall through */ | ||
1593 | case FSF_ADAPTER_STATUS_AVAILABLE: | 1604 | case FSF_ADAPTER_STATUS_AVAILABLE: |
1594 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 1605 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
1606 | /* fall through */ | ||
1595 | case FSF_ACCESS_DENIED: | 1607 | case FSF_ACCESS_DENIED: |
1596 | wka_port->status = ZFCP_WKA_PORT_OFFLINE; | 1608 | wka_port->status = ZFCP_WKA_PORT_OFFLINE; |
1597 | break; | 1609 | break; |
@@ -1876,7 +1888,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) | |||
1876 | 1888 | ||
1877 | if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && | 1889 | if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && |
1878 | (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) && | 1890 | (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) && |
1879 | (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) { | 1891 | !zfcp_ccw_priv_sch(adapter)) { |
1880 | exclusive = (bottom->lun_access_info & | 1892 | exclusive = (bottom->lun_access_info & |
1881 | FSF_UNIT_ACCESS_EXCLUSIVE); | 1893 | FSF_UNIT_ACCESS_EXCLUSIVE); |
1882 | readwrite = (bottom->lun_access_info & | 1894 | readwrite = (bottom->lun_access_info & |
@@ -2314,7 +2326,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, | |||
2314 | { | 2326 | { |
2315 | struct zfcp_fsf_req *req; | 2327 | struct zfcp_fsf_req *req; |
2316 | struct fcp_cmnd_iu *fcp_cmnd_iu; | 2328 | struct fcp_cmnd_iu *fcp_cmnd_iu; |
2317 | unsigned int sbtype; | 2329 | unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; |
2318 | int real_bytes, retval = -EIO; | 2330 | int real_bytes, retval = -EIO; |
2319 | struct zfcp_adapter *adapter = unit->port->adapter; | 2331 | struct zfcp_adapter *adapter = unit->port->adapter; |
2320 | 2332 | ||
@@ -2356,11 +2368,9 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, | |||
2356 | switch (scsi_cmnd->sc_data_direction) { | 2368 | switch (scsi_cmnd->sc_data_direction) { |
2357 | case DMA_NONE: | 2369 | case DMA_NONE: |
2358 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; | 2370 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; |
2359 | sbtype = SBAL_FLAGS0_TYPE_READ; | ||
2360 | break; | 2371 | break; |
2361 | case DMA_FROM_DEVICE: | 2372 | case DMA_FROM_DEVICE: |
2362 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; | 2373 | req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; |
2363 | sbtype = SBAL_FLAGS0_TYPE_READ; | ||
2364 | fcp_cmnd_iu->rddata = 1; | 2374 | fcp_cmnd_iu->rddata = 1; |
2365 | break; | 2375 | break; |
2366 | case DMA_TO_DEVICE: | 2376 | case DMA_TO_DEVICE: |
@@ -2369,8 +2379,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, | |||
2369 | fcp_cmnd_iu->wddata = 1; | 2379 | fcp_cmnd_iu->wddata = 1; |
2370 | break; | 2380 | break; |
2371 | case DMA_BIDIRECTIONAL: | 2381 | case DMA_BIDIRECTIONAL: |
2372 | default: | ||
2373 | retval = -EIO; | ||
2374 | goto failed_scsi_cmnd; | 2382 | goto failed_scsi_cmnd; |
2375 | } | 2383 | } |
2376 | 2384 | ||
@@ -2394,9 +2402,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, | |||
2394 | scsi_sglist(scsi_cmnd), | 2402 | scsi_sglist(scsi_cmnd), |
2395 | FSF_MAX_SBALS_PER_REQ); | 2403 | FSF_MAX_SBALS_PER_REQ); |
2396 | if (unlikely(real_bytes < 0)) { | 2404 | if (unlikely(real_bytes < 0)) { |
2397 | if (req->sbal_number < FSF_MAX_SBALS_PER_REQ) | 2405 | if (req->sbal_number >= FSF_MAX_SBALS_PER_REQ) { |
2398 | retval = -EIO; | ||
2399 | else { | ||
2400 | dev_err(&adapter->ccw_device->dev, | 2406 | dev_err(&adapter->ccw_device->dev, |
2401 | "Oversize data package, unit 0x%016Lx " | 2407 | "Oversize data package, unit 0x%016Lx " |
2402 | "on port 0x%016Lx closed\n", | 2408 | "on port 0x%016Lx closed\n", |
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index e8fbeaeb5fbf..967ede73f4c5 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -12,6 +12,10 @@ | |||
12 | #include "zfcp_ext.h" | 12 | #include "zfcp_ext.h" |
13 | #include <asm/atomic.h> | 13 | #include <asm/atomic.h> |
14 | 14 | ||
15 | static unsigned int default_depth = 32; | ||
16 | module_param_named(queue_depth, default_depth, uint, 0600); | ||
17 | MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices"); | ||
18 | |||
15 | /* Find start of Sense Information in FCP response unit*/ | 19 | /* Find start of Sense Information in FCP response unit*/ |
16 | char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) | 20 | char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) |
17 | { | 21 | { |
@@ -24,6 +28,12 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) | |||
24 | return fcp_sns_info_ptr; | 28 | return fcp_sns_info_ptr; |
25 | } | 29 | } |
26 | 30 | ||
31 | static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth) | ||
32 | { | ||
33 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | ||
34 | return sdev->queue_depth; | ||
35 | } | ||
36 | |||
27 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) | 37 | static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) |
28 | { | 38 | { |
29 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; | 39 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; |
@@ -34,7 +44,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) | |||
34 | static int zfcp_scsi_slave_configure(struct scsi_device *sdp) | 44 | static int zfcp_scsi_slave_configure(struct scsi_device *sdp) |
35 | { | 45 | { |
36 | if (sdp->tagged_supported) | 46 | if (sdp->tagged_supported) |
37 | scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, 32); | 47 | scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, default_depth); |
38 | else | 48 | else |
39 | scsi_adjust_queue_depth(sdp, 0, 1); | 49 | scsi_adjust_queue_depth(sdp, 0, 1); |
40 | return 0; | 50 | return 0; |
@@ -613,6 +623,20 @@ void zfcp_scsi_scan(struct work_struct *work) | |||
613 | zfcp_unit_put(unit); | 623 | zfcp_unit_put(unit); |
614 | } | 624 | } |
615 | 625 | ||
626 | static int zfcp_execute_fc_job(struct fc_bsg_job *job) | ||
627 | { | ||
628 | switch (job->request->msgcode) { | ||
629 | case FC_BSG_RPT_ELS: | ||
630 | case FC_BSG_HST_ELS_NOLOGIN: | ||
631 | return zfcp_fc_execute_els_fc_job(job); | ||
632 | case FC_BSG_RPT_CT: | ||
633 | case FC_BSG_HST_CT: | ||
634 | return zfcp_fc_execute_ct_fc_job(job); | ||
635 | default: | ||
636 | return -EINVAL; | ||
637 | } | ||
638 | } | ||
639 | |||
616 | struct fc_function_template zfcp_transport_functions = { | 640 | struct fc_function_template zfcp_transport_functions = { |
617 | .show_starget_port_id = 1, | 641 | .show_starget_port_id = 1, |
618 | .show_starget_port_name = 1, | 642 | .show_starget_port_name = 1, |
@@ -634,6 +658,7 @@ struct fc_function_template zfcp_transport_functions = { | |||
634 | .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, | 658 | .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, |
635 | .terminate_rport_io = zfcp_scsi_terminate_rport_io, | 659 | .terminate_rport_io = zfcp_scsi_terminate_rport_io, |
636 | .show_host_port_state = 1, | 660 | .show_host_port_state = 1, |
661 | .bsg_request = zfcp_execute_fc_job, | ||
637 | /* no functions registered for following dynamic attributes but | 662 | /* no functions registered for following dynamic attributes but |
638 | directly set by LLDD */ | 663 | directly set by LLDD */ |
639 | .show_host_port_type = 1, | 664 | .show_host_port_type = 1, |
@@ -647,6 +672,7 @@ struct zfcp_data zfcp_data = { | |||
647 | .name = "zfcp", | 672 | .name = "zfcp", |
648 | .module = THIS_MODULE, | 673 | .module = THIS_MODULE, |
649 | .proc_name = "zfcp", | 674 | .proc_name = "zfcp", |
675 | .change_queue_depth = zfcp_scsi_change_queue_depth, | ||
650 | .slave_alloc = zfcp_scsi_slave_alloc, | 676 | .slave_alloc = zfcp_scsi_slave_alloc, |
651 | .slave_configure = zfcp_scsi_slave_configure, | 677 | .slave_configure = zfcp_scsi_slave_configure, |
652 | .slave_destroy = zfcp_scsi_slave_destroy, | 678 | .slave_destroy = zfcp_scsi_slave_destroy, |