1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/types.h> 3 #include <linux/init.h> 4 #include <linux/interrupt.h> 5 #include <linux/mm.h> 6 #include <linux/slab.h> 7 #include <linux/spinlock.h> 8 #include <linux/zorro.h> 9 #include <linux/module.h> 10 11 #include <asm/page.h> 12 #include <asm/amigaints.h> 13 #include <asm/amigahw.h> 14 15 #include <scsi/scsi.h> 16 #include <scsi/scsi_cmnd.h> 17 #include <scsi/scsi_device.h> 18 #include <scsi/scsi_eh.h> 19 #include <scsi/scsi_tcq.h> 20 #include "wd33c93.h" 21 #include "a2091.h" 22 23 24 struct a2091_hostdata { 25 struct WD33C93_hostdata wh; 26 struct a2091_scsiregs *regs; 27 struct device *dev; 28 }; 29 30 #define DMA_DIR(d) ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE) 31 32 static irqreturn_t a2091_intr(int irq, void *data) 33 { 34 struct Scsi_Host *instance = data; 35 struct a2091_hostdata *hdata = shost_priv(instance); 36 unsigned int status = hdata->regs->ISTR; 37 unsigned long flags; 38 39 if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS)) 40 return IRQ_NONE; 41 42 spin_lock_irqsave(instance->host_lock, flags); 43 wd33c93_intr(instance); 44 spin_unlock_irqrestore(instance->host_lock, flags); 45 return IRQ_HANDLED; 46 } 47 48 static int dma_setup(struct scsi_cmnd *cmd, int dir_in) 49 { 50 struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd); 51 unsigned long len = scsi_pointer->this_residual; 52 struct Scsi_Host *instance = cmd->device->host; 53 struct a2091_hostdata *hdata = shost_priv(instance); 54 struct WD33C93_hostdata *wh = &hdata->wh; 55 struct a2091_scsiregs *regs = hdata->regs; 56 unsigned short cntr = CNTR_PDMD | CNTR_INTEN; 57 dma_addr_t addr; 58 59 addr = dma_map_single(hdata->dev, scsi_pointer->ptr, 60 len, DMA_DIR(dir_in)); 61 if (dma_mapping_error(hdata->dev, addr)) { 62 dev_warn(hdata->dev, "cannot map SCSI data block %p\n", 63 scsi_pointer->ptr); 64 return 1; 65 } 66 scsi_pointer->dma_handle = addr; 67 68 /* don't allow DMA if the physical address is bad */ 69 if (addr & A2091_XFER_MASK) { 70 /* drop useless mapping */ 71 dma_unmap_single(hdata->dev, scsi_pointer->dma_handle, 72 scsi_pointer->this_residual, 73 DMA_DIR(dir_in)); 74 scsi_pointer->dma_handle = (dma_addr_t) NULL; 75 76 wh->dma_bounce_len = (scsi_pointer->this_residual + 511) & ~0x1ff; 77 wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len, 78 GFP_KERNEL); 79 80 /* can't allocate memory; use PIO */ 81 if (!wh->dma_bounce_buffer) { 82 wh->dma_bounce_len = 0; 83 return 1; 84 } 85 86 if (!dir_in) { 87 /* copy to bounce buffer for a write */ 88 memcpy(wh->dma_bounce_buffer, scsi_pointer->ptr, 89 scsi_pointer->this_residual); 90 } 91 92 /* will flush/invalidate cache for us */ 93 addr = dma_map_single(hdata->dev, wh->dma_bounce_buffer, 94 wh->dma_bounce_len, DMA_DIR(dir_in)); 95 /* can't map buffer; use PIO */ 96 if (dma_mapping_error(hdata->dev, addr)) { 97 dev_warn(hdata->dev, "cannot map bounce buffer %p\n", 98 wh->dma_bounce_buffer); 99 return 1; 100 } 101 102 /* the bounce buffer may not be in the first 16M of physmem */ 103 if (addr & A2091_XFER_MASK) { 104 /* we could use chipmem... maybe later */ 105 kfree(wh->dma_bounce_buffer); 106 wh->dma_bounce_buffer = NULL; 107 wh->dma_bounce_len = 0; 108 return 1; 109 } 110 111 scsi_pointer->dma_handle = addr; 112 } 113 114 /* setup dma direction */ 115 if (!dir_in) 116 cntr |= CNTR_DDIR; 117 118 /* remember direction */ 119 wh->dma_dir = dir_in; 120 121 regs->CNTR = cntr; 122 123 /* setup DMA *physical* address */ 124 regs->ACR = addr; 125 126 /* no more cache flush here - dma_map_single() takes care */ 127 128 /* start DMA */ 129 regs->ST_DMA = 1; 130 131 /* return success */ 132 return 0; 133 } 134 135 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, 136 int status) 137 { 138 struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(SCpnt); 139 struct a2091_hostdata *hdata = shost_priv(instance); 140 struct WD33C93_hostdata *wh = &hdata->wh; 141 struct a2091_scsiregs *regs = hdata->regs; 142 143 /* disable SCSI interrupts */ 144 unsigned short cntr = CNTR_PDMD; 145 146 if (!wh->dma_dir) 147 cntr |= CNTR_DDIR; 148 149 /* disable SCSI interrupts */ 150 regs->CNTR = cntr; 151 152 /* flush if we were reading */ 153 if (wh->dma_dir) { 154 regs->FLUSH = 1; 155 while (!(regs->ISTR & ISTR_FE_FLG)) 156 ; 157 } 158 159 /* clear a possible interrupt */ 160 regs->CINT = 1; 161 162 /* stop DMA */ 163 regs->SP_DMA = 1; 164 165 /* restore the CONTROL bits (minus the direction flag) */ 166 regs->CNTR = CNTR_PDMD | CNTR_INTEN; 167 168 dma_unmap_single(hdata->dev, scsi_pointer->dma_handle, 169 scsi_pointer->this_residual, 170 DMA_DIR(wh->dma_dir)); 171 172 /* copy from a bounce buffer, if necessary */ 173 if (status && wh->dma_bounce_buffer) { 174 if (wh->dma_dir) 175 memcpy(scsi_pointer->ptr, wh->dma_bounce_buffer, 176 scsi_pointer->this_residual); 177 kfree(wh->dma_bounce_buffer); 178 wh->dma_bounce_buffer = NULL; 179 wh->dma_bounce_len = 0; 180 } 181 } 182 183 static const struct scsi_host_template a2091_scsi_template = { 184 .module = THIS_MODULE, 185 .name = "Commodore A2091/A590 SCSI", 186 .show_info = wd33c93_show_info, 187 .write_info = wd33c93_write_info, 188 .proc_name = "A2901", 189 .queuecommand = wd33c93_queuecommand, 190 .eh_abort_handler = wd33c93_abort, 191 .eh_host_reset_handler = wd33c93_host_reset, 192 .can_queue = CAN_QUEUE, 193 .this_id = 7, 194 .sg_tablesize = SG_ALL, 195 .cmd_per_lun = CMD_PER_LUN, 196 .dma_boundary = PAGE_SIZE - 1, 197 .cmd_size = sizeof(struct scsi_pointer), 198 }; 199 200 static int a2091_probe(struct zorro_dev *z, const struct zorro_device_id *ent) 201 { 202 struct Scsi_Host *instance; 203 int error; 204 struct a2091_scsiregs *regs; 205 wd33c93_regs wdregs; 206 struct a2091_hostdata *hdata; 207 208 if (dma_set_mask_and_coherent(&z->dev, DMA_BIT_MASK(24))) { 209 dev_warn(&z->dev, "cannot use 24 bit DMA\n"); 210 return -ENODEV; 211 } 212 213 if (!request_mem_region(z->resource.start, 256, "wd33c93")) 214 return -EBUSY; 215 216 instance = scsi_host_alloc(&a2091_scsi_template, 217 sizeof(struct a2091_hostdata)); 218 if (!instance) { 219 error = -ENOMEM; 220 goto fail_alloc; 221 } 222 223 instance->irq = IRQ_AMIGA_PORTS; 224 instance->unique_id = z->slotaddr; 225 226 regs = ZTWO_VADDR(z->resource.start); 227 regs->DAWR = DAWR_A2091; 228 229 wdregs.SASR = ®s->SASR; 230 wdregs.SCMD = ®s->SCMD; 231 232 hdata = shost_priv(instance); 233 hdata->dev = &z->dev; 234 hdata->wh.no_sync = 0xff; 235 hdata->wh.fast = 0; 236 hdata->wh.dma_mode = CTRL_DMA; 237 hdata->regs = regs; 238 239 wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_8_10); 240 error = request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, 241 "A2091 SCSI", instance); 242 if (error) 243 goto fail_irq; 244 245 regs->CNTR = CNTR_PDMD | CNTR_INTEN; 246 247 error = scsi_add_host(instance, NULL); 248 if (error) 249 goto fail_host; 250 251 zorro_set_drvdata(z, instance); 252 253 scsi_scan_host(instance); 254 return 0; 255 256 fail_host: 257 free_irq(IRQ_AMIGA_PORTS, instance); 258 fail_irq: 259 scsi_host_put(instance); 260 fail_alloc: 261 release_mem_region(z->resource.start, 256); 262 return error; 263 } 264 265 static void a2091_remove(struct zorro_dev *z) 266 { 267 struct Scsi_Host *instance = zorro_get_drvdata(z); 268 struct a2091_hostdata *hdata = shost_priv(instance); 269 270 hdata->regs->CNTR = 0; 271 scsi_remove_host(instance); 272 free_irq(IRQ_AMIGA_PORTS, instance); 273 scsi_host_put(instance); 274 release_mem_region(z->resource.start, 256); 275 } 276 277 static struct zorro_device_id a2091_zorro_tbl[] = { 278 { ZORRO_PROD_CBM_A590_A2091_1 }, 279 { ZORRO_PROD_CBM_A590_A2091_2 }, 280 { 0 } 281 }; 282 MODULE_DEVICE_TABLE(zorro, a2091_zorro_tbl); 283 284 static struct zorro_driver a2091_driver = { 285 .name = "a2091", 286 .id_table = a2091_zorro_tbl, 287 .probe = a2091_probe, 288 .remove = a2091_remove, 289 }; 290 291 static int __init a2091_init(void) 292 { 293 return zorro_register_driver(&a2091_driver); 294 } 295 module_init(a2091_init); 296 297 static void __exit a2091_exit(void) 298 { 299 zorro_unregister_driver(&a2091_driver); 300 } 301 module_exit(a2091_exit); 302 303 MODULE_DESCRIPTION("Commodore A2091/A590 SCSI"); 304 MODULE_LICENSE("GPL"); 305