diff options
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 109 |
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 | ||
380 | static 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 | |||
391 | static 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 | |||
995 | ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event) | 1045 | ccw_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 | ||
1002 | static void | 1051 | static void |