Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2ace466 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Martin Schwidefsky
Browse files

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: default avatarHannes Reinecke <hare@suse.de>
Acked-by: default avatarStefan Weinhuber <wein@de.ibm.com>
Signed-off-by: default avatarStefan Weinhuber <wein@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 1fbdb8be
Loading
Loading
Loading
Loading
+76 −0
Original line number Diff line number Diff line
@@ -2573,8 +2573,10 @@ static void __dasd_process_request_queue(struct dasd_block *block)
		 */
		cqr->callback_data = (void *) req;
		cqr->status = DASD_CQR_FILLED;
		req->completion_data = cqr;
		blk_start_request(req);
		list_add_tail(&cqr->blocklist, &block->ccw_queue);
		INIT_LIST_HEAD(&cqr->devlist);
		dasd_profile_start(block, cqr, req);
	}
}
@@ -2861,6 +2863,80 @@ static void do_dasd_request(struct request_queue *queue)
	spin_unlock(&block->queue_lock);
}

/*
 * Block timeout callback, called from the block layer
 *
 * request_queue lock is held on entry.
 *
 * Return values:
 * BLK_EH_RESET_TIMER if the request should be left running
 * BLK_EH_NOT_HANDLED if the request is handled or terminated
 *		      by the driver.
 */
enum blk_eh_timer_return dasd_times_out(struct request *req)
{
	struct dasd_ccw_req *cqr = req->completion_data;
	struct dasd_block *block = req->q->queuedata;
	struct dasd_device *device;
	int rc = 0;

	if (!cqr)
		return BLK_EH_NOT_HANDLED;

	device = cqr->startdev ? cqr->startdev : block->base;
	DBF_DEV_EVENT(DBF_WARNING, device,
		      " dasd_times_out cqr %p status %x",
		      cqr, cqr->status);

	spin_lock(&block->queue_lock);
	spin_lock(get_ccwdev_lock(device->cdev));
	cqr->retries = -1;
	cqr->intrc = -ETIMEDOUT;
	if (cqr->status >= DASD_CQR_QUEUED) {
		spin_unlock(get_ccwdev_lock(device->cdev));
		rc = dasd_cancel_req(cqr);
	} else if (cqr->status == DASD_CQR_FILLED ||
		   cqr->status == DASD_CQR_NEED_ERP) {
		cqr->status = DASD_CQR_TERMINATED;
		spin_unlock(get_ccwdev_lock(device->cdev));
	} else if (cqr->status == DASD_CQR_IN_ERP) {
		struct dasd_ccw_req *searchcqr, *nextcqr, *tmpcqr;

		list_for_each_entry_safe(searchcqr, nextcqr,
					 &block->ccw_queue, blocklist) {
			tmpcqr = searchcqr;
			while (tmpcqr->refers)
				tmpcqr = tmpcqr->refers;
			if (tmpcqr != cqr)
				continue;
			/* searchcqr is an ERP request for cqr */
			searchcqr->retries = -1;
			searchcqr->intrc = -ETIMEDOUT;
			if (searchcqr->status >= DASD_CQR_QUEUED) {
				spin_unlock(get_ccwdev_lock(device->cdev));
				rc = dasd_cancel_req(searchcqr);
				spin_lock(get_ccwdev_lock(device->cdev));
			} else if ((searchcqr->status == DASD_CQR_FILLED) ||
				   (searchcqr->status == DASD_CQR_NEED_ERP)) {
				searchcqr->status = DASD_CQR_TERMINATED;
				rc = 0;
			} else if (searchcqr->status == DASD_CQR_IN_ERP) {
				/*
				 * Shouldn't happen; most recent ERP
				 * request is at the front of queue
				 */
				continue;
			}
			break;
		}
		spin_unlock(get_ccwdev_lock(device->cdev));
	}
	dasd_schedule_block_bh(block);
	spin_unlock(&block->queue_lock);

	return rc ? BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED;
}

/*
 * Allocate and initialize request queue and default I/O scheduler.
 */
+4 −1
Original line number Diff line number Diff line
@@ -583,6 +583,9 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)

static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
{
	if (cqr->retries < 0)
		cqr->status = DASD_CQR_FAILED;
	else
		cqr->status = DASD_CQR_FILLED;
};

+4 −0
Original line number Diff line number Diff line
@@ -2381,6 +2381,10 @@ dasd_eckd_format_device(struct dasd_device *base,

static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
{
	if (cqr->retries < 0) {
		cqr->status = DASD_CQR_FAILED;
		return;
	}
	cqr->status = DASD_CQR_FILLED;
	if (cqr->block && (cqr->startdev != cqr->block->base)) {
		dasd_eckd_reset_ccw_to_base_io(cqr);
+4 −1
Original line number Diff line number Diff line
@@ -428,6 +428,9 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)

static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
{
	if (cqr->retries < 0)
		cqr->status = DASD_CQR_FAILED;
	else
		cqr->status = DASD_CQR_FILLED;
};