xref: /netbsd-src/sys/arch/vax/vsa/asc_vsbus.c (revision d1579b2d70337e1b895f03478838f880e450f6da)
1 /*	$NetBSD: asc_vsbus.c,v 1.45 2018/09/03 16:29:28 riastradh Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
33 
34 __KERNEL_RCSID(0, "$NetBSD: asc_vsbus.c,v 1.45 2018/09/03 16:29:28 riastradh Exp $");
35 
36 #include "locators.h"
37 #include "opt_cputype.h"
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/bus.h>
42 #include <sys/cpu.h>
43 #include <sys/device.h>
44 #include <sys/kernel.h>
45 #include <sys/errno.h>
46 #include <sys/ioctl.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 #include <dev/scsipi/scsi_message.h>
53 
54 #include <dev/ic/ncr53c9xreg.h>
55 #include <dev/ic/ncr53c9xvar.h>
56 
57 #include <machine/vmparam.h>
58 #include <machine/sid.h>
59 #include <machine/scb.h>
60 #include <machine/vsbus.h>
61 #include <machine/clock.h>	/* for SCSI ctlr ID# XXX */
62 
63 struct asc_vsbus_softc {
64 	struct ncr53c9x_softc sc_ncr53c9x;	/* Must be first */
65 	struct evcnt sc_intrcnt;		/* count interrupts */
66 	bus_space_tag_t sc_bst;			/* bus space tag */
67 	bus_space_handle_t sc_bsh;		/* bus space handle */
68 	bus_space_handle_t sc_dirh;		/* scsi direction handle */
69 	bus_space_handle_t sc_adrh;		/* scsi address handle */
70 	bus_space_handle_t sc_ncrh;		/* ncr bus space handle */
71 	bus_dma_tag_t sc_dmat;			/* bus DMA tag */
72 	bus_dmamap_t sc_dmamap;
73 	uint8_t **sc_dmaaddr;
74 	size_t *sc_dmalen;
75 	size_t sc_dmasize;
76 	unsigned int sc_flags;
77 #define	ASC_FROMMEMORY		0x0001		/* Must be 1 */
78 #define	ASC_DMAACTIVE		0x0002
79 #define	ASC_MAPLOADED		0x0004
80 	unsigned long sc_xfers;
81 };
82 
83 #define	ASC_REG_KA46_ADR	0x0000
84 #define	ASC_REG_KA46_DIR	0x000C
85 #define	ASC_REG_KA49_ADR	0x0000
86 #define	ASC_REG_KA49_DIR	0x0004
87 #define	ASC_REG_NCR		0x0080
88 #define	ASC_REG_END		0x00B0
89 
90 #define	ASC_MAXXFERSIZE		65536
91 #define	ASC_FREQUENCY		25000000
92 
93 static int asc_vsbus_match(device_t, cfdata_t, void *);
94 static void asc_vsbus_attach(device_t, device_t, void *);
95 
96 CFATTACH_DECL_NEW(asc_vsbus, sizeof(struct asc_vsbus_softc),
97     asc_vsbus_match, asc_vsbus_attach, NULL, NULL);
98 
99 /*
100  * Functions and the switch for the MI code
101  */
102 static uint8_t	asc_vsbus_read_reg(struct ncr53c9x_softc *, int);
103 static void	asc_vsbus_write_reg(struct ncr53c9x_softc *, int, uint8_t);
104 static int	asc_vsbus_dma_isintr(struct ncr53c9x_softc *);
105 static void	asc_vsbus_dma_reset(struct ncr53c9x_softc *);
106 static int	asc_vsbus_dma_intr(struct ncr53c9x_softc *);
107 static int	asc_vsbus_dma_setup(struct ncr53c9x_softc *, uint8_t **,
108 		    size_t *, int, size_t *);
109 static void	asc_vsbus_dma_go(struct ncr53c9x_softc *);
110 static void	asc_vsbus_dma_stop(struct ncr53c9x_softc *);
111 static int	asc_vsbus_dma_isactive(struct ncr53c9x_softc *);
112 
113 static const struct ncr53c9x_glue asc_vsbus_glue = {
114 	.gl_read_reg	= asc_vsbus_read_reg,
115 	.gl_write_reg	= asc_vsbus_write_reg,
116 	.gl_dma_isintr	= asc_vsbus_dma_isintr,
117 	.gl_dma_reset	= asc_vsbus_dma_reset,
118 	.gl_dma_intr	= asc_vsbus_dma_intr,
119 	.gl_dma_setup	= asc_vsbus_dma_setup,
120 	.gl_dma_go	= asc_vsbus_dma_go,
121 	.gl_dma_stop	= asc_vsbus_dma_stop,
122 	.gl_dma_isactive = asc_vsbus_dma_isactive,
123 };
124 
125 static uint8_t asc_attached;		/* can't have more than one asc */
126 
127 static int
asc_vsbus_match(device_t parent,cfdata_t cf,void * aux)128 asc_vsbus_match(device_t parent, cfdata_t cf, void *aux)
129 {
130 	struct vsbus_attach_args * const va = aux;
131 	volatile uint8_t *ncr_regs;
132 	int dummy;
133 
134 	if (asc_attached)
135 		return 0;
136 
137 	if (vax_boardtype == VAX_BTYP_46 || vax_boardtype == VAX_BTYP_48) {
138 		if (cf->cf_loc[VSBUSCF_CSR] != 0x200c0080)
139 			return 0;
140 	} else if (vax_boardtype == VAX_BTYP_49 ||
141 	    vax_boardtype == VAX_BTYP_53) {
142 		if (cf->cf_loc[VSBUSCF_CSR] != 0x26000080)
143 			return 0;
144 	} else {
145 		return 0;
146 	}
147 
148 	ncr_regs = (volatile uint8_t *) va->va_addr;
149 
150 	/*  *** need to generate an interrupt here
151 	 * From trial and error, I've determined that an INT is generated
152 	 * only when the following sequence of events occurs:
153 	 *   1) The interrupt status register (0x05) must be read.
154 	 *   2) SCSI bus reset interrupt must be enabled
155 	 *   3) SCSI bus reset command must be sent
156 	 *   4) NOP command must be sent
157 	 */
158 
159 	dummy = ncr_regs[NCR_INTR << 2] & 0xFF;
160         ncr_regs[NCR_CFG1 << 2] = 0x06; /* we're ID 6, turn on INT for SCSI reset */
161         ncr_regs[NCR_CMD << 2] = NCRCMD_RSTSCSI; /* send the reset */
162         ncr_regs[NCR_CMD << 2] = NCRCMD_NOP; /* send a NOP */
163 	DELAY(10000);
164 
165 	dummy = ncr_regs[NCR_INTR << 2] & 0xFF;
166 	return (dummy & NCRINTR_SBR) != 0;
167 }
168 
169 
170 /*
171  * Attach this instance, and then all the sub-devices
172  */
173 static void
asc_vsbus_attach(device_t parent,device_t self,void * aux)174 asc_vsbus_attach(device_t parent, device_t self, void *aux)
175 {
176 	struct vsbus_attach_args * const va = aux;
177 	struct asc_vsbus_softc * const asc = device_private(self);
178 	struct ncr53c9x_softc * const sc = &asc->sc_ncr53c9x;
179 	int error;
180 
181 	asc_attached = 1;
182 	/*
183 	 * Set up glue for MI code early; we use some of it here.
184 	 */
185 	sc->sc_dev = self;
186 	sc->sc_glue = &asc_vsbus_glue;
187 
188 	asc->sc_bst = va->va_memt;
189 	asc->sc_dmat = va->va_dmat;
190 
191 	error = bus_space_map(asc->sc_bst, va->va_paddr - ASC_REG_NCR,
192 	    ASC_REG_END, 0, &asc->sc_bsh);
193 	if (error) {
194 		aprint_error(": failed to map registers: error=%d\n", error);
195 		return;
196 	}
197 	error = bus_space_subregion(asc->sc_bst, asc->sc_bsh, ASC_REG_NCR,
198 	    ASC_REG_END - ASC_REG_NCR, &asc->sc_ncrh);
199 	if (error) {
200 		aprint_error(": failed to map ncr registers: error=%d\n",
201 		    error);
202 		return;
203 	}
204 	if (vax_boardtype == VAX_BTYP_46 || vax_boardtype == VAX_BTYP_48) {
205 		error = bus_space_subregion(asc->sc_bst, asc->sc_bsh,
206 		    ASC_REG_KA46_ADR, sizeof(uint32_t), &asc->sc_adrh);
207 		if (error) {
208 			aprint_error(": failed to map adr register: error=%d\n",
209 			     error);
210 			return;
211 		}
212 		error = bus_space_subregion(asc->sc_bst, asc->sc_bsh,
213 		    ASC_REG_KA46_DIR, sizeof(uint32_t), &asc->sc_dirh);
214 		if (error) {
215 			aprint_error(": failed to map dir register: error=%d\n",
216 			     error);
217 			return;
218 		}
219 	} else {
220 		/* This is a gross and disgusting kludge but it'll
221 		 * save a bunch of ugly code.  Unlike the VS4000/60,
222 		 * the SCSI Address and direction registers are not
223 		 * near the SCSI NCR registers and are inside the
224 		 * block of general VAXstation registers.  So we grab
225 		 * them from there and knowing the internals of the
226 		 * bus_space implementation, we cast to bus_space_handles.
227 		 */
228 		struct vsbus_softc *vsc = device_private(parent);
229 		asc->sc_adrh =
230 		    (bus_space_handle_t)(vsc->sc_vsregs + ASC_REG_KA49_ADR);
231 		asc->sc_dirh =
232 		    (bus_space_handle_t)(vsc->sc_vsregs + ASC_REG_KA49_DIR);
233 #if 0
234 		printf("\n%s: adrh=0x%08lx dirh=0x%08lx", device_xname(self),
235 		    asc->sc_adrh, asc->sc_dirh);
236 		ncr53c9x_debug = NCR_SHOWDMA | NCR_SHOWINTS | NCR_SHOWCMDS |
237 		    NCR_SHOWPHASE | NCR_SHOWSTART | NCR_SHOWMSGS;
238 #endif
239 	}
240 	error = bus_dmamap_create(asc->sc_dmat, ASC_MAXXFERSIZE, 1,
241 	    ASC_MAXXFERSIZE, 0, BUS_DMA_NOWAIT, &asc->sc_dmamap);
242 
243 #if defined(VAX46) || defined(VAX48) || defined(VAX49) || defined(VAXANY)
244 	if(vax_boardtype != VAX_BTYP_53)
245 		/* SCSI ID is store in the clock NVRAM at magic address 0xbc */
246 		sc->sc_id = (clk_page[0xbc / 2] >> clk_tweak) & 7;
247 	else
248 #endif
249 		sc->sc_id = 6; /* XXX need to get this from VMB */
250 	sc->sc_freq = ASC_FREQUENCY;
251 
252 	/* gimme MHz */
253 	sc->sc_freq /= 1000000;
254 
255 	scb_vecalloc(va->va_cvec, (void (*)(void *))ncr53c9x_intr,
256 	    &asc->sc_ncr53c9x, SCB_ISTACK, &asc->sc_intrcnt);
257 	evcnt_attach_dynamic(&asc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
258 	    device_xname(self), "intr");
259 
260 	/*
261 	 * XXX More of this should be in ncr53c9x_attach(), but
262 	 * XXX should we really poke around the chip that much in
263 	 * XXX the MI code?  Think about this more...
264 	 */
265 
266 	/*
267 	 * Set up static configuration info.
268 	 */
269 	sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
270 	sc->sc_cfg2 = NCRCFG2_SCSI2;
271 	sc->sc_cfg3 = 0;
272 	sc->sc_rev = NCR_VARIANT_NCR53C94;
273 
274 	/*
275 	 * XXX minsync and maxxfer _should_ be set up in MI code,
276 	 * XXX but it appears to have some dependency on what sort
277 	 * XXX of DMA we're hooked up to, etc.
278 	 */
279 
280 	/*
281 	 * This is the value used to start sync negotiations
282 	 * Note that the NCR register "SYNCTP" is programmed
283 	 * in "clocks per byte", and has a minimum value of 4.
284 	 * The SCSI period used in negotiation is one-fourth
285 	 * of the time (in nanoseconds) needed to transfer one byte.
286 	 * Since the chip's clock is given in MHz, we have the following
287 	 * formula: 4 * period = (1000 / freq) * 4
288 	 */
289 	sc->sc_minsync = (1000 / sc->sc_freq);
290 	sc->sc_maxxfer = 64 * 1024;
291 
292 	aprint_normal("\n%s", device_xname(self)); /* Pretty print */
293 
294 	/* Do the common parts of attachment. */
295 	sc->sc_adapter.adapt_minphys = minphys;
296 	sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request;
297 	ncr53c9x_attach(sc);
298 }
299 
300 /*
301  * Glue functions.
302  */
303 
304 static uint8_t
asc_vsbus_read_reg(struct ncr53c9x_softc * sc,int reg)305 asc_vsbus_read_reg(struct ncr53c9x_softc *sc, int reg)
306 {
307 	struct asc_vsbus_softc * const asc = (struct asc_vsbus_softc *)sc;
308 
309 	return bus_space_read_1(asc->sc_bst, asc->sc_ncrh,
310 	    reg * sizeof(uint32_t));
311 }
312 
313 static void
asc_vsbus_write_reg(struct ncr53c9x_softc * sc,int reg,uint8_t val)314 asc_vsbus_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val)
315 {
316 	struct asc_vsbus_softc * const asc = (struct asc_vsbus_softc *)sc;
317 
318 	bus_space_write_1(asc->sc_bst, asc->sc_ncrh,
319 	    reg * sizeof(uint32_t), val);
320 }
321 
322 static int
asc_vsbus_dma_isintr(struct ncr53c9x_softc * sc)323 asc_vsbus_dma_isintr(struct ncr53c9x_softc *sc)
324 {
325 	struct asc_vsbus_softc * const asc = (struct asc_vsbus_softc *)sc;
326 
327 	return bus_space_read_1(asc->sc_bst, asc->sc_ncrh,
328 	    NCR_STAT * sizeof(uint32_t)) & NCRSTAT_INT;
329 }
330 
331 static void
asc_vsbus_dma_reset(struct ncr53c9x_softc * sc)332 asc_vsbus_dma_reset(struct ncr53c9x_softc *sc)
333 {
334 	struct asc_vsbus_softc * const asc = (struct asc_vsbus_softc *)sc;
335 
336 	if (asc->sc_flags & ASC_MAPLOADED)
337 		bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
338 	asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
339 }
340 
341 static int
asc_vsbus_dma_intr(struct ncr53c9x_softc * sc)342 asc_vsbus_dma_intr(struct ncr53c9x_softc *sc)
343 {
344 	struct asc_vsbus_softc * const asc = (struct asc_vsbus_softc *)sc;
345 	u_int tcl, tcm;
346 	int trans, resid;
347 
348 	if ((asc->sc_flags & ASC_DMAACTIVE) == 0)
349 		panic("%s: DMA wasn't active", __func__);
350 
351 	asc->sc_flags &= ~ASC_DMAACTIVE;
352 
353 	if (asc->sc_dmasize == 0) {
354 		/* A "Transfer Pad" operation completed */
355 		tcl = NCR_READ_REG(sc, NCR_TCL);
356 		tcm = NCR_READ_REG(sc, NCR_TCM);
357 		NCR_DMA(("asc_vsbus_intr: discarded %d bytes (tcl=%d, tcm=%d)\n",
358 		    tcl | (tcm << 8), tcl, tcm));
359 		return 0;
360 	}
361 
362 	resid = 0;
363 	if ((resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
364 		NCR_DMA(("asc_vsbus_intr: empty FIFO of %d ", resid));
365 		DELAY(1);
366 	}
367 	if (asc->sc_flags & ASC_MAPLOADED) {
368 		bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
369 				0, asc->sc_dmasize,
370 				asc->sc_flags & ASC_FROMMEMORY
371 					? BUS_DMASYNC_POSTWRITE
372 					: BUS_DMASYNC_POSTREAD);
373 		bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
374 	}
375 	asc->sc_flags &= ~ASC_MAPLOADED;
376 
377 	resid += (tcl = NCR_READ_REG(sc, NCR_TCL));
378 	resid += (tcm = NCR_READ_REG(sc, NCR_TCM)) << 8;
379 
380 	trans = asc->sc_dmasize - resid;
381 	if (trans < 0) {			/* transferred < 0 ? */
382 		printf("asc_vsbus_intr: xfer (%d) > req (%lu)\n",
383 		    trans, (u_long) asc->sc_dmasize);
384 		trans = asc->sc_dmasize;
385 	}
386 	NCR_DMA(("asc_vsbus_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n",
387 	    tcl, tcm, trans, resid));
388 
389 	*asc->sc_dmalen -= trans;
390 	*asc->sc_dmaaddr += trans;
391 
392 	asc->sc_xfers++;
393 	return 0;
394 }
395 
396 static int
asc_vsbus_dma_setup(struct ncr53c9x_softc * sc,uint8_t ** addr,size_t * len,int datain,size_t * dmasize)397 asc_vsbus_dma_setup(struct ncr53c9x_softc *sc, uint8_t **addr, size_t *len,
398 		    int datain, size_t *dmasize)
399 {
400 	struct asc_vsbus_softc * const asc = (struct asc_vsbus_softc *)sc;
401 
402 	asc->sc_dmaaddr = addr;
403 	asc->sc_dmalen = len;
404 	if (datain) {
405 		asc->sc_flags &= ~ASC_FROMMEMORY;
406 	} else {
407 		asc->sc_flags |= ASC_FROMMEMORY;
408 	}
409 	if ((vaddr_t)*asc->sc_dmaaddr < VM_MIN_KERNEL_ADDRESS)
410 		panic("%s: DMA address (%p) outside of kernel",
411 		    __func__, *asc->sc_dmaaddr);
412 
413         NCR_DMA(("%s: start %d@%p,%d\n", device_xname(sc->sc_dev),
414             (int)*asc->sc_dmalen, *asc->sc_dmaaddr,
415 	    (asc->sc_flags & ASC_FROMMEMORY)));
416 	*dmasize = asc->sc_dmasize = uimin(*dmasize, ASC_MAXXFERSIZE);
417 
418 	if (asc->sc_dmasize) {
419 		if (bus_dmamap_load(asc->sc_dmat, asc->sc_dmamap,
420 				*asc->sc_dmaaddr, asc->sc_dmasize,
421 				NULL /* kernel address */,
422 				BUS_DMA_NOWAIT|VAX_BUS_DMA_SPILLPAGE))
423 			panic("%s: cannot load DMA map",
424 			    device_xname(sc->sc_dev));
425 		bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
426 				0, asc->sc_dmasize,
427 				asc->sc_flags & ASC_FROMMEMORY
428 					? BUS_DMASYNC_PREWRITE
429 					: BUS_DMASYNC_PREREAD);
430 		bus_space_write_4(asc->sc_bst, asc->sc_adrh, 0,
431 				  asc->sc_dmamap->dm_segs[0].ds_addr);
432 		bus_space_write_4(asc->sc_bst, asc->sc_dirh, 0,
433 				  asc->sc_flags & ASC_FROMMEMORY);
434 		NCR_DMA(("%s: dma-load %lu@0x%08lx\n",
435 		    device_xname(sc->sc_dev),
436 		    asc->sc_dmamap->dm_segs[0].ds_len,
437 		    asc->sc_dmamap->dm_segs[0].ds_addr));
438 		asc->sc_flags |= ASC_MAPLOADED;
439 	}
440 
441 	return 0;
442 }
443 
444 static void
asc_vsbus_dma_go(struct ncr53c9x_softc * sc)445 asc_vsbus_dma_go(struct ncr53c9x_softc *sc)
446 {
447 	struct asc_vsbus_softc * const asc = (struct asc_vsbus_softc *)sc;
448 
449 	asc->sc_flags |= ASC_DMAACTIVE;
450 }
451 
452 static void
asc_vsbus_dma_stop(struct ncr53c9x_softc * sc)453 asc_vsbus_dma_stop(struct ncr53c9x_softc *sc)
454 {
455 	struct asc_vsbus_softc * const asc = (struct asc_vsbus_softc *)sc;
456 
457 	if (asc->sc_flags & ASC_MAPLOADED) {
458 		bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
459 				0, asc->sc_dmasize,
460 				asc->sc_flags & ASC_FROMMEMORY
461 					? BUS_DMASYNC_POSTWRITE
462 					: BUS_DMASYNC_POSTREAD);
463 		bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
464 	}
465 
466 	asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
467 }
468 
469 static int
asc_vsbus_dma_isactive(struct ncr53c9x_softc * sc)470 asc_vsbus_dma_isactive(struct ncr53c9x_softc *sc)
471 {
472 	struct asc_vsbus_softc * const asc = (struct asc_vsbus_softc *)sc;
473 
474 	return (asc->sc_flags & ASC_DMAACTIVE) != 0;
475 }
476