diff options
Diffstat (limited to 'drivers/s390/cio/cio.c')
-rw-r--r-- | drivers/s390/cio/cio.c | 84 |
1 files changed, 45 insertions, 39 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 185bc73c3ecd..396bada65f86 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -135,7 +135,7 @@ cio_tpi(void) | |||
135 | return 0; | 135 | return 0; |
136 | irb = (struct irb *) __LC_IRB; | 136 | irb = (struct irb *) __LC_IRB; |
137 | /* Store interrupt response block to lowcore. */ | 137 | /* Store interrupt response block to lowcore. */ |
138 | if (tsch (tpi_info->irq, irb) != 0) | 138 | if (tsch (tpi_info->schid, irb) != 0) |
139 | /* Not status pending or not operational. */ | 139 | /* Not status pending or not operational. */ |
140 | return 1; | 140 | return 1; |
141 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 141 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; |
@@ -163,10 +163,10 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) | |||
163 | else | 163 | else |
164 | sch->lpm = 0; | 164 | sch->lpm = 0; |
165 | 165 | ||
166 | stsch (sch->irq, &sch->schib); | 166 | stsch (sch->schid, &sch->schib); |
167 | 167 | ||
168 | CIO_MSG_EVENT(0, "cio_start: 'not oper' status for " | 168 | CIO_MSG_EVENT(0, "cio_start: 'not oper' status for " |
169 | "subchannel %04x!\n", sch->irq); | 169 | "subchannel %04x!\n", sch->schid.sch_no); |
170 | sprintf(dbf_text, "no%s", sch->dev.bus_id); | 170 | sprintf(dbf_text, "no%s", sch->dev.bus_id); |
171 | CIO_TRACE_EVENT(0, dbf_text); | 171 | CIO_TRACE_EVENT(0, dbf_text); |
172 | CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); | 172 | CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); |
@@ -204,7 +204,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ | |||
204 | sch->orb.key = key >> 4; | 204 | sch->orb.key = key >> 4; |
205 | /* issue "Start Subchannel" */ | 205 | /* issue "Start Subchannel" */ |
206 | sch->orb.cpa = (__u32) __pa (cpa); | 206 | sch->orb.cpa = (__u32) __pa (cpa); |
207 | ccode = ssch (sch->irq, &sch->orb); | 207 | ccode = ssch (sch->schid, &sch->orb); |
208 | 208 | ||
209 | /* process condition code */ | 209 | /* process condition code */ |
210 | sprintf (dbf_txt, "ccode:%d", ccode); | 210 | sprintf (dbf_txt, "ccode:%d", ccode); |
@@ -243,7 +243,7 @@ cio_resume (struct subchannel *sch) | |||
243 | CIO_TRACE_EVENT (4, "resIO"); | 243 | CIO_TRACE_EVENT (4, "resIO"); |
244 | CIO_TRACE_EVENT (4, sch->dev.bus_id); | 244 | CIO_TRACE_EVENT (4, sch->dev.bus_id); |
245 | 245 | ||
246 | ccode = rsch (sch->irq); | 246 | ccode = rsch (sch->schid); |
247 | 247 | ||
248 | sprintf (dbf_txt, "ccode:%d", ccode); | 248 | sprintf (dbf_txt, "ccode:%d", ccode); |
249 | CIO_TRACE_EVENT (4, dbf_txt); | 249 | CIO_TRACE_EVENT (4, dbf_txt); |
@@ -283,7 +283,7 @@ cio_halt(struct subchannel *sch) | |||
283 | /* | 283 | /* |
284 | * Issue "Halt subchannel" and process condition code | 284 | * Issue "Halt subchannel" and process condition code |
285 | */ | 285 | */ |
286 | ccode = hsch (sch->irq); | 286 | ccode = hsch (sch->schid); |
287 | 287 | ||
288 | sprintf (dbf_txt, "ccode:%d", ccode); | 288 | sprintf (dbf_txt, "ccode:%d", ccode); |
289 | CIO_TRACE_EVENT (2, dbf_txt); | 289 | CIO_TRACE_EVENT (2, dbf_txt); |
@@ -318,7 +318,7 @@ cio_clear(struct subchannel *sch) | |||
318 | /* | 318 | /* |
319 | * Issue "Clear subchannel" and process condition code | 319 | * Issue "Clear subchannel" and process condition code |
320 | */ | 320 | */ |
321 | ccode = csch (sch->irq); | 321 | ccode = csch (sch->schid); |
322 | 322 | ||
323 | sprintf (dbf_txt, "ccode:%d", ccode); | 323 | sprintf (dbf_txt, "ccode:%d", ccode); |
324 | CIO_TRACE_EVENT (2, dbf_txt); | 324 | CIO_TRACE_EVENT (2, dbf_txt); |
@@ -351,7 +351,7 @@ cio_cancel (struct subchannel *sch) | |||
351 | CIO_TRACE_EVENT (2, "cancelIO"); | 351 | CIO_TRACE_EVENT (2, "cancelIO"); |
352 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 352 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
353 | 353 | ||
354 | ccode = xsch (sch->irq); | 354 | ccode = xsch (sch->schid); |
355 | 355 | ||
356 | sprintf (dbf_txt, "ccode:%d", ccode); | 356 | sprintf (dbf_txt, "ccode:%d", ccode); |
357 | CIO_TRACE_EVENT (2, dbf_txt); | 357 | CIO_TRACE_EVENT (2, dbf_txt); |
@@ -359,7 +359,7 @@ cio_cancel (struct subchannel *sch) | |||
359 | switch (ccode) { | 359 | switch (ccode) { |
360 | case 0: /* success */ | 360 | case 0: /* success */ |
361 | /* Update information in scsw. */ | 361 | /* Update information in scsw. */ |
362 | stsch (sch->irq, &sch->schib); | 362 | stsch (sch->schid, &sch->schib); |
363 | return 0; | 363 | return 0; |
364 | case 1: /* status pending */ | 364 | case 1: /* status pending */ |
365 | return -EBUSY; | 365 | return -EBUSY; |
@@ -381,7 +381,7 @@ cio_modify (struct subchannel *sch) | |||
381 | 381 | ||
382 | ret = 0; | 382 | ret = 0; |
383 | for (retry = 0; retry < 5; retry++) { | 383 | for (retry = 0; retry < 5; retry++) { |
384 | ccode = msch_err (sch->irq, &sch->schib); | 384 | ccode = msch_err (sch->schid, &sch->schib); |
385 | if (ccode < 0) /* -EIO if msch gets a program check. */ | 385 | if (ccode < 0) /* -EIO if msch gets a program check. */ |
386 | return ccode; | 386 | return ccode; |
387 | switch (ccode) { | 387 | switch (ccode) { |
@@ -414,7 +414,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) | |||
414 | CIO_TRACE_EVENT (2, "ensch"); | 414 | CIO_TRACE_EVENT (2, "ensch"); |
415 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 415 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
416 | 416 | ||
417 | ccode = stsch (sch->irq, &sch->schib); | 417 | ccode = stsch (sch->schid, &sch->schib); |
418 | if (ccode) | 418 | if (ccode) |
419 | return -ENODEV; | 419 | return -ENODEV; |
420 | 420 | ||
@@ -432,13 +432,13 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) | |||
432 | */ | 432 | */ |
433 | sch->schib.pmcw.csense = 0; | 433 | sch->schib.pmcw.csense = 0; |
434 | if (ret == 0) { | 434 | if (ret == 0) { |
435 | stsch (sch->irq, &sch->schib); | 435 | stsch (sch->schid, &sch->schib); |
436 | if (sch->schib.pmcw.ena) | 436 | if (sch->schib.pmcw.ena) |
437 | break; | 437 | break; |
438 | } | 438 | } |
439 | if (ret == -EBUSY) { | 439 | if (ret == -EBUSY) { |
440 | struct irb irb; | 440 | struct irb irb; |
441 | if (tsch(sch->irq, &irb) != 0) | 441 | if (tsch(sch->schid, &irb) != 0) |
442 | break; | 442 | break; |
443 | } | 443 | } |
444 | } | 444 | } |
@@ -461,7 +461,7 @@ cio_disable_subchannel (struct subchannel *sch) | |||
461 | CIO_TRACE_EVENT (2, "dissch"); | 461 | CIO_TRACE_EVENT (2, "dissch"); |
462 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 462 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
463 | 463 | ||
464 | ccode = stsch (sch->irq, &sch->schib); | 464 | ccode = stsch (sch->schid, &sch->schib); |
465 | if (ccode == 3) /* Not operational. */ | 465 | if (ccode == 3) /* Not operational. */ |
466 | return -ENODEV; | 466 | return -ENODEV; |
467 | 467 | ||
@@ -485,7 +485,7 @@ cio_disable_subchannel (struct subchannel *sch) | |||
485 | */ | 485 | */ |
486 | break; | 486 | break; |
487 | if (ret == 0) { | 487 | if (ret == 0) { |
488 | stsch (sch->irq, &sch->schib); | 488 | stsch (sch->schid, &sch->schib); |
489 | if (!sch->schib.pmcw.ena) | 489 | if (!sch->schib.pmcw.ena) |
490 | break; | 490 | break; |
491 | } | 491 | } |
@@ -508,12 +508,12 @@ cio_disable_subchannel (struct subchannel *sch) | |||
508 | * -ENODEV for subchannels with invalid device number or blacklisted devices | 508 | * -ENODEV for subchannels with invalid device number or blacklisted devices |
509 | */ | 509 | */ |
510 | int | 510 | int |
511 | cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | 511 | cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) |
512 | { | 512 | { |
513 | char dbf_txt[15]; | 513 | char dbf_txt[15]; |
514 | int ccode; | 514 | int ccode; |
515 | 515 | ||
516 | sprintf (dbf_txt, "valsch%x", irq); | 516 | sprintf (dbf_txt, "valsch%x", schid.sch_no); |
517 | CIO_TRACE_EVENT (4, dbf_txt); | 517 | CIO_TRACE_EVENT (4, dbf_txt); |
518 | 518 | ||
519 | /* Nuke all fields. */ | 519 | /* Nuke all fields. */ |
@@ -522,17 +522,17 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | |||
522 | spin_lock_init(&sch->lock); | 522 | spin_lock_init(&sch->lock); |
523 | 523 | ||
524 | /* Set a name for the subchannel */ | 524 | /* Set a name for the subchannel */ |
525 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", irq); | 525 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", schid.sch_no); |
526 | 526 | ||
527 | /* | 527 | /* |
528 | * The first subchannel that is not-operational (ccode==3) | 528 | * The first subchannel that is not-operational (ccode==3) |
529 | * indicates that there aren't any more devices available. | 529 | * indicates that there aren't any more devices available. |
530 | */ | 530 | */ |
531 | sch->irq = irq; | 531 | ccode = stsch (schid, &sch->schib); |
532 | ccode = stsch (irq, &sch->schib); | ||
533 | if (ccode) | 532 | if (ccode) |
534 | return -ENXIO; | 533 | return -ENXIO; |
535 | 534 | ||
535 | sch->schid = schid; | ||
536 | /* Copy subchannel type from path management control word. */ | 536 | /* Copy subchannel type from path management control word. */ |
537 | sch->st = sch->schib.pmcw.st; | 537 | sch->st = sch->schib.pmcw.st; |
538 | 538 | ||
@@ -543,7 +543,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | |||
543 | CIO_DEBUG(KERN_INFO, 0, | 543 | CIO_DEBUG(KERN_INFO, 0, |
544 | "Subchannel %04X reports " | 544 | "Subchannel %04X reports " |
545 | "non-I/O subchannel type %04X\n", | 545 | "non-I/O subchannel type %04X\n", |
546 | sch->irq, sch->st); | 546 | sch->schid.sch_no, sch->st); |
547 | /* We stop here for non-io subchannels. */ | 547 | /* We stop here for non-io subchannels. */ |
548 | return sch->st; | 548 | return sch->st; |
549 | } | 549 | } |
@@ -573,7 +573,7 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | |||
573 | CIO_DEBUG(KERN_INFO, 0, | 573 | CIO_DEBUG(KERN_INFO, 0, |
574 | "Detected device %04X on subchannel %04X" | 574 | "Detected device %04X on subchannel %04X" |
575 | " - PIM = %02X, PAM = %02X, POM = %02X\n", | 575 | " - PIM = %02X, PAM = %02X, POM = %02X\n", |
576 | sch->schib.pmcw.dev, sch->irq, sch->schib.pmcw.pim, | 576 | sch->schib.pmcw.dev, sch->schid.sch_no, sch->schib.pmcw.pim, |
577 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); | 577 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); |
578 | 578 | ||
579 | /* | 579 | /* |
@@ -632,7 +632,7 @@ do_IRQ (struct pt_regs *regs) | |||
632 | if (sch) | 632 | if (sch) |
633 | spin_lock(&sch->lock); | 633 | spin_lock(&sch->lock); |
634 | /* Store interrupt response block to lowcore. */ | 634 | /* Store interrupt response block to lowcore. */ |
635 | if (tsch (tpi_info->irq, irb) == 0 && sch) { | 635 | if (tsch (tpi_info->schid, irb) == 0 && sch) { |
636 | /* Keep subchannel information word up to date. */ | 636 | /* Keep subchannel information word up to date. */ |
637 | memcpy (&sch->schib.scsw, &irb->scsw, | 637 | memcpy (&sch->schib.scsw, &irb->scsw, |
638 | sizeof (irb->scsw)); | 638 | sizeof (irb->scsw)); |
@@ -693,26 +693,28 @@ wait_cons_dev (void) | |||
693 | static int | 693 | static int |
694 | cio_console_irq(void) | 694 | cio_console_irq(void) |
695 | { | 695 | { |
696 | int irq; | 696 | struct subchannel_id schid; |
697 | 697 | ||
698 | init_subchannel_id(&schid); | ||
698 | if (console_irq != -1) { | 699 | if (console_irq != -1) { |
699 | /* VM provided us with the irq number of the console. */ | 700 | /* VM provided us with the irq number of the console. */ |
700 | if (stsch(console_irq, &console_subchannel.schib) != 0 || | 701 | schid.sch_no = console_irq; |
702 | if (stsch(schid, &console_subchannel.schib) != 0 || | ||
701 | !console_subchannel.schib.pmcw.dnv) | 703 | !console_subchannel.schib.pmcw.dnv) |
702 | return -1; | 704 | return -1; |
703 | console_devno = console_subchannel.schib.pmcw.dev; | 705 | console_devno = console_subchannel.schib.pmcw.dev; |
704 | } else if (console_devno != -1) { | 706 | } else if (console_devno != -1) { |
705 | /* At least the console device number is known. */ | 707 | /* At least the console device number is known. */ |
706 | for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { | 708 | do { |
707 | if (stsch(irq, &console_subchannel.schib) != 0) | 709 | if (stsch(schid, &console_subchannel.schib) != 0) |
708 | break; | 710 | break; |
709 | if (console_subchannel.schib.pmcw.dnv && | 711 | if (console_subchannel.schib.pmcw.dnv && |
710 | console_subchannel.schib.pmcw.dev == | 712 | console_subchannel.schib.pmcw.dev == |
711 | console_devno) { | 713 | console_devno) { |
712 | console_irq = irq; | 714 | console_irq = schid.sch_no; |
713 | break; | 715 | break; |
714 | } | 716 | } |
715 | } | 717 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); |
716 | if (console_irq == -1) | 718 | if (console_irq == -1) |
717 | return -1; | 719 | return -1; |
718 | } else { | 720 | } else { |
@@ -729,6 +731,7 @@ struct subchannel * | |||
729 | cio_probe_console(void) | 731 | cio_probe_console(void) |
730 | { | 732 | { |
731 | int irq, ret; | 733 | int irq, ret; |
734 | struct subchannel_id schid; | ||
732 | 735 | ||
733 | if (xchg(&console_subchannel_in_use, 1) != 0) | 736 | if (xchg(&console_subchannel_in_use, 1) != 0) |
734 | return ERR_PTR(-EBUSY); | 737 | return ERR_PTR(-EBUSY); |
@@ -738,7 +741,9 @@ cio_probe_console(void) | |||
738 | return ERR_PTR(-ENODEV); | 741 | return ERR_PTR(-ENODEV); |
739 | } | 742 | } |
740 | memset(&console_subchannel, 0, sizeof(struct subchannel)); | 743 | memset(&console_subchannel, 0, sizeof(struct subchannel)); |
741 | ret = cio_validate_subchannel(&console_subchannel, irq); | 744 | init_subchannel_id(&schid); |
745 | schid.sch_no = irq; | ||
746 | ret = cio_validate_subchannel(&console_subchannel, schid); | ||
742 | if (ret) { | 747 | if (ret) { |
743 | console_subchannel_in_use = 0; | 748 | console_subchannel_in_use = 0; |
744 | return ERR_PTR(-ENODEV); | 749 | return ERR_PTR(-ENODEV); |
@@ -770,11 +775,11 @@ cio_release_console(void) | |||
770 | 775 | ||
771 | /* Bah... hack to catch console special sausages. */ | 776 | /* Bah... hack to catch console special sausages. */ |
772 | int | 777 | int |
773 | cio_is_console(int irq) | 778 | cio_is_console(struct subchannel_id schid) |
774 | { | 779 | { |
775 | if (!console_subchannel_in_use) | 780 | if (!console_subchannel_in_use) |
776 | return 0; | 781 | return 0; |
777 | return (irq == console_subchannel.irq); | 782 | return schid_equal(&schid, &console_subchannel.schid); |
778 | } | 783 | } |
779 | 784 | ||
780 | struct subchannel * | 785 | struct subchannel * |
@@ -787,7 +792,7 @@ cio_get_console_subchannel(void) | |||
787 | 792 | ||
788 | #endif | 793 | #endif |
789 | static inline int | 794 | static inline int |
790 | __disable_subchannel_easy(unsigned int schid, struct schib *schib) | 795 | __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) |
791 | { | 796 | { |
792 | int retry, cc; | 797 | int retry, cc; |
793 | 798 | ||
@@ -805,7 +810,7 @@ __disable_subchannel_easy(unsigned int schid, struct schib *schib) | |||
805 | } | 810 | } |
806 | 811 | ||
807 | static inline int | 812 | static inline int |
808 | __clear_subchannel_easy(unsigned int schid) | 813 | __clear_subchannel_easy(struct subchannel_id schid) |
809 | { | 814 | { |
810 | int retry; | 815 | int retry; |
811 | 816 | ||
@@ -815,8 +820,8 @@ __clear_subchannel_easy(unsigned int schid) | |||
815 | struct tpi_info ti; | 820 | struct tpi_info ti; |
816 | 821 | ||
817 | if (tpi(&ti)) { | 822 | if (tpi(&ti)) { |
818 | tsch(ti.irq, (struct irb *)__LC_IRB); | 823 | tsch(ti.schid, (struct irb *)__LC_IRB); |
819 | if (ti.irq == schid) | 824 | if (schid_equal(&ti.schid, &schid)) |
820 | return 0; | 825 | return 0; |
821 | } | 826 | } |
822 | udelay(100); | 827 | udelay(100); |
@@ -830,10 +835,11 @@ extern void do_reipl(unsigned long devno); | |||
830 | void | 835 | void |
831 | clear_all_subchannels(void) | 836 | clear_all_subchannels(void) |
832 | { | 837 | { |
833 | unsigned int schid; | 838 | struct subchannel_id schid; |
834 | 839 | ||
835 | local_irq_disable(); | 840 | local_irq_disable(); |
836 | for (schid=0;schid<=highest_subchannel;schid++) { | 841 | init_subchannel_id(&schid); |
842 | do { | ||
837 | struct schib schib; | 843 | struct schib schib; |
838 | if (stsch(schid, &schib)) | 844 | if (stsch(schid, &schib)) |
839 | break; /* break out of the loop */ | 845 | break; /* break out of the loop */ |
@@ -849,7 +855,7 @@ clear_all_subchannels(void) | |||
849 | stsch(schid, &schib); | 855 | stsch(schid, &schib); |
850 | __disable_subchannel_easy(schid, &schib); | 856 | __disable_subchannel_easy(schid, &schib); |
851 | } | 857 | } |
852 | } | 858 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); |
853 | } | 859 | } |
854 | 860 | ||
855 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 861 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |