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/blk.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
33 #include <asm/dma.h>
34 #include <asm/io.h>
35 #include <asm/irq.h>
36 #include <asm/ecard.h>
37
38 #include "../../scsi/sd.h"
39 #include "../../scsi/hosts.h"
40 #include <scsi/scsicam.h>
41 #include "fas216.h"
42 #include "scsi.h"
43
44 struct arxescsi_info {
45 FAS216_Info info;
46 struct expansion_card *ec;
47 unsigned int dmaarea; /* Pseudo DMA area */
48 };
49
50 #define DMADATA_OFFSET (0x200/4)
51
52 #define DMASTAT_OFFSET (0x600/4)
53 #define DMASTAT_DRQ (1 << 0)
54
55 #define CSTATUS_IRQ (1 << 0)
56
57 /*
58 * List of devices that the driver will recognise
59 */
60 #define ARXESCSI_LIST { MANU_ARXE, PROD_ARXE_SCSI }
61
62 /*
63 * Version
64 */
65 #define VERSION "1.10 (22/01/2003 2.4.19-rmk5)"
66
67 /*
68 * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type)
69 * Purpose : initialises DMA/PIO
70 * Params : host - host
71 * SCpnt - command
72 * direction - DMA on to/off of card
73 * min_type - minimum DMA support that we must have for this transfer
74 * Returns : 0 if we should not set CMD_WITHDMA for transfer info command
75 */
76 static fasdmatype_t
arxescsi_dma_setup(struct Scsi_Host * host,Scsi_Pointer * SCp,fasdmadir_t direction,fasdmatype_t min_type)77 arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
78 fasdmadir_t direction, fasdmatype_t min_type)
79 {
80 /*
81 * We don't do real DMA
82 */
83 return fasdma_pseudo;
84 }
85
86
87
88 /* Faster transfer routines, written by SH to speed up the loops */
89
getb(unsigned int address,unsigned int reg)90 static __inline__ unsigned char getb(unsigned int address, unsigned int reg)
91 {
92 unsigned char value;
93
94 __asm__ __volatile__(
95 "ldrb %0, [%1, %2, lsl #5]"
96 : "=r" (value)
97 : "r" (address), "r" (reg) );
98 return value;
99 }
100
getw(unsigned int address,unsigned int reg)101 static __inline__ unsigned int getw(unsigned int address, unsigned int reg)
102 {
103 unsigned int value;
104
105 __asm__ __volatile__(
106 "ldr %0, [%1, %2, lsl #5]\n\t"
107 "mov %0, %0, lsl #16\n\t"
108 "mov %0, %0, lsr #16"
109 : "=r" (value)
110 : "r" (address), "r" (reg) );
111 return value;
112 }
113
putw(unsigned int address,unsigned int reg,unsigned long value)114 static __inline__ void putw(unsigned int address, unsigned int reg, unsigned long value)
115 {
116 __asm__ __volatile__(
117 "mov %0, %0, lsl #16\n\t"
118 "str %0, [%1, %2, lsl #5]"
119 :
120 : "r" (value), "r" (address), "r" (reg) );
121 }
122
arxescsi_pseudo_dma_write(unsigned char * addr,unsigned int io)123 void arxescsi_pseudo_dma_write(unsigned char *addr, unsigned int io)
124 {
125 __asm__ __volatile__(
126 " stmdb sp!, {r0-r12}\n"
127 " mov r3, %0\n"
128 " mov r1, %1\n"
129 " add r2, r1, #512\n"
130 " mov r4, #256\n"
131 ".loop_1: ldmia r3!, {r6, r8, r10, r12}\n"
132 " mov r5, r6, lsl #16\n"
133 " mov r7, r8, lsl #16\n"
134 ".loop_2: ldrb r0, [r1, #1536]\n"
135 " tst r0, #1\n"
136 " beq .loop_2\n"
137 " stmia r2, {r5-r8}\n\t"
138 " mov r9, r10, lsl #16\n"
139 " mov r11, r12, lsl #16\n"
140 ".loop_3: ldrb r0, [r1, #1536]\n"
141 " tst r0, #1\n"
142 " beq .loop_3\n"
143 " stmia r2, {r9-r12}\n"
144 " subs r4, r4, #16\n"
145 " bne .loop_1\n"
146 " ldmia sp!, {r0-r12}\n"
147 :
148 : "r" (addr), "r" (io) );
149 }
150
151 /*
152 * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer)
153 * Purpose : handles pseudo DMA
154 * Params : host - host
155 * SCpnt - command
156 * direction - DMA on to/off of card
157 * transfer - minimum number of bytes we expect to transfer
158 */
arxescsi_dma_pseudo(struct Scsi_Host * host,Scsi_Pointer * SCp,fasdmadir_t direction,int transfer)159 void arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
160 fasdmadir_t direction, int transfer)
161 {
162 struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
163 unsigned int length, io, error=0;
164 unsigned char *addr;
165
166 length = SCp->this_residual;
167 addr = SCp->ptr;
168 io = __ioaddr(host->io_port);
169
170 if (direction == DMA_OUT) {
171 unsigned int word;
172 while (length > 256) {
173 if (getb(io, 4) & STAT_INT) {
174 error=1;
175 break;
176 }
177 arxescsi_pseudo_dma_write(addr, io);
178 addr += 256;
179 length -= 256;
180 }
181
182 if (!error)
183 while (length > 0) {
184 if (getb(io, 4) & STAT_INT)
185 break;
186
187 if (!(getb(io, 48) & DMASTAT_DRQ))
188 continue;
189
190 word = *addr | *(addr + 1) << 8;
191
192 putw(io, 16, word);
193 if (length > 1) {
194 addr += 2;
195 length -= 2;
196 } else {
197 addr += 1;
198 length -= 1;
199 }
200 }
201 }
202 else {
203 if (transfer && (transfer & 255)) {
204 while (length >= 256) {
205 if (getb(io, 4) & STAT_INT) {
206 error=1;
207 break;
208 }
209
210 if (!(getb(io, 48) & DMASTAT_DRQ))
211 continue;
212
213 insw(info->dmaarea, addr, 256 >> 1);
214 addr += 256;
215 length -= 256;
216 }
217 }
218
219 if (!(error))
220 while (length > 0) {
221 unsigned long word;
222
223 if (getb(io, 4) & STAT_INT)
224 break;
225
226 if (!(getb(io, 48) & DMASTAT_DRQ))
227 continue;
228
229 word = getw(io, 16);
230 *addr++ = word;
231 if (--length > 0) {
232 *addr++ = word >> 8;
233 length --;
234 }
235 }
236 }
237 }
238
239 /*
240 * Function: int arxescsi_dma_stop(host, SCpnt)
241 * Purpose : stops DMA/PIO
242 * Params : host - host
243 * SCpnt - command
244 */
arxescsi_dma_stop(struct Scsi_Host * host,Scsi_Pointer * SCp)245 static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
246 {
247 /*
248 * no DMA to stop
249 */
250 }
251
252 /*
253 * Function: const char *arxescsi_info(struct Scsi_Host * host)
254 * Purpose : returns a descriptive string about this interface,
255 * Params : host - driver host structure to return info for.
256 * Returns : pointer to a static buffer containing null terminated string.
257 */
arxescsi_info(struct Scsi_Host * host)258 const char *arxescsi_info(struct Scsi_Host *host)
259 {
260 struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
261 static char string[150];
262
263 sprintf(string, "%s (%s) in slot %d v%s",
264 host->hostt->name, info->info.scsi.type, info->ec->slot_no,
265 VERSION);
266
267 return string;
268 }
269
270 /*
271 * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset,
272 * int length, int host_no, int inout)
273 * Purpose : Return information about the driver to a user process accessing
274 * the /proc filesystem.
275 * Params : buffer - a buffer to write information to
276 * start - a pointer into this buffer set by this routine to the start
277 * of the required information.
278 * offset - offset into information that we have read upto.
279 * length - length of buffer
280 * host_no - host number to return information for
281 * inout - 0 for reading, 1 for writing.
282 * Returns : length of data written to buffer.
283 */
arxescsi_proc_info(char * buffer,char ** start,off_t offset,int length,int host_no,int inout)284 int arxescsi_proc_info(char *buffer, char **start, off_t offset,
285 int length, int host_no, int inout)
286 {
287 int pos, begin;
288 struct Scsi_Host *host;
289 struct arxescsi_info *info;
290 Scsi_Device *scd;
291
292 host = scsi_host_hn_get(host_no);
293 if (!host)
294 return 0;
295
296 info = (struct arxescsi_info *)host->hostdata;
297 if (inout == 1)
298 return -EINVAL;
299
300 begin = 0;
301 pos = sprintf(buffer, "ARXE 16-bit SCSI driver v%s\n", VERSION);
302 pos += fas216_print_host(&info->info, buffer + pos);
303 pos += fas216_print_stats(&info->info, buffer + pos);
304
305 pos += sprintf (buffer+pos, "\nAttached devices:\n");
306
307 for (scd = host->host_queue; scd; scd = scd->next) {
308 pos += fas216_print_device(&info->info, scd, buffer + pos);
309
310 if (pos + begin < offset) {
311 begin += pos;
312 pos = 0;
313 }
314 if (pos + begin > offset + length)
315 break;
316 }
317
318 *start = buffer + (offset - begin);
319 pos -= offset - begin;
320 if (pos > length)
321 pos = length;
322
323 return pos;
324 }
325
326 static int arxescsi_probe(struct expansion_card *ec);
327
328 /*
329 * Function: int arxescsi_detect(Scsi_Host_Template * tpnt)
330 * Purpose : initialises ARXE SCSI driver
331 * Params : tpnt - template for this SCSI adapter
332 * Returns : >0 if host found, 0 otherwise.
333 */
arxescsi_detect(Scsi_Host_Template * tpnt)334 static int arxescsi_detect(Scsi_Host_Template *tpnt)
335 {
336 static const card_ids arxescsi_cids[] = { ARXESCSI_LIST, { 0xffff, 0xffff} };
337 int count = 0, ret;
338
339 ecard_startfind();
340
341 while (1) {
342 struct expansion_card *ec;
343 ec = ecard_find(0, arxescsi_cids);
344 if (!ec)
345 break;
346
347 ecard_claim(ec);
348 ret = arxescsi_probe(ec);
349 if (ret) {
350 ecard_release(ec);
351 break;
352 }
353 ++count;
354 }
355 return count;
356 }
357
358 static void arxescsi_remove(struct Scsi_Host *host);
359
360 /*
361 * Function: int arxescsi_release(struct Scsi_Host * host)
362 * Purpose : releases all resources used by this adapter
363 * Params : host - driver host structure to return info for.
364 * Returns : nothing
365 */
arxescsi_release(struct Scsi_Host * host)366 static int arxescsi_release(struct Scsi_Host *host)
367 {
368 arxescsi_remove(host);
369 return 0;
370 }
371
372 static Scsi_Host_Template arxescsi_template = {
373 .module = THIS_MODULE,
374 .proc_info = arxescsi_proc_info,
375 .name = "ARXE SCSI card",
376 .detect = arxescsi_detect,
377 .release = arxescsi_release,
378 .info = arxescsi_info,
379 .bios_param = scsicam_bios_param,
380 .command = fas216_command,
381 .queuecommand = fas216_queue_command,
382 .eh_host_reset_handler = fas216_eh_host_reset,
383 .eh_bus_reset_handler = fas216_eh_bus_reset,
384 .eh_device_reset_handler = fas216_eh_device_reset,
385 .eh_abort_handler = fas216_eh_abort,
386 .use_new_eh_code = 1,
387
388 .can_queue = 0,
389 .this_id = 7,
390 .sg_tablesize = SG_ALL,
391 .cmd_per_lun = 1,
392 .use_clustering = DISABLE_CLUSTERING,
393 .proc_name = "arxescsi",
394 };
395
396 static int
arxescsi_probe(struct expansion_card * ec)397 arxescsi_probe(struct expansion_card *ec)
398 {
399 struct Scsi_Host *host;
400 struct arxescsi_info *info;
401 unsigned long base;
402 int ret;
403
404 base = ecard_address(ec, ECARD_MEMC, 0) + 0x0800;
405
406 if (!request_region(base, 512, "arxescsi")) {
407 ret = -EBUSY;
408 goto out;
409 }
410
411 host = scsi_register(&arxescsi_template, sizeof(struct arxescsi_info));
412 if (!host) {
413 ret = -ENOMEM;
414 goto out_region;
415 }
416
417 host->io_port = base;
418 host->irq = NO_IRQ;
419 host->dma_channel = NO_DMA;
420
421 info = (struct arxescsi_info *)host->hostdata;
422 info->ec = ec;
423 info->dmaarea = base + DMADATA_OFFSET;
424
425 info->info.scsi.io_port = host->io_port;
426 info->info.scsi.irq = NO_IRQ;
427 info->info.scsi.io_shift = 3;
428 info->info.ifcfg.clockrate = 24; /* MHz */
429 info->info.ifcfg.select_timeout = 255;
430 info->info.ifcfg.asyncperiod = 200; /* ns */
431 info->info.ifcfg.sync_max_depth = 0;
432 info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK;
433 info->info.ifcfg.disconnect_ok = 0;
434 info->info.ifcfg.wide_max_size = 0;
435 info->info.ifcfg.capabilities = FASCAP_PSEUDODMA;
436 info->info.dma.setup = arxescsi_dma_setup;
437 info->info.dma.pseudo = arxescsi_dma_pseudo;
438 info->info.dma.stop = arxescsi_dma_stop;
439
440 ec->irqaddr = (unsigned char *)ioaddr(base);
441 ec->irqmask = CSTATUS_IRQ;
442
443 ret = fas216_init(host);
444 if (ret)
445 goto out_unregister;
446
447 ret = fas216_add(host);
448 if (ret == 0)
449 goto out;
450
451 fas216_release(host);
452 out_unregister:
453 scsi_unregister(host);
454 out_region:
455 release_region(base, 512);
456 out:
457 return ret;
458 }
459
arxescsi_remove(struct Scsi_Host * host)460 static void arxescsi_remove(struct Scsi_Host *host)
461 {
462 struct arxescsi_info *info;
463
464 info = (struct arxescsi_info *)host->hostdata;
465
466 fas216_remove(host);
467
468 release_region(host->io_port, 512);
469
470 ecard_release(info->ec);
471 fas216_release(host);
472 }
473
init_arxe_scsi_driver(void)474 static int __init init_arxe_scsi_driver(void)
475 {
476 scsi_register_module(MODULE_SCSI_HA, &arxescsi_template);
477 if (arxescsi_template.present)
478 return 0;
479
480 scsi_unregister_module(MODULE_SCSI_HA, &arxescsi_template);
481 return -ENODEV;
482 }
483
exit_arxe_scsi_driver(void)484 static void __exit exit_arxe_scsi_driver(void)
485 {
486 scsi_unregister_module(MODULE_SCSI_HA, &arxescsi_template);
487 }
488
489 module_init(init_arxe_scsi_driver);
490 module_exit(exit_arxe_scsi_driver);
491
492 MODULE_AUTHOR("Stefan Hanske");
493 MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines");
494 MODULE_LICENSE("GPL");
495 EXPORT_NO_SYMBOLS;
496