aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2008-12-25 07:39:12 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-12-25 07:39:10 -0500
commitcdb912a40df8b8507ab60b3d52f9980c0ba1f44d (patch)
tree52d693b3515b71b4f84b539d41571facb75498db /drivers/s390
parentd6a30761d8116b8de8a5b5e79e68cce81d36414b (diff)
[S390] cio: introduce cio_update_schib
There is the chance that we get condition code 0 for a stsch but the resulting schib is not vaild. In the current code there are 2 cases: * we do a check for validity of the schib after stsch, but at this time we have already stored the invaild schib in the subchannel structure. This may lead to problems. * we don't do a check for validity, which is not that good either. The patch addresses both issues by introducing the stsch wrapper cio_update_schib which performs stsch on a local schib. This schib is only written back to the subchannel if it's valid. side note: For some functions (chp_events) the return codes are different now (-ENXIO vs -ENODEV) but this shouldn't do harm since the caller doesn't check for _specific_ errors. Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/chsc_sch.c2
-rw-r--r--drivers/s390/cio/cio.c47
-rw-r--r--drivers/s390/cio/cio.h1
-rw-r--r--drivers/s390/cio/cmf.c8
-rw-r--r--drivers/s390/cio/device.c13
-rw-r--r--drivers/s390/cio/device_fsm.c28
-rw-r--r--drivers/s390/cio/device_pgid.c2
-rw-r--r--drivers/s390/cio/device_status.c4
8 files changed, 67 insertions, 38 deletions
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index f49f0e502b8..0a2f2edafc0 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -61,7 +61,7 @@ static void chsc_subchannel_irq(struct subchannel *sch)
61 } 61 }
62 private->request = NULL; 62 private->request = NULL;
63 memcpy(&request->irb, irb, sizeof(*irb)); 63 memcpy(&request->irb, irb, sizeof(*irb));
64 stsch(sch->schid, &sch->schib); 64 cio_update_schib(sch);
65 complete(&request->completion); 65 complete(&request->completion);
66 put_device(&sch->dev); 66 put_device(&sch->dev);
67} 67}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 8047800e9a0..9bdb463765c 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -114,11 +114,13 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
114 else 114 else
115 sch->lpm = 0; 115 sch->lpm = 0;
116 116
117 stsch (sch->schid, &sch->schib);
118
119 CIO_MSG_EVENT(2, "cio_start: 'not oper' status for " 117 CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
120 "subchannel 0.%x.%04x!\n", sch->schid.ssid, 118 "subchannel 0.%x.%04x!\n", sch->schid.ssid,
121 sch->schid.sch_no); 119 sch->schid.sch_no);
120
121 if (cio_update_schib(sch))
122 return -ENODEV;
123
122 sprintf(dbf_text, "no%s", dev_name(&sch->dev)); 124 sprintf(dbf_text, "no%s", dev_name(&sch->dev));
123 CIO_TRACE_EVENT(0, dbf_text); 125 CIO_TRACE_EVENT(0, dbf_text);
124 CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); 126 CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
@@ -316,7 +318,8 @@ cio_cancel (struct subchannel *sch)
316 switch (ccode) { 318 switch (ccode) {
317 case 0: /* success */ 319 case 0: /* success */
318 /* Update information in scsw. */ 320 /* Update information in scsw. */
319 stsch (sch->schid, &sch->schib); 321 if (cio_update_schib(sch))
322 return -ENODEV;
320 return 0; 323 return 0;
321 case 1: /* status pending */ 324 case 1: /* status pending */
322 return -EBUSY; 325 return -EBUSY;
@@ -358,6 +361,23 @@ cio_modify (struct subchannel *sch)
358} 361}
359 362
360/** 363/**
364 * cio_update_schib - Perform stsch and update schib if subchannel is valid.
365 * @sch: subchannel on which to perform stsch
366 * Return zero on success, -ENODEV otherwise.
367 */
368int cio_update_schib(struct subchannel *sch)
369{
370 struct schib schib;
371
372 if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
373 return -ENODEV;
374
375 memcpy(&sch->schib, &schib, sizeof(schib));
376 return 0;
377}
378EXPORT_SYMBOL_GPL(cio_update_schib);
379
380/**
361 * cio_enable_subchannel - enable a subchannel. 381 * cio_enable_subchannel - enable a subchannel.
362 * @sch: subchannel to be enabled 382 * @sch: subchannel to be enabled
363 * @intparm: interruption parameter to set 383 * @intparm: interruption parameter to set
@@ -365,7 +385,6 @@ cio_modify (struct subchannel *sch)
365int cio_enable_subchannel(struct subchannel *sch, u32 intparm) 385int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
366{ 386{
367 char dbf_txt[15]; 387 char dbf_txt[15];
368 int ccode;
369 int retry; 388 int retry;
370 int ret; 389 int ret;
371 390
@@ -374,8 +393,7 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
374 393
375 if (sch_is_pseudo_sch(sch)) 394 if (sch_is_pseudo_sch(sch))
376 return -EINVAL; 395 return -EINVAL;
377 ccode = stsch (sch->schid, &sch->schib); 396 if (cio_update_schib(sch))
378 if (ccode)
379 return -ENODEV; 397 return -ENODEV;
380 398
381 for (retry = 5, ret = 0; retry > 0; retry--) { 399 for (retry = 5, ret = 0; retry > 0; retry--) {
@@ -392,7 +410,10 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
392 */ 410 */
393 sch->schib.pmcw.csense = 0; 411 sch->schib.pmcw.csense = 0;
394 if (ret == 0) { 412 if (ret == 0) {
395 stsch (sch->schid, &sch->schib); 413 if (cio_update_schib(sch)) {
414 ret = -ENODEV;
415 break;
416 }
396 if (sch->schib.pmcw.ena) 417 if (sch->schib.pmcw.ena)
397 break; 418 break;
398 } 419 }
@@ -415,7 +436,6 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel);
415int cio_disable_subchannel(struct subchannel *sch) 436int cio_disable_subchannel(struct subchannel *sch)
416{ 437{
417 char dbf_txt[15]; 438 char dbf_txt[15];
418 int ccode;
419 int retry; 439 int retry;
420 int ret; 440 int ret;
421 441
@@ -424,8 +444,7 @@ int cio_disable_subchannel(struct subchannel *sch)
424 444
425 if (sch_is_pseudo_sch(sch)) 445 if (sch_is_pseudo_sch(sch))
426 return 0; 446 return 0;
427 ccode = stsch (sch->schid, &sch->schib); 447 if (cio_update_schib(sch))
428 if (ccode == 3) /* Not operational. */
429 return -ENODEV; 448 return -ENODEV;
430 449
431 if (scsw_actl(&sch->schib.scsw) != 0) 450 if (scsw_actl(&sch->schib.scsw) != 0)
@@ -448,7 +467,10 @@ int cio_disable_subchannel(struct subchannel *sch)
448 */ 467 */
449 break; 468 break;
450 if (ret == 0) { 469 if (ret == 0) {
451 stsch (sch->schid, &sch->schib); 470 if (cio_update_schib(sch)) {
471 ret = -ENODEV;
472 break;
473 }
452 if (!sch->schib.pmcw.ena) 474 if (!sch->schib.pmcw.ena)
453 break; 475 break;
454 } 476 }
@@ -851,7 +873,8 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
851 cc = msch(schid, schib); 873 cc = msch(schid, schib);
852 if (cc) 874 if (cc)
853 return (cc==3?-ENODEV:-EBUSY); 875 return (cc==3?-ENODEV:-EBUSY);
854 stsch(schid, schib); 876 if (stsch(schid, schib) || !css_sch_is_valid(schib))
877 return -ENODEV;
855 if (!schib->pmcw.ena) 878 if (!schib->pmcw.ena)
856 return 0; 879 return 0;
857 } 880 }
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 5db887e8f03..fb125efd689 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -102,6 +102,7 @@ extern int cio_cancel (struct subchannel *);
102extern int cio_set_options (struct subchannel *, int); 102extern int cio_set_options (struct subchannel *, int);
103extern int cio_get_options (struct subchannel *); 103extern int cio_get_options (struct subchannel *);
104extern int cio_modify (struct subchannel *); 104extern int cio_modify (struct subchannel *);
105extern int cio_update_schib(struct subchannel *sch);
105 106
106int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); 107int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
107int cio_tm_intrg(struct subchannel *sch); 108int cio_tm_intrg(struct subchannel *sch);
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index a90b28c0be5..288482b2104 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -195,7 +195,8 @@ static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
195 /* msch can silently fail, so do it again if necessary */ 195 /* msch can silently fail, so do it again if necessary */
196 for (retry = 0; retry < 3; retry++) { 196 for (retry = 0; retry < 3; retry++) {
197 /* prepare schib */ 197 /* prepare schib */
198 stsch(sch->schid, schib); 198 if (cio_update_schib(sch))
199 return -ENODEV;
199 schib->pmcw.mme = mme; 200 schib->pmcw.mme = mme;
200 schib->pmcw.mbfc = mbfc; 201 schib->pmcw.mbfc = mbfc;
201 /* address can be either a block address or a block index */ 202 /* address can be either a block address or a block index */
@@ -219,7 +220,8 @@ static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
219 ret = -EINVAL; 220 ret = -EINVAL;
220 break; 221 break;
221 } 222 }
222 stsch(sch->schid, schib); /* restore the schib */ 223 if (cio_update_schib(sch))
224 return -ENODEV;
223 225
224 if (ret) 226 if (ret)
225 break; 227 break;
@@ -338,7 +340,7 @@ static int cmf_copy_block(struct ccw_device *cdev)
338 340
339 sch = to_subchannel(cdev->dev.parent); 341 sch = to_subchannel(cdev->dev.parent);
340 342
341 if (stsch(sch->schid, &sch->schib)) 343 if (cio_update_schib(sch))
342 return -ENODEV; 344 return -ENODEV;
343 345
344 if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) { 346 if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) {
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 868aa191538..51e94212bf6 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1350,10 +1350,7 @@ static void io_subchannel_verify(struct subchannel *sch)
1350 1350
1351static int check_for_io_on_path(struct subchannel *sch, int mask) 1351static int check_for_io_on_path(struct subchannel *sch, int mask)
1352{ 1352{
1353 int cc; 1353 if (cio_update_schib(sch))
1354
1355 cc = stsch(sch->schid, &sch->schib);
1356 if (cc)
1357 return 0; 1354 return 0;
1358 if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask) 1355 if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask)
1359 return 1; 1356 return 1;
@@ -1422,15 +1419,13 @@ static int io_subchannel_chp_event(struct subchannel *sch,
1422 io_subchannel_verify(sch); 1419 io_subchannel_verify(sch);
1423 break; 1420 break;
1424 case CHP_OFFLINE: 1421 case CHP_OFFLINE:
1425 if (stsch(sch->schid, &sch->schib)) 1422 if (cio_update_schib(sch))
1426 return -ENXIO;
1427 if (!css_sch_is_valid(&sch->schib))
1428 return -ENODEV; 1423 return -ENODEV;
1429 io_subchannel_terminate_path(sch, mask); 1424 io_subchannel_terminate_path(sch, mask);
1430 break; 1425 break;
1431 case CHP_ONLINE: 1426 case CHP_ONLINE:
1432 if (stsch(sch->schid, &sch->schib)) 1427 if (cio_update_schib(sch))
1433 return -ENXIO; 1428 return -ENODEV;
1434 sch->lpm |= mask & sch->opm; 1429 sch->lpm |= mask & sch->opm;
1435 io_subchannel_verify(sch); 1430 io_subchannel_verify(sch);
1436 break; 1431 break;
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 01330cf5ae5..e1a3786779b 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -140,8 +140,7 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
140 int ret; 140 int ret;
141 141
142 sch = to_subchannel(cdev->dev.parent); 142 sch = to_subchannel(cdev->dev.parent);
143 ret = stsch(sch->schid, &sch->schib); 143 if (cio_update_schib(sch))
144 if (ret || !sch->schib.pmcw.dnv)
145 return -ENODEV; 144 return -ENODEV;
146 if (!sch->schib.pmcw.ena) 145 if (!sch->schib.pmcw.ena)
147 /* Not operational -> done. */ 146 /* Not operational -> done. */
@@ -245,11 +244,13 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
245 * through ssch() and the path information is up to date. 244 * through ssch() and the path information is up to date.
246 */ 245 */
247 old_lpm = sch->lpm; 246 old_lpm = sch->lpm;
248 stsch(sch->schid, &sch->schib); 247
249 sch->lpm = sch->schib.pmcw.pam & sch->opm;
250 /* Check since device may again have become not operational. */ 248 /* Check since device may again have become not operational. */
251 if (!sch->schib.pmcw.dnv) 249 if (cio_update_schib(sch))
252 state = DEV_STATE_NOT_OPER; 250 state = DEV_STATE_NOT_OPER;
251 else
252 sch->lpm = sch->schib.pmcw.pam & sch->opm;
253
253 if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) 254 if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID)
254 /* Force reprobe on all chpids. */ 255 /* Force reprobe on all chpids. */
255 old_lpm = 0; 256 old_lpm = 0;
@@ -549,7 +550,11 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
549 550
550 sch = to_subchannel(cdev->dev.parent); 551 sch = to_subchannel(cdev->dev.parent);
551 /* Update schib - pom may have changed. */ 552 /* Update schib - pom may have changed. */
552 stsch(sch->schid, &sch->schib); 553 if (cio_update_schib(sch)) {
554 cdev->private->flags.donotify = 0;
555 ccw_device_done(cdev, DEV_STATE_NOT_OPER);
556 return;
557 }
553 /* Update lpm with verified path mask. */ 558 /* Update lpm with verified path mask. */
554 sch->lpm = sch->vpm; 559 sch->lpm = sch->vpm;
555 /* Repeat path verification? */ 560 /* Repeat path verification? */
@@ -667,7 +672,7 @@ ccw_device_offline(struct ccw_device *cdev)
667 return 0; 672 return 0;
668 } 673 }
669 sch = to_subchannel(cdev->dev.parent); 674 sch = to_subchannel(cdev->dev.parent);
670 if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv) 675 if (cio_update_schib(sch))
671 return -ENODEV; 676 return -ENODEV;
672 if (scsw_actl(&sch->schib.scsw) != 0) 677 if (scsw_actl(&sch->schib.scsw) != 0)
673 return -EBUSY; 678 return -EBUSY;
@@ -745,7 +750,10 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
745 * Since we might not just be coming from an interrupt from the 750 * Since we might not just be coming from an interrupt from the
746 * subchannel we have to update the schib. 751 * subchannel we have to update the schib.
747 */ 752 */
748 stsch(sch->schid, &sch->schib); 753 if (cio_update_schib(sch)) {
754 ccw_device_verify_done(cdev, -ENODEV);
755 return;
756 }
749 757
750 if (scsw_actl(&sch->schib.scsw) != 0 || 758 if (scsw_actl(&sch->schib.scsw) != 0 ||
751 (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) || 759 (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) ||
@@ -1011,9 +1019,7 @@ void ccw_device_trigger_reprobe(struct ccw_device *cdev)
1011 1019
1012 sch = to_subchannel(cdev->dev.parent); 1020 sch = to_subchannel(cdev->dev.parent);
1013 /* Update some values. */ 1021 /* Update some values. */
1014 if (stsch(sch->schid, &sch->schib)) 1022 if (cio_update_schib(sch))
1015 return;
1016 if (!sch->schib.pmcw.dnv)
1017 return; 1023 return;
1018 /* 1024 /*
1019 * The pim, pam, pom values may not be accurate, but they are the best 1025 * The pim, pam, pom values may not be accurate, but they are the best
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 86bc94eb607..fc5ca1dd52b 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -504,7 +504,7 @@ ccw_device_verify_start(struct ccw_device *cdev)
504 sch->vpm = 0; 504 sch->vpm = 0;
505 505
506 /* Get current pam. */ 506 /* Get current pam. */
507 if (stsch(sch->schid, &sch->schib)) { 507 if (cio_update_schib(sch)) {
508 ccw_device_verify_done(cdev, -ENODEV); 508 ccw_device_verify_done(cdev, -ENODEV);
509 return; 509 return;
510 } 510 }
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index 1b03c5423be..5814dbee241 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -56,7 +56,8 @@ ccw_device_path_notoper(struct ccw_device *cdev)
56 struct subchannel *sch; 56 struct subchannel *sch;
57 57
58 sch = to_subchannel(cdev->dev.parent); 58 sch = to_subchannel(cdev->dev.parent);
59 stsch (sch->schid, &sch->schib); 59 if (cio_update_schib(sch))
60 goto doverify;
60 61
61 CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are " 62 CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are "
62 "not operational \n", __func__, 63 "not operational \n", __func__,
@@ -64,6 +65,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
64 sch->schib.pmcw.pnom); 65 sch->schib.pmcw.pnom);
65 66
66 sch->lpm &= ~sch->schib.pmcw.pnom; 67 sch->lpm &= ~sch->schib.pmcw.pnom;
68doverify:
67 cdev->private->flags.doverify = 1; 69 cdev->private->flags.doverify = 1;
68} 70}
69 71