ccwreq.c revision 6adbc9236bc01225c056757d6e0eb14cd0409dff
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{ 255cbb870c8221147ae337612e04b2bb0211f31a74bHeiko Carstens struct irb *irb = (struct irb *)&S390_lowcore.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