X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fscsi%2Fsgiwd93.c;h=31fe6051c799869f76713ffa674d4d795baf73dc;hb=4aa12f7b927c3cac0e0cf3503642597527d0ece0;hp=a15752b379906b3b50464ee72f4110578f93d2e4;hpb=cb2ebc59ff52cee770cfd6ba5f23a6cc3c214648;p=linux-2.6-omap-h63xx.git diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index a15752b3799..31fe6051c79 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -6,87 +6,53 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) * Copyright (C) 2001 Florian Lohoff (flo@rfc822.org) - * Copyright (C) 2003 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org) * * (In all truth, Jed Schimmel wrote all this code.) */ -#include -#include -#include -#include -#include + +#undef DEBUG + #include #include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include #include #include -#include -#include +#include #include "scsi.h" -#include #include "wd33c93.h" -#include - -#if 0 -#define DPRINTK(args...) printk(args) -#else -#define DPRINTK(args...) -#endif - -#define HDATA(ptr) ((struct ip22_hostdata *)((ptr)->hostdata)) - struct ip22_hostdata { struct WD33C93_hostdata wh; - struct hpc_data { - dma_addr_t dma; - void * cpu; - } hd; + dma_addr_t dma; + void *cpu; + struct device *dev; }; +#define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata)) + struct hpc_chunk { struct hpc_dma_desc desc; u32 _padding; /* align to quadword boundary */ }; -struct Scsi_Host *sgiwd93_host; -struct Scsi_Host *sgiwd93_host1; +/* space for hpc dma descriptors */ +#define HPC_DMA_SIZE PAGE_SIZE -/* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */ -static inline void write_wd33c93_count(const wd33c93_regs regs, - unsigned long value) -{ - *regs.SASR = WD_TRANSFER_COUNT_MSB; - mb(); - *regs.SCMD = ((value >> 16) & 0xff); - *regs.SCMD = ((value >> 8) & 0xff); - *regs.SCMD = ((value >> 0) & 0xff); - mb(); -} - -static inline unsigned long read_wd33c93_count(const wd33c93_regs regs) -{ - unsigned long value; - - *regs.SASR = WD_TRANSFER_COUNT_MSB; - mb(); - value = ((*regs.SCMD & 0xff) << 16); - value |= ((*regs.SCMD & 0xff) << 8); - value |= ((*regs.SCMD & 0xff) << 0); - mb(); - return value; -} +#define DMA_DIR(d) ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE) static irqreturn_t sgiwd93_intr(int irq, void *dev_id) { - struct Scsi_Host * host = (struct Scsi_Host *) dev_id; + struct Scsi_Host * host = dev_id; unsigned long flags; spin_lock_irqsave(host->host_lock, flags); @@ -97,15 +63,17 @@ static irqreturn_t sgiwd93_intr(int irq, void *dev_id) } static inline -void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp) +void fill_hpc_entries(struct ip22_hostdata *hd, struct scsi_cmnd *cmd, int din) { unsigned long len = cmd->SCp.this_residual; void *addr = cmd->SCp.ptr; dma_addr_t physaddr; unsigned long count; + struct hpc_chunk *hcp; - physaddr = dma_map_single(NULL, addr, len, cmd->sc_data_direction); + physaddr = dma_map_single(hd->dev, addr, len, DMA_DIR(din)); cmd->SCp.dma_handle = physaddr; + hcp = hd->cpu; while (len) { /* @@ -127,16 +95,18 @@ void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp) */ hcp->desc.pbuf = 0; hcp->desc.cntinfo = HPCDMA_EOX; + dma_cache_sync(hd->dev, hd->cpu, + (unsigned long)(hcp + 1) - (unsigned long)hd->cpu, + DMA_TO_DEVICE); } static int dma_setup(struct scsi_cmnd *cmd, int datainp) { - struct ip22_hostdata *hdata = HDATA(cmd->device->host); + struct ip22_hostdata *hdata = host_to_hostdata(cmd->device->host); struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->device->host->base; - struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->hd.cpu; - DPRINTK("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp); + pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hdata->cpu); hdata->wh.dma_dir = datainp; @@ -149,12 +119,12 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp) if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0) return 1; - fill_hpc_entries(hcp, cmd, datainp); + fill_hpc_entries(hdata, cmd, datainp); - DPRINTK(" HPCGO\n"); + pr_debug(" HPCGO\n"); /* Start up the HPC. */ - hregs->ndptr = hdata->hd.dma; + hregs->ndptr = hdata->dma; if (datainp) hregs->ctrl = HPC3_SCTRL_ACTIVE; else @@ -166,15 +136,18 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp) static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, int status) { - struct ip22_hostdata *hdata = HDATA(instance); + struct ip22_hostdata *hdata = host_to_hostdata(instance); struct hpc3_scsiregs *hregs; if (!SCpnt) return; + if (SCpnt->SCp.ptr == NULL || SCpnt->SCp.this_residual == 0) + return; + hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base; - DPRINTK("dma_stop: status<%d> ", status); + pr_debug("dma_stop: status<%d> ", status); /* First stop the HPC and flush it's FIFO. */ if (hdata->wh.dma_dir) { @@ -183,10 +156,11 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, barrier(); } hregs->ctrl = 0; - dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual, - SCpnt->sc_data_direction); + dma_unmap_single(hdata->dev, SCpnt->SCp.dma_handle, + SCpnt->SCp.this_residual, + DMA_DIR(hdata->wh.dma_dir)); - DPRINTK("\n"); + pr_debug("\n"); } void sgiwd93_reset(unsigned long base) @@ -197,147 +171,167 @@ void sgiwd93_reset(unsigned long base) udelay(50); hregs->ctrl = 0; } +EXPORT_SYMBOL_GPL(sgiwd93_reset); -static inline void init_hpc_chain(struct hpc_data *hd) +static inline void init_hpc_chain(struct ip22_hostdata *hdata) { - struct hpc_chunk *hcp = (struct hpc_chunk *) hd->cpu; - struct hpc_chunk *dma = (struct hpc_chunk *) hd->dma; + struct hpc_chunk *hcp = (struct hpc_chunk *)hdata->cpu; + dma_addr_t dma = hdata->dma; unsigned long start, end; start = (unsigned long) hcp; - end = start + PAGE_SIZE; + end = start + HPC_DMA_SIZE; while (start < end) { - hcp->desc.pnext = (u32) (dma + 1); + hcp->desc.pnext = (u32) (dma + sizeof(struct hpc_chunk)); hcp->desc.cntinfo = HPCDMA_EOX; - hcp++; dma++; + hcp++; + dma += sizeof(struct hpc_chunk); start += sizeof(struct hpc_chunk); }; hcp--; - hcp->desc.pnext = hd->dma; + hcp->desc.pnext = hdata->dma; } -static struct Scsi_Host * __init sgiwd93_setup_scsi( - struct scsi_host_template *SGIblows, int unit, int irq, - struct hpc3_scsiregs *hregs, unsigned char *wdregs) +static int sgiwd93_bus_reset(struct scsi_cmnd *cmd) +{ + /* FIXME perform bus-specific reset */ + + /* FIXME 2: kill this function, and let midlayer fallback + to the same result, calling wd33c93_host_reset() */ + + spin_lock_irq(cmd->device->host->host_lock); + wd33c93_host_reset(cmd); + spin_unlock_irq(cmd->device->host->host_lock); + + return SUCCESS; +} + +/* + * Kludge alert - the SCSI code calls the abort and reset method with int + * arguments not with pointers. So this is going to blow up beautyfully + * on 64-bit systems with memory outside the compat address spaces. + */ +static struct scsi_host_template sgiwd93_template = { + .module = THIS_MODULE, + .proc_name = "SGIWD93", + .name = "SGI WD93", + .queuecommand = wd33c93_queuecommand, + .eh_abort_handler = wd33c93_abort, + .eh_bus_reset_handler = sgiwd93_bus_reset, + .eh_host_reset_handler = wd33c93_host_reset, + .can_queue = 16, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 8, + .use_clustering = DISABLE_CLUSTERING, +}; + +static int __init sgiwd93_probe(struct platform_device *pdev) { + struct sgiwd93_platform_data *pd = pdev->dev.platform_data; + unsigned char *wdregs = pd->wdregs; + struct hpc3_scsiregs *hregs = pd->hregs; struct ip22_hostdata *hdata; struct Scsi_Host *host; wd33c93_regs regs; - - host = scsi_register(SGIblows, sizeof(struct ip22_hostdata)); - if (!host) - return NULL; + unsigned int unit = pd->unit; + unsigned int irq = pd->irq; + int err; + + host = scsi_host_alloc(&sgiwd93_template, sizeof(struct ip22_hostdata)); + if (!host) { + err = -ENOMEM; + goto out; + } host->base = (unsigned long) hregs; host->irq = irq; - hdata = HDATA(host); - hdata->hd.cpu = dma_alloc_coherent(NULL, PAGE_SIZE, &hdata->hd.dma, - GFP_KERNEL); - if (!hdata->hd.cpu) { + hdata = host_to_hostdata(host); + hdata->dev = &pdev->dev; + hdata->cpu = dma_alloc_noncoherent(&pdev->dev, HPC_DMA_SIZE, + &hdata->dma, GFP_KERNEL); + if (!hdata->cpu) { printk(KERN_WARNING "sgiwd93: Could not allocate memory for " "host %d buffer.\n", unit); - goto out_unregister; + err = -ENOMEM; + goto out_put; } - init_hpc_chain(&hdata->hd); + + init_hpc_chain(hdata); regs.SASR = wdregs + 3; regs.SCMD = wdregs + 7; - wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20)); + hdata->wh.no_sync = 0; + hdata->wh.fast = 1; + hdata->wh.dma_mode = CTRL_BURST; - if (hdata->wh.no_sync == 0xff) - hdata->wh.no_sync = 0; + wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20)); - if (request_irq(irq, sgiwd93_intr, 0, "SGI WD93", (void *) host)) { + err = request_irq(irq, sgiwd93_intr, 0, "SGI WD93", host); + if (err) { printk(KERN_WARNING "sgiwd93: Could not register irq %d " "for host %d.\n", irq, unit); goto out_free; } - return host; -out_free: - dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma); - wd33c93_release(); + platform_set_drvdata(pdev, host); -out_unregister: - scsi_unregister(host); + err = scsi_add_host(host, NULL); + if (err) + goto out_irq; - return NULL; -} + scsi_scan_host(host); -static int __init sgiwd93_detect(struct scsi_host_template *SGIblows) -{ - int found = 0; - - SGIblows->proc_name = "SGIWD93"; - sgiwd93_host = sgiwd93_setup_scsi(SGIblows, 0, SGI_WD93_0_IRQ, - &hpc3c0->scsi_chan0, - (unsigned char *)hpc3c0->scsi0_ext); - if (sgiwd93_host) - found++; - - /* Set up second controller on the Indigo2 */ - if (ip22_is_fullhouse()) { - sgiwd93_host1 = sgiwd93_setup_scsi(SGIblows, 1, SGI_WD93_1_IRQ, - &hpc3c0->scsi_chan1, - (unsigned char *)hpc3c0->scsi1_ext); - if (sgiwd93_host1) - found++; - } + return 0; - return found; +out_irq: + free_irq(irq, host); +out_free: + dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma); +out_put: + scsi_host_put(host); +out: + + return err; } -static int sgiwd93_release(struct Scsi_Host *instance) +static void __exit sgiwd93_remove(struct platform_device *pdev) { - struct ip22_hostdata *hdata = HDATA(instance); - int irq = 0; - - if (sgiwd93_host && sgiwd93_host == instance) - irq = SGI_WD93_0_IRQ; - else if (sgiwd93_host1 && sgiwd93_host1 == instance) - irq = SGI_WD93_1_IRQ; + struct Scsi_Host *host = platform_get_drvdata(pdev); + struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata; + struct sgiwd93_platform_data *pd = pdev->dev.platform_data; + + scsi_remove_host(host); + free_irq(pd->irq, host); + dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma); + scsi_host_put(host); +} - free_irq(irq, sgiwd93_intr); - dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma); - wd33c93_release(); +static struct platform_driver sgiwd93_driver = { + .probe = sgiwd93_probe, + .remove = __devexit_p(sgiwd93_remove), + .driver = { + .name = "sgiwd93", + .owner = THIS_MODULE, + } +}; - return 1; +static int __init sgiwd93_module_init(void) +{ + return platform_driver_register(&sgiwd93_driver); } -static int sgiwd93_bus_reset(struct scsi_cmnd *cmd) +static void __exit sgiwd93_module_exit(void) { - /* FIXME perform bus-specific reset */ - - /* FIXME 2: kill this function, and let midlayer fallback - to the same result, calling wd33c93_host_reset() */ - - spin_lock_irq(cmd->device->host->host_lock); - wd33c93_host_reset(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return SUCCESS; + return platform_driver_unregister(&sgiwd93_driver); } -/* - * Kludge alert - the SCSI code calls the abort and reset method with int - * arguments not with pointers. So this is going to blow up beautyfully - * on 64-bit systems with memory outside the compat address spaces. - */ -static struct scsi_host_template driver_template = { - .proc_name = "SGIWD93", - .name = "SGI WD93", - .detect = sgiwd93_detect, - .release = sgiwd93_release, - .queuecommand = wd33c93_queuecommand, - .eh_abort_handler = wd33c93_abort, - .eh_bus_reset_handler = sgiwd93_bus_reset, - .eh_host_reset_handler = wd33c93_host_reset, - .can_queue = 16, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 8, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" +module_init(sgiwd93_module_init); +module_exit(sgiwd93_module_exit); + +MODULE_DESCRIPTION("SGI WD33C93 driver"); +MODULE_AUTHOR("Ralf Baechle "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sgiwd93");