]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Generic Generic NCR5380 driver | |
3 | * | |
4 | * Copyright 1995-2002, Russell King | |
5 | */ | |
6 | #include <linux/module.h> | |
1da177e4 | 7 | #include <linux/ioport.h> |
1da177e4 LT |
8 | #include <linux/blkdev.h> |
9 | #include <linux/init.h> | |
10 | ||
11 | #include <asm/ecard.h> | |
12 | #include <asm/io.h> | |
1da177e4 | 13 | |
1da177e4 LT |
14 | #include <scsi/scsi_host.h> |
15 | ||
8b801ead | 16 | #define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata) |
61e1ce58 FT |
17 | #define NCR5380_read(reg) cumanascsi_read(hostdata, reg) |
18 | #define NCR5380_write(reg, value) cumanascsi_write(hostdata, reg, value) | |
ff3d4578 | 19 | |
4a98f896 | 20 | #define NCR5380_dma_xfer_len cumanascsi_dma_xfer_len |
6c4b88ca FT |
21 | #define NCR5380_dma_recv_setup cumanascsi_pread |
22 | #define NCR5380_dma_send_setup cumanascsi_pwrite | |
4a98f896 | 23 | #define NCR5380_dma_residual NCR5380_dma_residual_none |
ff3d4578 | 24 | |
1da177e4 LT |
25 | #define NCR5380_intr cumanascsi_intr |
26 | #define NCR5380_queue_command cumanascsi_queue_command | |
8c32513b | 27 | #define NCR5380_info cumanascsi_info |
1da177e4 | 28 | |
8b801ead | 29 | #define NCR5380_implementation_fields \ |
820682b1 | 30 | unsigned ctrl |
8b801ead | 31 | |
7c606631 FT |
32 | struct NCR5380_hostdata; |
33 | static u8 cumanascsi_read(struct NCR5380_hostdata *, unsigned int); | |
34 | static void cumanascsi_write(struct NCR5380_hostdata *, unsigned int, u8); | |
35 | ||
1da177e4 LT |
36 | #include "../NCR5380.h" |
37 | ||
8b801ead RK |
38 | #define CTRL 0x16fc |
39 | #define STAT 0x2004 | |
40 | #define L(v) (((v)<<16)|((v) & 0x0000ffff)) | |
41 | #define H(v) (((v)>>16)|((v) & 0xffff0000)) | |
1da177e4 | 42 | |
4a98f896 | 43 | static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata, |
6c4b88ca | 44 | unsigned char *addr, int len) |
1da177e4 | 45 | { |
1da177e4 | 46 | unsigned long *laddr; |
4a98f896 FT |
47 | u8 __iomem *base = hostdata->io; |
48 | u8 __iomem *dma = hostdata->pdma_io + 0x2000; | |
1da177e4 LT |
49 | |
50 | if(!len) return 0; | |
51 | ||
820682b1 | 52 | writeb(0x02, base + CTRL); |
1da177e4 LT |
53 | laddr = (unsigned long *)addr; |
54 | while(len >= 32) | |
55 | { | |
8b801ead | 56 | unsigned int status; |
1da177e4 | 57 | unsigned long v; |
820682b1 | 58 | status = readb(base + STAT); |
1da177e4 LT |
59 | if(status & 0x80) |
60 | goto end; | |
61 | if(!(status & 0x40)) | |
62 | continue; | |
8b801ead RK |
63 | v=*laddr++; writew(L(v), dma); writew(H(v), dma); |
64 | v=*laddr++; writew(L(v), dma); writew(H(v), dma); | |
65 | v=*laddr++; writew(L(v), dma); writew(H(v), dma); | |
66 | v=*laddr++; writew(L(v), dma); writew(H(v), dma); | |
67 | v=*laddr++; writew(L(v), dma); writew(H(v), dma); | |
68 | v=*laddr++; writew(L(v), dma); writew(H(v), dma); | |
69 | v=*laddr++; writew(L(v), dma); writew(H(v), dma); | |
70 | v=*laddr++; writew(L(v), dma); writew(H(v), dma); | |
1da177e4 LT |
71 | len -= 32; |
72 | if(len == 0) | |
73 | break; | |
74 | } | |
75 | ||
76 | addr = (unsigned char *)laddr; | |
820682b1 | 77 | writeb(0x12, base + CTRL); |
8b801ead | 78 | |
1da177e4 LT |
79 | while(len > 0) |
80 | { | |
8b801ead | 81 | unsigned int status; |
820682b1 | 82 | status = readb(base + STAT); |
1da177e4 LT |
83 | if(status & 0x80) |
84 | goto end; | |
85 | if(status & 0x40) | |
86 | { | |
8b801ead | 87 | writeb(*addr++, dma); |
1da177e4 LT |
88 | if(--len == 0) |
89 | break; | |
90 | } | |
91 | ||
820682b1 | 92 | status = readb(base + STAT); |
1da177e4 LT |
93 | if(status & 0x80) |
94 | goto end; | |
95 | if(status & 0x40) | |
96 | { | |
8b801ead | 97 | writeb(*addr++, dma); |
1da177e4 LT |
98 | if(--len == 0) |
99 | break; | |
100 | } | |
101 | } | |
102 | end: | |
4a98f896 | 103 | writeb(hostdata->ctrl | 0x40, base + CTRL); |
438af51c FT |
104 | |
105 | if (len) | |
106 | return -1; | |
107 | return 0; | |
1da177e4 LT |
108 | } |
109 | ||
4a98f896 | 110 | static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata, |
6c4b88ca | 111 | unsigned char *addr, int len) |
1da177e4 | 112 | { |
1da177e4 | 113 | unsigned long *laddr; |
4a98f896 FT |
114 | u8 __iomem *base = hostdata->io; |
115 | u8 __iomem *dma = hostdata->pdma_io + 0x2000; | |
1da177e4 LT |
116 | |
117 | if(!len) return 0; | |
118 | ||
820682b1 | 119 | writeb(0x00, base + CTRL); |
1da177e4 LT |
120 | laddr = (unsigned long *)addr; |
121 | while(len >= 32) | |
122 | { | |
8b801ead | 123 | unsigned int status; |
820682b1 | 124 | status = readb(base + STAT); |
1da177e4 LT |
125 | if(status & 0x80) |
126 | goto end; | |
127 | if(!(status & 0x40)) | |
128 | continue; | |
8b801ead RK |
129 | *laddr++ = readw(dma) | (readw(dma) << 16); |
130 | *laddr++ = readw(dma) | (readw(dma) << 16); | |
131 | *laddr++ = readw(dma) | (readw(dma) << 16); | |
132 | *laddr++ = readw(dma) | (readw(dma) << 16); | |
133 | *laddr++ = readw(dma) | (readw(dma) << 16); | |
134 | *laddr++ = readw(dma) | (readw(dma) << 16); | |
135 | *laddr++ = readw(dma) | (readw(dma) << 16); | |
136 | *laddr++ = readw(dma) | (readw(dma) << 16); | |
1da177e4 LT |
137 | len -= 32; |
138 | if(len == 0) | |
139 | break; | |
140 | } | |
141 | ||
142 | addr = (unsigned char *)laddr; | |
820682b1 | 143 | writeb(0x10, base + CTRL); |
8b801ead | 144 | |
1da177e4 LT |
145 | while(len > 0) |
146 | { | |
8b801ead | 147 | unsigned int status; |
820682b1 | 148 | status = readb(base + STAT); |
1da177e4 LT |
149 | if(status & 0x80) |
150 | goto end; | |
151 | if(status & 0x40) | |
152 | { | |
8b801ead | 153 | *addr++ = readb(dma); |
1da177e4 LT |
154 | if(--len == 0) |
155 | break; | |
156 | } | |
157 | ||
820682b1 | 158 | status = readb(base + STAT); |
1da177e4 LT |
159 | if(status & 0x80) |
160 | goto end; | |
161 | if(status & 0x40) | |
162 | { | |
8b801ead | 163 | *addr++ = readb(dma); |
1da177e4 LT |
164 | if(--len == 0) |
165 | break; | |
166 | } | |
167 | } | |
168 | end: | |
4a98f896 | 169 | writeb(hostdata->ctrl | 0x40, base + CTRL); |
438af51c FT |
170 | |
171 | if (len) | |
172 | return -1; | |
173 | return 0; | |
1da177e4 LT |
174 | } |
175 | ||
4a98f896 FT |
176 | static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, |
177 | struct scsi_cmnd *cmd) | |
178 | { | |
179 | return cmd->transfersize; | |
180 | } | |
181 | ||
61e1ce58 FT |
182 | static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata, |
183 | unsigned int reg) | |
8b801ead | 184 | { |
61e1ce58 FT |
185 | u8 __iomem *base = hostdata->io; |
186 | u8 val; | |
1da177e4 | 187 | |
8b801ead | 188 | writeb(0, base + CTRL); |
1da177e4 | 189 | |
8b801ead | 190 | val = readb(base + 0x2100 + (reg << 2)); |
1da177e4 | 191 | |
61e1ce58 | 192 | hostdata->ctrl = 0x40; |
8b801ead | 193 | writeb(0x40, base + CTRL); |
1da177e4 | 194 | |
8b801ead | 195 | return val; |
1da177e4 LT |
196 | } |
197 | ||
61e1ce58 FT |
198 | static void cumanascsi_write(struct NCR5380_hostdata *hostdata, |
199 | unsigned int reg, u8 value) | |
1da177e4 | 200 | { |
61e1ce58 | 201 | u8 __iomem *base = hostdata->io; |
1da177e4 | 202 | |
8b801ead | 203 | writeb(0, base + CTRL); |
1da177e4 | 204 | |
8b801ead RK |
205 | writeb(value, base + 0x2100 + (reg << 2)); |
206 | ||
61e1ce58 | 207 | hostdata->ctrl = 0x40; |
8b801ead RK |
208 | writeb(0x40, base + CTRL); |
209 | } | |
1da177e4 LT |
210 | |
211 | #include "../NCR5380.c" | |
212 | ||
d0be4a7d | 213 | static struct scsi_host_template cumanascsi_template = { |
1da177e4 LT |
214 | .module = THIS_MODULE, |
215 | .name = "Cumana 16-bit SCSI", | |
216 | .info = cumanascsi_info, | |
217 | .queuecommand = cumanascsi_queue_command, | |
218 | .eh_abort_handler = NCR5380_abort, | |
1da177e4 | 219 | .eh_bus_reset_handler = NCR5380_bus_reset, |
1da177e4 LT |
220 | .can_queue = 16, |
221 | .this_id = 7, | |
222 | .sg_tablesize = SG_ALL, | |
223 | .cmd_per_lun = 2, | |
1da177e4 LT |
224 | .use_clustering = DISABLE_CLUSTERING, |
225 | .proc_name = "CumanaSCSI-1", | |
32b26a10 | 226 | .cmd_size = NCR5380_CMD_SIZE, |
0a4e3612 | 227 | .max_sectors = 128, |
1da177e4 LT |
228 | }; |
229 | ||
6f039790 GKH |
230 | static int cumanascsi1_probe(struct expansion_card *ec, |
231 | const struct ecard_id *id) | |
1da177e4 LT |
232 | { |
233 | struct Scsi_Host *host; | |
8b801ead | 234 | int ret; |
1da177e4 | 235 | |
8b801ead RK |
236 | ret = ecard_request_resources(ec); |
237 | if (ret) | |
1da177e4 LT |
238 | goto out; |
239 | ||
8b801ead RK |
240 | host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata)); |
241 | if (!host) { | |
242 | ret = -ENOMEM; | |
243 | goto out_release; | |
244 | } | |
245 | ||
820682b1 FT |
246 | priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW), |
247 | ecard_resource_len(ec, ECARD_RES_IOCSLOW)); | |
248 | priv(host)->pdma_io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), | |
249 | ecard_resource_len(ec, ECARD_RES_MEMC)); | |
250 | if (!priv(host)->io || !priv(host)->pdma_io) { | |
8b801ead RK |
251 | ret = -ENOMEM; |
252 | goto out_unmap; | |
253 | } | |
254 | ||
1da177e4 LT |
255 | host->irq = ec->irq; |
256 | ||
8053b0ee | 257 | ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP); |
0ad0eff9 FT |
258 | if (ret) |
259 | goto out_unmap; | |
1da177e4 | 260 | |
b6488f97 FT |
261 | NCR5380_maybe_reset_bus(host); |
262 | ||
8b801ead | 263 | priv(host)->ctrl = 0; |
820682b1 | 264 | writeb(0, priv(host)->io + CTRL); |
8b801ead | 265 | |
4909cc2b | 266 | ret = request_irq(host->irq, cumanascsi_intr, 0, |
1da177e4 LT |
267 | "CumanaSCSI-1", host); |
268 | if (ret) { | |
269 | printk("scsi%d: IRQ%d not free: %d\n", | |
270 | host->host_no, host->irq, ret); | |
0ad0eff9 | 271 | goto out_exit; |
1da177e4 LT |
272 | } |
273 | ||
1da177e4 LT |
274 | ret = scsi_add_host(host, &ec->dev); |
275 | if (ret) | |
276 | goto out_free_irq; | |
277 | ||
278 | scsi_scan_host(host); | |
279 | goto out; | |
280 | ||
281 | out_free_irq: | |
282 | free_irq(host->irq, host); | |
0ad0eff9 FT |
283 | out_exit: |
284 | NCR5380_exit(host); | |
8b801ead | 285 | out_unmap: |
820682b1 FT |
286 | iounmap(priv(host)->io); |
287 | iounmap(priv(host)->pdma_io); | |
1da177e4 | 288 | scsi_host_put(host); |
8b801ead RK |
289 | out_release: |
290 | ecard_release_resources(ec); | |
1da177e4 LT |
291 | out: |
292 | return ret; | |
293 | } | |
294 | ||
6f039790 | 295 | static void cumanascsi1_remove(struct expansion_card *ec) |
1da177e4 LT |
296 | { |
297 | struct Scsi_Host *host = ecard_get_drvdata(ec); | |
820682b1 FT |
298 | void __iomem *base = priv(host)->io; |
299 | void __iomem *dma = priv(host)->pdma_io; | |
1da177e4 LT |
300 | |
301 | ecard_set_drvdata(ec, NULL); | |
302 | ||
303 | scsi_remove_host(host); | |
304 | free_irq(host->irq, host); | |
305 | NCR5380_exit(host); | |
1da177e4 | 306 | scsi_host_put(host); |
820682b1 FT |
307 | iounmap(base); |
308 | iounmap(dma); | |
8b801ead | 309 | ecard_release_resources(ec); |
1da177e4 LT |
310 | } |
311 | ||
312 | static const struct ecard_id cumanascsi1_cids[] = { | |
313 | { MANU_CUMANA, PROD_CUMANA_SCSI_1 }, | |
314 | { 0xffff, 0xffff } | |
315 | }; | |
316 | ||
317 | static struct ecard_driver cumanascsi1_driver = { | |
318 | .probe = cumanascsi1_probe, | |
6f039790 | 319 | .remove = cumanascsi1_remove, |
1da177e4 LT |
320 | .id_table = cumanascsi1_cids, |
321 | .drv = { | |
322 | .name = "cumanascsi1", | |
323 | }, | |
324 | }; | |
325 | ||
326 | static int __init cumanascsi_init(void) | |
327 | { | |
328 | return ecard_register_driver(&cumanascsi1_driver); | |
329 | } | |
330 | ||
331 | static void __exit cumanascsi_exit(void) | |
332 | { | |
333 | ecard_remove_driver(&cumanascsi1_driver); | |
334 | } | |
335 | ||
336 | module_init(cumanascsi_init); | |
337 | module_exit(cumanascsi_exit); | |
338 | ||
339 | MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines"); | |
340 | MODULE_LICENSE("GPL"); |