xref: /openbmc/linux/drivers/scsi/a3000.c (revision 21351013402ab4556d1ef62aed6cbe8dfb809f77)
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 #define HDATA(ptr)	((struct WD33C93_hostdata *)((ptr)->hostdata))
27 
28 static struct Scsi_Host *a3000_host = NULL;
29 
30 static int a3000_release(struct Scsi_Host *instance);
31 
32 static irqreturn_t a3000_intr(int irq, void *dummy)
33 {
34 	unsigned long flags;
35 	unsigned int status = DMA(a3000_host)->ISTR;
36 
37 	if (!(status & ISTR_INT_P))
38 		return IRQ_NONE;
39 	if (status & ISTR_INTS) {
40 		spin_lock_irqsave(a3000_host->host_lock, flags);
41 		wd33c93_intr(a3000_host);
42 		spin_unlock_irqrestore(a3000_host->host_lock, flags);
43 		return IRQ_HANDLED;
44 	}
45 	printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
46 	return IRQ_NONE;
47 }
48 
49 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
50 {
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(a3000_host)->dma_bounce_len =
62 			(cmd->SCp.this_residual + 511) & ~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 
101 	/* start DMA */
102 	mb();			/* make sure setup is completed */
103 	DMA(a3000_host)->ST_DMA = 1;
104 	mb();			/* make sure DMA has started before next IO */
105 
106 	/* return success */
107 	return 0;
108 }
109 
110 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
111 		     int status)
112 {
113 	/* disable SCSI interrupts */
114 	unsigned short cntr = CNTR_PDMD;
115 
116 	if (!HDATA(instance)->dma_dir)
117 		cntr |= CNTR_DDIR;
118 
119 	DMA(instance)->CNTR = cntr;
120 	mb();			/* make sure CNTR is updated before next IO */
121 
122 	/* flush if we were reading */
123 	if (HDATA(instance)->dma_dir) {
124 		DMA(instance)->FLUSH = 1;
125 		mb();		/* don't allow prefetch */
126 		while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
127 			barrier();
128 		mb();		/* no IO until FLUSH is done */
129 	}
130 
131 	/* clear a possible interrupt */
132 	/* I think that this CINT is only necessary if you are
133 	 * using the terminal count features.   HM 7 Mar 1994
134 	 */
135 	DMA(instance)->CINT = 1;
136 
137 	/* stop DMA */
138 	DMA(instance)->SP_DMA = 1;
139 	mb();			/* make sure DMA is stopped before next IO */
140 
141 	/* restore the CONTROL bits (minus the direction flag) */
142 	DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
143 	mb();			/* make sure CNTR is updated before next IO */
144 
145 	/* copy from a bounce buffer, if necessary */
146 	if (status && HDATA(instance)->dma_bounce_buffer) {
147 		if (SCpnt) {
148 			if (HDATA(instance)->dma_dir && SCpnt)
149 				memcpy(SCpnt->SCp.ptr,
150 				       HDATA(instance)->dma_bounce_buffer,
151 				       SCpnt->SCp.this_residual);
152 			kfree(HDATA(instance)->dma_bounce_buffer);
153 			HDATA(instance)->dma_bounce_buffer = NULL;
154 			HDATA(instance)->dma_bounce_len = 0;
155 		} else {
156 			kfree(HDATA(instance)->dma_bounce_buffer);
157 			HDATA(instance)->dma_bounce_buffer = NULL;
158 			HDATA(instance)->dma_bounce_len = 0;
159 		}
160 	}
161 }
162 
163 static int __init a3000_detect(struct scsi_host_template *tpnt)
164 {
165 	wd33c93_regs regs;
166 
167 	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
168 		return 0;
169 	if (!request_mem_region(0xDD0000, 256, "wd33c93"))
170 		return 0;
171 
172 	tpnt->proc_name = "A3000";
173 	tpnt->proc_info = &wd33c93_proc_info;
174 
175 	a3000_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
176 	if (a3000_host == NULL)
177 		goto fail_register;
178 
179 	a3000_host->base = ZTWO_VADDR(0xDD0000);
180 	a3000_host->irq = IRQ_AMIGA_PORTS;
181 	DMA(a3000_host)->DAWR = DAWR_A3000;
182 	regs.SASR = &(DMA(a3000_host)->SASR);
183 	regs.SCMD = &(DMA(a3000_host)->SCMD);
184 	HDATA(a3000_host)->no_sync = 0xff;
185 	HDATA(a3000_host)->fast = 0;
186 	HDATA(a3000_host)->dma_mode = CTRL_DMA;
187 	wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
188 	if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
189 			a3000_intr))
190 		goto fail_irq;
191 	DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
192 
193 	return 1;
194 
195 fail_irq:
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 	DMA(instance)->CNTR = 0;
240 	release_mem_region(0xDD0000, 256);
241 	free_irq(IRQ_AMIGA_PORTS, a3000_intr);
242 	return 1;
243 }
244 
245 MODULE_LICENSE("GPL");
246