aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/mac_esp.c
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2008-11-17 15:37:45 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-12-29 12:24:19 -0500
commitda244654c66e78e03668863974ec74c981934c38 (patch)
treeb0aadb4b90381c175afa2a3504b949f235f00097 /drivers/scsi/mac_esp.c
parent09e13e91670b69736b5da0a869a076a55a326394 (diff)
[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>
Diffstat (limited to 'drivers/scsi/mac_esp.c')
-rw-r--r--drivers/scsi/mac_esp.c81
1 files changed, 58 insertions, 23 deletions
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index a99f9ce6be55..c24e86f07804 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -53,7 +53,8 @@ struct mac_esp_priv {
53 void __iomem *pdma_io; 53 void __iomem *pdma_io;
54 int error; 54 int error;
55}; 55};
56static struct platform_device *internal_esp, *external_esp; 56static struct platform_device *internal_pdev, *external_pdev;
57static struct esp *esp_chips[2];
57 58
58#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ 59#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \
59 platform_get_drvdata((struct platform_device *) \ 60 platform_get_drvdata((struct platform_device *) \
@@ -443,6 +444,32 @@ static u32 mac_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
443 return dma_len > 0xFFFF ? 0xFFFF : dma_len; 444 return dma_len > 0xFFFF ? 0xFFFF : dma_len;
444} 445}
445 446
447static 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
446static struct esp_driver_ops mac_esp_ops = { 473static struct esp_driver_ops mac_esp_ops = {
447 .esp_write8 = mac_esp_write8, 474 .esp_write8 = mac_esp_write8,
448 .esp_read8 = mac_esp_read8, 475 .esp_read8 = mac_esp_read8,
@@ -557,10 +584,16 @@ static int __devinit esp_mac_probe(struct platform_device *dev)
557 } 584 }
558 585
559 host->irq = IRQ_MAC_SCSI; 586 host->irq = IRQ_MAC_SCSI;
560 err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "Mac ESP", 587 esp_chips[dev->id] = esp;
561 esp); 588 mb();
562 if (err < 0) 589 if (esp_chips[!dev->id] == NULL) {
563 goto fail_free_priv; 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 err = scsi_esp_register(esp, &dev->dev); 598 err = scsi_esp_register(esp, &dev->dev);
566 if (err) 599 if (err)
@@ -569,7 +602,8 @@ static int __devinit esp_mac_probe(struct platform_device *dev)
569 return 0; 602 return 0;
570 603
571fail_free_irq: 604fail_free_irq:
572 free_irq(host->irq, esp); 605 if (esp_chips[!dev->id] == NULL)
606 free_irq(host->irq, esp);
573fail_free_priv: 607fail_free_priv:
574 kfree(mep); 608 kfree(mep);
575fail_free_command_block: 609fail_free_command_block:
@@ -588,7 +622,9 @@ static int __devexit esp_mac_remove(struct platform_device *dev)
588 622
589 scsi_esp_unregister(esp); 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 kfree(mep); 629 kfree(mep);
594 630
@@ -615,19 +651,18 @@ static int __init mac_esp_init(void)
615 if (err) 651 if (err)
616 return err; 652 return err;
617 653
618 internal_esp = platform_device_alloc(DRV_MODULE_NAME, 0); 654 internal_pdev = platform_device_alloc(DRV_MODULE_NAME, 0);
619 if (internal_esp && platform_device_add(internal_esp)) { 655 if (internal_pdev && platform_device_add(internal_pdev)) {
620 platform_device_put(internal_esp); 656 platform_device_put(internal_pdev);
621 internal_esp = NULL; 657 internal_pdev = NULL;
622 } 658 }
623 659 external_pdev = platform_device_alloc(DRV_MODULE_NAME, 1);
624 external_esp = platform_device_alloc(DRV_MODULE_NAME, 1); 660 if (external_pdev && platform_device_add(external_pdev)) {
625 if (external_esp && platform_device_add(external_esp)) { 661 platform_device_put(external_pdev);
626 platform_device_put(external_esp); 662 external_pdev = NULL;
627 external_esp = NULL;
628 } 663 }
629 664
630 if (internal_esp || external_esp) { 665 if (internal_pdev || external_pdev) {
631 return 0; 666 return 0;
632 } else { 667 } else {
633 platform_driver_unregister(&esp_mac_driver); 668 platform_driver_unregister(&esp_mac_driver);
@@ -639,13 +674,13 @@ static void __exit mac_esp_exit(void)
639{ 674{
640 platform_driver_unregister(&esp_mac_driver); 675 platform_driver_unregister(&esp_mac_driver);
641 676
642 if (internal_esp) { 677 if (internal_pdev) {
643 platform_device_unregister(internal_esp); 678 platform_device_unregister(internal_pdev);
644 internal_esp = NULL; 679 internal_pdev = NULL;
645 } 680 }
646 if (external_esp) { 681 if (external_pdev) {
647 platform_device_unregister(external_esp); 682 platform_device_unregister(external_pdev);
648 external_esp = NULL; 683 external_pdev = NULL;
649 } 684 }
650} 685}
651 686