1 /* $NetBSD: wdsc.c,v 1.30 2008/01/12 09:54:27 tsutsui Exp $ */
4 * Copyright (c) 1982, 1990 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
35 * Copyright (c) 1996-2004 The NetBSD Foundation, Inc.
36 * All rights reserved.
38 * This code is derived from software contributed to The NetBSD Foundation
39 * by Steve C. Woodford.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
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.
50 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60 * POSSIBILITY OF SUCH DAMAGE.
63 #include <sys/cdefs.h>
64 __KERNEL_RCSID(0, "$NetBSD: wdsc.c,v 1.30 2008/01/12 09:54:27 tsutsui Exp $");
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/kernel.h>
69 #include <sys/device.h>
71 #include <dev/scsipi/scsi_all.h>
72 #include <dev/scsipi/scsipi_all.h>
73 #include <dev/scsipi/scsiconf.h>
75 #include <machine/cpu.h>
76 #include <machine/bus.h>
77 #include <machine/autoconf.h>
79 #include <mvme68k/dev/dmavar.h>
80 #include <mvme68k/dev/pccreg.h>
81 #include <mvme68k/dev/pccvar.h>
82 #include <mvme68k/dev/sbicreg.h>
83 #include <mvme68k/dev/sbicvar.h>
84 #include <mvme68k/dev/wdscreg.h>
88 void wdsc_pcc_attach(struct device
*, struct device
*, void *);
89 int wdsc_pcc_match(struct device
*, struct cfdata
*, void *);
91 CFATTACH_DECL(wdsc_pcc
, sizeof(struct sbic_softc
),
92 wdsc_pcc_match
, wdsc_pcc_attach
, NULL
, NULL
);
94 void wdsc_enintr(struct sbic_softc
*);
95 int wdsc_dmago(struct sbic_softc
*, char *, int, int);
96 int wdsc_dmanext(struct sbic_softc
*);
97 void wdsc_dmastop(struct sbic_softc
*);
98 int wdsc_dmaintr(void *);
99 int wdsc_scsiintr(void *);
102 * Match for SCSI devices on the onboard WD33C93 chip
105 wdsc_pcc_match(struct device
*pdp
, struct cfdata
*cf
, void *auxp
)
107 struct pcc_attach_args
*pa
= auxp
;
109 if (strcmp(pa
->pa_name
, wdsc_cd
.cd_name
))
112 pa
->pa_ipl
= cf
->pcccf_ipl
;
117 * Attach the wdsc driver
120 wdsc_pcc_attach(struct device
*pdp
, struct device
*dp
, void *auxp
)
122 struct sbic_softc
*sc
;
123 struct pcc_attach_args
*pa
;
124 bus_space_handle_t bush
;
125 static struct evcnt evcnt
; /* XXXSCW: Temporary hack */
127 sc
= (struct sbic_softc
*)dp
;
130 bus_space_map(pa
->pa_bust
, pa
->pa_offset
, 0x20, 0, &bush
);
133 * XXXSCW: We *need* an MI, bus_spaced WD33C93 driver...
135 sc
->sc_sbicp
= (sbic_regmap_p
) bush
;
137 sc
->sc_driver
= (void *) &evcnt
;
138 sc
->sc_enintr
= wdsc_enintr
;
139 sc
->sc_dmago
= wdsc_dmago
;
140 sc
->sc_dmanext
= wdsc_dmanext
;
141 sc
->sc_dmastop
= wdsc_dmastop
;
144 sc
->sc_adapter
.adapt_dev
= &sc
->sc_dev
;
145 sc
->sc_adapter
.adapt_nchannels
= 1;
146 sc
->sc_adapter
.adapt_openings
= 7;
147 sc
->sc_adapter
.adapt_max_periph
= 1;
148 sc
->sc_adapter
.adapt_ioctl
= NULL
;
149 sc
->sc_adapter
.adapt_minphys
= sbic_minphys
;
150 sc
->sc_adapter
.adapt_request
= sbic_scsi_request
;
152 sc
->sc_channel
.chan_adapter
= &sc
->sc_adapter
;
153 sc
->sc_channel
.chan_bustype
= &scsi_bustype
;
154 sc
->sc_channel
.chan_channel
= 0;
155 sc
->sc_channel
.chan_ntargets
= 8;
156 sc
->sc_channel
.chan_nluns
= 8;
157 sc
->sc_channel
.chan_id
= 7;
159 printf(": WD33C93 SCSI, target %d\n", sc
->sc_channel
.chan_id
);
162 * Everything is a valid DMA address.
167 * The onboard WD33C93 of the '147 is usually clocked at 10MHz...
168 * (We use 10 times this for accuracy in later calculations)
170 sc
->sc_clkfreq
= 100;
173 * Initialise the hardware
178 * Fix up the interrupts
180 sc
->sc_ipl
= pa
->pa_ipl
& PCC_IMASK
;
182 pcc_reg_write(sys_pcc
, PCCREG_SCSI_INTR_CTRL
, PCC_ICLEAR
);
183 pcc_reg_write(sys_pcc
, PCCREG_DMA_INTR_CTRL
, PCC_ICLEAR
);
184 pcc_reg_write(sys_pcc
, PCCREG_DMA_CONTROL
, 0);
186 evcnt_attach_dynamic(&evcnt
, EVCNT_TYPE_INTR
, pccintr_evcnt(sc
->sc_ipl
),
187 "disk", sc
->sc_dev
.dv_xname
);
188 pccintr_establish(PCCV_DMA
, wdsc_dmaintr
, sc
->sc_ipl
, sc
, &evcnt
);
189 pccintr_establish(PCCV_SCSI
, wdsc_scsiintr
, sc
->sc_ipl
, sc
, &evcnt
);
190 pcc_reg_write(sys_pcc
, PCCREG_SCSI_INTR_CTRL
,
191 sc
->sc_ipl
| PCC_IENABLE
| PCC_ICLEAR
);
193 (void)config_found(dp
, &sc
->sc_channel
, scsiprint
);
197 * Enable DMA interrupts
200 wdsc_enintr(struct sbic_softc
*dev
)
203 dev
->sc_flags
|= SBICF_INTR
;
205 pcc_reg_write(sys_pcc
, PCCREG_DMA_INTR_CTRL
,
206 dev
->sc_ipl
| PCC_IENABLE
| PCC_ICLEAR
);
210 * Prime the hardware for a DMA transfer
213 wdsc_dmago(struct sbic_softc
*dev
, char *addr
, int count
, int flags
)
217 * Set up the command word based on flags
219 if ((flags
& DMAGO_READ
) == 0)
220 dev
->sc_dmacmd
= DMAC_CSR_ENABLE
| DMAC_CSR_WRITE
;
222 dev
->sc_dmacmd
= DMAC_CSR_ENABLE
;
224 dev
->sc_flags
|= SBICF_INTR
;
225 dev
->sc_tcnt
= dev
->sc_cur
->dc_count
<< 1;
228 * Prime the hardware.
229 * Note, it's probably not necessary to do this here, since dmanext
230 * is called just prior to the actual transfer.
232 pcc_reg_write(sys_pcc
, PCCREG_DMA_CONTROL
, 0);
233 pcc_reg_write(sys_pcc
, PCCREG_DMA_INTR_CTRL
,
234 dev
->sc_ipl
| PCC_IENABLE
| PCC_ICLEAR
);
235 pcc_reg_write32(sys_pcc
, PCCREG_DMA_DATA_ADDR
,
236 (uint32_t) dev
->sc_cur
->dc_addr
);
237 pcc_reg_write32(sys_pcc
, PCCREG_DMA_BYTE_COUNT
,
238 (uint32_t) dev
->sc_tcnt
| (1 << 24));
239 pcc_reg_write(sys_pcc
, PCCREG_DMA_CONTROL
, dev
->sc_dmacmd
);
245 * Prime the hardware for the next DMA transfer
248 wdsc_dmanext(struct sbic_softc
*dev
)
251 if (dev
->sc_cur
> dev
->sc_last
) {
253 * Shouldn't happen !!
255 printf("wdsc_dmanext at end !!!\n");
260 dev
->sc_tcnt
= dev
->sc_cur
->dc_count
<< 1;
263 * Load the next DMA address
265 pcc_reg_write(sys_pcc
, PCCREG_DMA_CONTROL
, 0);
266 pcc_reg_write(sys_pcc
, PCCREG_DMA_INTR_CTRL
,
267 dev
->sc_ipl
| PCC_IENABLE
| PCC_ICLEAR
);
268 pcc_reg_write32(sys_pcc
, PCCREG_DMA_DATA_ADDR
,
269 (uint32_t) dev
->sc_cur
->dc_addr
);
270 pcc_reg_write32(sys_pcc
, PCCREG_DMA_BYTE_COUNT
,
271 (uint32_t) dev
->sc_tcnt
| (1 << 24));
272 pcc_reg_write(sys_pcc
, PCCREG_DMA_CONTROL
, dev
->sc_dmacmd
);
278 * Stop DMA, and disable interrupts
281 wdsc_dmastop(struct sbic_softc
*dev
)
287 pcc_reg_write(sys_pcc
, PCCREG_DMA_CONTROL
, 0);
288 pcc_reg_write(sys_pcc
, PCCREG_DMA_INTR_CTRL
, dev
->sc_ipl
| PCC_ICLEAR
);
294 * Come here following a DMA interrupt
297 wdsc_dmaintr(void *arg
)
299 struct sbic_softc
*dev
= arg
;
303 * Really a DMA interrupt?
305 if ((pcc_reg_read(sys_pcc
, PCCREG_DMA_INTR_CTRL
) & 0x80) == 0)
309 * Was it a completion interrupt?
310 * XXXSCW Note: Support for other DMA interrupts is required,
313 if (pcc_reg_read(sys_pcc
, PCCREG_DMA_CONTROL
) & DMAC_CSR_DONE
) {
316 pcc_reg_write(sys_pcc
, PCCREG_DMA_INTR_CTRL
,
317 dev
->sc_ipl
| PCC_IENABLE
| PCC_ICLEAR
);
324 * Come here for SCSI interrupts
327 wdsc_scsiintr(void *arg
)
329 struct sbic_softc
*dev
= arg
;
333 * Really a SCSI interrupt?
335 if ((pcc_reg_read(sys_pcc
, PCCREG_SCSI_INTR_CTRL
) & 0x80) == 0)
341 found
= sbicintr(dev
);
344 * Acknowledge and clear the interrupt
346 pcc_reg_write(sys_pcc
, PCCREG_SCSI_INTR_CTRL
,
347 dev
->sc_ipl
| PCC_IENABLE
| PCC_ICLEAR
);