1 /* 2 * linux/arch/arm/drivers/scsi/arxescsi.c 3 * 4 * Copyright (C) 1997-2000 Russell King, Stefan Hanske 5 * 6 * This driver is based on experimentation. Hence, it may have made 7 * assumptions about the particular card that I have available, and 8 * may not be reliable! 9 * 10 * Changelog: 11 * 30-08-1997 RMK 0.0.0 Created, READONLY version as cumana_2.c 12 * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 13 * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. 14 * 11-06-1998 SH 0.0.2 Changed to support ARXE 16-bit SCSI card 15 * enabled writing 16 * 01-01-2000 SH 0.1.0 Added *real* pseudo dma writing 17 * (arxescsi_pseudo_dma_write) 18 * 02-04-2000 RMK 0.1.1 Updated for new error handling code. 19 * 22-10-2000 SH Updated for new registering scheme. 20 */ 21 #include <linux/module.h> 22 #include <linux/blkdev.h> 23 #include <linux/kernel.h> 24 #include <linux/string.h> 25 #include <linux/ioport.h> 26 #include <linux/sched.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 /* 225 * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset, 226 * int length, int host_no, int inout) 227 * Purpose : Return information about the driver to a user process accessing 228 * the /proc filesystem. 229 * Params : buffer - a buffer to write information to 230 * start - a pointer into this buffer set by this routine to the start 231 * of the required information. 232 * offset - offset into information that we have read upto. 233 * length - length of buffer 234 * host_no - host number to return information for 235 * inout - 0 for reading, 1 for writing. 236 * Returns : length of data written to buffer. 237 */ 238 static int 239 arxescsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, 240 int inout) 241 { 242 struct arxescsi_info *info; 243 char *p = buffer; 244 int pos; 245 246 info = (struct arxescsi_info *)host->hostdata; 247 if (inout == 1) 248 return -EINVAL; 249 250 p += sprintf(p, "ARXE 16-bit SCSI driver v%s\n", VERSION); 251 p += fas216_print_host(&info->info, p); 252 p += fas216_print_stats(&info->info, p); 253 p += fas216_print_devices(&info->info, p); 254 255 *start = buffer + offset; 256 pos = p - buffer - offset; 257 if (pos > length) 258 pos = length; 259 260 return pos; 261 } 262 263 static struct scsi_host_template arxescsi_template = { 264 .proc_info = arxescsi_proc_info, 265 .name = "ARXE SCSI card", 266 .info = arxescsi_info, 267 .queuecommand = fas216_noqueue_command, 268 .eh_host_reset_handler = fas216_eh_host_reset, 269 .eh_bus_reset_handler = fas216_eh_bus_reset, 270 .eh_device_reset_handler = fas216_eh_device_reset, 271 .eh_abort_handler = fas216_eh_abort, 272 .can_queue = 0, 273 .this_id = 7, 274 .sg_tablesize = SG_ALL, 275 .cmd_per_lun = 1, 276 .use_clustering = DISABLE_CLUSTERING, 277 .proc_name = "arxescsi", 278 }; 279 280 static int __devinit 281 arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id) 282 { 283 struct Scsi_Host *host; 284 struct arxescsi_info *info; 285 unsigned long resbase, reslen; 286 void __iomem *base; 287 int ret; 288 289 ret = ecard_request_resources(ec); 290 if (ret) 291 goto out; 292 293 resbase = ecard_resource_start(ec, ECARD_RES_MEMC); 294 reslen = ecard_resource_len(ec, ECARD_RES_MEMC); 295 base = ioremap(resbase, reslen); 296 if (!base) { 297 ret = -ENOMEM; 298 goto out_region; 299 } 300 301 host = scsi_host_alloc(&arxescsi_template, sizeof(struct arxescsi_info)); 302 if (!host) { 303 ret = -ENOMEM; 304 goto out_unmap; 305 } 306 307 info = (struct arxescsi_info *)host->hostdata; 308 info->ec = ec; 309 info->base = base; 310 311 info->info.scsi.io_base = base + 0x2000; 312 info->info.scsi.irq = NO_IRQ; 313 info->info.scsi.dma = NO_DMA; 314 info->info.scsi.io_shift = 5; 315 info->info.ifcfg.clockrate = 24; /* MHz */ 316 info->info.ifcfg.select_timeout = 255; 317 info->info.ifcfg.asyncperiod = 200; /* ns */ 318 info->info.ifcfg.sync_max_depth = 0; 319 info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK; 320 info->info.ifcfg.disconnect_ok = 0; 321 info->info.ifcfg.wide_max_size = 0; 322 info->info.ifcfg.capabilities = FASCAP_PSEUDODMA; 323 info->info.dma.setup = arxescsi_dma_setup; 324 info->info.dma.pseudo = arxescsi_dma_pseudo; 325 info->info.dma.stop = arxescsi_dma_stop; 326 327 ec->irqaddr = base; 328 ec->irqmask = CSTATUS_IRQ; 329 330 ret = fas216_init(host); 331 if (ret) 332 goto out_unregister; 333 334 ret = fas216_add(host, &ec->dev); 335 if (ret == 0) 336 goto out; 337 338 fas216_release(host); 339 out_unregister: 340 scsi_host_put(host); 341 out_unmap: 342 iounmap(base); 343 out_region: 344 ecard_release_resources(ec); 345 out: 346 return ret; 347 } 348 349 static void __devexit arxescsi_remove(struct expansion_card *ec) 350 { 351 struct Scsi_Host *host = ecard_get_drvdata(ec); 352 struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata; 353 354 ecard_set_drvdata(ec, NULL); 355 fas216_remove(host); 356 357 iounmap(info->base); 358 359 fas216_release(host); 360 scsi_host_put(host); 361 ecard_release_resources(ec); 362 } 363 364 static const struct ecard_id arxescsi_cids[] = { 365 { MANU_ARXE, PROD_ARXE_SCSI }, 366 { 0xffff, 0xffff }, 367 }; 368 369 static struct ecard_driver arxescsi_driver = { 370 .probe = arxescsi_probe, 371 .remove = __devexit_p(arxescsi_remove), 372 .id_table = arxescsi_cids, 373 .drv = { 374 .name = "arxescsi", 375 }, 376 }; 377 378 static int __init init_arxe_scsi_driver(void) 379 { 380 return ecard_register_driver(&arxescsi_driver); 381 } 382 383 static void __exit exit_arxe_scsi_driver(void) 384 { 385 ecard_remove_driver(&arxescsi_driver); 386 } 387 388 module_init(init_arxe_scsi_driver); 389 module_exit(exit_arxe_scsi_driver); 390 391 MODULE_AUTHOR("Stefan Hanske"); 392 MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines"); 393 MODULE_LICENSE("GPL"); 394 395