179697Snon/*	$NecBSD: bshw_machdep.c,v 1.8.12.6 2001/06/29 06:28:05 honda Exp $	*/
2119418Sobrien
3119418Sobrien#include <sys/cdefs.h>
4119418Sobrien__FBSDID("$FreeBSD$");
573149Snyan/*	$NetBSD$	*/
673149Snyan
7139749Simp/*-
873149Snyan * [NetBSD for NEC PC-98 series]
979697Snon *  Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
1073149Snyan *	NetBSD/pc98 porting staff. All rights reserved.
1173149Snyan *
1279697Snon *  Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
1373149Snyan *	Naofumi HONDA.  All rights reserved.
1473149Snyan *
1573149Snyan *  Redistribution and use in source and binary forms, with or without
1673149Snyan *  modification, are permitted provided that the following conditions
1773149Snyan *  are met:
1873149Snyan *  1. Redistributions of source code must retain the above copyright
1973149Snyan *     notice, this list of conditions and the following disclaimer.
2073149Snyan *  2. Redistributions in binary form must reproduce the above copyright
2173149Snyan *     notice, this list of conditions and the following disclaimer in the
2273149Snyan *     documentation and/or other materials provided with the distribution.
2373149Snyan *  3. The name of the author may not be used to endorse or promote products
2473149Snyan *     derived from this software without specific prior written permission.
2573149Snyan *
2673149Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2773149Snyan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2873149Snyan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2973149Snyan * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
3073149Snyan * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3173149Snyan * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3273149Snyan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3373149Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3473149Snyan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3573149Snyan * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3673149Snyan * POSSIBILITY OF SUCH DAMAGE.
3773149Snyan */
3873149Snyan
3973149Snyan#include "opt_ddb.h"
4073149Snyan
4173149Snyan#include <sys/param.h>
4273149Snyan#include <sys/systm.h>
4373149Snyan#include <sys/kernel.h>
4479697Snon#if defined(__FreeBSD__) && __FreeBSD_version > 500001
4573149Snyan#include <sys/bio.h>
4679697Snon#endif	/* __ FreeBSD__ */
4773149Snyan#include <sys/buf.h>
4873149Snyan#include <sys/queue.h>
4973149Snyan#include <sys/malloc.h>
5073149Snyan#include <sys/errno.h>
5173149Snyan
5273149Snyan#include <vm/vm.h>
5373149Snyan
5473149Snyan#ifdef __NetBSD__
5579697Snon#include <sys/device.h>
5679697Snon
5773149Snyan#include <machine/bus.h>
5873149Snyan#include <machine/intr.h>
5973149Snyan
6073149Snyan#include <dev/scsipi/scsi_all.h>
6173149Snyan#include <dev/scsipi/scsipi_all.h>
6273149Snyan#include <dev/scsipi/scsiconf.h>
6373149Snyan#include <dev/scsipi/scsi_disk.h>
6473149Snyan
6573149Snyan#include <machine/dvcfg.h>
6673149Snyan#include <machine/physio_proc.h>
6773149Snyan
6873149Snyan#include <i386/Cbus/dev/scsi_low.h>
6973149Snyan
7073149Snyan#include <dev/ic/wd33c93reg.h>
7173149Snyan#include <i386/Cbus/dev/ct/ctvar.h>
7279697Snon#include <i386/Cbus/dev/ct/ct_machdep.h>
7373149Snyan#include <i386/Cbus/dev/ct/bshwvar.h>
7473149Snyan#endif /* __NetBSD__ */
7573149Snyan
7673149Snyan#ifdef __FreeBSD__
7773149Snyan#include <machine/bus.h>
7873149Snyan#include <machine/md_var.h>
7973149Snyan
80126928Speter#include <compat/netbsd/dvcfg.h>
81126928Speter#include <compat/netbsd/physio_proc.h>
8273149Snyan
8373149Snyan#include <cam/scsi/scsi_low.h>
8473149Snyan
8578209Snyan#include <dev/ic/wd33c93reg.h>
8673149Snyan#include <dev/ct/ctvar.h>
8779697Snon#include <dev/ct/ct_machdep.h>
8873149Snyan#include <dev/ct/bshwvar.h>
8979697Snon
9079697Snon#include <vm/pmap.h>
9173149Snyan#endif /* __FreeBSD__ */
9273149Snyan
9379697Snon#define	BSHW_IO_CONTROL_FLAGS	0
9479697Snon
9579697Snonu_int bshw_io_control = BSHW_IO_CONTROL_FLAGS;
9679697Snonint bshw_data_read_bytes = 4096;
9779697Snonint bshw_data_write_bytes = 4096;
9879697Snon
9973149Snyan/*********************************************************
10079697Snon * OS dep part
10179697Snon *********************************************************/
10279697Snon#ifdef	__NetBSD__
10379697Snon#define	BSHW_PAGE_SIZE NBPG
10479697Snon#endif	/* __NetBSD__ */
10579697Snon
10679697Snon#ifdef	__FreeBSD__
10779697Snon#define	BSHW_PAGE_SIZE PAGE_SIZE
10879697Snontypedef	unsigned long vaddr_t;
10979697Snon#endif /* __FreeBSD__ */
11079697Snon
11179697Snon/*********************************************************
11273149Snyan * GENERIC MACHDEP FUNCTIONS
11373149Snyan *********************************************************/
11473149Snyanvoid
115243455Snyanbshw_synch_setup(struct ct_softc *ct, struct targ_info *ti)
11673149Snyan{
11779697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
11873149Snyan	struct ct_targ_info *cti = (void *) ti;
11973149Snyan	struct bshw_softc *bs = ct->ct_hw;
12073149Snyan	struct bshw *hw = bs->sc_hw;
12173149Snyan
12279697Snon	if (hw->hw_sregaddr == 0)
12373149Snyan		return;
12473149Snyan
12579697Snon	ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id, cti->cti_syncreg);
12673149Snyan	if (hw->hw_flags & BSHW_DOUBLE_DMACHAN)
12773149Snyan	{
12879697Snon		ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id + 8,
12973149Snyan			      cti->cti_syncreg);
13073149Snyan	}
13173149Snyan}
13273149Snyan
13373149Snyanvoid
134243455Snyanbshw_bus_reset(struct ct_softc *ct)
13573149Snyan{
13673149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
13779697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
13873149Snyan	struct bshw_softc *bs = ct->ct_hw;
13973149Snyan	struct bshw *hw = bs->sc_hw;
14073149Snyan	bus_addr_t offs;
14173149Snyan	u_int8_t regv;
14273149Snyan	int i;
14373149Snyan
14473149Snyan	/* open hardware busmaster mode */
14579697Snon	if (hw->hw_dma_init != NULL && ((*hw->hw_dma_init)(ct)) != 0)
14673149Snyan	{
14779697Snon		printf("%s: change mode using external DMA (%x)\n",
14879697Snon		    slp->sl_xname, (u_int)ct_cr_read_1(chp, 0x37));
14973149Snyan	}
15073149Snyan
15173149Snyan	/* clear hardware synch registers */
15279697Snon	offs = hw->hw_sregaddr;
15373149Snyan	if (offs != 0)
15473149Snyan	{
15573149Snyan		for (i = 0; i < 8; i ++, offs ++)
15673149Snyan		{
15779697Snon			ct_cr_write_1(chp, offs, 0);
15873149Snyan			if ((hw->hw_flags & BSHW_DOUBLE_DMACHAN) != 0)
15979697Snon				ct_cr_write_1(chp, offs + 8, 0);
16073149Snyan		}
16173149Snyan	}
16273149Snyan
16373149Snyan	/* disable interrupt & assert reset */
16479697Snon	regv = ct_cr_read_1(chp, wd3s_mbank);
16573149Snyan	regv |= MBR_RST;
16673149Snyan	regv &= ~MBR_IEN;
16779697Snon	ct_cr_write_1(chp, wd3s_mbank, regv);
16873149Snyan
16979697Snon	SCSI_LOW_DELAY(500000);
17073149Snyan
17173149Snyan	/* reset signal off */
17273149Snyan	regv &= ~MBR_RST;
17379697Snon	ct_cr_write_1(chp, wd3s_mbank, regv);
17473149Snyan
17573149Snyan	/* interrupt enable */
17673149Snyan	regv |= MBR_IEN;
17779697Snon	ct_cr_write_1(chp, wd3s_mbank, regv);
17873149Snyan}
17973149Snyan
18073149Snyan/* probe */
18173149Snyanint
182243455Snyanbshw_read_settings(struct ct_bus_access_handle *chp, struct bshw_softc *bs)
18373149Snyan{
18473149Snyan	static int irq_tbl[] = { 3, 5, 6, 9, 12, 13 };
18573149Snyan
18679697Snon	bs->sc_hostid = (ct_cr_read_1(chp, wd3s_auxc) & AUXCR_HIDM);
18779697Snon	bs->sc_irq = irq_tbl[(ct_cr_read_1(chp, wd3s_auxc) >> 3) & 7];
18879697Snon	bs->sc_drq = ct_cmdp_read_1(chp) & 3;
18973149Snyan	return 0;
19073149Snyan}
19173149Snyan
19273149Snyan/*********************************************************
19373149Snyan * DMA PIO TRANSFER (SMIT)
19473149Snyan *********************************************************/
19573149Snyan#define	LC_SMIT_TIMEOUT	2	/* 2 sec: timeout for a fifo status ready */
19673149Snyan#define	LC_SMIT_OFFSET	0x1000
19773149Snyan#define	LC_FSZ		DEV_BSIZE
19873149Snyan#define	LC_SFSZ		0x0c
19973149Snyan#define	LC_REST		(LC_FSZ - LC_SFSZ)
20073149Snyan
20173149Snyan#define	BSHW_LC_FSET	0x36
20273149Snyan#define	BSHW_LC_FCTRL	0x44
20373149Snyan#define	FCTRL_EN	0x01
20473149Snyan#define	FCTRL_WRITE	0x02
20573149Snyan
20673149Snyan#define	SF_ABORT	0x08
20773149Snyan#define	SF_RDY		0x10
20873149Snyan
20992739Salfredstatic __inline void bshw_lc_smit_start(struct ct_softc *, int, u_int);
21092739Salfredstatic __inline void bshw_lc_smit_stop(struct ct_softc *);
21192739Salfredstatic int bshw_lc_smit_fstat(struct ct_softc *, int, int);
21273149Snyan
21373149Snyanstatic __inline void
214243455Snyanbshw_lc_smit_stop(struct ct_softc *ct)
21573149Snyan{
21679697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
21773149Snyan
21879697Snon	ct_cr_write_1(chp, BSHW_LC_FCTRL, 0);
21979697Snon	ct_cmdp_write_1(chp, CMDP_DMER);
22073149Snyan}
22173149Snyan
22273149Snyanstatic __inline void
223243455Snyanbshw_lc_smit_start(struct ct_softc *ct, int count, u_int direction)
22473149Snyan{
22579697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
22673149Snyan	u_int8_t pval, val;
22773149Snyan
22879697Snon	val = ct_cr_read_1(chp, BSHW_LC_FSET);
22979697Snon	cthw_set_count(chp, count);
23073149Snyan
23173149Snyan	pval = FCTRL_EN;
23273149Snyan	if (direction == SCSI_LOW_WRITE)
23373149Snyan		pval |= (val & 0xe0) | FCTRL_WRITE;
23479697Snon	ct_cr_write_1(chp, BSHW_LC_FCTRL, pval);
23579697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
23673149Snyan}
23773149Snyan
23873149Snyanstatic int
239243455Snyanbshw_lc_smit_fstat(struct ct_softc *ct, int wc, int read)
24073149Snyan{
24179697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
24273149Snyan	u_int8_t stat;
24373149Snyan
24473149Snyan	while (wc -- > 0)
24573149Snyan	{
24679697Snon		chp->ch_bus_weight(chp);
24779697Snon		stat = ct_cmdp_read_1(chp);
24873149Snyan		if (read == SCSI_LOW_READ)
24973149Snyan		{
25073149Snyan			if ((stat & SF_RDY) != 0)
25173149Snyan				return 0;
25273149Snyan			if ((stat & SF_ABORT) != 0)
25373149Snyan				return EIO;
25473149Snyan		}
25573149Snyan		else
25673149Snyan		{
25773149Snyan			if ((stat & SF_ABORT) != 0)
25873149Snyan				return EIO;
25973149Snyan			if ((stat & SF_RDY) != 0)
26073149Snyan				return 0;
26173149Snyan		}
26273149Snyan	}
26373149Snyan
26473149Snyan	printf("%s: SMIT fifo status timeout\n", ct->sc_sclow.sl_xname);
26573149Snyan	return EIO;
26673149Snyan}
26773149Snyan
26873149Snyanvoid
269243455Snyanbshw_smit_xfer_stop(struct ct_softc *ct)
27073149Snyan{
27173149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
27273149Snyan	struct bshw_softc *bs = ct->ct_hw;
27373149Snyan	struct targ_info *ti;
27473149Snyan	struct sc_p *sp = &slp->sl_scp;
27573149Snyan	u_int count;
27673149Snyan
27773149Snyan	bshw_lc_smit_stop(ct);
27873149Snyan
27979697Snon	ti = slp->sl_Tnexus;
28073149Snyan	if (ti == NULL)
28173149Snyan		return;
28273149Snyan
28373149Snyan	if (ti->ti_phase == PH_DATA)
28473149Snyan	{
28579697Snon		count = cthw_get_count(&ct->sc_ch);
28679697Snon		if (count < bs->sc_sdatalen)
28773149Snyan		{
28873149Snyan			if (sp->scp_direction == SCSI_LOW_READ &&
28979697Snon			    count != bs->sc_edatalen)
29073149Snyan				goto bad;
29179697Snon
29279697Snon			count = bs->sc_sdatalen - count;
29379697Snon			if (count > (u_int) sp->scp_datalen)
29479697Snon				goto bad;
29579697Snon
29679697Snon			sp->scp_data += count;
29779697Snon			sp->scp_datalen -= count;
29873149Snyan		}
29979697Snon		else if (count > bs->sc_sdatalen)
30073149Snyan		{
30179697Snonbad:
30279697Snon			printf("%s: smit_xfer_end: cnt error\n", slp->sl_xname);
30379697Snon			slp->sl_error |= PDMAERR;
30473149Snyan		}
30579697Snon		scsi_low_data_finish(slp);
30673149Snyan	}
30773149Snyan	else
30879697Snon	{
30979697Snon		printf("%s: smit_xfer_end: phase miss\n", slp->sl_xname);
31079697Snon		slp->sl_error |= PDMAERR;
31179697Snon	}
31273149Snyan}
31373149Snyan
31479697Snonint
315243455Snyanbshw_smit_xfer_start(struct ct_softc *ct)
31673149Snyan{
31773149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
31879697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
31973149Snyan	struct bshw_softc *bs = ct->ct_hw;
32073149Snyan	struct sc_p *sp = &slp->sl_scp;
32179697Snon	struct targ_info *ti = slp->sl_Tnexus;
32273149Snyan	struct ct_targ_info *cti = (void *) ti;
32379697Snon	u_int datalen, count, io_control;
32479697Snon	int wc;
32573149Snyan	u_int8_t *data;
32673149Snyan
32779697Snon	io_control = bs->sc_io_control | bshw_io_control;
32879697Snon	if ((io_control & BSHW_SMIT_BLOCK) != 0)
32979697Snon		return EINVAL;
33079697Snon
33179697Snon	if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0)
33279697Snon		return EINVAL;
33379697Snon
33473149Snyan	datalen = sp->scp_datalen;
33579697Snon	if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
33679697Snon	{
33779697Snon		if ((io_control & BSHW_READ_INTERRUPT_DRIVEN) != 0 &&
33879697Snon		     datalen > bshw_data_read_bytes)
33979697Snon			datalen = bshw_data_read_bytes;
34079697Snon	}
34179697Snon	else
34279697Snon	{
34379697Snon	        if ((io_control & BSHW_WRITE_INTERRUPT_DRIVEN) != 0 &&
34479697Snon		    datalen > bshw_data_write_bytes)
34579697Snon			datalen = bshw_data_write_bytes;
34679697Snon	}
34773149Snyan
34879697Snon	bs->sc_sdatalen = datalen;
34979697Snon	data = sp->scp_data;
35079697Snon 	wc = LC_SMIT_TIMEOUT * 1024 * 1024;
35173149Snyan
35279697Snon	ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
35379697Snon	bshw_lc_smit_start(ct, datalen, sp->scp_direction);
35479697Snon
35573149Snyan	if (sp->scp_direction == SCSI_LOW_READ)
35673149Snyan	{
35773149Snyan		do
35873149Snyan		{
35973149Snyan			if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_READ))
36073149Snyan				break;
36173149Snyan
36273149Snyan			count = (datalen > LC_FSZ ? LC_FSZ : datalen);
36379697Snon			bus_space_read_region_4(chp->ch_memt, chp->ch_memh,
36473149Snyan				LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2);
36573149Snyan			data += count;
36673149Snyan			datalen -= count;
36773149Snyan		}
36873149Snyan		while (datalen > 0);
36973149Snyan
37079697Snon		bs->sc_edatalen = datalen;
37173149Snyan	}
37273149Snyan	else
37373149Snyan	{
37473149Snyan		do
37573149Snyan		{
37673149Snyan			if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE))
37773149Snyan				break;
37873149Snyan			if (cti->cti_syncreg == 0)
37973149Snyan			{
38073149Snyan				/* XXX:
38173149Snyan				 * If async transfer, reconfirm a scsi phase
38273149Snyan				 * again. Unless C bus might hang up.
38373149Snyan			 	 */
38473149Snyan				if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE))
38573149Snyan					break;
38673149Snyan			}
38773149Snyan
38873149Snyan			count = (datalen > LC_SFSZ ? LC_SFSZ : datalen);
38979697Snon			bus_space_write_region_4(chp->ch_memt, chp->ch_memh,
39073149Snyan				LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2);
39173149Snyan			data += count;
39273149Snyan			datalen -= count;
39373149Snyan
39473149Snyan			if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE))
39573149Snyan				break;
39673149Snyan
39773149Snyan			count = (datalen > LC_REST ? LC_REST : datalen);
39879697Snon			bus_space_write_region_4(chp->ch_memt, chp->ch_memh,
39973149Snyan						 LC_SMIT_OFFSET + LC_SFSZ,
40073149Snyan						 (u_int32_t *) data, count >> 2);
40173149Snyan			data += count;
40273149Snyan			datalen -= count;
40373149Snyan		}
40473149Snyan		while (datalen > 0);
40573149Snyan	}
40679697Snon	return 0;
40773149Snyan}
40873149Snyan
40973149Snyan/*********************************************************
41073149Snyan * DMA TRANSFER (BS)
41173149Snyan *********************************************************/
41279697Snonstatic __inline void bshw_dma_write_1 \
41392739Salfred	(struct ct_bus_access_handle *, bus_addr_t, u_int8_t);
41492739Salfredstatic void bshw_dmastart(struct ct_softc *);
41592739Salfredstatic void bshw_dmadone(struct ct_softc *);
41673149Snyan
41779697Snonint
418243455Snyanbshw_dma_xfer_start(struct ct_softc *ct)
41973149Snyan{
42073149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
42173149Snyan	struct sc_p *sp = &slp->sl_scp;
42279697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
42373149Snyan	struct bshw_softc *bs = ct->ct_hw;
42473149Snyan	vaddr_t va, endva, phys, nphys;
42579697Snon	u_int io_control;
42673149Snyan
42779697Snon	io_control = bs->sc_io_control | bshw_io_control;
42879697Snon	if ((io_control & BSHW_DMA_BLOCK) != 0 && sp->scp_datalen < 256)
42979697Snon		return EINVAL;
43079697Snon
43179697Snon	ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
43273149Snyan	phys = vtophys((vaddr_t) sp->scp_data);
43373149Snyan	if (phys >= bs->sc_minphys)
43473149Snyan	{
43573149Snyan		/* setup segaddr */
43673149Snyan		bs->sc_segaddr = bs->sc_bounce_phys;
43773149Snyan		/* setup seglen */
43873149Snyan		bs->sc_seglen = sp->scp_datalen;
43973149Snyan		if (bs->sc_seglen > bs->sc_bounce_size)
44073149Snyan			bs->sc_seglen = bs->sc_bounce_size;
44173149Snyan		/* setup bufp */
44273149Snyan		bs->sc_bufp = bs->sc_bounce_addr;
44373149Snyan		if (sp->scp_direction == SCSI_LOW_WRITE)
44473149Snyan			bcopy(sp->scp_data, bs->sc_bufp, bs->sc_seglen);
44573149Snyan	}
44673149Snyan	else
44773149Snyan	{
44873149Snyan		/* setup segaddr */
44973149Snyan		bs->sc_segaddr = (u_int8_t *) phys;
45073149Snyan		/* setup seglen */
45179697Snon		endva = (vaddr_t) round_page((vaddr_t) sp->scp_data + sp->scp_datalen);
45273149Snyan		for (va = (vaddr_t) sp->scp_data; ; phys = nphys)
45373149Snyan		{
45479697Snon			if ((va += BSHW_PAGE_SIZE) >= endva)
45573149Snyan			{
45673149Snyan				bs->sc_seglen = sp->scp_datalen;
45773149Snyan				break;
45873149Snyan			}
45973149Snyan
46073149Snyan			nphys = vtophys(va);
46179697Snon			if (phys + BSHW_PAGE_SIZE != nphys || nphys >= bs->sc_minphys)
46273149Snyan			{
46373149Snyan				bs->sc_seglen =
46473149Snyan				    (u_int8_t *) trunc_page(va) - sp->scp_data;
46573149Snyan				break;
46673149Snyan			}
46773149Snyan		}
46873149Snyan		/* setup bufp */
46973149Snyan		bs->sc_bufp = NULL;
47073149Snyan	}
47173149Snyan
47273149Snyan	bshw_dmastart(ct);
47379697Snon	cthw_set_count(chp, bs->sc_seglen);
47479697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
47579697Snon	return 0;
47673149Snyan}
47773149Snyan
47873149Snyanvoid
479243455Snyanbshw_dma_xfer_stop(struct ct_softc *ct)
48073149Snyan{
48173149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
48273149Snyan	struct sc_p *sp = &slp->sl_scp;
48373149Snyan	struct bshw_softc *bs = ct->ct_hw;
48473149Snyan	struct targ_info *ti;
48573149Snyan	u_int count, transbytes;
48673149Snyan
48773149Snyan	bshw_dmadone(ct);
48873149Snyan
48979697Snon 	ti = slp->sl_Tnexus;
49073149Snyan	if (ti == NULL)
49173149Snyan		return;
49273149Snyan
49373149Snyan	if (ti->ti_phase == PH_DATA)
49473149Snyan	{
49579697Snon		count = cthw_get_count(&ct->sc_ch);
49673149Snyan		if (count < (u_int) bs->sc_seglen)
49773149Snyan		{
49873149Snyan			transbytes = bs->sc_seglen - count;
49973149Snyan			if (bs->sc_bufp != NULL &&
50073149Snyan			    sp->scp_direction == SCSI_LOW_READ)
50173149Snyan				bcopy(bs->sc_bufp, sp->scp_data, transbytes);
50273149Snyan
50373149Snyan			sp->scp_data += transbytes;
50473149Snyan			sp->scp_datalen -= transbytes;
50573149Snyan		}
50679697Snon		else if (count > (u_int) bs->sc_seglen)
50773149Snyan		{
50879697Snon			printf("%s: port data %x != seglen %x\n",
50979697Snon				slp->sl_xname, count, bs->sc_seglen);
51079697Snon			slp->sl_error |= PDMAERR;
51173149Snyan		}
51273149Snyan
51379697Snon		scsi_low_data_finish(slp);
51473149Snyan	}
51573149Snyan	else
51673149Snyan	{
51773149Snyan		printf("%s: extra DMA interrupt\n", slp->sl_xname);
51879697Snon		slp->sl_error |= PDMAERR;
51973149Snyan	}
52073149Snyan
52173149Snyan	bs->sc_bufp = NULL;
52273149Snyan}
52373149Snyan
52473149Snyan/* common dma settings */
52573149Snyan#undef	DMA1_SMSK
52673149Snyan#define DMA1_SMSK	(0x15)
52773149Snyan#undef	DMA1_MODE
52873149Snyan#define DMA1_MODE	(0x17)
52973149Snyan#undef	DMA1_FFC
53073149Snyan#define DMA1_FFC	(0x19)
53173149Snyan#undef	DMA1_CHN
53273149Snyan#define DMA1_CHN(c)	(0x01 + ((c) << 2))
53373149Snyan
53473149Snyan#define DMA37SM_SET	0x04
53573149Snyan#define	DMA37MD_WRITE	0x04
53673149Snyan#define	DMA37MD_READ	0x08
53773149Snyan#define	DMA37MD_SINGLE	0x40
53873149Snyan
53979697Snonstatic bus_addr_t dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 };
54079697Snon
54179697Snonstatic __inline void
542243455Snyanbshw_dma_write_1(struct ct_bus_access_handle *chp, bus_addr_t port,
543243455Snyan    u_int8_t val)
54479697Snon{
54579697Snon
54679697Snon	CT_BUS_WEIGHT(chp);
54779697Snon	outb(port, val);
54879697Snon}
54979697Snon
55073149Snyanstatic void
551243455Snyanbshw_dmastart(struct ct_softc *ct)
55273149Snyan{
55373149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
55473149Snyan	struct bshw_softc *bs = ct->ct_hw;
55579697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
55673149Snyan	int chan = bs->sc_drq;
55779697Snon	bus_addr_t waport;
55879697Snon	u_int8_t regv, *phys = bs->sc_segaddr;
55973149Snyan	u_int nbytes = bs->sc_seglen;
56073149Snyan
56179697Snon	/* flush cpu cache */
56279697Snon	(*bs->sc_dmasync_before) (ct);
56379697Snon
56473149Snyan	/*
56573149Snyan	 * Program one of DMA channels 0..3. These are
56673149Snyan	 * byte mode channels.
56773149Snyan	 */
56873149Snyan	/* set dma channel mode, and reset address ff */
56973149Snyan
57073149Snyan	if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
57179697Snon		regv = DMA37MD_WRITE | DMA37MD_SINGLE | chan;
57273149Snyan	else
57379697Snon		regv = DMA37MD_READ | DMA37MD_SINGLE | chan;
57473149Snyan
57579697Snon	bshw_dma_write_1(chp, DMA1_MODE, regv);
57679697Snon	bshw_dma_write_1(chp, DMA1_FFC, 0);
57779697Snon
57873149Snyan	/* send start address */
57973149Snyan	waport = DMA1_CHN(chan);
58079697Snon	bshw_dma_write_1(chp, waport, (u_int) phys);
58179697Snon	bshw_dma_write_1(chp, waport, ((u_int) phys) >> 8);
58279697Snon	bshw_dma_write_1(chp, dmapageport[chan], ((u_int) phys) >> 16);
58373149Snyan
58473149Snyan	/* send count */
58579697Snon	bshw_dma_write_1(chp, waport + 2, --nbytes);
58679697Snon	bshw_dma_write_1(chp, waport + 2, nbytes >> 8);
58773149Snyan
58873149Snyan	/* vendor unique hook */
58979697Snon	if (bs->sc_hw->hw_dma_start)
59079697Snon		(*bs->sc_hw->hw_dma_start)(ct);
59173149Snyan
59279697Snon	bshw_dma_write_1(chp, DMA1_SMSK, chan);
59379697Snon	ct_cmdp_write_1(chp, CMDP_DMES);
59473149Snyan}
59573149Snyan
59673149Snyanstatic void
597243455Snyanbshw_dmadone(struct ct_softc *ct)
59873149Snyan{
59973149Snyan	struct bshw_softc *bs = ct->ct_hw;
60079697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
60173149Snyan
60279697Snon	bshw_dma_write_1(chp, DMA1_SMSK, (bs->sc_drq | DMA37SM_SET));
60379697Snon	ct_cmdp_write_1(chp, CMDP_DMER);
60473149Snyan
60573149Snyan	/* vendor unique hook */
60679697Snon	if (bs->sc_hw->hw_dma_stop)
60779697Snon		(*bs->sc_hw->hw_dma_stop) (ct);
60873149Snyan
60979697Snon	/* flush cpu cache */
61079697Snon	(*bs->sc_dmasync_after) (ct);
61173149Snyan}
61273149Snyan
61373149Snyan/**********************************************
61473149Snyan * VENDOR UNIQUE DMA FUNCS
61573149Snyan **********************************************/
61692739Salfredstatic int bshw_dma_init_sc98(struct ct_softc *);
61792739Salfredstatic void bshw_dma_start_sc98(struct ct_softc *);
61892739Salfredstatic void bshw_dma_stop_sc98(struct ct_softc *);
61992739Salfredstatic int bshw_dma_init_texa(struct ct_softc *);
62092739Salfredstatic void bshw_dma_start_elecom(struct ct_softc *);
62192739Salfredstatic void bshw_dma_stop_elecom(struct ct_softc *);
62273149Snyan
62373149Snyanstatic int
624243455Snyanbshw_dma_init_texa(struct ct_softc *ct)
62573149Snyan{
62679697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
62773149Snyan	u_int8_t regval;
62873149Snyan
62979697Snon	if ((regval = ct_cr_read_1(chp, 0x37)) & 0x08)
63073149Snyan		return 0;
63173149Snyan
63279697Snon	ct_cr_write_1(chp, 0x37, regval | 0x08);
63379697Snon	regval = ct_cr_read_1(chp, 0x3f);
63479697Snon	ct_cr_write_1(chp, 0x3f, regval | 0x08);
63573149Snyan	return 1;
63673149Snyan}
63773149Snyan
63873149Snyanstatic int
639243455Snyanbshw_dma_init_sc98(struct ct_softc *ct)
64073149Snyan{
64179697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
64273149Snyan
64379697Snon	if (ct_cr_read_1(chp, 0x37) & 0x08)
64473149Snyan		return 0;
64573149Snyan
64673149Snyan	/* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */
64779697Snon	ct_cr_write_1(chp, 0x37, 0x1a);
64879697Snon	ct_cr_write_1(chp, 0x3f, 0x1a);
64973149Snyan#if	0
65073149Snyan	/* only valid for IO */
65179697Snon	ct_cr_write_1(chp, 0x40, 0xf4);
65279697Snon	ct_cr_write_1(chp, 0x41, 0x9);
65379697Snon	ct_cr_write_1(chp, 0x43, 0xff);
65479697Snon	ct_cr_write_1(chp, 0x46, 0x4e);
65573149Snyan
65679697Snon	ct_cr_write_1(chp, 0x48, 0xf4);
65779697Snon	ct_cr_write_1(chp, 0x49, 0x9);
65879697Snon	ct_cr_write_1(chp, 0x4b, 0xff);
65979697Snon	ct_cr_write_1(chp, 0x4e, 0x4e);
66073149Snyan#endif
66173149Snyan	return 1;
66273149Snyan}
66373149Snyan
66473149Snyanstatic void
665243455Snyanbshw_dma_start_sc98(struct ct_softc *ct)
66673149Snyan{
66779697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
66873149Snyan
66979697Snon	ct_cr_write_1(chp, 0x73, 0x32);
67079697Snon	ct_cr_write_1(chp, 0x74, 0x23);
67173149Snyan}
67273149Snyan
67373149Snyanstatic void
674243455Snyanbshw_dma_stop_sc98(struct ct_softc *ct)
67573149Snyan{
67679697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
67773149Snyan
67879697Snon	ct_cr_write_1(chp, 0x73, 0x43);
67979697Snon	ct_cr_write_1(chp, 0x74, 0x34);
68073149Snyan}
68173149Snyan
68273149Snyanstatic void
683243455Snyanbshw_dma_start_elecom(struct ct_softc *ct)
68473149Snyan{
68579697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
68679697Snon	u_int8_t tmp = ct_cr_read_1(chp, 0x4c);
68773149Snyan
68879697Snon	ct_cr_write_1(chp, 0x32, tmp & 0xdf);
68973149Snyan}
69073149Snyan
69173149Snyanstatic void
692243455Snyanbshw_dma_stop_elecom(struct ct_softc *ct)
69373149Snyan{
69479697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
69579697Snon	u_int8_t tmp = ct_cr_read_1(chp, 0x4c);
69673149Snyan
69779697Snon	ct_cr_write_1(chp, 0x32, tmp | 0x20);
69873149Snyan}
69973149Snyan
70073149Snyanstatic struct bshw bshw_generic = {
70173149Snyan	BSHW_SYNC_RELOAD,
70273149Snyan
70373149Snyan	0,
70473149Snyan
70573149Snyan	NULL,
70673149Snyan	NULL,
70773149Snyan	NULL,
70873149Snyan};
70973149Snyan
71073149Snyanstatic struct bshw bshw_sc98 = {
71173149Snyan	BSHW_DOUBLE_DMACHAN,
71273149Snyan
71373149Snyan	0x60,
71473149Snyan
71573149Snyan	bshw_dma_init_sc98,
71673149Snyan	bshw_dma_start_sc98,
71773149Snyan	bshw_dma_stop_sc98,
71873149Snyan};
71973149Snyan
72073149Snyanstatic struct bshw bshw_texa = {
72173149Snyan	BSHW_DOUBLE_DMACHAN,
72273149Snyan
72373149Snyan	0x60,
72473149Snyan
72573149Snyan	bshw_dma_init_texa,
72673149Snyan	NULL,
72773149Snyan	NULL,
72873149Snyan};
72973149Snyan
73073149Snyanstatic struct bshw bshw_elecom = {
73173149Snyan	0,
73273149Snyan
73373149Snyan	0x38,
73473149Snyan
73573149Snyan	NULL,
73673149Snyan	bshw_dma_start_elecom,
73773149Snyan	bshw_dma_stop_elecom,
73873149Snyan};
73973149Snyan
74073149Snyanstatic struct bshw bshw_lc_smit = {
74173149Snyan	BSHW_SMFIFO | BSHW_DOUBLE_DMACHAN,
74273149Snyan
74373149Snyan	0x60,
74473149Snyan
74573149Snyan	NULL,
74673149Snyan	NULL,
74773149Snyan	NULL,
74873149Snyan};
74973149Snyan
75073149Snyanstatic struct bshw bshw_lha20X = {
75173149Snyan	BSHW_DOUBLE_DMACHAN,
75273149Snyan
75373149Snyan	0x60,
75473149Snyan
75573149Snyan	NULL,
75673149Snyan	NULL,
75773149Snyan	NULL,
75873149Snyan};
75973149Snyan
76073149Snyan/* hw tabs */
76173149Snyanstatic dvcfg_hw_t bshw_hwsel_array[] = {
76273149Snyan/* 0x00 */	&bshw_generic,
76373149Snyan/* 0x01 */	&bshw_sc98,
76473149Snyan/* 0x02 */	&bshw_texa,
76573149Snyan/* 0x03 */	&bshw_elecom,
76673149Snyan/* 0x04 */	&bshw_lc_smit,
76773149Snyan/* 0x05 */	&bshw_lha20X,
76873149Snyan};
76973149Snyan
77073149Snyanstruct dvcfg_hwsel bshw_hwsel = {
77173149Snyan	DVCFG_HWSEL_SZ(bshw_hwsel_array),
77273149Snyan	bshw_hwsel_array
77373149Snyan};
774