From bedee18193ed6f3b64f76f08f7e156130a7dd436 Mon Sep 17 00:00:00 2001 From: Yoshihiro Takahashi Date: Tue, 27 Feb 2001 12:34:01 +0000 Subject: [PATCH] Added another wd33c93 based SCSI card driver which replaces the bs driver. Now, default is still bs. Submitted by: nyan and non. Obtained from: NetBSD/pc98 --- sys/conf/files | 2 + sys/conf/files.pc98 | 3 + sys/dev/ct/bshw_machdep.c | 767 ++++++++++++++++++++++++++++ sys/dev/ct/bshwvar.h | 86 ++++ sys/dev/ct/ct.c | 960 ++++++++++++++++++++++++++++++++++++ sys/dev/ct/ct_isa.c | 322 ++++++++++++ sys/dev/ct/ct_machdep.h | 155 ++++++ sys/dev/ct/ctvar.h | 127 +++++ sys/pc98/conf/GENERIC | 7 +- sys/pc98/conf/GENERIC.hints | 29 +- 10 files changed, 2449 insertions(+), 9 deletions(-) create mode 100644 sys/dev/ct/bshw_machdep.c create mode 100644 sys/dev/ct/bshwvar.h create mode 100644 sys/dev/ct/ct.c create mode 100644 sys/dev/ct/ct_isa.c create mode 100644 sys/dev/ct/ct_machdep.h create mode 100644 sys/dev/ct/ctvar.h diff --git a/sys/conf/files b/sys/conf/files index 93b652a26964..84c2552b049e 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -27,9 +27,11 @@ cam/scsi/scsi_all.c optional scbus cam/scsi/scsi_cd.c optional cd cam/scsi/scsi_ch.c optional ch cam/scsi/scsi_da.c optional da +cam/scsi/scsi_low.c optional ct cam/scsi/scsi_low.c optional ncv cam/scsi/scsi_low.c optional nsp cam/scsi/scsi_low.c optional stg +cam/scsi/scsi_low_pisa.c optional ct cam/scsi/scsi_low_pisa.c optional ncv cam/scsi/scsi_low_pisa.c optional nsp cam/scsi/scsi_low_pisa.c optional stg diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 8655b214f77b..6c9ae2c0dac3 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -93,6 +93,9 @@ contrib/dev/oltr/trlldmac.c optional oltr #dev/advansys/adv_isa.c optional adv isa dev/aic/aic_cbus.c optional aic isa #dev/ar/if_ar_isa.c optional ar isa +dev/ct/bshw_machdep.c optional ct +dev/ct/ct.c optional ct +dev/ct/ct_isa.c optional ct isa dev/ed/if_ed_cbus.c optional ed isa dev/eisa/eisaconf.c optional eisa dev/fb/fb.c optional fb diff --git a/sys/dev/ct/bshw_machdep.c b/sys/dev/ct/bshw_machdep.c new file mode 100644 index 000000000000..37aebdd1446a --- /dev/null +++ b/sys/dev/ct/bshw_machdep.c @@ -0,0 +1,767 @@ +/* $FreeBSD$ */ +/* $NecBSD: bshw_machdep.c,v 1.8 1999/07/23 20:54:00 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999 + * NetBSD/pc98 porting staff. All rights reserved. + * + * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999 + * Naofumi HONDA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef __NetBSD__ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#endif /* __FreeBSD__ */ + +/********************************************************* + * GENERIC MACHDEP FUNCTIONS + *********************************************************/ +void +bshw_synch_setup(ct, li) + struct ct_softc *ct; + struct lun_info *li; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + struct targ_info *ti = slp->sl_nexus; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + struct ct_targ_info *cti = (void *) ti; + struct bshw_softc *bs = ct->ct_hw; + struct bshw *hw = bs->sc_hw; + + if (hw->sregaddr == 0) + return; + + ct_cr_write_1(bst, bsh, hw->sregaddr + ti->ti_id, cti->cti_syncreg); + if (hw->hw_flags & BSHW_DOUBLE_DMACHAN) + { + ct_cr_write_1(bst, bsh, hw->sregaddr + ti->ti_id + 8, + cti->cti_syncreg); + } +} + +void +bshw_bus_reset(ct) + struct ct_softc *ct; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + struct bshw_softc *bs = ct->ct_hw; + struct bshw *hw = bs->sc_hw; + bus_addr_t offs; + u_int8_t regv; + int i; + + /* open hardware busmaster mode */ + if (hw->dma_init != NULL && ((*hw->dma_init)(ct)) != 0) + { + printf("%s change mode using external DMA (%x)\n", + slp->sl_xname, (u_int)ct_cr_read_1(bst, bsh, 0x37)); + } + + /* clear hardware synch registers */ + offs = hw->sregaddr; + if (offs != 0) + { + for (i = 0; i < 8; i ++, offs ++) + { + ct_cr_write_1(bst, bsh, offs, 0); + if ((hw->hw_flags & BSHW_DOUBLE_DMACHAN) != 0) + ct_cr_write_1(bst, bsh, offs + 8, 0); + } + } + + /* disable interrupt & assert reset */ + regv = ct_cr_read_1(bst, bsh, wd3s_mbank); + regv |= MBR_RST; + regv &= ~MBR_IEN; + ct_cr_write_1(bst, bsh, wd3s_mbank, regv); + + delay(500000); + + /* reset signal off */ + regv &= ~MBR_RST; + ct_cr_write_1(bst, bsh, wd3s_mbank, regv); + + /* interrupt enable */ + regv |= MBR_IEN; + ct_cr_write_1(bst, bsh, wd3s_mbank, regv); +} + +/* probe */ +int +bshw_read_settings(bst, bsh, bs) + bus_space_tag_t bst; + bus_space_handle_t bsh; + struct bshw_softc *bs; +{ + static int irq_tbl[] = { 3, 5, 6, 9, 12, 13 }; + + bs->sc_hostid = (ct_cr_read_1(bst, bsh, wd3s_auxc) & AUXCR_HIDM); + bs->sc_irq = irq_tbl[(ct_cr_read_1(bst, bsh, wd3s_auxc) >> 3) & 7]; + bs->sc_drq = bus_space_read_1(bst, bsh, cmd_port) & 3; + return 0; +} + +/********************************************************* + * DMA PIO TRANSFER (SMIT) + *********************************************************/ +#define LC_SMIT_TIMEOUT 2 /* 2 sec: timeout for a fifo status ready */ +#define LC_SMIT_OFFSET 0x1000 +#define LC_FSZ DEV_BSIZE +#define LC_SFSZ 0x0c +#define LC_REST (LC_FSZ - LC_SFSZ) + +#define BSHW_LC_FSET 0x36 +#define BSHW_LC_FCTRL 0x44 +#define FCTRL_EN 0x01 +#define FCTRL_WRITE 0x02 + +#define SF_ABORT 0x08 +#define SF_RDY 0x10 + +static __inline void bshw_lc_smit_start __P((struct ct_softc *, int, u_int)); +static int bshw_lc_smit_fstat __P((struct ct_softc *, int, int)); +static __inline void bshw_lc_smit_stop __P((struct ct_softc *)); + +static __inline void +bshw_lc_smit_stop(ct) + struct ct_softc *ct; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + + ct_cr_write_1(bst, bsh, BSHW_LC_FCTRL, 0); + bus_space_write_1(ct->sc_iot, ct->sc_ioh, cmd_port, CMDP_DMER); +} + +static __inline void +bshw_lc_smit_start(ct, count, direction) + struct ct_softc *ct; + int count; + u_int direction; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + u_int8_t pval, val; + + val = ct_cr_read_1(bst, bsh, BSHW_LC_FSET); + cthw_set_count(bst, bsh, count); + + pval = FCTRL_EN; + if (direction == SCSI_LOW_WRITE) + pval |= (val & 0xe0) | FCTRL_WRITE; + ct_cr_write_1(bst, bsh, BSHW_LC_FCTRL, pval); + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_TFR_INFO); +} + +static int +bshw_lc_smit_fstat(ct, wc, read) + struct ct_softc *ct; + int wc, read; +{ + u_int8_t stat; + + while (wc -- > 0) + { + outb(0x5f, 0); + stat = bus_space_read_1(ct->sc_iot, ct->sc_ioh, cmd_port); + if (read == SCSI_LOW_READ) + { + if ((stat & SF_RDY) != 0) + return 0; + if ((stat & SF_ABORT) != 0) + return EIO; + } + else + { + if ((stat & SF_ABORT) != 0) + return EIO; + if ((stat & SF_RDY) != 0) + return 0; + } + } + + printf("%s: SMIT fifo status timeout\n", ct->sc_sclow.sl_xname); + return EIO; +} + +void +bshw_smit_xfer_stop(ct) + struct ct_softc *ct; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + struct bshw_softc *bs = ct->ct_hw; + struct targ_info *ti; + struct sc_p *sp = &slp->sl_scp; + u_int count; + u_char *s; + + bshw_lc_smit_stop(ct); + + ti = slp->sl_nexus; + if (ti == NULL) + return; + + if (ti->ti_phase == PH_DATA) + { + count = cthw_get_count(ct->sc_iot, ct->sc_ioh); + if (count < (u_int) sp->scp_datalen) + { + sp->scp_data += (sp->scp_datalen - count); + sp->scp_datalen = count; + /* XXX: + * strict double checks! + * target => wd33c93c transfer counts + * wd33c93c => memory transfer counts + */ + if (sp->scp_direction == SCSI_LOW_READ && + count != bs->sc_tdatalen) + { + s = "read count miss"; + goto bad; + } + return; + } + else if (count == (u_int) sp->scp_datalen) + { + return; + } + + s = "strange count"; + } + else + s = "extra smit interrupt"; + +bad: + printf("%s: smit_xfer_end: %s", slp->sl_xname, s); + slp->sl_error |= PDMAERR; +} + +void +bshw_smit_xfer_start(ct) + struct ct_softc *ct; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + struct bshw_softc *bs = ct->ct_hw; + struct sc_p *sp = &slp->sl_scp; + struct targ_info *ti = slp->sl_nexus; + struct ct_targ_info *cti = (void *) ti; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + int datalen, count, wc = LC_SMIT_TIMEOUT * 1024 * 1024; + u_int8_t *data; + + data = sp->scp_data; + datalen = sp->scp_datalen; + + ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg | CR_DMA); + bshw_lc_smit_start(ct, sp->scp_datalen, sp->scp_direction); + + if (sp->scp_direction == SCSI_LOW_READ) + { + do + { + if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_READ)) + break; + + count = (datalen > LC_FSZ ? LC_FSZ : datalen); + bus_space_read_region_4(ct->sc_memt, ct->sc_memh, + LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2); + data += count; + datalen -= count; + } + while (datalen > 0); + + bs->sc_tdatalen = datalen; + } + else + { + do + { + if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE)) + break; + if (cti->cti_syncreg == 0) + { + /* XXX: + * If async transfer, reconfirm a scsi phase + * again. Unless C bus might hang up. + */ + if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE)) + break; + } + + count = (datalen > LC_SFSZ ? LC_SFSZ : datalen); + bus_space_write_region_4(ct->sc_memt, ct->sc_memh, + LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2); + data += count; + datalen -= count; + + if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE)) + break; + + count = (datalen > LC_REST ? LC_REST : datalen); + bus_space_write_region_4(ct->sc_memt, ct->sc_memh, + LC_SMIT_OFFSET + LC_SFSZ, + (u_int32_t *) data, count >> 2); + data += count; + datalen -= count; + } + while (datalen > 0); + } +} + +/********************************************************* + * DMA TRANSFER (BS) + *********************************************************/ +static void bshw_dmastart __P((struct ct_softc *)); +static void bshw_dmadone __P((struct ct_softc *)); + +void +bshw_dma_xfer_start(ct) + struct ct_softc *ct; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + struct sc_p *sp = &slp->sl_scp; + struct bshw_softc *bs = ct->ct_hw; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + vaddr_t va, endva, phys, nphys; + + ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg | CR_DMA); + phys = vtophys((vaddr_t) sp->scp_data); + if (phys >= bs->sc_minphys) + { + /* setup segaddr */ + bs->sc_segaddr = bs->sc_bounce_phys; + /* setup seglen */ + bs->sc_seglen = sp->scp_datalen; + if (bs->sc_seglen > bs->sc_bounce_size) + bs->sc_seglen = bs->sc_bounce_size; + /* setup bufp */ + bs->sc_bufp = bs->sc_bounce_addr; + if (sp->scp_direction == SCSI_LOW_WRITE) + bcopy(sp->scp_data, bs->sc_bufp, bs->sc_seglen); + } + else + { + /* setup segaddr */ + bs->sc_segaddr = (u_int8_t *) phys; + /* setup seglen */ + endva = (vaddr_t)round_page((vaddr_t)(sp->scp_data + + sp->scp_datalen)); + for (va = (vaddr_t) sp->scp_data; ; phys = nphys) + { + if ((va += PAGE_SIZE) >= endva) + { + bs->sc_seglen = sp->scp_datalen; + break; + } + + nphys = vtophys(va); + if (phys + PAGE_SIZE != nphys || + nphys >= bs->sc_minphys) + { + bs->sc_seglen = + (u_int8_t *) trunc_page(va) - sp->scp_data; + break; + } + } + /* setup bufp */ + bs->sc_bufp = NULL; + } + + bshw_dmastart(ct); + cthw_set_count(bst, bsh, bs->sc_seglen); +} + +void +bshw_dma_xfer_stop(ct) + struct ct_softc *ct; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + struct sc_p *sp = &slp->sl_scp; + struct bshw_softc *bs = ct->ct_hw; + struct targ_info *ti; + u_int count, transbytes; + + bshw_dmadone(ct); + + ti = slp->sl_nexus; + if (ti == NULL) + return; + + if (ti->ti_phase == PH_DATA) + { + count = cthw_get_count(ct->sc_iot, ct->sc_ioh); + if (count < (u_int) bs->sc_seglen) + { + transbytes = bs->sc_seglen - count; + if (bs->sc_bufp != NULL && + sp->scp_direction == SCSI_LOW_READ) + bcopy(bs->sc_bufp, sp->scp_data, transbytes); + + bs->sc_bufp = NULL; + sp->scp_data += transbytes; + sp->scp_datalen -= transbytes; + return; + } + else if (count == (u_int) bs->sc_seglen) + { + bs->sc_bufp = NULL; + return; + } + + printf("%s: port data %x != seglen %x\n", + slp->sl_xname, count, bs->sc_seglen); + } + else + { + printf("%s: extra DMA interrupt\n", slp->sl_xname); + } + + slp->sl_error |= PDMAERR; + bs->sc_bufp = NULL; +} + +static int dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 }; + +/* common dma settings */ +#undef DMA1_SMSK +#define DMA1_SMSK (0x15) +#undef DMA1_MODE +#define DMA1_MODE (0x17) +#undef DMA1_FFC +#define DMA1_FFC (0x19) +#undef DMA1_CHN +#define DMA1_CHN(c) (0x01 + ((c) << 2)) + +#define DMA37SM_SET 0x04 +#define DMA37MD_WRITE 0x04 +#define DMA37MD_READ 0x08 +#define DMA37MD_SINGLE 0x40 + +static void +bshw_dmastart(ct) + struct ct_softc *ct; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + struct bshw_softc *bs = ct->ct_hw; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + int chan = bs->sc_drq; + int waport; + u_int8_t *phys = bs->sc_segaddr; + u_int nbytes = bs->sc_seglen; + + /* + * Program one of DMA channels 0..3. These are + * byte mode channels. + */ + /* set dma channel mode, and reset address ff */ +#ifdef __FreeBSD__ + if (need_pre_dma_flush) + wbinvd(); +#else + if (slp->sl_scp.scp_direction == SCSI_LOW_READ) + cpu_cf_preRead(curcpu); + else + cpu_cf_preWrite(curcpu); +#endif + + if (slp->sl_scp.scp_direction == SCSI_LOW_READ) + outb(DMA1_MODE, DMA37MD_SINGLE | DMA37MD_WRITE | chan); + else + outb(DMA1_MODE, DMA37MD_SINGLE | DMA37MD_READ | chan); + outb(DMA1_FFC, 0); + + /* send start address */ + waport = DMA1_CHN(chan); + outb(waport, (u_int) phys); + outb(waport, ((u_int) phys) >> 8); + outb(dmapageport[chan], ((u_int) phys) >> 16); + + /* send count */ + outb(waport + 2, --nbytes); + outb(waport + 2, nbytes >> 8); + + /* vendor unique hook */ + if (bs->sc_hw->dma_start) + (*bs->sc_hw->dma_start)(ct); + + outb(DMA1_SMSK, chan); + bus_space_write_1(bst, bsh, cmd_port, CMDP_DMES); +} + +static void +bshw_dmadone(ct) + struct ct_softc *ct; +{ + struct bshw_softc *bs = ct->ct_hw; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + + outb(DMA1_SMSK, (bs->sc_drq | DMA37SM_SET)); + bus_space_write_1(bst, bsh, cmd_port, CMDP_DMER); + + /* vendor unique hook */ + if (bs->sc_hw->dma_stop) + (*bs->sc_hw->dma_stop)(ct); + +#ifdef __FreeBSD__ + if (need_post_dma_flush) + invd(); +#else + if (slp->sl_scp.scp_direction == SCSI_LOW_READ) + cpu_cf_postRead(curcpu); + else + cpu_cf_postWrite(curcpu); +#endif +} + +/********************************************** + * VENDOR UNIQUE DMA FUNCS + **********************************************/ +static int bshw_dma_init_sc98 __P((struct ct_softc *)); +static void bshw_dma_start_sc98 __P((struct ct_softc *)); +static void bshw_dma_stop_sc98 __P((struct ct_softc *)); +static int bshw_dma_init_texa __P((struct ct_softc *)); +static void bshw_dma_start_elecom __P((struct ct_softc *)); +static void bshw_dma_stop_elecom __P((struct ct_softc *)); + +static int +bshw_dma_init_texa(ct) + struct ct_softc *ct; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + u_int8_t regval; + + if ((regval = ct_cr_read_1(bst, bsh, 0x37)) & 0x08) + return 0; + + ct_cr_write_1(bst, bsh, 0x37, regval | 0x08); + regval = ct_cr_read_1(bst, bsh, 0x3f); + ct_cr_write_1(bst, bsh, 0x3f, regval | 0x08); + return 1; +} + +static int +bshw_dma_init_sc98(ct) + struct ct_softc *ct; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + + if (ct_cr_read_1(bst, bsh, 0x37) & 0x08) + return 0; + + /* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */ + ct_cr_write_1(bst, bsh, 0x37, 0x1a); + ct_cr_write_1(bst, bsh, 0x3f, 0x1a); +#if 0 + /* only valid for IO */ + ct_cr_write_1(bst, bsh, 0x40, 0xf4); + ct_cr_write_1(bst, bsh, 0x41, 0x9); + ct_cr_write_1(bst, bsh, 0x43, 0xff); + ct_cr_write_1(bst, bsh, 0x46, 0x4e); + + ct_cr_write_1(bst, bsh, 0x48, 0xf4); + ct_cr_write_1(bst, bsh, 0x49, 0x9); + ct_cr_write_1(bst, bsh, 0x4b, 0xff); + ct_cr_write_1(bst, bsh, 0x4e, 0x4e); +#endif + return 1; +} + +static void +bshw_dma_start_sc98(ct) + struct ct_softc *ct; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + + ct_cr_write_1(bst, bsh, 0x73, 0x32); + ct_cr_write_1(bst, bsh, 0x74, 0x23); +} + +static void +bshw_dma_stop_sc98(ct) + struct ct_softc *ct; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + + ct_cr_write_1(bst, bsh, 0x73, 0x43); + ct_cr_write_1(bst, bsh, 0x74, 0x34); +} + +static void +bshw_dma_start_elecom(ct) + struct ct_softc *ct; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + u_int8_t tmp = ct_cr_read_1(bst, bsh, 0x4c); + + ct_cr_write_1(bst, bsh, 0x32, tmp & 0xdf); +} + +static void +bshw_dma_stop_elecom(ct) + struct ct_softc *ct; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + u_int8_t tmp = ct_cr_read_1(bst, bsh, 0x4c); + + ct_cr_write_1(bst, bsh, 0x32, tmp | 0x20); +} + +static struct bshw bshw_generic = { + BSHW_SYNC_RELOAD, + + 0, + + NULL, + NULL, + NULL, +}; + +static struct bshw bshw_sc98 = { + BSHW_DOUBLE_DMACHAN, + + 0x60, + + bshw_dma_init_sc98, + bshw_dma_start_sc98, + bshw_dma_stop_sc98, +}; + +static struct bshw bshw_texa = { + BSHW_DOUBLE_DMACHAN, + + 0x60, + + bshw_dma_init_texa, + NULL, + NULL, +}; + +static struct bshw bshw_elecom = { + 0, + + 0x38, + + NULL, + bshw_dma_start_elecom, + bshw_dma_stop_elecom, +}; + +static struct bshw bshw_lc_smit = { + BSHW_SMFIFO | BSHW_DOUBLE_DMACHAN, + + 0x60, + + NULL, + NULL, + NULL, +}; + +static struct bshw bshw_lha20X = { + BSHW_DOUBLE_DMACHAN, + + 0x60, + + NULL, + NULL, + NULL, +}; + +/* hw tabs */ +static dvcfg_hw_t bshw_hwsel_array[] = { +/* 0x00 */ &bshw_generic, +/* 0x01 */ &bshw_sc98, +/* 0x02 */ &bshw_texa, +/* 0x03 */ &bshw_elecom, +/* 0x04 */ &bshw_lc_smit, +/* 0x05 */ &bshw_lha20X, +}; + +struct dvcfg_hwsel bshw_hwsel = { + DVCFG_HWSEL_SZ(bshw_hwsel_array), + bshw_hwsel_array +}; diff --git a/sys/dev/ct/bshwvar.h b/sys/dev/ct/bshwvar.h new file mode 100644 index 000000000000..6e31b4d0e11d --- /dev/null +++ b/sys/dev/ct/bshwvar.h @@ -0,0 +1,86 @@ +/* $FreeBSD$ */ +/* $NecBSD: bshwvar.h,v 1.3 1999/04/15 01:36:10 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _BSHWVAR_H_ +#define _BSHWVAR_H_ + +/* + * bshwvar.h + * NEC 55 compatible board specific definitions + */ + +#define BSHW_DEFAULT_CHIPCLK 20 /* 20MHz */ +#define BSHW_DEFAULT_HOSTID 7 + +struct bshw { +#define BSHW_SYNC_RELOAD 0x01 +#define BSHW_SMFIFO 0x02 +#define BSHW_DOUBLE_DMACHAN 0x04 + u_int hw_flags; + + u_int sregaddr; + + int ((*dma_init) __P((struct ct_softc *))); + void ((*dma_start) __P((struct ct_softc *))); + void ((*dma_stop) __P((struct ct_softc *))); +}; + +struct bshw_softc { + int sc_hostid; + int sc_irq; /* irq */ + int sc_drq; /* drq */ + + /* dma transfer */ + u_int8_t *sc_segaddr; + u_int8_t *sc_bufp; + int sc_seglen; + int sc_tdatalen; /* temp datalen */ + + /* private bounce */ + u_int8_t *sc_bounce_phys; + u_int8_t *sc_bounce_addr; + u_int sc_bounce_size; + bus_addr_t sc_minphys; + + /* hardware */ + struct bshw *sc_hw; +}; + +void bshw_synch_setup __P((struct ct_softc *, struct lun_info *)); +void bshw_bus_reset __P((struct ct_softc *)); +int bshw_read_settings __P((bus_space_tag_t, bus_space_handle_t, struct bshw_softc *)); +void bshw_smit_xfer_start __P((struct ct_softc *)); +void bshw_smit_xfer_stop __P((struct ct_softc *)); +void bshw_dma_xfer_start __P((struct ct_softc *)); +void bshw_dma_xfer_stop __P((struct ct_softc *)); +extern struct dvcfg_hwsel bshw_hwsel; +#endif /* !_BSHWVAR_H_ */ diff --git a/sys/dev/ct/ct.c b/sys/dev/ct/ct.c new file mode 100644 index 000000000000..a0bb390e70b7 --- /dev/null +++ b/sys/dev/ct/ct.c @@ -0,0 +1,960 @@ +/* $FreeBSD$ */ +/* $NecBSD: ct.c,v 1.13 1999/07/23 20:54:00 honda Exp $ */ +/* $NetBSD$ */ + +#define CT_DEBUG +#define CT_USE_CCSEQ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999 + * NetBSD/pc98 porting staff. All rights reserved. + * + * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999 + * Naofumi HONDA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __NetBSD__ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include + +#include +#include + +#include + +#include +#include +#endif /* __FreeBSD__ */ + +/*************************************************** + * DEBUG + ***************************************************/ +#define CT_NTARGETS 8 +#define CT_NLUNS 8 +#define CT_RESET_DEFAULT 2000 + +#ifndef DDB +#define Debugger() panic("should call debugger here (ct.c)") +#else /* ! DDB */ +#ifdef __FreeBSD__ +#define Debugger() Debugger("ct") +#endif /* __FreeBSD__ */ +#endif + +#ifdef CT_DEBUG +int ct_debug; +#endif /* CT_DEBUG */ + +/*************************************************** + * default data + ***************************************************/ +u_int8_t cthw_cmdlevel[256] = { +/* 0 1 2 3 4 5 6 7 8 9 A B C E D F */ +/*0*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 , +/*1*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*2*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 , +/*3*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*4*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*5*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*6*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*7*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*8*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*9*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*A*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*B*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*C*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*D*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*E*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +/*F*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +}; + +/* default synch data table */ +/* A 10 6.6 5.0 4.0 3.3 2.8 2.5 2.0 M/s */ +/* X 100 150 200 250 300 350 400 500 ns */ +static struct ct_synch_data ct_synch_data_20MHz[] = { + {25, 0xa0}, {37, 0xb0}, {50, 0x20}, {62, 0xd0}, {75, 0x30}, + {87, 0xf0}, {100, 0x40}, {125, 0x50}, {0, 0} +}; + +extern unsigned int delaycount; + +/***************************************************************** + * Interface functions + *****************************************************************/ +static int ct_xfer __P((struct ct_softc *, u_int8_t *, int, int)); +static void ct_io_xfer __P((struct ct_softc *)); +static __inline int ct_reselected __P((struct ct_softc *)); +static void ct_phase_error __P((struct ct_softc *, u_int8_t)); +static int ct_start_selection __P((struct ct_softc *, struct slccb *)); +static int ct_msg __P((struct ct_softc *, struct targ_info *, u_int)); +static int ct_world_start __P((struct ct_softc *, int)); +static __inline void cthw_phase_bypass __P((struct ct_softc *, u_int8_t)); +static int cthw_chip_reset __P((bus_space_tag_t, bus_space_handle_t, int, int)); +static void cthw_bus_reset __P((struct ct_softc *)); +static int ct_nexus __P((struct ct_softc *, struct targ_info *)); +static void cthw_attention __P((struct ct_softc *)); +static int ct_targ_init __P((struct ct_softc *, struct targ_info *)); + +struct scsi_low_funcs ct_funcs = { + SC_LOW_INIT_T ct_world_start, + SC_LOW_BUSRST_T cthw_bus_reset, + SC_LOW_TARG_INIT_T ct_targ_init, + + SC_LOW_SELECT_T ct_start_selection, + SC_LOW_NEXUS_T ct_nexus, + + SC_LOW_ATTEN_T cthw_attention, + SC_LOW_MSG_T ct_msg, + + SC_LOW_POLL_T ctintr, + + NULL, /* SC_LOW_POWER_T cthw_power, */ +}; + +/************************************************** + * HW functions + **************************************************/ +static __inline void +cthw_phase_bypass(ct, ph) + struct ct_softc *ct; + u_int8_t ph; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + + ct_cr_write_1(bst, bsh, wd3s_cph, ph); + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_SELECT_ATN_TFR); + ct->sc_satgo = CT_SAT_GOING; +} + +static void +cthw_bus_reset(ct) + struct ct_softc *ct; +{ + + /* + * wd33c93 does not have bus reset function. + */ + if (ct->ct_bus_reset != NULL) + ((*ct->ct_bus_reset) (ct)); +} + +static int +cthw_chip_reset(bst, bsh, chipclk, hostid) + bus_space_tag_t bst; + bus_space_handle_t bsh; + int chipclk, hostid; +{ +#define CT_SELTIMEOUT_20MHz_REGV (0x80) + u_int8_t aux, regv; + u_int seltout; + int wc; + + /* issue abort cmd */ + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_ABORT); + delay(1000); /* 1ms wait */ + (void) ct_stat_read_1(bst, bsh); + (void) ct_cr_read_1(bst, bsh, wd3s_stat); + + /* setup chip registers */ + regv = 0; + seltout = CT_SELTIMEOUT_20MHz_REGV; + switch (chipclk) + { + case 10: + seltout = (seltout * chipclk) / 20; + regv = 0; + break; + + case 15: + seltout = (seltout * chipclk) / 20; + regv = IDR_FS_12_15; + break; + + case 20: + seltout = (seltout * chipclk) / 20; + regv = IDR_FS_15_20; + break; + + default: + panic("ct: illegal chip clk rate\n"); + break; + } + regv |= IDR_EHP | hostid; + ct_cr_write_1(bst, bsh, wd3s_oid, regv); + + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_RESET); + for (wc = CT_RESET_DEFAULT; wc > 0; wc --) + { + aux = ct_stat_read_1(bst, bsh); + if (aux != 0xff && (aux & STR_INT)) + { + if (ct_cr_read_1(bst, bsh, wd3s_stat) == 0) + break; + + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_RESET); + } + delay(1); + } + if (wc == 0) + return ENXIO; + + ct_cr_write_1(bst, bsh, wd3s_tout, seltout); + ct_cr_write_1(bst, bsh, wd3s_sid, SIDR_RESEL); + ct_cr_write_1(bst, bsh, wd3s_ctrl, CR_DEFAULT); + ct_cr_write_1(bst, bsh, wd3s_synch, 0); + + (void) ct_stat_read_1(bst, bsh); + (void) ct_cr_read_1(bst, bsh, wd3s_stat); + return 0; +} + +/************************************************** + * Attach & Probe + **************************************************/ +int +ctprobesubr(bst, bsh, dvcfg, hsid, chipclk) + bus_space_tag_t bst; + bus_space_handle_t bsh; + u_int dvcfg, chipclk; + int hsid; +{ + +#if 0 + if ((ct_stat_read_1(bst, bsh) & STR_BUSY) != 0) + return 0; +#endif + if (cthw_chip_reset(bst, bsh, chipclk, hsid) != 0) + return 0; + return 1; +} + +int +ctprint(aux, name) + void *aux; + const char *name; +{ + + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; +} + +void +ctattachsubr(ct) + struct ct_softc *ct; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + + ct->sc_wc = delaycount * 2000; /* 2 sec */ + slp->sl_funcs = &ct_funcs; + (void) scsi_low_attach(slp, 2, CT_NTARGETS, CT_NLUNS, + sizeof(struct ct_targ_info)); +} + +/************************************************** + * SCSI LOW interface functions + **************************************************/ +static void +cthw_attention(ct) + struct ct_softc *ct; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + + if ((ct_stat_read_1(bst, bsh) & STR_BUSY) != 0) + { + ct->sc_atten = 1; + return; + } + + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_ASSERT_ATN); + delay(10); + if ((ct_stat_read_1(bst, bsh) & STR_LCI) != 0) + { + ct->sc_atten = 1; + return; + } + ct->sc_atten = 0; +} + +static int +ct_targ_init(ct, ti) + struct ct_softc *ct; + struct targ_info *ti; +{ + struct ct_targ_info *cti = (void *) ti; + + if (ct->sc_chiprev == CT_WD33C93_A) + { + ti->ti_maxsynch.period = 200 / 4; /* 5MHz */ + ti->ti_maxsynch.offset = 8; + } + else + { + ti->ti_maxsynch.period = 100 / 4; /* 10MHz */ + ti->ti_maxsynch.offset = 12; + } + + cti->cti_syncreg = 0; + return 0; +} + +static int +ct_world_start(ct, fdone) + struct ct_softc *ct; + int fdone; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + intrmask_t s; + + if (ct->sc_sdp == NULL) + ct->sc_sdp = &ct_synch_data_20MHz[0]; + + slp->sl_cfgflags |= CFG_MSGUNIFY; + if (slp->sl_cfgflags & CFG_NOPARITY) + ct->sc_creg = CR_DEFAULT; + else + ct->sc_creg = CR_DEFAULT_HP; + + if (ct->sc_dma & CT_DMA_DMASTART) + (*ct->ct_dma_xfer_stop) (ct); + if (ct->sc_dma & CT_DMA_PIOSTART) + (*ct->ct_pio_xfer_stop) (ct); + ct->sc_dma = 0; + ct->sc_atten = 0; + + s = splcam(); + cthw_chip_reset(bst, bsh, ct->sc_chipclk, slp->sl_hostid); + scsi_low_bus_reset(slp); + cthw_chip_reset(bst, bsh, ct->sc_chipclk, slp->sl_hostid); + splx(s); + + SOFT_INTR_REQUIRED(slp); + return 0; +} + +static int +ct_start_selection(ct, cb) + struct ct_softc *ct; + struct slccb *cb; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + struct targ_info *ti = slp->sl_nexus; + struct lun_info *li = ti->ti_li; + int s; + u_int8_t cmd; + + ct->sc_atten = 0; + if (cthw_cmdlevel[slp->sl_scp.scp_cmd[0]] != 0) + { + /* + * This completely violates scsi protocols, + * however some old devices do not work + * properly with scsi attentions. + */ + if ((li->li_flags & SCSI_LOW_DISC) != 0) + cmd = WD3S_SELECT_ATN_TFR; + else + cmd = WD3S_SELECT_NO_ATN_TFR; + ct->sc_satgo = CT_SAT_GOING; + } + else + { + cmd = WD3S_SELECT_ATN; + ct->sc_satgo = 0; + } + + if ((ct_stat_read_1(bst, bsh) & STR_BUSY) != 0) + return SCSI_LOW_START_FAIL; + + scsi_low_cmd(slp, ti); + + if ((ct->sc_satgo & CT_SAT_GOING) != 0) + ct_write_cmds(bst, bsh, + slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); + + s = splhigh(); + if ((ct_stat_read_1(bst, bsh) & STR_BUSY) == 0) + { + /* XXX: + * Reload a lun again here. + */ + ct_cr_write_1(bst, bsh, wd3s_lun, li->li_lun); + ct_cr_write_1(bst, bsh, wd3s_cmd, cmd); + if ((ct_stat_read_1(bst, bsh) & STR_LCI) == 0) + { + splx(s); + SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); + return SCSI_LOW_START_OK; + } + } + splx(s); + return SCSI_LOW_START_FAIL; +} + +static int +ct_msg(ct, ti, msg) + struct ct_softc *ct; + struct targ_info *ti; + u_int msg; +{ + struct lun_info *li = ti->ti_li; + struct ct_targ_info *cti = (void *) ti; + struct ct_synch_data *csp = ct->sc_sdp; + u_int offset, period; + + if (msg != SCSI_LOW_MSG_SYNCH) + return 0; + + offset = ti->ti_maxsynch.offset; + period = ti->ti_maxsynch.period; + for ( ; csp->cs_period != 0; csp ++) + { + if (period == csp->cs_period) + break; + } + + if (ti->ti_maxsynch.period != 0 && csp->cs_period == 0) + { + ti->ti_maxsynch.period = 0; + ti->ti_maxsynch.offset = 0; + cti->cti_syncreg = 0; + return EINVAL; + } + + cti->cti_syncreg = ((offset & 0x0f) | csp->cs_syncr); + if (ct->ct_synch_setup != 0) + (*ct->ct_synch_setup) (ct, li); + return 0; +} + +/************************************************* + * + *************************************************/ +static int +ct_xfer(ct, data, len, direction) + struct ct_softc *ct; + u_int8_t *data; + int len, direction; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + int wc; + register u_int8_t aux; + + if (len == 1) + { + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO); + } + else + { + cthw_set_count(bst, bsh, len); + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_TFR_INFO); + } + + aux = ct_stat_read_1(bst, bsh); + if ((aux & STR_LCI) != 0) + { + cthw_set_count(bst, bsh, 0); + return len; + } + + for (wc = ct->sc_wc ; wc > 0; wc --) + { + /* check data ready */ + if ((aux & (STR_BSY | STR_DBR)) == (STR_BSY | STR_DBR)) + { + if (direction == SCSI_LOW_READ) + *data = ct_cr_read_1(bst, bsh, wd3s_data); + else + ct_cr_write_1(bst, bsh, wd3s_data, *data); + len --; + if (len <= 0) + break; + data ++; + } + + /* check phase miss */ + aux = ct_stat_read_1(bst, bsh); + if ((aux & STR_INT) != 0) + break; + } + return len; +} + +static void +ct_io_xfer(ct) + struct ct_softc *ct; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + struct sc_p *sp = &slp->sl_scp; + u_int dummy; + int len; + + /* io polling mode */ + ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg); + + if (sp->scp_datalen <= 0) + { + slp->sl_error |= PDMAERR; + dummy = 0; + len = ct_xfer(ct, (u_int8_t *) &dummy, 1, sp->scp_direction); + } + else + len = ct_xfer(ct, sp->scp_data, sp->scp_datalen, + sp->scp_direction); + + sp->scp_data += (sp->scp_datalen - len); + sp->scp_datalen = len; +} + +/************************************************** + * + **************************************************/ +struct ct_err { + u_char *pe_msg; + u_int pe_err; + u_int pe_errmsg; + int pe_done; +}; + +struct ct_err ct_cmderr[] = { +/*0*/ { "illegal cmd", FATALIO, SCSI_LOW_MSG_ABORT, 1}, +/*1*/ { "unexpected bus free", FATALIO, 0, 1}, +/*2*/ { NULL, SELTIMEOUTIO, 0, 1}, +/*3*/ { "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, +/*4*/ { "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, +/*5*/ { "unknown" , FATALIO, SCSI_LOW_MSG_ABORT, 1}, +/*6*/ { "miss reselection (target mode)", FATALIO, SCSI_LOW_MSG_ABORT, 0}, +/*7*/ { "wrong status byte", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, +}; + +static void +ct_phase_error(ct, scsi_status) + struct ct_softc *ct; + u_int8_t scsi_status; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + struct targ_info *ti = slp->sl_nexus; + struct ct_err *pep; + u_int msg = 0; + + if ((scsi_status & BSR_CM) == BSR_CMDERR && + (scsi_status & BSR_PHVALID) == 0) + { + pep = &ct_cmderr[scsi_status & BSR_PM]; + slp->sl_error |= pep->pe_err; + if ((pep->pe_err & PARITYERR) != 0) + { + if (ti->ti_phase == PH_MSGIN) + msg = SCSI_LOW_MSG_PARITY; + else + msg = SCSI_LOW_MSG_ERROR; + } + else + msg = pep->pe_errmsg; + + if (msg != 0) + scsi_low_assert_msg(slp, slp->sl_nexus, msg, 1); + + if (pep->pe_msg != NULL) + { + printf("%s: phase error: %s", + slp->sl_xname, pep->pe_msg); + scsi_low_print(slp, slp->sl_nexus); + } + + if (pep->pe_done != 0) + scsi_low_disconnected(slp, ti); + } + else + { + slp->sl_error |= FATALIO; + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "phase error"); + } +} + +/************************************************** + * ### SCSI PHASE SEQUENCER ### + **************************************************/ +static __inline int +ct_reselected(ct) + struct ct_softc *ct; +{ + struct scsi_low_softc *slp = &ct->sc_sclow; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + struct targ_info *ti; + u_int sid; + + ct->sc_atten = 0; + sid = (ct_cr_read_1(bst, bsh, wd3s_sid) & SIDR_IDM); + if ((ti = scsi_low_reselected(slp, sid)) == NULL) + return EJUSTRETURN; + + ct_cr_write_1(bst, bsh, wd3s_did, sid); + ct_cr_write_1(bst, bsh, wd3s_lun, 0); /* temp */ + ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg | CR_DMA); + cthw_set_count(bst, bsh, 0); + return EJUSTRETURN; +} + +static int +ct_nexus(ct, ti) + struct ct_softc *ct; + struct targ_info *ti; +{ + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + struct lun_info *li = ti->ti_li; + struct ct_targ_info *cti = (void *) ti; + + if ((li->li_flags & SCSI_LOW_NOPARITY) != 0) + ct->sc_creg = CR_DEFAULT; + else + ct->sc_creg = CR_DEFAULT_HP; + + ct_cr_write_1(bst, bsh, wd3s_did, ti->ti_id); + ct_cr_write_1(bst, bsh, wd3s_lun, li->li_lun); + ct_cr_write_1(bst, bsh, wd3s_ctrl, ct->sc_creg | CR_DMA); + ct_cr_write_1(bst, bsh, wd3s_cph, 0); + ct_cr_write_1(bst, bsh, wd3s_synch, cti->cti_syncreg); + cthw_set_count(bst, bsh, 0); + ct_cr_write_1(bst, bsh, wd3s_lun, li->li_lun); /* XXX */ + return 0; +} + +int +ctintr(arg) + void *arg; +{ + struct ct_softc *ct = arg; + struct scsi_low_softc *slp = &ct->sc_sclow; + bus_space_tag_t bst = ct->sc_iot; + bus_space_handle_t bsh = ct->sc_ioh; + struct targ_info *ti; + struct physio_proc *pp; + struct buf *bp; + int len, satgo; + u_int8_t scsi_status, regv; + + if (slp->sl_flags & HW_INACTIVE) + return 0; + + /************************************************** + * Get status & bus phase + **************************************************/ + if ((ct_stat_read_1(bst, bsh) & STR_INT) == 0) + return 0; + + scsi_status = ct_cr_read_1(bst, bsh, wd3s_stat); + if (scsi_status == ((u_int8_t) -1)) + return 1; + + /************************************************** + * Check reselection, or nexus + **************************************************/ + if (scsi_status == BSR_RESEL) + { + if (ct_reselected(ct) == EJUSTRETURN) + return 1; + } + + if ((ti = slp->sl_nexus) == NULL) + return 1; + + /************************************************** + * Debug section + **************************************************/ +#ifdef CT_DEBUG + if (ct_debug > 0) + { + scsi_low_print(slp, NULL); + printf("%s: scsi_status 0x%x\n\n", slp->sl_xname, + (u_int) scsi_status); + if (ct_debug > 1) + Debugger(); + } +#endif /* CT_DEBUG */ + + /************************************************** + * Internal scsi phase + **************************************************/ + satgo = ct->sc_satgo; + ct->sc_satgo = 0; + + switch (ti->ti_phase) + { + case PH_SELSTART: + if ((satgo & CT_SAT_GOING) == 0) + { + if (scsi_status != BSR_SELECTED) + { + ct_phase_error(ct, scsi_status); + return 1; + } + scsi_low_arbit_win(slp, ti); + SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); + return 1; + } + else + { + scsi_low_arbit_win(slp, ti); + SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); + } + break; + + case PH_RESEL: + if ((scsi_status & BSR_PHVALID) == 0 || + (scsi_status & BSR_PM) != BSR_MSGIN) + { + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, + "phase miss after reselect"); + return 1; + } + break; + + default: + if (slp->sl_flags & HW_PDMASTART) + { + slp->sl_flags &= ~HW_PDMASTART; + if (ct->sc_dma & CT_DMA_DMASTART) + { + (*ct->ct_dma_xfer_stop) (ct); + ct->sc_dma &= ~CT_DMA_DMASTART; + } + else + { + (*ct->ct_pio_xfer_stop) (ct); + ct->sc_dma &= ~CT_DMA_PIOSTART; + } + } + break; + } + + /************************************************** + * parse scsi phase + **************************************************/ + if (scsi_status & BSR_PHVALID) + { + /************************************************** + * Normal SCSI phase. + **************************************************/ + if ((scsi_status & BSR_CM) == BSR_CMDABT) + { + ct_phase_error(ct, scsi_status); + return 1; + } + + switch (scsi_status & BSR_PM) + { + case BSR_DATAOUT: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) + return 1; + goto common_data_phase; + + case BSR_DATAIN: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) + return 1; + +common_data_phase: + if (slp->sl_scp.scp_datalen <= 0) + { + ct_io_xfer(ct); + return 1; + } + + slp->sl_flags |= HW_PDMASTART; + if ((ct->sc_xmode & CT_XMODE_PIO) != 0 && + (slp->sl_scp.scp_datalen % DEV_BSIZE) == 0) + { + pp = physio_proc_enter(bp); + ct->sc_dma |= CT_DMA_PIOSTART; + (*ct->ct_pio_xfer_start) (ct); + physio_proc_leave(pp); + return 1; + } + else + { + ct->sc_dma |= CT_DMA_DMASTART; + (*ct->ct_dma_xfer_start) (ct); + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_TFR_INFO); + } + return 1; + + case BSR_CMDOUT: + SCSI_LOW_SETUP_PHASE(ti, PH_CMD); + if (scsi_low_cmd(slp, ti) != 0) + break; + + if (ct_xfer(ct, + slp->sl_scp.scp_cmd, + slp->sl_scp.scp_cmdlen, + SCSI_LOW_WRITE) != 0) + { + printf("%s: scsi cmd xfer short\n", + slp->sl_xname); + } + return 1; + + case BSR_STATIN: + SCSI_LOW_SETUP_PHASE(ti, PH_STAT); +#ifdef CT_USE_CCSEQ + if (scsi_low_is_msgout_continue(ti) != 0 || + ct->sc_atten != 0) + { + ct_xfer(ct, &ti->ti_status, 1, SCSI_LOW_READ); + } + else + { + cthw_set_count(bst, bsh, 0); + cthw_phase_bypass(ct, 0x41); + } +#else /* !CT_USE_CCSEQ */ + ct_xfer(ct, &ti->ti_status, 1, SCSI_LOW_READ); +#endif /* !CT_USE_CCSEQ */ + return 1; + + case BSR_UNSPINFO0: + case BSR_UNSPINFO1: + printf("%s: illegal bus phase (0x%x)\n", slp->sl_xname, + (u_int) scsi_status); + scsi_low_print(slp, ti); + return 1; + + case BSR_MSGOUT: + SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); + len = scsi_low_msgout(slp, ti); + if (ct_xfer(ct, ti->ti_msgoutstr, len, SCSI_LOW_WRITE)) + { + printf("%s: scsi msgout xfer short\n", + slp->sl_xname); + scsi_low_assert_msg(slp, ti, + SCSI_LOW_MSG_ABORT, 1); + } + return 1; + + case BSR_MSGIN:/* msg in */ + SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); + ct_xfer(ct, ®v, 1, SCSI_LOW_READ); + scsi_low_msgin(slp, ti, regv); + return 1; + } + } + else + { + /************************************************** + * Special SCSI phase + **************************************************/ + switch (scsi_status) + { + case BSR_SATSDP: /* SAT with save data pointer */ + SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); + scsi_low_msgin(slp, ti, MSG_SAVESP); + cthw_phase_bypass(ct, 0x41); + return 1; + + case BSR_SATFIN: /* SAT COMPLETE */ + /* + * emulate statusin => msgin + */ + ti->ti_status = ct_cr_read_1(bst, bsh, wd3s_lun); + SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); + scsi_low_disconnected(slp, ti); + return 1; + + case BSR_ACKREQ: /* negate ACK */ + if (ct->sc_atten != 0) + cthw_attention(ct); + + ct_cr_write_1(bst, bsh, wd3s_cmd, WD3S_NEGATE_ACK); + return 1; + + case BSR_DISC: /* disconnect */ + if (slp->sl_msgphase == MSGPH_NULL && + (satgo & CT_SAT_GOING) != 0) + { + /* + * emulate disconnect msg + */ + SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC); + } + scsi_low_disconnected(slp, ti); + return 1; + + default: + break; + } + } + + ct_phase_error(ct, scsi_status); + return 1; +} diff --git a/sys/dev/ct/ct_isa.c b/sys/dev/ct/ct_isa.c new file mode 100644 index 000000000000..959a2a85e476 --- /dev/null +++ b/sys/dev/ct/ct_isa.c @@ -0,0 +1,322 @@ +/* $FreeBSD$ */ +/* $NecBSD: ct_isa.c,v 1.6 1999/07/26 06:32:01 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define SCSIBUS_RESCAN + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __NetBSD__ +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#endif /* __FreeBSD__ */ + +#define BSHW_IOSZ 0x08 +#define BSHW_IOBASE 0xcc0 +#define BSHW_MEMSZ (PAGE_SIZE * 2) + +static int ct_isa_match(device_t); +static int ct_isa_attach(device_t); +static int ct_space_map(device_t, struct bshw *, + struct resource **, struct resource **); +static void ct_space_unmap(device_t, struct ct_softc *); +static struct bshw *ct_find_hw(device_t); +static void ct_dmamap(void *, bus_dma_segment_t *, int, int); + +struct ct_isa_softc { + struct ct_softc sc_ct; + struct bshw_softc sc_bshw; +}; + +static struct isa_pnp_id ct_pnp_ids[] = { + { 0x110154dc, "I-O DATA SC-98III" }, + { 0x4120acb4, "MELCO IFC-NN" }, + { 0, NULL } +}; + +static device_method_t ct_isa_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ct_isa_match), + DEVMETHOD(device_attach, ct_isa_attach), + { 0, 0 } +}; + +static driver_t ct_isa_driver = { + "ct", ct_isa_methods, sizeof(struct ct_isa_softc), +}; + +static devclass_t ct_devclass; + +DRIVER_MODULE(ct, isa, ct_isa_driver, ct_devclass, 0, 0); + +static int +ct_isa_match(device_t dev) +{ + struct bshw *hw; + struct resource *port_res, *mem_res; + int rv; + + if (ISA_PNP_PROBE(device_get_parent(dev), dev, ct_pnp_ids) == ENXIO) + return ENXIO; + + if (isa_get_port(dev) == -1) + bus_set_resource(dev, SYS_RES_IOPORT, 0, + BSHW_IOBASE, BSHW_IOSZ); + + if ((hw = ct_find_hw(dev)) == NULL) + return ENXIO; + if (ct_space_map(dev, hw, &port_res, &mem_res) != 0) + return ENXIO; + + rv = ctprobesubr(rman_get_bustag(port_res), + rman_get_bushandle(port_res), + 0, BSHW_DEFAULT_HOSTID, BSHW_DEFAULT_CHIPCLK); + if (rv != 0) + { + struct bshw_softc bshw_tab; + struct bshw_softc *bs = &bshw_tab; + + memset(bs, 0, sizeof(*bs)); + bshw_read_settings(rman_get_bustag(port_res), + rman_get_bushandle(port_res), bs); + bus_set_resource(dev, SYS_RES_IRQ, 0, bs->sc_irq, 1); + bus_set_resource(dev, SYS_RES_DRQ, 0, bs->sc_drq, 1); + } + + bus_release_resource(dev, SYS_RES_IOPORT, 0, port_res); + if (mem_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, 0, mem_res); + + if (rv != 0) + return 0; + return ENXIO; +} + +static int +ct_isa_attach(device_t dev) +{ + struct ct_isa_softc *pct = device_get_softc(dev); + struct ct_softc *ct = &pct->sc_ct; + struct scsi_low_softc *slp = &ct->sc_sclow; + struct bshw_softc *bs = &pct->sc_bshw; + struct bshw *hw; + int irq_rid, drq_rid; + u_int8_t *vaddr; + bus_addr_t addr; + + hw = ct_find_hw(dev); + if (ct_space_map(dev, hw, &ct->port_res, &ct->mem_res) != 0) { + device_printf(dev, "bus io mem map failed\n"); + return ENXIO; + } + + ct->sc_iot = rman_get_bustag(ct->port_res); + ct->sc_ioh = rman_get_bushandle(ct->port_res); + if (ct->mem_res) { + ct->sc_memt = rman_get_bustag(ct->mem_res); + ct->sc_memh = rman_get_bushandle(ct->mem_res); + } + + irq_rid = 0; + ct->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &irq_rid, 0, ~0, + 1, RF_ACTIVE); + drq_rid = 0; + ct->drq_res = bus_alloc_resource(dev, SYS_RES_DRQ, &drq_rid, 0, ~0, + 1, RF_ACTIVE); + if (ct->irq_res == NULL || ct->drq_res == NULL) { + ct_space_unmap(dev, ct); + return ENXIO; + } + + /* setup DMA map */ + if (bus_dma_tag_create(NULL, 1, 0, + BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR, + NULL, NULL, MAXBSIZE, 1, + BUS_SPACE_MAXSIZE_32BIT, + BUS_DMA_ALLOCNOW, &ct->sc_dmat) != 0) { + device_printf(dev, "can't set up ISA DMA map\n"); + ct_space_unmap(dev, ct); + return ENXIO; + } + + if (bus_dmamem_alloc(ct->sc_dmat, (void **)&vaddr, BUS_DMA_NOWAIT, + &ct->sc_dmamapt) != 0) { + device_printf(dev, "can't set up ISA DMA map\n"); + ct_space_unmap(dev, ct); + return ENXIO; + } + + bus_dmamap_load(ct->sc_dmat, ct->sc_dmamapt, vaddr, MAXBSIZE, + ct_dmamap, &addr, 0); + + /* setup machdep softc */ + bs->sc_hw = hw; + bs->sc_bounce_phys = (u_int8_t *)addr; + bs->sc_bounce_addr = vaddr; + bs->sc_bounce_size = MAXBSIZE; + bs->sc_minphys = (1 << 24); + bshw_read_settings(ct->sc_iot, ct->sc_ioh, bs); + + /* setup ct driver softc */ + ct->ct_hw = bs; + ct->ct_dma_xfer_start = bshw_dma_xfer_start; + ct->ct_pio_xfer_start = bshw_smit_xfer_start; + ct->ct_dma_xfer_stop = bshw_dma_xfer_stop; + ct->ct_pio_xfer_stop = bshw_smit_xfer_stop; + ct->ct_bus_reset = bshw_bus_reset; + ct->ct_synch_setup = bshw_synch_setup; + + ct->sc_xmode = CT_XMODE_DMA; + if (ct->sc_memh != NULL) + ct->sc_xmode |= CT_XMODE_PIO; + ct->sc_chiprev = CT_WD33C93_B; + ct->sc_chipclk = BSHW_DEFAULT_CHIPCLK; + + slp->sl_dev = dev; + slp->sl_hostid = bs->sc_hostid; + slp->sl_irq = isa_get_irq(dev); + slp->sl_cfgflags = device_get_flags(dev); + + ctattachsubr(ct); + + if (bus_setup_intr(dev, ct->irq_res, INTR_TYPE_CAM, + (driver_intr_t *)ctintr, ct, &ct->sc_ih)) { + ct_space_unmap(dev, ct); + return ENXIO; + } + + return 0; +} + +static struct bshw * +ct_find_hw(device_t dev) +{ + return DVCFG_HW(&bshw_hwsel, DVCFG_MAJOR(device_get_flags(dev))); +} + +static int +ct_space_map(device_t dev, struct bshw *hw, + struct resource **iohp, struct resource **memhp) +{ + int port_rid, mem_rid; + + *memhp = NULL; + + port_rid = 0; + *iohp = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid, 0, ~0, + BSHW_IOSZ, RF_ACTIVE); + if (*iohp == NULL) + return ENXIO; + + if ((hw->hw_flags & BSHW_SMFIFO) == 0 || isa_get_maddr(dev) == -1) + return 0; + + mem_rid = 0; + *memhp = bus_alloc_resource(dev, SYS_RES_MEMORY, &mem_rid, 0, ~0, + BSHW_MEMSZ, RF_ACTIVE); + if (*memhp == NULL) { + bus_release_resource(dev, SYS_RES_IOPORT, port_rid, *iohp); + return ENXIO; + } + + return 0; +} + +static void +ct_space_unmap(device_t dev, struct ct_softc *ct) +{ + if (ct->port_res != NULL) + bus_release_resource(dev, SYS_RES_IOPORT, 0, ct->port_res); + if (ct->mem_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, 0, ct->mem_res); + if (ct->irq_res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, 0, ct->irq_res); + if (ct->drq_res != NULL) + bus_release_resource(dev, SYS_RES_DRQ, 0, ct->drq_res); +} + +static void +ct_dmamap(void *arg, bus_dma_segment_t *seg, int nseg, int error) +{ + bus_addr_t *addr = (bus_addr_t *)arg; + + *addr = seg->ds_addr; +} diff --git a/sys/dev/ct/ct_machdep.h b/sys/dev/ct/ct_machdep.h new file mode 100644 index 000000000000..195af5bed826 --- /dev/null +++ b/sys/dev/ct/ct_machdep.h @@ -0,0 +1,155 @@ +/* $FreeBSD$ */ +/* $NecBSD: ct_machdep.h,v 1.4 1999/07/23 20:54:00 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998 + * Naofumi HONDA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _CT_MACHDEP_H_ +#define _CT_MACHDEP_H_ + +/* + * Principal rules: + * 1) do not use bus_space_write/read_X directly in ct.c. + * 2) do not use port offset defs directly in ct.c. + */ + +/* special weight if requried */ +#define CT_BUS_WEIGHT + +/* port offset */ +#define addr_port 0 +#define stat_port 0 +#define ctrl_port 2 +#define cmd_port 4 + +/* + * All port accesses primitive methods + */ +static __inline u_int8_t ct_cr_read_1 __P((bus_space_tag_t, bus_space_handle_t, bus_addr_t)); +static __inline void ct_cr_write_1 __P((bus_space_tag_t, bus_space_handle_t, bus_addr_t, u_int8_t)); +static __inline void ct_write_cmds __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *, int)); +static __inline u_int cthw_get_count __P((bus_space_tag_t, bus_space_handle_t)); +static __inline void cthw_set_count __P((bus_space_tag_t, bus_space_handle_t, u_int)); + +#define ct_stat_read_1(bst, bsh) bus_space_read_1((bst), (bsh), stat_port) + +static __inline void +cthw_set_count(bst, bsh, count) + bus_space_tag_t bst; + bus_space_handle_t bsh; + u_int count; +{ + + bus_space_write_1(bst, bsh, addr_port, wd3s_cnt); + CT_BUS_WEIGHT + bus_space_write_1(bst, bsh, ctrl_port, count >> 16); + CT_BUS_WEIGHT + bus_space_write_1(bst, bsh, ctrl_port, count >> 8); + CT_BUS_WEIGHT + bus_space_write_1(bst, bsh, ctrl_port, count); + CT_BUS_WEIGHT +} + +static __inline u_int +cthw_get_count(bst, bsh) + bus_space_tag_t bst; + bus_space_handle_t bsh; +{ + u_int count; + + bus_space_write_1(bst, bsh, addr_port, wd3s_cnt); + CT_BUS_WEIGHT + count = (((u_int) bus_space_read_1(bst, bsh, ctrl_port)) << 16); + CT_BUS_WEIGHT + count += (((u_int) bus_space_read_1(bst, bsh, ctrl_port)) << 8); + CT_BUS_WEIGHT + count += ((u_int) bus_space_read_1(bst, bsh, ctrl_port)); + CT_BUS_WEIGHT + return count; +} + +static __inline void +ct_write_cmds(bst, bsh, cmd, len) + bus_space_tag_t bst; + bus_space_handle_t bsh; + u_int8_t *cmd; + int len; +{ + int i; + + bus_space_write_1(bst, bsh, addr_port, wd3s_cdb); + for (i = 0; i < len; i ++) + bus_space_write_1(bst, bsh, ctrl_port, cmd[i]); +} + +static __inline u_int8_t +ct_cr_read_1(bst, bsh, offs) + bus_space_tag_t bst; + bus_space_handle_t bsh; + bus_addr_t offs; +{ + u_int8_t regv; + + bus_space_write_1(bst, bsh, addr_port, offs); + CT_BUS_WEIGHT + regv = bus_space_read_1(bst, bsh, ctrl_port); + CT_BUS_WEIGHT + return regv; +} + +static __inline void +ct_cr_write_1(bst, bsh, offs, val) + bus_space_tag_t bst; + bus_space_handle_t bsh; + bus_addr_t offs; + u_int8_t val; +{ + + bus_space_write_1(bst, bsh, addr_port, offs); + CT_BUS_WEIGHT + bus_space_write_1(bst, bsh, ctrl_port, val); + CT_BUS_WEIGHT +} + +#if defined(i386) +#define SOFT_INTR_REQUIRED(slp) (softintr((slp)->sl_irq)) +#else /* !i386 */ +#define SOFT_INTR_REQUIRED(slp) +#endif /* !i386 */ + +#ifdef __FreeBSD__ +typedef unsigned long vaddr_t; + +#define delay(t) DELAY(t) +#endif + +#endif /* !_CT_MACHDEP_H_ */ diff --git a/sys/dev/ct/ctvar.h b/sys/dev/ct/ctvar.h new file mode 100644 index 000000000000..5ad3db125a10 --- /dev/null +++ b/sys/dev/ct/ctvar.h @@ -0,0 +1,127 @@ +/* $FreeBSD$ */ +/* $NecBSD: ctvar.h,v 1.4 1999/04/15 01:36:13 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998 + * Naofumi HONDA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _CTVAR_H_ +#define _CTVAR_H_ +/* + * ctvar.h + * Generic wd33c93 chip driver's definitions + */ + +/***************************************************************** + * Host adapter structure + *****************************************************************/ +struct ct_softc { + struct scsi_low_softc sc_sclow; /* generic data */ + + struct resource *port_res; + struct resource *mem_res; + struct resource *irq_res; + struct resource *drq_res; + + bus_space_tag_t sc_iot; /* core chip ctrl port tag */ + bus_space_tag_t sc_datat; /* data port tag (pio) */ + bus_space_tag_t sc_memt; /* data port tag (shm) */ + bus_dma_tag_t sc_dmat; /* data DMA tag */ + bus_dmamap_t sc_dmamapt; /* data DMAMAP tag */ + + bus_space_handle_t sc_ioh; + bus_space_handle_t sc_datah; + bus_space_handle_t sc_memh; + + void *sc_ih; + int sc_wc; /* weight counter */ + + int sc_chiprev; /* chip version */ +#define CT_WD33C93_A 0x00000 +#define CT_WD33C93_B 0x10000 +#define CT_WD33C93_C 0x20000 + + int sc_xmode; +#define CT_XMODE_PIO 1 +#define CT_XMODE_DMA 2 + + int sc_dma; /* dma transfer start */ +#define CT_DMA_PIOSTART 1 +#define CT_DMA_DMASTART 2 + + int sc_satgo; /* combination cmd start */ +#define CT_SAT_GOING 1 + + int sc_atten; /* attention */ + u_int8_t sc_creg; /* control register value */ + + int sc_chipclk; /* chipclk 0, 10, 15, 20 */ + struct ct_synch_data { + u_int cs_period; + u_int cs_syncr; + } *sc_sdp; /* synchronous data table pt */ + + /* + * Machdep stuff. + */ + void *ct_hw; /* point to bshw_softc etc ... */ + void (*ct_dma_xfer_start) __P((struct ct_softc *)); + void (*ct_pio_xfer_start) __P((struct ct_softc *)); + void (*ct_dma_xfer_stop) __P((struct ct_softc *)); + void (*ct_pio_xfer_stop) __P((struct ct_softc *)); + void (*ct_bus_reset) __P((struct ct_softc *)); + void (*ct_synch_setup) __P((struct ct_softc *, struct lun_info *)); +}; + +/***************************************************************** + * Target information + *****************************************************************/ +struct ct_targ_info { + struct targ_info cti_ti; + + u_int8_t cti_syncreg; +}; + +/***************************************************************** + * PROTO + *****************************************************************/ +#ifdef __NetBSD__ +#include +#endif +#ifdef __FreeBSD__ +#include +#endif + +int ctprobesubr __P((bus_space_tag_t, bus_space_handle_t ioh, u_int, int, u_int)); +void ctattachsubr __P((struct ct_softc *)); +int ctprint __P((void *, const char *)); +int ctintr __P((void *)); +#endif /* !_CTVAR_H_ */ diff --git a/sys/pc98/conf/GENERIC b/sys/pc98/conf/GENERIC index c8e5d0ad7797..28ed752f61fb 100644 --- a/sys/pc98/conf/GENERIC +++ b/sys/pc98/conf/GENERIC @@ -87,11 +87,10 @@ device isp # Qlogic family #device ncr # NCR/Symbios Logic device sym # NCR/Symbios Logic (newer chipsets + those of `ncr') -# WD33C93 SCSI card (55/92 like board) -options BS_TARG_SAFEMODE -device bs 1 - device aic # PC-9801-100 +options BS_TARG_SAFEMODE +device bs 1 # WD33C93 SCSI card (55/92 like board) +#device ct # host adapter using WD33C93[ABC] chip (C bus) device ncv # NCR 53C500 device nsp # Workbit Ninja SCSI-3 diff --git a/sys/pc98/conf/GENERIC.hints b/sys/pc98/conf/GENERIC.hints index 540bcc68651d..0dabb577693f 100644 --- a/sys/pc98/conf/GENERIC.hints +++ b/sys/pc98/conf/GENERIC.hints @@ -24,6 +24,12 @@ hint.wd.0.drive="0" #hint.wd.3.at="wdc0" #hint.wd.3.drive="3" +# PC-9801-100 +hint.aic.0.at="isa" +hint.aic.0.port="0x1840" +hint.aic.0.irq="5" +hint.aic.0.flags="0x10000" + # PC-9801-92 hint.bs.0.at="isa" hint.bs.0.port="0xCC0" @@ -63,11 +69,24 @@ hint.bs.0.flags="0" #hint.bs.0.drq="3" #hint.bs.0.flags="0x50000" -# PC-9801-100 -hint.aic.0.at="isa" -hint.aic.0.port="0x1840" -hint.aic.0.irq="5" -hint.aic.0.flags="0x10000" +# GENERIC +hint.ct.0.at="isa" +# SC98 +#hint.ct.0.at="isa" +#hint.ct.0.flags="0x10000" +# TEXA +#hint.ct.0.at="isa" +#hint.ct.0.flags="0x20000" +# ELECOM +#hint.ct.0.at="isa" +#hint.ct.0.flags="0x30000" +# SMIT +#hint.ct.0.at="isa" +#hint.ct.0.maddr="0xdc000" +#hint.ct.0.flags="0x40000" +# LOGITEC +#hint.ct.0.at="isa" +#hint.ct.0.flags="0x50000" hint.pckbd.0.at="isa" hint.pckbd.0.port="0x041"