diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2009-12-07 06:51:32 -0500 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2009-12-07 06:51:32 -0500 |
commit | d7d12ef2befac4fed0dccaddff11338b654804df (patch) | |
tree | 1563b299e609024844affbc3ebba99c0718db238 /drivers/s390/cio/device_fsm.c | |
parent | 52ef0608e3ee4a511725e443c4b572fece22b353 (diff) |
[S390] cio: make steal lock procedure more robust
An Unconditional Reserve + Release operation (steal lock) for a
boxed device may fail when encountering special error cases
(e.g. unit checks or path errors). Fix this by using the more
robust ccw_request infrastructure for performing the steal lock
CCW program.
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 55 |
1 files changed, 26 insertions, 29 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 8d565ff85e43..7d42417bc2c7 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -641,6 +641,23 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) | |||
641 | } | 641 | } |
642 | 642 | ||
643 | /* | 643 | /* |
644 | * Handle path verification event in boxed state. | ||
645 | */ | ||
646 | static void ccw_device_boxed_verify(struct ccw_device *cdev, | ||
647 | enum dev_event dev_event) | ||
648 | { | ||
649 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
650 | |||
651 | if (cdev->online) { | ||
652 | if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) | ||
653 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | ||
654 | else | ||
655 | ccw_device_online_verify(cdev, dev_event); | ||
656 | } else | ||
657 | css_schedule_eval(sch->schid); | ||
658 | } | ||
659 | |||
660 | /* | ||
644 | * Got an interrupt for a normal io (state online). | 661 | * Got an interrupt for a normal io (state online). |
645 | */ | 662 | */ |
646 | static void | 663 | static void |
@@ -817,32 +834,6 @@ ccw_device_delay_verify(struct ccw_device *cdev, enum dev_event dev_event) | |||
817 | } | 834 | } |
818 | 835 | ||
819 | static void | 836 | static void |
820 | ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event) | ||
821 | { | ||
822 | struct irb *irb; | ||
823 | |||
824 | switch (dev_event) { | ||
825 | case DEV_EVENT_INTERRUPT: | ||
826 | irb = (struct irb *) __LC_IRB; | ||
827 | /* Check for unsolicited interrupt. */ | ||
828 | if ((scsw_stctl(&irb->scsw) == | ||
829 | (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) && | ||
830 | (!scsw_cc(&irb->scsw))) | ||
831 | /* FIXME: we should restart stlck here, but this | ||
832 | * is extremely unlikely ... */ | ||
833 | goto out_wakeup; | ||
834 | |||
835 | ccw_device_accumulate_irb(cdev, irb); | ||
836 | /* We don't care about basic sense etc. */ | ||
837 | break; | ||
838 | default: /* timeout */ | ||
839 | break; | ||
840 | } | ||
841 | out_wakeup: | ||
842 | wake_up(&cdev->private->wait_q); | ||
843 | } | ||
844 | |||
845 | static void | ||
846 | ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) | 837 | ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) |
847 | { | 838 | { |
848 | struct subchannel *sch; | 839 | struct subchannel *sch; |
@@ -1010,9 +1001,9 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { | |||
1010 | }, | 1001 | }, |
1011 | [DEV_STATE_BOXED] = { | 1002 | [DEV_STATE_BOXED] = { |
1012 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, | 1003 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, |
1013 | [DEV_EVENT_INTERRUPT] = ccw_device_stlck_done, | 1004 | [DEV_EVENT_INTERRUPT] = ccw_device_nop, |
1014 | [DEV_EVENT_TIMEOUT] = ccw_device_stlck_done, | 1005 | [DEV_EVENT_TIMEOUT] = ccw_device_nop, |
1015 | [DEV_EVENT_VERIFY] = ccw_device_nop, | 1006 | [DEV_EVENT_VERIFY] = ccw_device_boxed_verify, |
1016 | }, | 1007 | }, |
1017 | /* states to wait for i/o completion before doing something */ | 1008 | /* states to wait for i/o completion before doing something */ |
1018 | [DEV_STATE_TIMEOUT_KILL] = { | 1009 | [DEV_STATE_TIMEOUT_KILL] = { |
@@ -1052,6 +1043,12 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { | |||
1052 | [DEV_EVENT_TIMEOUT] = ccw_device_update_cmfblock, | 1043 | [DEV_EVENT_TIMEOUT] = ccw_device_update_cmfblock, |
1053 | [DEV_EVENT_VERIFY] = ccw_device_update_cmfblock, | 1044 | [DEV_EVENT_VERIFY] = ccw_device_update_cmfblock, |
1054 | }, | 1045 | }, |
1046 | [DEV_STATE_STEAL_LOCK] = { | ||
1047 | [DEV_EVENT_NOTOPER] = ccw_device_request_event, | ||
1048 | [DEV_EVENT_INTERRUPT] = ccw_device_request_event, | ||
1049 | [DEV_EVENT_TIMEOUT] = ccw_device_request_event, | ||
1050 | [DEV_EVENT_VERIFY] = ccw_device_nop, | ||
1051 | }, | ||
1055 | }; | 1052 | }; |
1056 | 1053 | ||
1057 | EXPORT_SYMBOL_GPL(ccw_device_set_timeout); | 1054 | EXPORT_SYMBOL_GPL(ccw_device_set_timeout); |