oiocsc.c revision 1.4 1 1.4 msaitoh /* $NetBSD: oiocsc.c,v 1.4 2019/12/27 09:41:50 msaitoh Exp $ */
2 1.1 rumble
3 1.1 rumble /*
4 1.1 rumble * Copyright (c) 2009 Stephen M. Rumble
5 1.1 rumble * Copyright (c) 2001 Wayne Knowles
6 1.1 rumble * All rights reserved.
7 1.1 rumble *
8 1.1 rumble * This code is derived from software contributed to The NetBSD Foundation
9 1.1 rumble * by Wayne Knowles
10 1.1 rumble *
11 1.1 rumble * Redistribution and use in source and binary forms, with or without
12 1.1 rumble * modification, are permitted provided that the following conditions
13 1.1 rumble * are met:
14 1.1 rumble * 1. Redistributions of source code must retain the above copyright
15 1.1 rumble * notice, this list of conditions and the following disclaimer.
16 1.1 rumble * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 rumble * notice, this list of conditions and the following disclaimer in the
18 1.1 rumble * documentation and/or other materials provided with the distribution.
19 1.1 rumble * 3. All advertising materials mentioning features or use of this software
20 1.1 rumble * must display the following acknowledgement:
21 1.1 rumble * This product includes software developed by the NetBSD
22 1.1 rumble * Foundation, Inc. and its contributors.
23 1.1 rumble * 4. Neither the name of The NetBSD Foundation nor the names of its
24 1.1 rumble * contributors may be used to endorse or promote products derived
25 1.1 rumble * from this software without specific prior written permission.
26 1.1 rumble *
27 1.1 rumble * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 1.1 rumble * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 1.1 rumble * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 1.1 rumble * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 1.1 rumble * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 1.1 rumble * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 1.1 rumble * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 1.1 rumble * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 1.1 rumble * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 1.1 rumble * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 1.1 rumble * POSSIBILITY OF SUCH DAMAGE.
38 1.1 rumble */
39 1.1 rumble
40 1.1 rumble #include <sys/cdefs.h>
41 1.4 msaitoh __KERNEL_RCSID(0, "$NetBSD: oiocsc.c,v 1.4 2019/12/27 09:41:50 msaitoh Exp $");
42 1.1 rumble
43 1.1 rumble #include <sys/param.h>
44 1.1 rumble #include <sys/systm.h>
45 1.1 rumble #include <sys/kernel.h>
46 1.1 rumble #include <sys/device.h>
47 1.1 rumble #include <sys/buf.h>
48 1.1 rumble
49 1.1 rumble #include <dev/scsipi/scsi_all.h>
50 1.1 rumble #include <dev/scsipi/scsipi_all.h>
51 1.1 rumble #include <dev/scsipi/scsiconf.h>
52 1.1 rumble
53 1.1 rumble #include <machine/cpu.h>
54 1.2 dyoung #include <sys/bus.h>
55 1.1 rumble #include <machine/autoconf.h>
56 1.1 rumble #include <machine/machtype.h>
57 1.1 rumble #include <machine/sysconf.h>
58 1.1 rumble
59 1.1 rumble #include <sgimips/ioc/oiocreg.h>
60 1.1 rumble #include <sgimips/ioc/oiocvar.h>
61 1.1 rumble
62 1.1 rumble #include <dev/ic/wd33c93reg.h>
63 1.1 rumble #include <dev/ic/wd33c93var.h>
64 1.1 rumble
65 1.1 rumble #include <opt_kgdb.h>
66 1.1 rumble #include <sys/kgdb.h>
67 1.1 rumble
68 1.1 rumble struct oiocsc_softc {
69 1.1 rumble struct wd33c93_softc sc_wd33c93; /* Must be first */
70 1.1 rumble struct evcnt sc_intrcnt; /* Interrupt counter */
71 1.1 rumble bus_space_handle_t sc_sh;
72 1.1 rumble bus_space_tag_t sc_st;
73 1.1 rumble bus_dma_tag_t sc_dmat;
74 1.1 rumble bus_dmamap_t sc_dmamap;
75 1.1 rumble int sc_flags;
76 1.1 rumble #define WDSC_DMA_ACTIVE 0x1
77 1.1 rumble #define WDSC_DMA_MAPLOADED 0x2
78 1.1 rumble struct oioc_dma_softc {
79 1.1 rumble bus_space_tag_t sc_bst;
80 1.1 rumble bus_space_handle_t sc_bsh;
81 1.1 rumble bus_dma_tag_t sc_dmat;
82 1.1 rumble
83 1.1 rumble uint32_t sc_flags;
84 1.1 rumble uint32_t sc_dmalow;
85 1.1 rumble int sc_ndesc;
86 1.1 rumble bus_dmamap_t sc_dmamap;
87 1.4 msaitoh ssize_t sc_dlen; /* # bytes transferred */
88 1.1 rumble } sc_oiocdma;
89 1.1 rumble };
90 1.1 rumble
91 1.1 rumble
92 1.1 rumble void oiocsc_attach (device_t, device_t, void *);
93 1.1 rumble int oiocsc_match (device_t, struct cfdata *, void *);
94 1.1 rumble
95 1.1 rumble CFATTACH_DECL_NEW(oiocsc, sizeof(struct oiocsc_softc),
96 1.1 rumble oiocsc_match, oiocsc_attach, NULL, NULL);
97 1.1 rumble
98 1.1 rumble int oiocsc_dmasetup (struct wd33c93_softc *, void **, size_t *,
99 1.1 rumble int, size_t *);
100 1.1 rumble int oiocsc_dmago (struct wd33c93_softc *);
101 1.1 rumble void oiocsc_dmastop (struct wd33c93_softc *);
102 1.1 rumble void oiocsc_reset (struct wd33c93_softc *);
103 1.1 rumble int oiocsc_dmaintr (void *);
104 1.1 rumble int oiocsc_scsiintr (void *);
105 1.1 rumble
106 1.1 rumble /*
107 1.1 rumble * Always present on IP4, IP6, IP10.
108 1.1 rumble */
109 1.1 rumble int
110 1.1 rumble oiocsc_match(device_t parent, struct cfdata *cf, void *aux)
111 1.1 rumble {
112 1.1 rumble struct oioc_attach_args *oa = aux;
113 1.1 rumble
114 1.1 rumble if (strcmp(oa->oa_name, cf->cf_name) == 0)
115 1.1 rumble return (1);
116 1.1 rumble
117 1.1 rumble return (0);
118 1.1 rumble }
119 1.1 rumble
120 1.1 rumble /*
121 1.1 rumble * Attach the wdsc driver
122 1.1 rumble */
123 1.1 rumble void
124 1.1 rumble oiocsc_attach(device_t parent, device_t self, void *aux)
125 1.1 rumble {
126 1.1 rumble struct oiocsc_softc *osc = device_private(self);
127 1.3 msaitoh struct wd33c93_softc *sc = &osc->sc_wd33c93;
128 1.1 rumble struct oioc_attach_args *oa = aux;
129 1.1 rumble int err;
130 1.1 rumble
131 1.1 rumble sc->sc_dev = self;
132 1.1 rumble sc->sc_regt = oa->oa_st;
133 1.1 rumble osc->sc_st = oa->oa_st;
134 1.1 rumble osc->sc_sh = oa->oa_sh;
135 1.1 rumble osc->sc_dmat = oa->oa_dmat;
136 1.1 rumble
137 1.1 rumble if ((err = bus_space_subregion(oa->oa_st, oa->oa_sh, OIOC_WD33C93_ASR,
138 1.1 rumble OIOC_WD33C93_ASR_SIZE, &sc->sc_asr_regh)) != 0) {
139 1.1 rumble printf(": unable to map regs, err=%d\n", err);
140 1.1 rumble return;
141 1.1 rumble }
142 1.1 rumble
143 1.1 rumble if ((err = bus_space_subregion(oa->oa_st, oa->oa_sh, OIOC_WD33C93_DATA,
144 1.1 rumble OIOC_WD33C93_DATA_SIZE, &sc->sc_data_regh)) != 0) {
145 1.1 rumble printf(": unable to map regs, err=%d\n", err);
146 1.1 rumble return;
147 1.1 rumble }
148 1.1 rumble
149 1.1 rumble if (bus_dmamap_create(osc->sc_dmat,
150 1.1 rumble OIOC_SCSI_DMA_NSEGS * PAGE_SIZE,
151 1.1 rumble OIOC_SCSI_DMA_NSEGS, PAGE_SIZE, PAGE_SIZE,
152 1.1 rumble BUS_DMA_WAITOK, &osc->sc_dmamap) != 0) {
153 1.1 rumble printf(": failed to create dmamap\n");
154 1.1 rumble return;
155 1.1 rumble }
156 1.1 rumble
157 1.1 rumble sc->sc_dmasetup = oiocsc_dmasetup;
158 1.1 rumble sc->sc_dmago = oiocsc_dmago;
159 1.1 rumble sc->sc_dmastop = oiocsc_dmastop;
160 1.1 rumble sc->sc_reset = oiocsc_reset;
161 1.1 rumble
162 1.1 rumble sc->sc_adapter.adapt_request = wd33c93_scsi_request;
163 1.1 rumble sc->sc_adapter.adapt_minphys = minphys;
164 1.1 rumble
165 1.1 rumble sc->sc_id = 0; /* Host ID = 0 */
166 1.1 rumble sc->sc_clkfreq = 100; /* 10MHz */
167 1.1 rumble
168 1.1 rumble /* Disable DMA - it's not ready for prime time, see oiocsc_dmasetup */
169 1.1 rumble #if 0
170 1.1 rumble sc->sc_dmamode = (oa->oa_burst_dma) ?
171 1.1 rumble SBIC_CTL_BURST_DMA : SBIC_CTL_DMA;
172 1.1 rumble #else
173 1.1 rumble sc->sc_dmamode = 0;
174 1.1 rumble #endif
175 1.1 rumble
176 1.1 rumble evcnt_attach_dynamic(&osc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
177 1.1 rumble device_xname(sc->sc_dev), "intr");
178 1.1 rumble
179 1.1 rumble if ((cpu_intr_establish(oa->oa_irq, IPL_BIO,
180 1.1 rumble oiocsc_scsiintr, sc)) == NULL) {
181 1.1 rumble printf(": unable to establish interrupt!\n");
182 1.1 rumble return;
183 1.1 rumble }
184 1.1 rumble
185 1.1 rumble wd33c93_attach(sc);
186 1.1 rumble }
187 1.1 rumble
188 1.1 rumble /*
189 1.1 rumble * Prime the hardware for a DMA transfer
190 1.1 rumble *
191 1.1 rumble * Requires splbio() interrupts to be disabled by the caller
192 1.1 rumble *
193 1.1 rumble * XXX- I'm not sure if this works properly yet. Primarily, I'm not sure
194 1.1 rumble * that all ds_addr's after the first will be page aligned. If they're
195 1.1 rumble * not, we apparently cannot use this DMA engine...
196 1.1 rumble *
197 1.1 rumble * Unfortunately, I'm getting mutex panics while testing with EFS (haven't
198 1.1 rumble * tried FFS), so I cannot yet confirm whether this works or not.
199 1.1 rumble */
200 1.1 rumble int
201 1.1 rumble oiocsc_dmasetup(struct wd33c93_softc *dev, void **addr, size_t *len, int datain,
202 1.1 rumble size_t *dmasize)
203 1.1 rumble {
204 1.1 rumble struct oiocsc_softc *osc = (void *)dev;
205 1.1 rumble struct oioc_dma_softc *dsc = &osc->sc_oiocdma;
206 1.1 rumble int count, err, i;
207 1.1 rumble void *vaddr;
208 1.1 rumble
209 1.1 rumble KASSERT((osc->sc_flags & WDSC_DMA_ACTIVE) == 0);
210 1.1 rumble
211 1.1 rumble vaddr = *addr;
212 1.1 rumble count = dsc->sc_dlen = *len;
213 1.1 rumble
214 1.1 rumble if (count) {
215 1.1 rumble bus_dmamap_t dmamap = osc->sc_dmamap;
216 1.1 rumble
217 1.1 rumble KASSERT((osc->sc_flags & WDSC_DMA_MAPLOADED) == 0);
218 1.1 rumble
219 1.1 rumble /* Build list of physical addresses for this transfer */
220 1.1 rumble if ((err = bus_dmamap_load(osc->sc_dmat, osc->sc_dmamap,
221 1.1 rumble vaddr, count,
222 1.1 rumble NULL /* kernel address */,
223 1.1 rumble BUS_DMA_NOWAIT)) != 0)
224 1.1 rumble panic("%s: bus_dmamap_load err=%d",
225 1.1 rumble device_xname(dev->sc_dev), err);
226 1.1 rumble
227 1.1 rumble /*
228 1.1 rumble * We can map the contiguous buffer with up to 256 pages.
229 1.1 rumble * The DMA low address register contains a 12-bit offset for
230 1.1 rumble * the first page (in case the buffer isn't aligned). The 256
231 1.1 rumble * high registers contain 16 bits each for page numbers.
232 1.1 rumble *
233 1.1 rumble * We will fill in the high registers here. The low register
234 1.1 rumble * fires off the DMA engine and is set in oiocsc_dmago.
235 1.1 rumble */
236 1.1 rumble dsc->sc_dmalow = dmamap->dm_segs[0].ds_addr &
237 1.1 rumble OIOC_SCSI_DMA_LOW_ADDR_MASK;
238 1.1 rumble
239 1.1 rumble KASSERT(dmamap->dm_nsegs <= OIOC_SCSI_DMA_NSEGS);
240 1.1 rumble
241 1.1 rumble for (i = 0; i < dmamap->dm_nsegs; i++) {
242 1.1 rumble uint16_t pgnum;
243 1.1 rumble
244 1.1 rumble pgnum = dmamap->dm_segs[i].ds_addr >>
245 1.1 rumble OIOC_SCSI_DMA_HIGH_SHFT;
246 1.1 rumble
247 1.1 rumble bus_space_write_2(osc->sc_st, osc->sc_sh,
248 1.1 rumble OIOC_SCSI_DMA_HIGH(i), pgnum);
249 1.1 rumble }
250 1.1 rumble
251 1.1 rumble osc->sc_flags |= WDSC_DMA_MAPLOADED;
252 1.1 rumble
253 1.1 rumble if (datain)
254 1.1 rumble dsc->sc_dmalow |= OIOC_SCSI_DMA_LOW_ADDR_DMADIR;
255 1.1 rumble }
256 1.1 rumble
257 1.1 rumble return (count);
258 1.1 rumble }
259 1.1 rumble
260 1.1 rumble /*
261 1.1 rumble * Prime the hardware for the next DMA transfer
262 1.1 rumble */
263 1.1 rumble int
264 1.1 rumble oiocsc_dmago(struct wd33c93_softc *dev)
265 1.1 rumble {
266 1.1 rumble struct oiocsc_softc *osc = (void *)dev;
267 1.1 rumble struct oioc_dma_softc *dsc = &osc->sc_oiocdma;
268 1.1 rumble
269 1.1 rumble if (dsc->sc_dlen == 0)
270 1.1 rumble return(0);
271 1.1 rumble
272 1.1 rumble KASSERT((osc->sc_flags & WDSC_DMA_ACTIVE) == 0);
273 1.1 rumble KASSERT((osc->sc_flags & WDSC_DMA_MAPLOADED));
274 1.1 rumble
275 1.1 rumble osc->sc_flags |= WDSC_DMA_ACTIVE;
276 1.1 rumble
277 1.1 rumble bus_dmamap_sync(osc->sc_dmat, osc->sc_dmamap, 0,
278 1.1 rumble osc->sc_dmamap->dm_mapsize,
279 1.1 rumble BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
280 1.1 rumble
281 1.1 rumble /* Blastoff! */
282 1.1 rumble bus_space_write_2(osc->sc_st, osc->sc_sh,
283 1.1 rumble OIOC_SCSI_DMA_LOW, dsc->sc_dmalow);
284 1.1 rumble
285 1.1 rumble return(osc->sc_dmamap->dm_mapsize);
286 1.1 rumble }
287 1.1 rumble
288 1.1 rumble /*
289 1.1 rumble * Stop DMA and unload active DMA maps
290 1.1 rumble */
291 1.1 rumble void
292 1.1 rumble oiocsc_dmastop(struct wd33c93_softc *dev)
293 1.1 rumble {
294 1.1 rumble struct oiocsc_softc *osc = (void *)dev;
295 1.1 rumble
296 1.1 rumble if (osc->sc_flags & WDSC_DMA_ACTIVE) {
297 1.1 rumble /* Stop DMA, flush and sync */
298 1.1 rumble bus_space_write_4(osc->sc_st, osc->sc_sh,
299 1.1 rumble OIOC_SCSI_DMA_FLUSH, 0);
300 1.1 rumble bus_dmamap_sync(osc->sc_dmat, osc->sc_dmamap, 0,
301 1.1 rumble osc->sc_dmamap->dm_mapsize,
302 1.1 rumble BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
303 1.1 rumble }
304 1.1 rumble if (osc->sc_flags & WDSC_DMA_MAPLOADED)
305 1.1 rumble bus_dmamap_unload(osc->sc_dmat, osc->sc_dmamap);
306 1.1 rumble osc->sc_flags &= ~(WDSC_DMA_ACTIVE | WDSC_DMA_MAPLOADED);
307 1.1 rumble }
308 1.1 rumble
309 1.1 rumble /*
310 1.1 rumble * Reset the controller.
311 1.1 rumble */
312 1.1 rumble void
313 1.1 rumble oiocsc_reset(struct wd33c93_softc *dev)
314 1.1 rumble {
315 1.1 rumble struct oiocsc_softc *osc = (void *)dev;
316 1.1 rumble
317 1.1 rumble /* hard reset the chip */
318 1.1 rumble bus_space_read_4(osc->sc_st, osc->sc_sh, OIOC_SCSI_RESET_ON);
319 1.1 rumble delay(1000);
320 1.1 rumble bus_space_read_4(osc->sc_st, osc->sc_sh, OIOC_SCSI_RESET_OFF);
321 1.1 rumble delay(1000);
322 1.1 rumble }
323 1.1 rumble
324 1.1 rumble /*
325 1.1 rumble * WD33c93 SCSI controller interrupt
326 1.1 rumble */
327 1.1 rumble int
328 1.1 rumble oiocsc_scsiintr(void *arg)
329 1.1 rumble {
330 1.1 rumble struct wd33c93_softc *dev = arg;
331 1.1 rumble struct oiocsc_softc *osc = arg;
332 1.1 rumble int found;
333 1.1 rumble
334 1.1 rumble found = wd33c93_intr(dev);
335 1.1 rumble if (found)
336 1.1 rumble osc->sc_intrcnt.ev_count++;
337 1.1 rumble return(found);
338 1.1 rumble }
339