diff options
Diffstat (limited to 'drivers/s390/cio/chsc.c')
-rw-r--r-- | drivers/s390/cio/chsc.c | 98 |
1 files changed, 32 insertions, 66 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 12a344c66b46..93e6f74187ee 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -136,17 +136,13 @@ static void terminate_internal_io(struct subchannel *sch) | |||
136 | sch->driver->termination(sch); | 136 | sch->driver->termination(sch); |
137 | } | 137 | } |
138 | 138 | ||
139 | static int | 139 | static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) |
140 | s390_subchannel_remove_chpid(struct device *dev, void *data) | ||
141 | { | 140 | { |
142 | int j; | 141 | int j; |
143 | int mask; | 142 | int mask; |
144 | struct subchannel *sch; | 143 | struct chp_id *chpid = data; |
145 | struct chp_id *chpid; | ||
146 | struct schib schib; | 144 | struct schib schib; |
147 | 145 | ||
148 | sch = to_subchannel(dev); | ||
149 | chpid = data; | ||
150 | for (j = 0; j < 8; j++) { | 146 | for (j = 0; j < 8; j++) { |
151 | mask = 0x80 >> j; | 147 | mask = 0x80 >> j; |
152 | if ((sch->schib.pmcw.pim & mask) && | 148 | if ((sch->schib.pmcw.pim & mask) && |
@@ -202,12 +198,10 @@ void chsc_chp_offline(struct chp_id chpid) | |||
202 | 198 | ||
203 | if (chp_get_status(chpid) <= 0) | 199 | if (chp_get_status(chpid) <= 0) |
204 | return; | 200 | return; |
205 | bus_for_each_dev(&css_bus_type, NULL, &chpid, | 201 | for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid); |
206 | s390_subchannel_remove_chpid); | ||
207 | } | 202 | } |
208 | 203 | ||
209 | static int | 204 | static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data) |
210 | s390_process_res_acc_new_sch(struct subchannel_id schid) | ||
211 | { | 205 | { |
212 | struct schib schib; | 206 | struct schib schib; |
213 | /* | 207 | /* |
@@ -253,18 +247,10 @@ static int get_res_chpid_mask(struct chsc_ssd_info *ssd, | |||
253 | return 0; | 247 | return 0; |
254 | } | 248 | } |
255 | 249 | ||
256 | static int | 250 | static int __s390_process_res_acc(struct subchannel *sch, void *data) |
257 | __s390_process_res_acc(struct subchannel_id schid, void *data) | ||
258 | { | 251 | { |
259 | int chp_mask, old_lpm; | 252 | int chp_mask, old_lpm; |
260 | struct res_acc_data *res_data; | 253 | struct res_acc_data *res_data = data; |
261 | struct subchannel *sch; | ||
262 | |||
263 | res_data = data; | ||
264 | sch = get_subchannel_by_schid(schid); | ||
265 | if (!sch) | ||
266 | /* Check if a subchannel is newly available. */ | ||
267 | return s390_process_res_acc_new_sch(schid); | ||
268 | 254 | ||
269 | spin_lock_irq(sch->lock); | 255 | spin_lock_irq(sch->lock); |
270 | chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data); | 256 | chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data); |
@@ -283,7 +269,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) | |||
283 | sch->driver->verify(sch); | 269 | sch->driver->verify(sch); |
284 | out: | 270 | out: |
285 | spin_unlock_irq(sch->lock); | 271 | spin_unlock_irq(sch->lock); |
286 | put_device(&sch->dev); | 272 | |
287 | return 0; | 273 | return 0; |
288 | } | 274 | } |
289 | 275 | ||
@@ -306,7 +292,8 @@ static void s390_process_res_acc (struct res_acc_data *res_data) | |||
306 | * The more information we have (info), the less scanning | 292 | * The more information we have (info), the less scanning |
307 | * will we have to do. | 293 | * will we have to do. |
308 | */ | 294 | */ |
309 | for_each_subchannel(__s390_process_res_acc, res_data); | 295 | for_each_subchannel_staged(__s390_process_res_acc, |
296 | s390_process_res_acc_new_sch, res_data); | ||
310 | } | 297 | } |
311 | 298 | ||
312 | static int | 299 | static int |
@@ -500,8 +487,7 @@ void chsc_process_crw(void) | |||
500 | } while (sei_area->flags & 0x80); | 487 | } while (sei_area->flags & 0x80); |
501 | } | 488 | } |
502 | 489 | ||
503 | static int | 490 | static int __chp_add_new_sch(struct subchannel_id schid, void *data) |
504 | __chp_add_new_sch(struct subchannel_id schid) | ||
505 | { | 491 | { |
506 | struct schib schib; | 492 | struct schib schib; |
507 | 493 | ||
@@ -515,35 +501,27 @@ __chp_add_new_sch(struct subchannel_id schid) | |||
515 | } | 501 | } |
516 | 502 | ||
517 | 503 | ||
518 | static int | 504 | static int __chp_add(struct subchannel *sch, void *data) |
519 | __chp_add(struct subchannel_id schid, void *data) | ||
520 | { | 505 | { |
521 | int i, mask; | 506 | int i, mask; |
522 | struct chp_id *chpid; | 507 | struct chp_id *chpid = data; |
523 | struct subchannel *sch; | 508 | |
524 | |||
525 | chpid = data; | ||
526 | sch = get_subchannel_by_schid(schid); | ||
527 | if (!sch) | ||
528 | /* Check if the subchannel is now available. */ | ||
529 | return __chp_add_new_sch(schid); | ||
530 | spin_lock_irq(sch->lock); | 509 | spin_lock_irq(sch->lock); |
531 | for (i=0; i<8; i++) { | 510 | for (i=0; i<8; i++) { |
532 | mask = 0x80 >> i; | 511 | mask = 0x80 >> i; |
533 | if ((sch->schib.pmcw.pim & mask) && | 512 | if ((sch->schib.pmcw.pim & mask) && |
534 | (sch->schib.pmcw.chpid[i] == chpid->id)) { | 513 | (sch->schib.pmcw.chpid[i] == chpid->id)) |
535 | if (stsch(sch->schid, &sch->schib) != 0) { | ||
536 | /* Endgame. */ | ||
537 | spin_unlock_irq(sch->lock); | ||
538 | return -ENXIO; | ||
539 | } | ||
540 | break; | 514 | break; |
541 | } | ||
542 | } | 515 | } |
543 | if (i==8) { | 516 | if (i==8) { |
544 | spin_unlock_irq(sch->lock); | 517 | spin_unlock_irq(sch->lock); |
545 | return 0; | 518 | return 0; |
546 | } | 519 | } |
520 | if (stsch(sch->schid, &sch->schib)) { | ||
521 | spin_unlock_irq(sch->lock); | ||
522 | css_schedule_eval(sch->schid); | ||
523 | return 0; | ||
524 | } | ||
547 | sch->lpm = ((sch->schib.pmcw.pim & | 525 | sch->lpm = ((sch->schib.pmcw.pim & |
548 | sch->schib.pmcw.pam & | 526 | sch->schib.pmcw.pam & |
549 | sch->schib.pmcw.pom) | 527 | sch->schib.pmcw.pom) |
@@ -553,7 +531,7 @@ __chp_add(struct subchannel_id schid, void *data) | |||
553 | sch->driver->verify(sch); | 531 | sch->driver->verify(sch); |
554 | 532 | ||
555 | spin_unlock_irq(sch->lock); | 533 | spin_unlock_irq(sch->lock); |
556 | put_device(&sch->dev); | 534 | |
557 | return 0; | 535 | return 0; |
558 | } | 536 | } |
559 | 537 | ||
@@ -565,7 +543,8 @@ void chsc_chp_online(struct chp_id chpid) | |||
565 | CIO_TRACE_EVENT(2, dbf_txt); | 543 | CIO_TRACE_EVENT(2, dbf_txt); |
566 | 544 | ||
567 | if (chp_get_status(chpid) != 0) | 545 | if (chp_get_status(chpid) != 0) |
568 | for_each_subchannel(__chp_add, &chpid); | 546 | for_each_subchannel_staged(__chp_add, __chp_add_new_sch, |
547 | &chpid); | ||
569 | } | 548 | } |
570 | 549 | ||
571 | static void __s390_subchannel_vary_chpid(struct subchannel *sch, | 550 | static void __s390_subchannel_vary_chpid(struct subchannel *sch, |
@@ -616,25 +595,17 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, | |||
616 | spin_unlock_irqrestore(sch->lock, flags); | 595 | spin_unlock_irqrestore(sch->lock, flags); |
617 | } | 596 | } |
618 | 597 | ||
619 | static int s390_subchannel_vary_chpid_off(struct device *dev, void *data) | 598 | static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data) |
620 | { | 599 | { |
621 | struct subchannel *sch; | 600 | struct chp_id *chpid = data; |
622 | struct chp_id *chpid; | ||
623 | |||
624 | sch = to_subchannel(dev); | ||
625 | chpid = data; | ||
626 | 601 | ||
627 | __s390_subchannel_vary_chpid(sch, *chpid, 0); | 602 | __s390_subchannel_vary_chpid(sch, *chpid, 0); |
628 | return 0; | 603 | return 0; |
629 | } | 604 | } |
630 | 605 | ||
631 | static int s390_subchannel_vary_chpid_on(struct device *dev, void *data) | 606 | static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data) |
632 | { | 607 | { |
633 | struct subchannel *sch; | 608 | struct chp_id *chpid = data; |
634 | struct chp_id *chpid; | ||
635 | |||
636 | sch = to_subchannel(dev); | ||
637 | chpid = data; | ||
638 | 609 | ||
639 | __s390_subchannel_vary_chpid(sch, *chpid, 1); | 610 | __s390_subchannel_vary_chpid(sch, *chpid, 1); |
640 | return 0; | 611 | return 0; |
@@ -644,13 +615,7 @@ static int | |||
644 | __s390_vary_chpid_on(struct subchannel_id schid, void *data) | 615 | __s390_vary_chpid_on(struct subchannel_id schid, void *data) |
645 | { | 616 | { |
646 | struct schib schib; | 617 | struct schib schib; |
647 | struct subchannel *sch; | ||
648 | 618 | ||
649 | sch = get_subchannel_by_schid(schid); | ||
650 | if (sch) { | ||
651 | put_device(&sch->dev); | ||
652 | return 0; | ||
653 | } | ||
654 | if (stsch_err(schid, &schib)) | 619 | if (stsch_err(schid, &schib)) |
655 | /* We're through */ | 620 | /* We're through */ |
656 | return -ENXIO; | 621 | return -ENXIO; |
@@ -670,12 +635,13 @@ int chsc_chp_vary(struct chp_id chpid, int on) | |||
670 | * Redo PathVerification on the devices the chpid connects to | 635 | * Redo PathVerification on the devices the chpid connects to |
671 | */ | 636 | */ |
672 | 637 | ||
673 | bus_for_each_dev(&css_bus_type, NULL, &chpid, on ? | ||
674 | s390_subchannel_vary_chpid_on : | ||
675 | s390_subchannel_vary_chpid_off); | ||
676 | if (on) | 638 | if (on) |
677 | /* Scan for new devices on varied on path. */ | 639 | for_each_subchannel_staged(s390_subchannel_vary_chpid_on, |
678 | for_each_subchannel(__s390_vary_chpid_on, NULL); | 640 | __s390_vary_chpid_on, &chpid); |
641 | else | ||
642 | for_each_subchannel_staged(s390_subchannel_vary_chpid_off, | ||
643 | NULL, &chpid); | ||
644 | |||
679 | return 0; | 645 | return 0; |
680 | } | 646 | } |
681 | 647 | ||