Thomas Gleixner | 09c434b | 2019-05-19 13:08:20 +0100 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | #include <linux/types.h> |
| 3 | #include <linux/mm.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 | #include <linux/ioport.h> |
| 5 | #include <linux/init.h> |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 6 | #include <linux/slab.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7 | #include <linux/spinlock.h> |
| 8 | #include <linux/interrupt.h> |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 9 | #include <linux/platform_device.h> |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 10 | #include <linux/dma-mapping.h> |
Paul Gortmaker | acf3368f | 2011-05-27 09:47:43 -0400 | [diff] [blame] | 11 | #include <linux/module.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 12 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 | #include <asm/page.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 | #include <asm/amigaints.h> |
| 15 | #include <asm/amigahw.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 16 | |
Bart Van Assche | 53555fb | 2022-02-18 11:50:34 -0800 | [diff] [blame] | 17 | #include <scsi/scsi.h> |
| 18 | #include <scsi/scsi_cmnd.h> |
| 19 | #include <scsi/scsi_device.h> |
| 20 | #include <scsi/scsi_eh.h> |
| 21 | #include <scsi/scsi_tcq.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | #include "wd33c93.h" |
| 23 | #include "a3000.h" |
| 24 | |
Adrian Bunk | 9387edb | 2009-03-04 12:06:08 -0800 | [diff] [blame] | 25 | |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 26 | struct a3000_hostdata { |
| 27 | struct WD33C93_hostdata wh; |
| 28 | struct a3000_scsiregs *regs; |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 29 | struct device *dev; |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 30 | }; |
| 31 | |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 32 | #define DMA_DIR(d) ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE) |
| 33 | |
Geert Uytterhoeven | a8169e6 | 2009-05-17 13:35:07 +0200 | [diff] [blame] | 34 | static irqreturn_t a3000_intr(int irq, void *data) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 | { |
Geert Uytterhoeven | a8169e6 | 2009-05-17 13:35:07 +0200 | [diff] [blame] | 36 | struct Scsi_Host *instance = data; |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 37 | struct a3000_hostdata *hdata = shost_priv(instance); |
| 38 | unsigned int status = hdata->regs->ISTR; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 | unsigned long flags; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 | |
| 41 | if (!(status & ISTR_INT_P)) |
| 42 | return IRQ_NONE; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 43 | if (status & ISTR_INTS) { |
Geert Uytterhoeven | a8169e6 | 2009-05-17 13:35:07 +0200 | [diff] [blame] | 44 | spin_lock_irqsave(instance->host_lock, flags); |
| 45 | wd33c93_intr(instance); |
| 46 | spin_unlock_irqrestore(instance->host_lock, flags); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 47 | return IRQ_HANDLED; |
| 48 | } |
Kefeng Wang | a2cc701 | 2019-10-18 11:18:38 +0800 | [diff] [blame] | 49 | pr_warn("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 50 | return IRQ_NONE; |
| 51 | } |
| 52 | |
Henrik Kretzschmar | 6539641 | 2006-09-12 23:49:33 +0200 | [diff] [blame] | 53 | static int dma_setup(struct scsi_cmnd *cmd, int dir_in) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 54 | { |
Bart Van Assche | dbb2da5 | 2022-02-18 11:51:15 -0800 | [diff] [blame] | 55 | struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd); |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 56 | unsigned long len = scsi_pointer->this_residual; |
Geert Uytterhoeven | a8169e6 | 2009-05-17 13:35:07 +0200 | [diff] [blame] | 57 | struct Scsi_Host *instance = cmd->device->host; |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 58 | struct a3000_hostdata *hdata = shost_priv(instance); |
| 59 | struct WD33C93_hostdata *wh = &hdata->wh; |
| 60 | struct a3000_scsiregs *regs = hdata->regs; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 61 | unsigned short cntr = CNTR_PDMD | CNTR_INTEN; |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 62 | dma_addr_t addr; |
| 63 | |
| 64 | addr = dma_map_single(hdata->dev, scsi_pointer->ptr, |
| 65 | len, DMA_DIR(dir_in)); |
| 66 | if (dma_mapping_error(hdata->dev, addr)) { |
| 67 | dev_warn(hdata->dev, "cannot map SCSI data block %p\n", |
| 68 | scsi_pointer->ptr); |
| 69 | return 1; |
| 70 | } |
| 71 | scsi_pointer->dma_handle = addr; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 | |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 73 | /* |
| 74 | * if the physical address has the wrong alignment, or if |
| 75 | * physical address is bad, or if it is a write and at the |
| 76 | * end of a physical memory chunk, then allocate a bounce |
| 77 | * buffer |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 78 | * MSch 20220629 - only wrong alignment tested - bounce |
| 79 | * buffer returned by kmalloc is guaranteed to be aligned |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 80 | */ |
| 81 | if (addr & A3000_XFER_MASK) { |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 82 | WARN_ONCE(1, "Invalid alignment for DMA!"); |
| 83 | /* drop useless mapping */ |
| 84 | dma_unmap_single(hdata->dev, scsi_pointer->dma_handle, |
| 85 | scsi_pointer->this_residual, |
| 86 | DMA_DIR(dir_in)); |
| 87 | |
Bart Van Assche | dbb2da5 | 2022-02-18 11:51:15 -0800 | [diff] [blame] | 88 | wh->dma_bounce_len = (scsi_pointer->this_residual + 511) & ~0x1ff; |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 89 | wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len, |
| 90 | GFP_KERNEL); |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 91 | |
| 92 | /* can't allocate memory; use PIO */ |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 93 | if (!wh->dma_bounce_buffer) { |
| 94 | wh->dma_bounce_len = 0; |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 95 | scsi_pointer->dma_handle = (dma_addr_t) NULL; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 96 | return 1; |
| 97 | } |
| 98 | |
| 99 | if (!dir_in) { |
| 100 | /* copy to bounce buffer for a write */ |
Bart Van Assche | dbb2da5 | 2022-02-18 11:51:15 -0800 | [diff] [blame] | 101 | memcpy(wh->dma_bounce_buffer, scsi_pointer->ptr, |
| 102 | scsi_pointer->this_residual); |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 103 | } |
| 104 | |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 105 | addr = dma_map_single(hdata->dev, scsi_pointer->ptr, |
| 106 | len, DMA_DIR(dir_in)); |
| 107 | if (dma_mapping_error(hdata->dev, addr)) { |
| 108 | dev_warn(hdata->dev, |
| 109 | "cannot map SCSI data block %p\n", |
| 110 | scsi_pointer->ptr); |
| 111 | return 1; |
| 112 | } |
| 113 | scsi_pointer->dma_handle = addr; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 | } |
| 115 | |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 116 | /* setup dma direction */ |
| 117 | if (!dir_in) |
| 118 | cntr |= CNTR_DDIR; |
| 119 | |
| 120 | /* remember direction */ |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 121 | wh->dma_dir = dir_in; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 122 | |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 123 | regs->CNTR = cntr; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 124 | |
| 125 | /* setup DMA *physical* address */ |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 126 | regs->ACR = addr; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 127 | |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 128 | /* no more cache flush here - dma_map_single() takes care */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 130 | /* start DMA */ |
| 131 | mb(); /* make sure setup is completed */ |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 132 | regs->ST_DMA = 1; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 133 | mb(); /* make sure DMA has started before next IO */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 134 | |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 135 | /* return success */ |
| 136 | return 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 137 | } |
| 138 | |
Henrik Kretzschmar | 6539641 | 2006-09-12 23:49:33 +0200 | [diff] [blame] | 139 | static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, |
| 140 | int status) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 141 | { |
Bart Van Assche | dbb2da5 | 2022-02-18 11:51:15 -0800 | [diff] [blame] | 142 | struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(SCpnt); |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 143 | struct a3000_hostdata *hdata = shost_priv(instance); |
| 144 | struct WD33C93_hostdata *wh = &hdata->wh; |
| 145 | struct a3000_scsiregs *regs = hdata->regs; |
Geert Uytterhoeven | afdbbc1 | 2010-04-04 11:00:39 +0200 | [diff] [blame] | 146 | |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 147 | /* disable SCSI interrupts */ |
| 148 | unsigned short cntr = CNTR_PDMD; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 149 | |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 150 | if (!wh->dma_dir) |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 151 | cntr |= CNTR_DDIR; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 152 | |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 153 | regs->CNTR = cntr; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 154 | mb(); /* make sure CNTR is updated before next IO */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 155 | |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 156 | /* flush if we were reading */ |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 157 | if (wh->dma_dir) { |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 158 | regs->FLUSH = 1; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 159 | mb(); /* don't allow prefetch */ |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 160 | while (!(regs->ISTR & ISTR_FE_FLG)) |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 161 | barrier(); |
| 162 | mb(); /* no IO until FLUSH is done */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 163 | } |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 164 | |
| 165 | /* clear a possible interrupt */ |
| 166 | /* I think that this CINT is only necessary if you are |
| 167 | * using the terminal count features. HM 7 Mar 1994 |
| 168 | */ |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 169 | regs->CINT = 1; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 170 | |
| 171 | /* stop DMA */ |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 172 | regs->SP_DMA = 1; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 173 | mb(); /* make sure DMA is stopped before next IO */ |
| 174 | |
| 175 | /* restore the CONTROL bits (minus the direction flag) */ |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 176 | regs->CNTR = CNTR_PDMD | CNTR_INTEN; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 177 | mb(); /* make sure CNTR is updated before next IO */ |
| 178 | |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 179 | dma_unmap_single(hdata->dev, scsi_pointer->dma_handle, |
| 180 | scsi_pointer->this_residual, |
| 181 | DMA_DIR(wh->dma_dir)); |
| 182 | |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 183 | /* copy from a bounce buffer, if necessary */ |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 184 | if (status && wh->dma_bounce_buffer) { |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 185 | if (SCpnt) { |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 186 | if (wh->dma_dir && SCpnt) |
Bart Van Assche | dbb2da5 | 2022-02-18 11:51:15 -0800 | [diff] [blame] | 187 | memcpy(scsi_pointer->ptr, wh->dma_bounce_buffer, |
| 188 | scsi_pointer->this_residual); |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 189 | kfree(wh->dma_bounce_buffer); |
| 190 | wh->dma_bounce_buffer = NULL; |
| 191 | wh->dma_bounce_len = 0; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 192 | } else { |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 193 | kfree(wh->dma_bounce_buffer); |
| 194 | wh->dma_bounce_buffer = NULL; |
| 195 | wh->dma_bounce_len = 0; |
Geert Uytterhoeven | 2135101 | 2010-04-04 11:00:35 +0200 | [diff] [blame] | 196 | } |
| 197 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 198 | } |
| 199 | |
Bart Van Assche | 88530b3 | 2023-03-22 12:54:10 -0700 | [diff] [blame] | 200 | static const struct scsi_host_template amiga_a3000_scsi_template = { |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 201 | .module = THIS_MODULE, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 202 | .name = "Amiga 3000 built-in SCSI", |
Al Viro | 408bb25 | 2013-03-31 00:30:35 -0400 | [diff] [blame] | 203 | .show_info = wd33c93_show_info, |
| 204 | .write_info = wd33c93_write_info, |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 205 | .proc_name = "A3000", |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | .queuecommand = wd33c93_queuecommand, |
| 207 | .eh_abort_handler = wd33c93_abort, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 208 | .eh_host_reset_handler = wd33c93_host_reset, |
| 209 | .can_queue = CAN_QUEUE, |
| 210 | .this_id = 7, |
| 211 | .sg_tablesize = SG_ALL, |
| 212 | .cmd_per_lun = CMD_PER_LUN, |
Bart Van Assche | dbb2da5 | 2022-02-18 11:51:15 -0800 | [diff] [blame] | 213 | .cmd_size = sizeof(struct scsi_pointer), |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 214 | }; |
| 215 | |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 216 | static int __init amiga_a3000_scsi_probe(struct platform_device *pdev) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 217 | { |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 218 | struct resource *res; |
| 219 | struct Scsi_Host *instance; |
| 220 | int error; |
| 221 | struct a3000_scsiregs *regs; |
| 222 | wd33c93_regs wdregs; |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 223 | struct a3000_hostdata *hdata; |
Geert Uytterhoeven | d753722 | 2009-05-17 12:17:23 +0200 | [diff] [blame] | 224 | |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 225 | if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { |
| 226 | dev_warn(&pdev->dev, "cannot use 32 bit DMA\n"); |
| 227 | return -ENODEV; |
| 228 | } |
| 229 | |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 230 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 231 | if (!res) |
| 232 | return -ENODEV; |
| 233 | |
| 234 | if (!request_mem_region(res->start, resource_size(res), "wd33c93")) |
| 235 | return -EBUSY; |
| 236 | |
| 237 | instance = scsi_host_alloc(&amiga_a3000_scsi_template, |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 238 | sizeof(struct a3000_hostdata)); |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 239 | if (!instance) { |
| 240 | error = -ENOMEM; |
| 241 | goto fail_alloc; |
| 242 | } |
| 243 | |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 244 | instance->irq = IRQ_AMIGA_PORTS; |
| 245 | |
Geert Uytterhoeven | 6112ea0 | 2011-01-09 11:03:43 +0100 | [diff] [blame] | 246 | regs = ZTWO_VADDR(res->start); |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 247 | regs->DAWR = DAWR_A3000; |
| 248 | |
| 249 | wdregs.SASR = ®s->SASR; |
| 250 | wdregs.SCMD = ®s->SCMD; |
| 251 | |
| 252 | hdata = shost_priv(instance); |
Michael Schmitz | e214806 | 2022-06-30 15:33:00 +1200 | [diff] [blame] | 253 | hdata->dev = &pdev->dev; |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 254 | hdata->wh.no_sync = 0xff; |
| 255 | hdata->wh.fast = 0; |
| 256 | hdata->wh.dma_mode = CTRL_DMA; |
| 257 | hdata->regs = regs; |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 258 | |
| 259 | wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15); |
| 260 | error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, |
| 261 | "A3000 SCSI", instance); |
| 262 | if (error) |
| 263 | goto fail_irq; |
| 264 | |
| 265 | regs->CNTR = CNTR_PDMD | CNTR_INTEN; |
| 266 | |
| 267 | error = scsi_add_host(instance, NULL); |
| 268 | if (error) |
| 269 | goto fail_host; |
| 270 | |
| 271 | platform_set_drvdata(pdev, instance); |
| 272 | |
| 273 | scsi_scan_host(instance); |
| 274 | return 0; |
| 275 | |
| 276 | fail_host: |
| 277 | free_irq(IRQ_AMIGA_PORTS, instance); |
| 278 | fail_irq: |
| 279 | scsi_host_put(instance); |
| 280 | fail_alloc: |
| 281 | release_mem_region(res->start, resource_size(res)); |
| 282 | return error; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 283 | } |
| 284 | |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 285 | static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) |
| 286 | { |
| 287 | struct Scsi_Host *instance = platform_get_drvdata(pdev); |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 288 | struct a3000_hostdata *hdata = shost_priv(instance); |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 289 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 290 | |
Geert Uytterhoeven | 2b21d5e | 2010-04-12 21:55:15 +0200 | [diff] [blame] | 291 | hdata->regs->CNTR = 0; |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 292 | scsi_remove_host(instance); |
| 293 | free_irq(IRQ_AMIGA_PORTS, instance); |
| 294 | scsi_host_put(instance); |
| 295 | release_mem_region(res->start, resource_size(res)); |
| 296 | return 0; |
| 297 | } |
| 298 | |
| 299 | static struct platform_driver amiga_a3000_scsi_driver = { |
| 300 | .remove = __exit_p(amiga_a3000_scsi_remove), |
| 301 | .driver = { |
| 302 | .name = "amiga-a3000-scsi", |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 303 | }, |
| 304 | }; |
| 305 | |
Jingoo Han | a915b84 | 2013-05-02 15:30:31 +0900 | [diff] [blame] | 306 | module_platform_driver_probe(amiga_a3000_scsi_driver, amiga_a3000_scsi_probe); |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 307 | |
| 308 | MODULE_DESCRIPTION("Amiga 3000 built-in SCSI"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 309 | MODULE_LICENSE("GPL"); |
Geert Uytterhoeven | c2a24a4 | 2009-04-05 13:02:45 +0200 | [diff] [blame] | 310 | MODULE_ALIAS("platform:amiga-a3000-scsi"); |