diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2006-12-04 09:41:04 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2006-12-04 09:41:04 -0500 |
commit | d23861ff1a4da1f4a5255eb4582f620191c6e1c0 (patch) | |
tree | fcf5cd0ce14600f2ace203bc71ae940db7fe6497 | |
parent | 24cb5b4846ebae5543869b5c596c2650f380df53 (diff) |
[S390] cio: Retry internal operations after vary off.
If I/O was running on a just varied off chpid, it will be terminated.
If this was a common I/O layer internal I/O, it needs to be retried.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | drivers/s390/cio/chsc.c | 37 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 3 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 16 | ||||
-rw-r--r-- | drivers/s390/cio/device_id.c | 10 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 30 | ||||
-rw-r--r-- | drivers/s390/cio/device_status.c | 3 |
7 files changed, 90 insertions, 11 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 11900de94cb3..dbfb77b03928 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -251,6 +251,8 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) | |||
251 | cc = cio_clear(sch); | 251 | cc = cio_clear(sch); |
252 | if (cc == -ENODEV) | 252 | if (cc == -ENODEV) |
253 | goto out_unreg; | 253 | goto out_unreg; |
254 | /* Request retry of internal operation. */ | ||
255 | device_set_intretry(sch); | ||
254 | /* Call handler. */ | 256 | /* Call handler. */ |
255 | if (sch->driver && sch->driver->termination) | 257 | if (sch->driver && sch->driver->termination) |
256 | sch->driver->termination(&sch->dev); | 258 | sch->driver->termination(&sch->dev); |
@@ -711,9 +713,6 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) | |||
711 | { | 713 | { |
712 | int cc; | 714 | int cc; |
713 | 715 | ||
714 | if (!device_is_online(sch)) | ||
715 | /* cio could be doing I/O. */ | ||
716 | return 0; | ||
717 | cc = stsch(sch->schid, &sch->schib); | 716 | cc = stsch(sch->schid, &sch->schib); |
718 | if (cc) | 717 | if (cc) |
719 | return 0; | 718 | return 0; |
@@ -722,6 +721,26 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) | |||
722 | return 0; | 721 | return 0; |
723 | } | 722 | } |
724 | 723 | ||
724 | static void terminate_internal_io(struct subchannel *sch) | ||
725 | { | ||
726 | if (cio_clear(sch)) { | ||
727 | /* Recheck device in case clear failed. */ | ||
728 | sch->lpm = 0; | ||
729 | if (device_trigger_verify(sch) != 0) { | ||
730 | if(css_enqueue_subchannel_slow(sch->schid)) { | ||
731 | css_clear_subchannel_slow_list(); | ||
732 | need_rescan = 1; | ||
733 | } | ||
734 | } | ||
735 | return; | ||
736 | } | ||
737 | /* Request retry of internal operation. */ | ||
738 | device_set_intretry(sch); | ||
739 | /* Call handler. */ | ||
740 | if (sch->driver && sch->driver->termination) | ||
741 | sch->driver->termination(&sch->dev); | ||
742 | } | ||
743 | |||
725 | static inline void | 744 | static inline void |
726 | __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) | 745 | __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) |
727 | { | 746 | { |
@@ -748,10 +767,14 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) | |||
748 | } | 767 | } |
749 | sch->opm &= ~(0x80 >> chp); | 768 | sch->opm &= ~(0x80 >> chp); |
750 | sch->lpm &= ~(0x80 >> chp); | 769 | sch->lpm &= ~(0x80 >> chp); |
751 | if (check_for_io_on_path(sch, chp)) | 770 | if (check_for_io_on_path(sch, chp)) { |
752 | /* Path verification is done after killing. */ | 771 | if (device_is_online(sch)) |
753 | device_kill_io(sch); | 772 | /* Path verification is done after killing. */ |
754 | else if (!sch->lpm) { | 773 | device_kill_io(sch); |
774 | else | ||
775 | /* Kill and retry internal I/O. */ | ||
776 | terminate_internal_io(sch); | ||
777 | } else if (!sch->lpm) { | ||
755 | if (device_trigger_verify(sch) != 0) { | 778 | if (device_trigger_verify(sch) != 0) { |
756 | if (css_enqueue_subchannel_slow(sch->schid)) { | 779 | if (css_enqueue_subchannel_slow(sch->schid)) { |
757 | css_clear_subchannel_slow_list(); | 780 | css_clear_subchannel_slow_list(); |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index da73453fa54b..9ff064e71767 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -94,6 +94,7 @@ struct ccw_device_private { | |||
94 | unsigned int donotify:1; /* call notify function */ | 94 | unsigned int donotify:1; /* call notify function */ |
95 | unsigned int recog_done:1; /* dev. recog. complete */ | 95 | unsigned int recog_done:1; /* dev. recog. complete */ |
96 | unsigned int fake_irb:1; /* deliver faked irb */ | 96 | unsigned int fake_irb:1; /* deliver faked irb */ |
97 | unsigned int intretry:1; /* retry internal operation */ | ||
97 | } __attribute__((packed)) flags; | 98 | } __attribute__((packed)) flags; |
98 | unsigned long intparm; /* user interruption parameter */ | 99 | unsigned long intparm; /* user interruption parameter */ |
99 | struct qdio_irq *qdio_data; | 100 | struct qdio_irq *qdio_data; |
@@ -171,6 +172,7 @@ void device_trigger_reprobe(struct subchannel *); | |||
171 | /* Helper functions for vary on/off. */ | 172 | /* Helper functions for vary on/off. */ |
172 | int device_is_online(struct subchannel *); | 173 | int device_is_online(struct subchannel *); |
173 | void device_kill_io(struct subchannel *); | 174 | void device_kill_io(struct subchannel *); |
175 | void device_set_intretry(struct subchannel *sch); | ||
174 | int device_trigger_verify(struct subchannel *sch); | 176 | int device_trigger_verify(struct subchannel *sch); |
175 | 177 | ||
176 | /* Machine check helper function. */ | 178 | /* Machine check helper function. */ |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 39c98f940507..359b46c25314 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -948,6 +948,9 @@ io_subchannel_ioterm(struct device *dev) | |||
948 | cdev = dev->driver_data; | 948 | cdev = dev->driver_data; |
949 | if (!cdev) | 949 | if (!cdev) |
950 | return; | 950 | return; |
951 | /* Internal I/O will be retried by the interrupt handler. */ | ||
952 | if (cdev->private->flags.intretry) | ||
953 | return; | ||
951 | cdev->private->state = DEV_STATE_CLEAR_VERIFY; | 954 | cdev->private->state = DEV_STATE_CLEAR_VERIFY; |
952 | if (cdev->handler) | 955 | if (cdev->handler) |
953 | cdev->handler(cdev, cdev->private->intparm, | 956 | cdev->handler(cdev, cdev->private->intparm, |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 7665000e8dfe..09c7672eb3f3 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -59,6 +59,16 @@ device_set_disconnected(struct subchannel *sch) | |||
59 | cdev->private->state = DEV_STATE_DISCONNECTED; | 59 | cdev->private->state = DEV_STATE_DISCONNECTED; |
60 | } | 60 | } |
61 | 61 | ||
62 | void device_set_intretry(struct subchannel *sch) | ||
63 | { | ||
64 | struct ccw_device *cdev; | ||
65 | |||
66 | cdev = sch->dev.driver_data; | ||
67 | if (!cdev) | ||
68 | return; | ||
69 | cdev->private->flags.intretry = 1; | ||
70 | } | ||
71 | |||
62 | int device_trigger_verify(struct subchannel *sch) | 72 | int device_trigger_verify(struct subchannel *sch) |
63 | { | 73 | { |
64 | struct ccw_device *cdev; | 74 | struct ccw_device *cdev; |
@@ -904,6 +914,12 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) | |||
904 | * had killed the original request. | 914 | * had killed the original request. |
905 | */ | 915 | */ |
906 | if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { | 916 | if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { |
917 | /* Retry Basic Sense if requested. */ | ||
918 | if (cdev->private->flags.intretry) { | ||
919 | cdev->private->flags.intretry = 0; | ||
920 | ccw_device_do_sense(cdev, irb); | ||
921 | return; | ||
922 | } | ||
907 | cdev->private->flags.dosense = 0; | 923 | cdev->private->flags.dosense = 0; |
908 | memset(&cdev->private->irb, 0, sizeof(struct irb)); | 924 | memset(&cdev->private->irb, 0, sizeof(struct irb)); |
909 | ccw_device_accumulate_irb(cdev, irb); | 925 | ccw_device_accumulate_irb(cdev, irb); |
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index a74785b9e4eb..f17275917fe5 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
@@ -191,6 +191,8 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) | |||
191 | if ((sch->opm & cdev->private->imask) != 0 && | 191 | if ((sch->opm & cdev->private->imask) != 0 && |
192 | cdev->private->iretry > 0) { | 192 | cdev->private->iretry > 0) { |
193 | cdev->private->iretry--; | 193 | cdev->private->iretry--; |
194 | /* Reset internal retry indication. */ | ||
195 | cdev->private->flags.intretry = 0; | ||
194 | ret = cio_start (sch, cdev->private->iccws, | 196 | ret = cio_start (sch, cdev->private->iccws, |
195 | cdev->private->imask); | 197 | cdev->private->imask); |
196 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ | 198 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ |
@@ -237,8 +239,14 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
237 | return 0; /* Success */ | 239 | return 0; /* Success */ |
238 | } | 240 | } |
239 | /* Check the error cases. */ | 241 | /* Check the error cases. */ |
240 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 242 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
243 | /* Retry Sense ID if requested. */ | ||
244 | if (cdev->private->flags.intretry) { | ||
245 | cdev->private->flags.intretry = 0; | ||
246 | return -EAGAIN; | ||
247 | } | ||
241 | return -ETIME; | 248 | return -ETIME; |
249 | } | ||
242 | if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) { | 250 | if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) { |
243 | /* | 251 | /* |
244 | * if the device doesn't support the SenseID | 252 | * if the device doesn't support the SenseID |
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 2975ce888c19..cb1879a96818 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -71,6 +71,8 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev) | |||
71 | ccw->cda = (__u32) __pa (&cdev->private->pgid[i]); | 71 | ccw->cda = (__u32) __pa (&cdev->private->pgid[i]); |
72 | if (cdev->private->iretry > 0) { | 72 | if (cdev->private->iretry > 0) { |
73 | cdev->private->iretry--; | 73 | cdev->private->iretry--; |
74 | /* Reset internal retry indication. */ | ||
75 | cdev->private->flags.intretry = 0; | ||
74 | ret = cio_start (sch, cdev->private->iccws, | 76 | ret = cio_start (sch, cdev->private->iccws, |
75 | cdev->private->imask); | 77 | cdev->private->imask); |
76 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ | 78 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ |
@@ -122,8 +124,14 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) | |||
122 | 124 | ||
123 | sch = to_subchannel(cdev->dev.parent); | 125 | sch = to_subchannel(cdev->dev.parent); |
124 | irb = &cdev->private->irb; | 126 | irb = &cdev->private->irb; |
125 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 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 | } | ||
126 | return -ETIME; | 133 | return -ETIME; |
134 | } | ||
127 | if (irb->esw.esw0.erw.cons && | 135 | if (irb->esw.esw0.erw.cons && |
128 | (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) { | 136 | (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) { |
129 | /* | 137 | /* |
@@ -253,6 +261,8 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) | |||
253 | ret = -EACCES; | 261 | ret = -EACCES; |
254 | if (cdev->private->iretry > 0) { | 262 | if (cdev->private->iretry > 0) { |
255 | cdev->private->iretry--; | 263 | cdev->private->iretry--; |
264 | /* Reset internal retry indication. */ | ||
265 | cdev->private->flags.intretry = 0; | ||
256 | ret = cio_start (sch, cdev->private->iccws, | 266 | ret = cio_start (sch, cdev->private->iccws, |
257 | cdev->private->imask); | 267 | cdev->private->imask); |
258 | /* We expect an interrupt in case of success or busy | 268 | /* We expect an interrupt in case of success or busy |
@@ -293,6 +303,8 @@ static int __ccw_device_do_nop(struct ccw_device *cdev) | |||
293 | ret = -EACCES; | 303 | ret = -EACCES; |
294 | if (cdev->private->iretry > 0) { | 304 | if (cdev->private->iretry > 0) { |
295 | cdev->private->iretry--; | 305 | cdev->private->iretry--; |
306 | /* Reset internal retry indication. */ | ||
307 | cdev->private->flags.intretry = 0; | ||
296 | ret = cio_start (sch, cdev->private->iccws, | 308 | ret = cio_start (sch, cdev->private->iccws, |
297 | cdev->private->imask); | 309 | cdev->private->imask); |
298 | /* We expect an interrupt in case of success or busy | 310 | /* We expect an interrupt in case of success or busy |
@@ -321,8 +333,14 @@ __ccw_device_check_pgid(struct ccw_device *cdev) | |||
321 | 333 | ||
322 | sch = to_subchannel(cdev->dev.parent); | 334 | sch = to_subchannel(cdev->dev.parent); |
323 | irb = &cdev->private->irb; | 335 | irb = &cdev->private->irb; |
324 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 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 | } | ||
325 | return -ETIME; | 342 | return -ETIME; |
343 | } | ||
326 | if (irb->esw.esw0.erw.cons) { | 344 | if (irb->esw.esw0.erw.cons) { |
327 | if (irb->ecw[0] & SNS0_CMD_REJECT) | 345 | if (irb->ecw[0] & SNS0_CMD_REJECT) |
328 | return -EOPNOTSUPP; | 346 | return -EOPNOTSUPP; |
@@ -360,8 +378,14 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) | |||
360 | 378 | ||
361 | sch = to_subchannel(cdev->dev.parent); | 379 | sch = to_subchannel(cdev->dev.parent); |
362 | irb = &cdev->private->irb; | 380 | irb = &cdev->private->irb; |
363 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 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 | } | ||
364 | return -ETIME; | 387 | return -ETIME; |
388 | } | ||
365 | if (irb->scsw.cc == 3) { | 389 | if (irb->scsw.cc == 3) { |
366 | CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," | 390 | CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," |
367 | " lpm %02X, became 'not operational'\n", | 391 | " lpm %02X, became 'not operational'\n", |
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 3f7cbce4cd87..bdcf930f7beb 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c | |||
@@ -319,6 +319,9 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) | |||
319 | sch->sense_ccw.count = SENSE_MAX_COUNT; | 319 | sch->sense_ccw.count = SENSE_MAX_COUNT; |
320 | sch->sense_ccw.flags = CCW_FLAG_SLI; | 320 | sch->sense_ccw.flags = CCW_FLAG_SLI; |
321 | 321 | ||
322 | /* Reset internal retry indication. */ | ||
323 | cdev->private->flags.intretry = 0; | ||
324 | |||
322 | return cio_start (sch, &sch->sense_ccw, 0xff); | 325 | return cio_start (sch, &sch->sense_ccw, 0xff); |
323 | } | 326 | } |
324 | 327 | ||