ccwreq.c revision 094f2100d6bb16ef0c4f82167cc55173ca22ee93
1e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
2e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *  Handling of internal CCW device requests.
3e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
4e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *    Copyright IBM Corp. 2009
5e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
6e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
7e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
8e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include <linux/types.h>
9e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include <linux/err.h>
10e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include <asm/ccwdev.h>
11e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include <asm/cio.h>
12e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
13e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include "io_sch.h"
14e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include "cio.h"
15e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include "device.h"
16e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include "cio_debug.h"
17e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
18e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
19e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * lpm_adjust - adjust path mask
20e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @lpm: path mask to adjust
21e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @mask: mask of available paths
22e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
23e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Shift @lpm right until @lpm and @mask have at least one bit in common or
24e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * until @lpm is zero. Return the resulting lpm.
25e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
26e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterint lpm_adjust(int lpm, int mask)
27e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
28e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	while (lpm && ((lpm & mask) == 0))
29e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		lpm >>= 1;
30e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return lpm;
31e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
32e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
33e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
34e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Adjust path mask to use next path and reset retry count. Return resulting
35e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * path mask.
36e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
37e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic u16 ccwreq_next_path(struct ccw_device *cdev)
38e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
39e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
40e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
41e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->retries	= req->maxretries;
42e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->mask	= lpm_adjust(req->mask >>= 1, req->lpm);
43e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
44e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return req->mask;
45e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
46e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
47e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
48e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Clean up device state and report to callback.
49e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
50e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic void ccwreq_stop(struct ccw_device *cdev, int rc)
51e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
52e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
53e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
54e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (req->done)
55e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return;
56e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->done = 1;
57e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccw_device_set_timeout(cdev, 0);
58e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	memset(&cdev->private->irb, 0, sizeof(struct irb));
59e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (rc && rc != -ENODEV && req->drc)
60e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		rc = req->drc;
61e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->callback(cdev, req->data, rc);
62e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
63e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
64e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
65e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * (Re-)Start the operation until retries and paths are exhausted.
66e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
67e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic void ccwreq_do(struct ccw_device *cdev)
68e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
69e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
70e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct subchannel *sch = to_subchannel(cdev->dev.parent);
71e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw1 *cp = req->cp;
72e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	int rc = -EACCES;
73e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
74e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	while (req->mask) {
75e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (req->retries-- == 0) {
76e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			/* Retries exhausted, try next path. */
77e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			ccwreq_next_path(cdev);
78e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			continue;
79e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
80e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Perform start function. */
81e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		memset(&cdev->private->irb, 0, sizeof(struct irb));
82de1b04388f63cbddf91d9f6c50c29be7232881caPeter Oberparleiter		rc = cio_start(sch, cp, (u8) req->mask);
83e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (rc == 0) {
84e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			/* I/O started successfully. */
85e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			ccw_device_set_timeout(cdev, req->timeout);
86e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			return;
87e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
88e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (rc == -ENODEV) {
89e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			/* Permanent device error. */
90e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			break;
91e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
92e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (rc == -EACCES) {
93e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			/* Permant path error. */
94e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			ccwreq_next_path(cdev);
95e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			continue;
96e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
97e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Temporary improper status. */
98e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		rc = cio_clear(sch);
99e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (rc)
100e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			break;
101e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return;
102e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
103e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, rc);
104e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
105e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
106e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
107e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_start - perform I/O request
108e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
109e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
110e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Perform the I/O request specified by cdev->req.
111e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
112e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitervoid ccw_request_start(struct ccw_device *cdev)
113e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
114e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
115e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
116de1b04388f63cbddf91d9f6c50c29be7232881caPeter Oberparleiter	/* Try all paths twice to counter link flapping. */
117de1b04388f63cbddf91d9f6c50c29be7232881caPeter Oberparleiter	req->mask	= 0x8080;
118e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->retries	= req->maxretries;
119e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->mask	= lpm_adjust(req->mask, req->lpm);
120e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->drc	= 0;
121e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->done	= 0;
122e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->cancel	= 0;
123e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!req->mask)
124e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_nopath;
125e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_do(cdev);
126e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return;
127e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
128e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterout_nopath:
129e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, -EACCES);
130e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
131e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
132e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
133e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_cancel - cancel running I/O request
134e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
135e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
136e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Cancel the I/O request specified by cdev->req. Return non-zero if request
137e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * has already finished, zero otherwise.
138e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
139e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterint ccw_request_cancel(struct ccw_device *cdev)
140e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
141e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct subchannel *sch = to_subchannel(cdev->dev.parent);
142e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
143e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	int rc;
144e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
145e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (req->done)
146e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return 1;
147e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->cancel = 1;
148e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	rc = cio_clear(sch);
149e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (rc)
150e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		ccwreq_stop(cdev, rc);
151e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return 0;
152e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
153e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
154e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
155e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Return the status of the internal I/O started on the specified ccw device.
156e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Perform BASIC SENSE if required.
157e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
158e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
159e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
160e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct irb *irb = &cdev->private->irb;
161e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct cmd_scsw *scsw = &irb->scsw.cmd;
162094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst	enum uc_todo todo;
163e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
164e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Perform BASIC SENSE if needed. */
165e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (ccw_device_accumulate_and_sense(cdev, lcirb))
166e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_RUNNING;
167e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for halt/clear interrupt. */
168e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
169e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_KILLED;
170e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for path error. */
171e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->cc == 3 || scsw->pno)
172e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_PATH_ERROR;
173e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Handle BASIC SENSE data. */
174e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (irb->esw.esw0.erw.cons) {
175e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		CIO_TRACE_EVENT(2, "sensedata");
176e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		CIO_HEX_EVENT(2, &cdev->private->dev_id,
177e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			      sizeof(struct ccw_dev_id));
178e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT);
179e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Check for command reject. */
180e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (irb->ecw[0] & SNS0_CMD_REJECT)
181e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			return IO_REJECTED;
182094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst		/* Ask the driver what to do */
183094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst		if (cdev->drv && cdev->drv->uc_handler) {
184094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			todo = cdev->drv->uc_handler(cdev, lcirb);
185094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			switch (todo) {
186094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			case UC_TODO_RETRY:
187094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst				return IO_STATUS_ERROR;
188094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			case UC_TODO_RETRY_ON_NEW_PATH:
189094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst				return IO_PATH_ERROR;
190094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			case UC_TODO_STOP:
191094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst				return IO_REJECTED;
192094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			default:
193094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst				return IO_STATUS_ERROR;
194094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			}
195094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst		}
196e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Assume that unexpected SENSE data implies an error. */
197e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_STATUS_ERROR;
198e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
199e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for channel errors. */
200e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->cstat != 0)
201e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_STATUS_ERROR;
202e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for device errors. */
203e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))
204e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_STATUS_ERROR;
205e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for final state. */
206e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!(scsw->dstat & DEV_STAT_DEV_END))
207e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_RUNNING;
208e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for other improper status. */
209e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->cc == 1 && (scsw->stctl & SCSW_STCTL_ALERT_STATUS))
210e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_STATUS_ERROR;
211e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return IO_DONE;
212e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
213e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
214e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
215e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Log ccw request status.
216e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
217e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic void ccwreq_log_status(struct ccw_device *cdev, enum io_status status)
218e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
219e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
220e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct {
221e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		struct ccw_dev_id dev_id;
222e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		u16 retries;
223e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		u8 lpm;
224e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		u8 status;
225e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}  __attribute__ ((packed)) data;
226e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	data.dev_id	= cdev->private->dev_id;
227e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	data.retries	= req->retries;
228de1b04388f63cbddf91d9f6c50c29be7232881caPeter Oberparleiter	data.lpm	= (u8) req->mask;
229e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	data.status	= (u8) status;
230e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	CIO_TRACE_EVENT(2, "reqstat");
231e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	CIO_HEX_EVENT(2, &data, sizeof(data));
232e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
233e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
234e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
235e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_handler - interrupt handler for I/O request procedure.
236e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
237e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
238e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Handle interrupt during I/O request procedure.
239e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
240e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitervoid ccw_request_handler(struct ccw_device *cdev)
241e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
242cbb870c8221147ae337612e04b2bb0211f31a74bHeiko Carstens	struct irb *irb = (struct irb *)&S390_lowcore.irb;
243e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
244e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	enum io_status status;
245e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	int rc = -EOPNOTSUPP;
246e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
247e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check status of I/O request. */
248e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	status = ccwreq_status(cdev, irb);
249e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (req->filter)
250e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		status = req->filter(cdev, req->data, irb, status);
251e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (status != IO_RUNNING)
252e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		ccw_device_set_timeout(cdev, 0);
253e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (status != IO_DONE && status != IO_RUNNING)
254e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		ccwreq_log_status(cdev, status);
255e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	switch (status) {
256e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_DONE:
257e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		break;
258e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_RUNNING:
259e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return;
260e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_REJECTED:
261e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto err;
262e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_PATH_ERROR:
263e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_next_path;
264e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_STATUS_ERROR:
265e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_restart;
266e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_KILLED:
267e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Check if request was cancelled on purpose. */
268e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (req->cancel) {
269e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			rc = -EIO;
270e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			goto err;
271e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
272e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_restart;
273e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
274e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check back with request initiator. */
275e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!req->check)
276e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out;
277e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	switch (req->check(cdev, req->data)) {
278e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case 0:
279e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		break;
280e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case -EAGAIN:
281e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_restart;
282e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case -EACCES:
283e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_next_path;
284e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	default:
285e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto err;
286e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
287e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterout:
288e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, 0);
289e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return;
290e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
291e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterout_next_path:
292e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Try next path and restart I/O. */
293e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!ccwreq_next_path(cdev)) {
294e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		rc = -EACCES;
295e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto err;
296e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
297e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterout_restart:
298e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Restart. */
299e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_do(cdev);
300e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return;
301e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitererr:
302e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, rc);
303e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
304e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
305e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
306e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
307e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_timeout - timeout handler for I/O request procedure
308e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
309e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
310e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Handle timeout during I/O request procedure.
311e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
312e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitervoid ccw_request_timeout(struct ccw_device *cdev)
313e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
314e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct subchannel *sch = to_subchannel(cdev->dev.parent);
315e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
316e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	int rc;
317e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
318e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!ccwreq_next_path(cdev)) {
319e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* set the final return code for this request */
320e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		req->drc = -ETIME;
321e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
322e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	rc = cio_clear(sch);
323e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (rc)
324e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto err;
325e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return;
326e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
327e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitererr:
328e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, rc);
329e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
330e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
331e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
332e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_notoper - notoper handler for I/O request procedure
333e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
334e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
335e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Handle timeout during I/O request procedure.
336e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
337e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitervoid ccw_request_notoper(struct ccw_device *cdev)
338e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
339e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, -ENODEV);
340e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
341