diff options
Diffstat (limited to 'drivers/scsi/arm/ecoscsi.c')
-rw-r--r-- | drivers/scsi/arm/ecoscsi.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c new file mode 100644 index 000000000000..303648a84709 --- /dev/null +++ b/drivers/scsi/arm/ecoscsi.c | |||
@@ -0,0 +1,239 @@ | |||
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 | |||