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