diff options
author | Hannes Reinecke <hare@suse.de> | 2013-01-30 04:26:14 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-07-01 11:31:20 -0400 |
commit | a2ace46632fb38c7a3771f2f0d235a4295e83bcf (patch) | |
tree | 3d69366b49c18967fda51cb6b0355148f91f7d6f /drivers/s390/block | |
parent | 1fbdb8be9bfc91efd45720493c7ecae884ae22bd (diff) |
s390/dasd: Implement block timeout handling
This patch implements generic block layer timeout handling
callbacks for DASDs. When the timeout expires the respective
cqr is aborted.
With this timeout handler time-critical request abort
is guaranteed as the abort does not depend on the internal
state of the various DASD driver queues.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Acked-by: Stefan Weinhuber <wein@de.ibm.com>
Signed-off-by: Stefan Weinhuber <wein@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block')
-rw-r--r-- | drivers/s390/block/dasd.c | 76 | ||||
-rw-r--r-- | drivers/s390/block/dasd_diag.c | 5 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd_fba.c | 5 |
4 files changed, 88 insertions, 2 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 000e5140bda4..87478becedb0 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -2573,8 +2573,10 @@ static void __dasd_process_request_queue(struct dasd_block *block) | |||
2573 | */ | 2573 | */ |
2574 | cqr->callback_data = (void *) req; | 2574 | cqr->callback_data = (void *) req; |
2575 | cqr->status = DASD_CQR_FILLED; | 2575 | cqr->status = DASD_CQR_FILLED; |
2576 | req->completion_data = cqr; | ||
2576 | blk_start_request(req); | 2577 | blk_start_request(req); |
2577 | list_add_tail(&cqr->blocklist, &block->ccw_queue); | 2578 | list_add_tail(&cqr->blocklist, &block->ccw_queue); |
2579 | INIT_LIST_HEAD(&cqr->devlist); | ||
2578 | dasd_profile_start(block, cqr, req); | 2580 | dasd_profile_start(block, cqr, req); |
2579 | } | 2581 | } |
2580 | } | 2582 | } |
@@ -2862,6 +2864,80 @@ static void do_dasd_request(struct request_queue *queue) | |||
2862 | } | 2864 | } |
2863 | 2865 | ||
2864 | /* | 2866 | /* |
2867 | * Block timeout callback, called from the block layer | ||
2868 | * | ||
2869 | * request_queue lock is held on entry. | ||
2870 | * | ||
2871 | * Return values: | ||
2872 | * BLK_EH_RESET_TIMER if the request should be left running | ||
2873 | * BLK_EH_NOT_HANDLED if the request is handled or terminated | ||
2874 | * by the driver. | ||
2875 | */ | ||
2876 | enum blk_eh_timer_return dasd_times_out(struct request *req) | ||
2877 | { | ||
2878 | struct dasd_ccw_req *cqr = req->completion_data; | ||
2879 | struct dasd_block *block = req->q->queuedata; | ||
2880 | struct dasd_device *device; | ||
2881 | int rc = 0; | ||
2882 | |||
2883 | if (!cqr) | ||
2884 | return BLK_EH_NOT_HANDLED; | ||
2885 | |||
2886 | device = cqr->startdev ? cqr->startdev : block->base; | ||
2887 | DBF_DEV_EVENT(DBF_WARNING, device, | ||
2888 | " dasd_times_out cqr %p status %x", | ||
2889 | cqr, cqr->status); | ||
2890 | |||
2891 | spin_lock(&block->queue_lock); | ||
2892 | spin_lock(get_ccwdev_lock(device->cdev)); | ||
2893 | cqr->retries = -1; | ||
2894 | cqr->intrc = -ETIMEDOUT; | ||
2895 | if (cqr->status >= DASD_CQR_QUEUED) { | ||
2896 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
2897 | rc = dasd_cancel_req(cqr); | ||
2898 | } else if (cqr->status == DASD_CQR_FILLED || | ||
2899 | cqr->status == DASD_CQR_NEED_ERP) { | ||
2900 | cqr->status = DASD_CQR_TERMINATED; | ||
2901 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
2902 | } else if (cqr->status == DASD_CQR_IN_ERP) { | ||
2903 | struct dasd_ccw_req *searchcqr, *nextcqr, *tmpcqr; | ||
2904 | |||
2905 | list_for_each_entry_safe(searchcqr, nextcqr, | ||
2906 | &block->ccw_queue, blocklist) { | ||
2907 | tmpcqr = searchcqr; | ||
2908 | while (tmpcqr->refers) | ||
2909 | tmpcqr = tmpcqr->refers; | ||
2910 | if (tmpcqr != cqr) | ||
2911 | continue; | ||
2912 | /* searchcqr is an ERP request for cqr */ | ||
2913 | searchcqr->retries = -1; | ||
2914 | searchcqr->intrc = -ETIMEDOUT; | ||
2915 | if (searchcqr->status >= DASD_CQR_QUEUED) { | ||
2916 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
2917 | rc = dasd_cancel_req(searchcqr); | ||
2918 | spin_lock(get_ccwdev_lock(device->cdev)); | ||
2919 | } else if ((searchcqr->status == DASD_CQR_FILLED) || | ||
2920 | (searchcqr->status == DASD_CQR_NEED_ERP)) { | ||
2921 | searchcqr->status = DASD_CQR_TERMINATED; | ||
2922 | rc = 0; | ||
2923 | } else if (searchcqr->status == DASD_CQR_IN_ERP) { | ||
2924 | /* | ||
2925 | * Shouldn't happen; most recent ERP | ||
2926 | * request is at the front of queue | ||
2927 | */ | ||
2928 | continue; | ||
2929 | } | ||
2930 | break; | ||
2931 | } | ||
2932 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
2933 | } | ||
2934 | dasd_schedule_block_bh(block); | ||
2935 | spin_unlock(&block->queue_lock); | ||
2936 | |||
2937 | return rc ? BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; | ||
2938 | } | ||
2939 | |||
2940 | /* | ||
2865 | * Allocate and initialize request queue and default I/O scheduler. | 2941 | * Allocate and initialize request queue and default I/O scheduler. |
2866 | */ | 2942 | */ |
2867 | static int dasd_alloc_queue(struct dasd_block *block) | 2943 | static int dasd_alloc_queue(struct dasd_block *block) |
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 154842242c3d..feca317b33de 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c | |||
@@ -583,7 +583,10 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req) | |||
583 | 583 | ||
584 | static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr) | 584 | static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr) |
585 | { | 585 | { |
586 | cqr->status = DASD_CQR_FILLED; | 586 | if (cqr->retries < 0) |
587 | cqr->status = DASD_CQR_FAILED; | ||
588 | else | ||
589 | cqr->status = DASD_CQR_FILLED; | ||
587 | }; | 590 | }; |
588 | 591 | ||
589 | /* Fill in IOCTL data for device. */ | 592 | /* Fill in IOCTL data for device. */ |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 05f5694c9c49..e61a6deea3c0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -2381,6 +2381,10 @@ sleep: | |||
2381 | 2381 | ||
2382 | static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) | 2382 | static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) |
2383 | { | 2383 | { |
2384 | if (cqr->retries < 0) { | ||
2385 | cqr->status = DASD_CQR_FAILED; | ||
2386 | return; | ||
2387 | } | ||
2384 | cqr->status = DASD_CQR_FILLED; | 2388 | cqr->status = DASD_CQR_FILLED; |
2385 | if (cqr->block && (cqr->startdev != cqr->block->base)) { | 2389 | if (cqr->block && (cqr->startdev != cqr->block->base)) { |
2386 | dasd_eckd_reset_ccw_to_base_io(cqr); | 2390 | dasd_eckd_reset_ccw_to_base_io(cqr); |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index d232c83ea95a..9cbc8c32ba59 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -428,7 +428,10 @@ out: | |||
428 | 428 | ||
429 | static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr) | 429 | static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr) |
430 | { | 430 | { |
431 | cqr->status = DASD_CQR_FILLED; | 431 | if (cqr->retries < 0) |
432 | cqr->status = DASD_CQR_FAILED; | ||
433 | else | ||
434 | cqr->status = DASD_CQR_FILLED; | ||
432 | }; | 435 | }; |
433 | 436 | ||
434 | static int | 437 | static int |