1 /* 2 * drivers/s390/cio/device_pgid.c 3 * 4 * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, 5 * IBM Corporation 6 * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com) 7 * Martin Schwidefsky (schwidefsky@de.ibm.com) 8 * 9 * Path Group ID functions. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/init.h> 14 15 #include <asm/ccwdev.h> 16 #include <asm/cio.h> 17 #include <asm/delay.h> 18 #include <asm/lowcore.h> 19 20 #include "cio.h" 21 #include "cio_debug.h" 22 #include "css.h" 23 #include "device.h" 24 #include "ioasm.h" 25 26 /* 27 * Helper function called from interrupt context to decide whether an 28 * operation should be tried again. 29 */ 30 static int __ccw_device_should_retry(struct scsw *scsw) 31 { 32 /* CC is only valid if start function bit is set. */ 33 if ((scsw->fctl & SCSW_FCTL_START_FUNC) && scsw->cc == 1) 34 return 1; 35 /* No more activity. For sense and set PGID we stubbornly try again. */ 36 if (!scsw->actl) 37 return 1; 38 return 0; 39 } 40 41 /* 42 * Start Sense Path Group ID helper function. Used in ccw_device_recog 43 * and ccw_device_sense_pgid. 44 */ 45 static int 46 __ccw_device_sense_pgid_start(struct ccw_device *cdev) 47 { 48 struct subchannel *sch; 49 struct ccw1 *ccw; 50 int ret; 51 int i; 52 53 sch = to_subchannel(cdev->dev.parent); 54 /* Return if we already checked on all paths. */ 55 if (cdev->private->imask == 0) 56 return (sch->lpm == 0) ? -ENODEV : -EACCES; 57 i = 8 - ffs(cdev->private->imask); 58 59 /* Setup sense path group id channel program. */ 60 ccw = cdev->private->iccws; 61 ccw->cmd_code = CCW_CMD_SENSE_PGID; 62 ccw->count = sizeof (struct pgid); 63 ccw->flags = CCW_FLAG_SLI; 64 65 /* Reset device status. */ 66 memset(&cdev->private->irb, 0, sizeof(struct irb)); 67 /* Try on every path. */ 68 ret = -ENODEV; 69 while (cdev->private->imask != 0) { 70 /* Try every path multiple times. */ 71 ccw->cda = (__u32) __pa (&cdev->private->pgid[i]); 72 if (cdev->private->iretry > 0) { 73 cdev->private->iretry--; 74 /* Reset internal retry indication. */ 75 cdev->private->flags.intretry = 0; 76 ret = cio_start (sch, cdev->private->iccws, 77 cdev->private->imask); 78 /* ret is 0, -EBUSY, -EACCES or -ENODEV */ 79 if (ret != -EACCES) 80 return ret; 81 CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel " 82 "0.%x.%04x, lpm %02X, became 'not " 83 "operational'\n", 84 cdev->private->dev_id.devno, 85 sch->schid.ssid, 86 sch->schid.sch_no, cdev->private->imask); 87 88 } 89 cdev->private->imask >>= 1; 90 cdev->private->iretry = 5; 91 i++; 92 } 93 94 return ret; 95 } 96 97 void 98 ccw_device_sense_pgid_start(struct ccw_device *cdev) 99 { 100 int ret; 101 102 /* Set a timeout of 60s */ 103 ccw_device_set_timeout(cdev, 60*HZ); 104 105 cdev->private->state = DEV_STATE_SENSE_PGID; 106 cdev->private->imask = 0x80; 107 cdev->private->iretry = 5; 108 memset (&cdev->private->pgid, 0, sizeof (cdev->private->pgid)); 109 ret = __ccw_device_sense_pgid_start(cdev); 110 if (ret && ret != -EBUSY) 111 ccw_device_sense_pgid_done(cdev, ret); 112 } 113 114 /* 115 * Called from interrupt context to check if a valid answer 116 * to Sense Path Group ID was received. 117 */ 118 static int 119 __ccw_device_check_sense_pgid(struct ccw_device *cdev) 120 { 121 struct subchannel *sch; 122 struct irb *irb; 123 int i; 124 125 sch = to_subchannel(cdev->dev.parent); 126 irb = &cdev->private->irb; 127 if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { 128 /* Retry Sense PGID if requested. */ 129 if (cdev->private->flags.intretry) { 130 cdev->private->flags.intretry = 0; 131 return -EAGAIN; 132 } 133 return -ETIME; 134 } 135 if (irb->esw.esw0.erw.cons && 136 (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) { 137 /* 138 * If the device doesn't support the Sense Path Group ID 139 * command further retries wouldn't help ... 140 */ 141 return -EOPNOTSUPP; 142 } 143 if (irb->esw.esw0.erw.cons) { 144 CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, " 145 "lpum %02X, cnt %02d, sns : " 146 "%02X%02X%02X%02X %02X%02X%02X%02X ...\n", 147 cdev->private->dev_id.ssid, 148 cdev->private->dev_id.devno, 149 irb->esw.esw0.sublog.lpum, 150 irb->esw.esw0.erw.scnt, 151 irb->ecw[0], irb->ecw[1], 152 irb->ecw[2], irb->ecw[3], 153 irb->ecw[4], irb->ecw[5], 154 irb->ecw[6], irb->ecw[7]); 155 return -EAGAIN; 156 } 157 if (irb->scsw.cc == 3) { 158 CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x," 159 " lpm %02X, became 'not operational'\n", 160 cdev->private->dev_id.devno, sch->schid.ssid, 161 sch->schid.sch_no, sch->orb.lpm); 162 return -EACCES; 163 } 164 i = 8 - ffs(cdev->private->imask); 165 if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) { 166 CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x " 167 "is reserved by someone else\n", 168 cdev->private->dev_id.devno, sch->schid.ssid, 169 sch->schid.sch_no); 170 return -EUSERS; 171 } 172 return 0; 173 } 174 175 /* 176 * Got interrupt for Sense Path Group ID. 177 */ 178 void 179 ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event) 180 { 181 struct subchannel *sch; 182 struct irb *irb; 183 int ret; 184 185 irb = (struct irb *) __LC_IRB; 186 187 if (irb->scsw.stctl == 188 (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { 189 if (__ccw_device_should_retry(&irb->scsw)) { 190 ret = __ccw_device_sense_pgid_start(cdev); 191 if (ret && ret != -EBUSY) 192 ccw_device_sense_pgid_done(cdev, ret); 193 } 194 return; 195 } 196 if (ccw_device_accumulate_and_sense(cdev, irb) != 0) 197 return; 198 sch = to_subchannel(cdev->dev.parent); 199 ret = __ccw_device_check_sense_pgid(cdev); 200 memset(&cdev->private->irb, 0, sizeof(struct irb)); 201 switch (ret) { 202 /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */ 203 case -EOPNOTSUPP: /* Sense Path Group ID not supported */ 204 ccw_device_sense_pgid_done(cdev, -EOPNOTSUPP); 205 break; 206 case -ETIME: /* Sense path group id stopped by timeout. */ 207 ccw_device_sense_pgid_done(cdev, -ETIME); 208 break; 209 case -EACCES: /* channel is not operational. */ 210 sch->lpm &= ~cdev->private->imask; 211 /* Fall through. */ 212 case 0: /* Sense Path Group ID successful. */ 213 cdev->private->imask >>= 1; 214 cdev->private->iretry = 5; 215 /* Fall through. */ 216 case -EAGAIN: /* Try again. */ 217 ret = __ccw_device_sense_pgid_start(cdev); 218 if (ret != 0 && ret != -EBUSY) 219 ccw_device_sense_pgid_done(cdev, ret); 220 break; 221 case -EUSERS: /* device is reserved for someone else. */ 222 ccw_device_sense_pgid_done(cdev, -EUSERS); 223 break; 224 } 225 } 226 227 /* 228 * Path Group ID helper function. 229 */ 230 static int 231 __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) 232 { 233 struct subchannel *sch; 234 struct ccw1 *ccw; 235 int ret; 236 237 sch = to_subchannel(cdev->dev.parent); 238 239 /* Setup sense path group id channel program. */ 240 cdev->private->pgid[0].inf.fc = func; 241 ccw = cdev->private->iccws; 242 if (!cdev->private->flags.pgid_single) { 243 cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH; 244 ccw->cmd_code = CCW_CMD_SUSPEND_RECONN; 245 ccw->cda = 0; 246 ccw->count = 0; 247 ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC; 248 ccw++; 249 } else 250 cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH; 251 252 ccw->cmd_code = CCW_CMD_SET_PGID; 253 ccw->cda = (__u32) __pa (&cdev->private->pgid[0]); 254 ccw->count = sizeof (struct pgid); 255 ccw->flags = CCW_FLAG_SLI; 256 257 /* Reset device status. */ 258 memset(&cdev->private->irb, 0, sizeof(struct irb)); 259 260 /* Try multiple times. */ 261 ret = -EACCES; 262 if (cdev->private->iretry > 0) { 263 cdev->private->iretry--; 264 /* Reset internal retry indication. */ 265 cdev->private->flags.intretry = 0; 266 ret = cio_start (sch, cdev->private->iccws, 267 cdev->private->imask); 268 /* We expect an interrupt in case of success or busy 269 * indication. */ 270 if ((ret == 0) || (ret == -EBUSY)) 271 return ret; 272 } 273 /* PGID command failed on this path. */ 274 CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " 275 "0.%x.%04x, lpm %02X, became 'not operational'\n", 276 cdev->private->dev_id.devno, sch->schid.ssid, 277 sch->schid.sch_no, cdev->private->imask); 278 return ret; 279 } 280 281 /* 282 * Helper function to send a nop ccw down a path. 283 */ 284 static int __ccw_device_do_nop(struct ccw_device *cdev) 285 { 286 struct subchannel *sch; 287 struct ccw1 *ccw; 288 int ret; 289 290 sch = to_subchannel(cdev->dev.parent); 291 292 /* Setup nop channel program. */ 293 ccw = cdev->private->iccws; 294 ccw->cmd_code = CCW_CMD_NOOP; 295 ccw->cda = 0; 296 ccw->count = 0; 297 ccw->flags = CCW_FLAG_SLI; 298 299 /* Reset device status. */ 300 memset(&cdev->private->irb, 0, sizeof(struct irb)); 301 302 /* Try multiple times. */ 303 ret = -EACCES; 304 if (cdev->private->iretry > 0) { 305 cdev->private->iretry--; 306 /* Reset internal retry indication. */ 307 cdev->private->flags.intretry = 0; 308 ret = cio_start (sch, cdev->private->iccws, 309 cdev->private->imask); 310 /* We expect an interrupt in case of success or busy 311 * indication. */ 312 if ((ret == 0) || (ret == -EBUSY)) 313 return ret; 314 } 315 /* nop command failed on this path. */ 316 CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel " 317 "0.%x.%04x, lpm %02X, became 'not operational'\n", 318 cdev->private->dev_id.devno, sch->schid.ssid, 319 sch->schid.sch_no, cdev->private->imask); 320 return ret; 321 } 322 323 324 /* 325 * Called from interrupt context to check if a valid answer 326 * to Set Path Group ID was received. 327 */ 328 static int 329 __ccw_device_check_pgid(struct ccw_device *cdev) 330 { 331 struct subchannel *sch; 332 struct irb *irb; 333 334 sch = to_subchannel(cdev->dev.parent); 335 irb = &cdev->private->irb; 336 if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { 337 /* Retry Set PGID if requested. */ 338 if (cdev->private->flags.intretry) { 339 cdev->private->flags.intretry = 0; 340 return -EAGAIN; 341 } 342 return -ETIME; 343 } 344 if (irb->esw.esw0.erw.cons) { 345 if (irb->ecw[0] & SNS0_CMD_REJECT) 346 return -EOPNOTSUPP; 347 /* Hmm, whatever happened, try again. */ 348 CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, " 349 "cnt %02d, " 350 "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n", 351 cdev->private->dev_id.ssid, 352 cdev->private->dev_id.devno, 353 irb->esw.esw0.erw.scnt, 354 irb->ecw[0], irb->ecw[1], 355 irb->ecw[2], irb->ecw[3], 356 irb->ecw[4], irb->ecw[5], 357 irb->ecw[6], irb->ecw[7]); 358 return -EAGAIN; 359 } 360 if (irb->scsw.cc == 3) { 361 CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel 0.%x.%04x," 362 " lpm %02X, became 'not operational'\n", 363 cdev->private->dev_id.devno, sch->schid.ssid, 364 sch->schid.sch_no, cdev->private->imask); 365 return -EACCES; 366 } 367 return 0; 368 } 369 370 /* 371 * Called from interrupt context to check the path status after a nop has 372 * been send. 373 */ 374 static int __ccw_device_check_nop(struct ccw_device *cdev) 375 { 376 struct subchannel *sch; 377 struct irb *irb; 378 379 sch = to_subchannel(cdev->dev.parent); 380 irb = &cdev->private->irb; 381 if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { 382 /* Retry NOP if requested. */ 383 if (cdev->private->flags.intretry) { 384 cdev->private->flags.intretry = 0; 385 return -EAGAIN; 386 } 387 return -ETIME; 388 } 389 if (irb->scsw.cc == 3) { 390 CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," 391 " lpm %02X, became 'not operational'\n", 392 cdev->private->dev_id.devno, sch->schid.ssid, 393 sch->schid.sch_no, cdev->private->imask); 394 return -EACCES; 395 } 396 return 0; 397 } 398 399 static void 400 __ccw_device_verify_start(struct ccw_device *cdev) 401 { 402 struct subchannel *sch; 403 __u8 func; 404 int ret; 405 406 sch = to_subchannel(cdev->dev.parent); 407 /* Repeat for all paths. */ 408 for (; cdev->private->imask; cdev->private->imask >>= 1, 409 cdev->private->iretry = 5) { 410 if ((cdev->private->imask & sch->schib.pmcw.pam) == 0) 411 /* Path not available, try next. */ 412 continue; 413 if (cdev->private->options.pgroup) { 414 if (sch->opm & cdev->private->imask) 415 func = SPID_FUNC_ESTABLISH; 416 else 417 func = SPID_FUNC_RESIGN; 418 ret = __ccw_device_do_pgid(cdev, func); 419 } else 420 ret = __ccw_device_do_nop(cdev); 421 /* We expect an interrupt in case of success or busy 422 * indication. */ 423 if (ret == 0 || ret == -EBUSY) 424 return; 425 /* Permanent path failure, try next. */ 426 } 427 /* Done with all paths. */ 428 ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -ENODEV); 429 } 430 431 /* 432 * Got interrupt for Set Path Group ID. 433 */ 434 void 435 ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event) 436 { 437 struct subchannel *sch; 438 struct irb *irb; 439 int ret; 440 441 irb = (struct irb *) __LC_IRB; 442 443 if (irb->scsw.stctl == 444 (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { 445 if (__ccw_device_should_retry(&irb->scsw)) 446 __ccw_device_verify_start(cdev); 447 return; 448 } 449 if (ccw_device_accumulate_and_sense(cdev, irb) != 0) 450 return; 451 sch = to_subchannel(cdev->dev.parent); 452 if (cdev->private->options.pgroup) 453 ret = __ccw_device_check_pgid(cdev); 454 else 455 ret = __ccw_device_check_nop(cdev); 456 memset(&cdev->private->irb, 0, sizeof(struct irb)); 457 458 switch (ret) { 459 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */ 460 case 0: 461 /* Path verification ccw finished successfully, update lpm. */ 462 sch->vpm |= sch->opm & cdev->private->imask; 463 /* Go on with next path. */ 464 cdev->private->imask >>= 1; 465 cdev->private->iretry = 5; 466 __ccw_device_verify_start(cdev); 467 break; 468 case -EOPNOTSUPP: 469 /* 470 * One of those strange devices which claim to be able 471 * to do multipathing but not for Set Path Group ID. 472 */ 473 if (cdev->private->flags.pgid_single) 474 cdev->private->options.pgroup = 0; 475 else 476 cdev->private->flags.pgid_single = 1; 477 /* Retry */ 478 sch->vpm = 0; 479 cdev->private->imask = 0x80; 480 cdev->private->iretry = 5; 481 /* fall through. */ 482 case -EAGAIN: /* Try again. */ 483 __ccw_device_verify_start(cdev); 484 break; 485 case -ETIME: /* Set path group id stopped by timeout. */ 486 ccw_device_verify_done(cdev, -ETIME); 487 break; 488 case -EACCES: /* channel is not operational. */ 489 cdev->private->imask >>= 1; 490 cdev->private->iretry = 5; 491 __ccw_device_verify_start(cdev); 492 break; 493 } 494 } 495 496 void 497 ccw_device_verify_start(struct ccw_device *cdev) 498 { 499 struct subchannel *sch = to_subchannel(cdev->dev.parent); 500 501 cdev->private->flags.pgid_single = 0; 502 cdev->private->imask = 0x80; 503 cdev->private->iretry = 5; 504 505 /* Start with empty vpm. */ 506 sch->vpm = 0; 507 508 /* Get current pam. */ 509 if (stsch(sch->schid, &sch->schib)) { 510 ccw_device_verify_done(cdev, -ENODEV); 511 return; 512 } 513 /* After 60s path verification is considered to have failed. */ 514 ccw_device_set_timeout(cdev, 60*HZ); 515 __ccw_device_verify_start(cdev); 516 } 517 518 static void 519 __ccw_device_disband_start(struct ccw_device *cdev) 520 { 521 struct subchannel *sch; 522 int ret; 523 524 sch = to_subchannel(cdev->dev.parent); 525 while (cdev->private->imask != 0) { 526 if (sch->lpm & cdev->private->imask) { 527 ret = __ccw_device_do_pgid(cdev, SPID_FUNC_DISBAND); 528 if (ret == 0) 529 return; 530 } 531 cdev->private->iretry = 5; 532 cdev->private->imask >>= 1; 533 } 534 ccw_device_disband_done(cdev, (sch->lpm != 0) ? 0 : -ENODEV); 535 } 536 537 /* 538 * Got interrupt for Unset Path Group ID. 539 */ 540 void 541 ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event) 542 { 543 struct subchannel *sch; 544 struct irb *irb; 545 int ret; 546 547 irb = (struct irb *) __LC_IRB; 548 549 if (irb->scsw.stctl == 550 (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { 551 if (__ccw_device_should_retry(&irb->scsw)) 552 __ccw_device_disband_start(cdev); 553 return; 554 } 555 if (ccw_device_accumulate_and_sense(cdev, irb) != 0) 556 return; 557 sch = to_subchannel(cdev->dev.parent); 558 ret = __ccw_device_check_pgid(cdev); 559 memset(&cdev->private->irb, 0, sizeof(struct irb)); 560 switch (ret) { 561 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */ 562 case 0: /* disband successful. */ 563 ccw_device_disband_done(cdev, ret); 564 break; 565 case -EOPNOTSUPP: 566 /* 567 * One of those strange devices which claim to be able 568 * to do multipathing but not for Unset Path Group ID. 569 */ 570 cdev->private->flags.pgid_single = 1; 571 /* fall through. */ 572 case -EAGAIN: /* Try again. */ 573 __ccw_device_disband_start(cdev); 574 break; 575 case -ETIME: /* Set path group id stopped by timeout. */ 576 ccw_device_disband_done(cdev, -ETIME); 577 break; 578 case -EACCES: /* channel is not operational. */ 579 cdev->private->imask >>= 1; 580 cdev->private->iretry = 5; 581 __ccw_device_disband_start(cdev); 582 break; 583 } 584 } 585 586 void 587 ccw_device_disband_start(struct ccw_device *cdev) 588 { 589 /* After 60s disbanding is considered to have failed. */ 590 ccw_device_set_timeout(cdev, 60*HZ); 591 592 cdev->private->flags.pgid_single = 0; 593 cdev->private->iretry = 5; 594 cdev->private->imask = 0x80; 595 __ccw_device_disband_start(cdev); 596 } 597