diff options
Diffstat (limited to 'drivers/s390/cio/cio.c')
-rw-r--r-- | drivers/s390/cio/cio.c | 168 |
1 files changed, 94 insertions, 74 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 185bc73c3ecd..7376bc87206d 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/cio.c | 2 | * drivers/s390/cio/cio.c |
3 | * S/390 common I/O routines -- low level i/o calls | 3 | * S/390 common I/O routines -- low level i/o calls |
4 | * $Revision: 1.135 $ | 4 | * $Revision: 1.138 $ |
5 | * | 5 | * |
6 | * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, | 6 | * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, |
7 | * IBM Corporation | 7 | * IBM Corporation |
@@ -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,11 @@ 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 0.%x.%04x!\n", sch->schid.ssid, |
170 | sch->schid.sch_no); | ||
170 | sprintf(dbf_text, "no%s", sch->dev.bus_id); | 171 | sprintf(dbf_text, "no%s", sch->dev.bus_id); |
171 | CIO_TRACE_EVENT(0, dbf_text); | 172 | CIO_TRACE_EVENT(0, dbf_text); |
172 | CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); | 173 | CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); |
@@ -194,7 +195,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ | |||
194 | sch->orb.spnd = sch->options.suspend; | 195 | sch->orb.spnd = sch->options.suspend; |
195 | sch->orb.ssic = sch->options.suspend && sch->options.inter; | 196 | sch->orb.ssic = sch->options.suspend && sch->options.inter; |
196 | sch->orb.lpm = (lpm != 0) ? (lpm & sch->opm) : sch->lpm; | 197 | sch->orb.lpm = (lpm != 0) ? (lpm & sch->opm) : sch->lpm; |
197 | #ifdef CONFIG_ARCH_S390X | 198 | #ifdef CONFIG_64BIT |
198 | /* | 199 | /* |
199 | * for 64 bit we always support 64 bit IDAWs with 4k page size only | 200 | * for 64 bit we always support 64 bit IDAWs with 4k page size only |
200 | */ | 201 | */ |
@@ -204,7 +205,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ | |||
204 | sch->orb.key = key >> 4; | 205 | sch->orb.key = key >> 4; |
205 | /* issue "Start Subchannel" */ | 206 | /* issue "Start Subchannel" */ |
206 | sch->orb.cpa = (__u32) __pa (cpa); | 207 | sch->orb.cpa = (__u32) __pa (cpa); |
207 | ccode = ssch (sch->irq, &sch->orb); | 208 | ccode = ssch (sch->schid, &sch->orb); |
208 | 209 | ||
209 | /* process condition code */ | 210 | /* process condition code */ |
210 | sprintf (dbf_txt, "ccode:%d", ccode); | 211 | sprintf (dbf_txt, "ccode:%d", ccode); |
@@ -243,7 +244,7 @@ cio_resume (struct subchannel *sch) | |||
243 | CIO_TRACE_EVENT (4, "resIO"); | 244 | CIO_TRACE_EVENT (4, "resIO"); |
244 | CIO_TRACE_EVENT (4, sch->dev.bus_id); | 245 | CIO_TRACE_EVENT (4, sch->dev.bus_id); |
245 | 246 | ||
246 | ccode = rsch (sch->irq); | 247 | ccode = rsch (sch->schid); |
247 | 248 | ||
248 | sprintf (dbf_txt, "ccode:%d", ccode); | 249 | sprintf (dbf_txt, "ccode:%d", ccode); |
249 | CIO_TRACE_EVENT (4, dbf_txt); | 250 | CIO_TRACE_EVENT (4, dbf_txt); |
@@ -283,7 +284,7 @@ cio_halt(struct subchannel *sch) | |||
283 | /* | 284 | /* |
284 | * Issue "Halt subchannel" and process condition code | 285 | * Issue "Halt subchannel" and process condition code |
285 | */ | 286 | */ |
286 | ccode = hsch (sch->irq); | 287 | ccode = hsch (sch->schid); |
287 | 288 | ||
288 | sprintf (dbf_txt, "ccode:%d", ccode); | 289 | sprintf (dbf_txt, "ccode:%d", ccode); |
289 | CIO_TRACE_EVENT (2, dbf_txt); | 290 | CIO_TRACE_EVENT (2, dbf_txt); |
@@ -318,7 +319,7 @@ cio_clear(struct subchannel *sch) | |||
318 | /* | 319 | /* |
319 | * Issue "Clear subchannel" and process condition code | 320 | * Issue "Clear subchannel" and process condition code |
320 | */ | 321 | */ |
321 | ccode = csch (sch->irq); | 322 | ccode = csch (sch->schid); |
322 | 323 | ||
323 | sprintf (dbf_txt, "ccode:%d", ccode); | 324 | sprintf (dbf_txt, "ccode:%d", ccode); |
324 | CIO_TRACE_EVENT (2, dbf_txt); | 325 | CIO_TRACE_EVENT (2, dbf_txt); |
@@ -351,7 +352,7 @@ cio_cancel (struct subchannel *sch) | |||
351 | CIO_TRACE_EVENT (2, "cancelIO"); | 352 | CIO_TRACE_EVENT (2, "cancelIO"); |
352 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 353 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
353 | 354 | ||
354 | ccode = xsch (sch->irq); | 355 | ccode = xsch (sch->schid); |
355 | 356 | ||
356 | sprintf (dbf_txt, "ccode:%d", ccode); | 357 | sprintf (dbf_txt, "ccode:%d", ccode); |
357 | CIO_TRACE_EVENT (2, dbf_txt); | 358 | CIO_TRACE_EVENT (2, dbf_txt); |
@@ -359,7 +360,7 @@ cio_cancel (struct subchannel *sch) | |||
359 | switch (ccode) { | 360 | switch (ccode) { |
360 | case 0: /* success */ | 361 | case 0: /* success */ |
361 | /* Update information in scsw. */ | 362 | /* Update information in scsw. */ |
362 | stsch (sch->irq, &sch->schib); | 363 | stsch (sch->schid, &sch->schib); |
363 | return 0; | 364 | return 0; |
364 | case 1: /* status pending */ | 365 | case 1: /* status pending */ |
365 | return -EBUSY; | 366 | return -EBUSY; |
@@ -381,7 +382,7 @@ cio_modify (struct subchannel *sch) | |||
381 | 382 | ||
382 | ret = 0; | 383 | ret = 0; |
383 | for (retry = 0; retry < 5; retry++) { | 384 | for (retry = 0; retry < 5; retry++) { |
384 | ccode = msch_err (sch->irq, &sch->schib); | 385 | ccode = msch_err (sch->schid, &sch->schib); |
385 | if (ccode < 0) /* -EIO if msch gets a program check. */ | 386 | if (ccode < 0) /* -EIO if msch gets a program check. */ |
386 | return ccode; | 387 | return ccode; |
387 | switch (ccode) { | 388 | switch (ccode) { |
@@ -414,7 +415,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) | |||
414 | CIO_TRACE_EVENT (2, "ensch"); | 415 | CIO_TRACE_EVENT (2, "ensch"); |
415 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 416 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
416 | 417 | ||
417 | ccode = stsch (sch->irq, &sch->schib); | 418 | ccode = stsch (sch->schid, &sch->schib); |
418 | if (ccode) | 419 | if (ccode) |
419 | return -ENODEV; | 420 | return -ENODEV; |
420 | 421 | ||
@@ -432,13 +433,13 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) | |||
432 | */ | 433 | */ |
433 | sch->schib.pmcw.csense = 0; | 434 | sch->schib.pmcw.csense = 0; |
434 | if (ret == 0) { | 435 | if (ret == 0) { |
435 | stsch (sch->irq, &sch->schib); | 436 | stsch (sch->schid, &sch->schib); |
436 | if (sch->schib.pmcw.ena) | 437 | if (sch->schib.pmcw.ena) |
437 | break; | 438 | break; |
438 | } | 439 | } |
439 | if (ret == -EBUSY) { | 440 | if (ret == -EBUSY) { |
440 | struct irb irb; | 441 | struct irb irb; |
441 | if (tsch(sch->irq, &irb) != 0) | 442 | if (tsch(sch->schid, &irb) != 0) |
442 | break; | 443 | break; |
443 | } | 444 | } |
444 | } | 445 | } |
@@ -461,7 +462,7 @@ cio_disable_subchannel (struct subchannel *sch) | |||
461 | CIO_TRACE_EVENT (2, "dissch"); | 462 | CIO_TRACE_EVENT (2, "dissch"); |
462 | CIO_TRACE_EVENT (2, sch->dev.bus_id); | 463 | CIO_TRACE_EVENT (2, sch->dev.bus_id); |
463 | 464 | ||
464 | ccode = stsch (sch->irq, &sch->schib); | 465 | ccode = stsch (sch->schid, &sch->schib); |
465 | if (ccode == 3) /* Not operational. */ | 466 | if (ccode == 3) /* Not operational. */ |
466 | return -ENODEV; | 467 | return -ENODEV; |
467 | 468 | ||
@@ -485,7 +486,7 @@ cio_disable_subchannel (struct subchannel *sch) | |||
485 | */ | 486 | */ |
486 | break; | 487 | break; |
487 | if (ret == 0) { | 488 | if (ret == 0) { |
488 | stsch (sch->irq, &sch->schib); | 489 | stsch (sch->schid, &sch->schib); |
489 | if (!sch->schib.pmcw.ena) | 490 | if (!sch->schib.pmcw.ena) |
490 | break; | 491 | break; |
491 | } | 492 | } |
@@ -508,12 +509,12 @@ cio_disable_subchannel (struct subchannel *sch) | |||
508 | * -ENODEV for subchannels with invalid device number or blacklisted devices | 509 | * -ENODEV for subchannels with invalid device number or blacklisted devices |
509 | */ | 510 | */ |
510 | int | 511 | int |
511 | cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | 512 | cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) |
512 | { | 513 | { |
513 | char dbf_txt[15]; | 514 | char dbf_txt[15]; |
514 | int ccode; | 515 | int ccode; |
515 | 516 | ||
516 | sprintf (dbf_txt, "valsch%x", irq); | 517 | sprintf (dbf_txt, "valsch%x", schid.sch_no); |
517 | CIO_TRACE_EVENT (4, dbf_txt); | 518 | CIO_TRACE_EVENT (4, dbf_txt); |
518 | 519 | ||
519 | /* Nuke all fields. */ | 520 | /* Nuke all fields. */ |
@@ -522,17 +523,20 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | |||
522 | spin_lock_init(&sch->lock); | 523 | spin_lock_init(&sch->lock); |
523 | 524 | ||
524 | /* Set a name for the subchannel */ | 525 | /* Set a name for the subchannel */ |
525 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", irq); | 526 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid, |
527 | schid.sch_no); | ||
526 | 528 | ||
527 | /* | 529 | /* |
528 | * The first subchannel that is not-operational (ccode==3) | 530 | * The first subchannel that is not-operational (ccode==3) |
529 | * indicates that there aren't any more devices available. | 531 | * indicates that there aren't any more devices available. |
532 | * If stsch gets an exception, it means the current subchannel set | ||
533 | * is not valid. | ||
530 | */ | 534 | */ |
531 | sch->irq = irq; | 535 | ccode = stsch_err (schid, &sch->schib); |
532 | ccode = stsch (irq, &sch->schib); | ||
533 | if (ccode) | 536 | if (ccode) |
534 | return -ENXIO; | 537 | return (ccode == 3) ? -ENXIO : ccode; |
535 | 538 | ||
539 | sch->schid = schid; | ||
536 | /* Copy subchannel type from path management control word. */ | 540 | /* Copy subchannel type from path management control word. */ |
537 | sch->st = sch->schib.pmcw.st; | 541 | sch->st = sch->schib.pmcw.st; |
538 | 542 | ||
@@ -541,9 +545,9 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | |||
541 | */ | 545 | */ |
542 | if (sch->st != 0) { | 546 | if (sch->st != 0) { |
543 | CIO_DEBUG(KERN_INFO, 0, | 547 | CIO_DEBUG(KERN_INFO, 0, |
544 | "Subchannel %04X reports " | 548 | "Subchannel 0.%x.%04x reports " |
545 | "non-I/O subchannel type %04X\n", | 549 | "non-I/O subchannel type %04X\n", |
546 | sch->irq, sch->st); | 550 | sch->schid.ssid, sch->schid.sch_no, sch->st); |
547 | /* We stop here for non-io subchannels. */ | 551 | /* We stop here for non-io subchannels. */ |
548 | return sch->st; | 552 | return sch->st; |
549 | } | 553 | } |
@@ -554,26 +558,29 @@ cio_validate_subchannel (struct subchannel *sch, unsigned int irq) | |||
554 | return -ENODEV; | 558 | return -ENODEV; |
555 | 559 | ||
556 | /* Devno is valid. */ | 560 | /* Devno is valid. */ |
557 | if (is_blacklisted (sch->schib.pmcw.dev)) { | 561 | if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) { |
558 | /* | 562 | /* |
559 | * This device must not be known to Linux. So we simply | 563 | * This device must not be known to Linux. So we simply |
560 | * say that there is no device and return ENODEV. | 564 | * say that there is no device and return ENODEV. |
561 | */ | 565 | */ |
562 | CIO_MSG_EVENT(0, "Blacklisted device detected " | 566 | CIO_MSG_EVENT(0, "Blacklisted device detected " |
563 | "at devno %04X\n", sch->schib.pmcw.dev); | 567 | "at devno %04X, subchannel set %x\n", |
568 | sch->schib.pmcw.dev, sch->schid.ssid); | ||
564 | return -ENODEV; | 569 | return -ENODEV; |
565 | } | 570 | } |
566 | sch->opm = 0xff; | 571 | sch->opm = 0xff; |
567 | chsc_validate_chpids(sch); | 572 | if (!cio_is_console(sch->schid)) |
573 | chsc_validate_chpids(sch); | ||
568 | sch->lpm = sch->schib.pmcw.pim & | 574 | sch->lpm = sch->schib.pmcw.pim & |
569 | sch->schib.pmcw.pam & | 575 | sch->schib.pmcw.pam & |
570 | sch->schib.pmcw.pom & | 576 | sch->schib.pmcw.pom & |
571 | sch->opm; | 577 | sch->opm; |
572 | 578 | ||
573 | CIO_DEBUG(KERN_INFO, 0, | 579 | CIO_DEBUG(KERN_INFO, 0, |
574 | "Detected device %04X on subchannel %04X" | 580 | "Detected device %04x on subchannel 0.%x.%04X" |
575 | " - PIM = %02X, PAM = %02X, POM = %02X\n", | 581 | " - PIM = %02X, PAM = %02X, POM = %02X\n", |
576 | sch->schib.pmcw.dev, sch->irq, sch->schib.pmcw.pim, | 582 | sch->schib.pmcw.dev, sch->schid.ssid, |
583 | sch->schid.sch_no, sch->schib.pmcw.pim, | ||
577 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); | 584 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); |
578 | 585 | ||
579 | /* | 586 | /* |
@@ -632,7 +639,7 @@ do_IRQ (struct pt_regs *regs) | |||
632 | if (sch) | 639 | if (sch) |
633 | spin_lock(&sch->lock); | 640 | spin_lock(&sch->lock); |
634 | /* Store interrupt response block to lowcore. */ | 641 | /* Store interrupt response block to lowcore. */ |
635 | if (tsch (tpi_info->irq, irb) == 0 && sch) { | 642 | if (tsch (tpi_info->schid, irb) == 0 && sch) { |
636 | /* Keep subchannel information word up to date. */ | 643 | /* Keep subchannel information word up to date. */ |
637 | memcpy (&sch->schib.scsw, &irb->scsw, | 644 | memcpy (&sch->schib.scsw, &irb->scsw, |
638 | sizeof (irb->scsw)); | 645 | sizeof (irb->scsw)); |
@@ -691,28 +698,36 @@ wait_cons_dev (void) | |||
691 | } | 698 | } |
692 | 699 | ||
693 | static int | 700 | static int |
694 | cio_console_irq(void) | 701 | cio_test_for_console(struct subchannel_id schid, void *data) |
695 | { | 702 | { |
696 | int irq; | 703 | if (stsch_err(schid, &console_subchannel.schib) != 0) |
704 | return -ENXIO; | ||
705 | if (console_subchannel.schib.pmcw.dnv && | ||
706 | console_subchannel.schib.pmcw.dev == | ||
707 | console_devno) { | ||
708 | console_irq = schid.sch_no; | ||
709 | return 1; /* found */ | ||
710 | } | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | |||
715 | static int | ||
716 | cio_get_console_sch_no(void) | ||
717 | { | ||
718 | struct subchannel_id schid; | ||
697 | 719 | ||
720 | init_subchannel_id(&schid); | ||
698 | if (console_irq != -1) { | 721 | if (console_irq != -1) { |
699 | /* VM provided us with the irq number of the console. */ | 722 | /* VM provided us with the irq number of the console. */ |
700 | if (stsch(console_irq, &console_subchannel.schib) != 0 || | 723 | schid.sch_no = console_irq; |
724 | if (stsch(schid, &console_subchannel.schib) != 0 || | ||
701 | !console_subchannel.schib.pmcw.dnv) | 725 | !console_subchannel.schib.pmcw.dnv) |
702 | return -1; | 726 | return -1; |
703 | console_devno = console_subchannel.schib.pmcw.dev; | 727 | console_devno = console_subchannel.schib.pmcw.dev; |
704 | } else if (console_devno != -1) { | 728 | } else if (console_devno != -1) { |
705 | /* At least the console device number is known. */ | 729 | /* At least the console device number is known. */ |
706 | for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) { | 730 | for_each_subchannel(cio_test_for_console, NULL); |
707 | if (stsch(irq, &console_subchannel.schib) != 0) | ||
708 | break; | ||
709 | if (console_subchannel.schib.pmcw.dnv && | ||
710 | console_subchannel.schib.pmcw.dev == | ||
711 | console_devno) { | ||
712 | console_irq = irq; | ||
713 | break; | ||
714 | } | ||
715 | } | ||
716 | if (console_irq == -1) | 731 | if (console_irq == -1) |
717 | return -1; | 732 | return -1; |
718 | } else { | 733 | } else { |
@@ -728,17 +743,20 @@ cio_console_irq(void) | |||
728 | struct subchannel * | 743 | struct subchannel * |
729 | cio_probe_console(void) | 744 | cio_probe_console(void) |
730 | { | 745 | { |
731 | int irq, ret; | 746 | int sch_no, ret; |
747 | struct subchannel_id schid; | ||
732 | 748 | ||
733 | if (xchg(&console_subchannel_in_use, 1) != 0) | 749 | if (xchg(&console_subchannel_in_use, 1) != 0) |
734 | return ERR_PTR(-EBUSY); | 750 | return ERR_PTR(-EBUSY); |
735 | irq = cio_console_irq(); | 751 | sch_no = cio_get_console_sch_no(); |
736 | if (irq == -1) { | 752 | if (sch_no == -1) { |
737 | console_subchannel_in_use = 0; | 753 | console_subchannel_in_use = 0; |
738 | return ERR_PTR(-ENODEV); | 754 | return ERR_PTR(-ENODEV); |
739 | } | 755 | } |
740 | memset(&console_subchannel, 0, sizeof(struct subchannel)); | 756 | memset(&console_subchannel, 0, sizeof(struct subchannel)); |
741 | ret = cio_validate_subchannel(&console_subchannel, irq); | 757 | init_subchannel_id(&schid); |
758 | schid.sch_no = sch_no; | ||
759 | ret = cio_validate_subchannel(&console_subchannel, schid); | ||
742 | if (ret) { | 760 | if (ret) { |
743 | console_subchannel_in_use = 0; | 761 | console_subchannel_in_use = 0; |
744 | return ERR_PTR(-ENODEV); | 762 | return ERR_PTR(-ENODEV); |
@@ -770,11 +788,11 @@ cio_release_console(void) | |||
770 | 788 | ||
771 | /* Bah... hack to catch console special sausages. */ | 789 | /* Bah... hack to catch console special sausages. */ |
772 | int | 790 | int |
773 | cio_is_console(int irq) | 791 | cio_is_console(struct subchannel_id schid) |
774 | { | 792 | { |
775 | if (!console_subchannel_in_use) | 793 | if (!console_subchannel_in_use) |
776 | return 0; | 794 | return 0; |
777 | return (irq == console_subchannel.irq); | 795 | return schid_equal(&schid, &console_subchannel.schid); |
778 | } | 796 | } |
779 | 797 | ||
780 | struct subchannel * | 798 | struct subchannel * |
@@ -787,7 +805,7 @@ cio_get_console_subchannel(void) | |||
787 | 805 | ||
788 | #endif | 806 | #endif |
789 | static inline int | 807 | static inline int |
790 | __disable_subchannel_easy(unsigned int schid, struct schib *schib) | 808 | __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) |
791 | { | 809 | { |
792 | int retry, cc; | 810 | int retry, cc; |
793 | 811 | ||
@@ -805,7 +823,7 @@ __disable_subchannel_easy(unsigned int schid, struct schib *schib) | |||
805 | } | 823 | } |
806 | 824 | ||
807 | static inline int | 825 | static inline int |
808 | __clear_subchannel_easy(unsigned int schid) | 826 | __clear_subchannel_easy(struct subchannel_id schid) |
809 | { | 827 | { |
810 | int retry; | 828 | int retry; |
811 | 829 | ||
@@ -815,8 +833,8 @@ __clear_subchannel_easy(unsigned int schid) | |||
815 | struct tpi_info ti; | 833 | struct tpi_info ti; |
816 | 834 | ||
817 | if (tpi(&ti)) { | 835 | if (tpi(&ti)) { |
818 | tsch(ti.irq, (struct irb *)__LC_IRB); | 836 | tsch(ti.schid, (struct irb *)__LC_IRB); |
819 | if (ti.irq == schid) | 837 | if (schid_equal(&ti.schid, &schid)) |
820 | return 0; | 838 | return 0; |
821 | } | 839 | } |
822 | udelay(100); | 840 | udelay(100); |
@@ -825,31 +843,33 @@ __clear_subchannel_easy(unsigned int schid) | |||
825 | } | 843 | } |
826 | 844 | ||
827 | extern void do_reipl(unsigned long devno); | 845 | extern void do_reipl(unsigned long devno); |
846 | static int | ||
847 | __shutdown_subchannel_easy(struct subchannel_id schid, void *data) | ||
848 | { | ||
849 | struct schib schib; | ||
850 | |||
851 | if (stsch_err(schid, &schib)) | ||
852 | return -ENXIO; | ||
853 | if (!schib.pmcw.ena) | ||
854 | return 0; | ||
855 | switch(__disable_subchannel_easy(schid, &schib)) { | ||
856 | case 0: | ||
857 | case -ENODEV: | ||
858 | break; | ||
859 | default: /* -EBUSY */ | ||
860 | if (__clear_subchannel_easy(schid)) | ||
861 | break; /* give up... */ | ||
862 | stsch(schid, &schib); | ||
863 | __disable_subchannel_easy(schid, &schib); | ||
864 | } | ||
865 | return 0; | ||
866 | } | ||
828 | 867 | ||
829 | /* Clear all subchannels. */ | ||
830 | void | 868 | void |
831 | clear_all_subchannels(void) | 869 | clear_all_subchannels(void) |
832 | { | 870 | { |
833 | unsigned int schid; | ||
834 | |||
835 | local_irq_disable(); | 871 | local_irq_disable(); |
836 | for (schid=0;schid<=highest_subchannel;schid++) { | 872 | for_each_subchannel(__shutdown_subchannel_easy, NULL); |
837 | struct schib schib; | ||
838 | if (stsch(schid, &schib)) | ||
839 | break; /* break out of the loop */ | ||
840 | if (!schib.pmcw.ena) | ||
841 | continue; | ||
842 | switch(__disable_subchannel_easy(schid, &schib)) { | ||
843 | case 0: | ||
844 | case -ENODEV: | ||
845 | break; | ||
846 | default: /* -EBUSY */ | ||
847 | if (__clear_subchannel_easy(schid)) | ||
848 | break; /* give up... jump out of switch */ | ||
849 | stsch(schid, &schib); | ||
850 | __disable_subchannel_easy(schid, &schib); | ||
851 | } | ||
852 | } | ||
853 | } | 873 | } |
854 | 874 | ||
855 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 875 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |