wdsc.c revision 1.1 1 /* $NetBSD: wdsc.c,v 1.1 1996/04/18 18:30:54 chuck Exp $ */
2
3 /*
4 * Copyright (c) 1996 Steve Woodford
5 * Copyright (c) 1982, 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)wdsc.c
37 */
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <scsi/scsi_all.h>
43 #include <scsi/scsiconf.h>
44 #include <mvme68k/mvme68k/isr.h>
45 #include <mvme68k/dev/iio.h>
46 #include <mvme68k/dev/pccreg.h>
47 #include <mvme68k/dev/dmavar.h>
48 #include <mvme68k/dev/sbicreg.h>
49 #include <mvme68k/dev/sbicvar.h>
50 #include <mvme68k/dev/wdscreg.h>
51
52 int wdscprint __P((void *auxp, char *));
53 void wdscattach __P((struct device *, struct device *, void *));
54 int wdscmatch __P((struct device *, struct cfdata *, void *));
55
56 void wdsc_enintr __P((struct sbic_softc *));
57 int wdsc_dmago __P((struct sbic_softc *, char *, int, int));
58 int wdsc_dmanext __P((struct sbic_softc *));
59 void wdsc_dmastop __P((struct sbic_softc *));
60 int wdsc_dmaintr __P((struct sbic_softc *));
61 int wdsc_scsiintr __P((struct sbic_softc *));
62
63 struct scsi_adapter wdsc_scsiswitch = {
64 sbic_scsicmd,
65 sbic_minphys,
66 0, /* no lun support */
67 0, /* no lun support */
68 };
69
70 struct scsi_device wdsc_scsidev = {
71 NULL, /* use default error handler */
72 NULL, /* do not have a start functio */
73 NULL, /* have no async handler */
74 NULL, /* Use default done routine */
75 };
76
77 struct cfattach wdsc_ca = {
78 sizeof(struct sbic_softc), (cfmatch_t)wdscmatch, wdscattach
79 };
80
81 struct cfdriver wdsc_cd = {
82 NULL, "wdsc", DV_DULL, NULL, 0
83 };
84
85 /*
86 * Define 'scsi_nosync = 0x00' to enable sync SCSI mode.
87 * This is untested as yet, use at your own risk...
88 */
89 u_long scsi_nosync = 0xff;
90 int shift_nosync = 0;
91
92 /*
93 * Match for SCSI devices on the onboard WD33C93 chip
94 */
95 int
96 wdscmatch(pdp, cdp, auxp)
97 struct device *pdp;
98 struct cfdata *cdp;
99 void *auxp;
100 {
101 /*
102 * Match everything
103 */
104 return(1);
105 }
106
107
108 /*
109 * Attach the wdsc driver
110 */
111 void
112 wdscattach(pdp, dp, auxp)
113 struct device *pdp, *dp;
114 void *auxp;
115 {
116 struct sbic_softc *sc = (struct sbic_softc *)dp;
117 int ipl;
118 static int attached = 0;
119
120 if ( attached )
121 panic("wdsc: Driver already attached!");
122
123 attached = 1;
124
125 iio_print(dp->dv_cfdata);
126
127 sc->sc_enintr = wdsc_enintr;
128 sc->sc_dmago = wdsc_dmago;
129 sc->sc_dmanext = wdsc_dmanext;
130 sc->sc_dmastop = wdsc_dmastop;
131 sc->sc_dmacmd = 0;
132
133 sc->sc_link.adapter_softc = sc;
134 sc->sc_link.adapter_target = 7;
135 sc->sc_link.adapter = &wdsc_scsiswitch;
136 sc->sc_link.device = &wdsc_scsidev;
137 sc->sc_link.openings = 2;
138
139 printf(": target %d\n", sc->sc_link.adapter_target);
140
141 sc->sc_cregs = (volatile void *)sys_pcc;
142 sc->sc_sbicp = (sbic_regmap_p) IIO_CFLOC_ADDR(dp->dv_cfdata);
143
144 /*
145 * Eveything is a valid dma address.
146 *
147 */
148 sc->sc_dmamask = 0;
149
150 /*
151 * The onboard WD33C93 of the '147 is usually clocked at 10MHz...
152 * (We use 10 times this for accuracy in later calculations)
153 */
154 sc->sc_clkfreq = 100;
155
156 /*
157 * Initialise the hardware
158 */
159 sbicinit(sc);
160
161 /*
162 * Fix up the interrupts
163 */
164 sc->sc_ipl = IIO_CFLOC_LEVEL(dp->dv_cfdata) & PCC_IMASK;
165
166 sys_pcc->scsi_int = sc->sc_ipl | PCC_ICLEAR;
167 sys_pcc->dma_int = sc->sc_ipl | PCC_ICLEAR;
168 sys_pcc->dma_csr = 0;
169
170 pccintr_establish(PCCV_SCSID, wdsc_dmaintr, sc->sc_ipl, sc);
171 pccintr_establish(PCCV_SCSIP, wdsc_scsiintr, sc->sc_ipl, sc);
172
173 sys_pcc->scsi_int = sc->sc_ipl | PCC_IENABLE | PCC_ICLEAR;
174
175 /*
176 * Attach all scsi units on us
177 */
178 config_found(dp, &sc->sc_link, wdscprint);
179 }
180
181 /*
182 * print diag if pnp is NULL else just extra
183 */
184 int
185 wdscprint(auxp, pnp)
186 void *auxp;
187 char *pnp;
188 {
189 if (pnp == NULL)
190 return(UNCONF);
191 return(QUIET);
192 }
193
194
195 /*
196 * Enable DMA interrupts
197 */
198 void
199 wdsc_enintr(dev)
200 struct sbic_softc *dev;
201 {
202 volatile struct pcc *pc = dev->sc_cregs;
203
204 dev->sc_flags |= SBICF_INTR;
205
206 pc->dma_int = dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR;
207 }
208
209 /*
210 * Prime the hardware for a DMA transfer
211 */
212 int
213 wdsc_dmago(dev, addr, count, flags)
214 struct sbic_softc *dev;
215 char *addr;
216 int count, flags;
217 {
218 volatile struct pcc *pc = dev->sc_cregs;
219
220 /*
221 * Set up the command word based on flags
222 */
223 if ( (flags & DMAGO_READ) == 0 )
224 dev->sc_dmacmd = DMAC_CSR_ENABLE | DMAC_CSR_WRITE;
225 else
226 dev->sc_dmacmd = DMAC_CSR_ENABLE;
227
228 dev->sc_flags |= SBICF_INTR;
229 dev->sc_tcnt = dev->sc_cur->dc_count << 1;
230
231 /*
232 * Prime the hardware.
233 * Note, it's probably not necessary to do this here, since dmanext
234 * is called just prior to the actual transfer.
235 */
236 pc->dma_csr = 0;
237 pc->dma_int = dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR;
238 pc->dma_daddr = (unsigned long)dev->sc_cur->dc_addr;
239 pc->dma_bcnt = (unsigned long)dev->sc_tcnt | (1 << 24);
240 pc->dma_csr = dev->sc_dmacmd;
241
242 return(dev->sc_tcnt);
243 }
244
245 /*
246 * Prime the hardware for the next DMA transfer
247 */
248 int
249 wdsc_dmanext(dev)
250 struct sbic_softc *dev;
251 {
252 volatile struct pcc *pc = dev->sc_cregs;
253
254 if ( dev->sc_cur > dev->sc_last ) {
255 /*
256 * Shouldn't happen !!
257 */
258 printf("wdsc_dmanext at end !!!\n");
259 wdsc_dmastop(dev);
260 return(0);
261 }
262
263 dev->sc_tcnt = dev->sc_cur->dc_count << 1;
264
265 /*
266 * Load the next DMA address
267 */
268 pc->dma_csr = 0;
269 pc->dma_int = dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR;
270 pc->dma_daddr = (unsigned long)dev->sc_cur->dc_addr;
271 pc->dma_bcnt = (unsigned long)dev->sc_tcnt | (1 << 24);
272 pc->dma_csr = dev->sc_dmacmd;
273
274 return(dev->sc_tcnt);
275 }
276
277 /*
278 * Stop DMA, and disable interrupts
279 */
280 void
281 wdsc_dmastop(dev)
282 struct sbic_softc *dev;
283 {
284 volatile struct pcc *pc = dev->sc_cregs;
285 int s;
286
287 s = splbio();
288
289 pc->dma_csr = 0;
290 pc->dma_int = dev->sc_ipl | PCC_ICLEAR;
291
292 splx(s);
293 }
294
295 /*
296 * Come here following a DMA interrupt
297 */
298 int
299 wdsc_dmaintr(dev)
300 struct sbic_softc *dev;
301 {
302 volatile struct pcc *pc = dev->sc_cregs;
303 int found = 0;
304
305 /*
306 * Really a DMA interrupt?
307 */
308 if ( (pc->dma_int & 0x80) == 0 )
309 return(0);
310
311 /*
312 * Was it a completion interrupt?
313 * XXXSCW Note: Support for other DMA interrupts is required, eg. buserr
314 */
315 if ( pc->dma_csr & DMAC_CSR_DONE ) {
316 ++found;
317
318 pc->dma_int = dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR;
319 }
320
321 return(found);
322 }
323
324 /*
325 * Come here for SCSI interrupts
326 */
327 int
328 wdsc_scsiintr(dev)
329 struct sbic_softc *dev;
330 {
331 volatile struct pcc *pc = dev->sc_cregs;
332 int found;
333
334 /*
335 * Really a SCSI interrupt?
336 */
337 if ( (pc->scsi_int & 0x80) == 0 )
338 return(0);
339
340 /*
341 * Go handle it
342 */
343 found = sbicintr(dev);
344
345 /*
346 * Acknowledge and clear the interrupt
347 */
348 pc->scsi_int = dev->sc_ipl | PCC_IENABLE | PCC_ICLEAR;
349
350 return(found);
351 }
352