1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/types.h> 3 #include <linux/mm.h> 4 #include <linux/ioport.h> 5 #include <linux/init.h> 6 #include <linux/slab.h> 7 #include <linux/spinlock.h> 8 #include <linux/interrupt.h> 9 #include <linux/platform_device.h> 10 #include <linux/module.h> 11 12 #include <asm/page.h> 13 #include <asm/pgtable.h> 14 #include <asm/amigaints.h> 15 #include <asm/amigahw.h> 16 17 #include "scsi.h" 18 #include "wd33c93.h" 19 #include "a3000.h" 20 21 22 struct a3000_hostdata { 23 struct WD33C93_hostdata wh; 24 struct a3000_scsiregs *regs; 25 }; 26 27 static irqreturn_t a3000_intr(int irq, void *data) 28 { 29 struct Scsi_Host *instance = data; 30 struct a3000_hostdata *hdata = shost_priv(instance); 31 unsigned int status = hdata->regs->ISTR; 32 unsigned long flags; 33 34 if (!(status & ISTR_INT_P)) 35 return IRQ_NONE; 36 if (status & ISTR_INTS) { 37 spin_lock_irqsave(instance->host_lock, flags); 38 wd33c93_intr(instance); 39 spin_unlock_irqrestore(instance->host_lock, flags); 40 return IRQ_HANDLED; 41 } 42 pr_warn("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status); 43 return IRQ_NONE; 44 } 45 46 static int dma_setup(struct scsi_cmnd *cmd, int dir_in) 47 { 48 struct Scsi_Host *instance = cmd->device->host; 49 struct a3000_hostdata *hdata = shost_priv(instance); 50 struct WD33C93_hostdata *wh = &hdata->wh; 51 struct a3000_scsiregs *regs = hdata->regs; 52 unsigned short cntr = CNTR_PDMD | CNTR_INTEN; 53 unsigned long addr = virt_to_bus(cmd->SCp.ptr); 54 55 /* 56 * if the physical address has the wrong alignment, or if 57 * physical address is bad, or if it is a write and at the 58 * end of a physical memory chunk, then allocate a bounce 59 * buffer 60 */ 61 if (addr & A3000_XFER_MASK) { 62 wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; 63 wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len, 64 GFP_KERNEL); 65 66 /* can't allocate memory; use PIO */ 67 if (!wh->dma_bounce_buffer) { 68 wh->dma_bounce_len = 0; 69 return 1; 70 } 71 72 if (!dir_in) { 73 /* copy to bounce buffer for a write */ 74 memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr, 75 cmd->SCp.this_residual); 76 } 77 78 addr = virt_to_bus(wh->dma_bounce_buffer); 79 } 80 81 /* setup dma direction */ 82 if (!dir_in) 83 cntr |= CNTR_DDIR; 84 85 /* remember direction */ 86 wh->dma_dir = dir_in; 87 88 regs->CNTR = cntr; 89 90 /* setup DMA *physical* address */ 91 regs->ACR = addr; 92 93 if (dir_in) { 94 /* invalidate any cache */ 95 cache_clear(addr, cmd->SCp.this_residual); 96 } else { 97 /* push any dirty cache */ 98 cache_push(addr, cmd->SCp.this_residual); 99 } 100 101 /* start DMA */ 102 mb(); /* make sure setup is completed */ 103 regs->ST_DMA = 1; 104 mb(); /* make sure DMA has started before next IO */ 105 106 /* return success */ 107 return 0; 108 } 109 110 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, 111 int status) 112 { 113 struct a3000_hostdata *hdata = shost_priv(instance); 114 struct WD33C93_hostdata *wh = &hdata->wh; 115 struct a3000_scsiregs *regs = hdata->regs; 116 117 /* disable SCSI interrupts */ 118 unsigned short cntr = CNTR_PDMD; 119 120 if (!wh->dma_dir) 121 cntr |= CNTR_DDIR; 122 123 regs->CNTR = cntr; 124 mb(); /* make sure CNTR is updated before next IO */ 125 126 /* flush if we were reading */ 127 if (wh->dma_dir) { 128 regs->FLUSH = 1; 129 mb(); /* don't allow prefetch */ 130 while (!(regs->ISTR & ISTR_FE_FLG)) 131 barrier(); 132 mb(); /* no IO until FLUSH is done */ 133 } 134 135 /* clear a possible interrupt */ 136 /* I think that this CINT is only necessary if you are 137 * using the terminal count features. HM 7 Mar 1994 138 */ 139 regs->CINT = 1; 140 141 /* stop DMA */ 142 regs->SP_DMA = 1; 143 mb(); /* make sure DMA is stopped before next IO */ 144 145 /* restore the CONTROL bits (minus the direction flag) */ 146 regs->CNTR = CNTR_PDMD | CNTR_INTEN; 147 mb(); /* make sure CNTR is updated before next IO */ 148 149 /* copy from a bounce buffer, if necessary */ 150 if (status && wh->dma_bounce_buffer) { 151 if (SCpnt) { 152 if (wh->dma_dir && SCpnt) 153 memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer, 154 SCpnt->SCp.this_residual); 155 kfree(wh->dma_bounce_buffer); 156 wh->dma_bounce_buffer = NULL; 157 wh->dma_bounce_len = 0; 158 } else { 159 kfree(wh->dma_bounce_buffer); 160 wh->dma_bounce_buffer = NULL; 161 wh->dma_bounce_len = 0; 162 } 163 } 164 } 165 166 static struct scsi_host_template amiga_a3000_scsi_template = { 167 .module = THIS_MODULE, 168 .name = "Amiga 3000 built-in SCSI", 169 .show_info = wd33c93_show_info, 170 .write_info = wd33c93_write_info, 171 .proc_name = "A3000", 172 .queuecommand = wd33c93_queuecommand, 173 .eh_abort_handler = wd33c93_abort, 174 .eh_host_reset_handler = wd33c93_host_reset, 175 .can_queue = CAN_QUEUE, 176 .this_id = 7, 177 .sg_tablesize = SG_ALL, 178 .cmd_per_lun = CMD_PER_LUN, 179 }; 180 181 static int __init amiga_a3000_scsi_probe(struct platform_device *pdev) 182 { 183 struct resource *res; 184 struct Scsi_Host *instance; 185 int error; 186 struct a3000_scsiregs *regs; 187 wd33c93_regs wdregs; 188 struct a3000_hostdata *hdata; 189 190 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 191 if (!res) 192 return -ENODEV; 193 194 if (!request_mem_region(res->start, resource_size(res), "wd33c93")) 195 return -EBUSY; 196 197 instance = scsi_host_alloc(&amiga_a3000_scsi_template, 198 sizeof(struct a3000_hostdata)); 199 if (!instance) { 200 error = -ENOMEM; 201 goto fail_alloc; 202 } 203 204 instance->irq = IRQ_AMIGA_PORTS; 205 206 regs = ZTWO_VADDR(res->start); 207 regs->DAWR = DAWR_A3000; 208 209 wdregs.SASR = ®s->SASR; 210 wdregs.SCMD = ®s->SCMD; 211 212 hdata = shost_priv(instance); 213 hdata->wh.no_sync = 0xff; 214 hdata->wh.fast = 0; 215 hdata->wh.dma_mode = CTRL_DMA; 216 hdata->regs = regs; 217 218 wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15); 219 error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, 220 "A3000 SCSI", instance); 221 if (error) 222 goto fail_irq; 223 224 regs->CNTR = CNTR_PDMD | CNTR_INTEN; 225 226 error = scsi_add_host(instance, NULL); 227 if (error) 228 goto fail_host; 229 230 platform_set_drvdata(pdev, instance); 231 232 scsi_scan_host(instance); 233 return 0; 234 235 fail_host: 236 free_irq(IRQ_AMIGA_PORTS, instance); 237 fail_irq: 238 scsi_host_put(instance); 239 fail_alloc: 240 release_mem_region(res->start, resource_size(res)); 241 return error; 242 } 243 244 static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) 245 { 246 struct Scsi_Host *instance = platform_get_drvdata(pdev); 247 struct a3000_hostdata *hdata = shost_priv(instance); 248 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 249 250 hdata->regs->CNTR = 0; 251 scsi_remove_host(instance); 252 free_irq(IRQ_AMIGA_PORTS, instance); 253 scsi_host_put(instance); 254 release_mem_region(res->start, resource_size(res)); 255 return 0; 256 } 257 258 static struct platform_driver amiga_a3000_scsi_driver = { 259 .remove = __exit_p(amiga_a3000_scsi_remove), 260 .driver = { 261 .name = "amiga-a3000-scsi", 262 }, 263 }; 264 265 module_platform_driver_probe(amiga_a3000_scsi_driver, amiga_a3000_scsi_probe); 266 267 MODULE_DESCRIPTION("Amiga 3000 built-in SCSI"); 268 MODULE_LICENSE("GPL"); 269 MODULE_ALIAS("platform:amiga-a3000-scsi"); 270