diff options
Diffstat (limited to 'drivers/scsi/mac_esp.c')
| -rw-r--r-- | drivers/scsi/mac_esp.c | 234 |
1 files changed, 109 insertions, 125 deletions
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 887682a24e3..994fc5caf03 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -19,12 +19,13 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/nubus.h> +#include <linux/slab.h> #include <asm/irq.h> #include <asm/dma.h> - #include <asm/macints.h> #include <asm/macintosh.h> +#include <asm/mac_via.h> #include <scsi/scsi_host.h> @@ -53,7 +54,7 @@ struct mac_esp_priv { void __iomem *pdma_io; int error; }; -static struct platform_device *internal_esp, *external_esp; +static struct esp *esp_chips[2]; #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ platform_get_drvdata((struct platform_device *) \ @@ -149,7 +150,7 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp) do { if (mep->pdma_regs == NULL) { - if (mac_irq_pending(IRQ_MAC_SCSIDRQ)) + if (via2_scsi_drq_pending()) return 0; } else { if (nubus_readl(mep->pdma_regs) & 0x200) @@ -170,7 +171,7 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp) #define MAC_ESP_PDMA_LOOP(operands) \ asm volatile ( \ - " tstw %2 \n" \ + " tstw %1 \n" \ " jbeq 20f \n" \ "1: movew " operands " \n" \ "2: movew " operands " \n" \ @@ -188,14 +189,14 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp) "14: movew " operands " \n" \ "15: movew " operands " \n" \ "16: movew " operands " \n" \ - " subqw #1,%2 \n" \ + " subqw #1,%1 \n" \ " jbne 1b \n" \ - "20: tstw %3 \n" \ + "20: tstw %2 \n" \ " jbeq 30f \n" \ "21: movew " operands " \n" \ - " subqw #1,%3 \n" \ + " subqw #1,%2 \n" \ " jbne 21b \n" \ - "30: tstw %4 \n" \ + "30: tstw %3 \n" \ " jbeq 40f \n" \ "31: moveb " operands " \n" \ "32: nop \n" \ @@ -223,16 +224,13 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp) " .long 31b,40b \n" \ " .long 32b,40b \n" \ " .previous \n" \ - : "+a" (addr) \ - : "a" (mep->pdma_io), "r" (count32), "r" (count2), "g" (esp_count)) + : "+a" (addr), "+r" (count32), "+r" (count2) \ + : "g" (count1), "a" (mep->pdma_io)) static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, u32 dma_count, int write, u8 cmd) { struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); - unsigned long flags; - - local_irq_save(flags); mep->error = 0; @@ -247,19 +245,20 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, do { unsigned int count32 = esp_count >> 5; unsigned int count2 = (esp_count & 0x1F) >> 1; + unsigned int count1 = esp_count & 1; unsigned int start_addr = addr; if (mac_esp_wait_for_dreq(esp)) break; if (write) { - MAC_ESP_PDMA_LOOP("%1@,%0@+"); + MAC_ESP_PDMA_LOOP("%4@,%0@+"); esp_count -= addr - start_addr; } else { unsigned int n; - MAC_ESP_PDMA_LOOP("%0@+,%1@"); + MAC_ESP_PDMA_LOOP("%0@+,%4@"); if (mac_esp_wait_for_empty_fifo(esp)) break; @@ -269,32 +268,33 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, esp_count = n; } } while (esp_count); - - local_irq_restore(flags); } /* * Programmed IO routines follow. */ -static inline int mac_esp_wait_for_fifo(struct esp *esp) +static inline unsigned int mac_esp_wait_for_fifo(struct esp *esp) { int i = 500000; do { - if (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) - return 0; + unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; + + if (fbytes) + return fbytes; udelay(2); } while (--i); printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n", esp_read8(ESP_STATUS)); - return 1; + return 0; } static inline int mac_esp_wait_for_intr(struct esp *esp) { + struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); int i = 500000; do { @@ -306,6 +306,7 @@ static inline int mac_esp_wait_for_intr(struct esp *esp) } while (--i); printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg); + mep->error = 1; return 1; } @@ -345,23 +346,44 @@ static inline int mac_esp_wait_for_intr(struct esp *esp) static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, u32 dma_count, int write, u8 cmd) { - unsigned long flags; struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); u8 *fifo = esp->regs + ESP_FDATA * 16; - local_irq_save(flags); - cmd &= ~ESP_CMD_DMA; mep->error = 0; if (write) { scsi_esp_cmd(esp, cmd); - if (!mac_esp_wait_for_intr(esp)) { - if (mac_esp_wait_for_fifo(esp)) - esp_count = 0; - } else { - esp_count = 0; + while (1) { + unsigned int n; + + n = mac_esp_wait_for_fifo(esp); + if (!n) + break; + + if (n > esp_count) + n = esp_count; + esp_count -= n; + + MAC_ESP_PIO_LOOP("%2@,%0@+", n); + + if (!esp_count) + break; + + if (mac_esp_wait_for_intr(esp)) + break; + + if (((esp->sreg & ESP_STAT_PMASK) != ESP_DIP) && + ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)) + break; + + esp->ireg = esp_read8(ESP_INTRPT); + if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) != + ESP_INTR_BSERV) + break; + + scsi_esp_cmd(esp, ESP_CMD_TI); } } else { scsi_esp_cmd(esp, ESP_CMD_FLUSH); @@ -372,47 +394,24 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count); scsi_esp_cmd(esp, cmd); - } - - while (esp_count) { - unsigned int n; - - if (mac_esp_wait_for_intr(esp)) { - mep->error = 1; - break; - } - - if (esp->sreg & ESP_STAT_SPAM) { - printk(KERN_ERR PFX "gross error\n"); - mep->error = 1; - break; - } - - n = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - - if (write) { - if (n > esp_count) - n = esp_count; - esp_count -= n; - MAC_ESP_PIO_LOOP("%2@,%0@+", n); + while (esp_count) { + unsigned int n; - if ((esp->sreg & ESP_STAT_PMASK) == ESP_STATP) + if (mac_esp_wait_for_intr(esp)) break; - if (esp_count) { - esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_DC) - break; + if (((esp->sreg & ESP_STAT_PMASK) != ESP_DOP) && + ((esp->sreg & ESP_STAT_PMASK) != ESP_MOP)) + break; - scsi_esp_cmd(esp, ESP_CMD_TI); - } - } else { esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_DC) + if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) != + ESP_INTR_BSERV) break; - n = MAC_ESP_FIFO_SIZE - n; + n = MAC_ESP_FIFO_SIZE - + (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES); if (n > esp_count) n = esp_count; @@ -426,8 +425,6 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, scsi_esp_cmd(esp, ESP_CMD_TI); } } - - local_irq_restore(flags); } static int mac_esp_irq_pending(struct esp *esp) @@ -442,6 +439,32 @@ static u32 mac_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) return dma_len > 0xFFFF ? 0xFFFF : dma_len; } +static irqreturn_t mac_scsi_esp_intr(int irq, void *dev_id) +{ + int got_intr; + + /* + * This is an edge triggered IRQ, so we have to be careful to + * avoid missing a transition when it is shared by two ESP devices. + */ + + do { + got_intr = 0; + if (esp_chips[0] && + (mac_esp_read8(esp_chips[0], ESP_STATUS) & ESP_STAT_INTR)) { + (void)scsi_esp_intr(irq, esp_chips[0]); + got_intr = 1; + } + if (esp_chips[1] && + (mac_esp_read8(esp_chips[1], ESP_STATUS) & ESP_STAT_INTR)) { + (void)scsi_esp_intr(irq, esp_chips[1]); + got_intr = 1; + } + } while (got_intr); + + return IRQ_HANDLED; +} + static struct esp_driver_ops mac_esp_ops = { .esp_write8 = mac_esp_write8, .esp_read8 = mac_esp_read8, @@ -458,35 +481,18 @@ static struct esp_driver_ops mac_esp_ops = { .dma_error = mac_esp_dma_error, }; -static int __devinit esp_mac_probe(struct platform_device *dev) +static int esp_mac_probe(struct platform_device *dev) { struct scsi_host_template *tpnt = &scsi_esp_template; struct Scsi_Host *host; struct esp *esp; int err; - int chips_present; struct mac_esp_priv *mep; if (!MACH_IS_MAC) return -ENODEV; - switch (macintosh_config->scsi_type) { - case MAC_SCSI_QUADRA: - case MAC_SCSI_QUADRA3: - chips_present = 1; - break; - case MAC_SCSI_QUADRA2: - if ((macintosh_config->ident == MAC_MODEL_Q900) || - (macintosh_config->ident == MAC_MODEL_Q950)) - chips_present = 2; - else - chips_present = 1; - break; - default: - chips_present = 0; - } - - if (dev->id + 1 > chips_present) + if (dev->id > 1) return -ENODEV; host = scsi_host_alloc(tpnt, sizeof(struct esp)); @@ -556,10 +562,15 @@ static int __devinit esp_mac_probe(struct platform_device *dev) } host->irq = IRQ_MAC_SCSI; - err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "Mac ESP", - esp); - if (err < 0) - goto fail_free_priv; + esp_chips[dev->id] = esp; + mb(); + if (esp_chips[!dev->id] == NULL) { + err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL); + if (err < 0) { + esp_chips[dev->id] = NULL; + goto fail_free_priv; + } + } err = scsi_esp_register(esp, &dev->dev); if (err) @@ -568,7 +579,8 @@ static int __devinit esp_mac_probe(struct platform_device *dev) return 0; fail_free_irq: - free_irq(host->irq, esp); + if (esp_chips[!dev->id] == NULL) + free_irq(host->irq, esp); fail_free_priv: kfree(mep); fail_free_command_block: @@ -579,7 +591,7 @@ fail: return err; } -static int __devexit esp_mac_remove(struct platform_device *dev) +static int esp_mac_remove(struct platform_device *dev) { struct mac_esp_priv *mep = platform_get_drvdata(dev); struct esp *esp = mep->esp; @@ -587,7 +599,9 @@ static int __devexit esp_mac_remove(struct platform_device *dev) scsi_esp_unregister(esp); - free_irq(irq, esp); + esp_chips[dev->id] = NULL; + if (!(esp_chips[0] || esp_chips[1])) + free_irq(irq, NULL); kfree(mep); @@ -600,58 +614,28 @@ static int __devexit esp_mac_remove(struct platform_device *dev) static struct platform_driver esp_mac_driver = { .probe = esp_mac_probe, - .remove = __devexit_p(esp_mac_remove), + .remove = esp_mac_remove, .driver = { - .name = DRV_MODULE_NAME, + .name = DRV_MODULE_NAME, + .owner = THIS_MODULE, }, }; static int __init mac_esp_init(void) { - int err; - - err = platform_driver_register(&esp_mac_driver); - if (err) - return err; - - internal_esp = platform_device_alloc(DRV_MODULE_NAME, 0); - if (internal_esp && platform_device_add(internal_esp)) { - platform_device_put(internal_esp); - internal_esp = NULL; - } - - external_esp = platform_device_alloc(DRV_MODULE_NAME, 1); - if (external_esp && platform_device_add(external_esp)) { - platform_device_put(external_esp); - external_esp = NULL; - } - - if (internal_esp || external_esp) { - return 0; - } else { - platform_driver_unregister(&esp_mac_driver); - return -ENOMEM; - } + return platform_driver_register(&esp_mac_driver); } static void __exit mac_esp_exit(void) { platform_driver_unregister(&esp_mac_driver); - - if (internal_esp) { - platform_device_unregister(internal_esp); - internal_esp = NULL; - } - if (external_esp) { - platform_device_unregister(external_esp); - external_esp = NULL; - } } MODULE_DESCRIPTION("Mac ESP SCSI driver"); MODULE_AUTHOR("Finn Thain <fthain@telegraphics.com.au>"); MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); +MODULE_ALIAS("platform:" DRV_MODULE_NAME); module_init(mac_esp_init); module_exit(mac_esp_exit); |
