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