summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/bs
diff options
context:
space:
mode:
authorasami <asami@FreeBSD.org>1996-12-04 04:32:52 +0000
committerasami <asami@FreeBSD.org>1996-12-04 04:32:52 +0000
commit5fdc748d8c34e6924a223a6dd13a1d3c36104b5b (patch)
treea876bb0feb1b4c4f4191a1d367e088a314cf155a /sys/i386/isa/bs
parent4d75d96d6e8b3a6ef3d9dcc16b1e9414af327f0e (diff)
downloadFreeBSD-src-5fdc748d8c34e6924a223a6dd13a1d3c36104b5b.zip
FreeBSD-src-5fdc748d8c34e6924a223a6dd13a1d3c36104b5b.tar.gz
Replace sbic driver (WD33C93 SCSI card driver) with new bs driver.
Submitted by: The FreeBSD(98) Development Team Obtained from: NetBSD/pc98 based on NetBSD 1.2
Diffstat (limited to 'sys/i386/isa/bs')
-rw-r--r--sys/i386/isa/bs/bs.c1622
-rw-r--r--sys/i386/isa/bs/bs_isa.c60
-rw-r--r--sys/i386/isa/bs/bs_pisa.c126
-rw-r--r--sys/i386/isa/bs/bsfunc.c926
-rw-r--r--sys/i386/isa/bs/bsfunc.h229
-rw-r--r--sys/i386/isa/bs/bshw.c451
-rw-r--r--sys/i386/isa/bs/bshw.h363
-rw-r--r--sys/i386/isa/bs/bshw.lst113
-rw-r--r--sys/i386/isa/bs/bshw_dma.c339
-rw-r--r--sys/i386/isa/bs/bshw_pdma.c242
-rw-r--r--sys/i386/isa/bs/bsif.c520
-rw-r--r--sys/i386/isa/bs/bsif.h201
-rw-r--r--sys/i386/isa/bs/bsvar.h542
-rw-r--r--sys/i386/isa/bs/ccbque.h130
-rw-r--r--sys/i386/isa/bs/dvcfg.h64
15 files changed, 5928 insertions, 0 deletions
diff --git a/sys/i386/isa/bs/bs.c b/sys/i386/isa/bs/bs.c
new file mode 100644
index 0000000..022af61
--- /dev/null
+++ b/sys/i386/isa/bs/bs.c
@@ -0,0 +1,1622 @@
+/* $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/bs/bsif.h>
+#endif
+#ifdef __FreeBSD__
+#include <i386/isa/bs/bsif.h>
+#endif
+
+/*****************************************************************
+ * Inline phase funcs
+ *****************************************************************/
+/* static inline declare */
+static BS_INLINE struct targ_info *bs_reselect __P((struct bs_softc *));
+static BS_INLINE void bs_sat_continue __P((struct bs_softc *, struct targ_info *, struct ccb *));
+static BS_INLINE struct targ_info *bs_selected __P((struct bs_softc *, struct targ_info *, struct ccb *));
+static BS_INLINE u_int8_t bs_read_1byte __P((struct bs_softc *));
+static BS_INLINE void bs_write_1byte __P((struct bs_softc *, u_int8_t));
+static BS_INLINE void bs_commandout __P((struct bs_softc *, struct targ_info *, struct ccb *));
+static BS_INLINE void bs_status_check __P((struct bs_softc *, struct targ_info *));
+static BS_INLINE void bs_msgin __P((struct bs_softc *, struct targ_info *));
+static BS_INLINE void bs_msgout __P((struct bs_softc *, struct targ_info *, struct ccb *));
+static BS_INLINE void bs_disconnect_phase __P((struct bs_softc *, struct targ_info *, struct ccb *));
+static void bs_phase_error __P((struct targ_info *, struct ccb *));
+static int bs_scsi_cmd_poll_internal __P((struct targ_info *));
+static int bs_xfer __P((struct bs_softc *, char *, int));
+static void bs_io_xfer __P((struct targ_info *));
+static void bs_quick_abort __P((struct targ_info *, u_int));
+static void bs_msgin_error __P((struct targ_info *, u_int));
+static void bs_msgin_ext __P((struct targ_info *));
+static void bs_msg_reject __P((struct targ_info *));
+static void bshoststart __P((struct bs_softc *, struct targ_info *));
+
+/*****************************************************************
+ * Julian scsi interface
+ *****************************************************************/
+XSBS_INT32T
+bs_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct bs_softc *bsc = (struct bs_softc *) xs->sc_link->adapter_softc;
+ int s, target = (u_int) (xs->sc_link->target);
+ struct targ_info *ti;
+ struct ccb *cb;
+ u_int flags = xs->flags;
+
+ if (xs->bp == NULL && (bsc->sc_openf & (1 << target)) == 0)
+ {
+ s = splbio();
+ xs->error = XS_DRIVER_STUFFUP;
+ xs->flags |= XSBS_ITSDONE;
+ scsi_done(xs);
+ splx(s);
+ return COMPLETE;
+ }
+
+ ti = bsc->sc_ti[target];
+ if ((cb = bs_get_ccb(flags & XSBS_SCSI_NOSLEEP)) == NULL)
+ return TRY_AGAIN_LATER;
+
+ /* make up ccb! */
+ cb->xs = xs;
+ cb->lun = xs->sc_link->lun;
+ cb->cmd = (u_int8_t *) xs->cmd;
+ cb->cmdlen = (int) xs->cmdlen;
+ cb->data = (u_int8_t *) xs->data;
+ cb->datalen = (int) xs->datalen;
+ cb->rcnt = 0;
+ cb->msgoutlen = 0;
+ cb->flags = (flags & XSBS_SCSI_POLL) ? BSFORCEIOPOLL : 0;
+ bs_targ_flags(ti, cb);
+ cb->tcmax = (xs->timeout >> 10);
+ if (cb->tcmax < BS_DEFAULT_TIMEOUT_SECOND)
+ cb->tcmax = BS_DEFAULT_TIMEOUT_SECOND;
+
+#ifdef BS_ADDRESS_CHECK
+ /* XXX:
+ * Sanity check, however this is critical!
+ * NetBSD 1.0: WRONG
+ * NetBSD 1.1: OK
+ * FreeBSD: WRONG
+ */
+ if ((caddr_t) cb->data < (caddr_t) KERNBASE)
+ {
+ u_int8_t *altbp;
+
+ altbp = (u_int8_t *) malloc(cb->datalen, M_DEVBUF, M_NOWAIT);
+ if (altbp == NULL)
+ {
+ bs_free_ccb(cb);
+ return TRY_AGAIN_LATER;
+ }
+
+ if (flags & SCSI_DATA_OUT)
+ bcopy(cb->data, altbp, cb->datalen);
+ else
+ bzero(altbp, cb->datalen);
+
+ cb->data = (u_int8_t *) altbp;
+ cb->flags |= BSALTBUF;
+ }
+#endif /* BS_ADDRESS_CHECK */
+
+ s = splbio();
+
+ TAILQ_INSERT_TAIL(&ti->ti_ctab, cb, ccb_chain)
+
+ if (ti->ti_phase == FREE)
+ {
+ if (ti->ti_state == BS_TARG_START)
+ {
+ if ((flags & XSBS_SCSI_POLL) == 0)
+ bs_start_syncmsg(ti, NULL, BS_SYNCMSG_ASSERT);
+ }
+ bscmdstart(ti, BSCMDSTART);
+ }
+
+ if ((flags & XSBS_SCSI_POLL) == 0)
+ {
+ splx(s);
+ return SUCCESSFULLY_QUEUED;
+ }
+
+ bs_scsi_cmd_poll(ti, cb);
+ splx(s);
+
+ return COMPLETE;
+}
+
+/**************************************************
+ * ### NEXUS START and TERMINATE ###
+ **************************************************/
+/*
+ * FLAGS : BSCMDRESTART restart in case of error.
+ */
+int
+bscmdstart(ti, flags)
+ struct targ_info *ti;
+ int flags;
+{
+ struct ccb *cb;
+ struct bs_softc *bsc = ti->ti_bsc;
+
+ if ((cb = ti->ti_ctab.tqh_first) == NULL)
+ {
+ if (bsc->sc_nexus == NULL)
+ bshoststart(bsc, NULL);
+ return 0;
+ }
+
+ ti->ti_lun = cb->lun;
+ ti->ti_error = 0;
+ ti->ti_scsp.data = cb->data;
+ ti->ti_scsp.datalen = cb->datalen;
+ ti->ti_scsp.seglen = 0;
+ if (cb->rcnt)
+ cb->flags &= ~(BSSAT | BSLINK);
+ ti->ti_flags &= ~BSCFLAGSMASK;
+ ti->ti_flags |= cb->flags & BSCFLAGSMASK;
+ cb->tc = cb->tcmax;
+
+ /* GO GO */
+ if (ti->ti_phase == FREE)
+ {
+ if (bsc->sc_nexus == NULL)
+ bshoststart(bsc, ti);
+ else
+ {
+ if (flags & BSCMDRESTART)
+ bs_hostque_head(bsc, ti);
+ else
+ bs_hostque_tail(bsc, ti);
+ BS_SETUP_PHASE(HOSTQUEUE)
+ }
+ }
+ else if (bsc->sc_nexus == NULL)
+ bshoststart(bsc, NULL);
+
+ return 1;
+}
+
+struct ccb *
+bscmddone(ti)
+ struct targ_info *ti;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct ccb *cb = ti->ti_ctab.tqh_first;
+ struct scsi_xfer *xs;
+ int error;
+
+ if (ti->ti_state == BS_TARG_SYNCH)
+ {
+ if (bs_analyze_syncmsg(ti, cb))
+ return cb;
+ }
+
+ if (bsc->sc_p.datalen != 0)
+ ti->ti_error |= BSDMAABNORMAL;
+
+ cb->error = ti->ti_error;
+
+ do
+ {
+ xs = cb->xs;
+ error = XS_NOERROR;
+
+ if (cb->flags & (BSITSDONE | BSSENSECCB | BSCASTAT))
+ {
+ if (cb->flags & BSSENSECCB)
+ {
+ cb->error &= ~BSDMAABNORMAL;
+ if (cb->error == 0)
+ ti->ti_flags |= BSCASTAT;
+
+ ti->ti_flags |= BSERROROK;
+ }
+ else if (cb->flags & BSCASTAT)
+ {
+ if (ti->ti_flags & BSCASTAT)
+ {
+ ti->ti_flags &= ~BSCASTAT;
+ error = XS_SENSE;
+ if (xs)
+ xs->sense = ti->sense;
+ }
+ else
+ error = XS_DRIVER_STUFFUP;
+
+ ti->ti_flags |= BSERROROK;
+ } else
+ bs_panic(bsc, "internal error");
+ }
+
+ while (cb->error)
+ {
+ if (ti->ti_flags & BSERROROK)
+ break;
+
+ if (cb->rcnt >= bsc->sc_retry || (cb->error & BSFATALIO))
+ {
+ if (cb->error & (BSSELTIMEOUT | BSTIMEOUT))
+ error = XS_TIMEOUT;
+ else if (cb->error & BSTARGETBUSY)
+ error = XS_BUSY;
+ else
+ error = XS_DRIVER_STUFFUP;
+ break;
+ }
+
+ if (cb->error & BSREQSENSE)
+ {
+ /* must clear the target's sense state */
+ cb->rcnt++;
+ cb->flags |= (BSITSDONE | BSCASTAT);
+ cb->error &= ~BSREQSENSE;
+ return bs_request_sense(ti);
+ }
+
+ /* XXX: compat with upper driver */
+ if ((cb->error & BSDMAABNORMAL) &&
+ BSHW_CMD_CHECK(cb, BSERROROK))
+ {
+ cb->error &= ~BSDMAABNORMAL;
+ continue;
+ }
+
+ if ((xs && xs->bp) || (cb->error & BSSELTIMEOUT) == 0)
+ bs_debug_print(bsc, ti);
+
+ cb->rcnt++;
+ return cb;
+ }
+
+#ifdef BS_DIAG
+ cb->flags |= BSITSDONE;
+#endif /* BS_DIAG */
+ if (bsc->sc_poll)
+ {
+ bsc->sc_flags |= BSJOBDONE;
+ if (bsc->sc_outccb == cb)
+ bsc->sc_flags |= BSPOLLDONE;
+ }
+
+ TAILQ_REMOVE(&ti->ti_ctab, cb, ccb_chain)
+
+ if (xs)
+ {
+#ifdef BS_ADDRESS_CHECK
+ if (cb->flags & BSALTBUF)
+ {
+ if (xs->flags & SCSI_DATA_IN)
+ bcopy(cb->data, xs->data, cb->datalen);
+ free(cb->data, M_DEVBUF);
+ }
+#endif /* BS_ADDRESS_CHECK */
+
+ if ((xs->error = error) == XS_NOERROR)
+ xs->resid = 0;
+ xs->flags |= XSBS_ITSDONE;
+ scsi_done(xs);
+ }
+
+ bs_free_ccb(cb);
+ cb = ti->ti_ctab.tqh_first;
+
+ }
+ while (cb != NULL && (cb->flags & BSITSDONE) != 0);
+
+ /* complete */
+ return NULL;
+}
+
+/**************************************************
+ * ### PHASE FUNCTIONS ###
+ **************************************************/
+/**************************************************
+ * <SELECTION PHASE>
+ **************************************************/
+static void
+bshoststart(bsc, ti)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+{
+ struct ccb *cb;
+ int s;
+
+ if (bsc->sc_flags & BSINACTIVE)
+ return;
+
+again:
+ if (ti == NULL)
+ {
+ if ((ti = bsc->sc_sttab.tqh_first) == NULL)
+ return;
+ bs_hostque_delete(bsc, ti);
+ }
+
+ if ((cb = ti->ti_ctab.tqh_first) == NULL)
+ {
+ bs_printf(ti, "bshoststart", "Warning: No ccb");
+ BS_SETUP_PHASE(FREE);
+ ti = NULL;
+ goto again;
+ }
+
+#ifdef BS_DIAG
+ if (cb->flags & BSITSDONE)
+ bs_panic(bsc, "bshoststart: already done");
+
+ if (bsc->sc_nexus || (ti->ti_flags & BSNEXUS))
+ {
+ char *s = ((ti->ti_flags & BSNEXUS) ?
+ "nexus already established" : "scsi board busy");
+
+ bs_debug_print(bsc, ti);
+ bs_printf(ti, "bshoststart", s);
+ }
+#endif /* BS_DIAG */
+
+#ifdef BS_STATICS
+ bs_statics[ti->ti_id].select++;
+#endif /* BS_STATICS */
+
+ if (ti->ti_cfgflags & BS_SCSI_WAIT)
+ {
+ struct targ_info *tmpti;
+
+ for (tmpti = bsc->sc_titab.tqh_first; tmpti;
+ tmpti = tmpti->ti_tchain.tqe_next)
+ if (tmpti->ti_phase >= DISCONNECTED)
+ goto retry;
+ }
+
+ /* start selection */
+ ti->ti_status = ST_UNK;
+ if (bs_check_sat(ti))
+ {
+ if ((bshw_get_auxstat(bsc) & STR_BUSY) == 0)
+ {
+ BS_LOAD_SDP
+ bshw_set_dst_id(bsc, ti->ti_id, ti->ti_lun);
+ bshw_setup_ctrl_reg(bsc, ti->ti_cfgflags);
+ bshw_cmd_pass(bsc, 0);
+ bshw_set_sync_reg(bsc, ti->ti_sync);
+ bshw_issue_satcmd(bsc, cb, bs_check_link(ti, cb));
+ if (bs_check_smit(ti) || bsc->sc_p.datalen <= 0)
+ bshw_set_count(bsc, 0);
+ else
+ bs_dma_xfer(ti, BSHW_CMD_CHECK(cb, BSREAD));
+
+ s = splhigh();
+ if ((bshw_get_auxstat(bsc) & STR_BUSY) == 0)
+ {
+ /* XXX:
+ * Reload a lun again here.
+ */
+ bshw_set_lun(bsc, ti->ti_lun);
+ bshw_start_sat(bsc, bs_check_disc(ti));
+ if ((bshw_get_auxstat(bsc) & STR_LCI) == 0)
+ {
+ splx(s);
+ BS_HOST_START
+ BS_SELECTION_START
+ BS_SETUP_PHASE(SATSEL);
+ ti->ti_omsgoutlen = 0;
+ ti->ti_msgout = bs_identify_msg(ti);
+#ifdef BS_DIAG
+ ti->ti_flags |= BSNEXUS;
+#endif /* BS_DIAG */
+#ifdef BS_STATICS
+ bs_statics[ti->ti_id].select_win++;
+#endif /* BS_STATICS */
+ return;
+ }
+ }
+ splx(s);
+
+ if (bs_check_smit(ti) == 0)
+ bshw_dmaabort(bsc, ti);
+#ifdef BS_STATICS
+ bs_statics[ti->ti_id].select_miss_in_assert++;
+#endif /* BS_STATICS */
+ }
+ }
+ else
+ {
+ s = splhigh();
+ if ((bshw_get_auxstat(bsc) & STR_BUSY) == 0)
+ {
+ bshw_set_dst_id(bsc, ti->ti_id, ti->ti_lun);
+ bshw_setup_ctrl_reg(bsc, ti->ti_cfgflags);
+ bshw_set_sync_reg(bsc, ti->ti_sync);
+ bshw_assert_select(bsc);
+
+ if ((bshw_get_auxstat(bsc) & STR_LCI) == 0)
+ {
+ splx(s);
+ BS_HOST_START
+ BS_SELECTION_START
+ BS_SETUP_PHASE(SELECTASSERT);
+#ifdef BS_STATICS
+ bs_statics[ti->ti_id].select_win++;
+#endif /* BS_STATICS */
+ return;
+ }
+#ifdef BS_STATICS
+ bs_statics[ti->ti_id].select_miss_in_assert++;
+#endif /* BS_STATICS */
+ }
+ splx(s);
+ }
+
+ /* RETRY LATER */
+retry:
+#ifdef BS_STATICS
+ bs_statics[ti->ti_id].select_miss++;
+#endif /* BS_STATICS */
+ bs_hostque_head(bsc, ti);
+ BS_SETUP_PHASE(HOSTQUEUE)
+}
+
+static BS_INLINE struct targ_info *
+bs_selected(bsc, ti, cb)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+
+ if (bsc->sc_busstat != BSR_SELECTED)
+ {
+ bs_phase_error(ti, cb);
+ return NULL;
+ }
+
+#ifdef BS_DIAG
+ if (bsc->sc_selwait != ti)
+ panic("%s selection internal error\n", bsc->sc_dvname);
+
+ ti->ti_flags |= BSNEXUS;
+#endif /* BS_DIAG */
+
+ /* clear select wait state */
+ BS_SETUP_PHASE(SELECTED);
+ BS_SELECTION_TERMINATE;
+ BS_LOAD_SDP
+ return ti;
+}
+
+/**************************************************
+ * <RESELECTION>
+ **************************************************/
+static BS_INLINE struct targ_info *
+bs_reselect(bsc)
+ struct bs_softc *bsc;
+{
+ u_int target;
+ struct targ_info *ti;
+
+ /* check collision */
+ if ((ti = bsc->sc_selwait) != NULL)
+ {
+ if (ti->ti_phase == SATSEL)
+ {
+#ifdef BS_DIAG
+ ti->ti_flags &= ~BSNEXUS;
+#endif /* BS_DIAG */
+ ti->ti_msgout = 0;
+ if (bs_check_smit(ti) == 0)
+ bshw_dmaabort(bsc, ti);
+ }
+ bs_hostque_head(bsc, ti);
+ BS_SELECTION_TERMINATE
+ BS_SETUP_PHASE(HOSTQUEUE)
+#ifdef BS_STATICS
+ bs_statics[ti->ti_id].select_miss_by_reselect++;
+ bs_statics[ti->ti_id].select_miss++;
+#endif /* BS_STATICS */
+ }
+
+ /* who are you ? */
+ target = bshw_get_src_id(bsc);
+ if ((ti = bsc->sc_ti[target]) == NULL)
+ {
+ bs_debug_print_all(bsc);
+ printf("reselect: miss reselect. target(%d)\n", target);
+ bs_reset_nexus(bsc);
+ return NULL;
+ }
+
+ /* confirm nexus */
+ BS_HOST_START
+ bshw_setup_ctrl_reg(bsc, ti->ti_cfgflags);
+ if (ti->ti_ctab.tqh_first == NULL || ti->ti_phase != DISCONNECTED)
+ {
+ bs_printf(ti, "reselect", "phase mismatch");
+ BS_SETUP_PHASE(UNDEF)
+ bs_force_abort(ti);
+ bs_hostque_delete(bsc, ti);
+ }
+ else
+ bsc->sc_dtgnum --;
+
+ /* recover host */
+ bshw_set_dst_id(bsc, ti->ti_id, ti->ti_lun);
+ bshw_set_sync_reg(bsc, ti->ti_sync);
+ BS_RESTORE_SDP
+ BS_SETUP_PHASE(RESELECTED)
+#ifdef BS_STATICS
+ bs_statics[ti->ti_id].reselect++;
+#endif /* BS_STATICS */
+ return ti;
+}
+
+static BS_INLINE void
+bs_sat_continue(bsc, ti, cb)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+
+ BS_SETUP_PHASE(SATRESEL);
+ bshw_set_dst_id(bsc, ti->ti_id, ti->ti_lun);
+ bshw_cmd_pass(bsc, 0x44);
+ bshw_set_sync_reg(bsc, ti->ti_sync);
+ bshw_issue_satcmd(bsc, cb, 0);
+ if (bs_check_smit(ti) || bsc->sc_p.datalen <= 0)
+ bshw_set_count(bsc, 0);
+ else
+ bs_dma_xfer(ti, BSHW_CMD_CHECK(cb, BSREAD));
+ bshw_set_lun(bsc, ti->ti_lun); /* XXX */
+ bshw_start_sat(bsc, 0);
+}
+
+/*************************************************
+ * <DATA PHASE>
+ *************************************************/
+#define DR (STR_BSY | STR_DBR)
+
+void
+bs_poll_timeout(bsc, s)
+ struct bs_softc *bsc;
+ char *s;
+{
+ struct targ_info *ti;
+
+ bs_printf(NULL, s, "timeout");
+ bsc->sc_flags |= BSRESET;
+ if ((ti = bsc->sc_nexus) && ti->ti_ctab.tqh_first)
+ ti->ti_error |= BSTIMEOUT;
+}
+
+static BS_INLINE u_int8_t
+bs_read_1byte(bsc)
+ struct bs_softc *bsc;
+{
+ register u_int wc;
+
+ bshw_start_sxfer(bsc);
+ for (wc = bsc->sc_wc; (bshw_get_auxstat(bsc) & DR) != DR && --wc; );
+ if (wc)
+ return bshw_read_data(bsc);
+ else
+ bs_poll_timeout(bsc, "read_1byte");
+
+ return 0;
+}
+
+static BS_INLINE void
+bs_write_1byte(bsc, data)
+ struct bs_softc *bsc;
+ u_int8_t data;
+{
+ register u_int wc;
+
+ bshw_start_sxfer(bsc);
+ for (wc = bsc->sc_wc; (bshw_get_auxstat(bsc) & DR) != DR && --wc; );
+ if (wc)
+ bshw_write_data(bsc, data);
+ else
+ bs_poll_timeout(bsc, "write_1byte");
+}
+
+static int
+bs_xfer(bsc, data, len)
+ struct bs_softc *bsc;
+ char *data;
+ int len;
+{
+ u_int8_t aux;
+ u_int count, wc;
+
+ bshw_set_count(bsc, len);
+ bshw_start_xfer(bsc);
+
+ for (count = 0, wc = bsc->sc_wc; count < len && --wc; )
+ {
+ if (((aux = bshw_get_auxstat(bsc)) & DR) == DR)
+ {
+ if (bsc->sc_busstat & BSHW_READ)
+ *(data++) = bshw_read_data(bsc);
+ else
+ bshw_write_data(bsc, *(data++));
+ count++;
+ wc = bsc->sc_wc;
+ }
+
+ if (aux & STR_INT)
+ break;
+ }
+
+ if (wc == 0)
+ bs_poll_timeout(bsc, "bs_xfer");
+
+ return count;
+}
+#undef DR
+
+static void
+bs_io_xfer(ti)
+ struct targ_info *ti;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct sc_p *sp = &bsc->sc_p;
+ u_int count, dummy;
+
+ /* switch dma trasnfr mode */
+ bshw_set_poll_trans(bsc, ti->ti_cfgflags);
+ sp->seglen = 0;
+ sp->bufp = NULL;
+
+ if (sp->datalen <= 0)
+ {
+ ti->ti_error |= BSDMAABNORMAL;
+ dummy = 0;
+ count = bs_xfer(bsc, (u_int8_t *) &dummy, 1);
+ }
+ else
+ count = bs_xfer(bsc, sp->data, sp->datalen);
+
+ sp->data += count;
+ sp->datalen -= count;
+}
+
+/************************************************
+ * <COMMAND PHASE>
+ ************************************************/
+static BS_INLINE void
+bs_commandout(bsc, ti, cb)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+ u_int8_t scsi_cmd[16];
+ int len;
+
+ BS_SETUP_PHASE(CMDPHASE);
+
+ if (bs_check_link(ti, cb))
+ {
+ bcopy(cb->cmd, scsi_cmd, cb->cmdlen);
+ scsi_cmd[cb->cmdlen - 1] |= 0x01;
+ len = bs_xfer(bsc, scsi_cmd, cb->cmdlen);
+ }
+ else
+ len = bs_xfer(bsc, cb->cmd, cb->cmdlen);
+
+ if (len != cb->cmdlen)
+ ti->ti_error |= BSCMDABNORMAL;
+}
+
+/************************************************
+ * <STATUS IN>
+ ************************************************/
+static BS_INLINE void
+bs_status_check(bsc, ti)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+{
+
+ if (ti->ti_status == ST_GOOD || ti->ti_status == ST_INTERGOOD)
+ return;
+
+ switch (ti->ti_status)
+ {
+ case ST_MET:
+ case ST_INTERMET:
+ case ST_CHKCOND:
+ ti->ti_error |= BSREQSENSE;
+ break;
+
+ case ST_BUSY:
+ ti->ti_error |= BSTARGETBUSY;
+ break;
+
+ default:
+ ti->ti_error |= BSSTATUSERROR;
+ break;
+ }
+}
+
+/************************************************
+ * <MSG IN>
+ ************************************************/
+#define MSGWAIT(cnt) { if (ti->ti_msginptr < (cnt)) return; }
+
+static void
+bs_quick_abort(ti, msg)
+ struct targ_info *ti;
+ u_int msg;
+{
+ struct ccb *cb;
+
+ if ((cb = ti->ti_ctab.tqh_first) == NULL)
+ return;
+
+ cb->msgoutlen = 1;
+ cb->msgout[0] = msg;
+ cb->rcnt++;
+
+ ti->ti_error |= BSMSGERROR;
+}
+
+static void
+bs_msgin_error(ti, count)
+ struct targ_info *ti;
+ u_int count;
+{
+ int n;
+
+ MSGWAIT(count);
+
+ bs_printf(ti, "msgin", "illegal msg");
+
+ for (n = 0; n < ti->ti_msginptr; n ++)
+ printf("[0x%x] ", (u_int) ti->ti_msgin[n]);
+ printf("\n");
+
+ bs_quick_abort(ti, MSG_REJECT);
+ ti->ti_msginptr = 0;
+}
+
+static void
+bs_msgin_ext(ti)
+ struct targ_info *ti;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct ccb *cb = ti->ti_ctab.tqh_first;
+ int count;
+ u_int reqlen;
+ u_int32_t *ptr;
+ struct msgbase msg;
+
+ MSGWAIT(2);
+
+ reqlen = ti->ti_msgin[1];
+ if (reqlen == 0)
+ reqlen = 256;
+
+ if (ti->ti_msginptr >= MAXMSGLEN)
+ ti->ti_msginptr = 3; /* XXX */
+
+ MSGWAIT(reqlen + 2);
+
+ switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2]))
+ {
+ case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE):
+ ptr = (u_int32_t *)(&ti->ti_msgin[3]);
+ count = (int) htonl((long) (*ptr));
+
+ bsc->sc_p.seglen = ti->ti_scsp.seglen = 0;
+ if (bsc->sc_p.datalen - count >= 0 &&
+ bsc->sc_p.datalen - count <= cb->datalen)
+ {
+ bsc->sc_p.datalen -= count;
+ bsc->sc_p.data += count;
+ }
+ else
+ bs_msgin_error(ti, 7);
+ break;
+
+ case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE):
+ ti->ti_syncnow.period = ti->ti_msgin[3];
+ ti->ti_syncnow.offset = ti->ti_msgin[4];
+ if (ti->ti_syncnow.offset == 0)
+ ti->ti_syncnow.period = 0;
+
+ if (ti->ti_syncnow.state != BS_SYNCMSG_ASSERT)
+ {
+ bs_start_syncmsg(ti, NULL, BS_SYNCMSG_REQUESTED);
+ bscmdstart(ti, BSCMDSTART);
+ }
+ else
+ BS_SETUP_SYNCSTATE(BS_SYNCMSG_ACCEPT)
+ break;
+
+ case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE):
+ msg.msglen = MSG_EXTEND_WIDELEN + 2;
+ msg.msg[0] = MSG_EXTEND;
+ msg.msg[1] = MSG_EXTEND_WIDELEN;
+ msg.msg[2] = MSG_EXTEND_WIDECODE;
+ msg.msg[3] = 0;
+ msg.flag = 0;
+ bs_make_msg_ccb(ti, cb->lun, cb, &msg, 0);
+ break;
+
+ default:
+ bs_msgin_error(ti, 0);
+ return;
+ }
+
+ ti->ti_msginptr = 0;
+ return;
+}
+
+static void
+bs_msg_reject(ti)
+ struct targ_info *ti;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct ccb *cb = ti->ti_ctab.tqh_first;
+ char *s = "unexpected msg reject";
+
+ switch (ti->ti_ophase)
+ {
+ case CMDPHASE:
+ s = "cmd rejected";
+ cb->flags &= ~BSLINK;
+ BS_SETUP_MSGPHASE(IOCOMPLETED);
+ break;
+
+ case MSGOUT:
+ if (ti->ti_msgout & 0x80)
+ {
+ s = "identify msg rejected";
+ cb->flags &= ~BSDISC;
+ BS_SETUP_MSGPHASE(IOCOMPLETED);
+ }
+ else if (ti->ti_msgout == MSG_EXTEND)
+ {
+ switch (ti->ti_emsgout)
+ {
+ case MSG_EXTEND_SYNCHCODE:
+ BS_SETUP_SYNCSTATE(BS_SYNCMSG_REJECT);
+ return;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ bs_debug_print(bsc, ti);
+ bs_printf(ti, "msgin", s);
+ ti->ti_error |= BSMSGERROR;
+}
+
+static BS_INLINE void
+bs_msgin(bsc, ti)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+{
+
+ BS_SETUP_PHASE(MSGIN);
+
+ switch (ti->ti_msgin[0])
+ {
+ case MSG_SAVESP:
+ BS_SAVE_SDP
+ break;
+
+ case MSG_RESTORESP:
+ BS_RESTORE_SDP
+ bs_printf(ti, "msgin", "restore scsi pointer");
+ break;
+
+ case MSG_REJECT:
+ bs_msg_reject(ti);
+ break;
+
+ case 0xf:
+ break;
+
+ case MSG_I_ERROR:/* all I -> T : nothing to do*/
+ case MSG_ABORT:
+ case MSG_PARITY:
+ case MSG_RESET:
+ case 0xe:
+ bs_msgin_error(ti, 1);
+ goto resume;
+
+ case MSG_NOOP:
+ break;
+
+ case MSG_EXTEND:
+ bs_msgin_ext(ti);
+ goto resume;
+
+ case 0xd:
+ bs_msgin_error(ti, 2);
+ goto resume;
+
+ case MSG_DISCON:
+ BS_SETUP_MSGPHASE(DISCONNECTASSERT);
+ break;
+
+ case MSG_COMP:
+ BS_SETUP_MSGPHASE(IOCOMPLETED);
+ break;
+
+ case MSG_LCOMP:
+ case MSG_LCOMP_F:
+ bs_status_check(bsc, ti);
+ if (bscmddone(ti) == NULL)
+ {
+ if (bscmdstart(ti, BSCMDSTART) == 0)
+ {
+ bs_printf(ti, "msgin", "cmd line miss");
+ bs_force_abort(ti);
+ }
+ }
+ else
+ bscmdstart(ti, BSCMDRESTART);
+#ifdef BS_STATICS
+ bs_linkcmd_count[ti->ti_id]++;
+#endif /* BS_STATICS */
+ BS_LOAD_SDP
+ ti->ti_status = ST_UNK;
+ break;
+
+ default:
+ if (ti->ti_msgin[0] & 0x80)
+ {
+ if ((ti->ti_msgin[0] & 0x07) != ti->ti_lun)
+ {
+ ti->ti_lun = (ti->ti_msgin[0] & 0x07);
+ bshw_set_dst_id(bsc, ti->ti_id, ti->ti_lun);
+ bshw_set_sync_reg(bsc, ti->ti_sync);
+
+ bs_printf(ti, "msgin", "lun error");
+ bs_quick_abort(ti, MSG_ABORT);
+ }
+ break;
+ }
+ else if (ti->ti_msgin[0] < 0x20)
+ bs_msgin_error(ti, 1);
+ else if (ti->ti_msgin[0] < 0x30)
+ bs_msgin_error(ti, 2);
+ else
+ bs_msgin_error(ti, 1);
+ goto resume;
+ }
+
+ ti->ti_msginptr = 0;
+
+resume:
+ return;
+}
+
+/************************************************
+ * <MSG OUT>
+ ************************************************/
+static BS_INLINE void
+bs_msgout(bsc, ti, cb)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+ u_int8_t msg[MAXMSGLEN + 1];
+
+ if (ti->ti_phase == MSGOUT)
+ {
+ if (cb->rcnt ++ < bsc->sc_retry)
+ cb->msgoutlen = ti->ti_omsgoutlen;
+ }
+ else
+ BS_SETUP_PHASE(MSGOUT);
+
+ if (ti->ti_ophase == SELECTED)
+ {
+identify:
+ if (cb->msgoutlen == 0)
+ {
+ ti->ti_msgout = bs_identify_msg(ti);
+ ti->ti_omsgoutlen = 0;
+ bs_write_1byte(bsc, ti->ti_msgout);
+ }
+ else
+ {
+ if (cb->msgout[0] != MSG_RESET &&
+ cb->msgout[0] != MSG_ABORT)
+ {
+ msg[0] = bs_identify_msg(ti);
+ bcopy(cb->msgout, &msg[1], cb->msgoutlen);
+ bs_xfer(bsc, msg, cb->msgoutlen + 1);
+ }
+ else
+ bs_xfer(bsc, cb->msgout, cb->msgoutlen);
+
+ ti->ti_msgout = cb->msgout[0];
+ ti->ti_emsgout = cb->msgout[2];
+ ti->ti_omsgoutlen = cb->msgoutlen;
+ cb->msgoutlen = 0;
+ }
+ return;
+ }
+
+ if (ti->ti_ophase == SATSEL)
+ {
+ /* XXX:
+ * Maybe identify msg rejected due to
+ * a parity error in target side.
+ */
+
+ bs_printf(ti, "msgout", "msg identify retry (SAT)");
+ goto identify;
+ }
+
+ if (cb->msgoutlen == 0)
+ {
+ ti->ti_msgout = MSG_REJECT;
+ ti->ti_omsgoutlen = 0;
+ bs_write_1byte(bsc, ti->ti_msgout);
+ }
+ else
+ {
+ ti->ti_msgout = cb->msgout[0];
+ ti->ti_emsgout = cb->msgout[2];
+ ti->ti_omsgoutlen = cb->msgoutlen;
+ bs_xfer(bsc, cb->msgout, cb->msgoutlen);
+ cb->msgoutlen = 0;
+ }
+}
+
+/************************************************
+ * <DISCONNECT>
+ ************************************************/
+static BS_INLINE void
+bs_disconnect_phase(bsc, ti, cb)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+
+ switch (bsc->sc_msgphase)
+ {
+ default:
+ panic("%s unknown msg phase\n", bsc->sc_dvname);
+ break;
+
+ case DISCONNECTASSERT:
+ case FREE:
+#ifdef BS_STATICS
+ bs_statics[ti->ti_id].disconnected++;
+#endif /* BS_STATICS */
+ if (ti->ti_cfgflags & BS_SCSI_SAVESP)
+ BS_SAVE_SDP;
+ BS_HOST_TERMINATE;
+ BS_SETUP_PHASE(DISCONNECTED);
+ bsc->sc_dtgnum ++;
+ bshoststart(bsc, NULL);
+ break;
+
+ case IOCOMPLETED:
+ bs_status_check(bsc, ti);
+ cb = bscmddone(ti);
+#ifdef BS_DIAG
+ ti->ti_flags &= ~BSNEXUS;
+#endif /* BS_DIAG */
+ BS_SETUP_PHASE(FREE);
+ if (cb || bsc->sc_sttab.tqh_first == NULL)
+ {
+ BS_HOST_TERMINATE;
+ bscmdstart(ti, BSCMDSTART);
+ }
+ else
+ {
+ /* give a chance to other target */
+ bscmdstart(ti, BSCMDSTART);
+ BS_HOST_TERMINATE;
+ bshoststart(bsc, NULL);
+ }
+ break;
+ }
+
+ BS_SETUP_MSGPHASE(FREE);
+}
+
+/**************************************************
+ * <PHASE ERROR>
+ **************************************************/
+#define scsi_status (bsc->sc_busstat)
+
+struct bs_err {
+ u_char *pe_msg;
+ u_int pe_err;
+ u_int pe_ph;
+};
+
+struct bs_err bs_cmderr[] = {
+/*0*/ { "illegal cmd", BSABNORMAL, UNDEF },
+/*1*/ { "unexpected bus free", BSABNORMAL, FREE },
+/*2*/ { NULL, BSSELTIMEOUT, FREE},
+/*3*/ { "scsi bus parity error", BSPARITY, UNDEF },
+/*4*/ { "scsi bus parity error", BSPARITY, UNDEF },
+/*5*/ { "unknown" , BSFATALIO, UNDEF },
+/*6*/ { "miss reselection (target mode)", BSFATALIO, UNDEF },
+/*7*/ { "wrong status byte", BSPARITY, STATUSIN },
+};
+
+static void
+bs_phase_error(ti, cb)
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct bs_err *pep;
+ char *s = NULL;
+
+ if ((scsi_status & BSR_CM) == BSR_CMDERR &&
+ (scsi_status & BSR_PHVALID) == 0)
+ {
+ pep = &bs_cmderr[scsi_status & BSR_PM];
+ ti->ti_error |= pep->pe_err;
+ if (pep->pe_msg)
+ {
+ bs_debug_print(bsc, ti);
+ bs_printf(ti, "bsintr", pep->pe_msg);
+ }
+ BS_SETUP_PHASE(pep->pe_ph);
+ }
+ else
+ {
+ ti->ti_error |= BSABNORMAL;
+ bs_debug_print(bsc, ti);
+ bs_printf(ti, "bsintr", "phase error");
+ BS_SETUP_PHASE(UNDEF);
+ }
+
+ BS_SETUP_MSGPHASE(FREE);
+ switch (ti->ti_phase)
+ {
+ case FREE:
+ BS_SETUP_PHASE(UNDEF);
+ cb = bscmddone(ti);
+#ifdef BS_DIAG
+ ti->ti_flags &= ~BSNEXUS;
+#endif /* BS_DIAG */
+ BS_HOST_TERMINATE;
+ BS_SETUP_PHASE(FREE);
+ bscmdstart(ti, ((cb == NULL) ? BSCMDSTART : BSCMDRESTART));
+ break;
+
+ case STATUSIN:
+ ti->ti_error |= BSSTATUSERROR;
+ ti->ti_status = bshw_get_status_insat(bsc); /* XXX SAT */
+ bs_debug_print(bsc, ti);
+ break;
+
+ case UNDEF:
+ default:
+ ti->ti_error |= BSABNORMAL;
+ bs_reset_nexus(bsc);
+ break;
+ }
+}
+
+/**************************************************
+ * ### SCSI PHASE SEQUENCER ###
+ **************************************************/
+static inline void bs_ack_wait __P((struct bs_softc *, struct targ_info *, struct ccb *));
+
+static inline void
+bs_ack_wait(bsc, ti, cb)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+ int wc = bsc->sc_wc;
+
+ for (wc = bsc->sc_wc; bshw_get_busstat(bsc) != BSR_ACKREQ && wc > 0; )
+ wc --;
+
+ if (wc <= 0)
+ {
+ bs_printf(ti, "bs_ack_wait", "timeout I");
+ return;
+ }
+
+ bshw_get_auxstat(bsc);
+ scsi_status = bshw_get_busstat(bsc);
+
+ if (cb->msgoutlen > 0)
+ {
+ bshw_assert_atn(bsc);
+ delay(800);
+ BS_SETUP_PHASE(ATTENTIONASSERT);
+ }
+
+ bshw_negate_ack(bsc);
+
+#ifdef WAITNEXTP
+ for (wc = bsc->sc_wc; bshw_get_busstat(bsc) == BSR_ACKREQ && wc > 0; )
+ wc --;
+
+ if (wc <= 0)
+ bs_printf(ti, "bs_ack_wait", "timeout II");
+#endif /* WAITNEXTP */
+}
+
+int
+bs_sequencer(bsc)
+ struct bs_softc *bsc;
+{
+ register struct targ_info *ti;
+ struct ccb *cb;
+
+ /**************************************************
+ * Check reset
+ **************************************************/
+ if (bsc->sc_flags & (BSRESET | BSINACTIVE))
+ {
+ if (bsc->sc_flags & BSRESET)
+ bs_reset_nexus(bsc);
+ return 1;
+ }
+
+ /**************************************************
+ * Get status & bus phase
+ **************************************************/
+ if ((bshw_get_auxstat(bsc) & STR_INT) == 0)
+ return 0;
+
+ scsi_status = bshw_get_busstat(bsc);
+ if (scsi_status == ((u_int8_t) -1))
+ {
+ bs_debug_print_all(bsc);
+ printf("%s strange scsi bus status\n");
+ return 1;
+ }
+ /**************************************************
+ * Check reselection, or nexus
+ **************************************************/
+ if (scsi_status == BSR_RESEL)
+ {
+ bs_reselect(bsc);
+ return 1;
+ }
+
+ ti = bsc->sc_nexus;
+ if (ti == NULL || (cb = ti->ti_ctab.tqh_first) == NULL)
+ {
+ bs_debug_print_all(bsc);
+ bs_printf(ti, "bsintr", "no nexus");
+ bs_reset_nexus(bsc);
+ return 1;
+ }
+
+ /**************************************************
+ * Debug section
+ **************************************************/
+#ifdef BS_DEBUG
+ if (bs_debug_flag)
+ {
+ bs_debug_print(bsc, ti);
+ if (bs_debug_flag > 1)
+ Debugger();
+ }
+#endif /* BS_DEBUG */
+
+ /**************************************************
+ * internal scsi phase
+ **************************************************/
+ switch (ti->ti_phase)
+ {
+ case SELECTASSERT:
+ bs_selected(bsc, ti, cb);
+ return 1;
+
+ case SATSEL:
+ BS_SELECTION_TERMINATE;
+
+ case SATRESEL:
+ if (bsc->sc_flags & (BSDMASTART | BSSMITSTART))
+ {
+ if (bsc->sc_flags & BSSMITSTART)
+ {
+ bs_debug_print_all(bsc);
+ bs_reset_nexus(bsc);
+ bs_printf(ti, "bsintr", "smit transfer");
+ return 1;
+ }
+
+ BS_SETUP_PHASE(DATAPHASE); /* XXX */
+ bs_dma_xfer_end(ti);
+ ti->ti_phase = ti->ti_ophase; /* XXX */
+ }
+ break;
+
+ default:
+ /* XXX:
+ * check check check for safty !!
+ */
+ if (bsc->sc_selwait)
+ {
+ /* Ghaaa! phase error! retry! */
+ bs_phase_error(ti, cb);
+ return 1;
+ }
+
+ if (bsc->sc_flags & (BSDMASTART | BSSMITSTART))
+ {
+ if (bsc->sc_flags & BSDMASTART)
+ bs_dma_xfer_end(ti);
+ else
+ bs_smit_xfer_end(ti);
+ }
+ break;
+ }
+
+ /**************************************************
+ * hw scsi phase
+ **************************************************/
+ if (scsi_status & BSR_PHVALID)
+ {
+ /**************************************************
+ * Normal SCSI phase.
+ **************************************************/
+ if ((scsi_status & BSR_CM) == BSR_CMDABT)
+ {
+ bs_phase_error(ti, cb);
+ return 1;
+ }
+
+ switch (scsi_status & BSR_PM)
+ {
+ case BSR_DATAOUT:
+ case BSR_DATAIN:
+ BS_SETUP_PHASE(DATAPHASE);
+
+ if (bsc->sc_p.datalen <= 0 ||
+ (ti->ti_flags & BSFORCEIOPOLL))
+ {
+ bs_io_xfer(ti);
+ return 1;
+ }
+
+ if (bs_check_smit(ti) &&
+ (bsc->sc_p.datalen % sizeof(u_int32_t)) == 0)
+ {
+ bs_lc_smit_xfer(ti, scsi_status & BSR_IOR);
+ return 1;
+ }
+
+ bs_dma_xfer(ti, scsi_status & BSR_IOR);
+ bshw_start_xfer(bsc);
+ return 1;
+
+ case BSR_CMDOUT:
+ bs_commandout(bsc, ti, cb);
+ return 1;
+
+ case BSR_STATIN:
+ if (bs_check_sat(ti))
+ {
+ BS_SETUP_PHASE(SATCOMPSEQ);
+ bshw_set_count(bsc, 0);
+ bshw_cmd_pass(bsc, 0x41);
+ bshw_start_sat(bsc, 0);
+ }
+ else
+ {
+ BS_SETUP_PHASE(STATUSIN);
+ ti->ti_status = bs_read_1byte(bsc);
+ }
+ return 1;
+
+ case BSR_UNSPINFO0:
+ case BSR_UNSPINFO1:
+ bs_debug_print(bsc, ti);
+ bs_printf(ti, "bsintr", "illegal bus phase");
+ return 1;
+
+ case BSR_MSGOUT:
+ bs_msgout(bsc, ti, cb);
+ return 1;
+
+ case BSR_MSGIN:/* msg in */
+ if (bs_check_sat(ti))
+ {
+ if (ti->ti_phase == RESELECTED)
+ {
+ bs_sat_continue(bsc, ti, cb);
+ return 1;
+ }
+ /* XXX */
+ if (ti->ti_status == ST_UNK)
+ ti->ti_status = bshw_get_status_insat(bsc);
+ }
+
+ ti->ti_msgin[ti->ti_msginptr ++] = bs_read_1byte(bsc);
+ bs_msgin(bsc, ti);
+ if (bsc->sc_cfgflags & BSC_FASTACK)
+ bs_ack_wait(bsc, ti, cb);
+
+ return 1;
+ }
+ }
+ else
+ {
+ /**************************************************
+ * Special SCSI phase
+ **************************************************/
+ switch (scsi_status)
+ {
+ case BSR_SATSDP:/* SAT with save data pointer */
+ BS_SAVE_SDP
+ bshw_cmd_pass(bsc, 0x41);
+ bshw_start_sat(bsc, 0);
+ BS_SETUP_PHASE(SATSDP)
+ return 1;
+
+ case BSR_SATFIN:/* SAT COMPLETE */
+ ti->ti_status = bshw_get_status_insat(bsc);
+ BS_SETUP_MSGPHASE(IOCOMPLETED);
+ bs_disconnect_phase(bsc, ti, cb);
+ return 1;
+
+ case BSR_ACKREQ:/* negate ACK */
+ if (cb->msgoutlen > 0)
+ {
+ bshw_assert_atn(bsc);
+ delay(800);
+ BS_SETUP_PHASE(ATTENTIONASSERT);
+ }
+ bshw_negate_ack(bsc);
+ return 1;
+
+ case BSR_DISC:/* disconnect */
+ bs_disconnect_phase(bsc, ti, cb);
+ return 1;
+
+ default:
+ break;
+ }
+ }
+
+ bs_phase_error(ti, cb);
+ return 1;
+}
+
+/*****************************************************************
+ * INTERNAL POLLING FUNCTIONS
+ *****************************************************************/
+static int
+bs_scsi_cmd_poll_internal(cti)
+ struct targ_info *cti;
+{
+ struct bs_softc *bsc = cti->ti_bsc;
+ struct targ_info *ti;
+ struct ccb *cb;
+ int i, waits, delay_count;
+
+ bsc->sc_poll++;
+
+ /* setup timeout count */
+ if ((ti = bsc->sc_nexus) == NULL ||
+ (cb = ti->ti_ctab.tqh_first) == NULL)
+ waits = BS_DEFAULT_TIMEOUT_SECOND * 1000000;
+ else
+ waits = cb->tcmax * 1000000;
+
+ /* force all current jobs into the polling state. */
+ for (i = 0; i < NTARGETS; i++)
+ {
+ if (ti = bsc->sc_ti[i])
+ {
+ ti->ti_flags |= BSFORCEIOPOLL;
+ if (cb = ti->ti_ctab.tqh_first)
+ cb->flags |= BSFORCEIOPOLL;
+ }
+ }
+
+ /* do io */
+ bsc->sc_flags &= ~BSJOBDONE;
+ do
+ {
+ delay_count = ((bsc->sc_flags & BSDMASTART) ? 1000000 : 100);
+ delay(delay_count);
+ waits -= delay_count;
+ bs_sequencer(bsc);
+ }
+ while (waits >= 0 && (bsc->sc_flags & (BSUNDERRESET | BSJOBDONE)) == 0);
+
+ /* done */
+ bsc->sc_poll--;
+ if (waits < 0 || (bsc->sc_flags & BSUNDERRESET))
+ {
+ bs_printf(NULL, "cmd_poll", "timeout or fatal");
+ return HASERROR;
+ }
+
+ return COMPLETE;
+}
+
+int
+bs_scsi_cmd_poll(cti, targetcb)
+ struct targ_info *cti;
+ struct ccb *targetcb;
+{
+ struct bs_softc *bsc = cti->ti_bsc;
+ struct targ_info *ti;
+ int s, error = COMPLETE;
+
+ s = splbio();
+ bs_terminate_timeout(bsc);
+
+ if (bsc->sc_hstate == BSC_TARG_CHECK)
+ {
+ if ((error = bs_scsi_cmd_poll_internal(cti)) != COMPLETE)
+ bs_reset_nexus(bsc);
+ }
+ else
+ {
+ if (bsc->sc_outccb)
+ bs_panic(bsc, "bs_cmd_poll: internal error");
+
+ bsc->sc_flags &= ~BSPOLLDONE;
+ bsc->sc_outccb = targetcb;
+
+ while ((bsc->sc_flags & BSPOLLDONE) == 0)
+ {
+ if (bs_scsi_cmd_poll_internal(cti) != COMPLETE)
+ {
+ if ((ti = bsc->sc_nexus) && ti->ti_ctab.tqh_first)
+ ti->ti_error |= (BSTIMEOUT | BSABNORMAL);
+ bs_reset_nexus(bsc);
+ }
+ }
+
+ bsc->sc_outccb = NULL;
+ }
+
+ bs_start_timeout(bsc);
+ softintr(bsc->sc_irqmasks);
+ splx(s);
+ return error;
+}
diff --git a/sys/i386/isa/bs/bs_isa.c b/sys/i386/isa/bs/bs_isa.c
new file mode 100644
index 0000000..fa4e2a0
--- /dev/null
+++ b/sys/i386/isa/bs/bs_isa.c
@@ -0,0 +1,60 @@
+/* $NetBSD$ */
+/*
+ * [NetBSD for NEC PC98 series]
+ * Copyright (c) 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.
+ */
+
+#include <dev/isa/bs/bsif.h>
+
+static int bs_isa_probe __P((struct device *, void *, void *));
+static void bs_isa_attach __P((struct device *, struct device *, void *));
+
+struct cfattach bs_isa_ca = {
+ sizeof(struct bs_softc), bs_isa_probe, bs_isa_attach
+};
+
+static int
+bs_isa_probe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct isa_attach_args *ia = aux;
+
+ ia->ia_irq = IRQUNK;
+ ia->ia_drq = DRQUNK;
+
+ return bsprobe(parent, match, aux);
+}
+
+static void
+bs_isa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+
+ bsattach(parent, self, aux);
+}
diff --git a/sys/i386/isa/bs/bs_pisa.c b/sys/i386/isa/bs/bs_pisa.c
new file mode 100644
index 0000000..2ca9277
--- /dev/null
+++ b/sys/i386/isa/bs/bs_pisa.c
@@ -0,0 +1,126 @@
+/* $NetBSD$ */
+/*
+ * [NetBSD for NEC PC98 series]
+ * Copyright (c) 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.
+ */
+
+#include <dev/isa/bs/bsif.h>
+
+static int bs_pisa_probe __P((struct device *, void *, void *));
+static void bs_pisa_attach __P((struct device *, struct device *, void *));
+static int bs_deactivate __P((pisa_device_args_t));
+static int bs_activate __P((pisa_device_args_t));
+
+struct cfattach bs_pisa_ca = {
+ sizeof(struct bs_softc), bs_pisa_probe, bs_pisa_attach
+};
+
+struct pisa_driver bs_pd = {
+ bs_activate, bs_deactivate,
+};
+
+static int
+bs_pisa_probe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct bs_softc *sc = match;
+ struct pisa_attach_args *pa = aux;
+ struct isa_attach_args *ia = &pa->pa_ia;
+
+ if (ia->ia_iobase == IOBASEUNK ||
+ ia->ia_irq == IRQUNK || ia->ia_drq == DRQUNK)
+ return 0;
+
+ sc->sc_pdv = pa->pa_pdv;
+
+ return bsprobe(parent, match, ia);
+}
+
+static void
+bs_pisa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct bs_softc *sc = (void *) self;
+ struct pisa_attach_args *pa = aux;
+
+ sc->sc_pdv = PISAMSG_BIND(pa->pa_pdv, sc, &bs_pd);
+
+ bsattach(parent, self, (void *) &pa->pa_ia);
+
+ PISA_INTR_REGISTER(sc->sc_pdv, sc->sc_ih);
+}
+
+static int
+bs_deactivate(arg)
+ pisa_device_args_t arg;
+{
+ struct bs_softc *bsc = arg->id;
+
+ bsc->sc_flags |= BSINACTIVE;
+ bs_terminate_timeout(bsc);
+
+ return 0;
+}
+
+#define SCSIBUS_RESCAN
+
+static int
+bs_activate(arg)
+ pisa_device_args_t arg;
+{
+ struct bs_softc *bsc = arg->id;
+ struct isa_attach_args *ia = arg->ia;
+ struct targ_info *ti;
+ int i;
+
+ bsc->sc_irqmasks = (1 << ia->ia_irq);
+
+ while((ti = bsc->sc_titab.tqh_first) != NULL)
+ TAILQ_REMOVE(&bsc->sc_titab, ti, ti_tchain);
+
+ bsc->sc_openf = 0;
+ for (i = 0; i < NTARGETS; i ++)
+ if (i != bsc->sc_hostid && (ti = bsc->sc_ti[i]) != NULL)
+ {
+ TAILQ_INSERT_TAIL(&bsc->sc_titab, ti, ti_tchain);
+ bsc->sc_openf |= (1 << i);
+ }
+
+ bsc->sc_hstate = BSC_BOOTUP;
+ bsc->sc_flags &= ~BSINACTIVE;
+ bs_reset_nexus(bsc);
+
+#ifdef SCSIBUS_RESCAN
+ if (bsc->sc_nexus == NULL)
+ scsi_probe_busses((int) bsc->sc_link.scsibus, -1, -1);
+#endif
+
+ bs_start_timeout(bsc);
+ return 0;
+}
diff --git a/sys/i386/isa/bs/bsfunc.c b/sys/i386/isa/bs/bsfunc.c
new file mode 100644
index 0000000..89d4acc
--- /dev/null
+++ b/sys/i386/isa/bs/bsfunc.c
@@ -0,0 +1,926 @@
+/* $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/bs/bsif.h>
+#endif
+#ifdef __FreeBSD__
+#include <i386/isa/bs/bsif.h>
+#endif
+
+#ifdef BS_STATICS
+struct bs_statics bs_statics[NTARGETS];
+u_int bs_linkcmd_count[NTARGETS];
+u_int bs_bounce_used[NTARGETS];
+#endif /* BS_STATICS */
+
+#ifdef BS_DEBUG
+int bs_debug_flag = 0;
+#endif /* BS_DEBUG */
+
+static void bs_print_syncmsg __P((struct targ_info *, char*));
+static void bs_timeout_target __P((struct targ_info *));
+static void bs_kill_msg __P((struct ccb *cb));
+
+static int bs_start_target __P((struct targ_info *));
+static int bs_check_target __P((struct targ_info *));
+
+/*************************************************************
+ * CCB
+ ************************************************************/
+GENERIC_CCB_STATIC_ALLOC(bs, ccb)
+GENERIC_CCB(bs, ccb, ccb_chain)
+
+/*************************************************************
+ * TIMEOUT
+ ************************************************************/
+static void
+bs_timeout_target(ti)
+ struct targ_info *ti;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+
+ ti->ti_error |= BSTIMEOUT;
+ bsc->sc_flags |= BSRESET;
+
+ if (ti->ti_herrcnt ++ >= HARDRETRIES)
+ {
+ bs_printf(ti, "timeout", "async transfer!");
+ ti->ti_syncmax.period = ti->ti_syncmax.offset = 0;
+ }
+}
+
+void
+bstimeout(arg)
+ void *arg;
+{
+ struct bs_softc *bsc = (struct bs_softc *) arg;
+ struct targ_info *ti;
+ struct ccb *cb;
+ int s;
+
+ s = splbio();
+ bsc->sc_flags &= ~BSSTARTTIMEOUT;
+
+ /* check */
+ if ((ti = bsc->sc_nexus) && (cb = ti->ti_ctab.tqh_first))
+ {
+ if ((cb->tc -= BS_TIMEOUT_CHECK_INTERVAL) < 0)
+ bs_timeout_target(ti);
+ }
+ else for (ti = bsc->sc_titab.tqh_first; ti; ti = ti->ti_tchain.tqe_next)
+ {
+ if (bsc->sc_dtgnum && ti->ti_phase < DISCONNECTED)
+ continue;
+
+ cb = ti->ti_ctab.tqh_first;
+ if (cb && ((cb->tc -= BS_TIMEOUT_CHECK_INTERVAL) < 0))
+ bs_timeout_target(ti);
+ }
+
+ /* try to recover */
+ if (bsc->sc_flags & BSRESET)
+ {
+ bs_debug_print_all(bsc);
+ bs_printf(ti, "timeout", "bus hang up");
+ bs_reset_nexus(bsc);
+ }
+
+ bs_start_timeout(bsc);
+ splx(s);
+}
+
+/**************************************************
+ * MAKE CCB & MSG CCB
+ *************************************************/
+static u_int8_t cmd_unit_ready[6];
+
+struct ccb *
+bs_make_internal_ccb(ti, lun, cmd, cmdlen, data, datalen, flags, timeout)
+ struct targ_info *ti;
+ u_int lun;
+ u_int8_t *cmd;
+ u_int cmdlen;
+ u_int8_t *data;
+ u_int datalen;
+ u_int flags;
+ int timeout;
+{
+ struct ccb *cb;
+
+ if ((cb = bs_get_ccb(XSBS_SCSI_NOSLEEP)) == NULL)
+ bs_panic(ti->ti_bsc, "can not get ccb mem");
+
+ cb->xs = NULL;
+ cb->lun = lun;
+ cb->cmd = (cmd ? cmd : cmd_unit_ready);
+ cb->cmdlen = (cmd ? cmdlen : sizeof(cmd_unit_ready));
+ cb->data = data;
+ cb->datalen = (data ? datalen : 0);
+ cb->msgoutlen = 0;
+ cb->flags = flags & BSCFLAGSMASK;
+ bs_targ_flags(ti, cb);
+ cb->rcnt = 0;
+ cb->tcmax = (timeout > BS_DEFAULT_TIMEOUT_SECOND ? timeout :
+ BS_DEFAULT_TIMEOUT_SECOND);
+
+ TAILQ_INSERT_HEAD(&ti->ti_ctab, cb, ccb_chain);
+
+ return cb;
+}
+
+struct ccb *
+bs_make_msg_ccb(ti, lun, cb, msg, timex)
+ struct targ_info *ti;
+ u_int lun;
+ struct ccb *cb;
+ struct msgbase *msg;
+ u_int timex;
+{
+ u_int flags;
+
+ flags = BSFORCEIOPOLL | msg->flag;
+ if (cb == NULL)
+ cb = bs_make_internal_ccb(ti, lun, NULL, 0, NULL, 0,
+ flags, timex);
+ else
+ cb->flags |= flags & BSCFLAGSMASK;
+
+ cb->msgoutlen = msg->msglen;
+ bcopy(msg->msg, cb->msgout, msg->msglen);
+ return cb;
+}
+
+int
+bs_send_msg(ti, lun, msg, timex)
+ struct targ_info *ti;
+ u_int lun;
+ struct msgbase *msg;
+ int timex;
+{
+ struct ccb *cb;
+
+ cb = bs_make_msg_ccb(ti, lun, NULL, msg, timex);
+ bscmdstart(ti, BSCMDSTART);
+ return bs_scsi_cmd_poll(ti, cb);
+}
+
+static void
+bs_kill_msg(cb)
+ struct ccb *cb;
+{
+ cb->msgoutlen = 0;
+}
+
+/**************************************************
+ * MAKE SENSE CCB
+ **************************************************/
+struct ccb *
+bs_request_sense(ti)
+ struct targ_info *ti;
+{
+ struct ccb *cb;
+
+ bzero(ti->scsi_cmd, sizeof(struct scsi_sense));
+ bzero(&ti->sense, sizeof(struct scsi_sense_data));
+ ti->scsi_cmd[0] = REQUEST_SENSE;
+ ti->scsi_cmd[1] = (ti->ti_lun << 5);
+ ti->scsi_cmd[4] = sizeof(struct scsi_sense_data);
+ cb = bs_make_internal_ccb(ti, ti->ti_lun, ti->scsi_cmd,
+ sizeof(struct scsi_sense),
+ (u_int8_t *) & ti->sense,
+ sizeof(struct scsi_sense_data),
+ BSFORCEIOPOLL,
+ BS_DEFAULT_TIMEOUT_SECOND);
+ cb->flags |= BSSENSECCB;
+ return cb;
+}
+
+/**************************************************
+ * SYNC MSG
+ *************************************************/
+/* sync neg */
+int
+bs_start_syncmsg(ti, cb, flag)
+ struct targ_info *ti;
+ struct ccb *cb;
+ int flag;
+{
+ struct syncdata *negp, *maxp;
+ struct msgbase msg;
+ u_int lun;
+
+ negp = &ti->ti_syncnow;
+ maxp = &ti->ti_syncmax;
+
+ ti->ti_state = BS_TARG_SYNCH;
+
+ if (flag == BS_SYNCMSG_REQUESTED)
+ {
+ if (negp->offset > maxp->offset)
+ negp->offset = maxp->offset;
+ if (negp->offset != 0 && negp->period < maxp->period)
+ negp->period = maxp->period;
+
+ msg.flag = 0;
+ lun = ti->ti_lun;
+ if (cb == NULL)
+ cb = ti->ti_ctab.tqh_first;
+ }
+ else if (ti->ti_cfgflags & BS_SCSI_SYNC)
+ {
+ negp->offset = maxp->offset;
+ negp->period = maxp->period;
+
+ msg.flag = BSERROROK;
+ lun = 0;
+ }
+ else
+ {
+ ti->ti_state = BS_TARG_RDY;
+ return COMPLETE;
+ }
+
+ BS_SETUP_SYNCSTATE(flag);
+ msg.msg[0] = MSG_EXTEND;
+ msg.msg[1] = MSG_EXTEND_SYNCHLEN;
+ msg.msg[2] = MSG_EXTEND_SYNCHCODE;
+ msg.msg[3] = negp->period;
+ msg.msg[4] = negp->offset;
+ msg.msglen = MSG_EXTEND_SYNCHLEN + 2;
+
+ bs_make_msg_ccb(ti, lun, cb, &msg, BS_SYNC_TIMEOUT);
+ return COMPLETE;
+}
+
+static void
+bs_print_syncmsg(ti, s)
+ struct targ_info *ti;
+ char *s;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct syncdata *negp;
+ u_int speed;
+
+ negp = &ti->ti_syncnow;
+ speed = (negp->offset && negp->period) ?
+ (2500 / ((u_int) negp->period)) : 0;
+
+ printf("%s(%d:%d): <%s> ", bsc->sc_dvname, ti->ti_id, ti->ti_lun, s);
+ printf("period 0x%x offset %d chip (0x%x)", negp->period, negp->offset,
+ ti->ti_sync);
+ if (speed)
+ printf(" %d.%d M/s", speed / 10, speed % 10);
+ printf("\n");
+}
+
+int
+bs_analyze_syncmsg(ti, cb)
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ u_int8_t ans = ti->ti_syncnow.state;
+ struct syncdata *negp, *maxp;
+ struct syncdata bdata;
+ char *s = NULL;
+ u_int8_t period;
+
+ negp = &ti->ti_syncnow;
+ bdata = *negp;
+ maxp = &ti->ti_syncmax;
+
+ switch(ans)
+ {
+ case BS_SYNCMSG_REJECT:
+ period = 0;
+ s = "msg reject";
+ break;
+
+ case BS_SYNCMSG_ASSERT:
+ period = 0;
+ s = "no msg";
+ break;
+
+ default:
+ if (negp->offset != 0 && negp->period < maxp->period)
+ {
+ period = 0xff;
+ s = "illegal(period)";
+ }
+ else if (negp->offset > maxp->offset)
+ {
+ period = 0xff;
+ s = "illegal(offset)";
+ }
+ else
+ period = negp->offset ? negp->period : 0;
+ break;
+ }
+
+ if (s == NULL)
+ {
+ bshw_adj_syncdata(negp);
+ *maxp = *negp;
+
+ if (ans == BS_SYNCMSG_REQUESTED)
+ s = "requested";
+ else
+ s = negp->offset ? "synchronous" : "async";
+ }
+ else
+ {
+ negp->offset = maxp->offset = 0;
+ bshw_adj_syncdata(negp);
+ bshw_adj_syncdata(maxp);
+ }
+
+ /* really setup hardware */
+ bshw_set_synchronous(bsc, ti);
+ if (cb == NULL || (period >= negp->period && period <= negp->period + 2))
+ {
+ bs_print_syncmsg(ti, s);
+ BS_SETUP_TARGSTATE(BS_TARG_RDY);
+ BS_SETUP_SYNCSTATE(BS_SYNCMSG_NULL);
+ if (cb)
+ bs_kill_msg(cb);
+
+ return 0;
+ }
+ else
+ {
+ bs_printf(ti, "bs_analyze_syncmsg",
+ "sync(period) mismatch, retry neg...");
+ printf("expect(%d:0x%x) => reply(%d:0x%x)\n",
+ bdata.offset, bdata.period, negp->offset, negp->period);
+
+ bs_start_syncmsg(ti, cb, BS_SYNCMSG_ASSERT);
+ return EINVAL;
+ }
+}
+
+/**************************************************
+ * ABORT AND RESET MSG
+ **************************************************/
+/* send device reset msg and wait */
+void
+bs_reset_device(ti)
+ struct targ_info *ti;
+{
+ struct msgbase msg;
+
+ msg.msglen = 1;
+ msg.msg[0] = MSG_RESET;
+ msg.flag = 0;
+
+ bs_send_msg(ti, 0, &msg, 0);
+
+ delay(ti->ti_bsc->sc_RSTdelay);
+ bs_check_target(ti);
+}
+
+/* send abort msg */
+struct ccb *
+bs_force_abort(ti)
+ struct targ_info *ti;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct msgbase msg;
+ struct ccb *cb = ti->ti_ctab.tqh_first;
+ u_int lun;
+
+ if (cb)
+ {
+ lun = cb->lun;
+ cb->rcnt++;
+ }
+ else
+ lun = 0;
+
+ msg.msglen = 1;
+ msg.msg[0] = MSG_ABORT;
+ msg.flag = 0;
+
+ cb = bs_make_msg_ccb(ti, lun, NULL, &msg, 0);
+ bscmdstart(ti, BSCMDSTART);
+
+ if (bsc->sc_nexus == ti)
+ BS_LOAD_SDP
+
+ return cb;
+}
+
+/**************************************************
+ * COMPLETE SCSI BUS RESET
+ *************************************************/
+/*
+ * XXX:
+ * 1) reset scsi bus (ie. all target reseted).
+ * 2) chip reset.
+ * 3) check target status.
+ * 4) sync neg with all targets.
+ * 5) setup sync reg in host.
+ * 6) recover previous nexus.
+ */
+void
+bs_scsibus_start(bsc)
+ struct bs_softc *bsc;
+{
+ struct targ_info *ti, *nextti = NULL;
+ struct ccb *cb;
+ int error = HASERROR;
+ u_int querm, bits, skip = 0;
+
+ querm = (bsc->sc_hstate == BSC_BOOTUP);
+ bsc->sc_hstate = BSC_TARG_CHECK;
+
+ /* target check */
+ do
+ {
+ if (error != COMPLETE)
+ {
+ printf("%s: scsi bus reset and try to restart ...",
+ bsc->sc_dvname);
+ bshw_smitabort(bsc);
+ bshw_dmaabort(bsc, NULL);
+ bshw_chip_reset(bsc);
+ bshw_bus_reset(bsc);
+ bshw_chip_reset(bsc);
+ printf(" done. scsi bus ready.\n");
+ nextti = bsc->sc_titab.tqh_first;
+ error = COMPLETE;
+ }
+
+ if ((ti = nextti) == NULL)
+ break;
+ nextti = ti->ti_tchain.tqe_next;
+
+ bits = (1 << ti->ti_id);
+ if (skip & bits)
+ continue;
+
+ if ((error = bs_check_target(ti)) != COMPLETE)
+ {
+ if (querm)
+ {
+ TAILQ_REMOVE(&bsc->sc_titab, ti, ti_tchain);
+ bsc->sc_openf &= ~bits;
+ }
+
+ if (error == NOTARGET)
+ error = COMPLETE;
+
+ skip |= bits;
+ }
+ }
+ while (1);
+
+ /* ok now ready */
+ bsc->sc_hstate = BSC_RDY;
+
+ /* recover */
+ for (ti = bsc->sc_titab.tqh_first; ti; ti = ti->ti_tchain.tqe_next)
+ {
+ ti->ti_ctab = ti->ti_bctab;
+ TAILQ_INIT(&ti->ti_bctab);
+ if (ti->ti_ctab.tqh_first)
+ bscmdstart(ti, BSCMDSTART);
+ }
+}
+
+void
+bs_reset_nexus(bsc)
+ struct bs_softc *bsc;
+{
+ struct targ_info *ti;
+ struct ccb *cb;
+
+ bsc->sc_flags &= ~(BSRESET | BSUNDERRESET);
+ if (bsc->sc_poll)
+ {
+ bsc->sc_flags |= BSUNDERRESET;
+ return;
+ }
+
+ /* host state clear */
+ BS_HOST_TERMINATE
+ BS_SETUP_MSGPHASE(FREE)
+ bsc->sc_dtgnum = 0;
+
+ /* target state clear */
+ for (ti = bsc->sc_titab.tqh_first; ti; ti = ti->ti_tchain.tqe_next)
+ {
+ if (ti->ti_state == BS_TARG_SYNCH)
+ bs_analyze_syncmsg(ti, NULL);
+ if (ti->ti_state > BS_TARG_START)
+ BS_SETUP_TARGSTATE(BS_TARG_START);
+
+ BS_SETUP_PHASE(UNDEF)
+ bs_hostque_delete(bsc, ti);
+ if (cb = ti->ti_ctab.tqh_first)
+ {
+ if (bsc->sc_hstate == BSC_TARG_CHECK)
+ {
+ ti->ti_error |= BSFATALIO;
+ bscmddone(ti);
+ }
+ else if (cb->rcnt >= bsc->sc_retry)
+ {
+ ti->ti_error |= BSABNORMAL;
+ bscmddone(ti);
+ }
+ else if (ti->ti_error)
+ cb->rcnt++;
+ }
+
+ /* target state clear */
+ BS_SETUP_PHASE(FREE)
+ BS_SETUP_SYNCSTATE(BS_SYNCMSG_NULL);
+ ti->ti_flags &= ~BSCFLAGSMASK;
+ ti->ti_msgout = 0;
+#ifdef BS_DIAG
+ ti->ti_flags &= ~BSNEXUS;
+#endif /* BS_DIAG */
+
+ for ( ; cb; cb = cb->ccb_chain.tqe_next)
+ {
+ bs_kill_msg(cb);
+ cb->flags &= ~(BSITSDONE | BSCASTAT);
+ cb->error = 0;
+ }
+
+ if (bsc->sc_hstate != BSC_TARG_CHECK &&
+ ti->ti_bctab.tqh_first == NULL)
+ ti->ti_bctab = ti->ti_ctab;
+
+ TAILQ_INIT(&ti->ti_ctab);
+ }
+
+ if (bsc->sc_hstate != BSC_TARG_CHECK)
+ bs_scsibus_start(bsc);
+}
+
+/**************************************************
+ * CHECK TARGETS AND START TARGETS
+ *************************************************/
+static int
+bs_start_target(ti)
+ struct targ_info *ti;
+{
+ struct ccb *cb;
+ struct scsi_start_stop cmd;
+
+ bzero(&cmd, sizeof(struct scsi_start_stop));
+#ifdef __NetBSD__
+ cmd.opcode = START_STOP;
+#else
+ cmd.op_code = START_STOP;
+#endif
+ cmd.how = SSS_START;
+ ti->ti_lun = 0;
+ cb = bs_make_internal_ccb(ti, 0, (u_int8_t *) &cmd,
+ sizeof(struct scsi_start_stop),
+ NULL, 0, BSFORCEIOPOLL, BS_MOTOR_TIMEOUT);
+ bscmdstart(ti, BSCMDSTART);
+ return bs_scsi_cmd_poll(ti, cb);
+}
+
+/* test unit ready and check ATN msgout response */
+static int
+bs_check_target(ti)
+ struct targ_info *ti;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct scsi_inquiry scsi_cmd;
+ struct scsi_inquiry_data scsi_inquiry_data;
+ struct ccb *cb;
+ int count, retry = bsc->sc_retry;
+ int s, error = COMPLETE;
+
+ ti->ti_lun = 0;
+ bsc->sc_retry = 2;
+ s = splbio();
+
+ /* inquiry */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+#ifdef __NetBSD__
+ scsi_cmd.opcode = INQUIRY;
+#else
+ scsi_cmd.op_code = INQUIRY;
+#endif
+ scsi_cmd.length = sizeof(struct scsi_inquiry_data);
+ cb = bs_make_internal_ccb(ti, 0,
+ (u_int8_t *) &scsi_cmd, sizeof(scsi_cmd),
+ (u_int8_t *) &scsi_inquiry_data,
+ sizeof(scsi_inquiry_data),
+ BSFORCEIOPOLL, BS_STARTUP_TIMEOUT);
+ bscmdstart(ti, BSCMDSTART);
+ error = bs_scsi_cmd_poll(ti, cb);
+ if (error != COMPLETE || (ti->ti_error & BSSELTIMEOUT))
+ goto done;
+ ti->targ_type = scsi_inquiry_data.device;
+ ti->targ_support = scsi_inquiry_data.flags;
+
+ /* test unit ready twice */
+ for (count = 0; count < 2; count++)
+ {
+ cb = bs_make_internal_ccb(ti, 0, NULL, 0, NULL, 0,
+ BSFORCEIOPOLL, BS_STARTUP_TIMEOUT);
+ bscmdstart(ti, BSCMDSTART);
+ error = bs_scsi_cmd_poll(ti, cb);
+ if (error != COMPLETE || (ti->ti_error & BSSELTIMEOUT))
+ goto done;
+ }
+
+ if (cb->flags & BSCASTAT)
+ bs_printf(ti, "check", "could not clear CA state");
+ ti->ti_error = 0;
+
+done:
+ bsc->sc_retry = retry;
+
+ if (ti->ti_error & BSSELTIMEOUT)
+ error = NOTARGET;
+
+ if (error == COMPLETE)
+ error = bs_start_target(ti);
+
+ splx(s);
+ return error;
+}
+
+/**************************************************
+ * TARGET CONTROL
+ **************************************************/
+struct targ_info *
+bs_init_target_info(bsc, target)
+ struct bs_softc *bsc;
+ int target;
+{
+ struct targ_info *ti;
+
+ ti = malloc(sizeof(struct targ_info), M_DEVBUF, M_NOWAIT);
+ if (ti == NULL)
+ {
+ bs_printf(NULL, "bs_init_targ_info", "no target info memory");
+ return ti;
+ }
+
+ bzero(ti, sizeof(*ti));
+
+ ti->ti_bsc = bsc;
+ ti->ti_id = target;
+ ti->sm_vaddr = (u_int8_t *) MADDRUNK;
+ ti->ti_cfgflags = BS_SCSI_NOPARITY | BS_SCSI_NOSAT;
+ ti->ti_mflags = ~(BSSAT | BSDISC | BSSMIT | BSLINK);
+ BS_SETUP_TARGSTATE(BS_TARG_CTRL);
+
+ TAILQ_INIT(&ti->ti_ctab);
+
+ bs_alloc_buf(ti);
+ if (ti->bounce_addr == NULL)
+ {
+ free(ti, M_DEVBUF);
+ return NULL;
+ }
+
+ TAILQ_INSERT_TAIL(&bsc->sc_titab, ti, ti_tchain);
+ bsc->sc_ti[target] = ti;
+ bsc->sc_openf |= (1 << target);
+
+ return ti;
+}
+
+void
+bs_setup_ctrl(ti, quirks, flags)
+ struct targ_info *ti;
+ u_int quirks;
+ u_int flags;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ u_int offset, period, maxperiod;
+
+ if (ti->ti_state == BS_TARG_CTRL)
+ {
+ ti->ti_cfgflags = BS_SCSI_POSITIVE;
+ ti->ti_syncmax.offset = BSHW_MAX_OFFSET;
+ BS_SETUP_TARGSTATE(BS_TARG_START);
+ }
+ else
+ flags |= ti->ti_cfgflags & BS_SCSI_NEGATIVE;
+
+#ifdef BS_TARG_SAFEMODE
+ if (ti->targ_type != 0)
+ {
+ flags &= ~(BS_SCSI_DISC | BS_SCSI_SYNC);
+ flags |= BS_SCSI_NOPARITY;
+ }
+#endif
+
+#ifdef SDEV_NODISC
+ if (quirks & SDEV_NODISC)
+ flags &= ~BS_SCSI_DISC;
+#endif
+#ifdef SDEV_NOPARITY
+ if (quirks & SDEV_NOPARITY)
+ flags |= BS_SCSI_NOPARITY;
+#endif
+#ifdef SDEV_NOCMDLNK
+ if (quirks & SDEV_NOCMDLNK)
+ flags &= ~BS_SCSI_LINK;
+#endif
+#ifdef SDEV_ASYNC
+ if (quirks & SDEV_ASYNC)
+ flags &= ~BS_SCSI_SYNC;
+#endif
+#ifdef SDEV_AUTOSAVE
+ if (quirks & SDEV_AUTOSAVE)
+ flags |= BS_SCSI_SAVESP;
+#endif
+
+ if ((flags & BS_SCSI_DISC) == 0 ||
+ (ti->targ_support & SID_Linked) == 0)
+ flags &= ~BS_SCSI_LINK;
+
+ ti->sm_vaddr = (flags & BS_SCSI_NOSMIT) ?
+ (u_int8_t *) MADDRUNK : bsc->sm_vaddr;
+
+ if (ti->sm_vaddr == (u_int8_t *) MADDRUNK)
+ flags |= BS_SCSI_NOSMIT;
+ else if (bsc->sc_cfgflags & BSC_SMITSAT_DISEN)
+ flags |= BS_SCSI_NOSAT;
+
+ flags &= (ti->ti_cfgflags & BS_SCSI_POSITIVE) | (~BS_SCSI_POSITIVE);
+ ti->ti_cfgflags = flags;
+
+ /* calculate synch setup */
+ period = BS_SCSI_PERIOD(flags);
+ offset = (flags & BS_SCSI_SYNC) ? BS_SCSI_OFFSET(flags) : 0;
+
+ maxperiod = (bsc->sc_cspeed & IDR_FS_15_20) ? 100 : 50;
+ if (period > maxperiod)
+ period = maxperiod;
+
+ if (period)
+ period = 2500 / period;
+
+ if (ti->ti_syncmax.offset > offset)
+ ti->ti_syncmax.offset = offset;
+ if (ti->ti_syncmax.period < period)
+ ti->ti_syncmax.period = period;
+
+ bshw_adj_syncdata(&ti->ti_syncmax);
+
+ /* finally report our info */
+ printf("%s(%d:%d): {%d:0x%x:0x%x:%s} flags 0x%b\n",
+ bsc->sc_dvname, ti->ti_id, ti->ti_lun,
+ (u_int) ti->targ_type,
+ (u_int) ti->targ_support,
+ (u_int) ti->bounce_size,
+ (flags & BS_SCSI_NOSMIT) ? "dma" : "pdma",
+ flags, BS_SCSI_BITS);
+
+ /* internal representation */
+ ti->ti_mflags = ~0;
+ if ((ti->ti_cfgflags & BS_SCSI_DISC) == 0)
+ ti->ti_mflags &= ~BSDISC;
+ if ((ti->ti_cfgflags & BS_SCSI_LINK) == 0)
+ ti->ti_mflags &= ~BSLINK;
+ if (ti->ti_cfgflags & BS_SCSI_NOSAT)
+ ti->ti_mflags &= ~BSSAT;
+ if (ti->ti_cfgflags & BS_SCSI_NOSMIT)
+ ti->ti_mflags &= ~BSSMIT;
+}
+
+/**************************************************
+ * MISC
+ **************************************************/
+void
+bs_printf(ti, ph, c)
+ struct targ_info *ti;
+ char *ph;
+ char *c;
+{
+
+ if (ti)
+ printf("%s(%d:%d): <%s> %s\n",
+ ti->ti_bsc->sc_dvname, ti->ti_id, ti->ti_lun, ph, c);
+ else
+ printf("bs*(*:*): <%s> %s\n", ph, c);
+}
+
+void
+bs_panic(bsc, c)
+ struct bs_softc *bsc;
+ u_char *c;
+{
+
+ panic("%s %s\n", bsc->sc_dvname, c);
+}
+
+/**************************************************
+ * DEBUG FUNC
+ **************************************************/
+#ifdef BS_DEBUG_ROUTINE
+u_int
+bsr(addr)
+ u_int addr;
+{
+
+ outb(0xcc0, addr);
+ return inb(0xcc2);
+}
+
+u_int
+bsw(addr, data)
+ u_int addr;
+ int data;
+{
+
+ outb(0xcc0, addr);
+ outb(0xcc2, data);
+ return 0;
+}
+#endif /* BS_DEBUG_ROUTINE */
+
+void
+bs_debug_print_all(bsc)
+ struct bs_softc *bsc;
+{
+ struct targ_info *ti;
+
+ for (ti = bsc->sc_titab.tqh_first; ti; ti = ti->ti_tchain.tqe_next)
+ bs_debug_print(bsc, ti);
+}
+
+static u_char *phase[] =
+{
+ "FREE", "HOSTQUE", "DISC", "COMPMSG", "ATN", "DISCMSG", "SELECT",
+ "SELECTED", "RESELECTED", "MSGIN", "MSGOUT", "STATIN", "CMDOUT",
+ "DATA", "SATSEL", "SATRESEL", "SATSDP", "SATCOMPSEQ", "UNDEF",
+};
+
+void
+bs_debug_print(bsc, ti)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+{
+ struct ccb *cb;
+
+ /* host stat */
+ printf("%s <DEBUG INFO> nexus %x bs %x bus status %x \n",
+ bsc->sc_dvname, ti, bsc->sc_nexus, (u_int) bsc->sc_busstat);
+
+ /* target stat */
+ if (ti)
+ {
+ struct sc_p *sp = &bsc->sc_p;
+
+ printf("%s(%d:%d) ph<%s> ", bsc->sc_dvname, ti->ti_id,
+ ti->ti_lun, phase[(int) ti->ti_phase]);
+ printf("msgptr %x msg[0] %x status %x tqh %x fl %x\n",
+ (u_int) (ti->ti_msginptr), (u_int) (ti->ti_msgin[0]),
+ ti->ti_status, cb = ti->ti_ctab.tqh_first, ti->ti_flags);
+ if (cb)
+ printf("cmdlen %x cmdaddr %x cmd[0] %x\n",
+ cb->cmdlen, cb->cmd, (int) cb->cmd[0]);
+ printf("datalen %x dataaddr %x seglen %x ",
+ sp->datalen, sp->data, sp->seglen);
+ if (cb)
+ printf("odatalen %x flags %x\n",
+ cb->datalen, cb->flags);
+ else
+ printf("\n");
+ printf("error flags %b\n", ti->ti_error, BSERRORBITS);
+ }
+}
diff --git a/sys/i386/isa/bs/bsfunc.h b/sys/i386/isa/bs/bsfunc.h
new file mode 100644
index 0000000..274be97
--- /dev/null
+++ b/sys/i386/isa/bs/bsfunc.h
@@ -0,0 +1,229 @@
+/* $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.
+ */
+
+/**************************************************
+ * FUNC
+ **************************************************/
+/* timeout */
+void bstimeout __P((void *));
+
+/* ctrl setup */
+void bs_setup_ctrl __P((struct targ_info *, u_int, u_int));
+struct targ_info *bs_init_target_info __P((struct bs_softc *, int));
+
+/* msg op */
+int bs_send_msg __P((struct targ_info *, u_int, struct msgbase *, int));
+struct ccb *bs_request_sense __P((struct targ_info *));
+
+/* sync msg op */
+int bs_start_syncmsg __P((struct targ_info *, struct ccb *, int));
+int bs_send_syncmsg __P((struct targ_info *));
+int bs_analyze_syncmsg __P((struct targ_info *, struct ccb *));
+
+/* reset device */
+void bs_scsibus_start __P((struct bs_softc *));
+void bs_reset_nexus __P((struct bs_softc *));
+struct ccb *bs_force_abort __P((struct targ_info *));
+void bs_reset_device __P((struct targ_info *));
+
+/* ccb */
+struct ccb *bs_make_internal_ccb __P((struct targ_info *, u_int, u_int8_t *, u_int, u_int8_t *, u_int, u_int, int));
+struct ccb *bs_make_msg_ccb __P((struct targ_info *, u_int, struct ccb *, struct msgbase *, u_int));
+
+/* misc funcs */
+void bs_printf __P((struct targ_info *, char *, char *));
+void bs_panic __P((struct bs_softc *, u_char *));
+
+/* misc debug */
+u_int bsr __P((u_int));
+u_int bsw __P((u_int, int));
+void bs_debug_print_all __P((struct bs_softc *));
+void bs_debug_print __P((struct bs_softc *, struct targ_info *));
+
+/**************************************************
+ * TARG FLAGS
+ *************************************************/
+static BS_INLINE int bs_check_sat __P((struct targ_info *));
+static BS_INLINE int bs_check_smit __P((struct targ_info *));
+static BS_INLINE int bs_check_disc __P((struct targ_info *));
+static BS_INLINE int bs_check_link __P((struct targ_info *, struct ccb *));
+static BS_INLINE u_int8_t bs_identify_msg __P((struct targ_info *));
+static BS_INLINE void bs_targ_flags __P((struct targ_info *, struct ccb *));
+
+static BS_INLINE int
+bs_check_disc(ti)
+ struct targ_info *ti;
+{
+
+ return (ti->ti_flags & BSDISC);
+}
+
+static BS_INLINE int
+bs_check_sat(ti)
+ struct targ_info *ti;
+{
+
+ return (ti->ti_flags & BSSAT);
+}
+
+static BS_INLINE int
+bs_check_smit(ti)
+ struct targ_info *ti;
+{
+
+ return (ti->ti_flags & BSSMIT);
+}
+
+static BS_INLINE int
+bs_check_link(ti, cb)
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+ struct ccb *nextcb;
+
+ return ((ti->ti_flags & BSLINK) &&
+ (nextcb = cb->ccb_chain.tqe_next) &&
+ (nextcb->flags & BSLINK));
+}
+
+static BS_INLINE u_int8_t
+bs_identify_msg(ti)
+ struct targ_info *ti;
+{
+
+ return ((bs_check_disc(ti) ? 0xc0 : 0x80) | ti->ti_lun);
+}
+
+static BS_INLINE void
+bs_targ_flags(ti, cb)
+ struct targ_info *ti;
+ struct ccb *cb;
+{
+ u_int cmf = (u_int) bshw_cmd[cb->cmd[0]];
+
+ cb->flags |= ((cmf & (BSSAT | BSSMIT | BSLINK)) | BSDISC);
+ cb->flags &= ti->ti_mflags;
+
+ if (cb->datalen < DEV_BSIZE)
+ cb->flags &= ~BSSMIT;
+ if (cb->flags & BSFORCEIOPOLL)
+ cb->flags &= ~(BSLINK | BSSMIT | BSSAT | BSDISC);
+}
+
+/**************************************************
+ * QUEUE OP
+ **************************************************/
+static BS_INLINE void bs_hostque_init __P((struct bs_softc *));
+static BS_INLINE void bs_hostque_head __P((struct bs_softc *, struct targ_info *));
+static BS_INLINE void bs_hostque_tail __P((struct bs_softc *, struct targ_info *));
+static BS_INLINE void bs_hostque_delete __P((struct bs_softc *, struct targ_info *));
+
+static BS_INLINE void
+bs_hostque_init(bsc)
+ struct bs_softc *bsc;
+{
+
+ TAILQ_INIT(&bsc->sc_sttab);
+ TAILQ_INIT(&bsc->sc_titab);
+}
+
+static BS_INLINE void
+bs_hostque_head(bsc, ti)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+{
+
+ if (ti->ti_flags & BSQUEUED)
+ TAILQ_REMOVE(&bsc->sc_sttab, ti, ti_wchain)
+ else
+ ti->ti_flags |= BSQUEUED;
+
+ TAILQ_INSERT_HEAD(&bsc->sc_sttab, ti, ti_wchain);
+}
+
+static BS_INLINE void
+bs_hostque_tail(bsc, ti)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+{
+
+ if (ti->ti_flags & BSQUEUED)
+ TAILQ_REMOVE(&bsc->sc_sttab, ti, ti_wchain)
+ else
+ ti->ti_flags |= BSQUEUED;
+
+ TAILQ_INSERT_TAIL(&bsc->sc_sttab, ti, ti_wchain)
+}
+
+static BS_INLINE void
+bs_hostque_delete(bsc, ti)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+{
+
+ if (ti->ti_flags & BSQUEUED)
+ {
+ ti->ti_flags &= ~BSQUEUED;
+ TAILQ_REMOVE(&bsc->sc_sttab, ti, ti_wchain)
+ }
+}
+
+/*************************************************************
+ * TIMEOUT
+ ************************************************************/
+static BS_INLINE void bs_start_timeout __P((struct bs_softc *));
+static BS_INLINE void bs_terminate_timeout __P((struct bs_softc *));
+
+static BS_INLINE void
+bs_start_timeout(bsc)
+ struct bs_softc *bsc;
+{
+
+ if ((bsc->sc_flags & BSSTARTTIMEOUT) == 0)
+ {
+ bsc->sc_flags |= BSSTARTTIMEOUT;
+ timeout(bstimeout, bsc, BS_TIMEOUT_INTERVAL);
+ }
+}
+
+static BS_INLINE void
+bs_terminate_timeout(bsc)
+ struct bs_softc *bsc;
+{
+
+ if (bsc->sc_flags & BSSTARTTIMEOUT)
+ {
+ untimeout(bstimeout, bsc);
+ bsc->sc_flags &= ~BSSTARTTIMEOUT;
+ }
+}
diff --git a/sys/i386/isa/bs/bshw.c b/sys/i386/isa/bs/bshw.c
new file mode 100644
index 0000000..5d9632b
--- /dev/null
+++ b/sys/i386/isa/bs/bshw.c
@@ -0,0 +1,451 @@
+/* $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 <dev/isa/bs/bsif.h>
+#include <dev/isa/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>
+#endif
+
+static 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 void
+bshw_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 2000
+
+int
+bshw_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 10000
+static int tw_pos;
+static char tw_chars[] = "|/-\\";
+
+/* this is some jokes */
+static void
+twiddle_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 void
+bshw_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);
+}
+
+void
+bshw_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])
+ {
+ ti->ti_sync = 0;
+ bshw_set_vsp(bsc, i, 0);
+ }
+ }
+}
+
+/* probe */
+int
+bshw_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_irqmasks = (1 << (*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 */
+
+void
+bshw_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];
+ }
+}
+
+void
+bshw_set_synchronous(bsc, ti)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+{
+ struct bshw *hw = bsc->sc_hw;
+ 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 */
+void
+bshw_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 */
+void
+bshw_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 */
+void
+bshw_lock(bsc)
+ struct bs_softc *bsc;
+{
+
+ bsc->sc_hwlock++;
+ write_wd33c93(bsc, wd3s_mbank, bsc->sc_membank & (~MBR_IEN));
+}
+
+void
+bshw_unlock(bsc)
+ struct bs_softc *bsc;
+{
+
+ if ((--bsc->sc_hwlock) <= 0)
+ write_wd33c93(bsc, wd3s_mbank, bsc->sc_membank);
+}
+
+/**********************************************
+ * DMA OPERATIONS
+ **********************************************/
+#ifdef __NetBSD__
+#include <dev/isa/bs/bshw_dma.c>
+#include <dev/isa/bs/bshw_pdma.c>
+#endif
+#ifdef __FreeBSD__
+#include <i386/isa/bs/bshw_dma.c>
+#include <i386/isa/bs/bshw_pdma.c>
+#endif
+
+/**********************************************
+ * DEBUG
+ **********************************************/
+/* misc */
+void
+bshw_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");
+ }
+}
diff --git a/sys/i386/isa/bs/bshw.h b/sys/i386/isa/bs/bshw.h
new file mode 100644
index 0000000..ac765ec
--- /dev/null
+++ b/sys/i386/isa/bs/bshw.h
@@ -0,0 +1,363 @@
+/* $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.
+ */
+
+/* NEC port offsets */
+#define BSHW_DEFAULT_PORT 0xcc0
+#define BSHW_IOSZ 5
+
+#define addr_port 0
+#define stat_port 0
+#define ctrl_port 2
+#define cmd_port 4
+
+#define BSHW_MAX_OFFSET 12
+#define BSHW_SEL_TIMEOUT 0x80
+
+#define BSHW_READ BSR_IOR
+#define BSHW_WRITE 0x0
+
+#define BSHW_CMD_CHECK(CCB, CAT) (bshw_cmd[(CCB)->cmd[0]] & (CAT))
+
+/*********************************************************
+ * static inline declare.
+ *********************************************************/
+static BS_INLINE void write_wd33c93 __P((struct bs_softc *, u_int, u_int8_t));
+static BS_INLINE u_int8_t read_wd33c93 __P((struct bs_softc *, u_int));
+static BS_INLINE u_int8_t bshw_get_auxstat __P((struct bs_softc *));
+static BS_INLINE u_int8_t bshw_get_busstat __P((struct bs_softc *));
+static BS_INLINE u_int8_t bshw_get_status_insat __P((struct bs_softc *));
+static BS_INLINE u_int8_t bshw_read_data __P((struct bs_softc *));
+static BS_INLINE void bshw_write_data __P((struct bs_softc *, u_int8_t));
+static BS_INLINE void bshw_set_count __P((struct bs_softc *, u_int));
+static BS_INLINE u_int bshw_get_count __P((struct bs_softc *));
+static BS_INLINE void bshw_set_dst_id __P((struct bs_softc *, u_int, u_int));
+static BS_INLINE void bshw_set_lun __P((struct bs_softc *, u_int));
+static BS_INLINE u_int bshw_get_src_id __P((struct bs_softc *));
+static BS_INLINE void bshw_negate_ack __P((struct bs_softc *));
+static BS_INLINE void bshw_assert_atn __P((struct bs_softc *));
+static BS_INLINE void bshw_assert_select __P((struct bs_softc *));
+static BS_INLINE void bshw_start_xfer __P((struct bs_softc *));
+static BS_INLINE void bshw_start_sxfer __P((struct bs_softc *));
+static BS_INLINE void bshw_cmd_pass __P((struct bs_softc *, u_int));
+static BS_INLINE void bshw_start_sat __P((struct bs_softc *, u_int));
+static BS_INLINE void bshw_abort_cmd __P((struct bs_softc *));
+static BS_INLINE void bshw_set_sync_reg __P((struct bs_softc *, u_int));
+static BS_INLINE void bshw_set_poll_trans __P((struct bs_softc *, u_int));
+static BS_INLINE void bshw_set_dma_trans __P((struct bs_softc *, u_int));
+
+/*********************************************************
+ * global declare
+ *********************************************************/
+void bs_dma_xfer __P((struct targ_info *, u_int));
+void bs_dma_xfer_end __P((struct targ_info *));
+void bshw_dmaabort __P((struct bs_softc *, struct targ_info *));
+
+void bshw_adj_syncdata __P((struct syncdata *));
+void bshw_set_synchronous __P((struct bs_softc *, struct targ_info *));
+
+void bs_smit_xfer_end __P((struct targ_info *));
+void bshw_smitabort __P((struct bs_softc *));
+
+void bshw_setup_ctrl_reg __P((struct bs_softc *, u_int));
+int bshw_chip_reset __P((struct bs_softc *));
+void bshw_bus_reset __P((struct bs_softc *));
+int bshw_board_probe __P((struct bs_softc *, u_int *, u_int *));
+void bshw_lock __P((struct bs_softc *));
+void bshw_unlock __P((struct bs_softc *));
+void bshw_get_syncreg __P((struct bs_softc *));
+void bshw_issue_satcmd __P((struct bs_softc *, struct ccb *, int));
+void bshw_print_port __P((struct bs_softc *));
+
+void bs_lc_smit_xfer __P((struct targ_info *, u_int));
+
+extern struct dvcfg_hwsel bshw_hwsel;
+extern u_int8_t bshw_cmd[];
+
+/*********************************************************
+ * hw
+ *********************************************************/
+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 bs_softc *)));
+ void ((*dma_start) __P((struct bs_softc *)));
+ void ((*dma_stop) __P((struct bs_softc *)));
+};
+
+/*********************************************************
+ * inline funcs.
+ *********************************************************/
+/*
+ * XXX: If your board does not work well, Please try BS_NEEDS_WEIGHT.
+ */
+static BS_INLINE void
+write_wd33c93(bsc, addr, data)
+ struct bs_softc *bsc;
+ u_int addr;
+ u_int8_t data;
+{
+
+ BUS_IOW(addr_port, addr);
+ BUS_IOW(ctrl_port, data);
+}
+
+static BS_INLINE u_int8_t
+read_wd33c93(bsc, addr)
+ struct bs_softc *bsc;
+ u_int addr;
+{
+
+ BUS_IOW(addr_port, addr);
+ return BUS_IOR(ctrl_port);
+}
+
+/* status */
+static BS_INLINE u_int8_t
+bshw_get_auxstat(bsc)
+ struct bs_softc *bsc;
+{
+
+ return BUS_IOR(stat_port);
+}
+
+static BS_INLINE u_int8_t
+bshw_get_busstat(bsc)
+ struct bs_softc *bsc;
+{
+
+ return read_wd33c93(bsc, wd3s_stat);
+}
+
+static BS_INLINE u_int8_t
+bshw_get_status_insat(bsc)
+ struct bs_softc *bsc;
+{
+
+ return read_wd33c93(bsc, wd3s_lun);
+}
+
+/* data */
+static BS_INLINE u_int8_t
+bshw_read_data(bsc)
+ struct bs_softc *bsc;
+{
+
+ return read_wd33c93(bsc, wd3s_data);
+}
+
+static BS_INLINE void
+bshw_write_data(bsc, data)
+ struct bs_softc *bsc;
+ u_int8_t data;
+{
+
+ write_wd33c93(bsc, wd3s_data, data);
+}
+
+/* counter */
+static BS_INLINE void
+bshw_set_count(bsc, count)
+ struct bs_softc *bsc;
+ u_int count;
+{
+
+ BUS_IOW(addr_port, wd3s_cnt);
+ BUS_IOW(ctrl_port, count >> 16);
+ BUS_IOW(ctrl_port, count >> 8);
+ BUS_IOW(ctrl_port, count);
+}
+
+static BS_INLINE u_int
+bshw_get_count(bsc)
+ struct bs_softc *bsc;
+{
+ u_int count;
+
+ BUS_IOW(addr_port, wd3s_cnt);
+ count = (((u_int) BUS_IOR(ctrl_port)) << 16);
+ count += (((u_int) BUS_IOR(ctrl_port)) << 8);
+ count += ((u_int) BUS_IOR(ctrl_port));
+ return count;
+}
+
+/* ID */
+static BS_INLINE void
+bshw_set_lun(bsc, lun)
+ struct bs_softc *bsc;
+ u_int lun;
+{
+
+ write_wd33c93(bsc, wd3s_lun, lun);
+}
+
+static BS_INLINE void
+bshw_set_dst_id(bsc, target, lun)
+ struct bs_softc *bsc;
+ u_int target, lun;
+{
+
+ write_wd33c93(bsc, wd3s_did, target);
+ write_wd33c93(bsc, wd3s_lun, lun);
+}
+
+static BS_INLINE u_int
+bshw_get_src_id(bsc)
+ struct bs_softc *bsc;
+{
+
+ return (read_wd33c93(bsc, wd3s_sid) & SIDR_IDM);
+}
+
+/* phase */
+static BS_INLINE void
+bshw_negate_ack(bsc)
+ struct bs_softc *bsc;
+{
+
+ write_wd33c93(bsc, wd3s_cmd, WD3S_NEGATE_ACK);
+}
+
+static BS_INLINE void
+bshw_assert_atn(bsc)
+ struct bs_softc *bsc;
+{
+
+ write_wd33c93(bsc, wd3s_cmd, WD3S_ASSERT_ATN);
+}
+
+static BS_INLINE void
+bshw_assert_select(bsc)
+ struct bs_softc *bsc;
+{
+
+ write_wd33c93(bsc, wd3s_cmd, WD3S_SELECT_ATN);
+}
+
+static BS_INLINE void
+bshw_start_xfer(bsc)
+ struct bs_softc *bsc;
+{
+
+ write_wd33c93(bsc, wd3s_cmd, WD3S_TFR_INFO);
+}
+
+static BS_INLINE void
+bshw_start_sxfer(bsc)
+ struct bs_softc *bsc;
+{
+
+ write_wd33c93(bsc, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO);
+}
+
+static BS_INLINE void
+bshw_cmd_pass(bsc, ph)
+ struct bs_softc *bsc;
+ u_int ph;
+{
+
+ write_wd33c93(bsc, wd3s_cph, ph);
+}
+
+static BS_INLINE void
+bshw_start_sat(bsc, flag)
+ struct bs_softc *bsc;
+ u_int flag;
+{
+
+ write_wd33c93(bsc, wd3s_cmd,
+ (flag ? WD3S_SELECT_ATN_TFR : WD3S_SELECT_NO_ATN_TFR));
+}
+
+
+static BS_INLINE void
+bshw_abort_cmd(bsc)
+ struct bs_softc *bsc;
+{
+
+ write_wd33c93(bsc, wd3s_cmd, WD3S_ABORT);
+}
+
+/* transfer mode */
+static BS_INLINE void
+bshw_set_sync_reg(bsc, val)
+ struct bs_softc *bsc;
+ u_int val;
+{
+
+ write_wd33c93(bsc, wd3s_synch, val);
+}
+
+static BS_INLINE void
+bshw_set_poll_trans(bsc, flags)
+ struct bs_softc *bsc;
+ u_int flags;
+{
+
+ if (bsc->sc_flags & BSDMATRANSFER)
+ {
+ bsc->sc_flags &= ~BSDMATRANSFER;
+ bshw_setup_ctrl_reg(bsc, flags);
+ }
+}
+
+static BS_INLINE void
+bshw_set_dma_trans(bsc, flags)
+ struct bs_softc *bsc;
+ u_int flags;
+{
+
+ if ((bsc->sc_flags & BSDMATRANSFER) == 0)
+ {
+ bsc->sc_flags |= BSDMATRANSFER;
+ bshw_setup_ctrl_reg(bsc, flags);
+ }
+}
+
+static BS_INLINE void memcopy __P((void *from, void *to, register size_t len));
+
+static BS_INLINE void
+memcopy(from, to, len)
+ void *from, *to;
+ register size_t len;
+{
+
+ len >>= 2;
+ __asm __volatile("cld\n\trep\n\tmovsl" : :
+ "S" (from), "D" (to), "c" (len) :
+ "%esi", "%edi", "%ecx");
+}
diff --git a/sys/i386/isa/bs/bshw.lst b/sys/i386/isa/bs/bshw.lst
new file mode 100644
index 0000000..2a3f232
--- /dev/null
+++ b/sys/i386/isa/bs/bshw.lst
@@ -0,0 +1,113 @@
+/* $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.
+ */
+
+static struct bshw bshw_generic = {
+ BSHW_SYNC_RELOAD,
+
+ 0,
+
+ NULL,
+ NULL,
+ NULL,
+};
+
+static int bshw_dma_init_sc98 __P((struct bs_softc *));
+static void bshw_dma_start_sc98 __P((struct bs_softc *));
+static void bshw_dma_stop_sc98 __P((struct bs_softc *));
+static struct bshw bshw_sc98 = {
+ BSHW_DOUBLE_DMACHAN,
+
+ 0x60,
+
+ bshw_dma_init_sc98,
+ bshw_dma_start_sc98,
+ bshw_dma_stop_sc98,
+};
+
+static int bshw_dma_init_texa __P((struct bs_softc *));
+static struct bshw bshw_texa = {
+ BSHW_DOUBLE_DMACHAN,
+
+ 0x60,
+
+ bshw_dma_init_texa,
+ NULL,
+ NULL,
+};
+
+static void bshw_dma_start_elecom __P((struct bs_softc *));
+static void bshw_dma_stop_elecom __P((struct bs_softc *));
+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/i386/isa/bs/bshw_dma.c b/sys/i386/isa/bs/bshw_dma.c
new file mode 100644
index 0000000..22051a9
--- /dev/null
+++ b/sys/i386/isa/bs/bshw_dma.c
@@ -0,0 +1,339 @@
+/* $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.
+ */
+
+/*********************************************************
+ * static declare.
+ *********************************************************/
+static BS_INLINE void bshw_dmastart __P((struct bs_softc *));
+static void bshw_dmadone __P((struct bs_softc *));
+
+/**********************************************
+ * UPPER INTERFACE FUNCS (all funcs exported)
+ **********************************************/
+void
+bshw_dmaabort(bsc, ti)
+ struct bs_softc *bsc;
+ struct targ_info *ti;
+{
+
+ bshw_dmadone(bsc);
+ bsc->sc_p.seglen = 0;
+ bshw_set_count(bsc, 0);
+
+ if (ti == NULL)
+ {
+ int i;
+ struct targ_info *tmpti;
+
+ for (i = 0; i < NTARGETS; i++)
+ if (tmpti = bsc->sc_ti[i])
+ tmpti->ti_scsp.seglen = 0;
+ }
+ else
+ ti->ti_scsp.seglen = 0;
+}
+
+/* DMA TRANSFER */
+void
+bs_dma_xfer(ti, direction)
+ struct targ_info *ti;
+ u_int direction;
+{
+ vm_offset_t va, endva, phys, nphys;
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct sc_p *sp = &bsc->sc_p;
+
+ bsc->sc_dmadir = direction;
+ bshw_set_dma_trans(bsc, ti->ti_cfgflags);
+
+ if (sp->seglen == 0)
+ {
+ phys = vtophys((vm_offset_t) sp->data);
+ if (phys >= RAM_END)
+ {
+ /* setup segaddr */
+ sp->segaddr = ti->bounce_phys;
+ /* setup seglen */
+ sp->seglen = sp->datalen;
+ if (sp->seglen > ti->bounce_size)
+ sp->seglen = ti->bounce_size;
+ /* setup bufp */
+ sp->bufp = ti->bounce_addr;
+ if (bsc->sc_dmadir != BSHW_READ)
+ bcopy(sp->data, sp->bufp, sp->seglen);
+#ifdef BS_STATICS
+ bs_bounce_used[ti->ti_id]++;
+#endif /* BS_STATICS */
+ }
+ else
+ {
+ /* setup segaddr */
+ sp->segaddr = (u_int8_t *) phys;
+ /* setup seglen */
+ endva = (vm_offset_t)round_page(sp->data + sp->datalen);
+ for (va = (vm_offset_t) sp->data; ; phys = nphys)
+ {
+ if ((va += BSHW_NBPG) >= endva)
+ {
+ sp->seglen = sp->datalen;
+ break;
+ }
+
+ nphys = vtophys(va);
+ if (phys + BSHW_NBPG != nphys || nphys >= RAM_END)
+ {
+ sp->seglen =
+ (u_int8_t *) trunc_page(va) - sp->data;
+ break;
+ }
+ }
+ /* setup bufp */
+ sp->bufp = NULL;
+ }
+ }
+
+ bshw_dmastart(bsc);
+ bshw_set_count(bsc, sp->seglen);
+}
+
+void
+bs_dma_xfer_end(ti)
+ struct targ_info *ti;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct sc_p *sp = &bsc->sc_p;
+ u_int count, transbytes;
+
+ bshw_dmadone(bsc);
+ if (ti->ti_phase == DATAPHASE)
+ {
+ count = bshw_get_count(bsc);
+ if (count < (u_int) sp->seglen)
+ {
+ transbytes = sp->seglen - count;
+ if (sp->bufp)
+ {
+ if (bsc->sc_dmadir == BSHW_READ)
+ bcopy(sp->bufp, sp->data, transbytes);
+ sp->bufp += transbytes;
+ }
+ sp->seglen = count;
+ sp->segaddr += transbytes;
+ sp->data += transbytes;
+ sp->datalen -= transbytes;
+ return;
+ }
+ else if (count == (u_int) sp->seglen)
+ {
+ return;
+ }
+
+ bs_printf(ti, "xfer_end", "strange count");
+ printf("port data %x seglen %x\n", count, sp->seglen);
+ }
+ else
+ bs_printf(ti, "xfer_end", "extra dma interrupt");
+
+ ti->ti_error |= BSDMAABNORMAL;
+ sp->seglen = ti->ti_scsp.seglen = 0; /* XXX */
+}
+
+/**********************************************
+ * GENERIC DMA FUNCS
+ **********************************************/
+static short dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 };
+
+/* common dma settings */
+#undef DMA1_SMSK
+#define DMA1_SMSK (IO_DMA + 0x14)
+#undef DMA1_MODE
+#define DMA1_MODE (IO_DMA + 0x16)
+#undef DMA1_FFC
+#define DMA1_FFC (IO_DMA + 0x18)
+#undef DMA37SM_SET
+#define DMA37SM_SET 0x04
+#undef DMA1_CHN
+#define DMA1_CHN(c) (IO_DMA + ((c) << 2))
+
+static BS_INLINE void
+bshw_dmastart(bsc)
+ struct bs_softc *bsc;
+{
+ int chan = bsc->sc_dmachan;
+ int waport;
+ u_int8_t *phys = bsc->sc_p.segaddr;
+ u_int nbytes = bsc->sc_p.seglen;
+
+ /*
+ * Program one of DMA channels 0..3. These are
+ * byte mode channels.
+ */
+ /* set dma channel mode, and reset address ff */
+#ifdef __FreeBSD__
+#ifdef CYRIX_5X86
+ asm("wbinvd");
+#endif
+#else /* NetBSD/pc98 */
+ if (cpuspec->cpuspec_cache_flush_before)
+ (*cpuspec->cpuspec_cache_flush_before)();
+#endif
+
+ if (bsc->sc_dmadir & BSHW_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 (bsc->sc_hw->dma_start)
+ (*bsc->sc_hw->dma_start)(bsc);
+
+ outb(DMA1_SMSK, chan);
+ BUS_IOW(cmd_port, CMDP_DMES);
+
+ bsc->sc_flags |= BSDMASTART;
+}
+
+static void
+bshw_dmadone(bsc)
+ struct bs_softc *bsc;
+{
+
+ outb(DMA1_SMSK, (bsc->sc_dmachan | DMA37SM_SET));
+ BUS_IOW(cmd_port, CMDP_DMER);
+
+ /* vendor unique hook */
+ if (bsc->sc_hw->dma_stop)
+ (*bsc->sc_hw->dma_stop)(bsc);
+
+#ifdef __FreeBSD__
+#if defined(CYRIX_486DLC) || defined(IBM_486SLC)
+ asm(".byte 0x0f, 0x08");
+#endif
+#else
+ if (cpuspec->cpuspec_cache_flush_after)
+ (*cpuspec->cpuspec_cache_flush_after)();
+#endif
+
+ bsc->sc_flags &= (~BSDMASTART);
+}
+
+/**********************************************
+ * VENDOR UNIQUE DMA FUNCS
+ **********************************************/
+static int
+bshw_dma_init_texa(bsc)
+ struct bs_softc *bsc;
+{
+ u_int8_t regval;
+
+ if ((regval = read_wd33c93(bsc, 0x37)) & 0x08)
+ return 0;
+
+ write_wd33c93(bsc, 0x37, regval | 0x08);
+ regval = read_wd33c93(bsc, 0x3f);
+ write_wd33c93(bsc, 0x3f, regval | 0x08);
+ return 1;
+}
+
+static int
+bshw_dma_init_sc98(bsc)
+ struct bs_softc *bsc;
+{
+
+ if (read_wd33c93(bsc, 0x37) & 0x08)
+ return 0;
+
+ /* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */
+ write_wd33c93(bsc, 0x37, 0x1a);
+ write_wd33c93(bsc, 0x3f, 0x1a);
+#if 0
+ /* only valid for IO */
+ write_wd33c93(bsc, 0x40, 0xf4);
+ write_wd33c93(bsc, 0x41, 0x9);
+ write_wd33c93(bsc, 0x43, 0xff);
+ write_wd33c93(bsc, 0x46, 0x4e);
+
+ write_wd33c93(bsc, 0x48, 0xf4);
+ write_wd33c93(bsc, 0x49, 0x9);
+ write_wd33c93(bsc, 0x4b, 0xff);
+ write_wd33c93(bsc, 0x4e, 0x4e);
+#endif
+ return 1;
+}
+
+static void
+bshw_dma_start_sc98(bsc)
+ struct bs_softc *bsc;
+{
+
+ write_wd33c93(bsc, 0x73, 0x32);
+ write_wd33c93(bsc, 0x74, 0x23);
+}
+
+static void
+bshw_dma_stop_sc98(bsc)
+ struct bs_softc *bsc;
+{
+
+ write_wd33c93(bsc, 0x73, 0x43);
+ write_wd33c93(bsc, 0x74, 0x34);
+}
+
+static void
+bshw_dma_start_elecom(bsc)
+ struct bs_softc *bsc;
+{
+ u_int8_t tmp = read_wd33c93(bsc, 0x4c);
+
+ write_wd33c93(bsc, 0x32, tmp & 0xdf);
+}
+
+static void
+bshw_dma_stop_elecom(bsc)
+ struct bs_softc *bsc;
+{
+ u_int8_t tmp = read_wd33c93(bsc, 0x4c);
+
+ write_wd33c93(bsc, 0x32, tmp | 0x20);
+}
diff --git a/sys/i386/isa/bs/bshw_pdma.c b/sys/i386/isa/bs/bshw_pdma.c
new file mode 100644
index 0000000..612db73
--- /dev/null
+++ b/sys/i386/isa/bs/bshw_pdma.c
@@ -0,0 +1,242 @@
+/* $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.
+ */
+
+#define LC_SMIT_TIMEOUT 2 /* 2 sec: timeout for a fifo status ready */
+
+static BS_INLINE void bshw_lc_smit_start __P((struct bs_softc *, int, u_int));
+static int bshw_lc_smit_fstat __P((struct bs_softc *, int, int));
+static BS_INLINE void bshw_lc_smit_stop __P((struct bs_softc *));
+
+/*********************************************************
+ * SM FIFO (GENERIC)
+ *********************************************************/
+void
+bshw_smitabort(bsc)
+ struct bs_softc *bsc;
+{
+ if (bsc->sc_hw->hw_flags & BSHW_SMFIFO)
+ bshw_lc_smit_stop(bsc);
+
+ bshw_set_count(bsc, 0);
+ bsc->sc_flags &= ~BSSMITSTART;
+}
+
+void
+bs_smit_xfer_end(ti)
+ struct targ_info *ti;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct sc_p *sp = &bsc->sc_p;
+ u_int count;
+ u_char *s;
+
+ bshw_lc_smit_stop(bsc);
+ bsc->sc_flags &= ~BSSMITSTART;
+
+ if (ti->ti_phase == DATAPHASE)
+ {
+ count = bshw_get_count(bsc);
+ if (count < (u_int) sp->datalen)
+ {
+ sp->data += (sp->datalen - count);
+ sp->datalen = count;
+ /* XXX:
+ * strict double checks!
+ * target => wd33c93c transfer counts
+ * wd33c93c => memory transfer counts
+ */
+ if ((bsc->sc_dmadir & BSHW_READ) &&
+ count != bsc->sm_tdatalen)
+ {
+ s = "read count miss";
+ goto bad;
+ }
+ return;
+ }
+ else if (count == (u_int) sp->datalen)
+ {
+ return;
+ }
+
+ s = "strange count";
+ }
+ else
+ s = "extra smit interrupt";
+
+bad:
+ bs_printf(ti, "smit_xfer_end", s);
+ ti->ti_error |= BSDMAABNORMAL;
+}
+
+/*********************************************************
+ * LOGITEC's SMIT TRANSFER
+ *********************************************************/
+
+#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
+
+#define LC_FSZ DEV_BSIZE
+#define LC_SFSZ 0x0c
+#define LC_REST (LC_FSZ - LC_SFSZ)
+
+static BS_INLINE void
+bshw_lc_smit_stop(bsc)
+ struct bs_softc *bsc;
+{
+
+ write_wd33c93(bsc, BSHW_LC_FCTRL, 0);
+ BUS_IOW(cmd_port, CMDP_DMER);
+}
+
+static BS_INLINE void
+bshw_lc_smit_start(bsc, count, direction)
+ struct bs_softc *bsc;
+ int count;
+ u_int direction;
+{
+ u_int8_t pval, val = read_wd33c93(bsc, BSHW_LC_FSET);
+
+ bsc->sc_flags |= BSSMITSTART;
+ bshw_set_count(bsc, count);
+
+ pval = FCTRL_EN;
+ if ((direction & BSHW_READ) == 0)
+ pval |= (val & 0xe0) | FCTRL_WRITE;
+ write_wd33c93(bsc, BSHW_LC_FCTRL, pval);
+ bshw_start_xfer(bsc);
+}
+
+static int
+bshw_lc_smit_fstat(bsc, wc, read)
+ struct bs_softc *bsc;
+ int wc, read;
+{
+ u_int8_t stat;
+
+#define ALWAYS_ABORT
+#ifdef ALWAYS_ABORT
+ if (read == BSHW_READ)
+ {
+ while (wc -- > 0)
+ {
+ BUS_IO_WEIGHT;
+ stat = BUS_IOR(cmd_port);
+ if (stat & SF_RDY)
+ return 0;
+ if (stat & SF_ABORT)
+ return EIO;
+ }
+ }
+ else
+ {
+#endif /* ALWAYS_ABORT */
+ while (wc -- > 0)
+ {
+ BUS_IO_WEIGHT;
+ stat = BUS_IOR(cmd_port);
+ if (stat & SF_ABORT)
+ return EIO;
+ if (stat & SF_RDY)
+ return 0;
+ }
+#ifdef ALWAYS_ABORT
+ }
+#endif /* ALWAYS_ABORT */
+
+ bs_poll_timeout(bsc, "bshw_lc_smit");
+ return EIO;
+}
+
+void
+bs_lc_smit_xfer(ti, direction)
+ struct targ_info *ti;
+ u_int direction;
+{
+ struct bs_softc *bsc = ti->ti_bsc;
+ struct sc_p *sp = &bsc->sc_p;
+ int datalen, count, wc = LC_SMIT_TIMEOUT * 1024 * 1024;
+ u_int8_t *data;
+
+ sp->bufp = NULL;
+ sp->seglen = 0;
+ data = sp->data;
+ datalen = sp->datalen;
+
+ bsc->sc_dmadir = direction;
+ bshw_set_dma_trans(bsc, ti->ti_cfgflags);
+ bshw_lc_smit_start(bsc, sp->datalen, direction);
+
+ if (direction & BSHW_READ)
+ {
+ do
+ {
+ if (bshw_lc_smit_fstat(bsc, wc, BSHW_READ))
+ break;
+
+ count = (datalen > LC_FSZ ? LC_FSZ : datalen);
+ memcopy(ti->sm_vaddr, data, count);
+ data += count;
+ datalen -= count;
+ }
+ while (datalen > 0);
+
+ bsc->sm_tdatalen = datalen;
+ }
+ else
+ {
+ do
+ {
+ if (bshw_lc_smit_fstat(bsc, wc, BSHW_WRITE))
+ break;
+
+ count = (datalen > LC_SFSZ ? LC_SFSZ : datalen);
+ memcopy(data, ti->sm_vaddr, count);
+ data += count;
+ datalen -= count;
+
+ if (bshw_lc_smit_fstat(bsc, wc, BSHW_WRITE))
+ break;
+
+ count = (datalen > LC_REST ? LC_REST : datalen);
+ memcopy(data, ti->sm_vaddr + LC_SFSZ, count);
+ data += count;
+ datalen -= count;
+ }
+ while (datalen > 0);
+ }
+}
diff --git a/sys/i386/isa/bs/bsif.c b/sys/i386/isa/bs/bsif.c
new file mode 100644
index 0000000..08dc069
--- /dev/null
+++ b/sys/i386/isa/bs/bsif.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) HONDA Naofumi, KATO Takenori, 1996. 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 as
+ * the first lines of this file unmodified.
+ * 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.
+ * 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.
+ */
+
+#if 0
+/* WARNING: Any bug report must contain BS_REL_VERSION */
+#define BS_REL_VERSION "NetBSD1.2/030" /* major jump */
+#endif
+
+#ifdef __NetBSD__
+#include <dev/isa/bs/bsif.h>
+#endif /* __NetBSD__ */
+#ifdef __FreeBSD__
+#include "bs.h"
+#include <i386/isa/bs/bsif.h>
+#endif /* __FreeBSD__ */
+
+/**************************************************
+ * DEVICE DECLARE
+ **************************************************/
+#ifdef __NetBSD__
+int bsintr __P((void *));
+static int bsprint __P((void *, char *));
+static void bs_scsi_minphys __P((struct buf *));
+
+struct cfdriver bs_cd = {
+ NULL, "bs", DV_DULL
+};
+
+struct scsi_device bs_dev = {
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+
+struct scsi_adapter pc98texa55bs = {
+ bs_scsi_cmd,
+ bs_scsi_minphys,
+ bs_target_open,
+ 0,
+};
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+static int bsprobe __P((struct isa_device *));
+static int bsattach __P((struct isa_device *));
+static int bsprint __P((void *, char *));
+static void bs_scsi_minphys __P((struct buf *));
+static int bs_dmarangecheck __P((caddr_t, unsigned));
+
+struct isa_driver bsdriver = {
+ bsprobe,
+ bsattach,
+ "bs"
+};
+
+struct scsi_device bs_dev = {
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "bs",
+ 0, {0, 0}
+};
+
+u_int32_t
+bs_adapter_info(unit)
+ int unit;
+{
+ return (1);
+}
+
+struct scsi_adapter pc98texa55bs = {
+ bs_scsi_cmd,
+ bs_scsi_minphys,
+ bs_target_open,
+ 0,
+ bs_adapter_info,
+ "bs", {0, 0}
+};
+
+static u_short pc98_irq_ball[16] = {
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ IRQ8, IRQ9, IRQ10, IRQ11, IRQ12, IRQ13, IRQ14, IRQ15
+};
+
+static struct bs_softc *bscdata[NBS];
+#endif /* __FreeBSD__ */
+
+/*****************************************************************
+ * OS <=> BS INTERFACE
+ *****************************************************************/
+#ifdef __FreeBSD__
+static int
+bsprobe(dev)
+ struct isa_device *dev;
+#else /* __NetBSD__ */
+int
+bsprobe(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+#endif /* __NetBSD__ */
+{
+#ifdef __FreeBSD__
+ struct bs_softc *bsc;
+ int unit = dev->id_unit;
+#else /* __NetBSD__ */
+ struct bs_softc *bsc = (void *) self;
+ struct isa_attach_args *ia = aux;
+ bus_chipset_tag_t bc = ia->ia_bc;
+#endif /* __NetBSD__ */
+ u_int irq, drq;
+ int i, rv = 0;
+
+#ifdef __FreeBSD__
+ if (unit >= NBS) {
+ printf("bs%d: unit number too high\n", unit);
+ return rv;
+ }
+ /*
+ * Allocate a storage for us
+ */
+ if (bscdata[unit]) {
+ printf("bs%d: memory already allocated\n", unit);
+ return rv;
+ }
+ if (!(bsc = malloc(sizeof(struct bs_softc), M_TEMP, M_NOWAIT))) {
+ printf("bs%d cannot malloc!\n", unit);
+ return rv;
+ }
+ bzero(bsc, sizeof(struct bs_softc));
+ bscdata[unit] = bsc;
+ bsc->unit = unit;
+#endif /* __FreeBSD__ */
+
+#ifdef __FreeBSD__
+ bsc->sc_cfgflags = DVCFG_MINOR(dev->id_flags);
+ bsc->sc_hw = DVCFG_HW(&bshw_hwsel, DVCFG_MAJOR(dev->id_flags));
+#else /* __NetBSD__ */
+ bsc->sc_cfgflags = DVCFG_MINOR(ia->ia_cfgflags);
+ bsc->sc_hw = DVCFG_HW(&bshw_hwsel, DVCFG_MAJOR(ia->ia_cfgflags));
+#endif /* __NetBSD__ */
+ if (bsc->sc_hw == NULL)
+ return rv;
+
+#ifdef __FreeBSD__
+ if ((bsc->sc_hw->hw_flags & BSHW_SMFIFO) &&
+ (dev->id_maddr != (caddr_t)MADDRUNK))
+ bsc->sm_vaddr = (u_int8_t *) dev->id_maddr;
+ else
+ bsc->sm_vaddr = (u_int8_t *) MADDRUNK;
+#else /* __NetBSD__ */
+ if ((bsc->sc_hw->hw_flags & BSHW_SMFIFO) && (ia->ia_maddr != MADDRUNK))
+ {
+ ia->ia_maddr &= ~((NBPG * 2) - 1);
+ ia->ia_maddr += NBPG;
+ ia->ia_msize = NBPG;
+ if (bus_mem_map(bc, ia->ia_maddr, NBPG, 0, &bsc->sc_memh))
+ return 0;
+ bsc->sm_vaddr = (u_int8_t *) bsc->sc_memh; /* XXX */
+ }
+ else
+ {
+ bsc->sm_vaddr = (u_int8_t *) MADDRUNK;
+ ia->ia_msize = 0;
+ }
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+ sprintf(bsc->sc_dvname, "bs%d", unit);
+#else /* __NetBSD__ */
+ strcpy(bsc->sc_dvname, bsc->sc_dev.dv_xname);
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+ if (dev->id_iobase == 0)
+#else /* __NetBSD__ */
+ if (ia->ia_iobase == IOBASEUNK)
+#endif /* __NetBSD__ */
+ {
+ printf("%s: iobase not specified. Assume default port(0x%x)\n",
+ bsc->sc_dvname, BSHW_DEFAULT_PORT);
+#ifdef __FreeBSD__
+ dev->id_iobase = BSHW_DEFAULT_PORT;
+#else /* __NetBSD__ */
+ ia->ia_iobase = BSHW_DEFAULT_PORT;
+#endif /* __NetBSD__ */
+ }
+
+#ifdef __FreeBSD__
+ bsc->sc_iobase = dev->id_iobase;
+#else /* __NetBSD__ */
+ bsc->sc_iobase = ia->ia_iobase;
+ bsc->sc_bc = bc;
+ bsc->sc_delayioh = ia->ia_delayioh;
+ if (bus_io_map(bsc->sc_bc, bsc->sc_iobase, BSHW_IOSZ, &bsc->sc_ioh))
+ return rv;
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+ irq = IRQUNK;
+ drq = DRQUNK;
+#else /* __NetBSD__ */
+ irq = ia->ia_irq;
+ drq = ia->ia_drq;
+#endif /* __NetBSD__ */
+ if (bshw_board_probe(bsc, &drq, &irq))
+ goto bad;
+
+#ifdef __FreeBSD__
+ dev->id_irq = pc98_irq_ball[irq];
+ dev->id_drq = (short)drq;
+#else /* __NetBSD__ */
+ ia->ia_irq = irq;
+ ia->ia_drq = drq;
+#endif /* __NetBSD__ */
+
+ /* initialize host queue and target info */
+ bs_hostque_init(bsc);
+ for (i = 0; i < NTARGETS; i++)
+ if (i != bsc->sc_hostid)
+ bs_init_target_info(bsc, i);
+
+ /* initialize ccb queue */
+ bs_init_ccbque(BS_MAX_CCB);
+
+#ifdef __NetBSD__
+ /* init port data */
+ ia->ia_iosize = BSHW_IOSZ;
+#endif /* __NetBSD__ */
+
+ /* scsi bus reset and restart */
+ bsc->sc_hstate = BSC_BOOTUP;
+ bsc->sc_retry = RETRIES;
+ bsc->sc_wc = delaycount * 250; /* about 1 sec */
+ bs_reset_nexus(bsc);
+
+#ifdef __FreeBSD__
+ return BSHW_IOSZ;
+bad:
+ return rv;
+#else /* __NetBSD__ */
+ rv = 1;
+bad:
+ bus_io_unmap(bsc->sc_bc, bsc->sc_ioh, BSHW_IOSZ);
+ return rv;
+#endif /* __NetBSD__ */
+}
+
+static int
+bsprint(aux, name)
+ void *aux;
+ char *name;
+{
+
+ if (name != NULL)
+ printf("%s: scsibus ", name);
+ return UNCONF;
+}
+
+#ifdef __FreeBSD__
+static int
+bsattach(dev)
+ struct isa_device *dev;
+#else /* __NetBSD__ */
+void
+bsattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+#endif /* __NetBSD__ */
+{
+#ifdef __FreeBSD__
+ int unit = dev->id_unit;
+ struct bs_softc *bsc = bscdata[unit];
+ struct scsibus_data *scbus;
+#else /* __NetBSD__ */
+ struct bs_softc *bsc = (void *) self;
+ struct isa_attach_args *ia = aux;
+
+ printf("\n");
+#endif /* __NetBSD__ */
+
+#ifdef __NetBSD__
+ bsc->sc_iobase = ia->ia_iobase;
+ bsc->sc_bc = ia->ia_bc;
+ bsc->sc_delayioh = ia->ia_delayioh;
+ if (bus_io_map(bsc->sc_bc, bsc->sc_iobase, BSHW_IOSZ, &bsc->sc_ioh))
+ panic("%s: bus io map failed\n", bsc->sc_dev.dv_xname);
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+ bsc->sc_link.adapter_unit = unit;
+ bsc->sc_link.adapter_targ = bsc->sc_hostid;
+ bsc->sc_link.flags = SDEV_BOUNCE;
+ bsc->sc_link.opennings = XSMAX;
+#else /* __NetBSD__ */
+ bsc->sc_link.adapter_target = bsc->sc_hostid;
+ bsc->sc_link.openings = XSMAX;
+#endif /* __NetBSD__ */
+ bsc->sc_link.adapter_softc = bsc;
+ bsc->sc_link.adapter = &pc98texa55bs;
+ bsc->sc_link.device = &bs_dev;
+
+#ifdef __FreeBSD__
+ /*
+ * Prepare the scsibus_data area for the upperlevel
+ * scsi code.
+ */
+ scbus = scsi_alloc_bus();
+ if (!scbus)
+ return 0;
+ scbus->adapter_link = &bsc->sc_link;
+ /*
+ * ask the adapter what subunits are present
+ */
+ scsi_attachdevs(scbus);
+#else /* __NetBSD__ */
+ bsc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
+ IPL_BIO, bsintr, bsc);
+ config_found(self, &bsc->sc_link, bsprint);
+#endif /* __NetBSD__ */
+ bs_start_timeout(bsc);
+#ifdef __FreeBSD__
+ return 1;
+#endif /* __FreeBSD__ */
+}
+
+#ifdef __NetBSD__
+int
+bsintr(arg)
+ void *arg;
+{
+
+ return bs_sequencer((struct bs_softc *)arg);
+}
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+void
+bsintr(unit)
+ int unit;
+{
+ (void)bs_sequencer(bscdata[unit]);
+}
+#endif /* __FreeBSD__ */
+
+/*****************************************************************
+ * JULIAN SCSI <=> BS INTERFACE
+ *****************************************************************/
+static void
+bs_scsi_minphys(bp)
+ struct buf *bp;
+{
+
+ if (bp->b_bcount > BSDMABUFSIZ)
+ bp->b_bcount = BSDMABUFSIZ;
+ minphys(bp);
+}
+
+XSBS_INT32T
+bs_target_open(sc, cf)
+ struct scsi_link *sc;
+ struct cfdata *cf;
+{
+ u_int target = sc->target;
+ struct bs_softc *bsc = (struct bs_softc *) (sc->adapter_softc);
+ struct targ_info *ti = bsc->sc_ti[target];
+ u_int flags;
+
+ if ((bsc->sc_openf & (1 << target)) == 0)
+ return ENODEV;
+
+ if ((flags = cf->cf_flags) == 0)
+ flags = BS_SCSI_DEFCFG;
+
+ bs_setup_ctrl(ti, (u_int)sc->quirks, flags);
+ return 0;
+}
+
+/*****************************************************************
+ * BS MEMORY ALLOCATION INTERFACE
+ *****************************************************************/
+#ifdef __NetBSD__
+void
+bs_alloc_buf(ti)
+ struct targ_info *ti;
+{
+ extern int cold;
+ caddr_t addr, physaddr;
+ u_int pages;
+
+ /* XXX:
+ * strategy change!
+ * A) total memory >= 16M at boot: MAXBSIZE * 7 = 112k.
+ * B) others: 4K * 7 = 28 K.
+ */
+ if (get_sysinfo(SYSINFO_MEMLEVEL) == MEM_LEVEL1 && cold != 0)
+ pages = 4;
+ else
+ pages = 1;
+
+ ti->bounce_size = NBPG * pages;
+ if ((addr = alloc_bounce_buffer(ti->bounce_size)) == NULL)
+ {
+ ti->bounce_size = NBPG;
+ if ((addr = malloc(NBPG, M_DEVBUF, M_NOWAIT)) == NULL)
+ goto bad;
+ }
+
+ physaddr = (caddr_t) vtophys(addr);
+ if ((u_int) physaddr >= RAM_END)
+ {
+ /* XXX: mem from malloc only! */
+ free(addr, M_DEVBUF);
+ goto bad;
+ }
+
+ ti->bounce_addr = (u_int8_t *) addr;
+ ti->bounce_phys = (u_int8_t *) physaddr;
+ return;
+
+bad:
+ bs_printf(ti, "bs_alloc_buf", "no phys bounce buffer");
+ printf("WARNING: this target is dislocated\n");
+}
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+static int bs_dmarangecheck(caddr_t va, unsigned length)
+{
+ vm_offset_t phys, priorpage = 0, endva;
+
+ endva = (vm_offset_t)round_page(va+length);
+ for (; va < (caddr_t)endva; va += PAGE_SIZE) {
+ phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
+ if (phys == 0)
+ panic("bs_dmarangecheck: no physical page present");
+ if (phys >= RAM_END)
+ return 1;
+ if (priorpage) {
+ if (priorpage + PAGE_SIZE != phys)
+ return 1;
+ }
+ priorpage = phys;
+ }
+ return 0;
+}
+
+void
+bs_alloc_buf(ti)
+ struct targ_info *ti;
+{
+ caddr_t addr, physaddr;
+
+#if BS_BOUNCE_SIZE != 0
+ ti->bounce_size = BS_BOUNCE_SIZE;
+#else
+ ti->bounce_size = BSHW_NBPG;
+#endif
+ /* Try malloc() first. It works better if it works. */
+ addr = malloc(ti->bounce_size, M_DEVBUF, M_NOWAIT);
+ if (addr != NULL) {
+ if (bs_dmarangecheck(addr, ti->bounce_size) == 0) {
+ physaddr = (caddr_t) vtophys(addr);
+ ti->bounce_addr = (u_int8_t *) addr;
+ ti->bounce_phys = (u_int8_t *) physaddr;
+ return;
+ }
+ free(buf, M_DEVBUF);
+ }
+ addr = contigmalloc(ti->bounce_size, M_DEVBUF, M_NOWAIT,
+ 0ul, RAM_END, 1ul, 0x10000ul);
+ if (addr == NULL)
+ goto bad;
+
+ physaddr = (caddr_t) vtophys(addr);
+ if ((u_int) physaddr >= RAM_END)
+ {
+ /* XXX:
+ * must free memory !
+ */
+ goto bad;
+ }
+
+ ti->bounce_addr = (u_int8_t *) addr;
+ ti->bounce_phys = (u_int8_t *) physaddr;
+ return;
+
+bad:
+ bs_printf(ti, "bs_alloc_buf", "no phys bounce buffer");
+ printf("WARNING: this target is dislocated\n");
+}
+#endif /* __FreeBSD__ */
diff --git a/sys/i386/isa/bs/bsif.h b/sys/i386/isa/bs/bsif.h
new file mode 100644
index 0000000..6a5286e
--- /dev/null
+++ b/sys/i386/isa/bs/bsif.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) HONDA Naofumi, KATO Takenori, 1996. 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 as
+ * the first lines of this file unmodified.
+ * 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.
+ * 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.
+ */
+
+/***************************************************
+ * misc device header in bs_softc
+ ***************************************************/
+#ifdef __NetBSD__
+#define OS_DEPEND_DEVICE_HEADER \
+ struct device sc_dev; \
+ void *sc_ih;
+
+#define OS_DEPEND_SCSI_HEADER \
+ struct scsi_link sc_link;
+
+#define OS_DEPEND_MISC_HEADER \
+ pisa_device_handle_t sc_pdv; \
+ bus_chipset_tag_t sc_bc; \
+ bus_io_handle_t sc_ioh; \
+ bus_io_handle_t sc_delayioh; \
+ bus_mem_handle_t sc_memh;
+
+#endif /* __NetBSD__ */
+#ifdef __FreeBSD__
+#define OS_DEPEND_DEVICE_HEADER \
+ int unit;
+
+#define OS_DEPEND_SCSI_HEADER \
+ struct scsi_link sc_link;
+
+#define OS_DEPEND_MISC_HEADER
+#endif /* __FreeBSD__ */
+
+#if defined(__NetBSD__)
+#define BSHW_NBPG NBPG
+#endif
+#if defined(__FreeBSD__)
+#define BSHW_NBPG PAGE_SIZE
+#endif
+
+/***************************************************
+ * include
+ ***************************************************/
+/* (I) common include */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/disklabel.h>
+#include <sys/buf.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+
+#include <vm/vm.h>
+
+/* (II) os depend include */
+#ifdef __NetBSD__
+#include <sys/device.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+#include <dev/isa/pisaif.h>
+
+#include <machine/cpufunc.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/dvcfg.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/scsi_disk.h>
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+#include <sys/device.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/vmparam.h>
+#include <vm/pmap.h>
+#include <sys/proc.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/scsi_disk.h>
+
+#include <pc98/pc98/pc98.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/icu.h>
+#endif /* __FreeBSD__ */
+
+/***************************************************
+ * BUS IO MAPPINGS & BS specific inclusion
+ ***************************************************/
+#ifdef __NetBSD__
+#define BUS_IO_DELAY ((void) bus_io_read_1(bsc->sc_bc, bsc->sc_delayioh, 0))
+#define BUS_IO_WEIGHT (bus_io_write_1(bsc->sc_bc, bsc->sc_delayioh, 0, 0))
+#define BUS_IOR(offs) (BUS_IO_DELAY, bus_io_read_1(bsc->sc_bc, bsc->sc_ioh, (offs)))
+#define BUS_IOW(offs, val) (BUS_IO_DELAY, bus_io_write_1(bsc->sc_bc, bsc->sc_ioh, (offs), (val)))
+
+#include <dev/ic/wd33c93reg.h>
+#include <dev/isa/ccbque.h>
+
+#include <dev/isa/scsi_dvcfg.h>
+#include <dev/isa/bs/bsvar.h>
+#include <dev/isa/bs/bshw.h>
+#include <dev/isa/bs/bsfunc.h>
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+#define BUS_IO_DELAY ((void) inb(0x5f))
+#define BUS_IO_WEIGHT (outb(0x5f, 0))
+#define BUS_IOR(offs) (BUS_IO_DELAY, inb(bsc->sc_iobase + (offs)))
+#define BUS_IOW(offs, val) (BUS_IO_DELAY, outb(bsc->sc_iobase + (offs), (val)))
+
+#include <i386/isa/ic/wd33c93.h>
+#include <i386/isa/bs/ccbque.h>
+#include <i386/isa/bs/dvcfg.h>
+
+#include <i386/isa/bs/scsi_dvcfg.h>
+#include <i386/isa/bs/bsvar.h>
+#include <i386/isa/bs/bshw.h>
+#include <i386/isa/bs/bsfunc.h>
+#endif /* __FreeBSD__ */
+
+/***************************************************
+ * XS return type
+ ***************************************************/
+#ifdef __NetBSD__
+#define XSBS_INT32T int
+#endif /* __NetBSD__ */
+#ifdef __FreeBSD__
+#define XSBS_INT32T int32_t
+#endif /* __FreeBSD__ */
+
+/***************************************************
+ * xs flags's abstraction (all currently used)
+ ***************************************************/
+#define XSBS_ITSDONE ITSDONE
+#define XSBS_SCSI_NOSLEEP SCSI_NOSLEEP
+#ifdef __NetBSD__
+#define XSBS_SCSI_POLL SCSI_POLL
+#endif /* __NetBSD__ */
+#ifdef __FreeBSD__
+#define XSBS_SCSI_POLL SCSI_NOMASK
+#endif /* __FreeBSD__ */
+
+/***************************************************
+ * Special operations
+ ***************************************************/
+#ifdef __FreeBSD__
+#define BS_ADDRESS_CHECK
+#endif /* __FreeBSD__ */
+
+/***************************************************
+ * declare
+ ***************************************************/
+/* (I) common declare */
+void bs_alloc_buf __P((struct targ_info *));
+XSBS_INT32T bs_target_open __P((struct scsi_link *, struct cfdata *));
+XSBS_INT32T bs_scsi_cmd __P((struct scsi_xfer *));
+
+extern int delaycount;
+
+/* (II) os depend declare */
+#ifdef __NetBSD__
+int bsprobe __P((struct device *, struct device *, void *));
+void bsattach __P((struct device *, struct device *, void *));
+#endif /* __NetBSD__ */
+
+#ifdef __FreeBSD__
+u_int32_t bs_adapter_info __P((int));
+#define delay(y) DELAY(y)
+extern int dma_init_flag;
+#define softintr(y) ipending |= (y)
+#endif /* __FreeBSD__ */
diff --git a/sys/i386/isa/bs/bsvar.h b/sys/i386/isa/bs/bsvar.h
new file mode 100644
index 0000000..8267338
--- /dev/null
+++ b/sys/i386/isa/bs/bsvar.h
@@ -0,0 +1,542 @@
+/* $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.
+ */
+
+#define BS_INLINE inline
+
+/**************************************************
+ * CONTROL FLAGS (cf_flags)
+ *************************************************/
+#define BSC_FASTACK 0x01
+#define BSC_SMITSAT_DISEN 0x02
+#define BSC_CHIP_CLOCK(dvcfg) (((dvcfg) >> 4) & 0x03)
+
+#define BS_SCSI_SYNC DVF_SCSI_SYNC
+#define BS_SCSI_DISC DVF_SCSI_DISC
+#define BS_SCSI_WAIT DVF_SCSI_WAIT
+#define BS_SCSI_LINK DVF_SCSI_LINK
+#define BS_SCSI_QTAG DVF_SCSI_QTAG
+#define BS_SCSI_NOSAT DVF_SCSI_SP0
+#define BS_SCSI_NOPARITY DVF_SCSI_NOPARITY
+#define BS_SCSI_SAVESP DVF_SCSI_SAVESP
+#define BS_SCSI_NOSMIT DVF_SCSI_SP1
+#define BS_SCSI_PERIOD(XXX) DVF_SCSI_PERIOD(XXX)
+#define BS_SCSI_OFFSET(XXX) DVF_SCSI_OFFSET(XXX)
+#define BS_SCSI_SYNCMASK DVF_SCSI_SYNCMASK
+#define BS_SCSI_BITS DVF_SCSI_BITS
+
+#define BS_SCSI_DEFCFG (BS_SCSI_NOSAT | DVF_SCSI_DEFCFG)
+
+#define BS_SCSI_POSITIVE (BS_SCSI_SYNC | BS_SCSI_DISC | BS_SCSI_LINK)
+#define BS_SCSI_NEGATIVE (BS_SCSI_WAIT | BS_SCSI_NOSAT | BS_SCSI_NOPARITY |\
+ BS_SCSI_SAVESP | BS_SCSI_NOSMIT)
+/*******************************************
+ * CONFIG SECTION
+ ******************************************/
+/* Enable timeout watch dog */
+#define BS_DEFAULT_TIMEOUT_SECOND 16 /* default 16 sec */
+#define BS_SYNC_TIMEOUT 16
+#define BS_STARTUP_TIMEOUT 60
+#define BS_MOTOR_TIMEOUT 120
+#define BS_TIMEOUT_CHECK_INTERVAL 4 /* check each 4 sec */
+
+/* If you use memory over 16M */
+#ifdef SCSI_BOUNCE_SIZE
+#define BS_BOUNCE_SIZE SCSI_BOUNCE_SIZE
+#else /* !SCSI_BOUNCE_SIZE */
+#define BS_BOUNCE_SIZE 0
+#endif /* !SCSI_BOUNCE_SIZE */
+
+/* debug */
+#define BS_STATICS 1
+#define BS_DIAG 1
+#define BS_DEBUG_ROUTINE 1
+#define BS_DEBUG 1
+/* #define SHOW_PORT 1 */
+
+/**************************************************
+ * PARAMETER
+ **************************************************/
+#define NTARGETS 8
+#define RETRIES 4 /* number of retries before giving up */
+#define HARDRETRIES 3
+#define XSMAX 4
+#define BSDMABUFSIZ 0x10000
+#define BS_MAX_CCB (XSMAX * (NTARGETS - 1))
+
+#define BSCMDSTART 0
+#define BSCMDRESTART 0x01
+#define BSCMDFORCE 0x02
+
+#define BS_TIMEOUT_INTERVAL (hz * BS_TIMEOUT_CHECK_INTERVAL)
+
+/**************************************************
+ * SCSI PHASE
+ **************************************************/
+enum scsi_phase {
+ FREE = 0,
+ HOSTQUEUE,
+ DISCONNECTED,
+ IOCOMPLETED,
+ ATTENTIONASSERT,
+ DISCONNECTASSERT,
+ SELECTASSERT,
+ SELECTED,
+ RESELECTED,
+ MSGIN,
+ MSGOUT,
+ STATUSIN,
+ CMDPHASE,
+ DATAPHASE,
+ SATSEL,
+ SATRESEL,
+ SATSDP,
+ SATCOMPSEQ,
+ UNDEF,
+};
+
+/**************************************************
+ * SCSI PHASE CONTROL MACRO
+ **************************************************/
+#define BS_HOST_START \
+{ \
+ bsc->sc_nexus = ti; \
+}
+
+#define BS_HOST_TERMINATE \
+{ \
+ bsc->sc_selwait = NULL; \
+ bsc->sc_nexus = NULL; \
+}
+
+#define BS_SELECTION_START \
+{ \
+ bsc->sc_selwait = ti; \
+}
+
+#define BS_SELECTION_TERMINATE \
+{ \
+ bsc->sc_selwait = NULL; \
+}
+
+#define BS_SETUP_PHASE(PHASE) \
+{ \
+ ti->ti_ophase = ti->ti_phase; \
+ ti->ti_phase = (PHASE); \
+}
+
+#define BS_SETUP_MSGPHASE(PHASE) \
+{ \
+ bsc->sc_msgphase = (PHASE); \
+}
+
+#define BS_SETUP_SYNCSTATE(STATE) \
+{ \
+ ti->ti_syncnow.state = (STATE); \
+}
+
+#define BS_SETUP_TARGSTATE(STATE) \
+{ \
+ ti->ti_state = (STATE); \
+}
+
+#define BS_LOAD_SDP \
+{ \
+ bsc->sc_p.data = ti->ti_scsp.data; \
+ bsc->sc_p.datalen = ti->ti_scsp.datalen; \
+ bsc->sc_p.seglen = ti->ti_scsp.seglen; \
+}
+
+#define BS_RESTORE_SDP \
+{ \
+ bsc->sc_p = ti->ti_scsp; \
+}
+
+#define BS_SAVE_SDP \
+{ \
+ ti->ti_scsp = bsc->sc_p; \
+}
+
+/**************************************************
+ * STRUCTURES
+ **************************************************/
+struct msgbase {
+#define MAXMSGLEN 8
+ u_int8_t msg[MAXMSGLEN];
+ u_int msglen;
+
+ u_int flag;
+};
+
+struct syncdata {
+ u_int8_t period;
+ u_int8_t offset;
+
+#define BS_SYNCMSG_NULL 0x00
+#define BS_SYNCMSG_ASSERT 0x01
+#define BS_SYNCMSG_REJECT 0x02
+#define BS_SYNCMSG_ACCEPT 0x03
+#define BS_SYNCMSG_REQUESTED 0x04
+ u_int state;
+};
+
+struct sc_p {
+ u_int8_t *data;
+ int datalen;
+
+ u_int8_t *segaddr;
+ int seglen;
+
+ u_int8_t *bufp;
+};
+
+/* targ_info error flags */
+#define BSDMAABNORMAL 0x01
+#define BSCMDABNORMAL 0x02
+#define BSPARITY 0x04
+#define BSSTATUSERROR 0x08
+#define BSTIMEOUT 0x10
+#define BSREQSENSE 0x20
+#define BSSELTIMEOUT 0x40
+#define BSFATALIO 0x80
+#define BSMSGERROR 0x100
+#define BSTRYRECOV 0x200
+#define BSABNORMAL 0x400
+#define BSTARGETBUSY 0x800
+
+#define BSERRORBITS "\020\014busy\013abnormal\012retry\011msgerr\010fatal\007seltimeout\006sense\005timeout\004statuserr\003parity\002cmderr\001dmaerr"
+
+/* ccb & targ_info flags & cmd flags*/
+#define BSREAD 0x0001
+#define BSSAT 0x0002
+#define BSLINK 0x0004
+#define BSERROROK 0x0008
+#define BSSMIT 0x0010
+#define BSDISC 0x1000
+#define BSFORCEIOPOLL 0x2000
+
+#define BSCASTAT 0x01000000
+#define BSSENSECCB 0x02000000
+#define BSQUEUED 0x04000000
+#define BSALTBUF 0x08000000
+#define BSITSDONE 0x10000000
+#define BSNEXUS 0x20000000
+
+#define BSCFLAGSMASK (0xffff)
+
+struct ccb {
+ TAILQ_ENTRY(ccb) ccb_chain;
+
+ struct scsi_xfer *xs; /* upper drivers info */
+
+ u_int lun; /* lun */
+
+ u_int flags; /* control flags */
+
+ int rcnt; /* retry counter of this ccb */
+
+ u_int error; /* recorded error */
+
+ /*****************************************
+ * scsi cmd & data
+ *****************************************/
+ u_int8_t *cmd; /* scsi cmd */
+ int cmdlen;
+
+ u_int8_t *data; /* scsi data */
+ int datalen;
+
+ u_int8_t msgout[MAXMSGLEN]; /* scsi msgout */
+ u_int msgoutlen;
+
+ /*****************************************
+ * timeout counter
+ *****************************************/
+ int tc;
+ int tcmax;
+};
+
+GENERIC_CCB_ASSERT(bs, ccb)
+
+/* target info */
+struct targ_info {
+ TAILQ_ENTRY(targ_info) ti_tchain; /* targ_info link */
+
+ TAILQ_ENTRY(targ_info) ti_wchain; /* wait link */
+
+ struct bs_softc *ti_bsc; /* our controller */
+ u_int ti_id; /* scsi id */
+ u_int ti_lun; /* current lun */
+
+ struct ccbtab ti_ctab, ti_bctab; /* ccb */
+
+#define BS_TARG_NULL 0
+#define BS_TARG_CTRL 1
+#define BS_TARG_START 2
+#define BS_TARG_SYNCH 3
+#define BS_TARG_RDY 4
+ int ti_state; /* target state */
+
+ u_int ti_cfgflags; /* target cfg flags */
+
+ u_int ti_flags; /* flags */
+ u_int ti_mflags; /* flags masks */
+
+ u_int ti_error; /* error flags */
+ u_int ti_herrcnt; /* hardware err retry counter */
+
+ /*****************************************
+ * scsi phase data
+ *****************************************/
+ struct sc_p ti_scsp; /* saved scsi data pointer */
+
+ enum scsi_phase ti_phase; /* scsi phase */
+ enum scsi_phase ti_ophase; /* previous scsi phase */
+
+ u_int8_t ti_status; /* status in */
+
+ u_int8_t ti_msgin[MAXMSGLEN]; /* msgin buffer */
+ int ti_msginptr;
+
+ u_int8_t ti_msgout; /* last msgout byte */
+ u_int8_t ti_emsgout; /* last msgout byte */
+ u_int ti_omsgoutlen; /* for retry msgout */
+
+ struct syncdata ti_syncmax; /* synch data (scsi) */
+ struct syncdata ti_syncnow;
+ u_int8_t ti_sync; /* synch val (chip) */
+
+ /*****************************************
+ * bounce buffer & smit data pointer
+ *****************************************/
+ u_int8_t *bounce_phys;
+ u_int8_t *bounce_addr;
+ u_int bounce_size;
+
+ u_int8_t *sm_vaddr;
+
+ /*****************************************
+ * target inq data
+ *****************************************/
+ u_int8_t targ_type;
+ u_int8_t targ_support;
+
+ /*****************************************
+ * generic scsi cmd buffer for this target
+ *****************************************/
+ u_int8_t scsi_cmd[12];
+ struct scsi_sense_data sense;
+};
+
+TAILQ_HEAD(titab, targ_info);
+struct bshw;
+
+struct bs_softc {
+ /*****************************************
+ * OS depend header
+ *****************************************/
+ OS_DEPEND_DEVICE_HEADER
+
+ OS_DEPEND_SCSI_HEADER
+
+ OS_DEPEND_MISC_HEADER
+
+ /*****************************************
+ * target link
+ *****************************************/
+ struct targ_info *sc_ti[NTARGETS];
+ u_int sc_openf;
+
+ struct titab sc_sttab;
+ struct titab sc_titab;
+
+ /*****************************************
+ * current scsi phase
+ *****************************************/
+ struct targ_info *sc_nexus; /* current active nexus */
+
+ enum scsi_phase sc_msgphase; /* scsi phase pointed by msg */
+
+ struct targ_info *sc_selwait; /* selection assert */
+
+ u_int sc_dtgnum; /* disconnected target */
+
+ /*****************************************
+ * current scsi data pointer
+ *****************************************/
+ struct sc_p sc_p; /* scsi data pointer */
+
+ int sc_dmadir; /* dma direction */
+
+ int sm_tdatalen; /* smit data transfer bytes */
+
+ /*****************************************
+ * parameter
+ *****************************************/
+ u_int sc_retry; /* max retry count */
+
+#define BSDMATRANSFER 0x01
+#define BSDMASTART 0x02
+#define BSSMITSTART 0x04
+#define BSUNDERRESET 0x08
+#define BSRESET 0x10
+#define BSSTARTTIMEOUT 0x20
+#define BSPOLLDONE 0x100
+#define BSJOBDONE 0x200
+#define BSBSMODE 0x400
+#define BSINACTIVE 0x800
+ volatile int sc_flags; /* host flags */
+
+#define BSC_NULL 0
+#define BSC_BOOTUP 1
+#define BSC_TARG_CHECK 2
+#define BSC_RDY 3
+ int sc_hstate; /* host state */
+
+ /*****************************************
+ * polling misc
+ *****************************************/
+ u_int sc_wc; /* weight count */
+
+ int sc_poll;
+ struct ccb *sc_outccb;
+
+ /*****************************************
+ * wd33c93 chip depend section
+ *****************************************/
+ u_int sc_cfgflags; /* hardware cfg flags */
+
+ struct bshw *sc_hw; /* hw selection */
+
+ u_int8_t *sm_vaddr; /* smit buffer */
+
+ u_int sc_RSTdelay;
+
+ int sc_hwlock; /* hardware lock count */
+
+ int sc_iobase; /* iobase for FreeBSD */
+ u_int32_t sc_irqmasks; /* irq */
+
+ u_int sc_dmachan; /* dma channel */
+ u_int8_t sc_busstat; /* scsi bus status register */
+ u_int8_t sc_hostid; /* host scsi id */
+ u_int8_t sc_cspeed; /* chip clock rate */
+ u_int8_t sc_membank; /* memory back (NEC) register */
+
+ /*****************************************
+ * our name
+ *****************************************/
+#define BS_DVNAME_LEN 16
+ u_char sc_dvname[BS_DVNAME_LEN];
+};
+
+/*************************************************
+ * debug
+ *************************************************/
+#ifdef BS_STATICS
+struct bs_statics {
+ u_int select;
+ u_int select_miss_in_assert;
+ u_int select_miss_by_reselect;
+ u_int select_miss;
+ u_int select_win;
+ u_int selected;
+ u_int disconnected;
+ u_int reselect;
+};
+
+extern struct bs_statics bs_statics[NTARGETS];
+extern u_int bs_linkcmd_count[];
+extern u_int bs_bounce_used[];
+#endif /* BS_STATICS */
+
+#ifdef BS_DEBUG_ROUTINE
+#ifndef DDB
+#define Debugger() panic("should call debugger here (bs.c)")
+#endif /* DDB */
+#ifdef BS_DEBUG
+extern int bs_debug_flag;
+#endif /* BS_DEBUG */
+#endif /* BS_DEBUG_ROUTINE */
+
+/*************************************************
+ * Function declare
+ *************************************************/
+int bs_scsi_cmd_internal __P((struct ccb *, u_int));
+struct ccb *bscmddone __P((struct targ_info *));
+int bscmdstart __P((struct targ_info *, int));
+int bs_scsi_cmd_poll __P((struct targ_info *, struct ccb *));
+int bs_sequencer __P((struct bs_softc *));
+void bs_poll_timeout __P((struct bs_softc *, char *));
+
+/*************************************************
+ * XXX
+ *************************************************/
+/* misc error */
+#define NOTARGET -2
+#define HASERROR -1
+
+/* XXX: use scsi_message.h */
+/* status */
+#define ST_GOOD 0x00
+#define ST_CHKCOND 0x02
+#define ST_MET 0x04
+#define ST_BUSY 0x08
+#define ST_INTERGOOD 0x10
+#define ST_INTERMET 0x14
+#define ST_CONFLICT 0x18
+#define ST_QUEFULL 0x28
+#define ST_UNK 0xff
+
+/* message */
+#define MSG_COMP 0x00
+#define MSG_EXTEND 0x01
+
+#define MKMSG_EXTEND(XLEN, XCODE) ((((u_int)(XLEN)) << NBBY) | ((u_int)(XCODE)))
+#define MSG_EXTEND_MDPCODE 0x00
+#define MSG_EXTEND_MDPLEN 0x05
+#define MSG_EXTEND_SYNCHCODE 0x01
+#define MSG_EXTEND_SYNCHLEN 0x03
+#define MSG_EXTEND_WIDECODE 0x03
+#define MSG_EXTEND_WIDELEN 0x02
+
+#define MSG_SAVESP 0x02
+#define MSG_RESTORESP 0x03
+#define MSG_DISCON 0x04
+#define MSG_I_ERROR 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJECT 0x07
+#define MSG_NOOP 0x08
+#define MSG_PARITY 0x09
+#define MSG_LCOMP 0x0a
+#define MSG_LCOMP_F 0x0b
+#define MSG_RESET 0x0c
diff --git a/sys/i386/isa/bs/ccbque.h b/sys/i386/isa/bs/ccbque.h
new file mode 100644
index 0000000..d2c4cfc
--- /dev/null
+++ b/sys/i386/isa/bs/ccbque.h
@@ -0,0 +1,130 @@
+/* $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.
+ */
+/*
+ * Common command control queue funcs.
+ * Written by N. Honda.
+ */
+
+#ifndef _CCBQUE_H_
+#define _CCBQUE_H_
+
+/* (I) structure and prototype */
+#define GENERIC_CCB_ASSERT(DEV, CCBTYPE) \
+TAILQ_HEAD(CCBTYPE##tab, CCBTYPE); \
+struct CCBTYPE##que { \
+ struct CCBTYPE##tab CCBTYPE##tab; \
+ int count; \
+ int maxccb; \
+}; \
+void DEV##_init_ccbque __P((int)); \
+struct CCBTYPE *DEV##_get_ccb __P((int)); \
+void DEV##_free_ccb __P((struct CCBTYPE *));
+
+/* (II) static allocated memory */
+#define GENERIC_CCB_STATIC_ALLOC(DEV, CCBTYPE) \
+static struct CCBTYPE##que CCBTYPE##que;
+
+/* (III) functions */
+#define GENERIC_CCB(DEV, CCBTYPE, CHAIN) \
+ \
+void \
+DEV##_init_ccbque(count) \
+ int count; \
+{ \
+ if (CCBTYPE##que.maxccb == 0) \
+ TAILQ_INIT(&CCBTYPE##que.CCBTYPE##tab) \
+ CCBTYPE##que.maxccb += count; \
+} \
+ \
+struct CCBTYPE * \
+DEV##_get_ccb(flags) \
+ int flags; \
+{ \
+ struct CCBTYPE *cb; \
+ int s = splbio(); \
+ \
+ do \
+ { \
+ if (CCBTYPE##que.count > CCBTYPE##que.maxccb) \
+ { \
+ if (flags) \
+ { \
+ cb = NULL; \
+ goto done; \
+ } \
+ else \
+ { \
+ tsleep((caddr_t) &CCBTYPE##que.count, \
+ PRIBIO, "ccbwait", 0); \
+ continue; \
+ } \
+ } \
+ \
+ if (cb = CCBTYPE##que.CCBTYPE##tab.tqh_first) \
+ { \
+ TAILQ_REMOVE(&CCBTYPE##que.CCBTYPE##tab, cb, CHAIN)\
+ break; \
+ } \
+ else \
+ { \
+ if (cb = malloc(sizeof(*cb), M_DEVBUF, M_NOWAIT))\
+ { \
+ bzero(cb, sizeof(*cb)); \
+ break; \
+ } \
+ else if (flags) \
+ goto done; \
+ \
+ tsleep((caddr_t) &CCBTYPE##que.count, \
+ PRIBIO, "ccbwait", 0); \
+ } \
+ } \
+ while (1); \
+ CCBTYPE##que.count ++; \
+ \
+done: \
+ splx(s); \
+ return cb; \
+} \
+ \
+void \
+DEV##_free_ccb(cb) \
+ struct CCBTYPE *cb; \
+{ \
+ int s = splbio(); \
+ \
+ TAILQ_INSERT_TAIL(&CCBTYPE##que.CCBTYPE##tab, cb, CHAIN) \
+ CCBTYPE##que.count --; \
+ \
+ if (CCBTYPE##que.count == CCBTYPE##que.maxccb) \
+ wakeup ((caddr_t) &CCBTYPE##que.count); \
+ splx(s); \
+}
+#endif /* !_CCBQUE_H_ */
diff --git a/sys/i386/isa/bs/dvcfg.h b/sys/i386/isa/bs/dvcfg.h
new file mode 100644
index 0000000..f092117
--- /dev/null
+++ b/sys/i386/isa/bs/dvcfg.h
@@ -0,0 +1,64 @@
+/* $NetBSD$ */
+/*
+ * [NetBSD for NEC PC98 series]
+ * Copyright (c) 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) 1996 Naofumi HONDA. All rights reserved.
+ */
+
+#ifndef _I386_DVCFG_H_
+#define _I386_DVCFG_H_
+
+typedef void *dvcfg_hw_t;
+
+struct dvcfg_hwsel {
+ int cfg_max;
+
+ dvcfg_hw_t *cfg_sel;
+};
+
+#define DVCFG_MAJOR(dvcfg) (((u_int)(dvcfg)) >> 16)
+#define DVCFG_MINOR(dvcfg) (((u_int)(dvcfg)) & 0xffff)
+
+#define DVCFG_MKCFG(major, minor) ((((u_int)(major)) << 16) | ((minor) & 0xffff))
+
+#define DVCFG_HWSEL_SZ(array) (sizeof(array) / sizeof(dvcfg_hw_t))
+
+static inline dvcfg_hw_t dvcfg_hw __P((struct dvcfg_hwsel *, u_int));
+
+static inline dvcfg_hw_t
+dvcfg_hw(selp, num)
+ struct dvcfg_hwsel *selp;
+ u_int num;
+{
+
+ return ((num >= selp->cfg_max) ? NULL : selp->cfg_sel[num]);
+}
+
+#define DVCFG_HW(SELP, NUM) dvcfg_hw((SELP), (NUM))
+#endif /* _I386_DVCFG_H_ */
OpenPOWER on IntegriCloud