clean
[linux-2.4.21-pre4.git] / drivers / acorn / scsi / ecoscsi.c
1 #define AUTOSENSE
2 /* #define PSEUDO_DMA */
3
4 /*
5  * EcoSCSI 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: ecoscsi.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.2  1998/03/08 05:49:47  davem
43  * Merge to 2.1.89
44  *
45  * Revision 1.1  1998/02/23 02:45:24  davem
46  * Merge to 2.1.88
47  *
48  */
49
50 #include <linux/module.h>
51 #include <linux/signal.h>
52 #include <linux/sched.h>
53 #include <linux/ioport.h>
54 #include <linux/init.h>
55 #include <linux/blk.h>
56
57 #include <asm/io.h>
58 #include <asm/system.h>
59
60 #include "../../scsi/scsi.h"
61 #include "../../scsi/hosts.h"
62 #include "../../scsi/NCR5380.h"
63 #include "../../scsi/constants.h"
64
65 #define ECOSCSI_PUBLIC_RELEASE 1
66
67 static char ecoscsi_read(struct Scsi_Host *instance, int reg)
68 {
69   int iobase = instance->io_port;
70   outb(reg | 8, iobase);
71   return inb(iobase + 1);
72 }
73
74 static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
75 {
76   int iobase = instance->io_port;
77   outb(reg | 8, iobase);
78   outb(value, iobase + 1);
79 }
80
81 /*
82  * Function : ecoscsi_setup(char *str, int *ints)
83  *
84  * Purpose : LILO command line initialization of the overrides array,
85  *
86  * Inputs : str - unused, ints - array of integer parameters with ints[0]
87  *      equal to the number of ints.
88  *
89  */
90
91 void ecoscsi_setup(char *str, int *ints) {
92 }
93
94 /*
95  * Function : int ecoscsi_detect(Scsi_Host_Template * tpnt)
96  *
97  * Purpose : initializes ecoscsi NCR5380 driver based on the
98  *      command line / compile time port and irq definitions.
99  *
100  * Inputs : tpnt - template for this SCSI adapter.
101  *
102  * Returns : 1 if a host adapter was found, 0 if not.
103  *
104  */
105
106 int ecoscsi_detect(Scsi_Host_Template * tpnt)
107 {
108     struct Scsi_Host *instance;
109
110     tpnt->proc_name = "ecoscsi";
111
112     instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
113     instance->io_port = 0x80ce8000;
114     instance->n_io_port = 144;
115     instance->irq = IRQ_NONE;
116
117     if (check_region (instance->io_port, instance->n_io_port)) {
118         scsi_unregister (instance);
119         return 0;
120     }
121
122     ecoscsi_write (instance, MODE_REG, 0x20);           /* Is it really SCSI? */
123     if (ecoscsi_read (instance, MODE_REG) != 0x20) {    /* Write to a reg.    */
124         scsi_unregister(instance);
125         return 0;                                       /* and try to read    */
126     }
127     ecoscsi_write( instance, MODE_REG, 0x00 );          /* it back.           */
128     if (ecoscsi_read (instance, MODE_REG) != 0x00) {
129         scsi_unregister(instance);
130         return 0;
131     }
132
133     NCR5380_init(instance, 0);
134     if (request_region (instance->io_port, instance->n_io_port, "ecoscsi") == NULL) {
135         scsi_unregister(instance);
136         return 0;
137     }
138
139     if (instance->irq != IRQ_NONE)
140         if (request_irq(instance->irq, do_ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) {
141             printk("scsi%d: IRQ%d not free, interrupts disabled\n",
142             instance->host_no, instance->irq);
143             instance->irq = IRQ_NONE;
144         }
145
146     if (instance->irq != IRQ_NONE) {
147         printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
148         printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
149     }
150
151     printk("scsi%d: at port %X irq", instance->host_no, instance->io_port);
152     if (instance->irq == IRQ_NONE)
153         printk ("s disabled");
154     else
155         printk (" %d", instance->irq);
156     printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
157         CAN_QUEUE, CMD_PER_LUN, ECOSCSI_PUBLIC_RELEASE);
158     printk("\nscsi%d:", instance->host_no);
159     NCR5380_print_options(instance);
160     printk("\n");
161     return 1;
162 }
163
164 int ecoscsi_release (struct Scsi_Host *shpnt)
165 {
166         if (shpnt->irq != IRQ_NONE)
167                 free_irq (shpnt->irq, NULL);
168         if (shpnt->io_port)
169                 release_region (shpnt->io_port, shpnt->n_io_port);
170         return 0;
171 }
172
173 const char * ecoscsi_info (struct Scsi_Host *spnt) {
174     return "";
175 }
176
177 #if 0
178 #define STAT(p) inw(p + 144)
179
180 static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
181               int len)
182 {
183   int iobase = instance->io_port;
184 printk("writing %p len %d\n",addr, len);
185   if(!len) return -1;
186
187   while(1)
188   {
189     int status;
190     while(((status = STAT(iobase)) & 0x100)==0);
191   }
192 }
193
194 static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
195               int len)
196 {
197   int iobase = instance->io_port;
198   int iobase2= instance->io_port + 0x100;
199   unsigned char *start = addr;
200   int s;
201 printk("reading %p len %d\n",addr, len);
202   outb(inb(iobase + 128), iobase + 135);
203   while(len > 0)
204   {
205     int status,b,i, timeout;
206     timeout = 0x07FFFFFF;
207     while(((status = STAT(iobase)) & 0x100)==0)
208     {
209       timeout--;
210       if(status & 0x200 || !timeout)
211       {
212         printk("status = %p\n",status);
213         outb(0, iobase + 135);
214         return 1;
215       }
216     }
217     if(len >= 128)
218     {
219       for(i=0; i<64; i++)
220       {
221         b = inw(iobase + 136);
222         *addr++ = b;
223         *addr++ = b>>8;
224       }
225       len -= 128;
226     }
227     else
228     {
229       b = inw(iobase + 136);
230       *addr ++ = b;
231       len -= 1;
232       if(len)
233         *addr ++ = b>>8;
234       len -= 1;
235     }
236   }
237   outb(0, iobase + 135);
238   printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
239   return 1;
240 }
241 #endif
242 #undef STAT
243
244 #define NCR5380_implementation_fields \
245     int port, ctrl
246
247 #define NCR5380_local_declare() \
248         struct Scsi_Host *_instance
249
250 #define NCR5380_setup(instance) \
251         _instance = instance
252
253 #define NCR5380_read(reg) ecoscsi_read(_instance, reg)
254 #define NCR5380_write(reg, value) ecoscsi_write(_instance, reg, value)
255
256 #define do_NCR5380_intr do_ecoscsi_intr
257 #define NCR5380_queue_command ecoscsi_queue_command
258 #define NCR5380_abort ecoscsi_abort
259 #define NCR5380_reset ecoscsi_reset
260 #define NCR5380_proc_info ecoscsi_proc_info
261
262 int NCR5380_proc_info(char *buffer, char **start, off_t offset,
263                       int length, int hostno, int inout);
264
265 #define BOARD_NORMAL    0
266 #define BOARD_NCR53C400 1
267
268 #include "../../scsi/NCR5380.c"
269
270 static Scsi_Host_Template ecoscsi_template =  {
271         module:         THIS_MODULE,
272         name:           "Serial Port EcoSCSI NCR5380",
273         detect:         ecoscsi_detect,
274         release:        ecoscsi_release,
275         info:           ecoscsi_info,
276         queuecommand:   ecoscsi_queue_command,
277         abort:          ecoscsi_abort,
278         reset:          ecoscsi_reset,
279         can_queue:      16,
280         this_id:        7,
281         sg_tablesize:   SG_ALL,
282         cmd_per_lun:    2,
283         use_clustering: DISABLE_CLUSTERING
284 };
285
286 static int __init ecoscsi_init(void)
287 {
288         scsi_register_module(MODULE_SCSI_HA, &ecoscsi_template);
289         if (ecoscsi_template.present)
290                 return 0;
291
292         scsi_unregister_module(MODULE_SCSI_HA, &ecoscsi_template);
293         return -ENODEV;
294 }
295
296 static void __exit ecoscsi_exit(void)
297 {
298         scsi_unregister_module(MODULE_SCSI_HA, &ecoscsi_template);
299 }
300
301 module_init(ecoscsi_init);
302 module_exit(ecoscsi_exit);
303
304 MODULE_AUTHOR("Russell King");
305 MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines");
306 MODULE_LICENSE("GPL");
307 EXPORT_NO_SYMBOLS;