ahci: don't ignore result code of ahci_reset_controller()
[sfrench/cifs-2.6.git] / drivers / scsi / arm / cumana_1.c
1 /*
2  * Generic Generic NCR5380 driver
3  *
4  * Copyright 1995-2002, Russell King
5  */
6 #include <linux/module.h>
7 #include <linux/ioport.h>
8 #include <linux/blkdev.h>
9 #include <linux/init.h>
10
11 #include <asm/ecard.h>
12 #include <asm/io.h>
13
14 #include <scsi/scsi_host.h>
15
16 #define priv(host)                      ((struct NCR5380_hostdata *)(host)->hostdata)
17 #define NCR5380_read(reg)               cumanascsi_read(hostdata, reg)
18 #define NCR5380_write(reg, value)       cumanascsi_write(hostdata, reg, value)
19
20 #define NCR5380_dma_xfer_len            cumanascsi_dma_xfer_len
21 #define NCR5380_dma_recv_setup          cumanascsi_pread
22 #define NCR5380_dma_send_setup          cumanascsi_pwrite
23 #define NCR5380_dma_residual            NCR5380_dma_residual_none
24
25 #define NCR5380_intr                    cumanascsi_intr
26 #define NCR5380_queue_command           cumanascsi_queue_command
27 #define NCR5380_info                    cumanascsi_info
28
29 #define NCR5380_implementation_fields   \
30         unsigned ctrl
31
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
36 #include "../NCR5380.h"
37
38 #define CTRL    0x16fc
39 #define STAT    0x2004
40 #define L(v)    (((v)<<16)|((v) & 0x0000ffff))
41 #define H(v)    (((v)>>16)|((v) & 0xffff0000))
42
43 static inline int cumanascsi_pwrite(struct NCR5380_hostdata *hostdata,
44                                     unsigned char *addr, int len)
45 {
46   unsigned long *laddr;
47   u8 __iomem *base = hostdata->io;
48   u8 __iomem *dma = hostdata->pdma_io + 0x2000;
49
50   if(!len) return 0;
51
52   writeb(0x02, base + CTRL);
53   laddr = (unsigned long *)addr;
54   while(len >= 32)
55   {
56     unsigned int status;
57     unsigned long v;
58     status = readb(base + STAT);
59     if(status & 0x80)
60       goto end;
61     if(!(status & 0x40))
62       continue;
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);
71     len -= 32;
72     if(len == 0)
73       break;
74   }
75
76   addr = (unsigned char *)laddr;
77   writeb(0x12, base + CTRL);
78
79   while(len > 0)
80   {
81     unsigned int status;
82     status = readb(base + STAT);
83     if(status & 0x80)
84       goto end;
85     if(status & 0x40)
86     {
87       writeb(*addr++, dma);
88       if(--len == 0)
89         break;
90     }
91
92     status = readb(base + STAT);
93     if(status & 0x80)
94       goto end;
95     if(status & 0x40)
96     {
97       writeb(*addr++, dma);
98       if(--len == 0)
99         break;
100     }
101   }
102 end:
103   writeb(hostdata->ctrl | 0x40, base + CTRL);
104
105         if (len)
106                 return -1;
107         return 0;
108 }
109
110 static inline int cumanascsi_pread(struct NCR5380_hostdata *hostdata,
111                                    unsigned char *addr, int len)
112 {
113   unsigned long *laddr;
114   u8 __iomem *base = hostdata->io;
115   u8 __iomem *dma = hostdata->pdma_io + 0x2000;
116
117   if(!len) return 0;
118
119   writeb(0x00, base + CTRL);
120   laddr = (unsigned long *)addr;
121   while(len >= 32)
122   {
123     unsigned int status;
124     status = readb(base + STAT);
125     if(status & 0x80)
126       goto end;
127     if(!(status & 0x40))
128       continue;
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);
137     len -= 32;
138     if(len == 0)
139       break;
140   }
141
142   addr = (unsigned char *)laddr;
143   writeb(0x10, base + CTRL);
144
145   while(len > 0)
146   {
147     unsigned int status;
148     status = readb(base + STAT);
149     if(status & 0x80)
150       goto end;
151     if(status & 0x40)
152     {
153       *addr++ = readb(dma);
154       if(--len == 0)
155         break;
156     }
157
158     status = readb(base + STAT);
159     if(status & 0x80)
160       goto end;
161     if(status & 0x40)
162     {
163       *addr++ = readb(dma);
164       if(--len == 0)
165         break;
166     }
167   }
168 end:
169   writeb(hostdata->ctrl | 0x40, base + CTRL);
170
171         if (len)
172                 return -1;
173         return 0;
174 }
175
176 static int cumanascsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
177                                    struct scsi_cmnd *cmd)
178 {
179         return cmd->transfersize;
180 }
181
182 static u8 cumanascsi_read(struct NCR5380_hostdata *hostdata,
183                           unsigned int reg)
184 {
185         u8 __iomem *base = hostdata->io;
186         u8 val;
187
188         writeb(0, base + CTRL);
189
190         val = readb(base + 0x2100 + (reg << 2));
191
192         hostdata->ctrl = 0x40;
193         writeb(0x40, base + CTRL);
194
195         return val;
196 }
197
198 static void cumanascsi_write(struct NCR5380_hostdata *hostdata,
199                              unsigned int reg, u8 value)
200 {
201         u8 __iomem *base = hostdata->io;
202
203         writeb(0, base + CTRL);
204
205         writeb(value, base + 0x2100 + (reg << 2));
206
207         hostdata->ctrl = 0x40;
208         writeb(0x40, base + CTRL);
209 }
210
211 #include "../NCR5380.c"
212
213 static struct scsi_host_template cumanascsi_template = {
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,
219         .eh_bus_reset_handler   = NCR5380_bus_reset,
220         .can_queue              = 16,
221         .this_id                = 7,
222         .sg_tablesize           = SG_ALL,
223         .cmd_per_lun            = 2,
224         .use_clustering         = DISABLE_CLUSTERING,
225         .proc_name              = "CumanaSCSI-1",
226         .cmd_size               = NCR5380_CMD_SIZE,
227         .max_sectors            = 128,
228 };
229
230 static int cumanascsi1_probe(struct expansion_card *ec,
231                              const struct ecard_id *id)
232 {
233         struct Scsi_Host *host;
234         int ret;
235
236         ret = ecard_request_resources(ec);
237         if (ret)
238                 goto out;
239
240         host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
241         if (!host) {
242                 ret = -ENOMEM;
243                 goto out_release;
244         }
245
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) {
251                 ret = -ENOMEM;
252                 goto out_unmap;
253         }
254
255         host->irq = ec->irq;
256
257         ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
258         if (ret)
259                 goto out_unmap;
260
261         NCR5380_maybe_reset_bus(host);
262
263         priv(host)->ctrl = 0;
264         writeb(0, priv(host)->io + CTRL);
265
266         ret = request_irq(host->irq, cumanascsi_intr, 0,
267                           "CumanaSCSI-1", host);
268         if (ret) {
269                 printk("scsi%d: IRQ%d not free: %d\n",
270                     host->host_no, host->irq, ret);
271                 goto out_exit;
272         }
273
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);
283  out_exit:
284         NCR5380_exit(host);
285  out_unmap:
286         iounmap(priv(host)->io);
287         iounmap(priv(host)->pdma_io);
288         scsi_host_put(host);
289  out_release:
290         ecard_release_resources(ec);
291  out:
292         return ret;
293 }
294
295 static void cumanascsi1_remove(struct expansion_card *ec)
296 {
297         struct Scsi_Host *host = ecard_get_drvdata(ec);
298         void __iomem *base = priv(host)->io;
299         void __iomem *dma = priv(host)->pdma_io;
300
301         ecard_set_drvdata(ec, NULL);
302
303         scsi_remove_host(host);
304         free_irq(host->irq, host);
305         NCR5380_exit(host);
306         scsi_host_put(host);
307         iounmap(base);
308         iounmap(dma);
309         ecard_release_resources(ec);
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,
319         .remove         = cumanascsi1_remove,
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");