diff options
Diffstat (limited to 'drivers/s390/cio/chsc.c')
-rw-r--r-- | drivers/s390/cio/chsc.c | 48 |
1 files changed, 25 insertions, 23 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 3bb4e472d73d..2d78f0f4a40f 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -200,11 +200,13 @@ css_get_ssd_info(struct subchannel *sch) | |||
200 | spin_unlock_irq(&sch->lock); | 200 | spin_unlock_irq(&sch->lock); |
201 | free_page((unsigned long)page); | 201 | free_page((unsigned long)page); |
202 | if (!ret) { | 202 | if (!ret) { |
203 | int j, chpid; | 203 | int j, chpid, mask; |
204 | /* Allocate channel path structures, if needed. */ | 204 | /* Allocate channel path structures, if needed. */ |
205 | for (j = 0; j < 8; j++) { | 205 | for (j = 0; j < 8; j++) { |
206 | mask = 0x80 >> j; | ||
206 | chpid = sch->ssd_info.chpid[j]; | 207 | chpid = sch->ssd_info.chpid[j]; |
207 | if (chpid && (get_chp_status(chpid) < 0)) | 208 | if ((sch->schib.pmcw.pim & mask) && |
209 | (get_chp_status(chpid) < 0)) | ||
208 | new_channel_path(chpid); | 210 | new_channel_path(chpid); |
209 | } | 211 | } |
210 | } | 212 | } |
@@ -222,13 +224,15 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) | |||
222 | 224 | ||
223 | sch = to_subchannel(dev); | 225 | sch = to_subchannel(dev); |
224 | chpid = data; | 226 | chpid = data; |
225 | for (j = 0; j < 8; j++) | 227 | for (j = 0; j < 8; j++) { |
226 | if (sch->schib.pmcw.chpid[j] == chpid->id) | 228 | mask = 0x80 >> j; |
229 | if ((sch->schib.pmcw.pim & mask) && | ||
230 | (sch->schib.pmcw.chpid[j] == chpid->id)) | ||
227 | break; | 231 | break; |
232 | } | ||
228 | if (j >= 8) | 233 | if (j >= 8) |
229 | return 0; | 234 | return 0; |
230 | 235 | ||
231 | mask = 0x80 >> j; | ||
232 | spin_lock_irq(&sch->lock); | 236 | spin_lock_irq(&sch->lock); |
233 | 237 | ||
234 | stsch(sch->schid, &schib); | 238 | stsch(sch->schid, &schib); |
@@ -366,7 +370,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) | |||
366 | struct res_acc_data *res_data; | 370 | struct res_acc_data *res_data; |
367 | struct subchannel *sch; | 371 | struct subchannel *sch; |
368 | 372 | ||
369 | res_data = (struct res_acc_data *)data; | 373 | res_data = data; |
370 | sch = get_subchannel_by_schid(schid); | 374 | sch = get_subchannel_by_schid(schid); |
371 | if (!sch) | 375 | if (!sch) |
372 | /* Check if a subchannel is newly available. */ | 376 | /* Check if a subchannel is newly available. */ |
@@ -440,7 +444,7 @@ __get_chpid_from_lir(void *data) | |||
440 | u32 isinfo[28]; | 444 | u32 isinfo[28]; |
441 | } *lir; | 445 | } *lir; |
442 | 446 | ||
443 | lir = (struct lir*) data; | 447 | lir = data; |
444 | if (!(lir->iq&0x80)) | 448 | if (!(lir->iq&0x80)) |
445 | /* NULL link incident record */ | 449 | /* NULL link incident record */ |
446 | return -EINVAL; | 450 | return -EINVAL; |
@@ -620,18 +624,20 @@ __chp_add_new_sch(struct subchannel_id schid) | |||
620 | static int | 624 | static int |
621 | __chp_add(struct subchannel_id schid, void *data) | 625 | __chp_add(struct subchannel_id schid, void *data) |
622 | { | 626 | { |
623 | int i; | 627 | int i, mask; |
624 | struct channel_path *chp; | 628 | struct channel_path *chp; |
625 | struct subchannel *sch; | 629 | struct subchannel *sch; |
626 | 630 | ||
627 | chp = (struct channel_path *)data; | 631 | chp = data; |
628 | sch = get_subchannel_by_schid(schid); | 632 | sch = get_subchannel_by_schid(schid); |
629 | if (!sch) | 633 | if (!sch) |
630 | /* Check if the subchannel is now available. */ | 634 | /* Check if the subchannel is now available. */ |
631 | return __chp_add_new_sch(schid); | 635 | return __chp_add_new_sch(schid); |
632 | spin_lock_irq(&sch->lock); | 636 | spin_lock_irq(&sch->lock); |
633 | for (i=0; i<8; i++) | 637 | for (i=0; i<8; i++) { |
634 | if (sch->schib.pmcw.chpid[i] == chp->id) { | 638 | mask = 0x80 >> i; |
639 | if ((sch->schib.pmcw.pim & mask) && | ||
640 | (sch->schib.pmcw.chpid[i] == chp->id)) { | ||
635 | if (stsch(sch->schid, &sch->schib) != 0) { | 641 | if (stsch(sch->schid, &sch->schib) != 0) { |
636 | /* Endgame. */ | 642 | /* Endgame. */ |
637 | spin_unlock_irq(&sch->lock); | 643 | spin_unlock_irq(&sch->lock); |
@@ -639,6 +645,7 @@ __chp_add(struct subchannel_id schid, void *data) | |||
639 | } | 645 | } |
640 | break; | 646 | break; |
641 | } | 647 | } |
648 | } | ||
642 | if (i==8) { | 649 | if (i==8) { |
643 | spin_unlock_irq(&sch->lock); | 650 | spin_unlock_irq(&sch->lock); |
644 | return 0; | 651 | return 0; |
@@ -646,7 +653,7 @@ __chp_add(struct subchannel_id schid, void *data) | |||
646 | sch->lpm = ((sch->schib.pmcw.pim & | 653 | sch->lpm = ((sch->schib.pmcw.pim & |
647 | sch->schib.pmcw.pam & | 654 | sch->schib.pmcw.pam & |
648 | sch->schib.pmcw.pom) | 655 | sch->schib.pmcw.pom) |
649 | | 0x80 >> i) & sch->opm; | 656 | | mask) & sch->opm; |
650 | 657 | ||
651 | if (sch->driver && sch->driver->verify) | 658 | if (sch->driver && sch->driver->verify) |
652 | sch->driver->verify(&sch->dev); | 659 | sch->driver->verify(&sch->dev); |
@@ -700,8 +707,7 @@ chp_process_crw(int chpid, int on) | |||
700 | return chp_add(chpid); | 707 | return chp_add(chpid); |
701 | } | 708 | } |
702 | 709 | ||
703 | static inline int | 710 | static inline int check_for_io_on_path(struct subchannel *sch, int index) |
704 | __check_for_io_and_kill(struct subchannel *sch, int index) | ||
705 | { | 711 | { |
706 | int cc; | 712 | int cc; |
707 | 713 | ||
@@ -711,10 +717,8 @@ __check_for_io_and_kill(struct subchannel *sch, int index) | |||
711 | cc = stsch(sch->schid, &sch->schib); | 717 | cc = stsch(sch->schid, &sch->schib); |
712 | if (cc) | 718 | if (cc) |
713 | return 0; | 719 | return 0; |
714 | if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) { | 720 | if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) |
715 | device_set_waiting(sch); | ||
716 | return 1; | 721 | return 1; |
717 | } | ||
718 | return 0; | 722 | return 0; |
719 | } | 723 | } |
720 | 724 | ||
@@ -743,12 +747,10 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) | |||
743 | } else { | 747 | } else { |
744 | sch->opm &= ~(0x80 >> chp); | 748 | sch->opm &= ~(0x80 >> chp); |
745 | sch->lpm &= ~(0x80 >> chp); | 749 | sch->lpm &= ~(0x80 >> chp); |
746 | /* | 750 | if (check_for_io_on_path(sch, chp)) |
747 | * Give running I/O a grace period in which it | 751 | /* Path verification is done after killing. */ |
748 | * can successfully terminate, even using the | 752 | device_kill_io(sch); |
749 | * just varied off path. Then kill it. | 753 | else if (!sch->lpm) { |
750 | */ | ||
751 | if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) { | ||
752 | if (css_enqueue_subchannel_slow(sch->schid)) { | 754 | if (css_enqueue_subchannel_slow(sch->schid)) { |
753 | css_clear_subchannel_slow_list(); | 755 | css_clear_subchannel_slow_list(); |
754 | need_rescan = 1; | 756 | need_rescan = 1; |