import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / acorn / scsi / oak.c
1 #define AUTOSENSE
2 /*#define PSEUDO_DMA*/
3
4 /*
5  * Oak Generic NCR5380 driver
6  *
7  * Copyright 1995, Russell King
8  *
9  * ALPHA RELEASE 1.
10  *
11  * For more information, please consult
12  *
13  * NCR 5380 Family
14  * SCSI Protocol Controller
15  * Databook
16  *
17  * NCR Microelectronics
18  * 1635 Aeroplaza Drive
19  * Colorado Springs, CO 80916
20  * 1+ (719) 578-3400
21  * 1+ (800) 334-5454
22  */
23
24 /*
25  * Options :
26  *
27  * PARITY - enable parity checking.  Not supported.
28  *
29  * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
30  *
31  * USLEEP - enable support for devices that don't disconnect.  Untested.
32  */
33
34 /*
35  * $Log: oak.c,v $
36  * Revision 1.1.1.1  2005/04/11 02:50:14  jack
37  * first release
38  *
39  * Revision 1.1.1.1  2005/01/10 13:16:15  jack
40  * First release
41  *
42  * Revision 1.3  1998/05/03 20:45:37  alan
43  * ARM SCSI update. This adds the eesox driver and massively updates the
44  * Cumana driver. The folks who bought cumana arent anal retentive all
45  * docs are secret weenies so now there are docs ..
46  *
47  * Revision 1.2  1998/03/08 05:49:48  davem
48  * Merge to 2.1.89
49  *
50  * Revision 1.1  1998/02/23 02:45:27  davem
51  * Merge to 2.1.88
52  *
53  */
54
55 #include <linux/module.h>
56 #include <linux/signal.h>
57 #include <linux/sched.h>
58 #include <linux/ioport.h>
59 #include <linux/blk.h>
60 #include <linux/init.h>
61
62 #include <asm/ecard.h>
63 #include <asm/io.h>
64 #include <asm/system.h>
65
66 #include "../../scsi/scsi.h"
67 #include "../../scsi/hosts.h"
68 #include "../../scsi/constants.h"
69
70 #define OAKSCSI_PUBLIC_RELEASE 1
71
72 #define NCR5380_read(reg)               oakscsi_read(_instance, reg)
73 #define NCR5380_write(reg, value)       oakscsi_write(_instance, reg, value)
74 #define do_NCR5380_intr                 do_oakscsi_intr
75 #define NCR5380_queue_command           oakscsi_queue_command
76 #define NCR5380_abort                   oakscsi_abort
77 #define NCR5380_reset                   oakscsi_reset
78 #define NCR5380_proc_info               oakscsi_proc_info
79
80 int NCR5380_proc_info(char *buffer, char **start, off_t offset,
81                       int length, int hostno, int inout);
82
83 #define NCR5380_implementation_fields \
84         int port, ctrl
85
86 #define NCR5380_local_declare() \
87         struct Scsi_Host *_instance
88
89 #define NCR5380_setup(instance) \
90         _instance = instance
91
92 #define BOARD_NORMAL    0
93 #define BOARD_NCR53C400 1
94
95 #include "../../scsi/NCR5380.h"
96
97 #undef START_DMA_INITIATOR_RECEIVE_REG
98 #define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
99
100 static const card_ids oakscsi_cids[] = {
101         { MANU_OAK, PROD_OAK_SCSI },
102         { 0xffff, 0xffff }
103 };
104
105 #define OAK_ADDRESS(card) (ecard_address((card), ECARD_MEMC, 0))
106 #define OAK_IRQ(card)     (IRQ_NONE)
107 /*
108  * Function : int oakscsi_detect(Scsi_Host_Template * tpnt)
109  *
110  * Purpose : initializes oak NCR5380 driver based on the
111  *      command line / compile time port and irq definitions.
112  *
113  * Inputs : tpnt - template for this SCSI adapter.
114  *
115  * Returns : 1 if a host adapter was found, 0 if not.
116  *
117  */
118 static struct expansion_card *ecs[4];
119
120 int oakscsi_detect(Scsi_Host_Template * tpnt)
121 {
122     int count = 0;
123     struct Scsi_Host *instance;
124
125     tpnt->proc_name = "oakscsi";
126
127     memset (ecs, 0, sizeof (ecs));
128
129     ecard_startfind ();
130
131     while(1) {
132         if ((ecs[count] = ecard_find(0, oakscsi_cids)) == NULL)
133             break;
134
135         instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
136         instance->io_port = OAK_ADDRESS(ecs[count]);
137         instance->irq = OAK_IRQ(ecs[count]);
138
139         NCR5380_init(instance, 0);
140         ecard_claim(ecs[count]);
141
142         instance->n_io_port = 255;
143         request_region (instance->io_port, instance->n_io_port, "Oak SCSI");
144
145         if (instance->irq != IRQ_NONE)
146             if (request_irq(instance->irq, do_oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) {
147                 printk("scsi%d: IRQ%d not free, interrupts disabled\n",
148                     instance->host_no, instance->irq);
149                 instance->irq = IRQ_NONE;
150             }
151
152         if (instance->irq != IRQ_NONE) {
153             printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
154             printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
155         }
156
157         printk("scsi%d: at port %lX irq", instance->host_no, instance->io_port);
158         if (instance->irq == IRQ_NONE)
159             printk ("s disabled");
160         else
161             printk (" %d", instance->irq);
162         printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
163             tpnt->can_queue, tpnt->cmd_per_lun, OAKSCSI_PUBLIC_RELEASE);
164         printk("\nscsi%d:", instance->host_no);
165         NCR5380_print_options(instance);
166         printk("\n");
167
168         ++count;
169     }
170 #ifdef MODULE
171     if(count == 0)
172         printk("No oak scsi devices found\n");
173 #endif
174     return count;
175 }
176
177 int oakscsi_release (struct Scsi_Host *shpnt)
178 {
179         int i;
180
181         if (shpnt->irq != IRQ_NONE)
182                 free_irq (shpnt->irq, NULL);
183         if (shpnt->io_port)
184                 release_region (shpnt->io_port, shpnt->n_io_port);
185
186         for (i = 0; i < 4; i++)
187                 if (shpnt->io_port == OAK_ADDRESS(ecs[i]))
188                         ecard_release (ecs[i]);
189         return 0;
190 }
191
192 const char * oakscsi_info (struct Scsi_Host *spnt) {
193     return "";
194 }
195
196 #define STAT(p)   inw(p + 144)
197 extern void inswb(int from, void *to, int len);
198
199 static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
200               int len)
201 {
202   int iobase = instance->io_port;
203 printk("writing %p len %d\n",addr, len);
204   if(!len) return -1;
205
206   while(1)
207   {
208     int status;
209     while(((status = STAT(iobase)) & 0x100)==0);
210   }
211 }
212
213 static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
214               int len)
215 {
216   int iobase = instance->io_port;
217 printk("reading %p len %d\n", addr, len);
218   while(len > 0)
219   {
220     int status, timeout;
221     unsigned long b;
222     
223     timeout = 0x01FFFFFF;
224     
225     while(((status = STAT(iobase)) & 0x100)==0)
226     {
227       timeout--;
228       if(status & 0x200 || !timeout)
229       {
230         printk("status = %08X\n",status);
231         return 1;
232       }
233     }
234     if(len >= 128)
235     {
236       inswb(iobase + 136, addr, 128);
237       addr += 128;
238       len -= 128;
239     }
240     else
241     {
242       b = (unsigned long) inw(iobase + 136);
243       *addr ++ = b;
244       len -= 1;
245       if(len)
246         *addr ++ = b>>8;
247       len -= 1;
248     }
249   }
250   return 0;
251 }
252
253 #define oakscsi_read(instance,reg)      (inb((instance)->io_port + (reg)))
254 #define oakscsi_write(instance,reg,val) (outb((val), (instance)->io_port + (reg)))
255
256 #undef STAT
257
258 #include "../../scsi/NCR5380.c"
259
260 static Scsi_Host_Template oakscsi_template = {
261         module:         THIS_MODULE,
262         proc_info:      oakscsi_proc_info,
263         name:           "Oak 16-bit SCSI",
264         detect:         oakscsi_detect,
265         release:        oakscsi_release,
266         info:           oakscsi_info,
267         queuecommand:   oakscsi_queue_command,
268         abort:          oakscsi_abort,
269         reset:          oakscsi_reset,
270         can_queue:      16,
271         this_id:        7,
272         sg_tablesize:   SG_ALL,
273         cmd_per_lun:    2,
274         use_clustering: DISABLE_CLUSTERING
275 };
276
277 static int __init oakscsi_init(void)
278 {
279         scsi_register_module(MODULE_SCSI_HA, &oakscsi_template);
280         if (oakscsi_template.present)
281                 return 0;
282
283         scsi_unregister_module(MODULE_SCSI_HA, &oakscsi_template);
284         return -ENODEV;
285 }
286
287 static void __exit oakscsi_exit(void)
288 {
289         scsi_unregister_module(MODULE_SCSI_HA, &oakscsi_template);
290 }
291
292 module_init(oakscsi_init);
293 module_exit(oakscsi_exit);
294
295 MODULE_AUTHOR("Russell King");
296 MODULE_DESCRIPTION("Oak SCSI driver");
297 MODULE_LICENSE("GPL");
298 EXPORT_NO_SYMBOLS;