diff options
author | asami <asami@FreeBSD.org> | 1996-12-04 04:32:52 +0000 |
---|---|---|
committer | asami <asami@FreeBSD.org> | 1996-12-04 04:32:52 +0000 |
commit | 5fdc748d8c34e6924a223a6dd13a1d3c36104b5b (patch) | |
tree | a876bb0feb1b4c4f4191a1d367e088a314cf155a /sys/i386/isa | |
parent | 4d75d96d6e8b3a6ef3d9dcc16b1e9414af327f0e (diff) | |
download | FreeBSD-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')
-rw-r--r-- | sys/i386/isa/bs/bs.c | 1622 | ||||
-rw-r--r-- | sys/i386/isa/bs/bs_isa.c | 60 | ||||
-rw-r--r-- | sys/i386/isa/bs/bs_pisa.c | 126 | ||||
-rw-r--r-- | sys/i386/isa/bs/bsfunc.c | 926 | ||||
-rw-r--r-- | sys/i386/isa/bs/bsfunc.h | 229 | ||||
-rw-r--r-- | sys/i386/isa/bs/bshw.c | 451 | ||||
-rw-r--r-- | sys/i386/isa/bs/bshw.h | 363 | ||||
-rw-r--r-- | sys/i386/isa/bs/bshw.lst | 113 | ||||
-rw-r--r-- | sys/i386/isa/bs/bshw_dma.c | 339 | ||||
-rw-r--r-- | sys/i386/isa/bs/bshw_pdma.c | 242 | ||||
-rw-r--r-- | sys/i386/isa/bs/bsif.c | 520 | ||||
-rw-r--r-- | sys/i386/isa/bs/bsif.h | 201 | ||||
-rw-r--r-- | sys/i386/isa/bs/bsvar.h | 542 | ||||
-rw-r--r-- | sys/i386/isa/bs/ccbque.h | 130 | ||||
-rw-r--r-- | sys/i386/isa/bs/dvcfg.h | 64 | ||||
-rw-r--r-- | sys/i386/isa/ic/wd33c93.h | 274 |
16 files changed, 6079 insertions, 123 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_ */ diff --git a/sys/i386/isa/ic/wd33c93.h b/sys/i386/isa/ic/wd33c93.h index f1aa7f9..e8ba4aa 100644 --- a/sys/i386/isa/ic/wd33c93.h +++ b/sys/i386/isa/ic/wd33c93.h @@ -1,127 +1,155 @@ /* - * PC9801 SCSI I/F (PC-9801-55) - * modified for PC9801 by A.Kojima - * Kyoto University Microcomputer Club (KMC) + * [NetBSD for NEC PC98 series] + * Copyright (c) 1996 NetBSD/pc98 porting staff. + * Copyright (c) 1996 Naofumi Honda + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ -/* I/O address */ - -/* WD33C93 */ -#define SCSI_ADR_REG 0xcc0 /* write Address Register */ -#define SCSI_AUX_REG 0xcc0 /* read Aux. Status Register */ -#define SCSI_CTL_REG 0xcc2 /* read/write Control Registers */ - -/* Port */ -#define SCSI_STAT_RD 0xcc4 /* read Status Read */ -#define SCSI_CMD_WRT 0xcc4 /* write Command Write */ - -#if 0 /* H98 extended mode */ -/* WD33C93 */ -#define SCSI_ADR_REG 0xee0 /* write Address Register */ -#define SCSI_AUX_REG 0xee0 /* read Control Register */ -#define SCSI_CTL_REG 0xee2 /* read/write Registers */ - -/* Port */ -#define SCSI_STAT_RD 0xee4 /* read Status Read */ -#define SCSI_CMD_WRT 0xee4 /* write Command Write */ -#endif - -/****************************************************************/ - -/* WD33C93 Registers */ -#define REG_OWN_ID 0x00 /* Own ID */ -#define REG_CONTROL 0x01 /* Control */ -#define REG_TIMEOUT_PERIOD 0x02 /* Timeout Period */ -#define REG_TOTAL_SECTORS 0x03 /* Total Sectors */ -#define REG_TOTAL_HEADS 0x04 /* Total Heads */ -#define REG_TOTAL_CYL_H 0x05 /* Total Cylinders (MSB) */ -#define REG_TOTAL_CYL_L 0x06 /* Total Cylinders (LSB) */ -#define REG_LOG_SECTOR_HH 0x07 /* Logical Address (MSB) */ -#define REG_LOG_SECTOR_HL 0x08 /* Logical Address */ -#define REG_LOG_SECTOR_LH 0x09 /* Logical Address */ -#define REG_LOG_SECTOR_LL 0x0a /* Logical Address (LSB) */ -#define REG_SECTOR_NUMBER 0x0b /* Sector Number */ -#define REG_HEAD_NUMBER 0x0c /* Head Number */ -#define REG_CYL_NUMBER_H 0x0d /* Cylinder Number (MSB) */ -#define REG_CYL_NUMBER_L 0x0e /* Cylinder Number (LSB) */ -#define REG_TARGET_LUN 0x0f /* Target LUN */ -#define REG_CMD_PHASE 0x10 /* Command Phase */ -#define REG_SYNC_TFR 0x11 /* Synchronous Transfer */ -#define REG_TFR_COUNT_H 0x12 /* Transfer Count (MSB) */ -#define REG_TFR_COUNT_M 0x13 /* Transfer Count */ -#define REG_TFR_COUNT_L 0x14 /* Transfer Count (LSB) */ -#define REG_DST_ID 0x15 /* Destination ID */ -#define REG_SRC_ID 0x16 /* Source ID */ -#define REG_SCSI_STATUS 0x17 /* SCSI Status (Read Only) */ -#define REG_COMMAND 0x18 /* Command */ -#define REG_DATA 0x19 /* Data */ - -/* PC98 only */ -#define REG_MEM_BANK 0x30 /* Memory Bank */ -#define REG_MEM_WIN 0x31 /* Memery Window */ -#define REG_RESERVED1 0x32 /* NEC Reserved 1 */ -#define REG_RESET_INT 0x33 /* Reset/Int */ -#define REG_RESERVED2 0x34 /* NEC Reserved 2 */ - -/****************************************************************/ - -/* WD33C93 Commands */ -#define CMD_RESET 0x00 /* Reset */ -#define CMD_ABORT 0x01 /* Abort */ -#define CMD_ASSERT_ATN 0x02 /* Assert ATN */ -#define CMD_NEGATE_ATN 0x03 /* Negate ATN */ -#define CMD_DISCONNECT 0x04 /* Disconnect */ -#define CMD_RESELECT 0x05 /* Reselect */ -#define CMD_SELECT_ATN 0x06 /* Select with ATN */ -#define CMD_SELECT_NO_ATN 0x07 /* Select without ATN */ -#define CMD_SELECT_ATN_TFR 0x08 /* Select with ATN and Transfer */ -#define CMD_SELECT_NO_ATN_TFR 0x09 /* Select without ATN and Transfer */ -#define CMD_RESELECT_RCV_DATA 0x0a /* Reselect and Recieve Data */ -#define CMD_RESELECT_SEND_DATA 0x0b /* Reselect and Send Data */ -#define CMD_WAIT_SELECT_RCV 0x0c /* Wait for Select and Recieve */ -#define CMD_RCV_CMD 0x10 /* Recieve Command */ -#define CMD_RCV_DATA 0x11 /* Recieve Data */ -#define CMD_RCV_MSG_OUT 0x12 /* Recieve Message Info Out*/ -#define CMD_RCV_UNSP_INFO_OUT 0x13 /* Recieve Unspecified Info Out */ -#define CMD_SEND_STATUS 0x14 /* Send Status */ -#define CMD_SEND_DATA 0x15 /* Send Data */ -#define CMD_SEND_MSG_IN 0x16 /* Send Message In */ -#define CMD_SEND_UNSP_INFO_IN 0x17 /* Send Unspecified Info In */ -#define CMD_TRANSLATE_ADDRESS 0x18 /* Translate Address */ -#define CMD_TFR_INFO 0x20 /* Transfer Info */ -#define CMD_TFR_PAD 0x21 /* Transfer Pad */ -#define CMD_SBT_SFX 0x80 /* single byte suffix */ - -/* WD33C93 bus status register (lower nibble) */ -#define STAT_DATAOUT 0x08 /* Data out phase */ -#define STAT_DATAIN 0x09 /* Data in phase */ -#define STAT_CMDOUT 0x0a /* Command out phase */ -#define STAT_STATIN 0x0b /* Status in phase */ -#define STAT_MSGOUT 0x0e /* Message out phase */ -#define STAT_MSGIN 0x0f /* Message in phase */ - -/* SCSI Status byte */ -#define SS_GOOD 0x00 /* Good status */ -#define SS_CHKCOND 0x02 -#define SS_MET 0x04 -#define SS_BUSY 0x08 -#define SS_INTERGOOD 0x10 -#define SS_INTERMET 0x14 -#define SS_CONFLICT 0x18 - -/* SCSI message system */ -#define MSG_COMPLETE 0x00 /* Command complete message */ -#define MSG_EXTEND 0x01 /* Extend message */ -#define MSG_SAVEPTR 0x02 /* Save data pointer message */ -#define MSG_RESTORE 0x03 /* Restore data pointer message */ -#define MSG_DISCON 0x04 /* Disconnect message */ -#define MSG_INIERROR 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJECT 0x07 -#define MSG_NOP 0x08 -#define MSG_PARERROR 0x09 -#define MSG_LCOMPLETE 0x0a -#define MSG_LCOMPLETEF 0x0b -#define MSG_DEVRESET 0x0c -#define MSG_IDENTIFY 0x80 /* Identify message */ +#ifndef _WD33C93REG_H_ +#define _WD33C93REG_H_ +/* wd33c93 register */ +#define wd3s_oid 0x00 +#define IDR_FS_15_20 0x80 +#define IDR_FS_12_15 0x40 +#define IDR_FS_8_10 0x00 +#define IDR_EHP 0x10 +#define IDR_EAF 0x08 +#define IDR_IDM 0x07 + +#define wd3s_ctrl 0x01 +#define CR_DMA 0x80 +#define CR_DMAD 0x40 +#define CR_HLT_HOST_PARITY 0x10 +#define CR_DIS_INT 0x08 +#define CR_IDIS_INT 0x04 +#define CR_HLT_ATN 0x02 +#define CR_HLT_BUS_PARITY 0x01 +#define CR_DEFAULT (CR_DIS_INT | CR_IDIS_INT) +#define CR_DEFAULT_HP (CR_DEFAULT | CR_HLT_BUS_PARITY) + +#define wd3s_tout 0x02 +#define wd3s_cdb 0x03 +#define wd3s_lun 0x0f +#define wd3s_cph 0x10 +#define wd3s_synch 0x11 +#define wd3s_cnt 0x12 +#define wd3s_did 0x15 + +#define wd3s_sid 0x16 +#define SIDR_RESEL 0x80 +#define SIDR_SEL 0x40 +#define SIDR_VALID 0x08 +#define SIDR_IDM 0x07 + +#define wd3s_stat 0x17 + +#define BSR_CM 0xf0 +#define BSR_CMDCPL 0x10 +#define BSR_CMDABT 0x20 +#define BSR_CMDERR 0x40 +#define BSR_CMDREQ 0x80 + +#define BSR_SM 0x0f +#define BSR_PM 0x07 +#define BSR_PHVALID 0x08 +#define BSR_IOR 0x01 +#define BSR_DATAOUT 0x00 +#define BSR_DATAIN 0x01 +#define BSR_CMDOUT 0x02 +#define BSR_STATIN 0x03 +#define BSR_UNSPINFO0 0x04 +#define BSR_UNSPINFO1 0x05 +#define BSR_MSGOUT 0x06 +#define BSR_MSGIN 0x07 + +#define BSR_SELECTED 0x11 +#define BSR_SATFIN 0x16 +#define BSR_ACKREQ 0x20 +#define BSR_SATSDP 0x21 +#define BSR_RESEL 0x80 +#define BSR_DISC 0x85 + +#define wd3s_cmd 0x18 +#define wd3s_data 0x19 +#define wd3s_qtag 0x1a + +#define wd3s_mbank 0x30 +#define MBR_RST 0x02 +#define MBR_IEN 0x04 + +#define wd3s_mwin 0x31 +#define wd3s_auxc 0x33 +#define AUXCR_HIDM 0x07 +#define AUXCR_INTM 0x38 +#define AUXCR_RRST 0x80 + +/* status port */ +#define STR_INT 0x80 +#define STR_LCI 0x40 +#define STR_BSY 0x20 +#define STR_CIP 0x10 +#define STR_PE 0x02 +#define STR_DBR 0x01 +#define STR_BUSY 0xf0 + +/* cmd port */ +#define CMDP_DMES 0x01 +#define CMDP_DMER 0x02 +#define CMDP_TCMS 0x04 +#define CMDP_TCMR 0x08 +#define CMDP_TCIR 0x10 + +/* wd33c93 chip cmds */ +#define WD3S_SBT 0x80 +#define WD3S_RESET 0x00 +#define WD3S_ABORT 0x01 +#define WD3S_ASSERT_ATN 0x02 +#define WD3S_NEGATE_ACK 0x03 +#define WD3S_DISCONNECT 0x04 +#define WD3S_RESELECT 0x05 +#define WD3S_SELECT_ATN 0x06 +#define WD3S_SELECT_NO_ATN 0x07 +#define WD3S_SELECT_ATN_TFR 0x08 +#define WD3S_SELECT_NO_ATN_TFR 0x09 +#define WD3S_RESELECT_RCV_DATA 0x0a +#define WD3S_RESELECT_SEND_DATA 0x0b +#define WD3S_WAIT_SELECT_RCV 0x0c +#define WD3S_CMD_COMPSEQ 0x0d +#define WD3S_SEND_DISC_MSG 0x0e +#define WD3S_SET_IDI 0x0f +#define WD3S_RCV_CMD 0x10 +#define WD3S_RCV_DATA 0x11 +#define WD3S_RCV_MSG_OUT 0x12 +#define WD3S_RCV_UNSP_INFO_OUT 0x13 +#define WD3S_SEND_STATUS 0x14 +#define WD3S_SEND_DATA 0x15 +#define WD3S_SEND_MSG_IN 0x16 +#define WD3S_SEND_UNSP_INFO_IN 0x17 +#define WD3S_TRANSLATE_ADDRESS 0x18 +#define WD3S_TFR_INFO 0x20 + +#endif /* !_WD33C93REG_H_ */ |