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