diff options
Diffstat (limited to 'drivers/scsi/jazz_esp.c')
-rw-r--r-- | drivers/scsi/jazz_esp.c | 429 |
1 files changed, 183 insertions, 246 deletions
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 19dd4b962e1..0140766c028 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -1,307 +1,244 @@ -/* - * jazz_esp.c: Driver for SCSI chip on Mips Magnum Boards (JAZZ architecture) +/* jazz_esp.c: ESP front-end for MIPS JAZZ systems. * - * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) - * - * jazz_esp is based on David S. Miller's ESP driver and cyber_esp + * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende) */ -#include <linux/init.h> #include <linux/kernel.h> -#include <linux/delay.h> #include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> #include <asm/irq.h> +#include <asm/io.h> +#include <asm/dma.h> + #include <asm/jazz.h> #include <asm/jazzdma.h> -#include <asm/dma.h> -#include <asm/pgtable.h> - -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp); -static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); -static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); -static void dma_ints_off(struct NCR_ESP *esp); -static void dma_ints_on(struct NCR_ESP *esp); -static int dma_irq_p(struct NCR_ESP *esp); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); -static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp); -static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp); -static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp); -static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp); -static void dma_advance_sg (struct scsi_cmnd *sp); -static void dma_led_off(struct NCR_ESP *); -static void dma_led_on(struct NCR_ESP *); - - -static volatile unsigned char cmd_buffer[16]; - /* This is where all commands are put - * before they are trasfered to the ESP chip - * via PIO. - */ - -static int jazz_esp_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} +#include <scsi/scsi_host.h> -/***************************************************************** Detection */ -static int jazz_esp_detect(struct scsi_host_template *tpnt) -{ - struct NCR_ESP *esp; - struct ConfigDev *esp_dev; - - /* - * first assumption it is there:-) - */ - if (1) { - esp_dev = NULL; - esp = esp_allocate(tpnt, esp_dev, 0); - - /* Do command transfer with programmed I/O */ - esp->do_pio_cmds = 1; - - /* 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 = NULL; - esp->dma_drain = NULL; - esp->dma_invalidate = NULL; - esp->dma_irq_entry = NULL; - esp->dma_irq_exit = NULL; - esp->dma_poll = NULL; - esp->dma_reset = NULL; - esp->dma_led_off = &dma_led_off; - esp->dma_led_on = &dma_led_on; - - /* 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; - - - /* SCSI chip speed */ - esp->cfreq = 40000000; +#include "esp_scsi.h" - /* - * we don't give the address of DMA channel, but the number - * of DMA channel, so we can use the jazz DMA functions - * - */ - esp->dregs = (void *) JAZZ_SCSI_DMA; - - /* ESP register base */ - esp->eregs = (struct ESP_regs *)(JAZZ_SCSI_BASE); - - /* 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(CPHYSADDR(cmd_buffer), sizeof (cmd_buffer)); - - esp->irq = JAZZ_SCSI_IRQ; - request_irq(JAZZ_SCSI_IRQ, esp_intr, IRQF_DISABLED, "JAZZ SCSI", - esp->ehost); - - /* - * FIXME, look if the scsi id is available from NVRAM - */ - esp->scsi_id = 7; - - /* Check for differential SCSI-bus */ - /* What is this stuff? */ - esp->diff = 0; - - esp_initialize(esp); - - 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; - } - return 0; -} +#define DRV_MODULE_NAME "jazz_esp" +#define PFX DRV_MODULE_NAME ": " +#define DRV_VERSION "1.000" +#define DRV_MODULE_RELDATE "May 19, 2007" -/************************************************************* DMA Functions */ -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +static void jazz_esp_write8(struct esp *esp, u8 val, unsigned long reg) { - return fifo_count; + *(volatile u8 *)(esp->regs + reg) = val; } -static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp) +static u8 jazz_esp_read8(struct esp *esp, unsigned long reg) { - /* - * maximum DMA size is 1MB - */ - unsigned long sz = sp->SCp.this_residual; - if(sz > 0x100000) - sz = 0x100000; - return sz; + return *(volatile u8 *)(esp->regs + reg); } -static void dma_dump_state(struct NCR_ESP *esp) +static dma_addr_t jazz_esp_map_single(struct esp *esp, void *buf, + size_t sz, int dir) { - - ESPLOG(("esp%d: dma -- enable <%08x> residue <%08x\n", - esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_residue((int)esp->dregs))); + return dma_map_single(esp->dev, buf, sz, dir); } -static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) +static int jazz_esp_map_sg(struct esp *esp, struct scatterlist *sg, + int num_sg, int dir) { - dma_cache_wback_inv ((unsigned long)phys_to_virt(vdma_log2phys(vaddress)), length); - vdma_disable ((int)esp->dregs); - vdma_set_mode ((int)esp->dregs, DMA_MODE_READ); - vdma_set_addr ((int)esp->dregs, vaddress); - vdma_set_count ((int)esp->dregs, length); - vdma_enable ((int)esp->dregs); + return dma_map_sg(esp->dev, sg, num_sg, dir); } -static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) +static void jazz_esp_unmap_single(struct esp *esp, dma_addr_t addr, + size_t sz, int dir) { - dma_cache_wback_inv ((unsigned long)phys_to_virt(vdma_log2phys(vaddress)), length); - vdma_disable ((int)esp->dregs); - vdma_set_mode ((int)esp->dregs, DMA_MODE_WRITE); - vdma_set_addr ((int)esp->dregs, vaddress); - vdma_set_count ((int)esp->dregs, length); - vdma_enable ((int)esp->dregs); + dma_unmap_single(esp->dev, addr, sz, dir); } -static void dma_ints_off(struct NCR_ESP *esp) +static void jazz_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, + int num_sg, int dir) { - disable_irq(esp->irq); + dma_unmap_sg(esp->dev, sg, num_sg, dir); } -static void dma_ints_on(struct NCR_ESP *esp) +static int jazz_esp_irq_pending(struct esp *esp) { - enable_irq(esp->irq); + if (jazz_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR) + return 1; + return 0; } -static int dma_irq_p(struct NCR_ESP *esp) +static void jazz_esp_reset_dma(struct esp *esp) { - return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); + vdma_disable ((int)esp->dma_regs); } -static int dma_ports_p(struct NCR_ESP *esp) +static void jazz_esp_dma_drain(struct esp *esp) { - int enable = vdma_get_enable((int)esp->dregs); - - return (enable & R4030_CHNL_ENABLE); + /* nothing to do */ } -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +static void jazz_esp_dma_invalidate(struct esp *esp) { - /* - * On the Sparc, DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if(write){ - dma_init_read(esp, addr, count); - } else { - dma_init_write(esp, addr, count); - } + vdma_disable ((int)esp->dma_regs); } -static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp) +static void jazz_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, + u32 dma_count, int write, u8 cmd) { - sp->SCp.have_data_in = vdma_alloc(CPHYSADDR(sp->SCp.buffer), sp->SCp.this_residual); - sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in); + BUG_ON(!(cmd & ESP_CMD_DMA)); + + jazz_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); + jazz_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); + vdma_disable ((int)esp->dma_regs); + if (write) + vdma_set_mode ((int)esp->dma_regs, DMA_MODE_READ); + else + vdma_set_mode ((int)esp->dma_regs, DMA_MODE_WRITE); + + vdma_set_addr ((int)esp->dma_regs, addr); + vdma_set_count ((int)esp->dma_regs, dma_count); + vdma_enable ((int)esp->dma_regs); + + scsi_esp_cmd(esp, cmd); } -static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp) -{ - int sz = sp->SCp.buffers_residual; - struct scatterlist *sg = (struct scatterlist *) sp->SCp.buffer; - - while (sz >= 0) { - sg[sz].dma_address = vdma_alloc(CPHYSADDR(page_address(sg[sz].page) + sg[sz].offset), sg[sz].length); - sz--; - } - sp->SCp.ptr=(char *)(sp->SCp.buffer->dma_address); -} - -static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp) +static int jazz_esp_dma_error(struct esp *esp) { - vdma_free(sp->SCp.have_data_in); + u32 enable = vdma_get_enable((int)esp->dma_regs); + + if (enable & (R4030_MEM_INTR|R4030_ADDR_INTR)) + return 1; + + return 0; } -static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp) +static const struct esp_driver_ops jazz_esp_ops = { + .esp_write8 = jazz_esp_write8, + .esp_read8 = jazz_esp_read8, + .map_single = jazz_esp_map_single, + .map_sg = jazz_esp_map_sg, + .unmap_single = jazz_esp_unmap_single, + .unmap_sg = jazz_esp_unmap_sg, + .irq_pending = jazz_esp_irq_pending, + .reset_dma = jazz_esp_reset_dma, + .dma_drain = jazz_esp_dma_drain, + .dma_invalidate = jazz_esp_dma_invalidate, + .send_dma_cmd = jazz_esp_send_dma_cmd, + .dma_error = jazz_esp_dma_error, +}; + +static int __devinit esp_jazz_probe(struct platform_device *dev) { - int sz = sp->use_sg - 1; - struct scatterlist *sg = (struct scatterlist *)sp->request_buffer; - - while(sz >= 0) { - vdma_free(sg[sz].dma_address); - sz--; - } + struct scsi_host_template *tpnt = &scsi_esp_template; + struct Scsi_Host *host; + struct esp *esp; + struct resource *res; + int err; + + host = scsi_host_alloc(tpnt, sizeof(struct esp)); + + err = -ENOMEM; + if (!host) + goto fail; + + host->max_id = 8; + esp = host_to_esp(host); + + esp->host = host; + esp->dev = dev; + esp->ops = &jazz_esp_ops; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + goto fail_unlink; + + esp->regs = (void __iomem *)res->start; + if (!esp->regs) + goto fail_unlink; + + res = platform_get_resource(dev, IORESOURCE_MEM, 1); + if (!res) + goto fail_unlink; + + esp->dma_regs = (void __iomem *)res->start; + + esp->command_block = dma_alloc_coherent(esp->dev, 16, + &esp->command_block_dma, + GFP_KERNEL); + if (!esp->command_block) + goto fail_unmap_regs; + + host->irq = platform_get_irq(dev, 0); + err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); + if (err < 0) + goto fail_unmap_command_block; + + esp->scsi_id = 7; + esp->host->this_id = esp->scsi_id; + esp->scsi_id_mask = (1 << esp->scsi_id); + esp->cfreq = 40000000; + + dev_set_drvdata(&dev->dev, esp); + + err = scsi_esp_register(esp, &dev->dev); + if (err) + goto fail_free_irq; + + return 0; + +fail_free_irq: + free_irq(host->irq, esp); +fail_unmap_command_block: + dma_free_coherent(esp->dev, 16, + esp->command_block, + esp->command_block_dma); +fail_unmap_regs: +fail_unlink: + scsi_host_put(host); +fail: + return err; } -static void dma_advance_sg (struct scsi_cmnd *sp) +static int __devexit esp_jazz_remove(struct platform_device *dev) { - sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); + struct esp *esp = dev_get_drvdata(&dev->dev); + unsigned int irq = esp->host->irq; + + scsi_esp_unregister(esp); + + free_irq(irq, esp); + dma_free_coherent(esp->dev, 16, + esp->command_block, + esp->command_block_dma); + + scsi_host_put(esp->host); + + return 0; } -#define JAZZ_HDC_LED 0xe000d100 /* FIXME, find correct address */ +static struct platform_driver esp_jazz_driver = { + .probe = esp_jazz_probe, + .remove = __devexit_p(esp_jazz_remove), + .driver = { + .name = "jazz_esp", + }, +}; -static void dma_led_off(struct NCR_ESP *esp) +static int __init jazz_esp_init(void) { -#if 0 - *(unsigned char *)JAZZ_HDC_LED = 0; -#endif + return platform_driver_register(&esp_jazz_driver); } -static void dma_led_on(struct NCR_ESP *esp) -{ -#if 0 - *(unsigned char *)JAZZ_HDC_LED = 1; -#endif +static void __exit jazz_esp_exit(void) +{ + platform_driver_unregister(&esp_jazz_driver); } -static struct scsi_host_template driver_template = { - .proc_name = "jazz_esp", - .proc_info = esp_proc_info, - .name = "ESP 100/100a/200", - .detect = jazz_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = jazz_esp_release, - .info = esp_info, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" +MODULE_DESCRIPTION("JAZZ ESP SCSI driver"); +MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(jazz_esp_init); +module_exit(jazz_esp_exit); |