Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cumana_1.c
Go to the documentation of this file.
1 /*
2  * Generic Generic NCR5380 driver
3  *
4  * Copyright 1995-2002, Russell King
5  */
6 #include <linux/module.h>
7 #include <linux/signal.h>
8 #include <linux/ioport.h>
9 #include <linux/delay.h>
10 #include <linux/blkdev.h>
11 #include <linux/init.h>
12 
13 #include <asm/ecard.h>
14 #include <asm/io.h>
15 
16 #include "../scsi.h"
17 #include <scsi/scsi_host.h>
18 
19 #include <scsi/scsicam.h>
20 
21 #define AUTOSENSE
22 #define PSEUDO_DMA
23 
24 #define CUMANASCSI_PUBLIC_RELEASE 1
25 
26 #define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
27 #define NCR5380_local_declare() struct Scsi_Host *_instance
28 #define NCR5380_setup(instance) _instance = instance
29 #define NCR5380_read(reg) cumanascsi_read(_instance, reg)
30 #define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value)
31 #define NCR5380_intr cumanascsi_intr
32 #define NCR5380_queue_command cumanascsi_queue_command
33 #define NCR5380_proc_info cumanascsi_proc_info
34 
35 #define NCR5380_implementation_fields \
36  unsigned ctrl; \
37  void __iomem *base; \
38  void __iomem *dma
39 
40 #define BOARD_NORMAL 0
41 #define BOARD_NCR53C400 1
42 
43 #include "../NCR5380.h"
44 
45 void cumanascsi_setup(char *str, int *ints)
46 {
47 }
48 
49 const char *cumanascsi_info(struct Scsi_Host *spnt)
50 {
51  return "";
52 }
53 
54 #define CTRL 0x16fc
55 #define STAT 0x2004
56 #define L(v) (((v)<<16)|((v) & 0x0000ffff))
57 #define H(v) (((v)>>16)|((v) & 0xffff0000))
58 
59 static inline int
60 NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr, int len)
61 {
62  unsigned long *laddr;
63  void __iomem *dma = priv(host)->dma + 0x2000;
64 
65  if(!len) return 0;
66 
67  writeb(0x02, priv(host)->base + CTRL);
68  laddr = (unsigned long *)addr;
69  while(len >= 32)
70  {
71  unsigned int status;
72  unsigned long v;
73  status = readb(priv(host)->base + STAT);
74  if(status & 0x80)
75  goto end;
76  if(!(status & 0x40))
77  continue;
78  v=*laddr++; writew(L(v), dma); writew(H(v), dma);
79  v=*laddr++; writew(L(v), dma); writew(H(v), dma);
80  v=*laddr++; writew(L(v), dma); writew(H(v), dma);
81  v=*laddr++; writew(L(v), dma); writew(H(v), dma);
82  v=*laddr++; writew(L(v), dma); writew(H(v), dma);
83  v=*laddr++; writew(L(v), dma); writew(H(v), dma);
84  v=*laddr++; writew(L(v), dma); writew(H(v), dma);
85  v=*laddr++; writew(L(v), dma); writew(H(v), dma);
86  len -= 32;
87  if(len == 0)
88  break;
89  }
90 
91  addr = (unsigned char *)laddr;
92  writeb(0x12, priv(host)->base + CTRL);
93 
94  while(len > 0)
95  {
96  unsigned int status;
97  status = readb(priv(host)->base + STAT);
98  if(status & 0x80)
99  goto end;
100  if(status & 0x40)
101  {
102  writeb(*addr++, dma);
103  if(--len == 0)
104  break;
105  }
106 
107  status = readb(priv(host)->base + STAT);
108  if(status & 0x80)
109  goto end;
110  if(status & 0x40)
111  {
112  writeb(*addr++, dma);
113  if(--len == 0)
114  break;
115  }
116  }
117 end:
118  writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
119  return len;
120 }
121 
122 static inline int
123 NCR5380_pread(struct Scsi_Host *host, unsigned char *addr, int len)
124 {
125  unsigned long *laddr;
126  void __iomem *dma = priv(host)->dma + 0x2000;
127 
128  if(!len) return 0;
129 
130  writeb(0x00, priv(host)->base + CTRL);
131  laddr = (unsigned long *)addr;
132  while(len >= 32)
133  {
134  unsigned int status;
135  status = readb(priv(host)->base + STAT);
136  if(status & 0x80)
137  goto end;
138  if(!(status & 0x40))
139  continue;
140  *laddr++ = readw(dma) | (readw(dma) << 16);
141  *laddr++ = readw(dma) | (readw(dma) << 16);
142  *laddr++ = readw(dma) | (readw(dma) << 16);
143  *laddr++ = readw(dma) | (readw(dma) << 16);
144  *laddr++ = readw(dma) | (readw(dma) << 16);
145  *laddr++ = readw(dma) | (readw(dma) << 16);
146  *laddr++ = readw(dma) | (readw(dma) << 16);
147  *laddr++ = readw(dma) | (readw(dma) << 16);
148  len -= 32;
149  if(len == 0)
150  break;
151  }
152 
153  addr = (unsigned char *)laddr;
154  writeb(0x10, priv(host)->base + CTRL);
155 
156  while(len > 0)
157  {
158  unsigned int status;
159  status = readb(priv(host)->base + STAT);
160  if(status & 0x80)
161  goto end;
162  if(status & 0x40)
163  {
164  *addr++ = readb(dma);
165  if(--len == 0)
166  break;
167  }
168 
169  status = readb(priv(host)->base + STAT);
170  if(status & 0x80)
171  goto end;
172  if(status & 0x40)
173  {
174  *addr++ = readb(dma);
175  if(--len == 0)
176  break;
177  }
178  }
179 end:
180  writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
181  return len;
182 }
183 
184 static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg)
185 {
186  void __iomem *base = priv(host)->base;
187  unsigned char val;
188 
189  writeb(0, base + CTRL);
190 
191  val = readb(base + 0x2100 + (reg << 2));
192 
193  priv(host)->ctrl = 0x40;
194  writeb(0x40, base + CTRL);
195 
196  return val;
197 }
198 
199 static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value)
200 {
201  void __iomem *base = priv(host)->base;
202 
203  writeb(0, base + CTRL);
204 
205  writeb(value, base + 0x2100 + (reg << 2));
206 
207  priv(host)->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 };
227 
228 static int __devinit
229 cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
230 {
231  struct Scsi_Host *host;
232  int ret;
233 
234  ret = ecard_request_resources(ec);
235  if (ret)
236  goto out;
237 
238  host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
239  if (!host) {
240  ret = -ENOMEM;
241  goto out_release;
242  }
243 
248  if (!priv(host)->base || !priv(host)->dma) {
249  ret = -ENOMEM;
250  goto out_unmap;
251  }
252 
253  host->irq = ec->irq;
254 
255  NCR5380_init(host, 0);
256 
257  priv(host)->ctrl = 0;
258  writeb(0, priv(host)->base + CTRL);
259 
260  host->n_io_port = 255;
261  if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
262  ret = -EBUSY;
263  goto out_unmap;
264  }
265 
266  ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
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_unmap;
272  }
273 
274  printk("scsi%d: at port 0x%08lx irq %d",
275  host->host_no, host->io_port, host->irq);
276  printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
278  printk("\nscsi%d:", host->host_no);
279  NCR5380_print_options(host);
280  printk("\n");
281 
282  ret = scsi_add_host(host, &ec->dev);
283  if (ret)
284  goto out_free_irq;
285 
286  scsi_scan_host(host);
287  goto out;
288 
289  out_free_irq:
290  free_irq(host->irq, host);
291  out_unmap:
292  iounmap(priv(host)->base);
293  iounmap(priv(host)->dma);
294  scsi_host_put(host);
295  out_release:
297  out:
298  return ret;
299 }
300 
301 static void __devexit cumanascsi1_remove(struct expansion_card *ec)
302 {
303  struct Scsi_Host *host = ecard_get_drvdata(ec);
304 
305  ecard_set_drvdata(ec, NULL);
306 
307  scsi_remove_host(host);
308  free_irq(host->irq, host);
309  NCR5380_exit(host);
310  iounmap(priv(host)->base);
311  iounmap(priv(host)->dma);
312  scsi_host_put(host);
314 }
315 
316 static const struct ecard_id cumanascsi1_cids[] = {
318  { 0xffff, 0xffff }
319 };
320 
321 static struct ecard_driver cumanascsi1_driver = {
322  .probe = cumanascsi1_probe,
323  .remove = __devexit_p(cumanascsi1_remove),
324  .id_table = cumanascsi1_cids,
325  .drv = {
326  .name = "cumanascsi1",
327  },
328 };
329 
330 static int __init cumanascsi_init(void)
331 {
332  return ecard_register_driver(&cumanascsi1_driver);
333 }
334 
335 static void __exit cumanascsi_exit(void)
336 {
337  ecard_remove_driver(&cumanascsi1_driver);
338 }
339 
340 module_init(cumanascsi_init);
341 module_exit(cumanascsi_exit);
342 
343 MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
344 MODULE_LICENSE("GPL");