aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/cio/chsc.c37
-rw-r--r--drivers/s390/cio/css.h2
-rw-r--r--drivers/s390/cio/device.c3
-rw-r--r--drivers/s390/cio/device_fsm.c16
-rw-r--r--drivers/s390/cio/device_id.c10
-rw-r--r--drivers/s390/cio/device_pgid.c30
-rw-r--r--drivers/s390/cio/device_status.c3
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
724static 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
725static inline void 744static 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. */
172int device_is_online(struct subchannel *); 173int device_is_online(struct subchannel *);
173void device_kill_io(struct subchannel *); 174void device_kill_io(struct subchannel *);
175void device_set_intretry(struct subchannel *sch);
174int device_trigger_verify(struct subchannel *sch); 176int 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
62void 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
62int device_trigger_verify(struct subchannel *sch) 72int 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