diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 73 |
1 files changed, 60 insertions, 13 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ab84da5592e8..0483b2e76b11 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -82,6 +82,14 @@ static struct ccw_driver dasd_eckd_driver; /* see below */ | |||
82 | #define INIT_CQR_UNFORMATTED 1 | 82 | #define INIT_CQR_UNFORMATTED 1 |
83 | #define INIT_CQR_ERROR 2 | 83 | #define INIT_CQR_ERROR 2 |
84 | 84 | ||
85 | /* emergency request for reserve/release */ | ||
86 | static struct { | ||
87 | struct dasd_ccw_req cqr; | ||
88 | struct ccw1 ccw; | ||
89 | char data[32]; | ||
90 | } *dasd_reserve_req; | ||
91 | static DEFINE_MUTEX(dasd_reserve_mutex); | ||
92 | |||
85 | 93 | ||
86 | /* initial attempt at a probe function. this can be simplified once | 94 | /* initial attempt at a probe function. this can be simplified once |
87 | * the other detection code is gone */ | 95 | * the other detection code is gone */ |
@@ -2645,15 +2653,23 @@ dasd_eckd_release(struct dasd_device *device) | |||
2645 | struct dasd_ccw_req *cqr; | 2653 | struct dasd_ccw_req *cqr; |
2646 | int rc; | 2654 | int rc; |
2647 | struct ccw1 *ccw; | 2655 | struct ccw1 *ccw; |
2656 | int useglobal; | ||
2648 | 2657 | ||
2649 | if (!capable(CAP_SYS_ADMIN)) | 2658 | if (!capable(CAP_SYS_ADMIN)) |
2650 | return -EACCES; | 2659 | return -EACCES; |
2651 | 2660 | ||
2661 | useglobal = 0; | ||
2652 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); | 2662 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); |
2653 | if (IS_ERR(cqr)) { | 2663 | if (IS_ERR(cqr)) { |
2654 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | 2664 | mutex_lock(&dasd_reserve_mutex); |
2655 | "Could not allocate initialization request"); | 2665 | useglobal = 1; |
2656 | return PTR_ERR(cqr); | 2666 | cqr = &dasd_reserve_req->cqr; |
2667 | memset(cqr, 0, sizeof(*cqr)); | ||
2668 | memset(&dasd_reserve_req->ccw, 0, | ||
2669 | sizeof(dasd_reserve_req->ccw)); | ||
2670 | cqr->cpaddr = &dasd_reserve_req->ccw; | ||
2671 | cqr->data = &dasd_reserve_req->data; | ||
2672 | cqr->magic = DASD_ECKD_MAGIC; | ||
2657 | } | 2673 | } |
2658 | ccw = cqr->cpaddr; | 2674 | ccw = cqr->cpaddr; |
2659 | ccw->cmd_code = DASD_ECKD_CCW_RELEASE; | 2675 | ccw->cmd_code = DASD_ECKD_CCW_RELEASE; |
@@ -2671,7 +2687,10 @@ dasd_eckd_release(struct dasd_device *device) | |||
2671 | 2687 | ||
2672 | rc = dasd_sleep_on_immediatly(cqr); | 2688 | rc = dasd_sleep_on_immediatly(cqr); |
2673 | 2689 | ||
2674 | dasd_sfree_request(cqr, cqr->memdev); | 2690 | if (useglobal) |
2691 | mutex_unlock(&dasd_reserve_mutex); | ||
2692 | else | ||
2693 | dasd_sfree_request(cqr, cqr->memdev); | ||
2675 | return rc; | 2694 | return rc; |
2676 | } | 2695 | } |
2677 | 2696 | ||
@@ -2687,15 +2706,23 @@ dasd_eckd_reserve(struct dasd_device *device) | |||
2687 | struct dasd_ccw_req *cqr; | 2706 | struct dasd_ccw_req *cqr; |
2688 | int rc; | 2707 | int rc; |
2689 | struct ccw1 *ccw; | 2708 | struct ccw1 *ccw; |
2709 | int useglobal; | ||
2690 | 2710 | ||
2691 | if (!capable(CAP_SYS_ADMIN)) | 2711 | if (!capable(CAP_SYS_ADMIN)) |
2692 | return -EACCES; | 2712 | return -EACCES; |
2693 | 2713 | ||
2714 | useglobal = 0; | ||
2694 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); | 2715 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); |
2695 | if (IS_ERR(cqr)) { | 2716 | if (IS_ERR(cqr)) { |
2696 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | 2717 | mutex_lock(&dasd_reserve_mutex); |
2697 | "Could not allocate initialization request"); | 2718 | useglobal = 1; |
2698 | return PTR_ERR(cqr); | 2719 | cqr = &dasd_reserve_req->cqr; |
2720 | memset(cqr, 0, sizeof(*cqr)); | ||
2721 | memset(&dasd_reserve_req->ccw, 0, | ||
2722 | sizeof(dasd_reserve_req->ccw)); | ||
2723 | cqr->cpaddr = &dasd_reserve_req->ccw; | ||
2724 | cqr->data = &dasd_reserve_req->data; | ||
2725 | cqr->magic = DASD_ECKD_MAGIC; | ||
2699 | } | 2726 | } |
2700 | ccw = cqr->cpaddr; | 2727 | ccw = cqr->cpaddr; |
2701 | ccw->cmd_code = DASD_ECKD_CCW_RESERVE; | 2728 | ccw->cmd_code = DASD_ECKD_CCW_RESERVE; |
@@ -2713,7 +2740,10 @@ dasd_eckd_reserve(struct dasd_device *device) | |||
2713 | 2740 | ||
2714 | rc = dasd_sleep_on_immediatly(cqr); | 2741 | rc = dasd_sleep_on_immediatly(cqr); |
2715 | 2742 | ||
2716 | dasd_sfree_request(cqr, cqr->memdev); | 2743 | if (useglobal) |
2744 | mutex_unlock(&dasd_reserve_mutex); | ||
2745 | else | ||
2746 | dasd_sfree_request(cqr, cqr->memdev); | ||
2717 | return rc; | 2747 | return rc; |
2718 | } | 2748 | } |
2719 | 2749 | ||
@@ -2728,15 +2758,23 @@ dasd_eckd_steal_lock(struct dasd_device *device) | |||
2728 | struct dasd_ccw_req *cqr; | 2758 | struct dasd_ccw_req *cqr; |
2729 | int rc; | 2759 | int rc; |
2730 | struct ccw1 *ccw; | 2760 | struct ccw1 *ccw; |
2761 | int useglobal; | ||
2731 | 2762 | ||
2732 | if (!capable(CAP_SYS_ADMIN)) | 2763 | if (!capable(CAP_SYS_ADMIN)) |
2733 | return -EACCES; | 2764 | return -EACCES; |
2734 | 2765 | ||
2766 | useglobal = 0; | ||
2735 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); | 2767 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); |
2736 | if (IS_ERR(cqr)) { | 2768 | if (IS_ERR(cqr)) { |
2737 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | 2769 | mutex_lock(&dasd_reserve_mutex); |
2738 | "Could not allocate initialization request"); | 2770 | useglobal = 1; |
2739 | return PTR_ERR(cqr); | 2771 | cqr = &dasd_reserve_req->cqr; |
2772 | memset(cqr, 0, sizeof(*cqr)); | ||
2773 | memset(&dasd_reserve_req->ccw, 0, | ||
2774 | sizeof(dasd_reserve_req->ccw)); | ||
2775 | cqr->cpaddr = &dasd_reserve_req->ccw; | ||
2776 | cqr->data = &dasd_reserve_req->data; | ||
2777 | cqr->magic = DASD_ECKD_MAGIC; | ||
2740 | } | 2778 | } |
2741 | ccw = cqr->cpaddr; | 2779 | ccw = cqr->cpaddr; |
2742 | ccw->cmd_code = DASD_ECKD_CCW_SLCK; | 2780 | ccw->cmd_code = DASD_ECKD_CCW_SLCK; |
@@ -2754,7 +2792,10 @@ dasd_eckd_steal_lock(struct dasd_device *device) | |||
2754 | 2792 | ||
2755 | rc = dasd_sleep_on_immediatly(cqr); | 2793 | rc = dasd_sleep_on_immediatly(cqr); |
2756 | 2794 | ||
2757 | dasd_sfree_request(cqr, cqr->memdev); | 2795 | if (useglobal) |
2796 | mutex_unlock(&dasd_reserve_mutex); | ||
2797 | else | ||
2798 | dasd_sfree_request(cqr, cqr->memdev); | ||
2758 | return rc; | 2799 | return rc; |
2759 | } | 2800 | } |
2760 | 2801 | ||
@@ -3488,10 +3529,15 @@ dasd_eckd_init(void) | |||
3488 | int ret; | 3529 | int ret; |
3489 | 3530 | ||
3490 | ASCEBC(dasd_eckd_discipline.ebcname, 4); | 3531 | ASCEBC(dasd_eckd_discipline.ebcname, 4); |
3532 | dasd_reserve_req = kmalloc(sizeof(*dasd_reserve_req), | ||
3533 | GFP_KERNEL | GFP_DMA); | ||
3534 | if (!dasd_reserve_req) | ||
3535 | return -ENOMEM; | ||
3491 | ret = ccw_driver_register(&dasd_eckd_driver); | 3536 | ret = ccw_driver_register(&dasd_eckd_driver); |
3492 | if (!ret) | 3537 | if (!ret) |
3493 | wait_for_device_probe(); | 3538 | wait_for_device_probe(); |
3494 | 3539 | else | |
3540 | kfree(dasd_reserve_req); | ||
3495 | return ret; | 3541 | return ret; |
3496 | } | 3542 | } |
3497 | 3543 | ||
@@ -3499,6 +3545,7 @@ static void __exit | |||
3499 | dasd_eckd_cleanup(void) | 3545 | dasd_eckd_cleanup(void) |
3500 | { | 3546 | { |
3501 | ccw_driver_unregister(&dasd_eckd_driver); | 3547 | ccw_driver_unregister(&dasd_eckd_driver); |
3548 | kfree(dasd_reserve_req); | ||
3502 | } | 3549 | } |
3503 | 3550 | ||
3504 | module_init(dasd_eckd_init); | 3551 | module_init(dasd_eckd_init); |