diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/s390/cio/device_fsm.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 53 |
1 files changed, 44 insertions, 9 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index c9b852647f01..52c233fa2b12 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -174,7 +174,10 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) | |||
174 | ret = cio_clear (sch); | 174 | ret = cio_clear (sch); |
175 | return (ret == 0) ? -EBUSY : ret; | 175 | return (ret == 0) ? -EBUSY : ret; |
176 | } | 176 | } |
177 | panic("Can't stop i/o on subchannel.\n"); | 177 | /* Function was unsuccessful */ |
178 | CIO_MSG_EVENT(0, "0.%x.%04x: could not stop I/O\n", | ||
179 | cdev->private->dev_id.ssid, cdev->private->dev_id.devno); | ||
180 | return -EIO; | ||
178 | } | 181 | } |
179 | 182 | ||
180 | void ccw_device_update_sense_data(struct ccw_device *cdev) | 183 | void ccw_device_update_sense_data(struct ccw_device *cdev) |
@@ -315,7 +318,7 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err) | |||
315 | 318 | ||
316 | /** | 319 | /** |
317 | * ccw_device_notify() - inform the device's driver about an event | 320 | * ccw_device_notify() - inform the device's driver about an event |
318 | * @cdev: device for which an event occured | 321 | * @cdev: device for which an event occurred |
319 | * @event: event that occurred | 322 | * @event: event that occurred |
320 | * | 323 | * |
321 | * Returns: | 324 | * Returns: |
@@ -349,9 +352,13 @@ out: | |||
349 | 352 | ||
350 | static void ccw_device_oper_notify(struct ccw_device *cdev) | 353 | static void ccw_device_oper_notify(struct ccw_device *cdev) |
351 | { | 354 | { |
355 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
356 | |||
352 | if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_OK) { | 357 | if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_OK) { |
353 | /* Reenable channel measurements, if needed. */ | 358 | /* Reenable channel measurements, if needed. */ |
354 | ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF); | 359 | ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF); |
360 | /* Save indication for new paths. */ | ||
361 | cdev->private->path_new_mask = sch->vpm; | ||
355 | return; | 362 | return; |
356 | } | 363 | } |
357 | /* Driver doesn't want device back. */ | 364 | /* Driver doesn't want device back. */ |
@@ -401,9 +408,10 @@ ccw_device_done(struct ccw_device *cdev, int state) | |||
401 | CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel " | 408 | CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel " |
402 | "%04x\n", cdev->private->dev_id.devno, | 409 | "%04x\n", cdev->private->dev_id.devno, |
403 | sch->schid.sch_no); | 410 | sch->schid.sch_no); |
404 | if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) | 411 | if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) { |
412 | cdev->private->state = DEV_STATE_NOT_OPER; | ||
405 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); | 413 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); |
406 | else | 414 | } else |
407 | ccw_device_set_disconnected(cdev); | 415 | ccw_device_set_disconnected(cdev); |
408 | cdev->private->flags.donotify = 0; | 416 | cdev->private->flags.donotify = 0; |
409 | break; | 417 | break; |
@@ -462,6 +470,32 @@ static void ccw_device_request_event(struct ccw_device *cdev, enum dev_event e) | |||
462 | } | 470 | } |
463 | } | 471 | } |
464 | 472 | ||
473 | static void ccw_device_report_path_events(struct ccw_device *cdev) | ||
474 | { | ||
475 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
476 | int path_event[8]; | ||
477 | int chp, mask; | ||
478 | |||
479 | for (chp = 0, mask = 0x80; chp < 8; chp++, mask >>= 1) { | ||
480 | path_event[chp] = PE_NONE; | ||
481 | if (mask & cdev->private->path_gone_mask & ~(sch->vpm)) | ||
482 | path_event[chp] |= PE_PATH_GONE; | ||
483 | if (mask & cdev->private->path_new_mask & sch->vpm) | ||
484 | path_event[chp] |= PE_PATH_AVAILABLE; | ||
485 | if (mask & cdev->private->pgid_reset_mask & sch->vpm) | ||
486 | path_event[chp] |= PE_PATHGROUP_ESTABLISHED; | ||
487 | } | ||
488 | if (cdev->online && cdev->drv->path_event) | ||
489 | cdev->drv->path_event(cdev, path_event); | ||
490 | } | ||
491 | |||
492 | static void ccw_device_reset_path_events(struct ccw_device *cdev) | ||
493 | { | ||
494 | cdev->private->path_gone_mask = 0; | ||
495 | cdev->private->path_new_mask = 0; | ||
496 | cdev->private->pgid_reset_mask = 0; | ||
497 | } | ||
498 | |||
465 | void | 499 | void |
466 | ccw_device_verify_done(struct ccw_device *cdev, int err) | 500 | ccw_device_verify_done(struct ccw_device *cdev, int err) |
467 | { | 501 | { |
@@ -498,6 +532,7 @@ callback: | |||
498 | &cdev->private->irb); | 532 | &cdev->private->irb); |
499 | memset(&cdev->private->irb, 0, sizeof(struct irb)); | 533 | memset(&cdev->private->irb, 0, sizeof(struct irb)); |
500 | } | 534 | } |
535 | ccw_device_report_path_events(cdev); | ||
501 | break; | 536 | break; |
502 | case -ETIME: | 537 | case -ETIME: |
503 | case -EUSERS: | 538 | case -EUSERS: |
@@ -516,6 +551,7 @@ callback: | |||
516 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | 551 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); |
517 | break; | 552 | break; |
518 | } | 553 | } |
554 | ccw_device_reset_path_events(cdev); | ||
519 | } | 555 | } |
520 | 556 | ||
521 | /* | 557 | /* |
@@ -653,7 +689,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) | |||
653 | (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) { | 689 | (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) { |
654 | /* | 690 | /* |
655 | * No final status yet or final status not yet delivered | 691 | * No final status yet or final status not yet delivered |
656 | * to the device driver. Can't do path verfication now, | 692 | * to the device driver. Can't do path verification now, |
657 | * delay until final status was delivered. | 693 | * delay until final status was delivered. |
658 | */ | 694 | */ |
659 | cdev->private->flags.doverify = 1; | 695 | cdev->private->flags.doverify = 1; |
@@ -734,13 +770,14 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) | |||
734 | int ret; | 770 | int ret; |
735 | 771 | ||
736 | ccw_device_set_timeout(cdev, 0); | 772 | ccw_device_set_timeout(cdev, 0); |
773 | cdev->private->iretry = 255; | ||
737 | ret = ccw_device_cancel_halt_clear(cdev); | 774 | ret = ccw_device_cancel_halt_clear(cdev); |
738 | if (ret == -EBUSY) { | 775 | if (ret == -EBUSY) { |
739 | ccw_device_set_timeout(cdev, 3*HZ); | 776 | ccw_device_set_timeout(cdev, 3*HZ); |
740 | cdev->private->state = DEV_STATE_TIMEOUT_KILL; | 777 | cdev->private->state = DEV_STATE_TIMEOUT_KILL; |
741 | return; | 778 | return; |
742 | } | 779 | } |
743 | if (ret == -ENODEV) | 780 | if (ret) |
744 | dev_fsm_event(cdev, DEV_EVENT_NOTOPER); | 781 | dev_fsm_event(cdev, DEV_EVENT_NOTOPER); |
745 | else if (cdev->handler) | 782 | else if (cdev->handler) |
746 | cdev->handler(cdev, cdev->private->intparm, | 783 | cdev->handler(cdev, cdev->private->intparm, |
@@ -804,9 +841,6 @@ call_handler: | |||
804 | static void | 841 | static void |
805 | ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) | 842 | ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) |
806 | { | 843 | { |
807 | struct subchannel *sch; | ||
808 | |||
809 | sch = to_subchannel(cdev->dev.parent); | ||
810 | ccw_device_set_timeout(cdev, 0); | 844 | ccw_device_set_timeout(cdev, 0); |
811 | /* Start delayed path verification. */ | 845 | /* Start delayed path verification. */ |
812 | ccw_device_online_verify(cdev, 0); | 846 | ccw_device_online_verify(cdev, 0); |
@@ -837,6 +871,7 @@ void ccw_device_kill_io(struct ccw_device *cdev) | |||
837 | { | 871 | { |
838 | int ret; | 872 | int ret; |
839 | 873 | ||
874 | cdev->private->iretry = 255; | ||
840 | ret = ccw_device_cancel_halt_clear(cdev); | 875 | ret = ccw_device_cancel_halt_clear(cdev); |
841 | if (ret == -EBUSY) { | 876 | if (ret == -EBUSY) { |
842 | ccw_device_set_timeout(cdev, 3*HZ); | 877 | ccw_device_set_timeout(cdev, 3*HZ); |