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