xref: /netbsd-src/sys/dev/podulebus/sec.c (revision b8f12c7fce13df57a61373fdc6dacc0446acd8f7)
1*b8f12c7fSmaya /* $NetBSD: sec.c,v 1.17 2017/01/20 12:25:07 maya Exp $ */
25375dc7fSbjh21 
35375dc7fSbjh21 /*-
45375dc7fSbjh21  * Copyright (c) 2000, 2001, 2006 Ben Harris
55375dc7fSbjh21  * All rights reserved.
65375dc7fSbjh21  *
75375dc7fSbjh21  * Redistribution and use in source and binary forms, with or without
85375dc7fSbjh21  * modification, are permitted provided that the following conditions
95375dc7fSbjh21  * are met:
105375dc7fSbjh21  * 1. Redistributions of source code must retain the above copyright
115375dc7fSbjh21  *    notice, this list of conditions and the following disclaimer.
125375dc7fSbjh21  * 2. Redistributions in binary form must reproduce the above copyright
135375dc7fSbjh21  *    notice, this list of conditions and the following disclaimer in the
145375dc7fSbjh21  *    documentation and/or other materials provided with the distribution.
155375dc7fSbjh21  * 3. The name of the author may not be used to endorse or promote products
165375dc7fSbjh21  *    derived from this software without specific prior written permission.
175375dc7fSbjh21  *
185375dc7fSbjh21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
195375dc7fSbjh21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
205375dc7fSbjh21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
215375dc7fSbjh21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
225375dc7fSbjh21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
235375dc7fSbjh21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
245375dc7fSbjh21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
255375dc7fSbjh21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
265375dc7fSbjh21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
275375dc7fSbjh21  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
285375dc7fSbjh21  */
295375dc7fSbjh21 /*
305375dc7fSbjh21  * sec.c -- driver for Acorn SCSI expansion cards (AKA30, AKA31, AKA32)
315375dc7fSbjh21  *
325375dc7fSbjh21  * These cards are documented in:
335375dc7fSbjh21  * Acorn Archimedes 500 series / Acorn R200 series Technical Reference Manual
345375dc7fSbjh21  * Published by Acorn Computers Limited
355375dc7fSbjh21  * ISBN 1 85250 086 7
365375dc7fSbjh21  * Part number 0486,052
375375dc7fSbjh21  * Issue 1, November 1990
385375dc7fSbjh21  */
395375dc7fSbjh21 
405375dc7fSbjh21 #include <sys/cdefs.h>
41*b8f12c7fSmaya __KERNEL_RCSID(0, "$NetBSD: sec.c,v 1.17 2017/01/20 12:25:07 maya Exp $");
425375dc7fSbjh21 
435375dc7fSbjh21 #include <sys/param.h>
445375dc7fSbjh21 
455375dc7fSbjh21 #include <sys/buf.h>
465375dc7fSbjh21 #include <sys/device.h>
475375dc7fSbjh21 #include <sys/malloc.h>
485375dc7fSbjh21 #include <sys/reboot.h>	/* For bootverbose */
495375dc7fSbjh21 #include <sys/syslog.h>
505375dc7fSbjh21 #include <sys/systm.h>
515375dc7fSbjh21 
525375dc7fSbjh21 #include <dev/scsipi/scsi_all.h>
535375dc7fSbjh21 #include <dev/scsipi/scsipi_all.h>
545375dc7fSbjh21 #include <dev/scsipi/scsiconf.h>
555375dc7fSbjh21 
56a2a38285Sad #include <sys/bus.h>
575375dc7fSbjh21 
585375dc7fSbjh21 #include <dev/ic/wd33c93reg.h>
595375dc7fSbjh21 #include <dev/ic/wd33c93var.h>
605375dc7fSbjh21 #include <dev/ic/nec71071reg.h>
615375dc7fSbjh21 
625375dc7fSbjh21 #include <dev/podulebus/podulebus.h>
635375dc7fSbjh21 #include <dev/podulebus/podules.h>
645375dc7fSbjh21 #include <dev/podulebus/powerromreg.h>
655375dc7fSbjh21 #include <dev/podulebus/secreg.h>
665375dc7fSbjh21 
675375dc7fSbjh21 #include "opt_ddb.h"
685375dc7fSbjh21 
695375dc7fSbjh21 struct sec_softc {
705375dc7fSbjh21 	struct	wd33c93_softc sc_sbic;
715375dc7fSbjh21 	bus_space_tag_t		sc_pod_t;
725375dc7fSbjh21 	bus_space_handle_t	sc_pod_h;
735375dc7fSbjh21 	bus_space_tag_t		sc_mod_t;
745375dc7fSbjh21 	bus_space_handle_t	sc_mod_h;
755375dc7fSbjh21 	void			*sc_ih;
765375dc7fSbjh21 	struct		evcnt	sc_intrcnt;
775375dc7fSbjh21 	uint8_t			sc_mpr;
785375dc7fSbjh21 
795375dc7fSbjh21 	/* Details of the current DMA transfer */
80712239e3Sthorpej 	bool			sc_dmaactive;
8153524e44Schristos 	void *			sc_dmaaddr;
825375dc7fSbjh21 	int			sc_dmaoff;
835375dc7fSbjh21 	size_t			sc_dmalen;
84712239e3Sthorpej 	bool			sc_dmain;
855375dc7fSbjh21 	/* Details of the current block within the above transfer */
865375dc7fSbjh21 	size_t			sc_dmablk;
875375dc7fSbjh21 };
885375dc7fSbjh21 
895375dc7fSbjh21 #define SEC_DMABLK	16384
905375dc7fSbjh21 #define SEC_NBLKS	3
91439213efSbjh21 #define SEC_DMAMODE	MODE_TMODE_DMD
925375dc7fSbjh21 
935375dc7fSbjh21 /* autoconfiguration glue */
94ca028b24Sbjh21 static int sec_match(device_t, cfdata_t, void *);
95ca028b24Sbjh21 static void sec_attach(device_t, device_t, void *);
965375dc7fSbjh21 
97bafb9c4fSbjh21 /* shutdown hook */
987f79b2d5Sbjh21 static bool sec_shutdown(device_t, int);
99bafb9c4fSbjh21 
1005375dc7fSbjh21 /* callbacks from MI WD33C93 driver */
10153524e44Schristos static int sec_dmasetup(struct wd33c93_softc *, void **, size_t *, int,
1025375dc7fSbjh21     size_t *);
1035375dc7fSbjh21 static int sec_dmago(struct wd33c93_softc *);
1045375dc7fSbjh21 static void sec_dmastop(struct wd33c93_softc *);
1055375dc7fSbjh21 static void sec_reset(struct wd33c93_softc *);
1065375dc7fSbjh21 
1075375dc7fSbjh21 static int sec_intr(void *);
1085375dc7fSbjh21 static int sec_dmatc(struct sec_softc *sc);
1095375dc7fSbjh21 
1105375dc7fSbjh21 void sec_dumpdma(void *arg);
1115375dc7fSbjh21 
11211aab16bSbjh21 CFATTACH_DECL_NEW(sec, sizeof(struct sec_softc),
1135375dc7fSbjh21     sec_match, sec_attach, NULL, NULL);
1145375dc7fSbjh21 
1155375dc7fSbjh21 static inline void
sec_setpage(struct sec_softc * sc,int page)1165375dc7fSbjh21 sec_setpage(struct sec_softc *sc, int page)
1175375dc7fSbjh21 {
1185375dc7fSbjh21 
1195375dc7fSbjh21 	sc->sc_mpr = (sc->sc_mpr & ~SEC_MPR_PAGE) | page;
1205375dc7fSbjh21 	bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr);
1215375dc7fSbjh21 }
1225375dc7fSbjh21 
1235375dc7fSbjh21 static inline void
sec_cli(struct sec_softc * sc)1245375dc7fSbjh21 sec_cli(struct sec_softc *sc)
1255375dc7fSbjh21 {
1265375dc7fSbjh21 
1275375dc7fSbjh21 	bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_CLRINT, 0);
1285375dc7fSbjh21 }
1295375dc7fSbjh21 
1305375dc7fSbjh21 static inline void
dmac_write(struct sec_softc * sc,int reg,uint8_t val)1315375dc7fSbjh21 dmac_write(struct sec_softc *sc, int reg, uint8_t val)
1325375dc7fSbjh21 {
1335375dc7fSbjh21 
1345375dc7fSbjh21 	bus_space_write_1(sc->sc_mod_t, sc->sc_mod_h,
1355375dc7fSbjh21 	    SEC_DMAC + DMAC(reg), val);
1365375dc7fSbjh21 }
1375375dc7fSbjh21 
1385375dc7fSbjh21 static inline uint8_t
dmac_read(struct sec_softc * sc,int reg)1395375dc7fSbjh21 dmac_read(struct sec_softc *sc, int reg)
1405375dc7fSbjh21 {
1415375dc7fSbjh21 
1425375dc7fSbjh21 	return bus_space_read_1(sc->sc_mod_t, sc->sc_mod_h,
1435375dc7fSbjh21 	    SEC_DMAC + DMAC(reg));
1445375dc7fSbjh21 }
1455375dc7fSbjh21 
1465375dc7fSbjh21 static int
sec_match(device_t parent,cfdata_t cf,void * aux)147ca028b24Sbjh21 sec_match(device_t parent, cfdata_t cf, void *aux)
1485375dc7fSbjh21 {
1495375dc7fSbjh21 	struct podulebus_attach_args *pa = aux;
1505375dc7fSbjh21 
1515375dc7fSbjh21 	/* Standard ROM, skipping the MCS card that used the same ID. */
1525375dc7fSbjh21 	if (pa->pa_product == PODULE_ACORN_SCSI &&
1535375dc7fSbjh21 	    strncmp(pa->pa_descr, "MCS", 3) != 0)
1545375dc7fSbjh21 		return 1;
1555375dc7fSbjh21 
1565375dc7fSbjh21 	/* PowerROM */
1575375dc7fSbjh21         if (pa->pa_product == PODULE_ALSYSTEMS_SCSI &&
1585375dc7fSbjh21             podulebus_initloader(pa) == 0 &&
1595375dc7fSbjh21             podloader_callloader(pa, 0, 0) == PRID_ACORN_SCSI1)
1605375dc7fSbjh21                 return 1;
1615375dc7fSbjh21 
1625375dc7fSbjh21 	return 0;
1635375dc7fSbjh21 }
1645375dc7fSbjh21 
1655375dc7fSbjh21 static void
sec_attach(device_t parent,device_t self,void * aux)166ca028b24Sbjh21 sec_attach(device_t parent, device_t self, void *aux)
1675375dc7fSbjh21 {
1685375dc7fSbjh21 	struct podulebus_attach_args *pa = aux;
1695375dc7fSbjh21 	struct sec_softc *sc = device_private(self);
1705375dc7fSbjh21 	int i;
1715375dc7fSbjh21 
17211aab16bSbjh21 	sc->sc_sbic.sc_dev = self;
1735375dc7fSbjh21 	/* Set up bus spaces */
1745375dc7fSbjh21 	sc->sc_pod_t = pa->pa_fast_t;
1755375dc7fSbjh21 	bus_space_map(pa->pa_fast_t, pa->pa_fast_base, 0x1000, 0,
1765375dc7fSbjh21 	    &sc->sc_pod_h);
1775375dc7fSbjh21 	sc->sc_mod_t = pa->pa_mod_t;
1785375dc7fSbjh21 	bus_space_map(pa->pa_mod_t, pa->pa_mod_base, 0x1000, 0,
1795375dc7fSbjh21 	    &sc->sc_mod_h);
1805375dc7fSbjh21 
1815375dc7fSbjh21 	sc->sc_sbic.sc_regt = sc->sc_mod_t;
1820e95582eSrumble 	bus_space_subregion(sc->sc_mod_t, sc->sc_mod_h, SEC_SBIC + 0, 1,
1830e95582eSrumble 	    &sc->sc_sbic.sc_asr_regh);
1840e95582eSrumble 	bus_space_subregion(sc->sc_mod_t, sc->sc_mod_h, SEC_SBIC + 1, 1,
1850e95582eSrumble 	    &sc->sc_sbic.sc_data_regh);
1865375dc7fSbjh21 
1875375dc7fSbjh21 	sc->sc_sbic.sc_id = 7;
1885375dc7fSbjh21 	sc->sc_sbic.sc_clkfreq = SEC_CLKFREQ;
189439213efSbjh21 	sc->sc_sbic.sc_dmamode = SBIC_CTL_BURST_DMA;
1905375dc7fSbjh21 
1915375dc7fSbjh21 	sc->sc_sbic.sc_adapter.adapt_request = wd33c93_scsi_request;
1925375dc7fSbjh21 	sc->sc_sbic.sc_adapter.adapt_minphys = minphys;
1935375dc7fSbjh21 
1945375dc7fSbjh21 	sc->sc_sbic.sc_dmasetup = sec_dmasetup;
1955375dc7fSbjh21 	sc->sc_sbic.sc_dmago = sec_dmago;
1965375dc7fSbjh21 	sc->sc_sbic.sc_dmastop = sec_dmastop;
1975375dc7fSbjh21 	sc->sc_sbic.sc_reset = sec_reset;
1985375dc7fSbjh21 
1995375dc7fSbjh21 	sc->sc_mpr = 0;
2005375dc7fSbjh21 	bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr);
2015375dc7fSbjh21 
2025375dc7fSbjh21 	for (i = 0; i < SEC_NPAGES; i++) {
2035375dc7fSbjh21 		sec_setpage(sc, i);
2045375dc7fSbjh21 		bus_space_set_region_2(sc->sc_mod_t, sc->sc_mod_h,
2055375dc7fSbjh21 				       SEC_SRAM, 0, SEC_PAGESIZE / 2);
2065375dc7fSbjh21 	}
2075375dc7fSbjh21 
2085375dc7fSbjh21 	wd33c93_attach(&sc->sc_sbic);
2095375dc7fSbjh21 
2105375dc7fSbjh21 	evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
211801bd3ddScegger 	    device_xname(self), "intr");
2125375dc7fSbjh21 	sc->sc_ih = podulebus_irq_establish(pa->pa_ih, IPL_BIO, sec_intr,
2135375dc7fSbjh21 	    sc, &sc->sc_intrcnt);
2145375dc7fSbjh21 	sec_cli(sc);
2155375dc7fSbjh21 	sc->sc_mpr |= SEC_MPR_IE;
2165375dc7fSbjh21 	bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr);
217*b8f12c7fSmaya 	if (!pmf_device_register1(sc->sc_sbic.sc_dev, NULL, NULL, sec_shutdown))
218*b8f12c7fSmaya 		aprint_error_dev(sc->sc_sbic.sc_dev,
219*b8f12c7fSmaya 		    "couldn't establish power handler\n");
220bafb9c4fSbjh21 }
221bafb9c4fSbjh21 
222bafb9c4fSbjh21 /*
223bafb9c4fSbjh21  * Before reboot, reset the page register to 0 so that RISC OS can see
224bafb9c4fSbjh21  * the podule ROM.
225bafb9c4fSbjh21  */
2267f79b2d5Sbjh21 static bool
sec_shutdown(device_t dev,int howto)2277f79b2d5Sbjh21 sec_shutdown(device_t dev, int howto)
228bafb9c4fSbjh21 {
2297f79b2d5Sbjh21 	struct sec_softc *sc = device_private(dev);
230bafb9c4fSbjh21 
231bafb9c4fSbjh21 	sec_setpage(sc, 0);
2327f79b2d5Sbjh21 	return true;
2335375dc7fSbjh21 }
2345375dc7fSbjh21 
2355375dc7fSbjh21 static void
sec_copyin(struct sec_softc * sc,void * dest,int src,size_t size)2365375dc7fSbjh21 sec_copyin(struct sec_softc *sc, void *dest, int src, size_t size)
2375375dc7fSbjh21 {
2385375dc7fSbjh21 	uint16_t tmp, *wptr;
2395375dc7fSbjh21 	int cnt, extra_byte;
2405375dc7fSbjh21 
2415375dc7fSbjh21 	KASSERT(src >= 0);
2425375dc7fSbjh21 	KASSERT(src + size <= SEC_MEMSIZE);
2435375dc7fSbjh21 	if (src % 2 != 0) {
2445375dc7fSbjh21 		/*
2455375dc7fSbjh21 		 * There's a stray byte at the start.  Read the word
2465375dc7fSbjh21 		 * containing it.
2475375dc7fSbjh21 		 */
2485375dc7fSbjh21 		sec_setpage(sc, src / SEC_PAGESIZE);
2495375dc7fSbjh21 		tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h,
2505375dc7fSbjh21 		    SEC_SRAM + (src % SEC_PAGESIZE / 2));
2515375dc7fSbjh21 		*(uint8_t *)dest = tmp >> 8;
2525375dc7fSbjh21 		dest = ((uint8_t *)dest) + 1;
2535375dc7fSbjh21 		src++; size--;
2545375dc7fSbjh21 	}
2555375dc7fSbjh21 	KASSERT(src % 2 == 0);
2565375dc7fSbjh21 	KASSERT(ALIGNED_POINTER(dest, uint16_t));
2575375dc7fSbjh21 	wptr = dest;
2585375dc7fSbjh21 	extra_byte = size % 2;
2595375dc7fSbjh21 	size -= extra_byte;
2605375dc7fSbjh21 	while (size > 0) {
2615375dc7fSbjh21 		cnt = SEC_PAGESIZE - src % SEC_PAGESIZE;
2625375dc7fSbjh21 		if (cnt > size)
2635375dc7fSbjh21 			cnt = size;
2645375dc7fSbjh21 		sec_setpage(sc, src / SEC_PAGESIZE);
2655375dc7fSbjh21 		/* bus ops are in words */
2665375dc7fSbjh21 		bus_space_read_region_2(sc->sc_mod_t, sc->sc_mod_h,
2675375dc7fSbjh21 		    SEC_SRAM + src % SEC_PAGESIZE / 2, wptr, cnt / 2);
2685375dc7fSbjh21 		src += cnt;
2695375dc7fSbjh21 		wptr += cnt / 2;
2705375dc7fSbjh21 		size -= cnt;
2715375dc7fSbjh21 	}
2725375dc7fSbjh21 	if (extra_byte) {
2735375dc7fSbjh21 		sec_setpage(sc, src / SEC_PAGESIZE);
2745375dc7fSbjh21 		*(u_int8_t *)wptr =
2755375dc7fSbjh21 		    bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h,
2765375dc7fSbjh21 		    SEC_SRAM + src % SEC_PAGESIZE / 2) & 0xff;
2775375dc7fSbjh21 	}
2785375dc7fSbjh21 }
2795375dc7fSbjh21 
2805375dc7fSbjh21 static void
sec_copyout(struct sec_softc * sc,const void * src,int dest,size_t size)2815375dc7fSbjh21 sec_copyout(struct sec_softc *sc, const void *src, int dest, size_t size)
2825375dc7fSbjh21 {
2835375dc7fSbjh21 	int cnt, extra_byte;
2845375dc7fSbjh21 	const uint16_t *wptr;
2855375dc7fSbjh21 	uint16_t tmp;
2865375dc7fSbjh21 
2875375dc7fSbjh21 	KASSERT(dest >= 0);
2885375dc7fSbjh21 	KASSERT(dest + size <= SEC_MEMSIZE);
2895375dc7fSbjh21 	if (dest % 2 != 0) {
2905375dc7fSbjh21 		/*
2915375dc7fSbjh21 		 * There's a stray byte at the start.  Read the word
2925375dc7fSbjh21 		 * containing it.
2935375dc7fSbjh21 		 */
2945375dc7fSbjh21 		sec_setpage(sc, dest / SEC_PAGESIZE);
2955375dc7fSbjh21 		tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h,
2965375dc7fSbjh21 		    SEC_SRAM + (dest % SEC_PAGESIZE / 2));
2975375dc7fSbjh21 		tmp &= 0xff;
2985375dc7fSbjh21 		tmp |= *(uint8_t const *)src << 8;
2995375dc7fSbjh21 		bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h,
3005375dc7fSbjh21 		    SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp);
3015375dc7fSbjh21 		src = ((uint8_t const *)src) + 1;
3025375dc7fSbjh21 		dest++; size--;
3035375dc7fSbjh21 	}
3045375dc7fSbjh21 	KASSERT(dest % 2 == 0);
3055375dc7fSbjh21 	KASSERT(ALIGNED_POINTER(src, uint16_t));
3065375dc7fSbjh21 	wptr = src;
3075375dc7fSbjh21 	extra_byte = size % 2;
3085375dc7fSbjh21 	size -= extra_byte;
3095375dc7fSbjh21 	while (size > 0) {
3105375dc7fSbjh21 		cnt = SEC_PAGESIZE - dest % SEC_PAGESIZE;
3115375dc7fSbjh21 		if (cnt > size)
3125375dc7fSbjh21 			cnt = size;
3135375dc7fSbjh21 		sec_setpage(sc, dest / SEC_PAGESIZE);
3145375dc7fSbjh21 		/* bus ops are in words */
3155375dc7fSbjh21 		bus_space_write_region_2(sc->sc_mod_t, sc->sc_mod_h,
3165375dc7fSbjh21 		    dest % SEC_PAGESIZE / 2, wptr, cnt / 2);
3175375dc7fSbjh21 		wptr += cnt / 2;
3185375dc7fSbjh21 		dest += cnt;
3195375dc7fSbjh21 		size -= cnt;
3205375dc7fSbjh21 	}
3215375dc7fSbjh21 	if (extra_byte) {
3225375dc7fSbjh21 		/*
3235375dc7fSbjh21 		 * There's a stray byte at the end.  Read the word
3245375dc7fSbjh21 		 * containing it.
3255375dc7fSbjh21 		 */
3265375dc7fSbjh21 		sec_setpage(sc, dest / SEC_PAGESIZE);
3275375dc7fSbjh21 		tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h,
3285375dc7fSbjh21 		    SEC_SRAM + (dest % SEC_PAGESIZE / 2));
3295375dc7fSbjh21 		tmp &= 0xff00;
3305375dc7fSbjh21 		tmp |= *(uint8_t const *)wptr;
3315375dc7fSbjh21 		bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h,
3325375dc7fSbjh21 		    SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp);
3335375dc7fSbjh21 	}
3345375dc7fSbjh21 }
3355375dc7fSbjh21 
3365375dc7fSbjh21 static void
sec_dmablk(struct sec_softc * sc,int blk)3375375dc7fSbjh21 sec_dmablk(struct sec_softc *sc, int blk)
3385375dc7fSbjh21 {
3395375dc7fSbjh21 	int off;
3405375dc7fSbjh21 	size_t len;
3415375dc7fSbjh21 
3425375dc7fSbjh21 	KASSERT(blk >= 0);
3435375dc7fSbjh21 	KASSERT(blk * SEC_DMABLK < sc->sc_dmalen);
3445375dc7fSbjh21 	off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff;
3455375dc7fSbjh21 	len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK));
3465375dc7fSbjh21 	dmac_write(sc, NEC71071_ADDRLO, off & 0xff);
3475375dc7fSbjh21 	dmac_write(sc, NEC71071_ADDRMID, off >> 8);
3485375dc7fSbjh21 	dmac_write(sc, NEC71071_ADDRHI, 0);
3495375dc7fSbjh21 	/*
3505375dc7fSbjh21 	 * "Note: The number of DMA transfer cycles is actually the
3515375dc7fSbjh21 	 * value of the current count register + 1.  Therefore, when
3525375dc7fSbjh21 	 * programming the count register, specify the number of DMA
3535375dc7fSbjh21 	 * transfers minus one." -- uPD71071 datasheet
3545375dc7fSbjh21 	 */
3555375dc7fSbjh21 	dmac_write(sc, NEC71071_COUNTLO, (len - 1) & 0xff);
3565375dc7fSbjh21 	dmac_write(sc, NEC71071_COUNTHI, (len - 1) >> 8);
3575375dc7fSbjh21 }
3585375dc7fSbjh21 
3595375dc7fSbjh21 static void
sec_copyoutblk(struct sec_softc * sc,int blk)3608ca76bdcSbjh21 sec_copyoutblk(struct sec_softc *sc, int blk)
3615375dc7fSbjh21 {
3625375dc7fSbjh21 	int off;
3635375dc7fSbjh21 	size_t len;
3645375dc7fSbjh21 
3655375dc7fSbjh21 	KASSERT(blk >= 0);
3665375dc7fSbjh21 	KASSERT(blk * SEC_DMABLK < sc->sc_dmalen);
3678ca76bdcSbjh21 	KASSERT(!sc->sc_dmain);
3685375dc7fSbjh21 	off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff;
3695375dc7fSbjh21 	len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK));
3707a898113She 	sec_copyout(sc, (char*)sc->sc_dmaaddr + (blk * SEC_DMABLK), off, len);
3718ca76bdcSbjh21 }
3728ca76bdcSbjh21 
3738ca76bdcSbjh21 static void
sec_copyinblk(struct sec_softc * sc,int blk)3748ca76bdcSbjh21 sec_copyinblk(struct sec_softc *sc, int blk)
3758ca76bdcSbjh21 {
3768ca76bdcSbjh21 	int off;
3778ca76bdcSbjh21 	size_t len;
3788ca76bdcSbjh21 
3798ca76bdcSbjh21 	KASSERT(blk >= 0);
3808ca76bdcSbjh21 	KASSERT(blk * SEC_DMABLK < sc->sc_dmalen);
3818ca76bdcSbjh21 	KASSERT(sc->sc_dmain);
3828ca76bdcSbjh21 	off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff;
3838ca76bdcSbjh21 	len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK));
3847a898113She 	sec_copyin(sc, (char*)sc->sc_dmaaddr + (blk * SEC_DMABLK), off, len);
3855375dc7fSbjh21 }
3865375dc7fSbjh21 
3875375dc7fSbjh21 static int
sec_dmasetup(struct wd33c93_softc * sc_sbic,void ** addr,size_t * len,int datain,size_t * dmasize)38853524e44Schristos sec_dmasetup(struct wd33c93_softc *sc_sbic, void **addr, size_t *len,
3895375dc7fSbjh21     int datain, size_t *dmasize)
3905375dc7fSbjh21 {
3915375dc7fSbjh21 	struct sec_softc *sc = (struct sec_softc *)sc_sbic;
3925375dc7fSbjh21 	uint8_t mode;
3935375dc7fSbjh21 
3945375dc7fSbjh21 	sc->sc_dmaaddr = *addr;
3955375dc7fSbjh21 	sc->sc_dmaoff = ALIGNED_POINTER(*addr, uint16_t) ? 0 : 1;
3965375dc7fSbjh21 	sc->sc_dmalen = *len;
3975375dc7fSbjh21 	sc->sc_dmain = datain;
3985375dc7fSbjh21 	sc->sc_dmablk = 0;
3995375dc7fSbjh21 	mode = SEC_DMAMODE | (datain ? MODE_TDIR_IOTM : MODE_TDIR_MTIO);
4005375dc7fSbjh21 	/* Program first block into DMAC and queue up second. */
4015375dc7fSbjh21 	dmac_write(sc, NEC71071_CHANNEL, 0);
4028ca76bdcSbjh21 	if (!sc->sc_dmain)
4038ca76bdcSbjh21 		sec_copyoutblk(sc, 0);
4045375dc7fSbjh21 	sec_dmablk(sc, 0);
4055375dc7fSbjh21 	/* Mode control register */
4065375dc7fSbjh21 	dmac_write(sc, NEC71071_MODE, mode);
4075375dc7fSbjh21 	return sc->sc_dmalen;
4085375dc7fSbjh21 }
4095375dc7fSbjh21 
4105375dc7fSbjh21 static int
sec_dmago(struct wd33c93_softc * sc_sbic)4115375dc7fSbjh21 sec_dmago(struct wd33c93_softc *sc_sbic)
4125375dc7fSbjh21 {
4135375dc7fSbjh21 	struct sec_softc *sc = (struct sec_softc *)sc_sbic;
4145375dc7fSbjh21 
4155375dc7fSbjh21 	dmac_write(sc, NEC71071_MASK, 0xe);
416a3ad5d72Sbjh21 	sc->sc_dmaactive = true;
4178ca76bdcSbjh21 	if (!sc->sc_dmain && sc->sc_dmalen > SEC_DMABLK)
4188ca76bdcSbjh21 		sec_copyoutblk(sc, 1);
4195375dc7fSbjh21 	return sc->sc_dmalen;
4205375dc7fSbjh21 }
4215375dc7fSbjh21 
4225375dc7fSbjh21 static void
sec_dmastop(struct wd33c93_softc * sc_sbic)4235375dc7fSbjh21 sec_dmastop(struct wd33c93_softc *sc_sbic)
4245375dc7fSbjh21 {
4255375dc7fSbjh21 	struct sec_softc *sc = (struct sec_softc *)sc_sbic;
4265375dc7fSbjh21 
4275375dc7fSbjh21 	dmac_write(sc, NEC71071_MASK, 0xf);
4288ca76bdcSbjh21 	if (sc->sc_dmaactive && sc->sc_dmain)
4298ca76bdcSbjh21 		sec_copyinblk(sc, sc->sc_dmablk);
430a3ad5d72Sbjh21 	sc->sc_dmaactive = false;
4315375dc7fSbjh21 }
4325375dc7fSbjh21 
4335375dc7fSbjh21 /*
4345375dc7fSbjh21  * Reset the SCSI bus, and incidentally the SBIC and DMAC.
4355375dc7fSbjh21  */
4365375dc7fSbjh21 static void
sec_reset(struct wd33c93_softc * sc_sbic)4375375dc7fSbjh21 sec_reset(struct wd33c93_softc *sc_sbic)
4385375dc7fSbjh21 {
4395375dc7fSbjh21 	struct sec_softc *sc = (struct sec_softc *)sc_sbic;
4405375dc7fSbjh21 	uint8_t asr, csr;
4415375dc7fSbjh21 
4425375dc7fSbjh21 	bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR,
4435375dc7fSbjh21 	    sc->sc_mpr | SEC_MPR_UR);
4445375dc7fSbjh21 	DELAY(7);
4455375dc7fSbjh21 	bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr);
4465375dc7fSbjh21 	/* Wait for and clear the reset-complete interrupt */
4475375dc7fSbjh21 	do
4485375dc7fSbjh21 		GET_SBIC_asr(sc_sbic, asr);
4495375dc7fSbjh21 	while (!(asr & SBIC_ASR_INT));
4505375dc7fSbjh21 	GET_SBIC_csr(sc_sbic, csr);
451fa70b039Schristos 	__USE(csr);
4525375dc7fSbjh21 	dmac_write(sc, NEC71071_DCTRL1, DCTRL1_CMP | DCTRL1_RQL);
4535375dc7fSbjh21 	dmac_write(sc, NEC71071_DCTRL2, 0);
4545375dc7fSbjh21 	sec_cli(sc);
4555375dc7fSbjh21 }
4565375dc7fSbjh21 
4575375dc7fSbjh21 static int
sec_intr(void * arg)4585375dc7fSbjh21 sec_intr(void *arg)
4595375dc7fSbjh21 {
4605375dc7fSbjh21 	struct sec_softc *sc = arg;
4615375dc7fSbjh21 	u_int8_t isr;
4625375dc7fSbjh21 
4635375dc7fSbjh21 	isr = bus_space_read_1(sc->sc_pod_t, sc->sc_pod_h, SEC_ISR);
4645375dc7fSbjh21 	if (!(isr & SEC_ISR_IRQ))
4655375dc7fSbjh21 		return 0;
4665375dc7fSbjh21 	if (isr & SEC_ISR_DMAC)
4675375dc7fSbjh21 		sec_dmatc(sc);
4685375dc7fSbjh21 	if (isr & SEC_ISR_SBIC)
4695375dc7fSbjh21 		wd33c93_intr(&sc->sc_sbic);
4705375dc7fSbjh21 	return 1;
4715375dc7fSbjh21 }
4725375dc7fSbjh21 
4735375dc7fSbjh21 static int
sec_dmatc(struct sec_softc * sc)4745375dc7fSbjh21 sec_dmatc(struct sec_softc *sc)
4755375dc7fSbjh21 {
4765375dc7fSbjh21 
4775375dc7fSbjh21 	sec_cli(sc);
4785375dc7fSbjh21 	/* DMAC finished block n-1 and is now working on block n */
4795375dc7fSbjh21 	sc->sc_dmablk++;
4808ca76bdcSbjh21 	if (sc->sc_dmalen > sc->sc_dmablk * SEC_DMABLK) {
4818ca76bdcSbjh21 		dmac_write(sc, NEC71071_CHANNEL, 0);
4828ca76bdcSbjh21 		sec_dmablk(sc, sc->sc_dmablk);
4838ca76bdcSbjh21 		dmac_write(sc, NEC71071_MASK, 0xe);
4848ca76bdcSbjh21 		if (!sc->sc_dmain &&
4858ca76bdcSbjh21 		    sc->sc_dmalen > (sc->sc_dmablk + 1) * SEC_DMABLK)
4868ca76bdcSbjh21 			sec_copyoutblk(sc, sc->sc_dmablk + 1);
4875375dc7fSbjh21 	} else {
4885375dc7fSbjh21 		/* All blocks fully processed. */
489a3ad5d72Sbjh21 		sc->sc_dmaactive = false;
4905375dc7fSbjh21 	}
4918ca76bdcSbjh21 	if (sc->sc_dmain)
4928ca76bdcSbjh21 		sec_copyinblk(sc, sc->sc_dmablk - 1);
4935375dc7fSbjh21 	return 1;
4945375dc7fSbjh21 }
4955375dc7fSbjh21 
4965375dc7fSbjh21 #ifdef DDB
4975375dc7fSbjh21 void
sec_dumpdma(void * arg)4985375dc7fSbjh21 sec_dumpdma(void *arg)
4995375dc7fSbjh21 {
5005375dc7fSbjh21 	struct sec_softc *sc = arg;
5015375dc7fSbjh21 
5025375dc7fSbjh21 	dmac_write(sc, NEC71071_CHANNEL, 0);
5035375dc7fSbjh21 	printf("%s: DMA state: cur count %02x%02x cur addr %02x%02x%02x ",
50411aab16bSbjh21 	    device_xname(sc->sc_sbic.sc_dev),
5055375dc7fSbjh21 	    dmac_read(sc, NEC71071_COUNTHI), dmac_read(sc, NEC71071_COUNTLO),
5065375dc7fSbjh21 	    dmac_read(sc, NEC71071_ADDRHI), dmac_read(sc, NEC71071_ADDRMID),
5075375dc7fSbjh21 	    dmac_read(sc, NEC71071_ADDRLO));
5085375dc7fSbjh21 	dmac_write(sc, NEC71071_CHANNEL, 0 | CHANNEL_WBASE);
5095375dc7fSbjh21 	printf("base count %02x%02x base addr %02x%02x%02x\n",
5105375dc7fSbjh21 	    dmac_read(sc, NEC71071_COUNTHI), dmac_read(sc, NEC71071_COUNTLO),
5115375dc7fSbjh21 	    dmac_read(sc, NEC71071_ADDRHI), dmac_read(sc, NEC71071_ADDRMID),
5125375dc7fSbjh21 	    dmac_read(sc, NEC71071_ADDRLO));
5135375dc7fSbjh21 	printf("%s: DMA state: dctrl %1x%02x mode %02x status %02x req %02x "
5145375dc7fSbjh21 	    "mask %02x\n",
51511aab16bSbjh21 	    device_xname(sc->sc_sbic.sc_dev), dmac_read(sc, NEC71071_DCTRL2),
5165375dc7fSbjh21 	    dmac_read(sc, NEC71071_DCTRL1), dmac_read(sc, NEC71071_MODE),
5175375dc7fSbjh21 	    dmac_read(sc, NEC71071_STATUS), dmac_read(sc, NEC71071_REQUEST),
5185375dc7fSbjh21 	    dmac_read(sc, NEC71071_MASK));
51911aab16bSbjh21 	printf("%s: soft DMA state: %zd@%p%s%d\n",
52011aab16bSbjh21 	    device_xname(sc->sc_sbic.sc_dev),
5215375dc7fSbjh21 	    sc->sc_dmalen, sc->sc_dmaaddr, sc->sc_dmain ? "<-" : "->",
5225375dc7fSbjh21 	    sc->sc_dmaoff);
5235375dc7fSbjh21 }
5245375dc7fSbjh21 
5255375dc7fSbjh21 void sec_dumpall(void); /* Call from DDB */
5265375dc7fSbjh21 
5275375dc7fSbjh21 extern struct cfdriver sec_cd;
5285375dc7fSbjh21 
sec_dumpall(void)5295375dc7fSbjh21 void sec_dumpall(void)
5305375dc7fSbjh21 {
5315375dc7fSbjh21 	int i;
5323bde75a1Scegger 	struct sec_softc *sc;
5335375dc7fSbjh21 
5343bde75a1Scegger 	for (i = 0; i < sec_cd.cd_ndevs; ++i) {
5353bde75a1Scegger 		sc = device_lookup_private(&sec_cd, i);
5363bde75a1Scegger 		if (sc != NULL)
5373bde75a1Scegger 			sec_dumpdma(sc);
5383bde75a1Scegger 	}
5395375dc7fSbjh21 }
5405375dc7fSbjh21 #endif
541