1e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
2e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *  Handling of internal CCW device requests.
3e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
475a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott *    Copyright IBM Corp. 2009, 2011
5e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
6e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
7e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
875a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott#define KMSG_COMPONENT "cio"
975a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1075a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott
11e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include <linux/types.h>
12e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include <linux/err.h>
13e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include <asm/ccwdev.h>
14e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include <asm/cio.h>
15e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
16e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include "io_sch.h"
17e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include "cio.h"
18e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include "device.h"
19e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter#include "cio_debug.h"
20e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
21e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
22e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * lpm_adjust - adjust path mask
23e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @lpm: path mask to adjust
24e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @mask: mask of available paths
25e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
26e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Shift @lpm right until @lpm and @mask have at least one bit in common or
27e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * until @lpm is zero. Return the resulting lpm.
28e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
29e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterint lpm_adjust(int lpm, int mask)
30e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
31e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	while (lpm && ((lpm & mask) == 0))
32e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		lpm >>= 1;
33e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return lpm;
34e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
35e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
36e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
37e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Adjust path mask to use next path and reset retry count. Return resulting
38e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * path mask.
39e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
40e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic u16 ccwreq_next_path(struct ccw_device *cdev)
41e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
42e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
43e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
44982bdf814616bec77c920e16ea4108d409f144edSebastian Ott	if (!req->singlepath) {
45982bdf814616bec77c920e16ea4108d409f144edSebastian Ott		req->mask = 0;
46982bdf814616bec77c920e16ea4108d409f144edSebastian Ott		goto out;
47982bdf814616bec77c920e16ea4108d409f144edSebastian Ott	}
48e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->retries	= req->maxretries;
496adbc9236bc01225c056757d6e0eb14cd0409dffSebastian Ott	req->mask	= lpm_adjust(req->mask >> 1, req->lpm);
50982bdf814616bec77c920e16ea4108d409f144edSebastian Ottout:
51e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return req->mask;
52e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
53e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
54e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
55e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Clean up device state and report to callback.
56e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
57e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic void ccwreq_stop(struct ccw_device *cdev, int rc)
58e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
59e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
60e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
61e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (req->done)
62e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return;
63e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->done = 1;
64e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccw_device_set_timeout(cdev, 0);
65e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	memset(&cdev->private->irb, 0, sizeof(struct irb));
66e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (rc && rc != -ENODEV && req->drc)
67e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		rc = req->drc;
68e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->callback(cdev, req->data, rc);
69e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
70e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
71e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
72e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * (Re-)Start the operation until retries and paths are exhausted.
73e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
74e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic void ccwreq_do(struct ccw_device *cdev)
75e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
76e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
77e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct subchannel *sch = to_subchannel(cdev->dev.parent);
78e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw1 *cp = req->cp;
79e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	int rc = -EACCES;
80e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
81e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	while (req->mask) {
82e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (req->retries-- == 0) {
83e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			/* Retries exhausted, try next path. */
84e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			ccwreq_next_path(cdev);
85e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			continue;
86e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
87e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Perform start function. */
88e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		memset(&cdev->private->irb, 0, sizeof(struct irb));
89de1b04388f63cbddf91d9f6c50c29be7232881caPeter Oberparleiter		rc = cio_start(sch, cp, (u8) req->mask);
90e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (rc == 0) {
91e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			/* I/O started successfully. */
92e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			ccw_device_set_timeout(cdev, req->timeout);
93e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			return;
94e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
95e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (rc == -ENODEV) {
96e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			/* Permanent device error. */
97e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			break;
98e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
99e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (rc == -EACCES) {
100e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			/* Permant path error. */
101e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			ccwreq_next_path(cdev);
102e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			continue;
103e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
104e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Temporary improper status. */
105e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		rc = cio_clear(sch);
106e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (rc)
107e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			break;
108e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return;
109e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
110e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, rc);
111e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
112e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
113e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
114e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_start - perform I/O request
115e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
116e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
117e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Perform the I/O request specified by cdev->req.
118e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
119e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitervoid ccw_request_start(struct ccw_device *cdev)
120e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
121e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
122e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
123982bdf814616bec77c920e16ea4108d409f144edSebastian Ott	if (req->singlepath) {
124982bdf814616bec77c920e16ea4108d409f144edSebastian Ott		/* Try all paths twice to counter link flapping. */
125982bdf814616bec77c920e16ea4108d409f144edSebastian Ott		req->mask = 0x8080;
126982bdf814616bec77c920e16ea4108d409f144edSebastian Ott	} else
127982bdf814616bec77c920e16ea4108d409f144edSebastian Ott		req->mask = req->lpm;
128982bdf814616bec77c920e16ea4108d409f144edSebastian Ott
129e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->retries	= req->maxretries;
130e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->mask	= lpm_adjust(req->mask, req->lpm);
131e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->drc	= 0;
132e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->done	= 0;
133e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->cancel	= 0;
134e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!req->mask)
135e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_nopath;
136e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_do(cdev);
137e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return;
138e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
139e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterout_nopath:
140e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, -EACCES);
141e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
142e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
143e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
144e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_cancel - cancel running I/O request
145e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
146e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
147e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Cancel the I/O request specified by cdev->req. Return non-zero if request
148e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * has already finished, zero otherwise.
149e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
150e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterint ccw_request_cancel(struct ccw_device *cdev)
151e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
152e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct subchannel *sch = to_subchannel(cdev->dev.parent);
153e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
154e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	int rc;
155e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
156e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (req->done)
157e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return 1;
158e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	req->cancel = 1;
159e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	rc = cio_clear(sch);
160e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (rc)
161e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		ccwreq_stop(cdev, rc);
162e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return 0;
163e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
164e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
165e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
166e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Return the status of the internal I/O started on the specified ccw device.
167e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Perform BASIC SENSE if required.
168e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
169e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
170e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
171e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct irb *irb = &cdev->private->irb;
172e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct cmd_scsw *scsw = &irb->scsw.cmd;
173094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst	enum uc_todo todo;
174e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
175e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Perform BASIC SENSE if needed. */
176e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (ccw_device_accumulate_and_sense(cdev, lcirb))
177e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_RUNNING;
178e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for halt/clear interrupt. */
179e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
180e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_KILLED;
181e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for path error. */
182e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->cc == 3 || scsw->pno)
183e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_PATH_ERROR;
184e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Handle BASIC SENSE data. */
185e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (irb->esw.esw0.erw.cons) {
186e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		CIO_TRACE_EVENT(2, "sensedata");
187e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		CIO_HEX_EVENT(2, &cdev->private->dev_id,
188e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			      sizeof(struct ccw_dev_id));
189e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT);
190e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Check for command reject. */
191e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (irb->ecw[0] & SNS0_CMD_REJECT)
192e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			return IO_REJECTED;
193094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst		/* Ask the driver what to do */
194094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst		if (cdev->drv && cdev->drv->uc_handler) {
195094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			todo = cdev->drv->uc_handler(cdev, lcirb);
196dbedd0ee47313f2a3c94b19346785fcdfa721390Michael Ernst			CIO_TRACE_EVENT(2, "uc_response");
197dbedd0ee47313f2a3c94b19346785fcdfa721390Michael Ernst			CIO_HEX_EVENT(2, &todo, sizeof(todo));
198094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			switch (todo) {
199094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			case UC_TODO_RETRY:
200094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst				return IO_STATUS_ERROR;
201094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			case UC_TODO_RETRY_ON_NEW_PATH:
202094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst				return IO_PATH_ERROR;
203094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			case UC_TODO_STOP:
204094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst				return IO_REJECTED;
205094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			default:
206094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst				return IO_STATUS_ERROR;
207094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst			}
208094f2100d6bb16ef0c4f82167cc55173ca22ee93Michael Ernst		}
209e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Assume that unexpected SENSE data implies an error. */
210e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_STATUS_ERROR;
211e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
212e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for channel errors. */
213e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->cstat != 0)
214e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_STATUS_ERROR;
215e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for device errors. */
216e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))
217e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_STATUS_ERROR;
218e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for final state. */
219e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!(scsw->dstat & DEV_STAT_DEV_END))
220e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_RUNNING;
221e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check for other improper status. */
222e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (scsw->cc == 1 && (scsw->stctl & SCSW_STCTL_ALERT_STATUS))
223e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return IO_STATUS_ERROR;
224e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return IO_DONE;
225e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
226e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
227e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/*
228e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Log ccw request status.
229e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
230e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterstatic void ccwreq_log_status(struct ccw_device *cdev, enum io_status status)
231e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
232e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
233e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct {
234e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		struct ccw_dev_id dev_id;
235e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		u16 retries;
236e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		u8 lpm;
237e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		u8 status;
238e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}  __attribute__ ((packed)) data;
239e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	data.dev_id	= cdev->private->dev_id;
240e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	data.retries	= req->retries;
241de1b04388f63cbddf91d9f6c50c29be7232881caPeter Oberparleiter	data.lpm	= (u8) req->mask;
242e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	data.status	= (u8) status;
243e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	CIO_TRACE_EVENT(2, "reqstat");
244e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	CIO_HEX_EVENT(2, &data, sizeof(data));
245e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
246e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
247e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
248e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_handler - interrupt handler for I/O request procedure.
249e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
250e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
251e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Handle interrupt during I/O request procedure.
252e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
253e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitervoid ccw_request_handler(struct ccw_device *cdev)
254e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
2550bf7fcf155160fd483af7ffdc50efd4be96f1c96Christoph Lameter	struct irb *irb = this_cpu_ptr(&cio_irb);
256e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
257e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	enum io_status status;
258e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	int rc = -EOPNOTSUPP;
259e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
260e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check status of I/O request. */
261e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	status = ccwreq_status(cdev, irb);
262e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (req->filter)
263e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		status = req->filter(cdev, req->data, irb, status);
264e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (status != IO_RUNNING)
265e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		ccw_device_set_timeout(cdev, 0);
266e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (status != IO_DONE && status != IO_RUNNING)
267e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		ccwreq_log_status(cdev, status);
268e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	switch (status) {
269e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_DONE:
270e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		break;
271e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_RUNNING:
272e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		return;
273e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_REJECTED:
274e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto err;
275e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_PATH_ERROR:
276e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_next_path;
277e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_STATUS_ERROR:
278e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_restart;
279e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case IO_KILLED:
280e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* Check if request was cancelled on purpose. */
281e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		if (req->cancel) {
282e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			rc = -EIO;
283e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter			goto err;
284e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		}
285e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_restart;
286e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
287e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Check back with request initiator. */
288e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!req->check)
289e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out;
290e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	switch (req->check(cdev, req->data)) {
291e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case 0:
292e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		break;
293e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case -EAGAIN:
294e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_restart;
295e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	case -EACCES:
296e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto out_next_path;
297e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	default:
298e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto err;
299e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
300e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterout:
301e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, 0);
302e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return;
303e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
304e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterout_next_path:
305e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Try next path and restart I/O. */
306e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!ccwreq_next_path(cdev)) {
307e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		rc = -EACCES;
308e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto err;
309e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
310e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiterout_restart:
311e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	/* Restart. */
312e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_do(cdev);
313e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return;
314e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitererr:
315e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, rc);
316e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
317e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
318e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
319e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
320e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_timeout - timeout handler for I/O request procedure
321e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
322e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
323e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * Handle timeout during I/O request procedure.
324e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
325e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitervoid ccw_request_timeout(struct ccw_device *cdev)
326e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
327e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct subchannel *sch = to_subchannel(cdev->dev.parent);
328e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	struct ccw_request *req = &cdev->private->req;
32975a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott	int rc = -ENODEV, chp;
33075a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott
33175a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott	if (cio_update_schib(sch))
33275a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott		goto err;
33375a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott
33475a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott	for (chp = 0; chp < 8; chp++) {
33575a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott		if ((0x80 >> chp) & sch->schib.pmcw.lpum)
33675a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott			pr_warning("%s: No interrupt was received within %lus "
33775a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott				   "(CS=%02x, DS=%02x, CHPID=%x.%02x)\n",
33875a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott				   dev_name(&cdev->dev), req->timeout / HZ,
33975a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott				   scsw_cstat(&sch->schib.scsw),
34075a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott				   scsw_dstat(&sch->schib.scsw),
34175a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott				   sch->schid.cssid,
34275a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott				   sch->schib.pmcw.chpid[chp]);
34375a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott	}
344e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
345e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (!ccwreq_next_path(cdev)) {
346e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		/* set the final return code for this request */
347e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		req->drc = -ETIME;
348e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	}
349e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	rc = cio_clear(sch);
350e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	if (rc)
351e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter		goto err;
352e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	return;
353e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
354e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitererr:
355e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, rc);
356e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
357e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter
358e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter/**
359e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * ccw_request_notoper - notoper handler for I/O request procedure
360e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter * @cdev: ccw device
361e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter *
36275a1c61b434759bf8f2c0118151713b010b44705Sebastian Ott * Handle notoper during I/O request procedure.
363e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter */
364e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleitervoid ccw_request_notoper(struct ccw_device *cdev)
365e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter{
366e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter	ccwreq_stop(cdev, -ENODEV);
367e1f0fbd655539b0093738f58d57db83a0ac2dd6cPeter Oberparleiter}
368