wdsc.c revision 1.27 1 /* $NetBSD: wdsc.c,v 1.27 2003/08/07 16:28:41 agc Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)wdsc.c
32 */
33
34 /*
35 * Copyright (c) 1996 Steve Woodford
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * @(#)wdsc.c
66 */
67
68 #include <sys/cdefs.h>
69 __KERNEL_RCSID(0, "$NetBSD: wdsc.c,v 1.27 2003/08/07 16:28:41 agc Exp $");
70
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
74 #include <sys/device.h>
75
76 #include <dev/scsipi/scsi_all.h>
77 #include <dev/scsipi/scsipi_all.h>
78 #include <dev/scsipi/scsiconf.h>
79
80 #include <machine/cpu.h>
81 #include <machine/bus.h>
82 #include <machine/autoconf.h>
83
84 #include <mvme68k/dev/dmavar.h>
85 #include <mvme68k/dev/pccreg.h>
86 #include <mvme68k/dev/pccvar.h>
87 #include <mvme68k/dev/sbicreg.h>
88 #include <mvme68k/dev/sbicvar.h>
89 #include <mvme68k/dev/wdscreg.h>
90
91 void wdsc_pcc_attach __P((struct device *, struct device *, void *));
92 int wdsc_pcc_match __P((struct device *, struct cfdata *, void *));
93
94 CFATTACH_DECL(wdsc_pcc, sizeof(struct sbic_softc),
95 wdsc_pcc_match, wdsc_pcc_attach, NULL, NULL);
96
97 extern struct cfdriver wdsc_cd;
98
99 void wdsc_enintr __P((struct sbic_softc *));
100 int wdsc_dmago __P((struct sbic_softc *, char *, int, int));
101 int wdsc_dmanext __P((struct sbic_softc *));
102 void wdsc_dmastop __P((struct sbic_softc *));
103 int wdsc_dmaintr __P((void *));
104 int wdsc_scsiintr __P((void *));
105
106 /*
107 * Match for SCSI devices on the onboard WD33C93 chip
108 */
109 int
110 wdsc_pcc_match(pdp, cf, auxp)
111 struct device *pdp;
112 struct cfdata *cf;
113 void *auxp;
114 {
115 struct pcc_attach_args *pa = auxp;
116
117 if (strcmp(pa->pa_name, wdsc_cd.cd_name))
118 return (0);
119
120 pa->pa_ipl = cf->pcccf_ipl;
121 return (1);
122 }
123
124 /*
125 * Attach the wdsc driver
126 */
127 void
128 wdsc_pcc_attach(pdp, dp, auxp)
129 struct device *pdp, *dp;
130 void *auxp;
131 {
132 struct sbic_softc *sc;
133 struct pcc_attach_args *pa;
134 bus_space_handle_t bush;
135 static struct evcnt evcnt; /* XXXSCW: Temporary hack */
136
137 sc = (struct sbic_softc *)dp;
138 pa = auxp;
139
140 bus_space_map(pa->pa_bust, pa->pa_offset, 0x20, 0, &bush);
141
142 /*
143 * XXXSCW: We *need* an MI, bus_spaced WD33C93 driver...
144 */
145 sc->sc_sbicp = (sbic_regmap_p) bush;
146
147 sc->sc_driver = (void *) &evcnt;
148 sc->sc_enintr = wdsc_enintr;
149 sc->sc_dmago = wdsc_dmago;
150 sc->sc_dmanext = wdsc_dmanext;
151 sc->sc_dmastop = wdsc_dmastop;
152 sc->sc_dmacmd = 0;
153
154 sc->sc_adapter.adapt_dev = &sc->sc_dev;
155 sc->sc_adapter.adapt_nchannels = 1;
156 sc->sc_adapter.adapt_openings = 7;
157 sc->sc_adapter.adapt_max_periph = 1;
158 sc->sc_adapter.adapt_ioctl = NULL;
159 sc->sc_adapter.adapt_minphys = sbic_minphys;
160 sc->sc_adapter.adapt_request = sbic_scsi_request;
161
162 sc->sc_channel.chan_adapter = &sc->sc_adapter;
163 sc->sc_channel.chan_bustype = &scsi_bustype;
164 sc->sc_channel.chan_channel = 0;
165 sc->sc_channel.chan_ntargets = 8;
166 sc->sc_channel.chan_nluns = 8;
167 sc->sc_channel.chan_id = 7;
168
169 printf(": WD33C93 SCSI, target %d\n", sc->sc_channel.chan_id);
170
171 /*
172 * Everything is a valid DMA address.
173 */
174 sc->sc_dmamask = 0;
175
176 /*
177 * The onboard WD33C93 of the '147 is usually clocked at 10MHz...
178 * (We use 10 times this for accuracy in later calculations)
179 */
180 sc->sc_clkfreq = 100;
181
182 /*
183 * Initialise the hardware
184 */
185 sbicinit(sc);
186
187 /*
188 * Fix up the interrupts
189 */
190 sc->sc_ipl = pa->pa_ipl & PCC_IMASK;
191
192 pcc_reg_write(sys_pcc, PCCREG_SCSI_INTR_CTRL, PCC_ICLEAR);
193 pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, PCC_ICLEAR);
194 pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0);
195
196 evcnt_attach_dynamic(&evcnt, EVCNT_TYPE_INTR, pccintr_evcnt(sc->sc_ipl),
197 "disk", sc->sc_dev.dv_xname);
198 pccintr_establish(PCCV_DMA, wdsc_dmaintr, sc->sc_ipl, sc, &evcnt);
199 pccintr_establish(PCCV_SCSI, wdsc_scsiintr, sc->sc_ipl, sc, &evcnt);
200 pcc_reg_write(sys_pcc, PCCREG_SCSI_INTR_CTRL,
201 sc->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
202
203 (void)config_found(dp, &sc->sc_channel, scsiprint);
204 }
205
206 /*
207 * Enable DMA interrupts
208 */
209 void
210 wdsc_enintr(dev)
211 struct sbic_softc *dev;
212 {
213 dev->sc_flags |= SBICF_INTR;
214
215 pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL,
216 dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
217 }
218
219 /*
220 * Prime the hardware for a DMA transfer
221 */
222 int
223 wdsc_dmago(dev, addr, count, flags)
224 struct sbic_softc *dev;
225 char *addr;
226 int count, flags;
227 {
228 /*
229 * Set up the command word based on flags
230 */
231 if ( (flags & DMAGO_READ) == 0 )
232 dev->sc_dmacmd = DMAC_CSR_ENABLE | DMAC_CSR_WRITE;
233 else
234 dev->sc_dmacmd = DMAC_CSR_ENABLE;
235
236 dev->sc_flags |= SBICF_INTR;
237 dev->sc_tcnt = dev->sc_cur->dc_count << 1;
238
239 /*
240 * Prime the hardware.
241 * Note, it's probably not necessary to do this here, since dmanext
242 * is called just prior to the actual transfer.
243 */
244 pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0);
245 pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL,
246 dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
247 pcc_reg_write32(sys_pcc, PCCREG_DMA_DATA_ADDR,
248 (u_int32_t) dev->sc_cur->dc_addr);
249 pcc_reg_write32(sys_pcc, PCCREG_DMA_BYTE_COUNT,
250 (u_int32_t) dev->sc_tcnt | (1 << 24));
251 pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, dev->sc_dmacmd);
252
253 return(dev->sc_tcnt);
254 }
255
256 /*
257 * Prime the hardware for the next DMA transfer
258 */
259 int
260 wdsc_dmanext(dev)
261 struct sbic_softc *dev;
262 {
263 if ( dev->sc_cur > dev->sc_last ) {
264 /*
265 * Shouldn't happen !!
266 */
267 printf("wdsc_dmanext at end !!!\n");
268 wdsc_dmastop(dev);
269 return(0);
270 }
271
272 dev->sc_tcnt = dev->sc_cur->dc_count << 1;
273
274 /*
275 * Load the next DMA address
276 */
277 pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0);
278 pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL,
279 dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
280 pcc_reg_write32(sys_pcc, PCCREG_DMA_DATA_ADDR,
281 (u_int32_t) dev->sc_cur->dc_addr);
282 pcc_reg_write32(sys_pcc, PCCREG_DMA_BYTE_COUNT,
283 (u_int32_t) dev->sc_tcnt | (1 << 24));
284 pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, dev->sc_dmacmd);
285
286 return(dev->sc_tcnt);
287 }
288
289 /*
290 * Stop DMA, and disable interrupts
291 */
292 void
293 wdsc_dmastop(dev)
294 struct sbic_softc *dev;
295 {
296 int s;
297
298 s = splbio();
299
300 pcc_reg_write(sys_pcc, PCCREG_DMA_CONTROL, 0);
301 pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL, dev->sc_ipl | PCC_ICLEAR);
302
303 splx(s);
304 }
305
306 /*
307 * Come here following a DMA interrupt
308 */
309 int
310 wdsc_dmaintr(arg)
311 void *arg;
312 {
313 struct sbic_softc *dev = arg;
314 int found = 0;
315
316 /*
317 * Really a DMA interrupt?
318 */
319 if ( (pcc_reg_read(sys_pcc, PCCREG_DMA_INTR_CTRL) & 0x80) == 0 )
320 return(0);
321
322 /*
323 * Was it a completion interrupt?
324 * XXXSCW Note: Support for other DMA interrupts is required, eg. buserr
325 */
326 if ( pcc_reg_read(sys_pcc, PCCREG_DMA_CONTROL) & DMAC_CSR_DONE ) {
327 ++found;
328
329 pcc_reg_write(sys_pcc, PCCREG_DMA_INTR_CTRL,
330 dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
331 }
332
333 return(found);
334 }
335
336 /*
337 * Come here for SCSI interrupts
338 */
339 int
340 wdsc_scsiintr(arg)
341 void *arg;
342 {
343 struct sbic_softc *dev = arg;
344 int found;
345
346 /*
347 * Really a SCSI interrupt?
348 */
349 if ( (pcc_reg_read(sys_pcc, PCCREG_SCSI_INTR_CTRL) & 0x80) == 0 )
350 return(0);
351
352 /*
353 * Go handle it
354 */
355 found = sbicintr(dev);
356
357 /*
358 * Acknowledge and clear the interrupt
359 */
360 pcc_reg_write(sys_pcc, PCCREG_SCSI_INTR_CTRL,
361 dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR);
362
363 return(found);
364 }
365