11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 5c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven#include <linux/slab.h> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 8c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven#include <linux/platform_device.h> 9acf3368ffb75fc4a83726655d697e79646fe4eb3Paul Gortmaker#include <linux/module.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/page.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/amigaints.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/amigahw.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "scsi.h" 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "wd33c93.h" 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "a3000.h" 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 209387edbe6045f0bde88f0f0ace51e0ead8a318feAdrian Bunk 212b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoevenstruct a3000_hostdata { 222b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct WD33C93_hostdata wh; 232b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct a3000_scsiregs *regs; 242b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven}; 252b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven 26a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoevenstatic irqreturn_t a3000_intr(int irq, void *data) 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoeven struct Scsi_Host *instance = data; 292b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct a3000_hostdata *hdata = shost_priv(instance); 302b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven unsigned int status = hdata->regs->ISTR; 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & ISTR_INT_P)) 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 3521351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven if (status & ISTR_INTS) { 36a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoeven spin_lock_irqsave(instance->host_lock, flags); 37a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoeven wd33c93_intr(instance); 38a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoeven spin_unlock_irqrestore(instance->host_lock, flags); 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven pr_warning("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status); 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4565396410af63db90d6428c678ff84aa652c3c1ecHenrik Kretzschmarstatic int dma_setup(struct scsi_cmnd *cmd, int dir_in) 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 47a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoeven struct Scsi_Host *instance = cmd->device->host; 482b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct a3000_hostdata *hdata = shost_priv(instance); 492b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct WD33C93_hostdata *wh = &hdata->wh; 502b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct a3000_scsiregs *regs = hdata->regs; 5121351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven unsigned short cntr = CNTR_PDMD | CNTR_INTEN; 5221351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven unsigned long addr = virt_to_bus(cmd->SCp.ptr); 5321351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 5421351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* 5521351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven * if the physical address has the wrong alignment, or if 5621351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven * physical address is bad, or if it is a write and at the 5721351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven * end of a physical memory chunk, then allocate a bounce 5821351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven * buffer 5921351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven */ 6021351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven if (addr & A3000_XFER_MASK) { 612b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; 622b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len, 632b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven GFP_KERNEL); 6421351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 6521351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* can't allocate memory; use PIO */ 662b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven if (!wh->dma_bounce_buffer) { 672b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven wh->dma_bounce_len = 0; 6821351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven return 1; 6921351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven } 7021351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 7121351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven if (!dir_in) { 7221351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* copy to bounce buffer for a write */ 732b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr, 74afdbbc16134ae2eea612b51cab7545938d266dceGeert Uytterhoeven cmd->SCp.this_residual); 7521351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven } 7621351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 772b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven addr = virt_to_bus(wh->dma_bounce_buffer); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8021351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* setup dma direction */ 8121351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven if (!dir_in) 8221351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven cntr |= CNTR_DDIR; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* remember direction */ 852b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven wh->dma_dir = dir_in; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->CNTR = cntr; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8921351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* setup DMA *physical* address */ 90d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->ACR = addr; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9221351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven if (dir_in) { 9321351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* invalidate any cache */ 9421351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven cache_clear(addr, cmd->SCp.this_residual); 9521351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven } else { 9621351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* push any dirty cache */ 9721351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven cache_push(addr, cmd->SCp.this_residual); 9821351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven } 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10021351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* start DMA */ 10121351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven mb(); /* make sure setup is completed */ 102d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->ST_DMA = 1; 10321351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven mb(); /* make sure DMA has started before next IO */ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10521351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* return success */ 10621351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven return 0; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10965396410af63db90d6428c678ff84aa652c3c1ecHenrik Kretzschmarstatic void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, 11065396410af63db90d6428c678ff84aa652c3c1ecHenrik Kretzschmar int status) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1122b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct a3000_hostdata *hdata = shost_priv(instance); 1132b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct WD33C93_hostdata *wh = &hdata->wh; 1142b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct a3000_scsiregs *regs = hdata->regs; 115afdbbc16134ae2eea612b51cab7545938d266dceGeert Uytterhoeven 11621351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* disable SCSI interrupts */ 11721351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven unsigned short cntr = CNTR_PDMD; 11821351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 1192b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven if (!wh->dma_dir) 12021351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven cntr |= CNTR_DDIR; 12121351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 122d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->CNTR = cntr; 12321351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven mb(); /* make sure CNTR is updated before next IO */ 12421351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 12521351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* flush if we were reading */ 1262b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven if (wh->dma_dir) { 127d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->FLUSH = 1; 12821351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven mb(); /* don't allow prefetch */ 129d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven while (!(regs->ISTR & ISTR_FE_FLG)) 13021351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven barrier(); 13121351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven mb(); /* no IO until FLUSH is done */ 13221351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven } 13321351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 13421351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* clear a possible interrupt */ 13521351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* I think that this CINT is only necessary if you are 13621351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven * using the terminal count features. HM 7 Mar 1994 13721351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven */ 138d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->CINT = 1; 13921351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 14021351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* stop DMA */ 141d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->SP_DMA = 1; 14221351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven mb(); /* make sure DMA is stopped before next IO */ 14321351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 14421351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* restore the CONTROL bits (minus the direction flag) */ 145d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->CNTR = CNTR_PDMD | CNTR_INTEN; 14621351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven mb(); /* make sure CNTR is updated before next IO */ 14721351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 14821351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven /* copy from a bounce buffer, if necessary */ 1492b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven if (status && wh->dma_bounce_buffer) { 15021351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven if (SCpnt) { 1512b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven if (wh->dma_dir && SCpnt) 1522b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer, 15321351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven SCpnt->SCp.this_residual); 1542b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven kfree(wh->dma_bounce_buffer); 1552b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven wh->dma_bounce_buffer = NULL; 1562b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven wh->dma_bounce_len = 0; 15721351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven } else { 1582b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven kfree(wh->dma_bounce_buffer); 1592b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven wh->dma_bounce_buffer = NULL; 1602b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven wh->dma_bounce_len = 0; 16121351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven } 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 165c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenstatic int a3000_bus_reset(struct scsi_cmnd *cmd) 166c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven{ 167c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven struct Scsi_Host *instance = cmd->device->host; 168c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 169c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven /* FIXME perform bus-specific reset */ 170c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 171c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven /* FIXME 2: kill this entire function, which should 172c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven cause mid-layer to call wd33c93_host_reset anyway? */ 173c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 174c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven spin_lock_irq(instance->host_lock); 175c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven wd33c93_host_reset(cmd); 176c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven spin_unlock_irq(instance->host_lock); 177c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 178c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven return SUCCESS; 179c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven} 180c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 181c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenstatic struct scsi_host_template amiga_a3000_scsi_template = { 182c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .module = THIS_MODULE, 183c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .name = "Amiga 3000 built-in SCSI", 184c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .proc_info = wd33c93_proc_info, 185c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .proc_name = "A3000", 186c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .queuecommand = wd33c93_queuecommand, 187c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .eh_abort_handler = wd33c93_abort, 188c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .eh_bus_reset_handler = a3000_bus_reset, 189c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .eh_host_reset_handler = wd33c93_host_reset, 190c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .can_queue = CAN_QUEUE, 191c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .this_id = 7, 192c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .sg_tablesize = SG_ALL, 193c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .cmd_per_lun = CMD_PER_LUN, 194c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .use_clustering = ENABLE_CLUSTERING 195c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven}; 196c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 197c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenstatic int __init amiga_a3000_scsi_probe(struct platform_device *pdev) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 199c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven struct resource *res; 200a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoeven struct Scsi_Host *instance; 201c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven int error; 202c57c1cab789e4d54fd767fb844e3a309c754e6edGeert Uytterhoeven struct a3000_scsiregs *regs; 203c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven wd33c93_regs wdregs; 2042b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct a3000_hostdata *hdata; 20521351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 206c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 207c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven if (!res) 208c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven return -ENODEV; 20921351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 210c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven if (!request_mem_region(res->start, resource_size(res), "wd33c93")) 211c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven return -EBUSY; 21221351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 213c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven instance = scsi_host_alloc(&amiga_a3000_scsi_template, 2142b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven sizeof(struct a3000_hostdata)); 215c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven if (!instance) { 216c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven error = -ENOMEM; 217c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven goto fail_alloc; 218c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven } 21921351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 220a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoeven instance->irq = IRQ_AMIGA_PORTS; 221c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 2222b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven regs = (struct a3000_scsiregs *)ZTWO_VADDR(res->start); 223d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->DAWR = DAWR_A3000; 224c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 225d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven wdregs.SASR = ®s->SASR; 226d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven wdregs.SCMD = ®s->SCMD; 227c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 228a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoeven hdata = shost_priv(instance); 2292b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven hdata->wh.no_sync = 0xff; 2302b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven hdata->wh.fast = 0; 2312b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven hdata->wh.dma_mode = CTRL_DMA; 2322b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven hdata->regs = regs; 233c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 234a8169e6057e9b7dd41c9e3b7a41efebc4bd859c9Geert Uytterhoeven wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15); 235c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, 236c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven "A3000 SCSI", instance); 237c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven if (error) 23821351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven goto fail_irq; 239c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 240d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven regs->CNTR = CNTR_PDMD | CNTR_INTEN; 24121351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven 242c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven error = scsi_add_host(instance, NULL); 243c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven if (error) 244c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven goto fail_host; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 246c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven platform_set_drvdata(pdev, instance); 247c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 248c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven scsi_scan_host(instance); 24921351013402ab4556d1ef62aed6cbe8dfb809f77Geert Uytterhoeven return 0; 250c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven 251c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenfail_host: 252c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven free_irq(IRQ_AMIGA_PORTS, instance); 253c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenfail_irq: 254c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven scsi_host_put(instance); 255c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenfail_alloc: 256c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven release_mem_region(res->start, resource_size(res)); 257c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven return error; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 260c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenstatic int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 262c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven struct Scsi_Host *instance = platform_get_drvdata(pdev); 2632b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven struct a3000_hostdata *hdata = shost_priv(instance); 264c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 26568b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik 2662b21d5e47bb9b07f90cf213c885867cf11f99976Geert Uytterhoeven hdata->regs->CNTR = 0; 267c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven scsi_remove_host(instance); 268c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven free_irq(IRQ_AMIGA_PORTS, instance); 269c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven scsi_host_put(instance); 270c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven release_mem_region(res->start, resource_size(res)); 271c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven return 0; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 274c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenstatic struct platform_driver amiga_a3000_scsi_driver = { 275c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .remove = __exit_p(amiga_a3000_scsi_remove), 276c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .driver = { 277c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .name = "amiga-a3000-scsi", 278c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven .owner = THIS_MODULE, 279c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven }, 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 282c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenstatic int __init amiga_a3000_scsi_init(void) 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 284c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven return platform_driver_probe(&amiga_a3000_scsi_driver, 285c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven amiga_a3000_scsi_probe); 286c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven} 287c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenmodule_init(amiga_a3000_scsi_init); 288d753722ee0223f80e6d0a553c68583c6ae57c1b2Geert Uytterhoeven 289c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenstatic void __exit amiga_a3000_scsi_exit(void) 290c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven{ 291c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoeven platform_driver_unregister(&amiga_a3000_scsi_driver); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 293c2a24a4ca1137473971842461612e56a654e7edbGeert Uytterhoevenmodule_exit(amiga_a3000_scsi_exit); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 295c2a24a4ca1137473971842461612e56a654e7edbGeert UytterhoevenMODULE_DESCRIPTION("Amiga 3000 built-in SCSI"); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 297c2a24a4ca1137473971842461612e56a654e7edbGeert UytterhoevenMODULE_ALIAS("platform:amiga-a3000-scsi"); 298