vserver 1.9.3
[linux-2.6.git] / drivers / scsi / arm / 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 #include <linux/module.h>
25 #include <linux/signal.h>
26 #include <linux/sched.h>
27 #include <linux/ioport.h>
28 #include <linux/delay.h>
29 #include <linux/init.h>
30 #include <linux/blkdev.h>
31
32 #include <asm/io.h>
33 #include <asm/system.h>
34
35 #include "../scsi.h"
36 #include <scsi/scsi_host.h>
37
38 #define NCR5380_implementation_fields   int port, ctrl
39 #define NCR5380_local_declare()         struct Scsi_Host *_instance
40 #define NCR5380_setup(instance)         _instance = instance
41
42 #define NCR5380_read(reg)               ecoscsi_read(_instance, reg)
43 #define NCR5380_write(reg, value)       ecoscsi_write(_instance, reg, value)
44
45 #define NCR5380_intr                    ecoscsi_intr
46 #define NCR5380_queue_command           ecoscsi_queue_command
47 #define NCR5380_proc_info               ecoscsi_proc_info
48
49 #include "../NCR5380.h"
50
51 #define ECOSCSI_PUBLIC_RELEASE 1
52
53 static char ecoscsi_read(struct Scsi_Host *instance, int reg)
54 {
55   int iobase = instance->io_port;
56   outb(reg | 8, iobase);
57   return inb(iobase + 1);
58 }
59
60 static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
61 {
62   int iobase = instance->io_port;
63   outb(reg | 8, iobase);
64   outb(value, iobase + 1);
65 }
66
67 /*
68  * Function : ecoscsi_setup(char *str, int *ints)
69  *
70  * Purpose : LILO command line initialization of the overrides array,
71  *
72  * Inputs : str - unused, ints - array of integer parameters with ints[0]
73  *      equal to the number of ints.
74  *
75  */
76
77 void ecoscsi_setup(char *str, int *ints)
78 {
79 }
80
81 const char * ecoscsi_info (struct Scsi_Host *spnt)
82 {
83         return "";
84 }
85
86 #if 0
87 #define STAT(p) inw(p + 144)
88
89 static inline int NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr,
90               int len)
91 {
92   int iobase = host->io_port;
93 printk("writing %p len %d\n",addr, len);
94   if(!len) return -1;
95
96   while(1)
97   {
98     int status;
99     while(((status = STAT(iobase)) & 0x100)==0);
100   }
101 }
102
103 static inline int NCR5380_pread(struct Scsi_Host *host, unsigned char *addr,
104               int len)
105 {
106   int iobase = host->io_port;
107   int iobase2= host->io_port + 0x100;
108   unsigned char *start = addr;
109   int s;
110 printk("reading %p len %d\n",addr, len);
111   outb(inb(iobase + 128), iobase + 135);
112   while(len > 0)
113   {
114     int status,b,i, timeout;
115     timeout = 0x07FFFFFF;
116     while(((status = STAT(iobase)) & 0x100)==0)
117     {
118       timeout--;
119       if(status & 0x200 || !timeout)
120       {
121         printk("status = %p\n",status);
122         outb(0, iobase + 135);
123         return 1;
124       }
125     }
126     if(len >= 128)
127     {
128       for(i=0; i<64; i++)
129       {
130         b = inw(iobase + 136);
131         *addr++ = b;
132         *addr++ = b>>8;
133       }
134       len -= 128;
135     }
136     else
137     {
138       b = inw(iobase + 136);
139       *addr ++ = b;
140       len -= 1;
141       if(len)
142         *addr ++ = b>>8;
143       len -= 1;
144     }
145   }
146   outb(0, iobase + 135);
147   printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
148   return 1;
149 }
150 #endif
151 #undef STAT
152
153 #define BOARD_NORMAL    0
154 #define BOARD_NCR53C400 1
155
156 #include "../NCR5380.c"
157
158 static Scsi_Host_Template ecoscsi_template =  {
159         .module         = THIS_MODULE,
160         .name           = "Serial Port EcoSCSI NCR5380",
161         .proc_name      = "ecoscsi",
162         .info           = ecoscsi_info,
163         .queuecommand   = ecoscsi_queue_command,
164         .eh_abort_handler       = NCR5380_abort,
165         .eh_device_reset_handler= NCR5380_device_reset,
166         .eh_bus_reset_handler   = NCR5380_bus_reset,
167         .eh_host_reset_handler  = NCR5380_host_reset,
168         .can_queue      = 16,
169         .this_id        = 7,
170         .sg_tablesize   = SG_ALL,
171         .cmd_per_lun    = 2,
172         .use_clustering = DISABLE_CLUSTERING
173 };
174
175 static struct Scsi_Host *host;
176
177 static int __init ecoscsi_init(void)
178 {
179
180         host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
181         if (!host)
182                 return 0;
183
184         host->io_port = 0x80ce8000;
185         host->n_io_port = 144;
186         host->irq = IRQ_NONE;
187
188         if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
189                 goto unregister_scsi;
190
191         ecoscsi_write(host, MODE_REG, 0x20);            /* Is it really SCSI? */
192         if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg.    */
193                 goto release_reg;
194
195         ecoscsi_write(host, MODE_REG, 0x00 );           /* it back.           */
196         if (ecoscsi_read(host, MODE_REG) != 0x00)
197                 goto release_reg;
198
199         NCR5380_init(host, 0);
200
201         printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port);
202         printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
203                 host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE);
204         printk("\nscsi%d:", host->host_no);
205         NCR5380_print_options(host);
206         printk("\n");
207
208         scsi_add_host(host, NULL); /* XXX handle failure */
209         scsi_scan_host(host);
210         return 0;
211
212 release_reg:
213         release_region(host->io_port, host->n_io_port);
214 unregister_scsi:
215         scsi_host_put(host);
216         return -ENODEV;
217 }
218
219 static void __exit ecoscsi_exit(void)
220 {
221         scsi_remove_host(host);
222
223         if (shpnt->irq != IRQ_NONE)
224                 free_irq(shpnt->irq, NULL);
225         NCR5380_exit(host);
226         if (shpnt->io_port)
227                 release_region(shpnt->io_port, shpnt->n_io_port);
228
229         scsi_host_put(host);
230         return 0;
231 }
232
233 module_init(ecoscsi_init);
234 module_exit(ecoscsi_exit);
235
236 MODULE_AUTHOR("Russell King");
237 MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines");
238 MODULE_LICENSE("GPL");
239