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