aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device_fsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r--drivers/s390/cio/device_fsm.c109
1 files changed, 79 insertions, 30 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index cb1af0b6f033..35e162ba6d54 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -152,7 +152,8 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
152 if (cdev->private->iretry) { 152 if (cdev->private->iretry) {
153 cdev->private->iretry--; 153 cdev->private->iretry--;
154 ret = cio_halt(sch); 154 ret = cio_halt(sch);
155 return (ret == 0) ? -EBUSY : ret; 155 if (ret != -EBUSY)
156 return (ret == 0) ? -EBUSY : ret;
156 } 157 }
157 /* halt io unsuccessful. */ 158 /* halt io unsuccessful. */
158 cdev->private->iretry = 255; /* 255 clear retries. */ 159 cdev->private->iretry = 255; /* 255 clear retries. */
@@ -266,12 +267,10 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
266 notify = 1; 267 notify = 1;
267 } 268 }
268 /* fill out sense information */ 269 /* fill out sense information */
269 cdev->id = (struct ccw_device_id) { 270 cdev->id.cu_type = cdev->private->senseid.cu_type;
270 .cu_type = cdev->private->senseid.cu_type, 271 cdev->id.cu_model = cdev->private->senseid.cu_model;
271 .cu_model = cdev->private->senseid.cu_model, 272 cdev->id.dev_type = cdev->private->senseid.dev_type;
272 .dev_type = cdev->private->senseid.dev_type, 273 cdev->id.dev_model = cdev->private->senseid.dev_model;
273 .dev_model = cdev->private->senseid.dev_model,
274 };
275 if (notify) { 274 if (notify) {
276 cdev->private->state = DEV_STATE_OFFLINE; 275 cdev->private->state = DEV_STATE_OFFLINE;
277 if (same_dev) { 276 if (same_dev) {
@@ -378,6 +377,56 @@ ccw_device_done(struct ccw_device *cdev, int state)
378 put_device (&cdev->dev); 377 put_device (&cdev->dev);
379} 378}
380 379
380static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
381{
382 char *c1;
383 char *c2;
384
385 c1 = (char *)p1;
386 c2 = (char *)p2;
387
388 return memcmp(c1 + 1, c2 + 1, sizeof(struct pgid) - 1);
389}
390
391static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
392{
393 int i;
394 int last;
395
396 last = 0;
397 for (i = 0; i < 8; i++) {
398 if (cdev->private->pgid[i].inf.ps.state1 == SNID_STATE1_RESET)
399 /* No PGID yet */
400 continue;
401 if (cdev->private->pgid[last].inf.ps.state1 ==
402 SNID_STATE1_RESET) {
403 /* First non-zero PGID */
404 last = i;
405 continue;
406 }
407 if (cmp_pgid(&cdev->private->pgid[i],
408 &cdev->private->pgid[last]) == 0)
409 /* Non-conflicting PGIDs */
410 continue;
411
412 /* PGID mismatch, can't pathgroup. */
413 CIO_MSG_EVENT(0, "SNID - pgid mismatch for device "
414 "0.%x.%04x, can't pathgroup\n",
415 cdev->private->ssid, cdev->private->devno);
416 cdev->private->options.pgroup = 0;
417 return;
418 }
419 if (cdev->private->pgid[last].inf.ps.state1 ==
420 SNID_STATE1_RESET)
421 /* No previous pgid found */
422 memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
423 sizeof(struct pgid));
424 else
425 /* Use existing pgid */
426 memcpy(&cdev->private->pgid[0], &cdev->private->pgid[last],
427 sizeof(struct pgid));
428}
429
381/* 430/*
382 * Function called from device_pgid.c after sense path ground has completed. 431 * Function called from device_pgid.c after sense path ground has completed.
383 */ 432 */
@@ -388,24 +437,26 @@ ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
388 437
389 sch = to_subchannel(cdev->dev.parent); 438 sch = to_subchannel(cdev->dev.parent);
390 switch (err) { 439 switch (err) {
391 case 0: 440 case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */
392 /* Start Path Group verification. */ 441 cdev->private->options.pgroup = 0;
393 sch->vpm = 0; /* Start with no path groups set. */ 442 break;
394 cdev->private->state = DEV_STATE_VERIFY; 443 case 0: /* success */
395 ccw_device_verify_start(cdev); 444 case -EACCES: /* partial success, some paths not operational */
445 /* Check if all pgids are equal or 0. */
446 __ccw_device_get_common_pgid(cdev);
396 break; 447 break;
397 case -ETIME: /* Sense path group id stopped by timeout. */ 448 case -ETIME: /* Sense path group id stopped by timeout. */
398 case -EUSERS: /* device is reserved for someone else. */ 449 case -EUSERS: /* device is reserved for someone else. */
399 ccw_device_done(cdev, DEV_STATE_BOXED); 450 ccw_device_done(cdev, DEV_STATE_BOXED);
400 break; 451 return;
401 case -EOPNOTSUPP: /* path grouping not supported, just set online. */
402 cdev->private->options.pgroup = 0;
403 ccw_device_done(cdev, DEV_STATE_ONLINE);
404 break;
405 default: 452 default:
406 ccw_device_done(cdev, DEV_STATE_NOT_OPER); 453 ccw_device_done(cdev, DEV_STATE_NOT_OPER);
407 break; 454 return;
408 } 455 }
456 /* Start Path Group verification. */
457 sch->vpm = 0; /* Start with no path groups set. */
458 cdev->private->state = DEV_STATE_VERIFY;
459 ccw_device_verify_start(cdev);
409} 460}
410 461
411/* 462/*
@@ -513,12 +564,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
513 /* Deliver fake irb to device driver, if needed. */ 564 /* Deliver fake irb to device driver, if needed. */
514 if (cdev->private->flags.fake_irb) { 565 if (cdev->private->flags.fake_irb) {
515 memset(&cdev->private->irb, 0, sizeof(struct irb)); 566 memset(&cdev->private->irb, 0, sizeof(struct irb));
516 cdev->private->irb.scsw = (struct scsw) { 567 cdev->private->irb.scsw.cc = 1;
517 .cc = 1, 568 cdev->private->irb.scsw.fctl = SCSW_FCTL_START_FUNC;
518 .fctl = SCSW_FCTL_START_FUNC, 569 cdev->private->irb.scsw.actl = SCSW_ACTL_START_PEND;
519 .actl = SCSW_ACTL_START_PEND, 570 cdev->private->irb.scsw.stctl = SCSW_STCTL_STATUS_PEND;
520 .stctl = SCSW_STCTL_STATUS_PEND,
521 };
522 cdev->private->flags.fake_irb = 0; 571 cdev->private->flags.fake_irb = 0;
523 if (cdev->handler) 572 if (cdev->handler)
524 cdev->handler(cdev, cdev->private->intparm, 573 cdev->handler(cdev, cdev->private->intparm,
@@ -562,8 +611,9 @@ ccw_device_online(struct ccw_device *cdev)
562 } 611 }
563 /* Do we want to do path grouping? */ 612 /* Do we want to do path grouping? */
564 if (!cdev->private->options.pgroup) { 613 if (!cdev->private->options.pgroup) {
565 /* No, set state online immediately. */ 614 /* Start initial path verification. */
566 ccw_device_done(cdev, DEV_STATE_ONLINE); 615 cdev->private->state = DEV_STATE_VERIFY;
616 ccw_device_verify_start(cdev);
567 return 0; 617 return 0;
568 } 618 }
569 /* Do a SensePGID first. */ 619 /* Do a SensePGID first. */
@@ -609,6 +659,7 @@ ccw_device_offline(struct ccw_device *cdev)
609 /* Are we doing path grouping? */ 659 /* Are we doing path grouping? */
610 if (!cdev->private->options.pgroup) { 660 if (!cdev->private->options.pgroup) {
611 /* No, set state offline immediately. */ 661 /* No, set state offline immediately. */
662 sch->vpm = 0;
612 ccw_device_done(cdev, DEV_STATE_OFFLINE); 663 ccw_device_done(cdev, DEV_STATE_OFFLINE);
613 return 0; 664 return 0;
614 } 665 }
@@ -705,8 +756,6 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
705{ 756{
706 struct subchannel *sch; 757 struct subchannel *sch;
707 758
708 if (!cdev->private->options.pgroup)
709 return;
710 if (cdev->private->state == DEV_STATE_W4SENSE) { 759 if (cdev->private->state == DEV_STATE_W4SENSE) {
711 cdev->private->flags.doverify = 1; 760 cdev->private->flags.doverify = 1;
712 return; 761 return;
@@ -719,6 +768,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
719 stsch(sch->schid, &sch->schib); 768 stsch(sch->schid, &sch->schib);
720 769
721 if (sch->schib.scsw.actl != 0 || 770 if (sch->schib.scsw.actl != 0 ||
771 (sch->schib.scsw.stctl & SCSW_STCTL_STATUS_PEND) ||
722 (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) { 772 (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
723 /* 773 /*
724 * No final status yet or final status not yet delivered 774 * No final status yet or final status not yet delivered
@@ -995,8 +1045,7 @@ static void
995ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event) 1045ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event)
996{ 1046{
997 /* When the I/O has terminated, we have to start verification. */ 1047 /* When the I/O has terminated, we have to start verification. */
998 if (cdev->private->options.pgroup) 1048 cdev->private->flags.doverify = 1;
999 cdev->private->flags.doverify = 1;
1000} 1049}
1001 1050
1002static void 1051static void