diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2008-12-25 07:39:12 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:39:10 -0500 |
commit | cdb912a40df8b8507ab60b3d52f9980c0ba1f44d (patch) | |
tree | 52d693b3515b71b4f84b539d41571facb75498db /drivers/s390 | |
parent | d6a30761d8116b8de8a5b5e79e68cce81d36414b (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.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 47 | ||||
-rw-r--r-- | drivers/s390/cio/cio.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/cmf.c | 8 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 13 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 28 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device_status.c | 4 |
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 | */ | ||
368 | int 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 | } | ||
378 | EXPORT_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) | |||
365 | int cio_enable_subchannel(struct subchannel *sch, u32 intparm) | 385 | int 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); | |||
415 | int cio_disable_subchannel(struct subchannel *sch) | 436 | int 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 *); | |||
102 | extern int cio_set_options (struct subchannel *, int); | 102 | extern int cio_set_options (struct subchannel *, int); |
103 | extern int cio_get_options (struct subchannel *); | 103 | extern int cio_get_options (struct subchannel *); |
104 | extern int cio_modify (struct subchannel *); | 104 | extern int cio_modify (struct subchannel *); |
105 | extern int cio_update_schib(struct subchannel *sch); | ||
105 | 106 | ||
106 | int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); | 107 | int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); |
107 | int cio_tm_intrg(struct subchannel *sch); | 108 | int 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 | ||
1351 | static int check_for_io_on_path(struct subchannel *sch, int mask) | 1351 | static 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; |
68 | doverify: | ||
67 | cdev->private->flags.doverify = 1; | 69 | cdev->private->flags.doverify = 1; |
68 | } | 70 | } |
69 | 71 | ||