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