Merge branch 'mv-merge'
[linux-2.6] / 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 struct 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_bus_reset_handler   = NCR5380_bus_reset,
166         .can_queue      = 16,
167         .this_id        = 7,
168         .sg_tablesize   = SG_ALL,
169         .cmd_per_lun    = 2,
170         .use_clustering = DISABLE_CLUSTERING
171 };
172
173 static struct Scsi_Host *host;
174
175 static int __init ecoscsi_init(void)
176 {
177
178         host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
179         if (!host)
180                 return 0;
181
182         host->io_port = 0x80ce8000;
183         host->n_io_port = 144;
184         host->irq = IRQ_NONE;
185
186         if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
187                 goto unregister_scsi;
188
189         ecoscsi_write(host, MODE_REG, 0x20);            /* Is it really SCSI? */
190         if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg.    */
191                 goto release_reg;
192
193         ecoscsi_write(host, MODE_REG, 0x00 );           /* it back.           */
194         if (ecoscsi_read(host, MODE_REG) != 0x00)
195                 goto release_reg;
196
197         NCR5380_init(host, 0);
198
199         printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port);
200         printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
201                 host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE);
202         printk("\nscsi%d:", host->host_no);
203         NCR5380_print_options(host);
204         printk("\n");
205
206         scsi_add_host(host, NULL); /* XXX handle failure */
207         scsi_scan_host(host);
208         return 0;
209
210 release_reg:
211         release_region(host->io_port, host->n_io_port);
212 unregister_scsi:
213         scsi_host_put(host);
214         return -ENODEV;
215 }
216
217 static void __exit ecoscsi_exit(void)
218 {
219         scsi_remove_host(host);
220
221         if (shpnt->irq != IRQ_NONE)
222                 free_irq(shpnt->irq, NULL);
223         NCR5380_exit(host);
224         if (shpnt->io_port)
225                 release_region(shpnt->io_port, shpnt->n_io_port);
226
227         scsi_host_put(host);
228         return 0;
229 }
230
231 module_init(ecoscsi_init);
232 module_exit(ecoscsi_exit);
233
234 MODULE_AUTHOR("Russell King");
235 MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines");
236 MODULE_LICENSE("GPL");
237