aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2013-01-30 04:26:14 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-07-01 11:31:20 -0400
commita2ace46632fb38c7a3771f2f0d235a4295e83bcf (patch)
tree3d69366b49c18967fda51cb6b0355148f91f7d6f /drivers/s390/block
parent1fbdb8be9bfc91efd45720493c7ecae884ae22bd (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.c76
-rw-r--r--drivers/s390/block/dasd_diag.c5
-rw-r--r--drivers/s390/block/dasd_eckd.c4
-rw-r--r--drivers/s390/block/dasd_fba.c5
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 */
2876enum 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 */
2867static int dasd_alloc_queue(struct dasd_block *block) 2943static 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
584static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr) 584static 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
2382static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) 2382static 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
429static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr) 429static 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
434static int 437static int