1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/drivers/scsi/arm/arxescsi.c 4 * 5 * Copyright (C) 1997-2000 Russell King, Stefan Hanske 6 * 7 * This driver is based on experimentation. Hence, it may have made 8 * assumptions about the particular card that I have available, and 9 * may not be reliable! 10 * 11 * Changelog: 12 * 30-08-1997 RMK 0.0.0 Created, READONLY version as cumana_2.c 13 * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 14 * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. 15 * 11-06-1998 SH 0.0.2 Changed to support ARXE 16-bit SCSI card 16 * enabled writing 17 * 01-01-2000 SH 0.1.0 Added *real* pseudo dma writing 18 * (arxescsi_pseudo_dma_write) 19 * 02-04-2000 RMK 0.1.1 Updated for new error handling code. 20 * 22-10-2000 SH Updated for new registering scheme. 21 */ 22 #include <linux/module.h> 23 #include <linux/blkdev.h> 24 #include <linux/kernel.h> 25 #include <linux/string.h> 26 #include <linux/ioport.h> 27 #include <linux/proc_fs.h> 28 #include <linux/unistd.h> 29 #include <linux/stat.h> 30 #include <linux/delay.h> 31 #include <linux/init.h> 32 #include <linux/interrupt.h> 33 34 #include <asm/dma.h> 35 #include <asm/io.h> 36 #include <asm/ecard.h> 37 38 #include "../scsi.h" 39 #include <scsi/scsi_host.h> 40 #include "fas216.h" 41 42 struct arxescsi_info { 43 FAS216_Info info; 44 struct expansion_card *ec; 45 void __iomem *base; 46 }; 47 48 #define DMADATA_OFFSET (0x200) 49 50 #define DMASTAT_OFFSET (0x600) 51 #define DMASTAT_DRQ (1 << 0) 52 53 #define CSTATUS_IRQ (1 << 0) 54 55 #define VERSION "1.10 (23/01/2003 2.5.57)" 56 57 /* 58 * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type) 59 * Purpose : initialises DMA/PIO 60 * Params : host - host 61 * SCpnt - command 62 * direction - DMA on to/off of card 63 * min_type - minimum DMA support that we must have for this transfer 64 * Returns : 0 if we should not set CMD_WITHDMA for transfer info command 65 */ 66 static fasdmatype_t 67 arxescsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp, 68 fasdmadir_t direction, fasdmatype_t min_type) 69 { 70 /* 71 * We don't do real DMA 72 */ 73 return fasdma_pseudo; 74 } 75 76 static void arxescsi_pseudo_dma_write(unsigned char *addr, void __iomem *base) 77 { 78 __asm__ __volatile__( 79 " stmdb sp!, {r0-r12}\n" 80 " mov r3, %0\n" 81 " mov r1, %1\n" 82 " add r2, r1, #512\n" 83 " mov r4, #256\n" 84 ".loop_1: ldmia r3!, {r6, r8, r10, r12}\n" 85 " mov r5, r6, lsl #16\n" 86 " mov r7, r8, lsl #16\n" 87 ".loop_2: ldrb r0, [r1, #1536]\n" 88 " tst r0, #1\n" 89 " beq .loop_2\n" 90 " stmia r2, {r5-r8}\n\t" 91 " mov r9, r10, lsl #16\n" 92 " mov r11, r12, lsl #16\n" 93 ".loop_3: ldrb r0, [r1, #1536]\n" 94 " tst r0, #1\n" 95 " beq .loop_3\n" 96 " stmia r2, {r9-r12}\n" 97 " subs r4, r4, #16\n" 98 " bne .loop_1\n" 99 " ldmia sp!, {r0-r12}\n" 100 : 101 : "r" (addr), "r" (base)); 102 } 103 104 /* 105 * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer) 106 * Purpose : handles pseudo DMA 107 * Params : host - host 108 * SCpnt - command 109 * direction - DMA on to/off of card 110 * transfer - minimum number of bytes we expect to transfer 111 */ 112 static void 113 arxescsi_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp, 114 fasdmadir_t direction, int transfer) 115 { 116 struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata; 117 unsigned int length, error = 0; 118 void __iomem *base = info->info.scsi.io_base; 119 unsigned char *addr; 120 121 length = SCp->this_residual; 122 addr = SCp->ptr; 123 124 if (direction == DMA_OUT) { 125 unsigned int word; 126 while (length > 256) { 127 if (readb(base + 0x80) & STAT_INT) { 128 error = 1; 129 break; 130 } 131 arxescsi_pseudo_dma_write(addr, base); 132 addr += 256; 133 length -= 256; 134 } 135 136 if (!error) 137 while (length > 0) { 138 if (readb(base + 0x80) & STAT_INT) 139 break; 140 141 if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ)) 142 continue; 143 144 word = *addr | *(addr + 1) << 8; 145 146 writew(word, base + DMADATA_OFFSET); 147 if (length > 1) { 148 addr += 2; 149 length -= 2; 150 } else { 151 addr += 1; 152 length -= 1; 153 } 154 } 155 } 156 else { 157 if (transfer && (transfer & 255)) { 158 while (length >= 256) { 159 if (readb(base + 0x80) & STAT_INT) { 160 error = 1; 161 break; 162 } 163 164 if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ)) 165 continue; 166 167 readsw(base + DMADATA_OFFSET, addr, 256 >> 1); 168 addr += 256; 169 length -= 256; 170 } 171 } 172 173 if (!(error)) 174 while (length > 0) { 175 unsigned long word; 176 177 if (readb(base + 0x80) & STAT_INT) 178 break; 179 180 if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ)) 181 continue; 182 183 word = readw(base + DMADATA_OFFSET); 184 *addr++ = word; 185 if (--length > 0) { 186 *addr++ = word >> 8; 187 length --; 188 } 189 } 190 } 191 } 192 193 /* 194 * Function: int arxescsi_dma_stop(host, SCpnt) 195 * Purpose : stops DMA/PIO 196 * Params : host - host 197 * SCpnt - command 198 */ 199 static void arxescsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp) 200 { 201 /* 202 * no DMA to stop 203 */ 204 } 205 206 /* 207 * Function: const char *arxescsi_info(struct Scsi_Host * host) 208 * Purpose : returns a descriptive string about this interface, 209 * Params : host - driver host structure to return info for. 210 * Returns : pointer to a static buffer containing null terminated string. 211 */ 212 static const char *arxescsi_info(struct Scsi_Host *host) 213 { 214 struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata; 215 static char string[150]; 216 217 sprintf(string, "%s (%s) in slot %d v%s", 218 host->hostt->name, info->info.scsi.type, info->ec->slot_no, 219 VERSION); 220 221 return string; 222 } 223 224 static int 225 arxescsi_show_info(struct seq_file *m, struct Scsi_Host *host) 226 { 227 struct arxescsi_info *info; 228 info = (struct arxescsi_info *)host->hostdata; 229 230 seq_printf(m, "ARXE 16-bit SCSI driver v%s\n", VERSION); 231 fas216_print_host(&info->info, m); 232 fas216_print_stats(&info->info, m); 233 fas216_print_devices(&info->info, m); 234 return 0; 235 } 236 237 static struct scsi_host_template arxescsi_template = { 238 .show_info = arxescsi_show_info, 239 .name = "ARXE SCSI card", 240 .info = arxescsi_info, 241 .queuecommand = fas216_noqueue_command, 242 .eh_host_reset_handler = fas216_eh_host_reset, 243 .eh_bus_reset_handler = fas216_eh_bus_reset, 244 .eh_device_reset_handler = fas216_eh_device_reset, 245 .eh_abort_handler = fas216_eh_abort, 246 .cmd_size = sizeof(struct fas216_cmd_priv), 247 .can_queue = 0, 248 .this_id = 7, 249 .sg_tablesize = SG_ALL, 250 .dma_boundary = PAGE_SIZE - 1, 251 .proc_name = "arxescsi", 252 }; 253 254 static int arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id) 255 { 256 struct Scsi_Host *host; 257 struct arxescsi_info *info; 258 void __iomem *base; 259 int ret; 260 261 ret = ecard_request_resources(ec); 262 if (ret) 263 goto out; 264 265 base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); 266 if (!base) { 267 ret = -ENOMEM; 268 goto out_region; 269 } 270 271 host = scsi_host_alloc(&arxescsi_template, sizeof(struct arxescsi_info)); 272 if (!host) { 273 ret = -ENOMEM; 274 goto out_region; 275 } 276 277 info = (struct arxescsi_info *)host->hostdata; 278 info->ec = ec; 279 info->base = base; 280 281 info->info.scsi.io_base = base + 0x2000; 282 info->info.scsi.irq = 0; 283 info->info.scsi.dma = NO_DMA; 284 info->info.scsi.io_shift = 5; 285 info->info.ifcfg.clockrate = 24; /* MHz */ 286 info->info.ifcfg.select_timeout = 255; 287 info->info.ifcfg.asyncperiod = 200; /* ns */ 288 info->info.ifcfg.sync_max_depth = 0; 289 info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK; 290 info->info.ifcfg.disconnect_ok = 0; 291 info->info.ifcfg.wide_max_size = 0; 292 info->info.ifcfg.capabilities = FASCAP_PSEUDODMA; 293 info->info.dma.setup = arxescsi_dma_setup; 294 info->info.dma.pseudo = arxescsi_dma_pseudo; 295 info->info.dma.stop = arxescsi_dma_stop; 296 297 ec->irqaddr = base; 298 ec->irqmask = CSTATUS_IRQ; 299 300 ret = fas216_init(host); 301 if (ret) 302 goto out_unregister; 303 304 ret = fas216_add(host, &ec->dev); 305 if (ret == 0) 306 goto out; 307 308 fas216_release(host); 309 out_unregister: 310 scsi_host_put(host); 311 out_region: 312 ecard_release_resources(ec); 313 out: 314 return ret; 315 } 316 317 static void arxescsi_remove(struct expansion_card *ec) 318 { 319 struct Scsi_Host *host = ecard_get_drvdata(ec); 320 321 ecard_set_drvdata(ec, NULL); 322 fas216_remove(host); 323 324 fas216_release(host); 325 scsi_host_put(host); 326 ecard_release_resources(ec); 327 } 328 329 static const struct ecard_id arxescsi_cids[] = { 330 { MANU_ARXE, PROD_ARXE_SCSI }, 331 { 0xffff, 0xffff }, 332 }; 333 334 static struct ecard_driver arxescsi_driver = { 335 .probe = arxescsi_probe, 336 .remove = arxescsi_remove, 337 .id_table = arxescsi_cids, 338 .drv = { 339 .name = "arxescsi", 340 }, 341 }; 342 343 static int __init init_arxe_scsi_driver(void) 344 { 345 return ecard_register_driver(&arxescsi_driver); 346 } 347 348 static void __exit exit_arxe_scsi_driver(void) 349 { 350 ecard_remove_driver(&arxescsi_driver); 351 } 352 353 module_init(init_arxe_scsi_driver); 354 module_exit(exit_arxe_scsi_driver); 355 356 MODULE_AUTHOR("Stefan Hanske"); 357 MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines"); 358 MODULE_LICENSE("GPL"); 359 360