📄 bshw.c
字号:
/* $NecBSD: bshw.c,v 1.1 1997/07/18 09:19:03 kmatsuda Exp $ *//* $NetBSD$ *//* * [NetBSD for NEC PC98 series] * Copyright (c) 1994, 1995, 1996 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. *//* * Copyright (c) 1994, 1995, 1996 Naofumi HONDA. All rights reserved. */#ifdef __NetBSD__#include <dev/isa/isadmareg.h>#include <i386/Cbus/dev/bs/bsif.h>#include <i386/Cbus/dev/bs/bshw.lst>#endif#ifdef __FreeBSD__#include <i386/isa/ic/i8237.h>#include <i386/isa/bs/bsif.h>#include <i386/isa/bs/bshw.lst>#include <machine/clock.h>#include <i386/i386/cons.h>#endifstatic struct bs_softc *gbsc;/************************************************** * DECLARATION **************************************************/static void bshw_force_bsmode __P((struct bs_softc *));/************************************************** * STATIC VAL **************************************************/static int irq_tbl[] = { 3, 5, 6, 9, 12, 13 };/************************************************** * SCSI CMD BRANCH **************************************************/#define RS (BSSAT | BSSMIT | BSLINK | BSREAD)#define WS (BSSAT | BSSMIT | BSLINK)#define EOK (BSERROROK)u_int8_t bshw_cmd[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 ,RS ,0 ,WS ,0 ,0 ,0 ,0 ,0 ,/*1*/0 ,0 ,EOK,0 ,0 ,0 ,0 ,0 ,0 ,0 ,EOK,0 ,0 ,0 ,0 ,0 ,/*2*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,RS ,0 ,WS ,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 ,EOK,EOK,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,/*5*/0 ,0 ,0 ,0 ,EOK,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 ,};#undef RS#undef WS#undef EOK/********************************************** * init **********************************************/static voidbshw_force_bsmode(bsc) struct bs_softc *bsc;{ if (bsc->sc_flags & BSBSMODE) return; bsc->sc_flags |= BSBSMODE; /* * If you have memory over 16M, some stupid boards always force to * use the io polling mode. Check such a case and change mode into * bus master DMA. However this depends heavily on the board's * specifications! */ if (bsc->sc_hw->dma_init && ((*bsc->sc_hw->dma_init)(bsc))) printf("%s change mode using external DMA (%x)\n", bsc->sc_dvname, (u_int)read_wd33c93(bsc, 0x37));}#define RESET_DEFAULT 2000intbshw_chip_reset(bsc) struct bs_softc *bsc;{ int ct; u_int8_t aux; bshw_lock(bsc); bshw_abort_cmd(bsc); delay(10000); bshw_get_auxstat(bsc); bshw_get_busstat(bsc); write_wd33c93(bsc, wd3s_oid, IDR_EHP | bsc->sc_cspeed | bsc->sc_hostid); write_wd33c93(bsc, wd3s_cmd, WD3S_RESET); for (ct = RESET_DEFAULT; ct > 0; ct--) { aux = bshw_get_auxstat(bsc); if (aux != 0xff && (aux & STR_INT)) { if (bshw_get_busstat(bsc) == 0) break; write_wd33c93(bsc, wd3s_cmd, WD3S_RESET); } delay(1); } if (ct == 0) { bshw_unlock(bsc); return ENXIO; } bshw_force_bsmode(bsc); write_wd33c93(bsc, wd3s_tout, BSHW_SEL_TIMEOUT); write_wd33c93(bsc, wd3s_sid, SIDR_RESEL); bsc->sc_flags |= BSDMATRANSFER; write_wd33c93(bsc, wd3s_ctrl, CR_DEFAULT); write_wd33c93(bsc, wd3s_synch, 0); bshw_get_auxstat(bsc); bsc->sc_busstat = bshw_get_busstat(bsc); bshw_unlock(bsc); return 0;}/* scsi bus hard reset */#define TWIDDLEWAIT 10000static int tw_pos;static char tw_chars[] = "|/-\\";/* this is some jokes */static voidtwiddle_wait(void){ cnputc('\b'); cnputc(tw_chars[tw_pos++]); tw_pos %= (sizeof(tw_chars) - 1); delay(TWIDDLEWAIT);}static void bshw_set_vsp __P((struct bs_softc *, u_int, u_int8_t));static voidbshw_set_vsp(bsc, chan, spva) struct bs_softc *bsc; u_int chan; u_int8_t spva;{ struct bshw *hw = bsc->sc_hw; if (hw->sregaddr == 0) return; write_wd33c93(bsc, hw->sregaddr + chan, spva); if (hw->hw_flags & BSHW_DOUBLE_DMACHAN) write_wd33c93(bsc, hw->sregaddr + chan + 8, spva);}voidbshw_bus_reset(bsc) struct bs_softc *bsc;{ struct targ_info *ti; int i, lpc; if (bsc->sc_RSTdelay == 0) bsc->sc_RSTdelay = 6 * 1000 * 1000; else { /* XXX: * second time reset will be requested by hardware failuer. */ bsc->sc_RSTdelay = 12 * 1000 * 1000; } bshw_lock(bsc); write_wd33c93(bsc, wd3s_mbank, (bsc->sc_membank | MBR_RST) & ~MBR_IEN); delay(500000); write_wd33c93(bsc, wd3s_mbank, (bsc->sc_membank) & ~MBR_IEN); bshw_unlock(bsc); for (lpc = 0; lpc < 2; lpc ++) { cnputc(' '); for (i = 0; i <= bsc->sc_RSTdelay / TWIDDLEWAIT; i++) twiddle_wait(); cnputc('\b'); (void) read_wd33c93(bsc, wd3s_auxc); delay(10000); if ((read_wd33c93(bsc, wd3s_auxc) & AUXCR_RRST) == 0) break; printf("\nreset state still continue, wait ..."); } for (i = 0; i < NTARGETS; i++) { if ((ti = bsc->sc_ti[i]) != NULL) { ti->ti_sync = 0; bshw_set_vsp(bsc, i, 0); } }}/* probe */intbshw_board_probe(bsc, drq, irq) struct bs_softc *bsc; u_int *drq; u_int *irq;{ gbsc = bsc;#ifdef SHOW_PORT bshw_print_port(bsc);#endif /* SHOW_PORT */ bsc->sc_hostid = (read_wd33c93(bsc, wd3s_auxc) & AUXCR_HIDM); if ((*irq) == IRQUNK) *irq = irq_tbl[(read_wd33c93(bsc, wd3s_auxc) >> 3) & 7]; if ((*drq) == DRQUNK) *drq = BUS_IOR(cmd_port) & 3; bsc->sc_dmachan = *drq; bsc->sc_irq = (*irq); bsc->sc_membank = read_wd33c93(bsc, wd3s_mbank); bsc->sc_membank &= ~MBR_RST; bsc->sc_membank |= MBR_IEN; bsc->sc_cspeed = (read_wd33c93(bsc, wd3s_oid) & (~IDR_IDM)); switch (BSC_CHIP_CLOCK(bsc->sc_cfgflags)) { case 0: break; case 1: bsc->sc_cspeed &= ~(IDR_FS_12_15 | IDR_FS_15_20); break; case 2: bsc->sc_cspeed &= ~(IDR_FS_12_15 | IDR_FS_15_20); bsc->sc_cspeed |= IDR_FS_12_15; break; case 3: bsc->sc_cspeed &= ~(IDR_FS_12_15 | IDR_FS_15_20); bsc->sc_cspeed |= IDR_FS_15_20; break; } /* XXX: host id fixed(7) */ bsc->sc_hostid = 7; if (bshw_chip_reset(bsc)) return ENXIO; return 0;}/* * XXX: * Assume the board clock rate must be 20Mhz (always satisfied, maybe)! * Only 10M/s 6.6M/s 5.0M/s 3.3M/s for synchronus transfer speed set. */#define ILLEGAL_SYNCH#ifdef ILLEGAL_SYNCH/* 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 u_int bshw_scsi_period[] = {0, 25, 37, 50, 62, 75, 87, 100, 125};static u_int8_t bshw_chip_pval[] = {0, 0xa0, 0xb0, 0x20, 0xd0, 0x30, 0xf0, 0x40, 0x50};#else /* !ILLEGAL_SYNCH *//* A 10 6.6 5.0 3.3 2.5 M/s *//* X 100 150 200 300 400 ns */static u_int bshw_scsi_period[] = {0, 25, 37, 50, 75, 100};static u_int8_t bshw_chip_pval[] = {0, 0xa0, 0xb0, 0x20, 0x30, 0x40};#endif /* !ILLEGAL_SYNCH */voidbshw_adj_syncdata(sdp) struct syncdata *sdp;{ int i; if (sdp->offset == 0 || sdp->period < 25 || sdp->period > 100) sdp->offset = sdp->period = 0; else { for (i = 0; sdp->period > bshw_scsi_period[i] + 2; i ++) ; sdp->period = bshw_scsi_period[i]; }}voidbshw_set_synchronous(bsc, ti) struct bs_softc *bsc; struct targ_info *ti;{ struct syncdata sd; int i; sd = ti->ti_syncnow; bshw_adj_syncdata(&sd); for (i = 0; sd.period != bshw_scsi_period[i]; i++) ; ti->ti_sync = ((sd.offset & 0x0f) | bshw_chip_pval[i]); bshw_set_vsp(bsc, ti->ti_id, ti->ti_sync); if (bsc->sc_nexus == ti) bshw_set_sync_reg(bsc, ti->ti_sync);}/* ctrl reg */voidbshw_setup_ctrl_reg(bsc, flags) struct bs_softc *bsc; u_int flags;{ u_int8_t regval; regval = (flags & BS_SCSI_NOPARITY) ? CR_DEFAULT : CR_DEFAULT_HP; if (bsc->sc_flags & BSDMATRANSFER) regval |= CR_DMA; write_wd33c93(bsc, wd3s_ctrl, regval);}/* sat command */voidbshw_issue_satcmd(bsc, cb, link) struct bs_softc *bsc; struct ccb *cb; int link;{ int i; BUS_IOW(addr_port, wd3s_cdb); for (i = 0; i < cb->cmdlen - 1; i++) BUS_IOW(ctrl_port, cb->cmd[i]); BUS_IOW(ctrl_port, cb->cmd[i] | (link ? 1 : 0));}/* lock */voidbshw_lock(bsc) struct bs_softc *bsc;{ bsc->sc_hwlock++; write_wd33c93(bsc, wd3s_mbank, bsc->sc_membank & (~MBR_IEN));}voidbshw_unlock(bsc) struct bs_softc *bsc;{ if ((--bsc->sc_hwlock) <= 0) write_wd33c93(bsc, wd3s_mbank, bsc->sc_membank);}/********************************************** * DMA OPERATIONS **********************************************/#ifdef __NetBSD__#include <i386/Cbus/dev/bs/bshw_dma.c>#include <i386/Cbus/dev/bs/bshw_pdma.c>#endif#ifdef __FreeBSD__#include <i386/isa/bs/bshw_dma.c>#include <i386/isa/bs/bshw_pdma.c>#endif/********************************************** * DEBUG **********************************************//* misc */voidbshw_print_port(bsc) struct bs_softc * bsc;{ int i, j; int port = 0x0; if (bsc == NULL) bsc = gbsc; printf("\n"); for (j = 0; j <= 0x70; j += 0x10) { printf("port %x: ", port); for (i = 0; i < 0x10; i++) printf("%x ", (u_int) read_wd33c93(bsc, port++)); printf("\n"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -