]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/scsi/sun3_scsi.c
Merge tag 'kvmgt-vfio-mdev-for-v4.10-rc1' of git://github.com/01org/gvt-linux
[karo-tx-linux.git] / drivers / scsi / sun3_scsi.c
1 /*
2  * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
3  *
4  * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
5  *
6  * VME support added by Sam Creasey
7  *
8  * TODO: modify this driver to support multiple Sun3 SCSI VME boards
9  *
10  * Adapted from mac_scsinew.c:
11  */
12 /*
13  * Generic Macintosh NCR5380 driver
14  *
15  * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
16  *
17  * derived in part from:
18  */
19 /*
20  * Generic Generic NCR5380 driver
21  *
22  * Copyright 1995, Russell King
23  */
24
25 #include <linux/types.h>
26 #include <linux/delay.h>
27 #include <linux/module.h>
28 #include <linux/ioport.h>
29 #include <linux/init.h>
30 #include <linux/blkdev.h>
31 #include <linux/platform_device.h>
32
33 #include <asm/io.h>
34 #include <asm/dvma.h>
35
36 #include <scsi/scsi_host.h>
37 #include "sun3_scsi.h"
38
39 /* minimum number of bytes to do dma on */
40 #define DMA_MIN_SIZE                    129
41
42 /* Definitions for the core NCR5380 driver. */
43
44 #define NCR5380_implementation_fields   /* none */
45
46 #define NCR5380_read(reg)               in_8(hostdata->io + (reg))
47 #define NCR5380_write(reg, value)       out_8(hostdata->io + (reg), value)
48
49 #define NCR5380_queue_command           sun3scsi_queue_command
50 #define NCR5380_bus_reset               sun3scsi_bus_reset
51 #define NCR5380_abort                   sun3scsi_abort
52 #define NCR5380_info                    sun3scsi_info
53
54 #define NCR5380_dma_xfer_len            sun3scsi_dma_xfer_len
55 #define NCR5380_dma_recv_setup          sun3scsi_dma_count
56 #define NCR5380_dma_send_setup          sun3scsi_dma_count
57 #define NCR5380_dma_residual            sun3scsi_dma_residual
58
59 #define NCR5380_acquire_dma_irq(instance)    (1)
60 #define NCR5380_release_dma_irq(instance)
61
62 #include "NCR5380.h"
63
64
65 extern int sun3_map_test(unsigned long, char *);
66
67 static int setup_can_queue = -1;
68 module_param(setup_can_queue, int, 0);
69 static int setup_cmd_per_lun = -1;
70 module_param(setup_cmd_per_lun, int, 0);
71 static int setup_sg_tablesize = -1;
72 module_param(setup_sg_tablesize, int, 0);
73 static int setup_hostid = -1;
74 module_param(setup_hostid, int, 0);
75
76 /* ms to wait after hitting dma regs */
77 #define SUN3_DMA_DELAY 10
78
79 /* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
80 #define SUN3_DVMA_BUFSIZE 0xe000
81
82 static struct scsi_cmnd *sun3_dma_setup_done;
83 static volatile struct sun3_dma_regs *dregs;
84 static struct sun3_udc_regs *udc_regs;
85 static unsigned char *sun3_dma_orig_addr;
86 static unsigned long sun3_dma_orig_count;
87 static int sun3_dma_active;
88 static unsigned long last_residual;
89
90 #ifndef SUN3_SCSI_VME
91 /* dma controller register access functions */
92
93 static inline unsigned short sun3_udc_read(unsigned char reg)
94 {
95         unsigned short ret;
96
97         dregs->udc_addr = UDC_CSR;
98         udelay(SUN3_DMA_DELAY);
99         ret = dregs->udc_data;
100         udelay(SUN3_DMA_DELAY);
101         
102         return ret;
103 }
104
105 static inline void sun3_udc_write(unsigned short val, unsigned char reg)
106 {
107         dregs->udc_addr = reg;
108         udelay(SUN3_DMA_DELAY);
109         dregs->udc_data = val;
110         udelay(SUN3_DMA_DELAY);
111 }
112 #endif
113
114 // safe bits for the CSR
115 #define CSR_GOOD 0x060f
116
117 static irqreturn_t scsi_sun3_intr(int irq, void *dev)
118 {
119         struct Scsi_Host *instance = dev;
120         unsigned short csr = dregs->csr;
121         int handled = 0;
122
123 #ifdef SUN3_SCSI_VME
124         dregs->csr &= ~CSR_DMA_ENABLE;
125 #endif
126
127         if(csr & ~CSR_GOOD) {
128                 if (csr & CSR_DMA_BUSERR)
129                         shost_printk(KERN_ERR, instance, "bus error in DMA\n");
130                 if (csr & CSR_DMA_CONFLICT)
131                         shost_printk(KERN_ERR, instance, "DMA conflict\n");
132                 handled = 1;
133         }
134
135         if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
136                 NCR5380_intr(irq, dev);
137                 handled = 1;
138         }
139
140         return IRQ_RETVAL(handled);
141 }
142
143 /* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
144 static int sun3scsi_dma_setup(struct NCR5380_hostdata *hostdata,
145                               unsigned char *data, int count, int write_flag)
146 {
147         void *addr;
148
149         if(sun3_dma_orig_addr != NULL)
150                 dvma_unmap(sun3_dma_orig_addr);
151
152 #ifdef SUN3_SCSI_VME
153         addr = (void *)dvma_map_vme((unsigned long) data, count);
154 #else
155         addr = (void *)dvma_map((unsigned long) data, count);
156 #endif
157                 
158         sun3_dma_orig_addr = addr;
159         sun3_dma_orig_count = count;
160
161 #ifndef SUN3_SCSI_VME
162         dregs->fifo_count = 0;
163         sun3_udc_write(UDC_RESET, UDC_CSR);
164         
165         /* reset fifo */
166         dregs->csr &= ~CSR_FIFO;
167         dregs->csr |= CSR_FIFO;
168 #endif
169         
170         /* set direction */
171         if(write_flag)
172                 dregs->csr |= CSR_SEND;
173         else
174                 dregs->csr &= ~CSR_SEND;
175         
176 #ifdef SUN3_SCSI_VME
177         dregs->csr |= CSR_PACK_ENABLE;
178
179         dregs->dma_addr_hi = ((unsigned long)addr >> 16);
180         dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
181
182         dregs->dma_count_hi = 0;
183         dregs->dma_count_lo = 0;
184         dregs->fifo_count_hi = 0;
185         dregs->fifo_count = 0;
186 #else
187         /* byte count for fifo */
188         dregs->fifo_count = count;
189
190         sun3_udc_write(UDC_RESET, UDC_CSR);
191         
192         /* reset fifo */
193         dregs->csr &= ~CSR_FIFO;
194         dregs->csr |= CSR_FIFO;
195         
196         if(dregs->fifo_count != count) { 
197                 shost_printk(KERN_ERR, hostdata->host,
198                              "FIFO mismatch %04x not %04x\n",
199                              dregs->fifo_count, (unsigned int) count);
200                 NCR5380_dprint(NDEBUG_DMA, hostdata->host);
201         }
202
203         /* setup udc */
204         udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
205         udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
206         udc_regs->count = count/2; /* count in words */
207         udc_regs->mode_hi = UDC_MODE_HIWORD;
208         if(write_flag) {
209                 if(count & 1)
210                         udc_regs->count++;
211                 udc_regs->mode_lo = UDC_MODE_LSEND;
212                 udc_regs->rsel = UDC_RSEL_SEND;
213         } else {
214                 udc_regs->mode_lo = UDC_MODE_LRECV;
215                 udc_regs->rsel = UDC_RSEL_RECV;
216         }
217         
218         /* announce location of regs block */
219         sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
220                        UDC_CHN_HI); 
221
222         sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
223
224         /* set dma master on */
225         sun3_udc_write(0xd, UDC_MODE);
226
227         /* interrupt enable */
228         sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
229 #endif
230         
231         return count;
232
233 }
234
235 static int sun3scsi_dma_count(struct NCR5380_hostdata *hostdata,
236                               unsigned char *data, int count)
237 {
238         return count;
239 }
240
241 static inline int sun3scsi_dma_recv_setup(struct NCR5380_hostdata *hostdata,
242                                           unsigned char *data, int count)
243 {
244         return sun3scsi_dma_setup(hostdata, data, count, 0);
245 }
246
247 static inline int sun3scsi_dma_send_setup(struct NCR5380_hostdata *hostdata,
248                                           unsigned char *data, int count)
249 {
250         return sun3scsi_dma_setup(hostdata, data, count, 1);
251 }
252
253 static int sun3scsi_dma_residual(struct NCR5380_hostdata *hostdata)
254 {
255         return last_residual;
256 }
257
258 static int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
259                                  struct scsi_cmnd *cmd)
260 {
261         int wanted_len = cmd->SCp.this_residual;
262
263         if (wanted_len < DMA_MIN_SIZE || cmd->request->cmd_type != REQ_TYPE_FS)
264                 return 0;
265
266         return wanted_len;
267 }
268
269 static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
270 {
271 #ifdef SUN3_SCSI_VME
272         unsigned short csr;
273
274         csr = dregs->csr;
275
276         dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
277         dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
278
279         dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
280         dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
281
282 /*      if(!(csr & CSR_DMA_ENABLE))
283  *              dregs->csr |= CSR_DMA_ENABLE;
284  */
285 #else
286     sun3_udc_write(UDC_CHN_START, UDC_CSR);
287 #endif
288     
289     return 0;
290 }
291
292 /* clean up after our dma is done */
293 static int sun3scsi_dma_finish(int write_flag)
294 {
295         unsigned short __maybe_unused count;
296         unsigned short fifo;
297         int ret = 0;
298         
299         sun3_dma_active = 0;
300
301 #ifdef SUN3_SCSI_VME
302         dregs->csr &= ~CSR_DMA_ENABLE;
303
304         fifo = dregs->fifo_count;
305         if (write_flag) {
306                 if ((fifo > 0) && (fifo < sun3_dma_orig_count))
307                         fifo++;
308         }
309
310         last_residual = fifo;
311         /* empty bytes from the fifo which didn't make it */
312         if ((!write_flag) && (dregs->csr & CSR_LEFT)) {
313                 unsigned char *vaddr;
314
315                 vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
316
317                 vaddr += (sun3_dma_orig_count - fifo);
318                 vaddr--;
319
320                 switch (dregs->csr & CSR_LEFT) {
321                 case CSR_LEFT_3:
322                         *vaddr = (dregs->bpack_lo & 0xff00) >> 8;
323                         vaddr--;
324
325                 case CSR_LEFT_2:
326                         *vaddr = (dregs->bpack_hi & 0x00ff);
327                         vaddr--;
328
329                 case CSR_LEFT_1:
330                         *vaddr = (dregs->bpack_hi & 0xff00) >> 8;
331                         break;
332                 }
333         }
334 #else
335         // check to empty the fifo on a read
336         if(!write_flag) {
337                 int tmo = 20000; /* .2 sec */
338                 
339                 while(1) {
340                         if(dregs->csr & CSR_FIFO_EMPTY)
341                                 break;
342
343                         if(--tmo <= 0) {
344                                 printk("sun3scsi: fifo failed to empty!\n");
345                                 return 1;
346                         }
347                         udelay(10);
348                 }
349         }
350
351         dregs->udc_addr = 0x32;
352         udelay(SUN3_DMA_DELAY);
353         count = 2 * dregs->udc_data;
354         udelay(SUN3_DMA_DELAY);
355
356         fifo = dregs->fifo_count;
357         last_residual = fifo;
358
359         /* empty bytes from the fifo which didn't make it */
360         if((!write_flag) && (count - fifo) == 2) {
361                 unsigned short data;
362                 unsigned char *vaddr;
363
364                 data = dregs->fifo_data;
365                 vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
366                 
367                 vaddr += (sun3_dma_orig_count - fifo);
368
369                 vaddr[-2] = (data & 0xff00) >> 8;
370                 vaddr[-1] = (data & 0xff);
371         }
372 #endif
373
374         dvma_unmap(sun3_dma_orig_addr);
375         sun3_dma_orig_addr = NULL;
376
377 #ifdef SUN3_SCSI_VME
378         dregs->dma_addr_hi = 0;
379         dregs->dma_addr_lo = 0;
380         dregs->dma_count_hi = 0;
381         dregs->dma_count_lo = 0;
382
383         dregs->fifo_count = 0;
384         dregs->fifo_count_hi = 0;
385
386         dregs->csr &= ~CSR_SEND;
387 /*      dregs->csr |= CSR_DMA_ENABLE; */
388 #else
389         sun3_udc_write(UDC_RESET, UDC_CSR);
390         dregs->fifo_count = 0;
391         dregs->csr &= ~CSR_SEND;
392
393         /* reset fifo */
394         dregs->csr &= ~CSR_FIFO;
395         dregs->csr |= CSR_FIFO;
396 #endif
397         
398         sun3_dma_setup_done = NULL;
399
400         return ret;
401
402 }
403         
404 #include "NCR5380.c"
405
406 #ifdef SUN3_SCSI_VME
407 #define SUN3_SCSI_NAME          "Sun3 NCR5380 VME SCSI"
408 #define DRV_MODULE_NAME         "sun3_scsi_vme"
409 #else
410 #define SUN3_SCSI_NAME          "Sun3 NCR5380 SCSI"
411 #define DRV_MODULE_NAME         "sun3_scsi"
412 #endif
413
414 #define PFX                     DRV_MODULE_NAME ": "
415
416 static struct scsi_host_template sun3_scsi_template = {
417         .module                 = THIS_MODULE,
418         .proc_name              = DRV_MODULE_NAME,
419         .name                   = SUN3_SCSI_NAME,
420         .info                   = sun3scsi_info,
421         .queuecommand           = sun3scsi_queue_command,
422         .eh_abort_handler       = sun3scsi_abort,
423         .eh_bus_reset_handler   = sun3scsi_bus_reset,
424         .can_queue              = 16,
425         .this_id                = 7,
426         .sg_tablesize           = SG_NONE,
427         .cmd_per_lun            = 2,
428         .use_clustering         = DISABLE_CLUSTERING,
429         .cmd_size               = NCR5380_CMD_SIZE,
430 };
431
432 static int __init sun3_scsi_probe(struct platform_device *pdev)
433 {
434         struct Scsi_Host *instance;
435         struct NCR5380_hostdata *hostdata;
436         int error;
437         struct resource *irq, *mem;
438         void __iomem *ioaddr;
439         int host_flags = 0;
440 #ifdef SUN3_SCSI_VME
441         int i;
442 #endif
443
444         if (setup_can_queue > 0)
445                 sun3_scsi_template.can_queue = setup_can_queue;
446         if (setup_cmd_per_lun > 0)
447                 sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
448         if (setup_sg_tablesize >= 0)
449                 sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
450         if (setup_hostid >= 0)
451                 sun3_scsi_template.this_id = setup_hostid & 7;
452
453 #ifdef SUN3_SCSI_VME
454         ioaddr = NULL;
455         for (i = 0; i < 2; i++) {
456                 unsigned char x;
457
458                 irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
459                 mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
460                 if (!irq || !mem)
461                         break;
462
463                 ioaddr = sun3_ioremap(mem->start, resource_size(mem),
464                                       SUN3_PAGE_TYPE_VME16);
465                 dregs = (struct sun3_dma_regs *)(ioaddr + 8);
466
467                 if (sun3_map_test((unsigned long)dregs, &x)) {
468                         unsigned short oldcsr;
469
470                         oldcsr = dregs->csr;
471                         dregs->csr = 0;
472                         udelay(SUN3_DMA_DELAY);
473                         if (dregs->csr == 0x1400)
474                                 break;
475
476                         dregs->csr = oldcsr;
477                 }
478
479                 iounmap(ioaddr);
480                 ioaddr = NULL;
481         }
482         if (!ioaddr)
483                 return -ENODEV;
484 #else
485         irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
486         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
487         if (!irq || !mem)
488                 return -ENODEV;
489
490         ioaddr = ioremap(mem->start, resource_size(mem));
491         dregs = (struct sun3_dma_regs *)(ioaddr + 8);
492
493         udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs));
494         if (!udc_regs) {
495                 pr_err(PFX "couldn't allocate DVMA memory!\n");
496                 iounmap(ioaddr);
497                 return -ENOMEM;
498         }
499 #endif
500
501         instance = scsi_host_alloc(&sun3_scsi_template,
502                                    sizeof(struct NCR5380_hostdata));
503         if (!instance) {
504                 error = -ENOMEM;
505                 goto fail_alloc;
506         }
507
508         instance->irq = irq->start;
509
510         hostdata = shost_priv(instance);
511         hostdata->base = mem->start;
512         hostdata->io = ioaddr;
513
514         error = NCR5380_init(instance, host_flags);
515         if (error)
516                 goto fail_init;
517
518         error = request_irq(instance->irq, scsi_sun3_intr, 0,
519                             "NCR5380", instance);
520         if (error) {
521                 pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n",
522                        instance->host_no, instance->irq);
523                 goto fail_irq;
524         }
525
526         dregs->csr = 0;
527         udelay(SUN3_DMA_DELAY);
528         dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
529         udelay(SUN3_DMA_DELAY);
530         dregs->fifo_count = 0;
531 #ifdef SUN3_SCSI_VME
532         dregs->fifo_count_hi = 0;
533         dregs->dma_addr_hi = 0;
534         dregs->dma_addr_lo = 0;
535         dregs->dma_count_hi = 0;
536         dregs->dma_count_lo = 0;
537
538         dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
539 #endif
540
541         NCR5380_maybe_reset_bus(instance);
542
543         error = scsi_add_host(instance, NULL);
544         if (error)
545                 goto fail_host;
546
547         platform_set_drvdata(pdev, instance);
548
549         scsi_scan_host(instance);
550         return 0;
551
552 fail_host:
553         free_irq(instance->irq, instance);
554 fail_irq:
555         NCR5380_exit(instance);
556 fail_init:
557         scsi_host_put(instance);
558 fail_alloc:
559         if (udc_regs)
560                 dvma_free(udc_regs);
561         iounmap(ioaddr);
562         return error;
563 }
564
565 static int __exit sun3_scsi_remove(struct platform_device *pdev)
566 {
567         struct Scsi_Host *instance = platform_get_drvdata(pdev);
568         struct NCR5380_hostdata *hostdata = shost_priv(instance);
569         void __iomem *ioaddr = hostdata->io;
570
571         scsi_remove_host(instance);
572         free_irq(instance->irq, instance);
573         NCR5380_exit(instance);
574         scsi_host_put(instance);
575         if (udc_regs)
576                 dvma_free(udc_regs);
577         iounmap(ioaddr);
578         return 0;
579 }
580
581 static struct platform_driver sun3_scsi_driver = {
582         .remove = __exit_p(sun3_scsi_remove),
583         .driver = {
584                 .name   = DRV_MODULE_NAME,
585         },
586 };
587
588 module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe);
589
590 MODULE_ALIAS("platform:" DRV_MODULE_NAME);
591 MODULE_LICENSE("GPL");