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>
4473149Snyan#include <sys/bio.h>
4573149Snyan#include <sys/buf.h>
4673149Snyan#include <sys/queue.h>
4773149Snyan#include <sys/malloc.h>
4873149Snyan#include <sys/errno.h>
4973149Snyan
5073149Snyan#include <vm/vm.h>
5173149Snyan
5273149Snyan#include <machine/bus.h>
5373149Snyan#include <machine/md_var.h>
5473149Snyan
55126928Speter#include <compat/netbsd/dvcfg.h>
5673149Snyan
5773149Snyan#include <cam/scsi/scsi_low.h>
5873149Snyan
5978209Snyan#include <dev/ic/wd33c93reg.h>
6073149Snyan#include <dev/ct/ctvar.h>
6179697Snon#include <dev/ct/ct_machdep.h>
6273149Snyan#include <dev/ct/bshwvar.h>
6379697Snon
6479697Snon#include <vm/pmap.h>
6573149Snyan
6679697Snon#define	BSHW_IO_CONTROL_FLAGS	0
6779697Snon
6879697Snonu_int bshw_io_control = BSHW_IO_CONTROL_FLAGS;
6979697Snonint bshw_data_read_bytes = 4096;
7079697Snonint bshw_data_write_bytes = 4096;
7179697Snon
7273149Snyan/*********************************************************
7379697Snon * OS dep part
7479697Snon *********************************************************/
7579697Snontypedef	unsigned long vaddr_t;
7679697Snon
7779697Snon/*********************************************************
7873149Snyan * GENERIC MACHDEP FUNCTIONS
7973149Snyan *********************************************************/
8073149Snyanvoid
81242871Snyanbshw_synch_setup(struct ct_softc *ct, struct targ_info *ti)
8273149Snyan{
8379697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
8473149Snyan	struct ct_targ_info *cti = (void *) ti;
8573149Snyan	struct bshw_softc *bs = ct->ct_hw;
8673149Snyan	struct bshw *hw = bs->sc_hw;
8773149Snyan
8879697Snon	if (hw->hw_sregaddr == 0)
8973149Snyan		return;
9073149Snyan
9179697Snon	ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id, cti->cti_syncreg);
9273149Snyan	if (hw->hw_flags & BSHW_DOUBLE_DMACHAN)
9373149Snyan	{
9479697Snon		ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id + 8,
9573149Snyan			      cti->cti_syncreg);
9673149Snyan	}
9773149Snyan}
9873149Snyan
9973149Snyanvoid
100242871Snyanbshw_bus_reset(struct ct_softc *ct)
10173149Snyan{
10273149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
10379697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
10473149Snyan	struct bshw_softc *bs = ct->ct_hw;
10573149Snyan	struct bshw *hw = bs->sc_hw;
10673149Snyan	bus_addr_t offs;
10773149Snyan	u_int8_t regv;
10873149Snyan	int i;
10973149Snyan
11073149Snyan	/* open hardware busmaster mode */
11179697Snon	if (hw->hw_dma_init != NULL && ((*hw->hw_dma_init)(ct)) != 0)
11273149Snyan	{
113240325Sjhb		device_printf(slp->sl_dev,
114240325Sjhb		    "change mode using external DMA (%x)\n",
115240325Sjhb		    (u_int)ct_cr_read_1(chp, 0x37));
11673149Snyan	}
11773149Snyan
11873149Snyan	/* clear hardware synch registers */
11979697Snon	offs = hw->hw_sregaddr;
12073149Snyan	if (offs != 0)
12173149Snyan	{
12273149Snyan		for (i = 0; i < 8; i ++, offs ++)
12373149Snyan		{
12479697Snon			ct_cr_write_1(chp, offs, 0);
12573149Snyan			if ((hw->hw_flags & BSHW_DOUBLE_DMACHAN) != 0)
12679697Snon				ct_cr_write_1(chp, offs + 8, 0);
12773149Snyan		}
12873149Snyan	}
12973149Snyan
13073149Snyan	/* disable interrupt & assert reset */
13179697Snon	regv = ct_cr_read_1(chp, wd3s_mbank);
13273149Snyan	regv |= MBR_RST;
13373149Snyan	regv &= ~MBR_IEN;
13479697Snon	ct_cr_write_1(chp, wd3s_mbank, regv);
13573149Snyan
136240172Sjhb	DELAY(500000);
13773149Snyan
13873149Snyan	/* reset signal off */
13973149Snyan	regv &= ~MBR_RST;
14079697Snon	ct_cr_write_1(chp, wd3s_mbank, regv);
14173149Snyan
14273149Snyan	/* interrupt enable */
14373149Snyan	regv |= MBR_IEN;
14479697Snon	ct_cr_write_1(chp, wd3s_mbank, regv);
14573149Snyan}
14673149Snyan
14773149Snyan/* probe */
14873149Snyanint
149242871Snyanbshw_read_settings(struct ct_bus_access_handle *chp, struct bshw_softc *bs)
15073149Snyan{
15173149Snyan	static int irq_tbl[] = { 3, 5, 6, 9, 12, 13 };
15273149Snyan
15379697Snon	bs->sc_hostid = (ct_cr_read_1(chp, wd3s_auxc) & AUXCR_HIDM);
15479697Snon	bs->sc_irq = irq_tbl[(ct_cr_read_1(chp, wd3s_auxc) >> 3) & 7];
15579697Snon	bs->sc_drq = ct_cmdp_read_1(chp) & 3;
15673149Snyan	return 0;
15773149Snyan}
15873149Snyan
15973149Snyan/*********************************************************
16073149Snyan * DMA PIO TRANSFER (SMIT)
16173149Snyan *********************************************************/
16273149Snyan#define	LC_SMIT_TIMEOUT	2	/* 2 sec: timeout for a fifo status ready */
16373149Snyan#define	LC_SMIT_OFFSET	0x1000
16473149Snyan#define	LC_FSZ		DEV_BSIZE
16573149Snyan#define	LC_SFSZ		0x0c
16673149Snyan#define	LC_REST		(LC_FSZ - LC_SFSZ)
16773149Snyan
16873149Snyan#define	BSHW_LC_FSET	0x36
16973149Snyan#define	BSHW_LC_FCTRL	0x44
17073149Snyan#define	FCTRL_EN	0x01
17173149Snyan#define	FCTRL_WRITE	0x02
17273149Snyan
17373149Snyan#define	SF_ABORT	0x08
17473149Snyan#define	SF_RDY		0x10
17573149Snyan
17692739Salfredstatic __inline void bshw_lc_smit_start(struct ct_softc *, int, u_int);
17792739Salfredstatic __inline void bshw_lc_smit_stop(struct ct_softc *);
17892739Salfredstatic int bshw_lc_smit_fstat(struct ct_softc *, int, int);
17973149Snyan
18073149Snyanstatic __inline void
181242871Snyanbshw_lc_smit_stop(struct ct_softc *ct)
18273149Snyan{
18379697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
18473149Snyan
18579697Snon	ct_cr_write_1(chp, BSHW_LC_FCTRL, 0);
18679697Snon	ct_cmdp_write_1(chp, CMDP_DMER);
18773149Snyan}
18873149Snyan
18973149Snyanstatic __inline void
190242871Snyanbshw_lc_smit_start(struct ct_softc *ct, int count, u_int direction)
19173149Snyan{
19279697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
19373149Snyan	u_int8_t pval, val;
19473149Snyan
19579697Snon	val = ct_cr_read_1(chp, BSHW_LC_FSET);
19679697Snon	cthw_set_count(chp, count);
19773149Snyan
19873149Snyan	pval = FCTRL_EN;
19973149Snyan	if (direction == SCSI_LOW_WRITE)
20073149Snyan		pval |= (val & 0xe0) | FCTRL_WRITE;
20179697Snon	ct_cr_write_1(chp, BSHW_LC_FCTRL, pval);
20279697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
20373149Snyan}
20473149Snyan
20573149Snyanstatic int
206242871Snyanbshw_lc_smit_fstat(struct ct_softc *ct, int wc, int read)
20773149Snyan{
20879697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
20973149Snyan	u_int8_t stat;
21073149Snyan
21173149Snyan	while (wc -- > 0)
21273149Snyan	{
21379697Snon		chp->ch_bus_weight(chp);
21479697Snon		stat = ct_cmdp_read_1(chp);
21573149Snyan		if (read == SCSI_LOW_READ)
21673149Snyan		{
21773149Snyan			if ((stat & SF_RDY) != 0)
21873149Snyan				return 0;
21973149Snyan			if ((stat & SF_ABORT) != 0)
22073149Snyan				return EIO;
22173149Snyan		}
22273149Snyan		else
22373149Snyan		{
22473149Snyan			if ((stat & SF_ABORT) != 0)
22573149Snyan				return EIO;
22673149Snyan			if ((stat & SF_RDY) != 0)
22773149Snyan				return 0;
22873149Snyan		}
22973149Snyan	}
23073149Snyan
231240325Sjhb	device_printf(ct->sc_sclow.sl_dev, "SMIT fifo status timeout\n");
23273149Snyan	return EIO;
23373149Snyan}
23473149Snyan
23573149Snyanvoid
236242871Snyanbshw_smit_xfer_stop(struct ct_softc *ct)
23773149Snyan{
23873149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
23973149Snyan	struct bshw_softc *bs = ct->ct_hw;
24073149Snyan	struct targ_info *ti;
24173149Snyan	struct sc_p *sp = &slp->sl_scp;
24273149Snyan	u_int count;
24373149Snyan
24473149Snyan	bshw_lc_smit_stop(ct);
24573149Snyan
24679697Snon	ti = slp->sl_Tnexus;
24773149Snyan	if (ti == NULL)
24873149Snyan		return;
24973149Snyan
25073149Snyan	if (ti->ti_phase == PH_DATA)
25173149Snyan	{
25279697Snon		count = cthw_get_count(&ct->sc_ch);
25379697Snon		if (count < bs->sc_sdatalen)
25473149Snyan		{
25573149Snyan			if (sp->scp_direction == SCSI_LOW_READ &&
25679697Snon			    count != bs->sc_edatalen)
25773149Snyan				goto bad;
25879697Snon
25979697Snon			count = bs->sc_sdatalen - count;
26079697Snon			if (count > (u_int) sp->scp_datalen)
26179697Snon				goto bad;
26279697Snon
26379697Snon			sp->scp_data += count;
26479697Snon			sp->scp_datalen -= count;
26573149Snyan		}
26679697Snon		else if (count > bs->sc_sdatalen)
26773149Snyan		{
26879697Snonbad:
269240325Sjhb			device_printf(slp->sl_dev,
270240325Sjhb			    "smit_xfer_end: cnt error\n");
27179697Snon			slp->sl_error |= PDMAERR;
27273149Snyan		}
27379697Snon		scsi_low_data_finish(slp);
27473149Snyan	}
27573149Snyan	else
27679697Snon	{
277240325Sjhb		device_printf(slp->sl_dev, "smit_xfer_end: phase miss\n");
27879697Snon		slp->sl_error |= PDMAERR;
27979697Snon	}
28073149Snyan}
28173149Snyan
28279697Snonint
283242871Snyanbshw_smit_xfer_start(struct ct_softc *ct)
28473149Snyan{
28573149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
28679697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
28773149Snyan	struct bshw_softc *bs = ct->ct_hw;
28873149Snyan	struct sc_p *sp = &slp->sl_scp;
28979697Snon	struct targ_info *ti = slp->sl_Tnexus;
29073149Snyan	struct ct_targ_info *cti = (void *) ti;
29179697Snon	u_int datalen, count, io_control;
29279697Snon	int wc;
29373149Snyan	u_int8_t *data;
29473149Snyan
29579697Snon	io_control = bs->sc_io_control | bshw_io_control;
29679697Snon	if ((io_control & BSHW_SMIT_BLOCK) != 0)
29779697Snon		return EINVAL;
29879697Snon
29979697Snon	if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0)
30079697Snon		return EINVAL;
30179697Snon
30273149Snyan	datalen = sp->scp_datalen;
30379697Snon	if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
30479697Snon	{
30579697Snon		if ((io_control & BSHW_READ_INTERRUPT_DRIVEN) != 0 &&
30679697Snon		     datalen > bshw_data_read_bytes)
30779697Snon			datalen = bshw_data_read_bytes;
30879697Snon	}
30979697Snon	else
31079697Snon	{
31179697Snon	        if ((io_control & BSHW_WRITE_INTERRUPT_DRIVEN) != 0 &&
31279697Snon		    datalen > bshw_data_write_bytes)
31379697Snon			datalen = bshw_data_write_bytes;
31479697Snon	}
31573149Snyan
31679697Snon	bs->sc_sdatalen = datalen;
31779697Snon	data = sp->scp_data;
31879697Snon 	wc = LC_SMIT_TIMEOUT * 1024 * 1024;
31973149Snyan
32079697Snon	ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
32179697Snon	bshw_lc_smit_start(ct, datalen, sp->scp_direction);
32279697Snon
32373149Snyan	if (sp->scp_direction == SCSI_LOW_READ)
32473149Snyan	{
32573149Snyan		do
32673149Snyan		{
32773149Snyan			if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_READ))
32873149Snyan				break;
32973149Snyan
33073149Snyan			count = (datalen > LC_FSZ ? LC_FSZ : datalen);
33179697Snon			bus_space_read_region_4(chp->ch_memt, chp->ch_memh,
33273149Snyan				LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2);
33373149Snyan			data += count;
33473149Snyan			datalen -= count;
33573149Snyan		}
33673149Snyan		while (datalen > 0);
33773149Snyan
33879697Snon		bs->sc_edatalen = datalen;
33973149Snyan	}
34073149Snyan	else
34173149Snyan	{
34273149Snyan		do
34373149Snyan		{
34473149Snyan			if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE))
34573149Snyan				break;
34673149Snyan			if (cti->cti_syncreg == 0)
34773149Snyan			{
34873149Snyan				/* XXX:
34973149Snyan				 * If async transfer, reconfirm a scsi phase
35073149Snyan				 * again. Unless C bus might hang up.
35173149Snyan			 	 */
35273149Snyan				if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE))
35373149Snyan					break;
35473149Snyan			}
35573149Snyan
35673149Snyan			count = (datalen > LC_SFSZ ? LC_SFSZ : datalen);
35779697Snon			bus_space_write_region_4(chp->ch_memt, chp->ch_memh,
35873149Snyan				LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2);
35973149Snyan			data += count;
36073149Snyan			datalen -= count;
36173149Snyan
36273149Snyan			if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE))
36373149Snyan				break;
36473149Snyan
36573149Snyan			count = (datalen > LC_REST ? LC_REST : datalen);
36679697Snon			bus_space_write_region_4(chp->ch_memt, chp->ch_memh,
36773149Snyan						 LC_SMIT_OFFSET + LC_SFSZ,
36873149Snyan						 (u_int32_t *) data, count >> 2);
36973149Snyan			data += count;
37073149Snyan			datalen -= count;
37173149Snyan		}
37273149Snyan		while (datalen > 0);
37373149Snyan	}
37479697Snon	return 0;
37573149Snyan}
37673149Snyan
37773149Snyan/*********************************************************
37873149Snyan * DMA TRANSFER (BS)
37973149Snyan *********************************************************/
38079697Snonstatic __inline void bshw_dma_write_1 \
38192739Salfred	(struct ct_bus_access_handle *, bus_addr_t, u_int8_t);
38292739Salfredstatic void bshw_dmastart(struct ct_softc *);
38392739Salfredstatic void bshw_dmadone(struct ct_softc *);
38473149Snyan
38579697Snonint
386242871Snyanbshw_dma_xfer_start(struct ct_softc *ct)
38773149Snyan{
38873149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
38973149Snyan	struct sc_p *sp = &slp->sl_scp;
39079697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
39173149Snyan	struct bshw_softc *bs = ct->ct_hw;
39273149Snyan	vaddr_t va, endva, phys, nphys;
39379697Snon	u_int io_control;
39473149Snyan
39579697Snon	io_control = bs->sc_io_control | bshw_io_control;
39679697Snon	if ((io_control & BSHW_DMA_BLOCK) != 0 && sp->scp_datalen < 256)
39779697Snon		return EINVAL;
39879697Snon
39979697Snon	ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
40073149Snyan	phys = vtophys((vaddr_t) sp->scp_data);
40173149Snyan	if (phys >= bs->sc_minphys)
40273149Snyan	{
40373149Snyan		/* setup segaddr */
40473149Snyan		bs->sc_segaddr = bs->sc_bounce_phys;
40573149Snyan		/* setup seglen */
40673149Snyan		bs->sc_seglen = sp->scp_datalen;
40773149Snyan		if (bs->sc_seglen > bs->sc_bounce_size)
40873149Snyan			bs->sc_seglen = bs->sc_bounce_size;
40973149Snyan		/* setup bufp */
41073149Snyan		bs->sc_bufp = bs->sc_bounce_addr;
41173149Snyan		if (sp->scp_direction == SCSI_LOW_WRITE)
41273149Snyan			bcopy(sp->scp_data, bs->sc_bufp, bs->sc_seglen);
41373149Snyan	}
41473149Snyan	else
41573149Snyan	{
41673149Snyan		/* setup segaddr */
41773149Snyan		bs->sc_segaddr = (u_int8_t *) phys;
41873149Snyan		/* setup seglen */
41979697Snon		endva = (vaddr_t) round_page((vaddr_t) sp->scp_data + sp->scp_datalen);
42073149Snyan		for (va = (vaddr_t) sp->scp_data; ; phys = nphys)
42173149Snyan		{
422240172Sjhb			if ((va += PAGE_SIZE) >= endva)
42373149Snyan			{
42473149Snyan				bs->sc_seglen = sp->scp_datalen;
42573149Snyan				break;
42673149Snyan			}
42773149Snyan
42873149Snyan			nphys = vtophys(va);
429240172Sjhb			if (phys + PAGE_SIZE != nphys || nphys >= bs->sc_minphys)
43073149Snyan			{
43173149Snyan				bs->sc_seglen =
43273149Snyan				    (u_int8_t *) trunc_page(va) - sp->scp_data;
43373149Snyan				break;
43473149Snyan			}
43573149Snyan		}
43673149Snyan		/* setup bufp */
43773149Snyan		bs->sc_bufp = NULL;
43873149Snyan	}
43973149Snyan
44073149Snyan	bshw_dmastart(ct);
44179697Snon	cthw_set_count(chp, bs->sc_seglen);
44279697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
44379697Snon	return 0;
44473149Snyan}
44573149Snyan
44673149Snyanvoid
447242871Snyanbshw_dma_xfer_stop(struct ct_softc *ct)
44873149Snyan{
44973149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
45073149Snyan	struct sc_p *sp = &slp->sl_scp;
45173149Snyan	struct bshw_softc *bs = ct->ct_hw;
45273149Snyan	struct targ_info *ti;
45373149Snyan	u_int count, transbytes;
45473149Snyan
45573149Snyan	bshw_dmadone(ct);
45673149Snyan
45779697Snon 	ti = slp->sl_Tnexus;
45873149Snyan	if (ti == NULL)
45973149Snyan		return;
46073149Snyan
46173149Snyan	if (ti->ti_phase == PH_DATA)
46273149Snyan	{
46379697Snon		count = cthw_get_count(&ct->sc_ch);
46473149Snyan		if (count < (u_int) bs->sc_seglen)
46573149Snyan		{
46673149Snyan			transbytes = bs->sc_seglen - count;
46773149Snyan			if (bs->sc_bufp != NULL &&
46873149Snyan			    sp->scp_direction == SCSI_LOW_READ)
46973149Snyan				bcopy(bs->sc_bufp, sp->scp_data, transbytes);
47073149Snyan
47173149Snyan			sp->scp_data += transbytes;
47273149Snyan			sp->scp_datalen -= transbytes;
47373149Snyan		}
47479697Snon		else if (count > (u_int) bs->sc_seglen)
47573149Snyan		{
476240325Sjhb			device_printf(slp->sl_dev,
477240325Sjhb			    "port data %x != seglen %x\n",
478240325Sjhb			    count, bs->sc_seglen);
47979697Snon			slp->sl_error |= PDMAERR;
48073149Snyan		}
48173149Snyan
48279697Snon		scsi_low_data_finish(slp);
48373149Snyan	}
48473149Snyan	else
48573149Snyan	{
486240325Sjhb		device_printf(slp->sl_dev, "extra DMA interrupt\n");
48779697Snon		slp->sl_error |= PDMAERR;
48873149Snyan	}
48973149Snyan
49073149Snyan	bs->sc_bufp = NULL;
49173149Snyan}
49273149Snyan
49373149Snyan/* common dma settings */
49473149Snyan#undef	DMA1_SMSK
49573149Snyan#define DMA1_SMSK	(0x15)
49673149Snyan#undef	DMA1_MODE
49773149Snyan#define DMA1_MODE	(0x17)
49873149Snyan#undef	DMA1_FFC
49973149Snyan#define DMA1_FFC	(0x19)
50073149Snyan#undef	DMA1_CHN
50173149Snyan#define DMA1_CHN(c)	(0x01 + ((c) << 2))
50273149Snyan
50373149Snyan#define DMA37SM_SET	0x04
50473149Snyan#define	DMA37MD_WRITE	0x04
50573149Snyan#define	DMA37MD_READ	0x08
50673149Snyan#define	DMA37MD_SINGLE	0x40
50773149Snyan
50879697Snonstatic bus_addr_t dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 };
50979697Snon
51079697Snonstatic __inline void
511242871Snyanbshw_dma_write_1(struct ct_bus_access_handle *chp, bus_addr_t port,
512242871Snyan    u_int8_t val)
51379697Snon{
51479697Snon
51579697Snon	CT_BUS_WEIGHT(chp);
51679697Snon	outb(port, val);
51779697Snon}
51879697Snon
51973149Snyanstatic void
520242871Snyanbshw_dmastart(struct ct_softc *ct)
52173149Snyan{
52273149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
52373149Snyan	struct bshw_softc *bs = ct->ct_hw;
52479697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
52573149Snyan	int chan = bs->sc_drq;
52679697Snon	bus_addr_t waport;
52779697Snon	u_int8_t regv, *phys = bs->sc_segaddr;
52873149Snyan	u_int nbytes = bs->sc_seglen;
52973149Snyan
53079697Snon	/* flush cpu cache */
53179697Snon	(*bs->sc_dmasync_before) (ct);
53279697Snon
53373149Snyan	/*
53473149Snyan	 * Program one of DMA channels 0..3. These are
53573149Snyan	 * byte mode channels.
53673149Snyan	 */
53773149Snyan	/* set dma channel mode, and reset address ff */
53873149Snyan
53973149Snyan	if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
54079697Snon		regv = DMA37MD_WRITE | DMA37MD_SINGLE | chan;
54173149Snyan	else
54279697Snon		regv = DMA37MD_READ | DMA37MD_SINGLE | chan;
54373149Snyan
54479697Snon	bshw_dma_write_1(chp, DMA1_MODE, regv);
54579697Snon	bshw_dma_write_1(chp, DMA1_FFC, 0);
54679697Snon
54773149Snyan	/* send start address */
54873149Snyan	waport = DMA1_CHN(chan);
54979697Snon	bshw_dma_write_1(chp, waport, (u_int) phys);
55079697Snon	bshw_dma_write_1(chp, waport, ((u_int) phys) >> 8);
55179697Snon	bshw_dma_write_1(chp, dmapageport[chan], ((u_int) phys) >> 16);
55273149Snyan
55373149Snyan	/* send count */
55479697Snon	bshw_dma_write_1(chp, waport + 2, --nbytes);
55579697Snon	bshw_dma_write_1(chp, waport + 2, nbytes >> 8);
55673149Snyan
55773149Snyan	/* vendor unique hook */
55879697Snon	if (bs->sc_hw->hw_dma_start)
55979697Snon		(*bs->sc_hw->hw_dma_start)(ct);
56073149Snyan
56179697Snon	bshw_dma_write_1(chp, DMA1_SMSK, chan);
56279697Snon	ct_cmdp_write_1(chp, CMDP_DMES);
56373149Snyan}
56473149Snyan
56573149Snyanstatic void
566242871Snyanbshw_dmadone(struct ct_softc *ct)
56773149Snyan{
56873149Snyan	struct bshw_softc *bs = ct->ct_hw;
56979697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
57073149Snyan
57179697Snon	bshw_dma_write_1(chp, DMA1_SMSK, (bs->sc_drq | DMA37SM_SET));
57279697Snon	ct_cmdp_write_1(chp, CMDP_DMER);
57373149Snyan
57473149Snyan	/* vendor unique hook */
57579697Snon	if (bs->sc_hw->hw_dma_stop)
57679697Snon		(*bs->sc_hw->hw_dma_stop) (ct);
57773149Snyan
57879697Snon	/* flush cpu cache */
57979697Snon	(*bs->sc_dmasync_after) (ct);
58073149Snyan}
58173149Snyan
58273149Snyan/**********************************************
58373149Snyan * VENDOR UNIQUE DMA FUNCS
58473149Snyan **********************************************/
58592739Salfredstatic int bshw_dma_init_sc98(struct ct_softc *);
58692739Salfredstatic void bshw_dma_start_sc98(struct ct_softc *);
58792739Salfredstatic void bshw_dma_stop_sc98(struct ct_softc *);
58892739Salfredstatic int bshw_dma_init_texa(struct ct_softc *);
58992739Salfredstatic void bshw_dma_start_elecom(struct ct_softc *);
59092739Salfredstatic void bshw_dma_stop_elecom(struct ct_softc *);
59173149Snyan
59273149Snyanstatic int
593242871Snyanbshw_dma_init_texa(struct ct_softc *ct)
59473149Snyan{
59579697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
59673149Snyan	u_int8_t regval;
59773149Snyan
59879697Snon	if ((regval = ct_cr_read_1(chp, 0x37)) & 0x08)
59973149Snyan		return 0;
60073149Snyan
60179697Snon	ct_cr_write_1(chp, 0x37, regval | 0x08);
60279697Snon	regval = ct_cr_read_1(chp, 0x3f);
60379697Snon	ct_cr_write_1(chp, 0x3f, regval | 0x08);
60473149Snyan	return 1;
60573149Snyan}
60673149Snyan
60773149Snyanstatic int
608242871Snyanbshw_dma_init_sc98(struct ct_softc *ct)
60973149Snyan{
61079697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
61173149Snyan
61279697Snon	if (ct_cr_read_1(chp, 0x37) & 0x08)
61373149Snyan		return 0;
61473149Snyan
61573149Snyan	/* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */
61679697Snon	ct_cr_write_1(chp, 0x37, 0x1a);
61779697Snon	ct_cr_write_1(chp, 0x3f, 0x1a);
61873149Snyan#if	0
61973149Snyan	/* only valid for IO */
62079697Snon	ct_cr_write_1(chp, 0x40, 0xf4);
62179697Snon	ct_cr_write_1(chp, 0x41, 0x9);
62279697Snon	ct_cr_write_1(chp, 0x43, 0xff);
62379697Snon	ct_cr_write_1(chp, 0x46, 0x4e);
62473149Snyan
62579697Snon	ct_cr_write_1(chp, 0x48, 0xf4);
62679697Snon	ct_cr_write_1(chp, 0x49, 0x9);
62779697Snon	ct_cr_write_1(chp, 0x4b, 0xff);
62879697Snon	ct_cr_write_1(chp, 0x4e, 0x4e);
62973149Snyan#endif
63073149Snyan	return 1;
63173149Snyan}
63273149Snyan
63373149Snyanstatic void
634242871Snyanbshw_dma_start_sc98(struct ct_softc *ct)
63573149Snyan{
63679697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
63773149Snyan
63879697Snon	ct_cr_write_1(chp, 0x73, 0x32);
63979697Snon	ct_cr_write_1(chp, 0x74, 0x23);
64073149Snyan}
64173149Snyan
64273149Snyanstatic void
643242871Snyanbshw_dma_stop_sc98(struct ct_softc *ct)
64473149Snyan{
64579697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
64673149Snyan
64779697Snon	ct_cr_write_1(chp, 0x73, 0x43);
64879697Snon	ct_cr_write_1(chp, 0x74, 0x34);
64973149Snyan}
65073149Snyan
65173149Snyanstatic void
652242871Snyanbshw_dma_start_elecom(struct ct_softc *ct)
65373149Snyan{
65479697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
65579697Snon	u_int8_t tmp = ct_cr_read_1(chp, 0x4c);
65673149Snyan
65779697Snon	ct_cr_write_1(chp, 0x32, tmp & 0xdf);
65873149Snyan}
65973149Snyan
66073149Snyanstatic void
661242871Snyanbshw_dma_stop_elecom(struct ct_softc *ct)
66273149Snyan{
66379697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
66479697Snon	u_int8_t tmp = ct_cr_read_1(chp, 0x4c);
66573149Snyan
66679697Snon	ct_cr_write_1(chp, 0x32, tmp | 0x20);
66773149Snyan}
66873149Snyan
66973149Snyanstatic struct bshw bshw_generic = {
67073149Snyan	BSHW_SYNC_RELOAD,
67173149Snyan
67273149Snyan	0,
67373149Snyan
67473149Snyan	NULL,
67573149Snyan	NULL,
67673149Snyan	NULL,
67773149Snyan};
67873149Snyan
67973149Snyanstatic struct bshw bshw_sc98 = {
68073149Snyan	BSHW_DOUBLE_DMACHAN,
68173149Snyan
68273149Snyan	0x60,
68373149Snyan
68473149Snyan	bshw_dma_init_sc98,
68573149Snyan	bshw_dma_start_sc98,
68673149Snyan	bshw_dma_stop_sc98,
68773149Snyan};
68873149Snyan
68973149Snyanstatic struct bshw bshw_texa = {
69073149Snyan	BSHW_DOUBLE_DMACHAN,
69173149Snyan
69273149Snyan	0x60,
69373149Snyan
69473149Snyan	bshw_dma_init_texa,
69573149Snyan	NULL,
69673149Snyan	NULL,
69773149Snyan};
69873149Snyan
69973149Snyanstatic struct bshw bshw_elecom = {
70073149Snyan	0,
70173149Snyan
70273149Snyan	0x38,
70373149Snyan
70473149Snyan	NULL,
70573149Snyan	bshw_dma_start_elecom,
70673149Snyan	bshw_dma_stop_elecom,
70773149Snyan};
70873149Snyan
70973149Snyanstatic struct bshw bshw_lc_smit = {
71073149Snyan	BSHW_SMFIFO | BSHW_DOUBLE_DMACHAN,
71173149Snyan
71273149Snyan	0x60,
71373149Snyan
71473149Snyan	NULL,
71573149Snyan	NULL,
71673149Snyan	NULL,
71773149Snyan};
71873149Snyan
71973149Snyanstatic struct bshw bshw_lha20X = {
72073149Snyan	BSHW_DOUBLE_DMACHAN,
72173149Snyan
72273149Snyan	0x60,
72373149Snyan
72473149Snyan	NULL,
72573149Snyan	NULL,
72673149Snyan	NULL,
72773149Snyan};
72873149Snyan
72973149Snyan/* hw tabs */
73073149Snyanstatic dvcfg_hw_t bshw_hwsel_array[] = {
73173149Snyan/* 0x00 */	&bshw_generic,
73273149Snyan/* 0x01 */	&bshw_sc98,
73373149Snyan/* 0x02 */	&bshw_texa,
73473149Snyan/* 0x03 */	&bshw_elecom,
73573149Snyan/* 0x04 */	&bshw_lc_smit,
73673149Snyan/* 0x05 */	&bshw_lha20X,
73773149Snyan};
73873149Snyan
73973149Snyanstruct dvcfg_hwsel bshw_hwsel = {
74073149Snyan	DVCFG_HWSEL_SZ(bshw_hwsel_array),
74173149Snyan	bshw_hwsel_array
74273149Snyan};
743