Commit da244654c66e78e03668863974ec74c981934c38
Committed by
James Bottomley
1 parent
09e13e9167
Exists in
master
and in
7 other branches
[SCSI] mac_esp: fix for quadras with two esp chips
On the Quadra 900 and 950 there are two ESP chips sharing one IRQ. Because the shared IRQ is edge-triggered, we must make sure that an IRQ transition from one chip doesn't go unnoticed when the shared IRQ is already active due to the other. This patch prevents interrupts getting lost so that both SCSI busses may be used simultaneously. Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Showing 1 changed file with 58 additions and 23 deletions Side-by-side Diff
drivers/scsi/mac_esp.c
... | ... | @@ -53,7 +53,8 @@ |
53 | 53 | void __iomem *pdma_io; |
54 | 54 | int error; |
55 | 55 | }; |
56 | -static struct platform_device *internal_esp, *external_esp; | |
56 | +static struct platform_device *internal_pdev, *external_pdev; | |
57 | +static struct esp *esp_chips[2]; | |
57 | 58 | |
58 | 59 | #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ |
59 | 60 | platform_get_drvdata((struct platform_device *) \ |
... | ... | @@ -443,6 +444,32 @@ |
443 | 444 | return dma_len > 0xFFFF ? 0xFFFF : dma_len; |
444 | 445 | } |
445 | 446 | |
447 | +static irqreturn_t mac_scsi_esp_intr(int irq, void *dev_id) | |
448 | +{ | |
449 | + int got_intr; | |
450 | + | |
451 | + /* | |
452 | + * This is an edge triggered IRQ, so we have to be careful to | |
453 | + * avoid missing a transition when it is shared by two ESP devices. | |
454 | + */ | |
455 | + | |
456 | + do { | |
457 | + got_intr = 0; | |
458 | + if (esp_chips[0] && | |
459 | + (mac_esp_read8(esp_chips[0], ESP_STATUS) & ESP_STAT_INTR)) { | |
460 | + (void)scsi_esp_intr(irq, esp_chips[0]); | |
461 | + got_intr = 1; | |
462 | + } | |
463 | + if (esp_chips[1] && | |
464 | + (mac_esp_read8(esp_chips[1], ESP_STATUS) & ESP_STAT_INTR)) { | |
465 | + (void)scsi_esp_intr(irq, esp_chips[1]); | |
466 | + got_intr = 1; | |
467 | + } | |
468 | + } while (got_intr); | |
469 | + | |
470 | + return IRQ_HANDLED; | |
471 | +} | |
472 | + | |
446 | 473 | static struct esp_driver_ops mac_esp_ops = { |
447 | 474 | .esp_write8 = mac_esp_write8, |
448 | 475 | .esp_read8 = mac_esp_read8, |
... | ... | @@ -557,10 +584,16 @@ |
557 | 584 | } |
558 | 585 | |
559 | 586 | host->irq = IRQ_MAC_SCSI; |
560 | - err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "Mac ESP", | |
561 | - esp); | |
562 | - if (err < 0) | |
563 | - goto fail_free_priv; | |
587 | + esp_chips[dev->id] = esp; | |
588 | + mb(); | |
589 | + if (esp_chips[!dev->id] == NULL) { | |
590 | + err = request_irq(host->irq, mac_scsi_esp_intr, 0, | |
591 | + "Mac ESP", NULL); | |
592 | + if (err < 0) { | |
593 | + esp_chips[dev->id] = NULL; | |
594 | + goto fail_free_priv; | |
595 | + } | |
596 | + } | |
564 | 597 | |
565 | 598 | err = scsi_esp_register(esp, &dev->dev); |
566 | 599 | if (err) |
... | ... | @@ -569,7 +602,8 @@ |
569 | 602 | return 0; |
570 | 603 | |
571 | 604 | fail_free_irq: |
572 | - free_irq(host->irq, esp); | |
605 | + if (esp_chips[!dev->id] == NULL) | |
606 | + free_irq(host->irq, esp); | |
573 | 607 | fail_free_priv: |
574 | 608 | kfree(mep); |
575 | 609 | fail_free_command_block: |
... | ... | @@ -588,7 +622,9 @@ |
588 | 622 | |
589 | 623 | scsi_esp_unregister(esp); |
590 | 624 | |
591 | - free_irq(irq, esp); | |
625 | + esp_chips[dev->id] = NULL; | |
626 | + if (!(esp_chips[0] || esp_chips[1])) | |
627 | + free_irq(irq, NULL); | |
592 | 628 | |
593 | 629 | kfree(mep); |
594 | 630 | |
595 | 631 | |
596 | 632 | |
... | ... | @@ -615,19 +651,18 @@ |
615 | 651 | if (err) |
616 | 652 | return err; |
617 | 653 | |
618 | - internal_esp = platform_device_alloc(DRV_MODULE_NAME, 0); | |
619 | - if (internal_esp && platform_device_add(internal_esp)) { | |
620 | - platform_device_put(internal_esp); | |
621 | - internal_esp = NULL; | |
654 | + internal_pdev = platform_device_alloc(DRV_MODULE_NAME, 0); | |
655 | + if (internal_pdev && platform_device_add(internal_pdev)) { | |
656 | + platform_device_put(internal_pdev); | |
657 | + internal_pdev = NULL; | |
622 | 658 | } |
623 | - | |
624 | - external_esp = platform_device_alloc(DRV_MODULE_NAME, 1); | |
625 | - if (external_esp && platform_device_add(external_esp)) { | |
626 | - platform_device_put(external_esp); | |
627 | - external_esp = NULL; | |
659 | + external_pdev = platform_device_alloc(DRV_MODULE_NAME, 1); | |
660 | + if (external_pdev && platform_device_add(external_pdev)) { | |
661 | + platform_device_put(external_pdev); | |
662 | + external_pdev = NULL; | |
628 | 663 | } |
629 | 664 | |
630 | - if (internal_esp || external_esp) { | |
665 | + if (internal_pdev || external_pdev) { | |
631 | 666 | return 0; |
632 | 667 | } else { |
633 | 668 | platform_driver_unregister(&esp_mac_driver); |
634 | 669 | |
... | ... | @@ -639,13 +674,13 @@ |
639 | 674 | { |
640 | 675 | platform_driver_unregister(&esp_mac_driver); |
641 | 676 | |
642 | - if (internal_esp) { | |
643 | - platform_device_unregister(internal_esp); | |
644 | - internal_esp = NULL; | |
677 | + if (internal_pdev) { | |
678 | + platform_device_unregister(internal_pdev); | |
679 | + internal_pdev = NULL; | |
645 | 680 | } |
646 | - if (external_esp) { | |
647 | - platform_device_unregister(external_esp); | |
648 | - external_esp = NULL; | |
681 | + if (external_pdev) { | |
682 | + platform_device_unregister(external_pdev); | |
683 | + external_pdev = NULL; | |
649 | 684 | } |
650 | 685 | } |
651 | 686 |