diff options
author | Thomas Bogendoerfer <tsbogend@alpha.franken.de> | 1997-12-29 00:14:17 +0000 |
---|---|---|
committer | Thomas Bogendoerfer <tsbogend@alpha.franken.de> | 1997-12-29 00:14:17 +0000 |
commit | 77b45c1b73d3972e37752f116a6a1af4bd6b8a4b (patch) | |
tree | 0e553e5872bb8a455603aaaf70b83e80d93ab827 /drivers/scsi | |
parent | 8a9fd000a0d3ea16d935dbb9929ee4cac018d1a0 (diff) |
made splitted esp working on Linux/Sparc (at least on my SS2)
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/Makefile | 4 | ||||
-rw-r--r-- | drivers/scsi/esp.c | 87 | ||||
-rw-r--r-- | drivers/scsi/esp.h | 8 | ||||
-rw-r--r-- | drivers/scsi/hosts.c | 2 | ||||
-rw-r--r-- | drivers/scsi/jazz_esp.c | 21 | ||||
-rw-r--r-- | drivers/scsi/sparc_esp.c | 638 | ||||
-rw-r--r-- | drivers/scsi/sparc_esp.h | 53 |
7 files changed, 724 insertions, 89 deletions
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 73da5128f..e79d4ee24 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -287,10 +287,10 @@ else endif ifeq ($(CONFIG_SCSI_SUNESP),y) -L_OBJS += esp.o +L_OBJS += esp.o sparc_esp.o else ifeq ($(CONFIG_SCSI_SUNESP),m) - M_OBJS += esp.o + M_OBJS += esp.o sparc_esp.o endif endif diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index d46e26cfd..811522465 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -616,10 +616,12 @@ void esp_initialize(struct Sparc_ESP *esp) esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); esp->sync_defp = SYNC_DEFP_SLOW; + printk("SCSI ID %d Clock %d MHz CCF=%d Time-Out %d ", + esp->scsi_id, (esp->cfreq / 1000000), + esp->ccf, (int) esp->neg_defp); /* Fill in ehost data */ esp->ehost->base = (unsigned char *) eregs; - esp->ehost->io_port = (unsigned int) eregs; esp->ehost->this_id = esp->scsi_id; esp->ehost->irq = esp->irq; @@ -684,10 +686,6 @@ void esp_initialize(struct Sparc_ESP *esp) esp_bootup_reset(esp, eregs); esps_in_use++; - - printk("SCSI ID %d Clock %d MHz CCF=%d Time-Out %d ", - esp->scsi_id, (esp->cfreq / 1000000), - esp->ccf, (int) esp->neg_defp); } /* The info function will return whatever useful @@ -1197,12 +1195,12 @@ after_nego_msg_built: eregs->fas_rlo = 0; eregs->fas_rhi = 0; esp_cmd(esp, eregs, the_esp_command); - esp->dma_init_write(esp, (char *) esp->esp_command, 16); + esp->dma_init_write(esp, esp->esp_command_dvma, 16); } else { /* Set up the ESP counters */ eregs->esp_tclow = i; eregs->esp_tcmed = 0; - esp->dma_init_write(esp, (char *) esp->esp_command, i); + esp->dma_init_write(esp, esp->esp_command_dvma, i); /* Tell ESP to "go". */ esp_cmd(esp, eregs, the_esp_command); @@ -1234,23 +1232,11 @@ int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; SCpnt->SCp.buffers_residual = 0; -#ifdef CONFIG_SCSI_SUNESP - /* Sneaky. */ - SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer, - SCpnt->SCp.this_residual, - esp->edev->my_bus); - /* XXX The casts are extremely gross, but with 64-bit kernel - * XXX and 32-bit SBUS what am I to do? -DaveM - */ - SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in); -#else if (esp->dma_mmu_get_scsi_one) esp->dma_mmu_get_scsi_one (esp, SCpnt); else SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr = (char *)SCpnt->request_buffer; -#endif - } else { ESPQUEUE(("use_sg ")); #ifdef DEBUG_ESP_SG @@ -1260,18 +1246,10 @@ int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer; SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; -#ifdef CONFIG_SCSI_SUNESP - mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer, - SCpnt->SCp.buffers_residual, - ((struct linux_sbus_device *) (esp->edev))->my_bus); - /* XXX Again these casts are sick... -DaveM */ - SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address); -#else if (esp->dma_mmu_get_scsi_sgl) esp->dma_mmu_get_scsi_sgl (esp, SCpnt); else SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; -#endif } SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0xff; @@ -1468,23 +1446,12 @@ static void esp_done(struct Sparc_ESP *esp, int error) /* Free dvma entry. */ if(!done_SC->use_sg) { -#ifdef CONFIG_SCSI_SUNESP - /* Sneaky. */ - mmu_release_scsi_one(done_SC->SCp.have_data_in, - done_SC->request_bufflen, - ((struct linux_sbus_device *) (esp->edev))->my_bus); -#endif if (esp->dma_mmu_release_scsi_one) esp->dma_mmu_release_scsi_one (esp, done_SC); } else { #ifdef DEBUG_ESP_SG printk("esp%d: unmapping sg ", esp->esp_id); #endif -#ifdef CONFIG_SCSI_SUNESP - mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer, - done_SC->use_sg - 1, - ((struct linux_sbus_device *) (esp->edev))->my_bus); -#endif if (esp->dma_mmu_release_scsi_sgl) esp->dma_mmu_release_scsi_sgl (esp, done_SC); @@ -1858,14 +1825,10 @@ static inline void advance_sg(struct Sparc_ESP *esp, Scsi_Cmnd *sp) ++sp->SCp.buffer; --sp->SCp.buffers_residual; sp->SCp.this_residual = sp->SCp.buffer->length; -#ifdef CONFIG_SCSI_SUNESP - sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address); -#else if (esp->dma_advance_sg) esp->dma_advance_sg(sp); else sp->SCp.ptr = sp->SCp.buffer->address; -#endif } /* Please note that the way I've coded these routines is that I _always_ @@ -1906,12 +1869,12 @@ static inline int esp_do_data(struct Sparc_ESP *esp, struct ESP_regs *eregs) esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); if(thisphase == in_datain) - esp->dma_init_read(esp, SCptr->SCp.ptr, hmuch); + esp->dma_init_read(esp, (__u32) SCptr->SCp.ptr, hmuch); else - esp->dma_init_write(esp, SCptr->SCp.ptr, hmuch); + esp->dma_init_write(esp, (__u32) SCptr->SCp.ptr, hmuch); } else { esp_setcount(eregs, hmuch, 0); - esp->dma_setup(esp, SCptr->SCp.ptr, hmuch, (thisphase == in_datain)); + esp->dma_setup(esp, (__u32) SCptr->SCp.ptr, hmuch, (thisphase == in_datain)); ESPDATA(("DMA|TI --> do_intr_end\n")); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); } @@ -2376,7 +2339,7 @@ static int esp_do_phase_determine(struct Sparc_ESP *esp, esp->esp_command[1] = 0xff; eregs->esp_tclow = 2; eregs->esp_tcmed = 0; - esp->dma_init_read(esp, (char *) esp->esp_command, 2); + esp->dma_init_read(esp, esp->esp_command_dvma, 2); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ); } else { /* Using DVMA for status/message bytes is @@ -3126,7 +3089,7 @@ static int esp_do_cmdbegin(struct Sparc_ESP *esp, struct ESP_regs *eregs) esp_cmd(esp, eregs, ESP_CMD_FLUSH); esp_setcount(eregs, i, 1); esp_cmd(esp, eregs, (ESP_CMD_DMA | ESP_CMD_TI)); - esp->dma_init_write(esp, (char *) esp->esp_command, i); + esp->dma_init_write(esp, esp->esp_command_dvma, i); } else { esp_cmd(esp, eregs, ESP_CMD_FLUSH); eregs->esp_fdata = *esp->esp_scmdp++; @@ -3176,7 +3139,7 @@ static int esp_do_msgout(struct Sparc_ESP *esp, struct ESP_regs *eregs) hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 2); esp_cmd(esp, eregs, ESP_CMD_TI); } else { - esp->dma_setup(esp, (char *) esp->esp_command, 2, 0); + esp->dma_setup(esp, esp->esp_command_dvma, 2, 0); esp_setcount(eregs, 2, 0); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); } @@ -3200,7 +3163,7 @@ static int esp_do_msgout(struct Sparc_ESP *esp, struct ESP_regs *eregs) hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 4); esp_cmd(esp, eregs, ESP_CMD_TI); } else { - esp->dma_setup(esp, (char *) esp->esp_command, 4, 0); + esp->dma_setup(esp, esp->esp_command_dvma, 4, 0); esp_setcount(eregs, 4, 0); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); } @@ -3226,7 +3189,7 @@ static int esp_do_msgout(struct Sparc_ESP *esp, struct ESP_regs *eregs) hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 5); esp_cmd(esp, eregs, ESP_CMD_TI); } else { - esp->dma_setup(esp, (char *) esp->esp_command, 5, 0); + esp->dma_setup(esp, esp->esp_command_dvma, 5, 0); esp_setcount(eregs, 5, 0); esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); } @@ -3379,7 +3342,7 @@ inline void esp_handle(struct Sparc_ESP *esp) Scsi_Cmnd *SCptr; int what_next = do_intr_end; #ifdef CONFIG_SCSI_SUNESP - struct dma_registers *dregs = esp->dregs; + struct sparc_dma_registers *dregs = esp->dregs; #endif eregs = esp->eregs; SCptr = esp->current_SC; @@ -3588,17 +3551,6 @@ again: if(esp->current_SC) { Scsi_Cmnd *SCptr = esp->current_SC; -#ifdef CONFIG_SCSI_SUNESP - if(!SCptr->use_sg) - mmu_release_scsi_one(SCptr->SCp.have_data_in, - SCptr->request_bufflen, - ((struct linux_sbus_device *) (esp->edev))->my_bus); - else - mmu_release_scsi_sgl((struct mmu_sglist *) - SCptr->buffer, - SCptr->use_sg - 1, - ((struct linux_sbus_device *) (esp->edev))->my_bus); -#endif if(!SCptr->use_sg) { if (esp->dma_mmu_release_scsi_one) esp->dma_mmu_release_scsi_one (esp, SCptr); @@ -3614,17 +3566,6 @@ again: if(esp->disconnected_SC) { Scsi_Cmnd *SCptr; while((SCptr = remove_first_SC(&esp->disconnected_SC))) { -#ifdef CONFIG_SCSI_SUNESP - if(!SCptr->use_sg) - mmu_release_scsi_one(SCptr->SCp.have_data_in, - SCptr->request_bufflen, - ((struct linux_sbus_device *) (esp->edev))->my_bus); - else - mmu_release_scsi_sgl((struct mmu_sglist *) - SCptr->buffer, - SCptr->use_sg - 1, - ((struct linux_sbus_device *) (esp->edev))->my_bus); -#endif if(!SCptr->use_sg) { if (esp->dma_mmu_release_scsi_one) esp->dma_mmu_release_scsi_one (esp, SCptr); diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h index bc5a879f6..f6f9718b5 100644 --- a/drivers/scsi/esp.h +++ b/drivers/scsi/esp.h @@ -191,7 +191,7 @@ enum esp_rev { struct Sparc_ESP { struct Sparc_ESP *next; /* Next ESP on probed or NULL */ struct ESP_regs *eregs; /* All esp registers */ - struct Linux_DMA *dma; /* Who I do transfers with. */ + struct Linux_SBus_DMA *dma; /* Who I do transfers with. */ void *dregs; /* And his registers. */ struct Scsi_Host *ehost; /* Backpointer to SCSI Host */ @@ -294,13 +294,13 @@ struct Sparc_ESP { int (*dma_bytes_sent)(struct Sparc_ESP *, int); int (*dma_can_transfer)(struct Sparc_ESP *, Scsi_Cmnd *); void (*dma_dump_state)(struct Sparc_ESP *); - void (*dma_init_read)(struct Sparc_ESP *, char *, int); - void (*dma_init_write)(struct Sparc_ESP *, char *, int); + void (*dma_init_read)(struct Sparc_ESP *, __u32, int); + void (*dma_init_write)(struct Sparc_ESP *, __u32, int); void (*dma_ints_off)(struct Sparc_ESP *); void (*dma_ints_on)(struct Sparc_ESP *); int (*dma_irq_p)(struct Sparc_ESP *); int (*dma_ports_p)(struct Sparc_ESP *); - void (*dma_setup)(struct Sparc_ESP *, char *, int, int); + void (*dma_setup)(struct Sparc_ESP *, __u32, int, int); /* Optional functions (i.e. may be initialized to 0) */ void (*dma_barrier)(struct Sparc_ESP *); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index b2271cb30..4c62c2df4 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -175,7 +175,7 @@ #endif #ifdef CONFIG_SCSI_SUNESP -#include "esp.h" +#include "sparc_esp.h" #endif #ifdef CONFIG_SCSI_SGIWD93 diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 4cd3b428f..2669e718a 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -30,13 +30,13 @@ static int dma_bytes_sent(struct Sparc_ESP *esp, int fifo_count); static int dma_can_transfer(struct Sparc_ESP *esp, Scsi_Cmnd *sp); static void dma_dump_state(struct Sparc_ESP *esp); -static void dma_init_read(struct Sparc_ESP *esp, char *vaddress, int length); -static void dma_init_write(struct Sparc_ESP *esp, char *vaddress, int length); +static void dma_init_read(struct Sparc_ESP *esp, __u32 vaddress, int length); +static void dma_init_write(struct Sparc_ESP *esp, __u32 vaddress, int length); static void dma_ints_off(struct Sparc_ESP *esp); static void dma_ints_on(struct Sparc_ESP *esp); static int dma_irq_p(struct Sparc_ESP *esp); static int dma_ports_p(struct Sparc_ESP *esp); -static void dma_setup(struct Sparc_ESP *esp, char *addr, int count, int write); +static void dma_setup(struct Sparc_ESP *esp, __u32 addr, int count, int write); static void dma_mmu_get_scsi_one (struct Sparc_ESP *esp, Scsi_Cmnd *sp); static void dma_mmu_get_scsi_sgl (struct Sparc_ESP *esp, Scsi_Cmnd *sp); static void dma_mmu_release_scsi_one (struct Sparc_ESP *esp, Scsi_Cmnd *sp); @@ -115,6 +115,9 @@ int jazz_esp_detect(Scsi_Host_Template *tpnt) /* Set the command buffer */ esp->esp_command = (volatile unsigned char *)cmd_buffer; + /* get virtual dma address for command buffer */ + esp->esp_command_dvma = vdma_alloc(PHYSADDR(cmd_buffer), sizeof (cmd_buffer)); + esp->irq = JAZZ_SCSI_IRQ; request_irq(JAZZ_SCSI_IRQ, esp_intr, SA_INTERRUPT, "JAZZ SCSI", esp_intr); @@ -129,7 +132,7 @@ int jazz_esp_detect(Scsi_Host_Template *tpnt) esp_initialize(esp); - printk("\nESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use); + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use); esps_running = esps_in_use; return esps_in_use; } @@ -160,22 +163,22 @@ static void dma_dump_state(struct Sparc_ESP *esp) esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_resdiue((int)esp->dregs))); } -static void dma_init_read(struct Sparc_ESP *esp, char *vaddress, int length) +static void dma_init_read(struct Sparc_ESP *esp, __u32 vaddress, int length) { flush_cache_all(); vdma_disable ((int)esp->dregs); vdma_set_mode ((int)esp->dregs, DMA_MODE_READ); - vdma_set_addr ((int)esp->dregs, (long)virt_to_bus(vaddress)); + vdma_set_addr ((int)esp->dregs, vaddress); vdma_set_count ((int)esp->dregs, length); vdma_enable ((int)esp->dregs); } -static void dma_init_write(struct Sparc_ESP *esp, char *vaddress, int length) +static void dma_init_write(struct Sparc_ESP *esp, __u32 vaddress, int length) { flush_cache_all(); vdma_disable ((int)esp->dregs); vdma_set_mode ((int)esp->dregs, DMA_MODE_WRITE); - vdma_set_addr ((int)esp->dregs, (long)virt_to_bus(vaddress)); + vdma_set_addr ((int)esp->dregs, vaddress); vdma_set_count ((int)esp->dregs, length); vdma_enable ((int)esp->dregs); } @@ -202,7 +205,7 @@ static int dma_ports_p(struct Sparc_ESP *esp) return (enable & R4030_CHNL_ENABLE); } -static void dma_setup(struct Sparc_ESP *esp, char *addr, int count, int write) +static void dma_setup(struct Sparc_ESP *esp, __u32 addr, int count, int write) { /* * On the Sparc, DMA_ST_WRITE means "move data from device to memory" diff --git a/drivers/scsi/sparc_esp.c b/drivers/scsi/sparc_esp.c new file mode 100644 index 000000000..2b3341b3a --- /dev/null +++ b/drivers/scsi/sparc_esp.c @@ -0,0 +1,638 @@ +/* sparc_esp.c: EnhancedScsiProcessor Sun SCSI driver code. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * Ugly generalization hacks by Jesper Skov. See "esp.c". + */ + +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/malloc.h> +#include <linux/blk.h> +#include <linux/proc_fs.h> +#include <linux/stat.h> + +#include "scsi.h" +#include "hosts.h" +#include "esp.h" + +#include "sparc_esp.h" +#include <asm/sbus.h> +#include <asm/dma.h> +#include <asm/machines.h> +#include <asm/oplib.h> +#include <asm/vaddrs.h> +#include <asm/pgtable.h> + +extern struct Sparc_ESP *espchain; + +static void dma_barrier(struct Sparc_ESP *esp); +static int dma_bytes_sent(struct Sparc_ESP *esp, int fifo_count); +static int dma_can_transfer(struct Sparc_ESP *esp, Scsi_Cmnd *sp); +static void dma_drain(struct Sparc_ESP *esp); +static void dma_dump_state(struct Sparc_ESP *esp); +static void dma_init_read(struct Sparc_ESP *esp, __u32 vaddress, int length); +static void dma_init_write(struct Sparc_ESP *esp, __u32 vaddress, int length); +static void dma_ints_off(struct Sparc_ESP *esp); +static void dma_ints_on(struct Sparc_ESP *esp); +static void dma_invalidate(struct Sparc_ESP *esp); +static void dma_irq_entry(struct Sparc_ESP *esp); +static void dma_irq_exit(struct Sparc_ESP *esp); +static int dma_irq_p(struct Sparc_ESP *esp); +static void dma_poll(struct Sparc_ESP *esp, unsigned char *vaddr); +static int dma_ports_p(struct Sparc_ESP *esp); +static void dma_reset(struct Sparc_ESP *esp); +static void dma_setup(struct Sparc_ESP *esp, __u32 addr, int count, int write); +static void dma_mmu_get_scsi_one (struct Sparc_ESP *esp, Scsi_Cmnd *sp); +static void dma_mmu_get_scsi_sgl (struct Sparc_ESP *esp, Scsi_Cmnd *sp); +static void dma_mmu_release_scsi_one (struct Sparc_ESP *esp, Scsi_Cmnd *sp); +static void dma_mmu_release_scsi_sgl (struct Sparc_ESP *esp, Scsi_Cmnd *sp); +static void dma_advance_sg (Scsi_Cmnd *sp); + +/* Detecting ESP chips on the machine. This is the simple and easy + * version. + */ +int esp_detect(Scsi_Host_Template *tpnt) +{ + struct Sparc_ESP *esp, *elink; + struct Scsi_Host *esp_host; + struct linux_sbus *sbus; + struct linux_sbus_device *esp_edev, *esp_dev, *sbdev_iter; + struct ESP_regs *eregs; + struct sparc_dma_registers *dregs; + struct Linux_SBus_DMA *dma, *dlink; + unchar bsizes, bsizes_more; + int esp_node; + + if(!SBus_chain) + panic("No SBUS in esp_detect()"); + for_each_sbus(sbus) { + for_each_sbusdev(sbdev_iter, sbus) { + struct linux_sbus_device *espdma = 0; + int hme = 0; + + /* Is it an esp sbus device? */ + esp_dev = sbdev_iter; + if(strcmp(esp_dev->prom_name, "esp") && + strcmp(esp_dev->prom_name, "SUNW,esp")) { + if(!strcmp(esp_dev->prom_name, "SUNW,fas")) { + hme = 1; + espdma = esp_dev; + } else { + if(!esp_dev->child || + (strcmp(esp_dev->prom_name, "espdma") && + strcmp(esp_dev->prom_name, "dma"))) + continue; /* nope... */ + espdma = esp_dev; + esp_dev = esp_dev->child; + if(strcmp(esp_dev->prom_name, "esp") && + strcmp(esp_dev->prom_name, "SUNW,esp")) + continue; /* how can this happen? */ + } + } + + esp = esp_allocate(tpnt, (void *) esp_dev); + + esp_host = esp->ehost; + + if(hme) + esp_host->max_id = 16; + + /* Do command transfer with DMA */ + esp->do_pio_cmds = 0; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = &dma_barrier; + esp->dma_drain = &dma_drain; + esp->dma_invalidate = &dma_invalidate; + esp->dma_irq_entry = &dma_irq_entry; + esp->dma_irq_exit = &dma_irq_exit; + esp->dma_led_on = 0; + esp->dma_led_off = 0; + esp->dma_poll = &dma_poll; + esp->dma_reset = &dma_reset; + + /* virtual DMA functions */ + esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; + esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one; + esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl; + esp->dma_advance_sg = &dma_advance_sg; + + /* Get misc. prom information */ +#define ESP_IS_MY_DVMA(esp, dma) \ + ((((struct linux_sbus_device*)(esp->edev))->my_bus == dma->SBus_dev->my_bus) && \ + (((struct linux_sbus_device*)(esp->edev))->slot == dma->SBus_dev->slot) && \ + (!strcmp(dma->SBus_dev->prom_name, "dma") || \ + !strcmp(dma->SBus_dev->prom_name, "espdma"))) + + esp_node = esp_dev->prom_node; + prom_getstring(esp_node, "name", esp->prom_name, + sizeof(esp->prom_name)); + esp->prom_node = esp_node; + if(espdma) { + for_each_dvma(dlink) { + if(dlink->SBus_dev == espdma) + break; + } + } else { + for_each_dvma(dlink) { + if(ESP_IS_MY_DVMA(esp, dlink) && + !dlink->allocated) + break; + } + } +#undef ESP_IS_MY_DVMA + /* If we don't know how to handle the dvma, + * do not use this device. + */ + if(!dlink){ + printk ("Cannot find dvma for ESP%d's SCSI\n", + esp->esp_id); + scsi_unregister (esp_host); + continue; + } + if (dlink->allocated){ + printk ("esp%d: can't use my espdma\n", + esp->esp_id); + scsi_unregister (esp_host); + continue; + } + dlink->allocated = 1; + dma = dlink; + esp->dma = (struct Linux_SBus_DMA *) dma; + esp->dregs = (void *) dregs = dma->regs; + + esp_edev = (struct linux_sbus_device *) esp->edev; + + /* Map in the ESP registers from I/O space */ + if(!hme) { + prom_apply_sbus_ranges(esp_edev->my_bus, + esp_edev->reg_addrs, + 1, esp_edev); + esp->eregs = eregs = (struct ESP_regs *) + sparc_alloc_io(esp_edev->reg_addrs[0].phys_addr, 0, + PAGE_SIZE, "ESP Registers", + esp_edev->reg_addrs[0].which_io, 0x0); + } else { + /* On HME, two reg sets exist, first is DVMA, + * second is ESP registers. + */ + esp->eregs = eregs = (struct ESP_regs *) + sparc_alloc_io(esp_edev->reg_addrs[1].phys_addr, 0, + PAGE_SIZE, "ESP Registers", + esp_edev->reg_addrs[1].which_io, 0x0); + } + if(!eregs) + panic("ESP registers unmappable"); + esp->esp_command = + sparc_dvma_malloc(16, "ESP DVMA Cmd Block", + &esp->esp_command_dvma); + if(!esp->esp_command || !esp->esp_command_dvma) + panic("ESP DVMA transport area unmappable"); + + /* Set up the irq's etc. */ + esp->ehost->io_port = + esp_edev->reg_addrs[0].phys_addr; + esp_host->n_io_port = (unsigned char) + esp_edev->reg_addrs[0].reg_size; + esp->irq = esp_edev->irqs[0].pri; + + /* Allocate the irq only if necessary */ + for_each_esp(elink) { + if((elink != esp) && (esp->irq == elink->irq)) { + goto esp_irq_acquired; /* BASIC rulez */ + } + } + if(request_irq(esp->irq, esp_intr, SA_SHIRQ, + "Sparc ESP SCSI", NULL)) + panic("Cannot acquire ESP irq line"); +esp_irq_acquired: + printk("esp%d: IRQ %d ", esp->esp_id, esp->irq); + + /* Figure out our scsi ID on the bus */ + esp->scsi_id = prom_getintdefault(esp->prom_node, + "initiator-id", + -1); + if(esp->scsi_id == -1) + esp->scsi_id = prom_getintdefault(esp->prom_node, + "scsi-initiator-id", + -1); + if(esp->scsi_id == -1) + esp->scsi_id = + prom_getintdefault(esp_edev->my_bus->prom_node, + "scsi-initiator-id", + 7); + + /* Check for differential SCSI-bus */ + esp->diff = prom_getbool(esp->prom_node, "differential"); + if(esp->diff) + printk("Differential "); + + + /* SCSI chip clock */ + esp->cfreq = prom_getintdefault(esp->prom_node, + "clock-frequency", + -1); + if(esp->cfreq==-1) + esp->cfreq = prom_getintdefault(esp_edev->my_bus->prom_node, + "clock-frequency", + -1); + + /* Find the burst sizes this dma/sbus/esp supports. */ + bsizes = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff); + bsizes &= 0xff; + if(espdma) { + bsizes_more = prom_getintdefault( + espdma->prom_node, + "burst-sizes", 0xff); + if(bsizes_more != 0xff) + bsizes &= bsizes_more; + } + bsizes_more = prom_getintdefault(esp_edev->my_bus->prom_node, + "burst-sizes", 0xff); + if(bsizes_more != 0xff) + bsizes &= bsizes_more; + + if(bsizes == 0xff || (bsizes & DMA_BURST16)==0 || + (bsizes & DMA_BURST32)==0) + bsizes = (DMA_BURST32 - 1); + + esp->bursts = bsizes; + + esp_initialize(esp); + + } /* for each sbusdev */ + } /* for each sbus */ + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, + esps_in_use); + esps_running = esps_in_use; + return esps_in_use; +} + + +/************************************************************* DMA Functions */ +/* XXXX UGLY! : Duplicate esp_cmd here so it can remain inline in esp.c */ +static inline void esp_cmd(struct Sparc_ESP *esp, + struct ESP_regs *eregs, unchar cmd) +{ +#ifdef DEBUG_ESP_CMDS + esp->espcmdlog[esp->espcmdent] = cmd; + esp->espcmdent = (esp->espcmdent + 1) & 31; +#endif + eregs->esp_cmd = cmd; +} + +static void dma_barrier(struct Sparc_ESP *esp) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + /* XXX HME/FAS ATN deassert workaround required, + * XXX no DMA flushing, only possible ESP_CMD_FLUSH + * XXX to kill the fifo. + */ + if(esp->erev != fashme) { + while(dregs->cond_reg & DMA_PEND_READ) + udelay(1); + dregs->cond_reg &= ~(DMA_ENABLE); + dma_invalidate(esp); + } else { + esp_cmd(esp, esp->eregs, ESP_CMD_FLUSH); + } +} + +/* This uses various DMA csr fields and the fifo flags count value to + * determine how many bytes were successfully sent/received by the ESP. + */ +static int dma_bytes_sent(struct Sparc_ESP *esp, int fifo_count) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + int rval = dregs->st_addr - esp->esp_command_dvma; + + if(((struct Linux_SBus_DMA *) esp->dma)->revision == dvmarev1) + rval -= (4 - ((dregs->cond_reg & DMA_READ_AHEAD)>>11)); + return rval - fifo_count; +} + +static int dma_can_transfer(struct Sparc_ESP *esp, Scsi_Cmnd *sp) +{ + __u32 base, end, sz; + enum dvma_rev drev = ((struct Linux_SBus_DMA *) esp->dma)->revision; + + if(drev == dvmarev3) { + sz = sp->SCp.this_residual; + if(sz > 0x1000000) + sz = 0x1000000; + } else { + base = ((__u32)sp->SCp.ptr); + base &= (0x1000000 - 1); + end = (base + sp->SCp.this_residual); + if(end > 0x1000000) + end = 0x1000000; + sz = (end - base); + } + return sz; +} + +static void dma_drain(struct Sparc_ESP *esp) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + enum dvma_rev drev = ((struct Linux_SBus_DMA *) esp->dma)->revision; + + if(drev == dvmahme) + return; + if(dregs->cond_reg & DMA_FIFO_ISDRAIN) { + switch(drev) { + default: + dregs->cond_reg |= DMA_FIFO_STDRAIN; + + case dvmarev3: + case dvmaesc1: + while(dregs->cond_reg & DMA_FIFO_ISDRAIN) + udelay(1); + }; + } +} + +static void dma_dump_state(struct Sparc_ESP *esp) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%p>\n", + esp->esp_id, dregs->cond_reg, dregs->st_addr)); +} + +static void dma_flashclear(struct Sparc_ESP *esp) +{ + dma_drain(esp); + dma_invalidate(esp); +} + +static void dma_init_read(struct Sparc_ESP *esp, __u32 vaddress, int length) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE); + if(((struct Linux_SBus_DMA *) esp->dma)->revision == dvmaesc1) + dregs->cnt = 0x1000; + dregs->st_addr = vaddress; +} + +static void dma_init_write(struct Sparc_ESP *esp, __u32 vaddress, int length) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + if(esp->erev == fashme) { + unsigned long tmp; + + /* Talk about touchy hardware... */ + tmp = dregs->cond_reg; + tmp |= (DMA_SCSI_DISAB | DMA_ENABLE); + tmp &= ~(DMA_ST_WRITE); + dregs->cnt = length; + dregs->st_addr = vaddress; + dregs->cond_reg = tmp; + } else { + /* Set up the DMA counters */ + dregs->cond_reg = ((dregs->cond_reg & ~(DMA_ST_WRITE)) | DMA_ENABLE); + if(((struct Linux_SBus_DMA *) esp->dma)->revision == dvmaesc1) { + if(length) /* Workaround ESC gate array SBUS rerun bug. */ + dregs->cnt = (PAGE_SIZE); + } + dregs->st_addr = vaddress; + } +} + +static void dma_ints_off(struct Sparc_ESP *esp) +{ + DMA_INTSOFF((struct sparc_dma_registers *) esp->dregs); +} + +static void dma_ints_on(struct Sparc_ESP *esp) +{ + DMA_INTSON((struct sparc_dma_registers *) esp->dregs); +} + +static void dma_invalidate(struct Sparc_ESP *esp) +{ + unsigned int tmp; + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + if(((struct Linux_SBus_DMA *) esp->dma)->revision == dvmahme) { + /* SMCC can bite me. */ + tmp = dregs->cond_reg; + dregs->cond_reg = DMA_RST_SCSI; + + /* This would explain a lot. */ + tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB); + + tmp &= ~(DMA_ENABLE|DMA_ST_WRITE); + dregs->cond_reg = 0; + dregs->cond_reg = tmp; + } else { + while(dregs->cond_reg & DMA_PEND_READ) + udelay(1); + + tmp = dregs->cond_reg; + tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); + tmp |= DMA_FIFO_INV; + dregs->cond_reg = tmp; + dregs->cond_reg = (tmp & ~(DMA_FIFO_INV)); + } +} + +static void dma_irq_entry(struct Sparc_ESP *esp) +{ + DMA_IRQ_ENTRY((struct Linux_SBus_DMA *) esp->dma, + (struct sparc_dma_registers *)esp->dregs); +} + +static void dma_irq_exit(struct Sparc_ESP *esp) +{ + DMA_IRQ_EXIT((struct Linux_SBus_DMA *) esp->dma, + (struct sparc_dma_registers *) esp->dregs); +} + +static int dma_irq_p(struct Sparc_ESP *esp) +{ + return DMA_IRQ_P((struct sparc_dma_registers *) esp->dregs); +} + +static void dma_poll(struct Sparc_ESP *esp, unsigned char *vaddr) +{ + if(esp->erev != fashme) { + dma_flashclear(esp); + + /* Wait till the first bits settle. */ + while(vaddr[0] == 0xff) + udelay(1); + } else { + vaddr[0] = esp->hme_fifo_workaround_buffer[0]; + vaddr[1] = esp->hme_fifo_workaround_buffer[1]; + } +} + +static int dma_ports_p(struct Sparc_ESP *esp) +{ + return (((struct sparc_dma_registers *) esp->dregs)->cond_reg + & DMA_INT_ENAB); +} + +/* Resetting various pieces of the ESP scsi driver chipset/buses. */ +static void dma_reset(struct Sparc_ESP *esp) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *)esp->dregs; + struct Linux_SBus_DMA *esp_dma = (struct Linux_SBus_DMA *) esp->dma; + unsigned long tmp, flags; + int can_do_burst16, can_do_burst32; + + can_do_burst16 = esp->bursts & DMA_BURST16; + can_do_burst32 = esp->bursts & DMA_BURST32; + + /* Punt the DVMA into a known state. */ + if(esp_dma->revision != dvmahme) { + dregs->cond_reg |= DMA_RST_SCSI; + dregs->cond_reg &= ~(DMA_RST_SCSI); + } + switch(esp_dma->revision) { + case dvmahme: + /* This is the HME DVMA gate array. */ + + save_flags(flags); cli(); /* I really hate this chip. */ + + dregs->cond_reg = 0x08000000; /* Reset interface to FAS */ + dregs->cond_reg = DMA_RST_SCSI; /* Reset DVMA itself */ + + tmp = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB); + tmp &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ); + + if(can_do_burst32) + tmp |= DMA_BRST32; + + /* This chip is horrible. */ + while(dregs->cond_reg & DMA_PEND_READ) + udelay(1); + + dregs->cond_reg = 0; + + dregs->cond_reg = tmp; /* bite me */ + restore_flags(flags); /* ugh... */ + break; + case dvmarev2: + /* This is the gate array found in the sun4m + * NCR SBUS I/O subsystem. + */ + if(esp->erev != esp100) + dregs->cond_reg |= DMA_3CLKS; + break; + case dvmarev3: + dregs->cond_reg &= ~(DMA_3CLKS); + dregs->cond_reg |= DMA_2CLKS; + if(can_do_burst32) { + dregs->cond_reg &= ~(DMA_BRST_SZ); + dregs->cond_reg |= DMA_BRST32; + } + break; + case dvmaesc1: + /* This is the DMA unit found on SCSI/Ether cards. */ + dregs->cond_reg |= DMA_ADD_ENABLE; + dregs->cond_reg &= ~DMA_BCNT_ENAB; + if(!can_do_burst32 && can_do_burst16) { + dregs->cond_reg |= DMA_ESC_BURST; + } else { + dregs->cond_reg &= ~(DMA_ESC_BURST); + } + break; + default: + break; + }; + DMA_INTSON(dregs); +} + +static void dma_setup(struct Sparc_ESP *esp, __u32 addr, int count, int write) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + unsigned long nreg = dregs->cond_reg; + if(write) + nreg |= DMA_ST_WRITE; + else + nreg &= ~(DMA_ST_WRITE); + nreg |= DMA_ENABLE; + dregs->cond_reg = nreg; + if(((struct Linux_SBus_DMA *) esp->dma)->revision == dvmaesc1) { + /* This ESC gate array sucks! */ + __u32 src = addr; + __u32 dest = src + count; + + if(dest & (PAGE_SIZE - 1)) + count = PAGE_ALIGN(count); + dregs->cnt = count; + } + dregs->st_addr = addr; +} + +static void dma_mmu_get_scsi_one (struct Sparc_ESP *esp, Scsi_Cmnd *sp) +{ + /* Sneaky. */ + sp->SCp.have_data_in = mmu_get_scsi_one((char *)sp->SCp.buffer, + sp->SCp.this_residual, + ((struct linux_sbus_device *)(esp->edev))->my_bus); + /* XXX The casts are extremely gross, but with 64-bit kernel + * XXX and 32-bit SBUS what am I to do? -DaveM + */ + sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in); +} + +static void dma_mmu_get_scsi_sgl (struct Sparc_ESP *esp, Scsi_Cmnd *sp) +{ + mmu_get_scsi_sgl((struct mmu_sglist *) sp->SCp.buffer, + sp->SCp.buffers_residual, + ((struct linux_sbus_device *) (esp->edev))->my_bus); + /* XXX Again these casts are sick... -DaveM */ + sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address); +} + +static void dma_mmu_release_scsi_one (struct Sparc_ESP *esp, Scsi_Cmnd *sp) +{ + /* Sneaky. */ + mmu_release_scsi_one(sp->SCp.have_data_in, + sp->request_bufflen, + ((struct linux_sbus_device *) (esp->edev))->my_bus); +} + +static void dma_mmu_release_scsi_sgl (struct Sparc_ESP *esp, Scsi_Cmnd *sp) +{ + mmu_release_scsi_sgl((struct mmu_sglist *) sp->buffer, + sp->use_sg - 1, + ((struct linux_sbus_device *) (esp->edev))->my_bus); +} + +static void dma_advance_sg (Scsi_Cmnd *sp) +{ + sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address); +} diff --git a/drivers/scsi/sparc_esp.h b/drivers/scsi/sparc_esp.h new file mode 100644 index 000000000..6fd09b2e9 --- /dev/null +++ b/drivers/scsi/sparc_esp.h @@ -0,0 +1,53 @@ +/* sparc_esp.h: Defines and structures for the Sparc ESP (Enhanced SCSI +¤ * Processor) driver under Linux. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_ESP_H +#define _SPARC_ESP_H + +/* For dvma controller register definitions. */ +#include <asm/dma.h> + +extern int esp_detect(struct SHT *); +extern const char *esp_info(struct Scsi_Host *); +extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int esp_command(Scsi_Cmnd *); +extern int esp_abort(Scsi_Cmnd *); +extern int esp_reset(Scsi_Cmnd *, unsigned int); +extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, + int hostno, int inout); + +extern struct proc_dir_entry proc_scsi_esp; + + +#define DMA_PORTS_P (dregs->cond_reg & DMA_INT_ENAB) + + + +#define SCSI_SPARC_ESP { \ +/* struct SHT *next */ NULL, \ +/* long *usage_count */ NULL, \ +/* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \ +/* int (*proc_info)(char *, char **, off_t, int, int, int) */ &esp_proc_info, \ +/* const char *name */ "Sun ESP 100/100a/200", \ +/* int detect(struct SHT *) */ esp_detect, \ +/* int release(struct Scsi_Host *) */ NULL, \ +/* const char *info(struct Scsi_Host *) */ esp_info, \ +/* int command(Scsi_Cmnd *) */ esp_command, \ +/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue, \ +/* int abort(Scsi_Cmnd *) */ esp_abort, \ +/* int reset(Scsi_Cmnd *, int) */ esp_reset, \ +/* int slave_attach(int, int) */ NULL, \ +/* int bios_param(Disk *, kdev_t, int[]) */ NULL, \ +/* int can_queue */ 7, \ +/* int this_id */ 7, \ +/* short unsigned int sg_tablesize */ SG_ALL, \ +/* short cmd_per_lun */ 1, \ +/* unsigned char present */ 0, \ +/* unsigned unchecked_isa_dma:1 */ 0, \ +/* unsigned use_clustering:1 */ DISABLE_CLUSTERING, } + +#endif /* !(_SPARC_ESP_H) */ + |