xref: /openbmc/linux/drivers/scsi/a3000.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds #include <linux/types.h>
2*1da177e4SLinus Torvalds #include <linux/mm.h>
3*1da177e4SLinus Torvalds #include <linux/blkdev.h>
4*1da177e4SLinus Torvalds #include <linux/sched.h>
5*1da177e4SLinus Torvalds #include <linux/ioport.h>
6*1da177e4SLinus Torvalds #include <linux/init.h>
7*1da177e4SLinus Torvalds #include <linux/spinlock.h>
8*1da177e4SLinus Torvalds #include <linux/interrupt.h>
9*1da177e4SLinus Torvalds 
10*1da177e4SLinus Torvalds #include <asm/setup.h>
11*1da177e4SLinus Torvalds #include <asm/page.h>
12*1da177e4SLinus Torvalds #include <asm/pgtable.h>
13*1da177e4SLinus Torvalds #include <asm/amigaints.h>
14*1da177e4SLinus Torvalds #include <asm/amigahw.h>
15*1da177e4SLinus Torvalds #include <asm/irq.h>
16*1da177e4SLinus Torvalds 
17*1da177e4SLinus Torvalds #include "scsi.h"
18*1da177e4SLinus Torvalds #include <scsi/scsi_host.h>
19*1da177e4SLinus Torvalds #include "wd33c93.h"
20*1da177e4SLinus Torvalds #include "a3000.h"
21*1da177e4SLinus Torvalds 
22*1da177e4SLinus Torvalds #include<linux/stat.h>
23*1da177e4SLinus Torvalds 
24*1da177e4SLinus Torvalds #define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
25*1da177e4SLinus Torvalds #define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
26*1da177e4SLinus Torvalds 
27*1da177e4SLinus Torvalds static struct Scsi_Host *a3000_host = NULL;
28*1da177e4SLinus Torvalds 
29*1da177e4SLinus Torvalds static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp)
30*1da177e4SLinus Torvalds {
31*1da177e4SLinus Torvalds 	unsigned long flags;
32*1da177e4SLinus Torvalds 	unsigned int status = DMA(a3000_host)->ISTR;
33*1da177e4SLinus Torvalds 
34*1da177e4SLinus Torvalds 	if (!(status & ISTR_INT_P))
35*1da177e4SLinus Torvalds 		return IRQ_NONE;
36*1da177e4SLinus Torvalds 	if (status & ISTR_INTS)
37*1da177e4SLinus Torvalds 	{
38*1da177e4SLinus Torvalds 		spin_lock_irqsave(a3000_host->host_lock, flags);
39*1da177e4SLinus Torvalds 		wd33c93_intr (a3000_host);
40*1da177e4SLinus Torvalds 		spin_unlock_irqrestore(a3000_host->host_lock, flags);
41*1da177e4SLinus Torvalds 		return IRQ_HANDLED;
42*1da177e4SLinus Torvalds 	}
43*1da177e4SLinus Torvalds 	printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
44*1da177e4SLinus Torvalds 	return IRQ_NONE;
45*1da177e4SLinus Torvalds }
46*1da177e4SLinus Torvalds 
47*1da177e4SLinus Torvalds static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
48*1da177e4SLinus Torvalds {
49*1da177e4SLinus Torvalds     unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
50*1da177e4SLinus Torvalds     unsigned long addr = virt_to_bus(cmd->SCp.ptr);
51*1da177e4SLinus Torvalds 
52*1da177e4SLinus Torvalds     /*
53*1da177e4SLinus Torvalds      * if the physical address has the wrong alignment, or if
54*1da177e4SLinus Torvalds      * physical address is bad, or if it is a write and at the
55*1da177e4SLinus Torvalds      * end of a physical memory chunk, then allocate a bounce
56*1da177e4SLinus Torvalds      * buffer
57*1da177e4SLinus Torvalds      */
58*1da177e4SLinus Torvalds     if (addr & A3000_XFER_MASK ||
59*1da177e4SLinus Torvalds 	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
60*1da177e4SLinus Torvalds     {
61*1da177e4SLinus Torvalds 	HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
62*1da177e4SLinus Torvalds 	    & ~0x1ff;
63*1da177e4SLinus Torvalds 	HDATA(a3000_host)->dma_bounce_buffer =
64*1da177e4SLinus Torvalds 	    kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL);
65*1da177e4SLinus Torvalds 
66*1da177e4SLinus Torvalds 	/* can't allocate memory; use PIO */
67*1da177e4SLinus Torvalds 	if (!HDATA(a3000_host)->dma_bounce_buffer) {
68*1da177e4SLinus Torvalds 	    HDATA(a3000_host)->dma_bounce_len = 0;
69*1da177e4SLinus Torvalds 	    return 1;
70*1da177e4SLinus Torvalds 	}
71*1da177e4SLinus Torvalds 
72*1da177e4SLinus Torvalds 	if (!dir_in) {
73*1da177e4SLinus Torvalds 	    /* copy to bounce buffer for a write */
74*1da177e4SLinus Torvalds 	    if (cmd->use_sg) {
75*1da177e4SLinus Torvalds 		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
76*1da177e4SLinus Torvalds 			cmd->SCp.ptr, cmd->SCp.this_residual);
77*1da177e4SLinus Torvalds 	    } else
78*1da177e4SLinus Torvalds 		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
79*1da177e4SLinus Torvalds 			cmd->request_buffer, cmd->request_bufflen);
80*1da177e4SLinus Torvalds 	}
81*1da177e4SLinus Torvalds 
82*1da177e4SLinus Torvalds 	addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
83*1da177e4SLinus Torvalds     }
84*1da177e4SLinus Torvalds 
85*1da177e4SLinus Torvalds     /* setup dma direction */
86*1da177e4SLinus Torvalds     if (!dir_in)
87*1da177e4SLinus Torvalds 	cntr |= CNTR_DDIR;
88*1da177e4SLinus Torvalds 
89*1da177e4SLinus Torvalds     /* remember direction */
90*1da177e4SLinus Torvalds     HDATA(a3000_host)->dma_dir = dir_in;
91*1da177e4SLinus Torvalds 
92*1da177e4SLinus Torvalds     DMA(a3000_host)->CNTR = cntr;
93*1da177e4SLinus Torvalds 
94*1da177e4SLinus Torvalds     /* setup DMA *physical* address */
95*1da177e4SLinus Torvalds     DMA(a3000_host)->ACR = addr;
96*1da177e4SLinus Torvalds 
97*1da177e4SLinus Torvalds     if (dir_in)
98*1da177e4SLinus Torvalds   	/* invalidate any cache */
99*1da177e4SLinus Torvalds 	cache_clear (addr, cmd->SCp.this_residual);
100*1da177e4SLinus Torvalds     else
101*1da177e4SLinus Torvalds 	/* push any dirty cache */
102*1da177e4SLinus Torvalds 	cache_push (addr, cmd->SCp.this_residual);
103*1da177e4SLinus Torvalds 
104*1da177e4SLinus Torvalds     /* start DMA */
105*1da177e4SLinus Torvalds     mb();			/* make sure setup is completed */
106*1da177e4SLinus Torvalds     DMA(a3000_host)->ST_DMA = 1;
107*1da177e4SLinus Torvalds     mb();			/* make sure DMA has started before next IO */
108*1da177e4SLinus Torvalds 
109*1da177e4SLinus Torvalds     /* return success */
110*1da177e4SLinus Torvalds     return 0;
111*1da177e4SLinus Torvalds }
112*1da177e4SLinus Torvalds 
113*1da177e4SLinus Torvalds static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
114*1da177e4SLinus Torvalds 		      int status)
115*1da177e4SLinus Torvalds {
116*1da177e4SLinus Torvalds     /* disable SCSI interrupts */
117*1da177e4SLinus Torvalds     unsigned short cntr = CNTR_PDMD;
118*1da177e4SLinus Torvalds 
119*1da177e4SLinus Torvalds     if (!HDATA(instance)->dma_dir)
120*1da177e4SLinus Torvalds 	cntr |= CNTR_DDIR;
121*1da177e4SLinus Torvalds 
122*1da177e4SLinus Torvalds     DMA(instance)->CNTR = cntr;
123*1da177e4SLinus Torvalds     mb();			/* make sure CNTR is updated before next IO */
124*1da177e4SLinus Torvalds 
125*1da177e4SLinus Torvalds     /* flush if we were reading */
126*1da177e4SLinus Torvalds     if (HDATA(instance)->dma_dir) {
127*1da177e4SLinus Torvalds 	DMA(instance)->FLUSH = 1;
128*1da177e4SLinus Torvalds 	mb();			/* don't allow prefetch */
129*1da177e4SLinus Torvalds 	while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
130*1da177e4SLinus Torvalds 	    barrier();
131*1da177e4SLinus Torvalds 	mb();			/* no IO until FLUSH is done */
132*1da177e4SLinus Torvalds     }
133*1da177e4SLinus Torvalds 
134*1da177e4SLinus Torvalds     /* clear a possible interrupt */
135*1da177e4SLinus Torvalds     /* I think that this CINT is only necessary if you are
136*1da177e4SLinus Torvalds      * using the terminal count features.   HM 7 Mar 1994
137*1da177e4SLinus Torvalds      */
138*1da177e4SLinus Torvalds     DMA(instance)->CINT = 1;
139*1da177e4SLinus Torvalds 
140*1da177e4SLinus Torvalds     /* stop DMA */
141*1da177e4SLinus Torvalds     DMA(instance)->SP_DMA = 1;
142*1da177e4SLinus Torvalds     mb();			/* make sure DMA is stopped before next IO */
143*1da177e4SLinus Torvalds 
144*1da177e4SLinus Torvalds     /* restore the CONTROL bits (minus the direction flag) */
145*1da177e4SLinus Torvalds     DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
146*1da177e4SLinus Torvalds     mb();			/* make sure CNTR is updated before next IO */
147*1da177e4SLinus Torvalds 
148*1da177e4SLinus Torvalds     /* copy from a bounce buffer, if necessary */
149*1da177e4SLinus Torvalds     if (status && HDATA(instance)->dma_bounce_buffer) {
150*1da177e4SLinus Torvalds 	if (SCpnt && SCpnt->use_sg) {
151*1da177e4SLinus Torvalds 	    if (HDATA(instance)->dma_dir && SCpnt)
152*1da177e4SLinus Torvalds 		memcpy (SCpnt->SCp.ptr,
153*1da177e4SLinus Torvalds 			HDATA(instance)->dma_bounce_buffer,
154*1da177e4SLinus Torvalds 			SCpnt->SCp.this_residual);
155*1da177e4SLinus Torvalds 	    kfree (HDATA(instance)->dma_bounce_buffer);
156*1da177e4SLinus Torvalds 	    HDATA(instance)->dma_bounce_buffer = NULL;
157*1da177e4SLinus Torvalds 	    HDATA(instance)->dma_bounce_len = 0;
158*1da177e4SLinus Torvalds 	} else {
159*1da177e4SLinus Torvalds 	    if (HDATA(instance)->dma_dir && SCpnt)
160*1da177e4SLinus Torvalds 		memcpy (SCpnt->request_buffer,
161*1da177e4SLinus Torvalds 			HDATA(instance)->dma_bounce_buffer,
162*1da177e4SLinus Torvalds 			SCpnt->request_bufflen);
163*1da177e4SLinus Torvalds 
164*1da177e4SLinus Torvalds 	    kfree (HDATA(instance)->dma_bounce_buffer);
165*1da177e4SLinus Torvalds 	    HDATA(instance)->dma_bounce_buffer = NULL;
166*1da177e4SLinus Torvalds 	    HDATA(instance)->dma_bounce_len = 0;
167*1da177e4SLinus Torvalds 	}
168*1da177e4SLinus Torvalds     }
169*1da177e4SLinus Torvalds }
170*1da177e4SLinus Torvalds 
171*1da177e4SLinus Torvalds int __init a3000_detect(Scsi_Host_Template *tpnt)
172*1da177e4SLinus Torvalds {
173*1da177e4SLinus Torvalds     wd33c93_regs regs;
174*1da177e4SLinus Torvalds 
175*1da177e4SLinus Torvalds     if  (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
176*1da177e4SLinus Torvalds 	return 0;
177*1da177e4SLinus Torvalds     if (!request_mem_region(0xDD0000, 256, "wd33c93"))
178*1da177e4SLinus Torvalds 	return 0;
179*1da177e4SLinus Torvalds 
180*1da177e4SLinus Torvalds     tpnt->proc_name = "A3000";
181*1da177e4SLinus Torvalds     tpnt->proc_info = &wd33c93_proc_info;
182*1da177e4SLinus Torvalds 
183*1da177e4SLinus Torvalds     a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
184*1da177e4SLinus Torvalds     if (a3000_host == NULL)
185*1da177e4SLinus Torvalds 	goto fail_register;
186*1da177e4SLinus Torvalds 
187*1da177e4SLinus Torvalds     a3000_host->base = ZTWO_VADDR(0xDD0000);
188*1da177e4SLinus Torvalds     a3000_host->irq = IRQ_AMIGA_PORTS;
189*1da177e4SLinus Torvalds     DMA(a3000_host)->DAWR = DAWR_A3000;
190*1da177e4SLinus Torvalds     regs.SASR = &(DMA(a3000_host)->SASR);
191*1da177e4SLinus Torvalds     regs.SCMD = &(DMA(a3000_host)->SCMD);
192*1da177e4SLinus Torvalds     wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
193*1da177e4SLinus Torvalds     if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, SA_SHIRQ, "A3000 SCSI",
194*1da177e4SLinus Torvalds 		    a3000_intr))
195*1da177e4SLinus Torvalds         goto fail_irq;
196*1da177e4SLinus Torvalds     DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
197*1da177e4SLinus Torvalds 
198*1da177e4SLinus Torvalds     return 1;
199*1da177e4SLinus Torvalds 
200*1da177e4SLinus Torvalds fail_irq:
201*1da177e4SLinus Torvalds     wd33c93_release();
202*1da177e4SLinus Torvalds     scsi_unregister(a3000_host);
203*1da177e4SLinus Torvalds fail_register:
204*1da177e4SLinus Torvalds     release_mem_region(0xDD0000, 256);
205*1da177e4SLinus Torvalds     return 0;
206*1da177e4SLinus Torvalds }
207*1da177e4SLinus Torvalds 
208*1da177e4SLinus Torvalds static int a3000_bus_reset(Scsi_Cmnd *cmd)
209*1da177e4SLinus Torvalds {
210*1da177e4SLinus Torvalds 	/* FIXME perform bus-specific reset */
211*1da177e4SLinus Torvalds 	wd33c93_host_reset(cmd);
212*1da177e4SLinus Torvalds 	return SUCCESS;
213*1da177e4SLinus Torvalds }
214*1da177e4SLinus Torvalds 
215*1da177e4SLinus Torvalds #define HOSTS_C
216*1da177e4SLinus Torvalds 
217*1da177e4SLinus Torvalds static Scsi_Host_Template driver_template = {
218*1da177e4SLinus Torvalds 	.proc_name		= "A3000",
219*1da177e4SLinus Torvalds 	.name			= "Amiga 3000 built-in SCSI",
220*1da177e4SLinus Torvalds 	.detect			= a3000_detect,
221*1da177e4SLinus Torvalds 	.release		= a3000_release,
222*1da177e4SLinus Torvalds 	.queuecommand		= wd33c93_queuecommand,
223*1da177e4SLinus Torvalds 	.eh_abort_handler	= wd33c93_abort,
224*1da177e4SLinus Torvalds 	.eh_bus_reset_handler	= a3000_bus_reset,
225*1da177e4SLinus Torvalds 	.eh_host_reset_handler	= wd33c93_host_reset,
226*1da177e4SLinus Torvalds 	.can_queue		= CAN_QUEUE,
227*1da177e4SLinus Torvalds 	.this_id		= 7,
228*1da177e4SLinus Torvalds 	.sg_tablesize		= SG_ALL,
229*1da177e4SLinus Torvalds 	.cmd_per_lun		= CMD_PER_LUN,
230*1da177e4SLinus Torvalds 	.use_clustering		= ENABLE_CLUSTERING
231*1da177e4SLinus Torvalds };
232*1da177e4SLinus Torvalds 
233*1da177e4SLinus Torvalds 
234*1da177e4SLinus Torvalds #include "scsi_module.c"
235*1da177e4SLinus Torvalds 
236*1da177e4SLinus Torvalds int a3000_release(struct Scsi_Host *instance)
237*1da177e4SLinus Torvalds {
238*1da177e4SLinus Torvalds     wd33c93_release();
239*1da177e4SLinus Torvalds     DMA(instance)->CNTR = 0;
240*1da177e4SLinus Torvalds     release_mem_region(0xDD0000, 256);
241*1da177e4SLinus Torvalds     free_irq(IRQ_AMIGA_PORTS, a3000_intr);
242*1da177e4SLinus Torvalds     return 1;
243*1da177e4SLinus Torvalds }
244*1da177e4SLinus Torvalds 
245*1da177e4SLinus Torvalds MODULE_LICENSE("GPL");
246