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