diff options
Diffstat (limited to 'drivers/s390/cio/cio.c')
-rw-r--r-- | drivers/s390/cio/cio.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 8047800e9a0c..9bdb463765c7 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 | } |