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