On Tue, May 5, 2009 at 09:36, Geert Uytterhoeven <[email protected]> wrote: > On Sat, Apr 18, 2009 at 20:52, Geert Uytterhoeven <[email protected]> > wrote: >> [07] m68k: amiga - A3000 SCSI platform device conversion >> >> Due to lack of hardware (only Amiga 4000 here), I couldn't test all drivers. >> Especially the SCSI drivers could use some testing feedback. >> The changes to most other drivers are fairly trivial. > > I'm a bit reluctant to apply the A3000 SCSI platform device conversion without > having received any feedback, and I would like to apply the whole series ASAP. > Did anyone try on A3000/A3000T? Similar changes are needed to convert the > A2091 and GVP II SCSI drivers to the zorro_driver model, so if we have > more users > of those, I can do that conversion first, so it can receive some testing.
Here's the conversion of the A2091/A590 SCSI driver to a proper zorro_driver. Due to the lack of hardware, it's untested. BTW, when comparing a2091.c to a3000.c, a3000.c has several additional mb()s and one additiona barrier(). Do we need those in a2091.c, too? >From 3cffd671427facc80cc7dbfb0ca18ce11ea4a46b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven <[email protected]> Date: Tue, 12 May 2009 22:21:09 +0200 Subject: [PATCH] m68k: amiga - A2091/A590 SCSI zorro_driver conversion --- drivers/scsi/a2091.c | 385 ++++++++++++++++++++++++++----------------------- 1 files changed, 204 insertions(+), 181 deletions(-) diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index 475e808..c294da1 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -1,203 +1,142 @@ #include <linux/types.h> #include <linux/mm.h> -#include <linux/blkdev.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/zorro.h> #include <asm/setup.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/amigaints.h> #include <asm/amigahw.h> -#include <linux/zorro.h> -#include <asm/irq.h> -#include <linux/spinlock.h> #include "scsi.h" -#include <scsi/scsi_host.h> #include "wd33c93.h" #include "a2091.h" -#include<linux/stat.h> -#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base)) -#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) - -static int a2091_release(struct Scsi_Host *instance); - -static irqreturn_t a2091_intr (int irq, void *_instance) +static irqreturn_t a2091_intr(int irq, void *data) { - unsigned long flags; - unsigned int status; - struct Scsi_Host *instance = (struct Scsi_Host *)_instance; - - status = DMA(instance)->ISTR; - if (!(status & (ISTR_INT_F|ISTR_INT_P)) || !(status & ISTR_INTS)) - return IRQ_NONE; - - spin_lock_irqsave(instance->host_lock, flags); - wd33c93_intr(instance); - spin_unlock_irqrestore(instance->host_lock, flags); - return IRQ_HANDLED; + struct Scsi_Host *host = data; + a2091_scsiregs *regs = (a2091_scsiregs *)(host->base); + unsigned int status = regs->ISTR; + unsigned long flags; + + if (!(status & (ISTR_INT_F|ISTR_INT_P)) || !(status & ISTR_INTS)) + return IRQ_NONE; + + spin_lock_irqsave(host->host_lock, flags); + wd33c93_intr(host); + spin_unlock_irqrestore(host->host_lock, flags); + return IRQ_HANDLED; } static int dma_setup(struct scsi_cmnd *cmd, int dir_in) { - unsigned short cntr = CNTR_PDMD | CNTR_INTEN; - unsigned long addr = virt_to_bus(cmd->SCp.ptr); - struct Scsi_Host *instance = cmd->device->host; - - /* don't allow DMA if the physical address is bad */ - if (addr & A2091_XFER_MASK) - { - HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511) - & ~0x1ff; - HDATA(instance)->dma_bounce_buffer = - kmalloc (HDATA(instance)->dma_bounce_len, GFP_KERNEL); - - /* can't allocate memory; use PIO */ - if (!HDATA(instance)->dma_bounce_buffer) { - HDATA(instance)->dma_bounce_len = 0; - return 1; - } + struct Scsi_Host *host = cmd->device->host; + struct WD33C93_hostdata *hdata = shost_priv(host); + a2091_scsiregs *regs = (a2091_scsiregs *)(host->base); + unsigned short cntr = CNTR_PDMD | CNTR_INTEN; + unsigned long addr = virt_to_bus(cmd->SCp.ptr); - /* get the physical address of the bounce buffer */ - addr = virt_to_bus(HDATA(instance)->dma_bounce_buffer); - - /* the bounce buffer may not be in the first 16M of physmem */ + /* don't allow DMA if the physical address is bad */ if (addr & A2091_XFER_MASK) { - /* we could use chipmem... maybe later */ - kfree (HDATA(instance)->dma_bounce_buffer); - HDATA(instance)->dma_bounce_buffer = NULL; - HDATA(instance)->dma_bounce_len = 0; - return 1; - } - - if (!dir_in) { - /* copy to bounce buffer for a write */ - memcpy (HDATA(instance)->dma_bounce_buffer, - cmd->SCp.ptr, cmd->SCp.this_residual); + hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; + hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len, + GFP_KERNEL); + + /* can't allocate memory; use PIO */ + if (!hdata->dma_bounce_buffer) { + hdata->dma_bounce_len = 0; + return 1; + } + + /* get the physical address of the bounce buffer */ + addr = virt_to_bus(hdata->dma_bounce_buffer); + + /* the bounce buffer may not be in the first 16M of physmem */ + if (addr & A2091_XFER_MASK) { + /* we could use chipmem... maybe later */ + kfree(hdata->dma_bounce_buffer); + hdata->dma_bounce_buffer = NULL; + hdata->dma_bounce_len = 0; + return 1; + } + + if (!dir_in) { + /* copy to bounce buffer for a write */ + memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr, + cmd->SCp.this_residual); + } } - } - /* setup dma direction */ - if (!dir_in) - cntr |= CNTR_DDIR; + /* setup dma direction */ + if (!dir_in) + cntr |= CNTR_DDIR; - /* remember direction */ - HDATA(cmd->device->host)->dma_dir = dir_in; + /* remember direction */ + hdata->dma_dir = dir_in; - DMA(cmd->device->host)->CNTR = cntr; + regs->CNTR = cntr; - /* setup DMA *physical* address */ - DMA(cmd->device->host)->ACR = addr; + /* setup DMA *physical* address */ + regs->ACR = addr; - if (dir_in){ - /* invalidate any cache */ - cache_clear (addr, cmd->SCp.this_residual); - }else{ - /* push any dirty cache */ - cache_push (addr, cmd->SCp.this_residual); - } - /* start DMA */ - DMA(cmd->device->host)->ST_DMA = 1; + if (dir_in) { + /* invalidate any cache */ + cache_clear(addr, cmd->SCp.this_residual); + } else { + /* push any dirty cache */ + cache_push(addr, cmd->SCp.this_residual); + } + /* start DMA */ + regs->ST_DMA = 1; - /* return success */ - return 0; + /* return success */ + return 0; } static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, - int status) + int status) { - /* disable SCSI interrupts */ - unsigned short cntr = CNTR_PDMD; - - if (!HDATA(instance)->dma_dir) - cntr |= CNTR_DDIR; - - /* disable SCSI interrupts */ - DMA(instance)->CNTR = cntr; - - /* flush if we were reading */ - if (HDATA(instance)->dma_dir) { - DMA(instance)->FLUSH = 1; - while (!(DMA(instance)->ISTR & ISTR_FE_FLG)) - ; - } - - /* clear a possible interrupt */ - DMA(instance)->CINT = 1; - - /* stop DMA */ - DMA(instance)->SP_DMA = 1; - - /* restore the CONTROL bits (minus the direction flag) */ - DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; - - /* copy from a bounce buffer, if necessary */ - if (status && HDATA(instance)->dma_bounce_buffer) { - if( HDATA(instance)->dma_dir ) - memcpy (SCpnt->SCp.ptr, - HDATA(instance)->dma_bounce_buffer, - SCpnt->SCp.this_residual); - kfree (HDATA(instance)->dma_bounce_buffer); - HDATA(instance)->dma_bounce_buffer = NULL; - HDATA(instance)->dma_bounce_len = 0; - } -} + struct WD33C93_hostdata *hdata = shost_priv(instance); + a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base); -static int __init a2091_detect(struct scsi_host_template *tpnt) -{ - static unsigned char called = 0; - struct Scsi_Host *instance; - unsigned long address; - struct zorro_dev *z = NULL; - wd33c93_regs regs; - int num_a2091 = 0; - - if (!MACH_IS_AMIGA || called) - return 0; - called = 1; - - tpnt->proc_name = "A2091"; - tpnt->proc_info = &wd33c93_proc_info; - - while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { - if (z->id != ZORRO_PROD_CBM_A590_A2091_1 && - z->id != ZORRO_PROD_CBM_A590_A2091_2) - continue; - address = z->resource.start; - if (!request_mem_region(address, 256, "wd33c93")) - continue; - - instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata)); - if (instance == NULL) - goto release; - instance->base = ZTWO_VADDR(address); - instance->irq = IRQ_AMIGA_PORTS; - instance->unique_id = z->slotaddr; - DMA(instance)->DAWR = DAWR_A2091; - regs.SASR = &(DMA(instance)->SASR); - regs.SCMD = &(DMA(instance)->SCMD); - HDATA(instance)->no_sync = 0xff; - HDATA(instance)->fast = 0; - HDATA(instance)->dma_mode = CTRL_DMA; - wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10); - if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI", - instance)) - goto unregister; - DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; - num_a2091++; - continue; - -unregister: - scsi_unregister(instance); - wd33c93_release(); -release: - release_mem_region(address, 256); - } - - return num_a2091; + /* disable SCSI interrupts */ + unsigned short cntr = CNTR_PDMD; + + if (!hdata->dma_dir) + cntr |= CNTR_DDIR; + + /* disable SCSI interrupts */ + regs->CNTR = cntr; + + /* flush if we were reading */ + if (hdata->dma_dir) { + regs->FLUSH = 1; + while (!(regs->ISTR & ISTR_FE_FLG)) + ; + } + + /* clear a possible interrupt */ + regs->CINT = 1; + + /* stop DMA */ + regs->SP_DMA = 1; + + /* restore the CONTROL bits (minus the direction flag) */ + regs->CNTR = CNTR_PDMD | CNTR_INTEN; + + /* copy from a bounce buffer, if necessary */ + if (status && hdata->dma_bounce_buffer) { + if (hdata->dma_dir) + memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer, + SCpnt->SCp.this_residual); + kfree(hdata->dma_bounce_buffer); + hdata->dma_bounce_buffer = NULL; + hdata->dma_bounce_len = 0; + } } static int a2091_bus_reset(struct scsi_cmnd *cmd) @@ -214,13 +153,11 @@ static int a2091_bus_reset(struct scsi_cmnd *cmd) return SUCCESS; } -#define HOSTS_C - -static struct scsi_host_template driver_template = { - .proc_name = "A2901", +static struct scsi_host_template a2091_scsi_template = { + .module = THIS_MODULE, .name = "Commodore A2091/A590 SCSI", - .detect = a2091_detect, - .release = a2091_release, + .proc_info = wd33c93_proc_info, + .proc_name = "A2901", .queuecommand = wd33c93_queuecommand, .eh_abort_handler = wd33c93_abort, .eh_bus_reset_handler = a2091_bus_reset, @@ -233,17 +170,104 @@ static struct scsi_host_template driver_template = { }; -#include "scsi_module.c" +static int __devinit a2091_init_one(struct zorro_dev *z, + const struct zorro_device_id *ent) +{ + struct Scsi_Host *host; + struct WD33C93_hostdata *hdata; + int error; + wd33c93_regs wdregs; + a2091_scsiregs *regs; + + if (!request_mem_region(z->resource.start, 256, "wd33c93")) + return -EBUSY; + + host = scsi_host_alloc(&a2091_scsi_template, + sizeof(struct WD33C93_hostdata)); + if (!host) { + error = -ENOMEM; + goto fail_alloc; + } + + host->base = ZTWO_VADDR(z->resource.start); + host->irq = IRQ_AMIGA_PORTS; + host->unique_id = z->slotaddr; + + regs = (a2091_scsiregs *)(host->base); + regs->DAWR = DAWR_A2091; + + wdregs.SASR = ®s->SASR; + wdregs.SCMD = ®s->SCMD; + + hdata = shost_priv(host); + hdata->no_sync = 0xff; + hdata->fast = 0; + hdata->dma_mode = CTRL_DMA; + + wd33c93_init(host, wdregs, dma_setup, dma_stop, WD33C93_FS_8_10); + error = request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, + "A2091 SCSI", host); + if (error) + goto fail_irq; + + regs->CNTR = CNTR_PDMD | CNTR_INTEN; + + error = scsi_add_host(host, NULL); + if (error) + goto fail_host; + + zorro_set_drvdata(z, host); + + scsi_scan_host(host); + return 0; + +fail_host: + free_irq(IRQ_AMIGA_PORTS, host); +fail_irq: + scsi_host_put(host); +fail_alloc: + release_mem_region(z->resource.start, 256); + return error; +} + +static void __devexit a2091_remove_one(struct zorro_dev *z) +{ + struct Scsi_Host *host = zorro_get_drvdata(z); + a2091_scsiregs *regs = (a2091_scsiregs *)(host->base); + + regs->CNTR = 0; + scsi_remove_host(host); + free_irq(IRQ_AMIGA_PORTS, host); + scsi_host_put(host); + release_mem_region(z->resource.start, 256); +} + +static struct zorro_device_id a2091_zorro_tbl[] __devinitdata = { + { ZORRO_PROD_CBM_A590_A2091_1 }, + { ZORRO_PROD_CBM_A590_A2091_2 }, + { 0 } +}; +MODULE_DEVICE_TABLE(zorro, a2091_zorro_tbl); + +static struct zorro_driver a2091_driver = { + .name = "a2091", + .id_table = a2091_zorro_tbl, + .probe = a2091_init_one, + .remove = __devexit_p(a2091_remove_one), +}; + +static int __init a2091_init(void) +{ + return zorro_register_driver(&a2091_driver); +} + +module_init(a2091_init); -static int a2091_release(struct Scsi_Host *instance) +static void __exit a2091_exit(void) { -#ifdef MODULE - DMA(instance)->CNTR = 0; - release_mem_region(ZTWO_PADDR(instance->base), 256); - free_irq(IRQ_AMIGA_PORTS, instance); - wd33c93_release(); -#endif - return 1; + zorro_unregister_driver(&a2091_driver); } +module_exit(a2091_exit); + +MODULE_DESCRIPTION("Commodore A2091/A590 SCSI"); MODULE_LICENSE("GPL"); -- 1.6.3 Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected] In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds -- To unsubscribe from this list: send the line "unsubscribe linux-m68k" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
