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 | |
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')
-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 | ||||
-rw-r--r-- | sys/pc98/conf/GENERIC | 31 | ||||
-rw-r--r-- | sys/pc98/conf/GENERIC98 | 31 | ||||
-rw-r--r-- | sys/pc98/pc98/sbic55.c | 917 | ||||
-rw-r--r-- | sys/pc98/pc98/sbic55.c.new | 1745 | ||||
-rw-r--r-- | sys/pc98/pc98/sbicreg.h | 429 | ||||
-rw-r--r-- | sys/pc98/pc98/sbicvar.h | 157 | ||||
-rw-r--r-- | sys/pc98/pc98/scsireg.h | 312 |
23 files changed, 6115 insertions, 3709 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_ */ diff --git a/sys/pc98/conf/GENERIC b/sys/pc98/conf/GENERIC index 69b5064..65af27f 100644 --- a/sys/pc98/conf/GENERIC +++ b/sys/pc98/conf/GENERIC @@ -11,7 +11,7 @@ # device lines is present in the ./LINT configuration file. If you are # in doubt as to the purpose or necessity of a line, check first in LINT. # -# $Id: GENERIC98,v 1.8 1996/10/30 22:39:29 asami Exp $ +# $Id: GENERIC98,v 1.9 1996/11/14 08:46:11 asami Exp $ # GENERIC98 -- Generic PC98 machine with WD/SBIC55 disks @@ -58,12 +58,6 @@ options COM_MULTIPORT #options SUSP_HLT # CPU enters suspend mode when HALT #options "DISABLE_5X86_LSSER" # Load-Store reordering enable # -# sbic55.c.new -# -#options SCSI_SYNC # synchronous transfer mode -#options FORCE_BUSMASTER -#options "HA55BS_ID=0" -# # IBM-PC HDD support #options COMPAT_ATDISK # @@ -100,13 +94,24 @@ device wcd0 #IDE CD-ROM # for any number of installed devices. controller ncr0 controller ahc0 -options "AHC_FORCE_PIO" # Some motherboards choke on MemI/O, - # so use PIO in the ahc driver in the - # generic kernel. -controller sbic0 at isa? port "IO_SCSI" bio irq 5 drq 3 vector sbicintr -# sbic55.c.new -#controller sbic0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0xff vector sbicintr +# +# WD33C93 SCSI card (55/92 like board) +# + +options BS_TARG_SAFEMODE + +# PC-9801-92 +controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0 vector bsintr +# SC-98 +# controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0x10000 vector bsintr +# HA-55BS2 and later +#controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0x20000 vector bsintr +# ELECOM type +#controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0x30000 vector bsintr +# SMIT +#controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 iomem 0xdd000 iosiz 0x1000 flags 0x40000 vector bsintr + controller aic0 at isa? port 0x1840 bio irq 5 flags 0x10000 vector aicintr controller scbus0 diff --git a/sys/pc98/conf/GENERIC98 b/sys/pc98/conf/GENERIC98 index 69b5064..65af27f 100644 --- a/sys/pc98/conf/GENERIC98 +++ b/sys/pc98/conf/GENERIC98 @@ -11,7 +11,7 @@ # device lines is present in the ./LINT configuration file. If you are # in doubt as to the purpose or necessity of a line, check first in LINT. # -# $Id: GENERIC98,v 1.8 1996/10/30 22:39:29 asami Exp $ +# $Id: GENERIC98,v 1.9 1996/11/14 08:46:11 asami Exp $ # GENERIC98 -- Generic PC98 machine with WD/SBIC55 disks @@ -58,12 +58,6 @@ options COM_MULTIPORT #options SUSP_HLT # CPU enters suspend mode when HALT #options "DISABLE_5X86_LSSER" # Load-Store reordering enable # -# sbic55.c.new -# -#options SCSI_SYNC # synchronous transfer mode -#options FORCE_BUSMASTER -#options "HA55BS_ID=0" -# # IBM-PC HDD support #options COMPAT_ATDISK # @@ -100,13 +94,24 @@ device wcd0 #IDE CD-ROM # for any number of installed devices. controller ncr0 controller ahc0 -options "AHC_FORCE_PIO" # Some motherboards choke on MemI/O, - # so use PIO in the ahc driver in the - # generic kernel. -controller sbic0 at isa? port "IO_SCSI" bio irq 5 drq 3 vector sbicintr -# sbic55.c.new -#controller sbic0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0xff vector sbicintr +# +# WD33C93 SCSI card (55/92 like board) +# + +options BS_TARG_SAFEMODE + +# PC-9801-92 +controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0 vector bsintr +# SC-98 +# controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0x10000 vector bsintr +# HA-55BS2 and later +#controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0x20000 vector bsintr +# ELECOM type +#controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 flags 0x30000 vector bsintr +# SMIT +#controller bs0 at isa? port "IO_SCSI" bio irq 5 drq 3 iomem 0xdd000 iosiz 0x1000 flags 0x40000 vector bsintr + controller aic0 at isa? port 0x1840 bio irq 5 flags 0x10000 vector aicintr controller scbus0 diff --git a/sys/pc98/pc98/sbic55.c b/sys/pc98/pc98/sbic55.c deleted file mode 100644 index 2bcaf17..0000000 --- a/sys/pc98/pc98/sbic55.c +++ /dev/null @@ -1,917 +0,0 @@ -/* - * Julian SCSI driver for PC-9801 based on aha1542.c - * - * Copyright (c) by Yoshio Kimura - * 05/14/1994 - */ - -#include <sys/types.h> -#include "sbic.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/errno.h> -#include <sys/ioctl.h> -#include <sys/malloc.h> -#include <sys/buf.h> -#include <sys/proc.h> - -#include <machine/clock.h> -#include <machine/cpu.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> - -#include <pc98/pc98/pc98.h> -#include <i386/isa/isa_device.h> -#include <i386/isa/icu.h> -#include <i386/isa/ic/i8237.h> -#include <pc98/pc98/scsireg.h> -#include <scsi/scsi_all.h> -#include <scsi/scsiconf.h> - -#include <sys/kernel.h> - -/************************** board definitions *******************************/ - -/* - * I/O Port Interface - */ - -#define SBIC_BASE sbic->sbic_base -#define SBIC_AUX_REG (SBIC_BASE + 0) /* auxiliary status(R) */ -#define SBIC_ADR_REG (SBIC_BASE + 0) /* address(W) */ -#define SBIC_CTL_REG (SBIC_BASE + 2) /* control(R/W) */ -#define SBIC_STA_REG (SBIC_BASE + 4) /* status(R/W) */ - -/* - * Register Access Interface - */ - -#define SBIC_asr(val) (val) = inb(SBIC_AUX_REG) -#define GET_SBIC_REG(regno, val) { \ - outb(SBIC_ADR_REG, (regno)); \ - (val) = inb(SBIC_CTL_REG); \ - } -#define SET_SBIC_REG(regno, val) { \ - outb(SBIC_ADR_REG, (regno)); \ - outb(SBIC_CTL_REG, (val)); \ - } -#define SET_SCSI_CMD(cmd, cmdlen) { \ - int n; \ - u_char *cmds = (u_char *)(cmd); \ - SET_SBIC_REG(SBIC_cdbsize, (cmdlen)); \ - for (n = 0; n < (cmdlen); n++) { \ - SET_SBIC_REG(SBIC_cdb1 + n, cmds[n]); \ - } \ - } -#define SET_XFER_LEN(val) { \ - SET_SBIC_REG(SBIC_count_hi, ((val) & 0xff0000) >> 16); \ - SET_SBIC_REG(SBIC_count_med, ((val) & 0x00ff00) >> 8); \ - SET_SBIC_REG(SBIC_count_lo, (val) & 0x0000ff); \ - } -#define SBIC_ENABLE_INT() { \ - int tmp; \ - GET_SBIC_REG(SBIC_bank, tmp); \ - SET_SBIC_REG(SBIC_bank, tmp | 0x04); \ - } -#define SBIC_DISABLE_INT() { \ - int tmp; \ - GET_SBIC_REG(SBIC_bank, tmp); \ - SET_SBIC_REG(SBIC_bank, tmp & 0xfb); \ - } -#define SBIC_DMA_ENABLE() outb(SBIC_STA_REG, 1) - -#define INT3 0 -#define INT5 1 -#define INT6 2 -#define INT9 3 -#define INT12 4 -#define INT13 5 - -#define SBIC_NSEG 17 -#define SBIC_ID 7 -#define MAXSIMUL 8 -#define SBIC_RESET_TIMEOUT 2000 /* time to wait for reset */ - -extern short dmapageport[]; - - -struct sbic_ccb { - u_char target; - u_char lun; - u_char status; - u_char message; - int datalen; - int sense_addr; - int sense_len; - u_char scsi_cmdlen; - struct scsi_generic scsi_cmd; - struct scsi_xfer *xfer; - struct scat_gather { - int seg_addr; - int seg_len; - } scat_gath[SBIC_NSEG]; - int seg; - int use_seg; - int xs_flags; - int flags; -#define CCB_FREE 0x00 -#define CCB_ACTIVE 0x01 -#define CCB_ABORT 0x40 -#define CCB_SENSE 0x80 -#define CCB_BOUNCE 0x100 -}; - -struct sbic_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char :5; -}; -/*********************************** end of board definitions***************/ - -#define KVTOPHYS(x) vtophys(x) -#define SBIC_DMA_PAGES SBIC_NSEG - -#define PAGESIZ 4096 -#define ALLWAYS_BOUNCE - -#ifdef ALLWAYS_BOUNCE -static vm_offset_t sbic_bounce; -#endif - -#ifdef SBICDEBUG -static int sbic_debug = 1; -#endif - -struct sbic_data { - short sbic_base; /* base port for each board */ - struct sbic_ccb sbic_ccb[MAXSIMUL]; - int top; /* ccb queue top */ - int bottom; /* ccb queue end */ - int active; /* number of active ccb */ - int free; /* number of free ccb */ - int unit; - int sbic_int; /* our irq level */ - int sbic_dma; /* our DMA req channel */ - int sbic_scsi_dev; /* our scsi bus address */ - struct scsi_link sc_link; /* prototype for subdevs */ -}; - -struct sbic_data *sbicdata[NSBIC];; - -static struct sbic_ccb *sbic_get_ccb(struct sbic_data *, int); -static int sbicprobe(struct isa_device *); -static void sbic_done(struct sbic_data *, struct sbic_ccb *); -static int sbicattach(struct isa_device *); -static int32_t sbic_scsi_cmd(struct scsi_xfer *xs); -static u_int32_t sbic_adapter_info(int); -static void sbicminphys(struct buf *); -static void sbic_free_ccb(struct sbic_data *, struct sbic_ccb *, int); -static int sbic_init(int); -static int xfer_addr_check(int, struct sbic_ccb *); -static int sbic_poll(struct sbic_data *, struct sbic_ccb *); -static void start_scsi(struct sbic_data *, struct sbic_ccb *); -static void dataphase(struct sbic_data *, struct sbic_ccb *); -static void sbic_request_sense(struct sbic_data *, struct sbic_ccb *); -static void sbic_dmastart(int, int, unsigned, unsigned); -static void sbic_dmadone(int, int, unsigned, unsigned); - -static struct scsi_adapter sbic_switch = { - sbic_scsi_cmd, - sbicminphys, - 0, - 0, - sbic_adapter_info, - "sbic", - { 0, 0 } -}; - -/* the below structure is so we have a default dev struct for out link struct */ -static struct scsi_device sbic_dev = { - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ - "sbic", - 0, - { 0, 0 } -}; - -struct isa_driver sbicdriver = { - sbicprobe, - sbicattach, - "sbic" -}; - -static int sbicunit = 0; - -/* - * Check if the device can be found at the port given - * and if so, set it up ready for further work - * as an argument, takes the isa_device structure from - * autoconf.c - */ -static int -sbicprobe(struct isa_device *dev) -{ - int unit = sbicunit; - struct sbic_data *sbic; - - /* - * find unit and check we have that many defined - */ - if (unit >= NSBIC) { - printf("sbic: unit number (%d) to high\n", unit); - return(0); - } - dev->id_unit = unit; - - /* - * a quick safety check so we can be sleazy later - */ - if (sizeof(struct sbic_data) > PAGESIZ) { - printf("sbic struct > pagesize\n"); - return(0); - } - /* - * Allocate a storage area for us - */ - if (sbicdata[unit]) { - printf("sbic%d: memory already allocated\n", unit); - return(0); - } - sbic = malloc(sizeof(struct sbic_data), M_TEMP, M_NOWAIT); - if (!sbic) { - printf("sbic%d: cannot malloc!\n", unit); - return(0); - } - bzero(sbic, sizeof(struct sbic_data)); - sbicdata[unit] = sbic; - sbic->sbic_base = dev->id_iobase; - -#ifdef ALLWAYS_BOUNCE - /* - * allocate bounce buffer for sense data - */ -#ifdef EPSON_BOUNCEDMA -#define PC98_RAMEND 0xf00000 -#else -#define PC98_RAMEND RAM_END -#endif - - /* try malloc() first. */ - sbic_bounce = (vm_offset_t)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); - if (sbic_bounce != NULL) { - if (vtophys(sbic_bounce) >= PC98_RAMEND) { - free(buf, M_DEVBUF); - sbic_bounce = (vm_offset_t)contigmalloc(PAGE_SIZE, M_DEVBUF, - M_NOWAIT, - 0ul, PC98_RAMEND, 1ul, - 0x10000ul); - } - } - if (sbic_bounce == NULL) - panic("Can't allocate bounce buffer."); -#endif - - /* - * Try initialize a unit at this location - * sets up dma, loads sbic_init[unit] - */ - if (sbic_init(unit) != 0) { - sbicdata[unit] = NULL; - free(sbic, M_TEMP); - return(0); - } - /* - * If it's there, put in it's interrupt vectors - */ - dev->id_irq = (1 << sbic->sbic_int); - dev->id_drq = sbic->sbic_dma; - sbicunit++; - return(5); -} - -/* - * Attach all the sub-devices we can find. - */ -static int -sbicattach(struct isa_device *dev) -{ - int unit = dev->id_unit; - struct sbic_data *sbic = sbicdata[unit]; - struct scsibus_data *scbus; - - /* - * fill in the prototype scsi_link - */ - sbic->sc_link.adapter_unit = unit; - sbic->sc_link.adapter_targ = sbic->sbic_scsi_dev; - sbic->sc_link.adapter_softc = sbic; - sbic->sc_link.adapter = &sbic_switch; - sbic->sc_link.device = &sbic_dev; - sbic->sc_link.flags = SDEV_BOUNCE; - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = &sbic->sc_link; - - /* - * ask the adapter what subunits are present - */ - scsi_attachdevs(scbus); - - return 1; -} - -/* - * Return some information to the caller about - * the adapter and it's capabilities - */ -static u_int32_t -sbic_adapter_info(int unit) -{ - return(1); /* 1 outstanding request at a time per device */ -} - -/* - * Catch an interrupt from the adapter - */ -void -sbicintr(int unit) -{ - struct sbic_ccb *ccb; - struct sbic_data *sbic = sbicdata[unit]; - u_char asr, host_stat, cmd_phase; - u_char *cmd; - int i, seg, phys; - -#ifdef SBICDEBUG - printf("sbicintr"); -#endif /* SBICDEBUG */ - - SBIC_asr(asr); - /* drop spurious interrupts */ - if (!(asr & SBIC_ASR_INT)) - return; - GET_SBIC_REG(SBIC_csr, host_stat); - GET_SBIC_REG(SBIC_cmd_phase, cmd_phase); - - ccb = &sbic->sbic_ccb[sbic->top]; - seg = ccb->seg; - - switch(host_stat) { - case SBIC_CSR_XFERRED | SBIC_MCI_DATA_OUT: /* data phase start */ - case SBIC_CSR_MIS_1 | SBIC_MCI_DATA_OUT: /* data phase continue */ - case SBIC_CSR_XFERRED | SBIC_MCI_DATA_IN: - case SBIC_CSR_MIS_1 | SBIC_MCI_DATA_IN: - dataphase(sbic, ccb); - return; - case SBIC_CSR_MIS_1 | SBIC_MCI_STATUS: /* status phase start */ - case SBIC_CSR_XFERRED | SBIC_MCI_STATUS: /* status phase start */ - SET_XFER_LEN(0); - SET_SBIC_REG(SBIC_cmd_phase, 0x46); - SET_SBIC_REG(SBIC_cmd, SBIC_CMD_SEL_XFER); - return; - case SBIC_CSR_S_XFERRED: - phys = KVTOPHYS(ccb->sense_addr); - if (ccb->flags & CCB_SENSE) { - sbic_dmadone(B_READ, phys, - ccb->sense_len, sbic->sbic_dma); - } else { - if ((ccb->datalen) && (ccb->xs_flags & SCSI_DATA_IN)) { - sbic_dmadone(B_READ, - ccb->scat_gath[seg - 1].seg_addr, - ccb->scat_gath[seg - 1].seg_len, - sbic->sbic_dma); - } - if ((ccb->datalen) && (ccb->xs_flags & SCSI_DATA_OUT)) { - sbic_dmadone(B_WRITE, - ccb->scat_gath[seg - 1].seg_addr, - ccb->scat_gath[seg - 1].seg_len, - sbic->sbic_dma); - } - } - GET_SBIC_REG(SBIC_tlun, ccb->status); - ccb->status &= 0x1f; - switch(ccb->status) { - case SCSI_CHECK: - ccb->flags |= CCB_SENSE; - ccb->xfer->error = XS_SENSE; - sbic_request_sense(sbic, ccb); - return; - case SCSI_BUSY: - ccb->xfer->error = XS_BUSY; - break; - default: - break; - } - sbic_done(sbic, ccb); - break; - - case SBIC_CSR_SEL_TIMEO: /* selection timeout */ - ccb->xfer->error = XS_TIMEOUT; - sbic_done(sbic, ccb); - break; - - default: - printf("sbic%d:%d:%d -- ", unit, ccb->target, ccb->lun); - printf("host: %x interrupt occured\n", host_stat); - panic("Unsupported interrupts. check intr code\n"); - break; - } - return; -} - -/* - * A ccb is put onto the free list. - */ -static void -sbic_free_ccb(struct sbic_data *sbic, struct sbic_ccb *ccb, int flags) -{ - unsigned opri = 0; - - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - if (ccb = &sbic->sbic_ccb[sbic->top]) - sbic->top = ++sbic->top % MAXSIMUL; - else - sbic->bottom = (--sbic->bottom + MAXSIMUL) % MAXSIMUL; - sbic->active--; - sbic->free++; - ccb->flags = CCB_FREE; - if (sbic->free) - wakeup((caddr_t)&sbic->free); - if (!(flags & SCSI_NOMASK)) - splx(opri); -} - -/* - * Get a free ccb - */ -static struct sbic_ccb * -sbic_get_ccb(struct sbic_data *sbic, int flags) -{ - unsigned opri = 0; - struct sbic_ccb *rc; - - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - /* - * If we can and have to, sleep waiting for one to come free - */ - while((!sbic->free) && (!(flags & SCSI_NOSLEEP))) - tsleep((caddr_t)&sbic->free, PRIBIO, "sbicccb", 0); - if (sbic->free) { - rc = &sbic->sbic_ccb[sbic->bottom]; - sbic->free--; - sbic->active++; - sbic->bottom = ++sbic->bottom % MAXSIMUL; - rc->flags = CCB_ACTIVE; - } else - rc = (struct sbic_ccb *)0; - if (!(flags & SCSI_NOMASK)) - splx(opri); - return(rc); -} - -/* - * We have a ccb which has been processed by the - * adapter, now we lock to see how the operation - * went. Wake up the owner if waiting - */ -static void -sbic_done(struct sbic_data *sbic, struct sbic_ccb *ccb) -{ - struct scsi_xfer *xs = ccb->xfer; - unsigned opri; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("sbic_done\n")); - if (!(xs->flags & INUSE)) { - printf("sbic%d: exiting but not in use!\n", sbic->unit); - Debugger("sbic55"); - } - if ((!xs->error) || (xs->flags & SCSI_ERR_OK)) - xs->resid = 0; - - xs->flags |= ITSDONE; -#ifdef ALLWAYS_BOUNCE - bcopy((char *)ccb->sense_addr, (char *)&xs->sense, ccb->sense_len); -#else - if(ccb->flags & CCB_BOUNCE) - bcopy((char *)ccb->sense_addr, - (char *)&xs->sense, ccb->sense_len); -#endif - sbic_free_ccb(sbic, ccb, xs->flags); - if(sbic->active) { - opri = splbio(); - SBIC_ENABLE_INT(); - start_scsi(sbic, &sbic->sbic_ccb[sbic->top]); - splx(opri); - } - scsi_done(xs); -} - -/* - * Start the board, ready for normal operation - */ -static int -sbic_init(int unit) -{ - struct sbic_data *sbic = sbicdata[unit]; - struct sbic_config conf; - int i, asr, csr, tmp; - - SBIC_asr(asr); /* dummy read */ - GET_SBIC_REG(SBIC_csr, csr); - SBIC_DISABLE_INT(); - - SET_SBIC_REG(SBIC_myid, SBIC_ID_FS_16_20 | SBIC_ID); - SET_SBIC_REG(SBIC_cmd, SBIC_CMD_RESET); - for (i = SBIC_RESET_TIMEOUT; i; i--) { - SBIC_asr(asr); - if ((asr != 0xff) && (asr & SBIC_ASR_INT)) { - GET_SBIC_REG(SBIC_csr, csr); - if (csr == SBIC_CSR_RESET) - break; - } - DELAY(1); /* calibrated in msec */ - } - if (i == 0) { -#ifdef SBICDEBUG - if (sbic_debug) - printf("sbic_init: No answer from sbic board\n"); -#endif - return(ENXIO); - } - - conf.chan = (inb(SBIC_STA_REG) & 0x03); - GET_SBIC_REG(SBIC_int, tmp); - conf.intr = (tmp >> 3) & 0x07; - conf.scsi_dev = tmp & 0x07; - sbic->sbic_dma = conf.chan; - sbic->sbic_scsi_dev = conf.scsi_dev; - switch(conf.intr) { - case INT3: - sbic->sbic_int = 3; - break; - case INT5: - sbic->sbic_int = 5; - break; - case INT6: - sbic->sbic_int = 6; - break; - case INT9: - sbic->sbic_int = 9; - break; - case INT12: - sbic->sbic_int = 12; - break; - case INT13: - sbic->sbic_int = 13; - break; - default: - printf("illegal int jumpter setting\n"); - return(EIO); - } - - SET_SBIC_REG(SBIC_rselid, 0); -#if 1 - SET_SBIC_REG(SBIC_timeo, 0x80); -#else - SET_SBIC_REG(SBIC_timeo, 0xa0); -#endif - SET_SBIC_REG(SBIC_control, SBIC_CTL_EDI); - SET_SBIC_REG(SBIC_syn, 0); - SBIC_ENABLE_INT(); - /* - * ccb queue initialize - */ - for (i = 0; i < MAXSIMUL; i++) { - sbic->sbic_ccb[i].flags = CCB_FREE; - } - sbic->top = sbic->bottom = sbic->active = 0; - sbic->free = MAXSIMUL; - /* - * Note that wa are going and return (to probe) - */ - return(0); -} - -static void -sbicminphys(struct buf *bp) -{ -/* sbic seems to explode with 17 segs (64k may require 17 segs) */ - if (bp->b_bcount > ((SBIC_NSEG - 1) *PAGESIZ)) - bp->b_bcount = ((SBIC_NSEG - 1) * PAGESIZ); -} - -/* - * start a scsi operation given the command and - * the data address. Also needs the unit, target - * and lu - */ -static int32_t -sbic_scsi_cmd(struct scsi_xfer *xs) -{ - struct scsi_link *sc_link = xs->sc_link; - int unit = sc_link->adapter_unit; - struct sbic_data *sbic = sc_link->adapter_softc; - struct sbic_ccb *ccb; - int s, i, retval, flags; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("sbic_scsi_cmd\n")); - flags = xs->flags; - if (!(ccb = sbic_get_ccb(sbic, flags))) { - xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); - } - ccb->xfer = xs; - ccb->target = xs->sc_link->target; - ccb->lun = xs->sc_link->lun; - ccb->xs_flags = xs->flags; - ccb->scsi_cmdlen = xs->cmdlen; - ccb->datalen = xs->datalen; - ccb->sense_len = sizeof(xs->sense); -#ifdef ALLWAYS_BOUNCE - ccb->sense_addr = (int)(sbic_bounce); -#else - ccb->sense_addr = (int)&xs->sense; -#endif - ccb->seg = 0; - - if (retval = xfer_addr_check(unit, ccb)) { - xs->error = XS_DRIVER_STUFFUP; - sbic_free_ccb(sbic, ccb, flags); - return(retval); - } - if (!(flags & SCSI_RESET)) { - bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmdlen); - ccb->scsi_cmd.bytes[0] |= ((ccb->lun << 5) & 0xe0); - } - if (!(flags & SCSI_NOMASK)) { - if (sbic->active == 1) { - s = splbio(); - SBIC_ENABLE_INT(); - start_scsi(sbic, ccb); - splx(s); - } - SC_DEBUG(xs->sc_link, SDEV_DB3, ("sent\n")); - return(SUCCESSFULLY_QUEUED); - } - SBIC_DISABLE_INT(); - start_scsi(sbic, ccb); - SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd sent, waiting\n")); - return(sbic_poll(sbic, ccb)); -} - -static int -sbic_poll(struct sbic_data *sbic, struct sbic_ccb *ccb) -{ - int count, asr, done = 0; - - count = ccb->xfer->timeout * 1000; - while(count) { - SBIC_asr(asr); - if ((asr != 0xff) && (asr & SBIC_ASR_INT)) { - sbicintr(sbic->unit); - } - if (ccb->xfer->flags & ITSDONE) { - break; - } - DELAY(1); - count--; - } - if (!count) panic("sbic scsi timeout!!"); - if (ccb->xfer->error) return(HAD_ERROR); - return(COMPLETE); -} - -static int -xfer_addr_check(int unit, struct sbic_ccb *ccb) -{ - struct iovec *iovp; - struct scat_gather *sg; - struct scsi_xfer *xs; - int thiskv, thisphys, nextphys; - int bytes_this_page, bytes_this_seg; - int datalen, flags; - - xs = ccb->xfer; - flags = ccb->xs_flags; - if ((xs->datalen) && (!(flags & SCSI_RESET))) { - sg = ccb->scat_gath; - ccb->use_seg = 0; - if (flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; - while((datalen) && (ccb->use_seg < SBIC_NSEG)) { - sg->seg_addr = KVTOPHYS((int)iovp->iov_base); - sg->seg_len = iovp->iov_len; - SC_DEBUGN(xs->sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)" - ,iovp->iov_len - ,iovp->iov_base)); - sg++; - iovp++; - ccb->use_seg++; - datalen++; - } - } else { - /* - * Set up scatter gather block - */ - SC_DEBUG(xs->sc_link, SDEV_DB4, - ("%d @0x%x:- ", xs->datalen, xs->data)); - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - while((datalen) && (ccb->use_seg < SBIC_NSEG)) { - bytes_this_seg = 0; - sg->seg_addr = thisphys; - SC_DEBUGN(xs->sc_link, SDEV_DB4, - ("0x%x", thisphys)); - nextphys = thisphys; - while((datalen) && (thisphys == nextphys)) { - if (thisphys > 0xFFFFFF) { - printf("sbic%d: DMA beyond" - " end of PC98\n", unit); - xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); - } - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = nextphys - thisphys; - bytes_this_page = min(bytes_this_page, - datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - SC_DEBUGN(xs->sc_link, SDEV_DB4, - ("(0x%x)", bytes_this_seg)); - sg->seg_len = bytes_this_seg; - sg++; - ccb->use_seg++; - } - } - SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); - if (datalen) { - printf("sbic%d: sbic_scsi_cmd, more than %d DMA segs\n", - unit, SBIC_NSEG); - xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); - } - } else { - ccb->scat_gath[0].seg_len = 0; - } - return(0); -} - -static void -start_scsi(struct sbic_data *sbic, struct sbic_ccb *ccb) -{ - if (ccb->xs_flags & SCSI_RESET) { - SET_SBIC_REG(SBIC_cmd, SBIC_CMD_RESET); - return; - } - - if ((ccb->datalen) && (ccb->xs_flags & SCSI_DATA_IN)) - sbic_dmastart(B_READ, ccb->scat_gath[0].seg_addr, - ccb->scat_gath[0].seg_len, sbic->sbic_dma); - if ((ccb->datalen) && (ccb->xs_flags & SCSI_DATA_OUT)) - sbic_dmastart(B_WRITE, ccb->scat_gath[0].seg_addr, - ccb->scat_gath[0].seg_len, sbic->sbic_dma); - SET_SCSI_CMD(&ccb->scsi_cmd, ccb->scsi_cmdlen); - SET_XFER_LEN(ccb->scat_gath[0].seg_len); - SET_SBIC_REG(SBIC_selid, ccb->target); - SET_SBIC_REG(SBIC_tlun, ccb->lun); - SBIC_DMA_ENABLE(); - SET_SBIC_REG(SBIC_control, SBIC_CTL_DMA | SBIC_CTL_EDI); - SET_SBIC_REG(SBIC_cmd, SBIC_CMD_SEL_XFER); - ccb->seg++; - return; -} - -static void -dataphase(struct sbic_data *sbic, struct sbic_ccb *ccb) -{ - int seg = ccb->seg, tmp; - - if ((ccb->datalen) && (ccb->xs_flags & SCSI_DATA_IN)) { - sbic_dmadone(B_READ, ccb->scat_gath[seg - 1].seg_addr, - ccb->scat_gath[seg - 1].seg_len, sbic->sbic_dma); - sbic_dmastart(B_READ, ccb->scat_gath[seg].seg_addr, - ccb->scat_gath[seg].seg_len, sbic->sbic_dma); - } - if ((ccb->datalen) && (ccb->xs_flags & SCSI_DATA_OUT)) { - sbic_dmadone(B_WRITE, ccb->scat_gath[seg - 1].seg_addr, - ccb->scat_gath[seg - 1].seg_len, sbic->sbic_dma); - sbic_dmastart(B_WRITE, ccb->scat_gath[seg].seg_addr, - ccb->scat_gath[seg].seg_len, sbic->sbic_dma); - } - SBIC_DMA_ENABLE(); - SET_SBIC_REG(SBIC_control, SBIC_CTL_DMA | SBIC_CTL_EDI); - SET_XFER_LEN(ccb->scat_gath[seg].seg_len); - SET_SBIC_REG(SBIC_cmd, SBIC_CMD_XFER_INFO); - ccb->seg++; - return; -} - -static void -sbic_request_sense(struct sbic_data *sbic, struct sbic_ccb *ccb) -{ - int phys, len; - unsigned chan; - u_char cmd[6] = { 3, 0, 0, 0, 0, 0 }; - - cmd[1] |= ((ccb->lun << 5) & 0xe0); - - chan = sbic->sbic_dma; - len = ccb->sense_len; -#ifndef ALLWAYS_BOUNCE - if(isa_dmarangecheck((caddr_t)ccb->sense_addr,len)) { - ccb->sense_addr = (int)(sbic_bounce); - ccb->flags |= CCB_BOUNCE; - } -#endif - phys = KVTOPHYS(ccb->sense_addr); - sbic_dmastart(B_READ, phys, len, chan); - - SET_SCSI_CMD(cmd, 6); - SET_XFER_LEN(ccb->sense_len); - SET_SBIC_REG(SBIC_selid, ccb->target); - SET_SBIC_REG(SBIC_tlun, ccb->lun); - SBIC_DMA_ENABLE(); - SET_SBIC_REG(SBIC_control, SBIC_CTL_DMA | SBIC_CTL_EDI); - SET_SBIC_REG(SBIC_cmd, SBIC_CMD_SEL_XFER); - return; -} - - -static void -sbic_dmastart(int flags, int phys, unsigned nbytes, unsigned chan) -{ - int modeport, waport, mskport; - caddr_t newaddr; - int s; - - if (chan > 3 || nbytes > (1<<16)) - panic("sbic_dmastart: impossible request"); - - s = splbio(); /* mask on */ - -#ifdef CYRIX_5X86 - asm("wbinvd"); /* wbinvd (WB cache flush) */ -#endif - - /* mask channel */ - mskport = IO_DMA + 0x14; /* 0x15 */ - outb(mskport, chan & 3 | 0x04); - - /* set dma channel mode, and reset address ff */ - modeport = IO_DMA + 0x16; /* 0x17 */ - if (flags & B_READ) { - outb(modeport, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); - } else { - outb(modeport, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); - } - outb(modeport + 1*2, 0); /* 0x19 (clear byte pointer) */ - - /* send start address */ - waport = IO_DMA + (chan<<2); /* 0x1, 0x5, 0x9, 0xd */ - outb(waport, phys); - outb(waport, phys>>8); - outb(dmapageport[chan], phys>>16); - - /* send count */ - outb(waport + 2, --nbytes); /* 0x3, 0x7, 0xb, 0xf */ - outb(waport + 2, nbytes>>8); - - /* unmask channel */ - mskport = IO_DMA + 0x14; /* 0x15 */ - outb(mskport, chan & 3); - - splx(s); /* mask off */ -} - -static void -sbic_dmadone(int flags, int addr, unsigned nbytes, unsigned chan) -{ -#if defined(CYRIX_486DLC) || defined(IBM_486SLC) - if (flags & B_READ) { - /* cache flush only after reading 92/12/9 by A.Kojima */ - asm(" .byte 0x0f,0x08"); /* invd (cache flush) */ - } -#endif -} diff --git a/sys/pc98/pc98/sbic55.c.new b/sys/pc98/pc98/sbic55.c.new deleted file mode 100644 index 5dc9091..0000000 --- a/sys/pc98/pc98/sbic55.c.new +++ /dev/null @@ -1,1745 +0,0 @@ -/* $NetBSD: sbic.c,v 1.10 1995/02/12 19:19:20 chopps Exp $ */ - -/* - * Copyright (c) 1994 Christian E. Hopps - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson of Lawrence Berkeley Laboratory. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. - * - * @(#)scsi.c 7.5 (Berkeley) 5/4/91 - */ -/* - * Ported to PC-9801 by Yoshio Kimura, 1994 - * last update 09/25/1994 - */ - -/* - * AMIGA AMD 33C93 scsi adaptor driver - */ - -#include "sbic.h" - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/errno.h> -#include <sys/ioctl.h> -#include <sys/device.h> -#include <sys/disklabel.h> -#include <sys/dkstat.h> -#include <sys/malloc.h> -#include <sys/buf.h> -#include <sys/proc.h> - -#include <machine/clock.h> -#include <machine/cpu.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> - -#include <i386/isa/icu.h> -#include <pc98/pc98/pc98.h> -#include <i386/isa/isa_device.h> -#include <i386/isa/ic/i8237.h> -#include <scsi/scsi_all.h> -#include <scsi/scsiconf.h> - -#include <pc98/pc98/sbicreg.h> -#include <pc98/pc98/sbicvar.h> - -extern short dmapageport[]; - -/* - * SCSI delays - * In u-seconds, primarily for state changes on the SPC. - */ -#define SBIC_CMD_WAIT 50000 /* wait per step of 'immediate' cmds */ -#define SBIC_DATA_WAIT 50000 /* wait per data in/out step */ -#define SBIC_INIT_WAIT 50000 /* wait per step (both) during init */ -#define SBIC_RESET_TIMEOUT 2000 - -#define SBIC_WAIT(sbic, until, timeo) sbicwait(sbic, until, timeo, __LINE__) -#define SBIC_ENABLE_INT(iobase) { \ - u_char tmp; \ - GET_SBIC_mem_bank(iobase, tmp); \ - SET_SBIC_mem_bank(iobase, tmp | 0x04);\ - } -#define SBIC_DISABLE_INT(iobase) { \ - u_char tmp; \ - GET_SBIC_mem_bank(iobase, tmp); \ - SET_SBIC_mem_bank(iobase, tmp & 0xfb); \ - } - -#define INT0 0 -#define INT1 1 -#define INT2 2 -#define INT3 3 -#define INT5 5 -#define INT6 6 - -static struct sbic_softc *sbicdata[NSBIC]; - -#define KVTOPHYS(x) vtophys(x) - -static int sbicprobe __P((struct isa_device *)); -static int sbicattach __P((struct isa_device *)); - -static u_int32_t sbic_adapter_info __P((int)); -static int sbic_find __P((struct sbic_softc *)); -static int32_t sbic_scsi_cmd __P((struct scsi_xfer *)); -static int sbicicmd __P((struct sbic_softc *, - int, int, void *, int, void *, int,u_char)); -static int sbicgo __P((struct sbic_softc *, struct scsi_xfer *)); -static int sbicdmaok __P((struct sbic_softc *, struct scsi_xfer *)); -static int sbicgetsense __P((struct sbic_softc *, struct scsi_xfer *)); -static int sbicwait __P((struct sbic_softc *, char, int , int)); -static int sbicselectbus __P((struct sbic_softc *, u_char, u_char, u_char)); -static int sbicxfstart __P((struct sbic_softc *, int, u_char, int)); -static int sbicxfout __P((struct sbic_softc *, int, void *, int)); -static int sbicfromscsiperiod __P((struct sbic_softc *, int)); -static int sbictoscsiperiod __P((struct sbic_softc *, int)); -static void sbicminphys __P((struct buf *)); -static void sbicxfin __P((struct sbic_softc *, int, void *)); -static void sbicxfdone __P((struct sbic_softc *, int)); -static void sbicabort __P((struct sbic_softc *, char *)); -static void sbicerror __P((struct sbic_softc *, u_char)); -static void sbicreset __P((struct sbic_softc *)); -static void sbicsetdelay __P((int)); -static void sbic_scsidone __P((struct sbic_softc *, int)); -static void sbic_donextcmd __P((struct sbic_softc *)); -static void sbic_dmastart __P((struct sbic_softc *)); -static void sbic_dmastop __P((struct sbic_softc *)); - -/* - * Synch xfer parameters, and timing conversions - */ -static int sbic_min_period = SBIC_SYN_MIN_PERIOD; /* in cycles = f(ICLK,FSn) */ -static int sbic_max_offset = SBIC_SYN_MAX_OFFSET; /* pure number */ - -static int sbic_cmd_wait = SBIC_CMD_WAIT; -static int sbic_data_wait = SBIC_DATA_WAIT; -static int sbic_init_wait = SBIC_INIT_WAIT; - -/* - * was broken before.. now if you want this you get it for all drives - * on sbic controllers. - */ -#ifdef SCSI_SYNC -static int sbic_inhibit_sync = 0; -#else -static int sbic_inhibit_sync = 1; -#endif - -static int sbic_force_async_flag = 0; - -#ifdef SC98BUSMASTER -static int sc98busmaster = 0; -#endif - -#ifdef DEBUG -#define QPRINTF(a) if (sbic_debug > 1) printf a -int sbic_debug = 0; -int sync_debug = 0; -int sbic_dma_debug = 0; -#else -#define QPRINTF(a) -#endif - -static -struct scsi_adapter sbic_switch = { - sbic_scsi_cmd, - sbicminphys, - 0, - 0, - sbic_adapter_info, - "sbic" - , { 0, 0 } -}; - -/* the below structure is so we have a default dev struct for out link struct */ -static -struct scsi_device sbic_dev = { - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ - "sbic", - 0 - , { 0, 0 } -}; - -struct isa_driver sbicdriver = { - sbicprobe, - sbicattach, - "sbic" -}; - -static int sbicunit = 0; - -/* - * Check if the device can be found at the port given - * and if so, set ip up ready for further work - * as an argument, takes the pc98_device structure from - * autoconf.c - */ -static int -sbicprobe(dev) - struct isa_device *dev; -{ - int unit = sbicunit; - struct sbic_softc *sbic; - -#define SBICFLAGS -# ifdef SBICFLAGS - sbic_force_async_flag = dev->id_flags; -# else - sbic_force_async_flag = 0; -# endif - if (unit >= NSBIC) { - printf("sbic%d: unit number too high\n", unit); - return 0; - } - dev->id_unit = unit; - /* - * Allocate a storage area for us - */ - if (sbicdata[unit]) { - printf("sbic%d: memory already allocated\n", unit); - return 0; - } - sbic = malloc(sizeof(struct sbic_softc), M_TEMP, M_NOWAIT); - if (!sbic) { - printf("sbic%d: cannot malloc!\n", unit); - return 0; - } - bzero(sbic, sizeof(struct sbic_softc)); - sbicdata[unit] = sbic; - sbic->sc_base = dev->id_iobase; - - if (sbic_find(sbic) != 0) { - sbicdata[unit] = NULL; - free(sbic, M_TEMP); - return 0; - } - - dev->id_irq = sbic->sc_int; - dev->id_drq = sbic->sc_dma; - sbicunit++; - return 5; -} - - -/* - * Attach all the sub-devices we can find - */ -static int -sbicattach(dev) - struct isa_device *dev; -{ - int unit = dev->id_unit; - struct sbic_softc *sbic = sbicdata[unit]; - struct scsibus_data *scbus; -#if defined(SC98BUSMASTER) || defined(FORCE_BUSMASTER) - int a; - int i; -#endif - -#ifdef FORCE_BUSMASTER - sbic_read_reg(sbic->sc_base, 0x37, a); - /* set busmaster flag */ - sbic_write_reg(sbic->sc_base, 0x37, a | 0x08); - printf("sbic%d: set busmaster flag\n", unit); -#if defined(HA55BS_ID) && defined(SCSI_SYNC) - sbic_read_reg(sbic->sc_base, 0x60 + HA55BS_ID, a); - for (i = 0; i < 7; i++) { - if (sbic_force_async_flag & 1 << i) { - sbic_write_reg(sbic->sc_base, 0x60 + i, a); - printf("sbic%d: set transfer rate (ID %d)\n", - unit, i); - } - } - sbic_force_async_flag = 0; -#endif -#endif - -#ifdef SC98BUSMASTER - sbic_read_reg(sbic->sc_base, 0x37, a); - if (a & 0x08) { - printf("sbic%d: busmaster enable\n", unit); - sc98busmaster = 1; - } -#endif - /* - * fill in the prototype scsi_link. - */ - sbic->sc_link.adapter_unit = unit; - sbic->sc_link.adapter_softc = sbic; - sbic->sc_link.adapter_targ = sbic->sc_scsi_dev; - sbic->sc_link.adapter = &sbic_switch; - sbic->sc_link.device = &sbic_dev; - sbic->sc_link.flags = SDEV_BOUNCE; - TAILQ_INIT(&sbic->sc_xslist); - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = &sbic->sc_link; - - /* - * ask the adapter what subunits are present - */ - scsi_attachdevs(scbus); - - return 1; -} - -/* - * Find the board and find its irq/drq - */ -static int -sbic_find(sbic) - struct sbic_softc *sbic; -{ - int intr, my_id, asr, csr; - volatile int i, sts; - - GET_SBIC_asr(sbic->sc_base, asr); /* dummy read */ - GET_SBIC_csr(sbic->sc_base, csr); - SBIC_DISABLE_INT(sbic->sc_base); - - GET_SBIC_myid(sbic->sc_base, my_id); - switch(my_id & 0xc0) { - case SBIC_ID_FS_8_10: - sbic->sc_clkfreq = 100; - break; - case SBIC_ID_FS_12_15: - sbic->sc_clkfreq = 150; - break; - case SBIC_ID_FS_16_20: - sbic->sc_clkfreq = 200; - break; - } - sbic->sc_scsi_dev = my_id & SBIC_ID_MASK; - my_id &= 0xc7; - my_id |= SBIC_ID_EAF; - /* - * reset board, If it doesn't respond, assume - * that it's not there.. good for the probe - */ - SET_SBIC_myid(sbic->sc_base, my_id); - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_RESET); - DELAY(10); - SBIC_WAIT(sbic, SBIC_ASR_INT, 0); - GET_SBIC_csr(sbic->sc_base, csr); - if (csr != SBIC_CSR_RESET_AM) - return(ENXIO); - - sbic->sc_dma = inb(sbic->sc_base + 4) & 0x03; - outb(sbic->sc_base, SBIC_reset_int); - intr = (inb(sbic->sc_base + 2) >> 3) & 0x07; - switch(intr) { - case INT0: - sbic->sc_int = IRQ3; - break; - case INT1: - sbic->sc_int = IRQ5; - break; - case INT2: - sbic->sc_int = IRQ6; - break; - case INT3: - sbic->sc_int = IRQ9; - break; - case INT5: - sbic->sc_int = IRQ12; - break; - case INT6: - sbic->sc_int = IRQ13; - break; - default: - printf("illegal int jumper setting\n"); - return(EIO); - } - SET_SBIC_control(sbic->sc_base, SBIC_CTL_EDI | SBIC_CTL_IDI - | SBIC_MACHINE_DMA_MODE); - SET_SBIC_rselid(sbic->sc_base, 0); - SET_SBIC_syn(sbic->sc_base, 0); /* asynch for now */ - - sbic->sc_flags = SBICF_ALIVE; - return 0; -} - -/* - * default minphys routine for sbic based controllers - */ -static void -sbicminphys(bp) - struct buf *bp; -{ - if (bp->b_bcount > ((SBIC_NSEG - 1) << PAGE_SHIFT)) - bp->b_bcount = ((SBIC_NSEG - 1) << PAGE_SHIFT); -} - -/* - * must be used - */ -static u_int32_t -sbic_adapter_info(unit) - int unit; -{ - /* - * one request at a time please - */ - return(1); -} - -/* - * used by specific sbic controller - * - * it appears that the higher level code does nothing with LUN's - * so I will too. I could plug it in, however so could they - * in scsi_scsi_cmd(). - */ -static int32_t -sbic_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct sbic_pending *pendp; - struct sbic_softc *sbic; - struct scsi_link *sc_link; - int flags, s; - int unit; - - sc_link = xs->sc_link; - unit = sc_link->adapter_unit; - sbic = sc_link->adapter_softc; - flags = xs->flags; - - if (flags & SCSI_DATA_UIO) - panic("sbic: scsi data uio requested"); - - if (sbic->sc_xs && flags & SCSI_NOMASK) - panic("sbic_scsi_cmd: busy"); - - s = splbio(); - pendp = &sbic->sc_xsstore[sc_link->target][sc_link->lun]; - if (pendp->xs) { - splx(s); - return(TRY_AGAIN_LATER); - } - - if (sbic->sc_xs) { - pendp->xs = xs; - TAILQ_INSERT_TAIL(&sbic->sc_xslist, pendp, link); - splx(s); - return(SUCCESSFULLY_QUEUED); - } - pendp->xs = NULL; - sbic->sc_xs = xs; - splx(s); - - /* - * nothing is pending do it now. - */ - sbic_donextcmd(sbic); - - if (flags & SCSI_NOMASK) - return(COMPLETE); - return(SUCCESSFULLY_QUEUED); -} - -/* - * entered with sbic->sc_xs pointing to the next xfer to perform - */ -static void -sbic_donextcmd(sbic) - struct sbic_softc *sbic; -{ - struct scsi_xfer *xs; - struct scsi_link *sc_link; - int flags, phase, stat; - - xs = sbic->sc_xs; - sc_link = xs->sc_link; - flags = xs->flags; - - if (flags & SCSI_DATA_IN) - phase = DATA_IN_PHASE; - else if (flags & SCSI_DATA_OUT) - phase = DATA_OUT_PHASE; - else - phase = STATUS_PHASE; - - if (flags & SCSI_RESET) - sbicreset(sbic); - - sbic->sc_stat[0] = -1; - xs->cmd->bytes[0] |= sc_link->lun << 5; - if (phase == STATUS_PHASE || flags & SCSI_NOMASK || - sbicdmaok(sbic, xs) == 0) - stat = sbicicmd(sbic, sc_link->target, sc_link->lun, xs->cmd, - xs->cmdlen, xs->data, xs->datalen, phase); - else if (sbicgo(sbic, xs) == 0) - return; - else - stat = sbic->sc_stat[0]; - - sbic_scsidone(sbic, stat); -} - -static void -sbic_scsidone(sbic, stat) - struct sbic_softc *sbic; - int stat; -{ - struct sbic_pending *pendp; - struct scsi_xfer *xs; - int s, donext; - - xs = sbic->sc_xs; -#ifdef DIAGNOSTIC - if (xs == NULL) - panic("sbic_scsidone"); -#endif - /* - * is this right? - */ - xs->status = stat; - - if (stat == 0) - xs->resid = 0; - else { - switch(stat) { - case SCSI_CHECK: - if (stat = sbicgetsense(sbic, xs)) - goto bad_sense; - xs->error = XS_SENSE; - break; - case SCSI_BUSY: - xs->error = XS_BUSY; - break; - bad_sense: - default: - xs->error = XS_DRIVER_STUFFUP; - QPRINTF(("sbic_scsicmd() bad %x\n", stat)); - break; - } - } - xs->flags |= ITSDONE; - - /* - * grab next command before scsi_done() - * this way no single device can hog scsi resources. - */ - s = splbio(); - pendp = sbic->sc_xslist.tqh_first; - if (pendp == NULL) { - donext = 0; - sbic->sc_xs = NULL; - } else { - donext = 1; - TAILQ_REMOVE(&sbic->sc_xslist, pendp, link); - sbic->sc_xs = pendp->xs; - pendp->xs = NULL; - } - splx(s); - scsi_done(xs); - - if (donext) - sbic_donextcmd(sbic); -} - -static int -sbicgetsense(sbic, xs) - struct sbic_softc *sbic; - struct scsi_xfer *xs; -{ - struct scsi_sense rqs; - struct scsi_link *sc_link; - int stat; - - sc_link = xs->sc_link; - - rqs.op_code = REQUEST_SENSE; - rqs.byte2 = sc_link->lun << 5; -#ifdef not_yet - rqs.length = xs->req_sense_length ? xs->req_sense_length : - sizeof(xs->sense); -#else - rqs.length = sizeof(xs->sense); -#endif - - rqs.unused[0] = rqs.unused[1] = rqs.control = 0; - - return(sbicicmd(sbic, sc_link->target, sc_link->lun, &rqs, - sizeof(rqs), &xs->sense, rqs.length, DATA_IN_PHASE)); -} - -static int -sbicdmaok(sbic, xs) - struct sbic_softc *sbic; - struct scsi_xfer *xs; -{ - int va, phys, priorpage = 0, endva, length; - - va = (int)xs->data; - length = xs->datalen; - endva = round_page(va + length); - - for (; va < endva; va += PAGE_SIZE) { - phys = trunc_page(pmap_extract(kernel_pmap, va)); - if (phys == 0) - panic("sbicdmaok: no physical page present"); - if (phys >= (1 << 24)) - return 0; - priorpage = phys; - } - return 1; -} - -static int -sbicwait(sbic, until, timeo, line) - struct sbic_softc *sbic; - char until; - int timeo; - int line; -{ - u_char val; - int csr; - - if (timeo == 0) - timeo = 1000000; /* some large value.. */ - - GET_SBIC_asr(sbic->sc_base,val); - while ((val & until) == 0) { - if (timeo-- == 0) { - GET_SBIC_csr(sbic->sc_base, csr); - printf("sbicwait TIMEO @%d with asr=x%x csr=x%x\n", - line, val, csr); - break; - } - DELAY(1); - GET_SBIC_asr(sbic->sc_base,val); - } - return(val); -} - -static void -sbicabort(sbic, where) - struct sbic_softc *sbic; - char *where; -{ - u_char csr, asr; - - GET_SBIC_csr(sbic->sc_base, csr); - GET_SBIC_asr(sbic->sc_base, asr); - - printf ("sbic%d: abort %s: csr = 0x%02x, asr = 0x%02x\n", - sbic->sc_link.adapter_unit, where, csr, asr); - - if (sbic->sc_flags & SBICF_SELECTED) { - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_ABORT); - WAIT_CIP(sbic->sc_base); - - GET_SBIC_asr(sbic->sc_base, asr); - if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) { - /* ok, get more drastic.. */ - - SET_SBIC_cmd (sbic->sc_base, SBIC_CMD_RESET); - DELAY(25); - SBIC_WAIT(sbic, SBIC_ASR_INT, 0); - /* clears interrupt also */ - GET_SBIC_csr (sbic->sc_base, csr); - - sbic->sc_flags &= ~SBICF_SELECTED; - return; - } - - do { - SBIC_WAIT (sbic, SBIC_ASR_INT, 0); - GET_SBIC_csr (sbic->sc_base, csr); - } while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1) - && (csr != SBIC_CSR_CMD_INVALID)); - - /* lets just hope it worked.. */ - sbic->sc_flags &= ~SBICF_SELECTED; - } -} - -/* - * XXX Set/reset long delays. - * - * if delay == 0, reset default delays - * if delay < 0, set both delays to default long initialization values - * if delay > 0, set both delays to this value - * - * Used when a devices is expected to respond slowly (e.g. during - * initialization). - */ -static void -sbicsetdelay(del) - int del; -{ - static int saved_cmd_wait, saved_data_wait; - - if (del) { - saved_cmd_wait = sbic_cmd_wait; - saved_data_wait = sbic_data_wait; - if (del > 0) - sbic_cmd_wait = sbic_data_wait = del; - else - sbic_cmd_wait = sbic_data_wait = sbic_init_wait; - } else { - sbic_cmd_wait = saved_cmd_wait; - sbic_data_wait = saved_data_wait; - } -} - -void -sbicreset(sbic) - struct sbic_softc *sbic; -{ - u_int i, s; - u_char my_id, csr; - - if (sbic->sc_flags & SBICF_ALIVE) - sbicabort(sbic, "reset"); - - s = splbio(); - /* preserve our ID for now */ - GET_SBIC_myid (sbic->sc_base, my_id); - my_id &= SBIC_ID_MASK; - - if (sbic->sc_clkfreq < 110) - my_id |= SBIC_ID_FS_8_10; - else if (sbic->sc_clkfreq < 160) - my_id |= SBIC_ID_FS_12_15; - else if (sbic->sc_clkfreq < 210) - my_id |= SBIC_ID_FS_16_20; - - my_id |= SBIC_ID_EAF /*| SBIC_ID_EHP*/ ; - - SET_SBIC_myid(sbic->sc_base, my_id); - - /* - * Disable interrupts (in dmainit) then reset the chip - */ - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_RESET); - DELAY(25); - SBIC_WAIT(sbic, SBIC_ASR_INT, 0); - GET_SBIC_csr(sbic->sc_base, csr); /* clears interrupt also */ - - /* - * Set up various chip parameters - */ - SET_SBIC_control(sbic->sc_base, SBIC_CTL_EDI | SBIC_CTL_IDI - | SBIC_MACHINE_DMA_MODE); - /* - * don't allow (re)selection (SBIC_RID_ES) - * until we can handle target mode!! - */ - SET_SBIC_rselid(sbic->sc_base, 0); - SET_SBIC_syn(sbic->sc_base, 0); /* asynch for now */ - - /* - * anything else was zeroed by reset - */ - splx(s); - - sbic->sc_flags |= SBICF_ALIVE; - sbic->sc_flags &= ~SBICF_SELECTED; -} - -static void -sbicerror(sbic, csr) - struct sbic_softc *sbic; - u_char csr; -{ - struct scsi_xfer *xs; - - xs = sbic->sc_xs; - -#ifdef DIAGNOSTIC - if (xs == NULL) - panic("sbicerror"); -#endif - if (xs->flags & SCSI_SILENT) - return; - - printf("sbic%d: ", sbic->sc_link.adapter_unit); - printf("csr == 0x%02x\n", csr); /* XXX */ -} - -/* - * select the bus, return when selected or error. - */ -static int -sbicselectbus(sbic, target, lun, our_addr) - struct sbic_softc *sbic; - u_char target, lun, our_addr; -{ - u_char asr, csr, id; - - QPRINTF(("sbicselectbus %d\n", target)); - - /* - * if we're already selected, return (XXXX panic maybe?) - */ - if (sbic->sc_flags & SBICF_SELECTED) - return(1); - - /* - * issue select - */ - SBIC_TC_PUT(sbic->sc_base, 0); - SET_SBIC_selid(sbic->sc_base, target); - SET_SBIC_timeo(sbic->sc_base, SBIC_TIMEOUT(250,sbic->sc_clkfreq)); - - /* - * set sync or async - */ - if (sbic->sc_sync[target].state == SYNC_DONE) - SET_SBIC_syn(sbic->sc_base, SBIC_SYN (sbic->sc_sync[target].offset, - sbic->sc_sync[target].period)); - else - SET_SBIC_syn(sbic->sc_base, SBIC_SYN (0, sbic_min_period)); - - SET_SBIC_cmd(sbic->sc_base, sbic_inhibit_sync ? SBIC_CMD_SEL : SBIC_CMD_SEL_ATN); - - /* - * wait for select (merged from seperate function may need - * cleanup) - */ - WAIT_CIP(sbic->sc_base); - do { - SBIC_WAIT(sbic, SBIC_ASR_INT, 0); - GET_SBIC_csr (sbic->sc_base, csr); - QPRINTF(("%02x ", csr)); - } while (csr != (SBIC_CSR_MIS_2|MESG_OUT_PHASE) - && csr != (SBIC_CSR_MIS_2|CMD_PHASE) && csr != SBIC_CSR_SEL_TIMEO); - - if (csr == (SBIC_CSR_MIS_2|CMD_PHASE)) - sbic->sc_flags |= SBICF_SELECTED; /* device ignored ATN */ - else if (csr == (SBIC_CSR_MIS_2|MESG_OUT_PHASE)) { - /* - * Send identify message - * (SCSI-2 requires an identify msg (?)) - */ - GET_SBIC_selid(sbic->sc_base, id); - - /* - * handle drives that don't want to be asked - * whether to go sync at all. - */ - if ((sbic_force_async_flag & (1 << id)) || (sbic_inhibit_sync && sbic->sc_sync[id].state == SYNC_START)) { -#ifdef DEBUG - if (sync_debug) - printf("Forcing target %d asynchronous.\n", id); -#endif - sbic->sc_sync[id].offset = 0; - sbic->sc_sync[id].period = sbic_min_period; - sbic->sc_sync[id].state = SYNC_DONE; - } - - - if (sbic->sc_sync[id].state != SYNC_START) - SEND_BYTE (sbic, MSG_IDENTIFY | lun); - else { - /* - * try to initiate a sync transfer. - * So compose the sync message we're going - * to send to the target - */ - -#ifdef DEBUG - if (sync_debug) - printf("Sending sync request to target %d ... ", - id); -#endif - /* - * setup scsi message sync message request - */ - sbic->sc_msg[0] = MSG_IDENTIFY | lun; - sbic->sc_msg[1] = MSG_EXT_MESSAGE; - sbic->sc_msg[2] = 3; - sbic->sc_msg[3] = MSG_SYNC_REQ; - sbic->sc_msg[4] = sbictoscsiperiod(sbic, - sbic_min_period); - sbic->sc_msg[5] = sbic_max_offset; - - if (sbicxfstart(sbic, 6, MESG_OUT_PHASE, sbic_cmd_wait)) - sbicxfout(sbic, 6, sbic->sc_msg, MESG_OUT_PHASE); - - sbic->sc_sync[id].state = SYNC_SENT; -#ifdef DEBUG - if (sync_debug) - printf ("sent\n"); -#endif - } - - SBIC_WAIT (sbic, SBIC_ASR_INT, 0); - GET_SBIC_csr (sbic->sc_base, csr); - QPRINTF(("[%02x]", csr)); -#ifdef DEBUG - if (sync_debug && sbic->sc_sync[id].state == SYNC_SENT) - printf("csr-result of last msgout: 0x%x\n", csr); -#endif - - if (csr != SBIC_CSR_SEL_TIMEO) - sbic->sc_flags |= SBICF_SELECTED; - } - - QPRINTF(("\n")); - - return(csr == SBIC_CSR_SEL_TIMEO); -} - -static int -sbicxfstart(sbic, len, phase, wait) - struct sbic_softc *sbic; - int len, wait; - u_char phase; -{ - u_char id; - - if (phase == DATA_IN_PHASE || phase == MESG_IN_PHASE) { - GET_SBIC_selid (sbic->sc_base, id); - id |= SBIC_SID_FROM_SCSI; - SET_SBIC_selid (sbic->sc_base, id); - SBIC_TC_PUT (sbic->sc_base, (unsigned)len); - } else if (phase == DATA_OUT_PHASE || phase == MESG_OUT_PHASE - || phase == CMD_PHASE) - SBIC_TC_PUT (sbic->sc_base, (unsigned)len); - else - SBIC_TC_PUT (sbic->sc_base, 0); - QPRINTF(("sbicxfstart %d, %d, %d\n", len, phase, wait)); - - return(1); -} - -static int -sbicxfout(sbic, len, bp, phase) - struct sbic_softc *sbic; - int len; - void *bp; - int phase; -{ - u_char orig_csr, csr, asr, *buf; - int wait; - - buf = bp; - wait = sbic_data_wait; - - QPRINTF(("sbicxfout {%d} %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x\n", len, buf[0], buf[1], buf[2], - buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9])); - - GET_SBIC_csr (sbic->sc_base, orig_csr); - - /* - * sigh.. WD-PROTO strikes again.. sending the command in one go - * causes the chip to lock up if talking to certain (misbehaving?) - * targets. Anyway, this procedure should work for all targets, but - * it's slightly slower due to the overhead - */ - WAIT_CIP (sbic->sc_base); - SET_SBIC_cmd (sbic->sc_base, SBIC_CMD_XFER_INFO); - for (;len > 0; len--) { - GET_SBIC_asr (sbic->sc_base, asr); - while ((asr & SBIC_ASR_DBR) == 0) { - if ((asr & SBIC_ASR_INT) || --wait < 0) { -#ifdef DEBUG - if (sbic_debug) - printf("sbicxfout fail: l%d i%x w%d\n", - len, asr, wait); -#endif - return (len); - } - DELAY(1); - GET_SBIC_asr (sbic->sc_base, asr); - } - - SET_SBIC_data (sbic->sc_base, *buf); - buf++; - } - - QPRINTF(("sbicxfout done\n")); - /* - * this leaves with one csr to be read - */ - return(0); -} - -static void -sbicxfin(sbic, len, bp) - struct sbic_softc *sbic; - int len; - void *bp; -{ - int wait; - u_char *obp, *buf; - u_char orig_csr, csr, asr; - - wait = sbic_data_wait; - obp = bp; - buf = bp; - - GET_SBIC_csr (sbic->sc_base, orig_csr); - - QPRINTF(("sbicxfin %d, csr=%02x\n", len, orig_csr)); - - WAIT_CIP (sbic->sc_base); - SET_SBIC_cmd (sbic->sc_base, SBIC_CMD_XFER_INFO); - for (;len > 0; len--) { - GET_SBIC_asr (sbic->sc_base, asr); - while ((asr & SBIC_ASR_DBR) == 0) { - if ((asr & SBIC_ASR_INT) || --wait < 0) { -#ifdef DEBUG - if (sbic_debug) - printf("sbicxfin fail: l%d i%x w%d\n", - len, asr, wait); -#endif - return; - } - - DELAY(1); - GET_SBIC_asr (sbic->sc_base, asr); - } - - GET_SBIC_data (sbic->sc_base, *buf); - buf++; - } - - QPRINTF(("sbicxfin {%d} %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x\n", len, obp[0], obp[1], obp[2], - obp[3], obp[4], obp[5], obp[6], obp[7], obp[8], obp[9])); - - /* this leaves with one csr to be read */ -} - - -/* - * SCSI 'immediate' command: issue a command to some SCSI device - * and get back an 'immediate' response (i.e., do programmed xfer - * to get the response data). 'cbuf' is a buffer containing a scsi - * command of length clen bytes. 'buf' is a buffer of length 'len' - * bytes for data. The transfer direction is determined by the device - * (i.e., by the scsi bus data xfer phase). If 'len' is zero, the - * command must supply no data. 'xferphase' is the bus phase the - * caller expects to happen after the command is issued. It should - * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE. - */ -static int -sbicicmd(sbic, target, lun, cbuf, clen, buf, len, xferphase) - struct sbic_softc *sbic; - int target, lun; - void *cbuf, *buf; - int clen, len; - u_char xferphase; -{ - u_char phase, csr, asr; - int wait; - - /* - * set the sbic into non-DMA mode - */ - SET_SBIC_control(sbic->sc_base, SBIC_CTL_EDI | SBIC_CTL_IDI); - -retry_selection: - /* - * select the SCSI bus (it's an error if bus isn't free) - */ - if (sbicselectbus(sbic, target, lun, sbic->sc_scsi_dev)) - return(-1); - /* - * Wait for a phase change (or error) then let the device sequence - * us through the various SCSI phases. - */ - sbic->sc_stat[0] = 0xff; - sbic->sc_msg[0] = 0xff; - phase = CMD_PHASE; - -new_phase: - wait = sbic_cmd_wait; - - GET_SBIC_csr (sbic->sc_base, csr); - QPRINTF((">CSR:%02x<", csr)); - - /* - * requesting some new phase - */ - if ((csr != 0xff) && (csr & 0xf0) && (csr & 0x08)) - phase = csr & PHASE; - else if ((csr == SBIC_CSR_DISC) || (csr == SBIC_CSR_DISC_1) - || (csr == SBIC_CSR_S_XFERRED)) { - sbic->sc_flags &= ~SBICF_SELECTED; - GET_SBIC_cmd_phase (sbic->sc_base, phase); - if (phase == 0x60) - GET_SBIC_tlun (sbic->sc_base, sbic->sc_stat[0]); - else - return(-1); - goto out; - } else { - sbicerror(sbic, csr); - goto abort; - } - - switch (phase) { - case CMD_PHASE: - if (sbicxfstart (sbic, clen, phase, wait)) - if (sbicxfout (sbic, clen, cbuf, phase)) - goto abort; - phase = xferphase; - break; - case DATA_IN_PHASE: - if (len <= 0) - goto abort; - wait = sbic_data_wait; - if (sbicxfstart(sbic, len, phase, wait)) - sbicxfin(sbic, len, buf); - phase = STATUS_PHASE; - break; - case MESG_IN_PHASE: - if (sbicxfstart(sbic, sizeof(sbic->sc_msg), phase, wait) == 0) - break; - sbic->sc_msg[0] = 0xff; - sbicxfin(sbic, sizeof(sbic->sc_msg), sbic->sc_msg); - /* - * get the command completion interrupt, or we - * can't send a new command (LCI) - */ - SBIC_WAIT(sbic, SBIC_ASR_INT, wait); - GET_SBIC_csr(sbic->sc_base, csr); -#ifdef DEBUG - if (sync_debug) - printf("msgin done csr 0x%x\n", csr); -#endif - /* - * test whether this is a reply to our sync - * request - */ - if (sbic->sc_msg[0] == MSG_EXT_MESSAGE && sbic->sc_msg[1] == 3 - && sbic->sc_msg[2] == MSG_SYNC_REQ) { - - sbic->sc_sync[target].period = sbicfromscsiperiod(sbic, - sbic->sc_msg[3]); - sbic->sc_sync[target].offset = sbic->sc_msg[4]; - sbic->sc_sync[target].state = SYNC_DONE; - SET_SBIC_syn(sbic->sc_base, SBIC_SYN(sbic->sc_sync[target].offset, - sbic->sc_sync[target].period)); - /* ACK the message */ - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_CLR_ACK); - WAIT_CIP(sbic->sc_base); - phase = CMD_PHASE; /* or whatever */ - printf("sbic%d: target %d now synchronous," - " period=%dns, offset=%d.\n", - sbic->sc_link.adapter_unit, target, sbic->sc_msg[3] * 4, - sbic->sc_msg[4]); - } else if (sbic->sc_msg[0] == MSG_REJECT - && sbic->sc_sync[target].state == SYNC_SENT) { -#ifdef DEBUG - if (sync_debug) - printf("target %d rejected sync, going async\n", - target); -#endif - sbic->sc_sync[target].period = sbic_min_period; - sbic->sc_sync[target].offset = 0; - sbic->sc_sync[target].state = SYNC_DONE; - SET_SBIC_syn(sbic->sc_base, SBIC_SYN(sbic->sc_sync[target].offset, - sbic->sc_sync[target].period)); - /* ACK the message */ - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_CLR_ACK); - WAIT_CIP(sbic->sc_base); - phase = CMD_PHASE; /* or whatever */ - } else if (sbic->sc_msg[0] == MSG_REJECT) { - /* - * we'll never REJECt a REJECT message.. - */ - /* ACK the message */ - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_CLR_ACK); - WAIT_CIP(sbic->sc_base); - phase = CMD_PHASE; /* or whatever */ - } else if (sbic->sc_msg[0] == MSG_CMD_COMPLETE - || sbic->sc_msg[0] == 0xff) { - /* !! KLUDGE ALERT !! quite a few drives don't seem to - * really like the current way of sending the - * sync-handshake together with the ident-message, and - * they react by sending command-complete and - * disconnecting right after returning the valid sync - * handshake. So, all I can do is reselect the drive, - * and hope it won't disconnect again. I don't think - * this is valid behavior, but I can't help fixing a - * problem that apparently exists. - * - * Note: we should not get here on `normal' command - * completion, as that condition is handled by the - * high-level sel&xfer resume command used to walk - * thru status/cc-phase. - */ - -#ifdef DEBUG - if (sync_debug) - printf ("GOT CMD-COMPLETE! %d acting weird.." - " waiting for disconnect...\n", target); -#endif - /* ACK the message */ - SET_SBIC_cmd (sbic->sc_base, SBIC_CMD_CLR_ACK); - WAIT_CIP(sbic->sc_base); - - /* wait for disconnect */ - while (csr != SBIC_CSR_DISC && - csr != SBIC_CSR_DISC_1) { - DELAY(1); - GET_SBIC_csr(sbic->sc_base, csr); - } -#ifdef DEBUG - if (sync_debug) - printf ("ok.\nRetrying selection.\n"); -#endif - sbic->sc_flags &= ~SBICF_SELECTED; - goto retry_selection; - } else { -#ifdef DEBUG - if (sbic_debug || sync_debug) - printf ("Rejecting message 0x%02x\n", - sbic->sc_msg[0]); -#endif - /* prepare to reject the message, NACK */ - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_SET_ATN); - WAIT_CIP(sbic->sc_base); - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_CLR_ACK); - WAIT_CIP(sbic->sc_base); - phase = MESG_OUT_PHASE; - } - break; - - case MESG_OUT_PHASE: -#ifdef DEBUG - if (sync_debug) - printf ("sending REJECT msg to last msg.\n"); -#endif - /* - * should only get here on reject, - * since it's always US that - * initiate a sync transfer - */ - SEND_BYTE(sbic, MSG_REJECT); - phase = STATUS_PHASE; - break; - case DATA_OUT_PHASE: - if (len <= 0) - goto abort; - wait = sbic_data_wait; - if (sbicxfstart(sbic, len, phase, wait)) - if (sbicxfout (sbic, len, buf, phase)) - goto abort; - phase = STATUS_PHASE; - break; - case STATUS_PHASE: - /* - * the sbic does the status/cmd-complete reading ok, - * so do this with its hi-level commands. - */ - SBIC_TC_PUT(sbic->sc_base, 0); - SET_SBIC_cmd_phase(sbic->sc_base, 0x46); - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_SEL_ATN_XFER); - phase = BUS_FREE_PHASE; - break; - case BUS_FREE_PHASE: - goto out; - default: - printf("sbic%d: unexpected phase %d in icmd from %d\n", - sbic->sc_link.adapter_unit, phase, target); - goto abort; - } - - /* - * make sure the last command was taken, - * ie. we're not hunting after an ignored command.. - */ - GET_SBIC_asr(sbic->sc_base, asr); - if (asr & SBIC_ASR_LCI) - goto abort; - - /* tapes may take a loooong time.. */ - while (asr & SBIC_ASR_BSY) { - DELAY(1); - GET_SBIC_asr(sbic->sc_base, asr); - } - - /* - * wait for last command to complete - */ - SBIC_WAIT (sbic, SBIC_ASR_INT, wait); - - /* - * do it again - */ - goto new_phase; -abort: - sbicabort(sbic, "icmd"); -out: - QPRINTF(("=STS:%02x=", sbic->sc_stat[0])); - return(sbic->sc_stat[0]); -} - -/* - * Finish SCSI xfer command: After the completion interrupt from - * a read/write operation, sequence through the final phases in - * programmed i/o. This routine is a lot like sbicicmd except we - * skip (and don't allow) the select, cmd out and data in/out phases. - */ -static void -sbicxfdone(sbic, target) - struct sbic_softc *sbic; - int target; -{ - u_char phase, csr; - int s; - - QPRINTF(("{")); - s = splbio(); - - /* - * have the sbic complete on its own - */ - SBIC_TC_PUT(sbic->sc_base, 0); - SET_SBIC_cmd_phase(sbic->sc_base, 0x46); - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_SEL_ATN_XFER); - - do { - SBIC_WAIT (sbic, SBIC_ASR_INT, 0); - GET_SBIC_csr (sbic->sc_base, csr); - QPRINTF(("%02x:", csr)); - } while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1) - && (csr != SBIC_CSR_S_XFERRED)); - - sbic->sc_flags &= ~SBICF_SELECTED; - - GET_SBIC_cmd_phase (sbic->sc_base, phase); - QPRINTF(("}%02x", phase)); - if (phase == 0x60) - GET_SBIC_tlun(sbic->sc_base, sbic->sc_stat[0]); - else - sbicerror(sbic, csr); - - QPRINTF(("=STS:%02x=\n", sbic->sc_stat[0])); - splx(s); -} - -static int -sbicgo(sbic, xs) - struct sbic_softc *sbic; - struct scsi_xfer *xs; -{ - int i, target, len, wait; - int seg, thiskv, thisphys, nextphys, datalen; - int bytes_this_seg, bytes_this_page; - u_char phase, csr, asr, cmd; - struct dma_chain *sg; - - target = xs->sc_link->target; - datalen = xs->datalen; - thiskv = (int)xs->data; - - /* - * set the sbic into DMA mode - */ - SET_SBIC_control(sbic->sc_base, SBIC_CTL_EDI | SBIC_CTL_IDI | - SBIC_MACHINE_DMA_MODE); - - /* - * select the SCSI bus (it's an error if bus isn't free) - */ - if (sbicselectbus(sbic, target, xs->sc_link->lun, - sbic->sc_scsi_dev)) { - sbic_dmastop(sbic); - SBIC_DISABLE_INT(sbic->sc_base); - return(-1); - } - - /* - * Wait for a phase change (or error) then let the device - * sequence us through command phase (we may have to take - * a msg in/out before doing the command). If the disk has - * to do a seek, it may be a long time until we get a change - * to data phase so, in the absense of an explicit phase - * change, we assume data phase will be coming up and tell - * the SPC to start a transfer whenever it does. We'll get - * a service required interrupt later if this assumption is - * wrong. Otherwise we'll get a service required int when - * the transfer changes to status phase. - */ - phase = CMD_PHASE; - -new_phase: - wait = sbic_cmd_wait; - switch (phase) { - case CMD_PHASE: - if (sbicxfstart(sbic, xs->cmdlen, phase, wait)) - if (sbicxfout(sbic, xs->cmdlen, xs->cmd, phase)) - goto abort; - break; - case MESG_IN_PHASE: - if (sbicxfstart(sbic, sizeof(sbic->sc_msg), phase, wait) == 0) - break; - - sbicxfin(sbic, sizeof(sbic->sc_msg), sbic->sc_msg); - /* - * prepare to reject any mesgin, - * no matter what it might be.. - */ - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_SET_ATN); - WAIT_CIP(sbic->sc_base); - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_CLR_ACK); - phase = MESG_OUT_PHASE; - break; - case MESG_OUT_PHASE: - SEND_BYTE(sbic, MSG_REJECT); - phase = STATUS_PHASE; - break; - case DATA_IN_PHASE: - case DATA_OUT_PHASE: - goto out; - /* - * status phase can happen, if the issued read/write command - * is illegal (for example, reading after EOT on tape) and the - * device doesn't even go to data in/out phase. So handle this - * here normally, instead of going thru abort-handling. - */ - case STATUS_PHASE: - sbic_dmastop(sbic); - SBIC_DISABLE_INT(sbic->sc_base); - sbicxfdone(sbic, target); - sbic->sc_flags &= ~(SBICF_INDMA | SBICF_BBUF); - sbic_scsidone(sbic, sbic->sc_stat[0]); - return(0); - default: - printf("sbic%d: unexpected phase %d in go from %d\n", phase, - sbic->sc_link.adapter_unit, target); - goto abort; - } - - /* - * make sure the last command was taken, - * ie. we're not hunting after an ignored command.. - */ - GET_SBIC_asr(sbic->sc_base, asr); - if (asr & SBIC_ASR_LCI) - goto abort; - - /* - * tapes may take a loooong time.. - */ - while (asr & SBIC_ASR_BSY) { - DELAY(1); - GET_SBIC_asr(sbic->sc_base, asr); - } - - if (wait <= 0) - goto abort; - - /* - * wait for last command to complete - */ - SBIC_WAIT(sbic, SBIC_ASR_INT, wait); - - GET_SBIC_csr(sbic->sc_base, csr); - QPRINTF((">CSR:%02x<", csr)); - - /* - * requesting some new phase - */ - if ((csr != 0xff) && (csr & 0xf0) && (csr & 0x08)) - phase = csr & PHASE; - else { - sbicerror(sbic, csr); - goto abort; - } - /* - * start again with for new phase - */ - goto new_phase; -out: - /* - * Build the DMA chain - */ - thisphys = KVTOPHYS(thiskv); - seg = 0; - sg = sbic->sc_chain; - while((datalen) && (seg < SBIC_NSEG)) { - bytes_this_seg = 0; - sg->dc_addr = thisphys; - nextphys = thisphys; - while((datalen) && (thisphys == nextphys)) { - nextphys = (thisphys & ~PAGE_MASK) + PAGE_SIZE; - bytes_this_page = nextphys - thisphys; - bytes_this_page = min(bytes_this_page, datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - thiskv = (thiskv & ~PAGE_MASK) + PAGE_SIZE; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - sg->dc_count = bytes_this_seg; - sg++; - seg++; - } - sbic->sc_cur = sbic->sc_chain; - sbic->sc_last = --sg; - -#ifdef DEBUG - if (sbic_dma_debug) { - for (sg = sbic->sc_chain; sg <= sbic->sc_last; sg++) - printf("\n %d: %d@%x", sg-sbic->sc_chain, - sg->dc_count, sg->dc_addr); - printf("Total: %d ", xs->datalen); - } -#endif - - sbic_dmastart(sbic); - SBIC_ENABLE_INT(sbic->sc_base); - SBIC_TC_PUT(sbic->sc_base, (unsigned)sbic->sc_cur->dc_count); - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_XFER_INFO); - - return(0); - -abort: - sbicabort(sbic, "go"); - sbic_dmastop(sbic); - SBIC_DISABLE_INT(sbic->sc_base); - return(-1); -} - - -void -sbicintr(unit) - int unit; -{ - struct sbic_softc *sbic = sbicdata[unit]; - u_char asr, csr; - int i; - - /* - * pending interrupt? - */ - GET_SBIC_asr (sbic->sc_base, asr); - if ((asr & SBIC_ASR_INT) == 0) - return; - GET_SBIC_csr(sbic->sc_base, csr); - QPRINTF(("[0x%x]", csr)); - - if (csr == (SBIC_CSR_XFERRED|STATUS_PHASE) - || csr == (SBIC_CSR_MIS|STATUS_PHASE) - || csr == (SBIC_CSR_MIS_1|STATUS_PHASE) - || csr == (SBIC_CSR_MIS_2|STATUS_PHASE)) { - /* - * this should be the normal i/o completion case. - * get the status & cmd complete msg then let the - * device driver look at what happened. - */ - sbic_dmastop(sbic); - SBIC_DISABLE_INT(sbic->sc_base); - sbicxfdone(sbic, sbic->sc_xs->sc_link->target); - /* - * check for overlapping cache line, flush if so - */ - sbic->sc_flags &= ~(SBICF_INDMA | SBICF_BBUF | SBICF_DCFLUSH); - sbic_scsidone(sbic, sbic->sc_stat[0]); - } else if (csr == (SBIC_CSR_XFERRED|DATA_OUT_PHASE) - || csr == (SBIC_CSR_XFERRED|DATA_IN_PHASE) - || csr == (SBIC_CSR_MIS|DATA_OUT_PHASE) - || csr == (SBIC_CSR_MIS|DATA_IN_PHASE) - || csr == (SBIC_CSR_MIS_1|DATA_OUT_PHASE) - || csr == (SBIC_CSR_MIS_1|DATA_IN_PHASE) - || csr == (SBIC_CSR_MIS_2|DATA_OUT_PHASE) - || csr == (SBIC_CSR_MIS_2|DATA_IN_PHASE)) { - /* - * do scatter-gather dma - * hacking the controller chip, ouch.. - */ - /* - * set next dma addr and dec count - */ - sbic_dmastop(sbic); - ++sbic->sc_cur; /* advance to next segment */ - sbic_dmastart(sbic); - SBIC_TC_PUT(sbic->sc_base, (unsigned)sbic->sc_cur->dc_count); - SET_SBIC_cmd(sbic->sc_base, SBIC_CMD_XFER_INFO); - } else { - /* - * Something unexpected happened -- deal with it. - */ - sbic_dmastop(sbic); - sbicerror(sbic, csr); - sbicabort(sbic, "intr"); - if (sbic->sc_flags & SBICF_INDMA) { - /* - * check for overlapping cache line, flush if so - */ - sbic->sc_flags &= - ~(SBICF_INDMA | SBICF_BBUF | SBICF_DCFLUSH); - SBIC_DISABLE_INT(sbic->sc_base); - sbic_scsidone(sbic, -1); - } - } - return; -} - -static int -sbictoscsiperiod(sbic, a) - struct sbic_softc *sbic; - int a; -{ - unsigned int fs; - - /* - * cycle = DIV / (2*CLK) - * DIV = FS+2 - * best we can do is 200ns at 20Mhz, 2 cycles - */ - - GET_SBIC_myid(sbic->sc_base,fs); - fs = (fs >>6) + 2; /* DIV */ - fs = (fs * 10000) / (sbic->sc_clkfreq<<1); /* Cycle, in ns */ - if (a < 2) a = 8; /* map to Cycles */ - return ((fs*a)>>2); /* in 4 ns units */ -} - -static int -sbicfromscsiperiod(sbic, p) - struct sbic_softc *sbic; - int p; -{ - register unsigned int fs, ret; - - /* Just the inverse of the above */ - - GET_SBIC_myid(sbic->sc_base,fs); - fs = (fs >>6) + 2; /* DIV */ - fs = (fs * 10000) / (sbic->sc_clkfreq<<1); /* Cycle, in ns */ - - ret = p << 2; /* in ns units */ - ret = ret / fs; /* in Cycles */ - if (ret < sbic_min_period) - return(sbic_min_period); - - /* verify rounding */ - if (sbictoscsiperiod(sbic, ret) < p) - ret++; - return (ret >= 8) ? 0 : ret; -} - -#define DMA_SMSK (IO_DMA + 0x14) -#define DMA_MODE (IO_DMA + 0x16) -#define DMA_FFC (IO_DMA + 0x18) - -#define DMA37SM_CLEAR 0x00 -#define DMA37SM_SET 0x04 - -#define DMA_CHN(c) (IO_DMA + ((c) << 2)) - -static void -sbic_dmastart(sbic) - struct sbic_softc *sbic; -{ - int waport; - -#ifdef CYRIX_5X86 - /* Cyrix 5x86 */ - asm("wbinvd"); /* wbinvd (WB cache flush) */ -#endif - -#ifdef SC98BUSMASTER - if (sc98busmaster) { - sbic_write_reg(sbic->sc_base, 0x73, 0x32); - sbic_write_reg(sbic->sc_base, 0x74, 0x23); - } -#endif - - /* mask channel */ - outb(DMA_SMSK, sbic->sc_dma | DMA37SM_SET); - - /* set dma channel mode, and reset address ff */ - if (sbic->sc_xs->flags & SCSI_DATA_IN) - outb(DMA_MODE, sbic->sc_dma | DMA37MD_SINGLE | DMA37MD_WRITE); - else - outb(DMA_MODE, sbic->sc_dma | DMA37MD_SINGLE | DMA37MD_READ); - outb(DMA_FFC, 0); - - /* send start address */ - waport = DMA_CHN(sbic->sc_dma); - outb(waport, sbic->sc_cur->dc_addr); - outb(waport, sbic->sc_cur->dc_addr>>8); - outb(dmapageport[sbic->sc_dma], sbic->sc_cur->dc_addr>>16); - - /* send count */ - outb(waport + 2, sbic->sc_cur->dc_count - 1); - outb(waport + 2, (sbic->sc_cur->dc_count-1)>>8); - - /* unmask channel */ - outb(DMA_SMSK, sbic->sc_dma | DMA37SM_CLEAR); - - /* SCSI DMA enable */ - outb(sbic->sc_base + 4, 1); -} - -static void -sbic_dmastop(sbic) - struct sbic_softc *sbic; -{ -#if defined(CYRIX_486DLC) || defined(IBM_486SLC) - if (sbic->sc_xs->flags & SCSI_DATA_IN) { - /* cache flush only after reading 92/12/9 by A.Kojima */ - asm(" .byte 0x0f,0x08"); /* invd (cache flush) */ - } -#endif - /* mask channel */ - outb(DMA_SMSK, DMA37SM_SET | sbic->sc_dma); - - /* SCSI DMA disable */ - outb(sbic->sc_base + 4, 2); - -#ifdef SC98BUSMASTER - if (sc98busmaster) { - sbic_write_reg(sbic->sc_base, 0x73, 0x43); - sbic_write_reg(sbic->sc_base, 0x74, 0x34); - } -#endif -} diff --git a/sys/pc98/pc98/sbicreg.h b/sys/pc98/pc98/sbicreg.h deleted file mode 100644 index e71a535..0000000 --- a/sys/pc98/pc98/sbicreg.h +++ /dev/null @@ -1,429 +0,0 @@ -/* $NetBSD: sbicreg.h,v 1.2 1994/10/26 02:04:40 cgd Exp $ */ - -/* - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson of Lawrence Berkeley Laboratory. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. - * - * @(#)scsireg.h 7.3 (Berkeley) 2/5/91 - */ -/* - * Ported to PC-9801 by Yoshio Kimura, 1994 - * last update 09/24/1994 - */ - -/* - * AMD AM33C93A SCSI interface hardware description. - * - * Using parts of the Mach scsi driver for the 33C93 - */ - -#define SBIC_myid 0 -#define SBIC_cdbsize 0 -#define SBIC_control 1 -#define SBIC_timeo 2 -#define SBIC_cdb1 3 -#define SBIC_tsecs 3 -#define SBIC_cdb2 4 -#define SBIC_theads 4 -#define SBIC_cdb3 5 -#define SBIC_tcyl_hi 5 -#define SBIC_cdb4 6 -#define SBIC_tcyl_lo 6 -#define SBIC_cdb5 7 -#define SBIC_addr_hi 7 -#define SBIC_cdb6 8 -#define SBIC_addr_2 8 -#define SBIC_cdb7 9 -#define SBIC_addr_3 9 -#define SBIC_cdb8 10 -#define SBIC_addr_lo 10 -#define SBIC_cdb9 11 -#define SBIC_secno 11 -#define SBIC_cdb10 12 -#define SBIC_headno 12 -#define SBIC_cdb11 13 -#define SBIC_cylno_hi 13 -#define SBIC_cdb12 14 -#define SBIC_cylno_lo 14 -#define SBIC_tlun 15 -#define SBIC_cmd_phase 16 -#define SBIC_syn 17 -#define SBIC_count_hi 18 -#define SBIC_count_med 19 -#define SBIC_count_lo 20 -#define SBIC_selid 21 -#define SBIC_rselid 22 -#define SBIC_csr 23 -#define SBIC_cmd 24 -#define SBIC_data 25 -#define SBIC_mem_bank 48 -#define SBIC_mem_win 49 -#define SBIC_reserved1 50 -#define SBIC_reset_int 51 -#define SBIC_reserved2 52 -#define SBIC_reserved3 53 -/* sbic_asr is addressed directly */ - -/* - * Register defines - */ - -/* - * Auxiliary Status Register - */ - -#define SBIC_ASR_INT 0x80 /* Interrupt pending */ -#define SBIC_ASR_LCI 0x40 /* Last command ignored */ -#define SBIC_ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */ -#define SBIC_ASR_CIP 0x10 /* Busy, cmd unavail also */ -#define SBIC_ASR_xxx 0x0c -#define SBIC_ASR_PE 0x02 /* Parity error (even) */ -#define SBIC_ASR_DBR 0x01 /* Data Buffer Ready */ - -/* - * My ID register, and/or CDB Size - */ - -#define SBIC_ID_FS_8_10 0x00 /* Input clock is 8-10 Mhz */ - /* 11 Mhz is invalid */ -#define SBIC_ID_FS_12_15 0x40 /* Input clock is 12-15 Mhz */ -#define SBIC_ID_FS_16_20 0x80 /* Input clock is 16-20 Mhz */ -#define SBIC_ID_EHP 0x10 /* Enable host parity */ -#define SBIC_ID_EAF 0x08 /* Enable Advanced Features */ -#define SBIC_ID_MASK 0x07 -#define SBIC_ID_CBDSIZE_MASK 0x0f /* if unk SCSI cmd group */ - -/* - * Control register - */ - -#define SBIC_CTL_DMA 0x80 /* Single byte dma */ -#define SBIC_CTL_DBA_DMA 0x40 /* direct buffer acces (bus master)*/ -#define SBIC_CTL_BURST_DMA 0x20 /* continuous mode (8237) */ -#define SBIC_CTL_NO_DMA 0x00 /* Programmed I/O */ -#define SBIC_CTL_HHP 0x10 /* Halt on host parity error */ -#define SBIC_CTL_EDI 0x08 /* Ending disconnect interrupt */ -#define SBIC_CTL_IDI 0x04 /* Intermediate disconnect interrupt*/ -#define SBIC_CTL_HA 0x02 /* Halt on ATN */ -#define SBIC_CTL_HSP 0x01 /* Halt on SCSI parity error */ - -/* - * Timeout period register - * [val in msecs, input clk in 0.1 Mhz] - */ - -#define SBIC_TIMEOUT(val,clk) ((((val) * (clk)) / 800) + 1) - -/* - * CDBn registers, note that - * cdb11 is used for status byte in target mode (send-status-and-cc) - * cdb12 sez if linked command complete, and w/flag if so - */ - -/* - * Target LUN register - * [holds target status when select-and-xfer] - */ - -#define SBIC_TLUN_VALID 0x80 /* did we receive an Identify msg */ -#define SBIC_TLUN_DOK 0x40 /* Disconnect OK */ -#define SBIC_TLUN_xxx 0x38 -#define SBIC_TLUN_MASK 0x07 - -/* - * Command Phase register - */ - -#define SBIC_CPH_MASK 0x7f /* values/restarts are cmd specific */ -#define SBIC_CPH(p) ((p) & SBIC_CPH_MASK) - -/* - * FIFO register - */ - -#define SBIC_FIFO_DEEP 12 - -/* - * maximum possible size in TC registers. Since this is 24 bit, it's easy - */ -#define SBIC_TC_MAX ((1 << 24) - 1) - -/* - * Synchronous xfer register - */ - -#define SBIC_SYN_OFF_MASK 0x0f -#define SBIC_SYN_MAX_OFFSET SBIC_FIFO_DEEP -#define SBIC_SYN_PER_MASK 0x70 -#define SBIC_SYN_MIN_PERIOD 2 /* upto 8, encoded as 0 */ - -#define SBIC_SYN(o,p) \ - (((o) & SBIC_SYN_OFF_MASK) | (((p) << 4) & SBIC_SYN_PER_MASK)) - -/* - * Transfer count register - * optimal access macros depend on addressing - */ - -/* - * Destination ID (selid) register - */ - -#define SBIC_SID_SCC 0x80 /* Select command chaining (tgt) */ -#define SBIC_SID_DPD 0x40 /* Data phase direction (inittor) */ -#define SBIC_SID_FROM_SCSI 0x40 -#define SBIC_SID_TO_SCSI 0x00 -#define SBIC_SID_xxx 0x38 -#define SBIC_SID_IDMASK 0x07 - -/* - * Source ID (rselid) register - */ - -#define SBIC_RID_ER 0x80 /* Enable reselection */ -#define SBIC_RID_ES 0x40 /* Enable selection */ -#define SBIC_RID_DSP 0x20 /* Disable select parity */ -#define SBIC_RID_SIV 0x08 /* Source ID valid */ -#define SBIC_RID_MASK 0x07 - -/* - * Status register - */ - -#define SBIC_CSR_CAUSE 0xf0 -#define SBIC_CSR_RESET 0x00 /* chip was reset */ -#define SBIC_CSR_CMD_DONE 0x10 /* cmd completed */ -#define SBIC_CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/ -#define SBIC_CSR_CMD_ERR 0x40 /* end with error */ -#define SBIC_CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */ - - -#define SBIC_CSR_QUALIFIER 0x0f -/* Reset State Interrupts */ -#define SBIC_CSR_RESET 0x00 /* reset w/advanced features*/ -#define SBIC_CSR_RESET_AM 0x01 /* reset w/advanced features*/ -/* Successful Completion Interrupts */ -#define SBIC_CSR_TARGET 0x10 /* reselect complete */ -#define SBIC_CSR_INITIATOR 0x11 /* select complete */ -#define SBIC_CSR_WO_ATN 0x13 /* tgt mode completion */ -#define SBIC_CSR_W_ATN 0x14 /* ditto */ -#define SBIC_CSR_XLATED 0x15 /* translate address cmd */ -#define SBIC_CSR_S_XFERRED 0x16 /* initiator mode completion*/ -#define SBIC_CSR_XFERRED 0x18 /* phase in low bits */ -/* Paused or Aborted Interrupts */ -#define SBIC_CSR_MSGIN_W_ACK 0x20 /* (I) msgin, ACK asserted*/ -#define SBIC_CSR_SDP 0x21 /* (I) SDP msg received */ -#define SBIC_CSR_SEL_ABRT 0x22 /* sel/resel aborted */ -#define SBIC_CSR_XFR_PAUSED 0x23 /* (T) no ATN */ -#define SBIC_CSR_XFR_PAUSED_ATN 0x24 /* (T) ATN is asserted */ -#define SBIC_CSR_RSLT_AM 0x27 /* (I) lost selection (AM) */ -#define SBIC_CSR_MIS 0x28 /* (I) xfer aborted, ph mis */ -/* Terminated Interrupts */ -#define SBIC_CSR_CMD_INVALID 0x40 -#define SBIC_CSR_DISC 0x41 /* (I) tgt disconnected */ -#define SBIC_CSR_SEL_TIMEO 0x42 -#define SBIC_CSR_PE 0x43 /* parity error */ -#define SBIC_CSR_PE_ATN 0x44 /* ditto, ATN is asserted */ -#define SBIC_CSR_XLATE_TOOBIG 0x45 -#define SBIC_CSR_RSLT_NOAM 0x46 /* (I) lost sel, no AM mode */ -#define SBIC_CSR_BAD_STATUS 0x47 /* status byte was nok */ -#define SBIC_CSR_MIS_1 0x48 /* ph mis, see low bits */ -/* Service Required Interrupts */ -#define SBIC_CSR_RSLT_NI 0x80 /* reselected, no ify msg */ -#define SBIC_CSR_RSLT_IFY 0x81 /* ditto, AM mode, got ify */ -#define SBIC_CSR_SLT 0x82 /* selected, no ATN */ -#define SBIC_CSR_SLT_ATN 0x83 /* selected with ATN */ -#define SBIC_CSR_ATN 0x84 /* (T) ATN asserted */ -#define SBIC_CSR_DISC_1 0x85 /* (I) bus is free */ -#define SBIC_CSR_UNK_GROUP 0x87 /* strange CDB1 */ -#define SBIC_CSR_MIS_2 0x88 /* (I) ph mis, see low bits */ - -#define SBIC_PHASE(csr) SCSI_PHASE(csr) - -/* - * Command register (command codes) - */ - -#define SBIC_CMD_SBT 0x80 /* Single byte xfer qualifier */ -#define SBIC_CMD_MASK 0x7f - - /* Miscellaneous */ -#define SBIC_CMD_RESET 0x00 /* (DTI) lev I */ -#define SBIC_CMD_ABORT 0x01 /* (DTI) lev I */ -#define SBIC_CMD_DISC 0x04 /* ( TI) lev I */ -#define SBIC_CMD_SSCC 0x0d /* ( TI) lev I */ -#define SBIC_CMD_SET_IDI 0x0f /* (DTI) lev I */ -#define SBIC_CMD_XLATE 0x18 /* (DT ) lev II */ - - /* Initiator state */ -#define SBIC_CMD_SET_ATN 0x02 /* ( I) lev I */ -#define SBIC_CMD_CLR_ACK 0x03 /* ( I) lev I */ -#define SBIC_CMD_XFER_PAD 0x19 /* ( I) lev II */ -#define SBIC_CMD_XFER_INFO 0x20 /* ( I) lev II */ - - /* Target state */ -#define SBIC_CMD_SND_DISC 0x0e /* ( T ) lev II */ -#define SBIC_CMD_RCV_CMD 0x10 /* ( T ) lev II */ -#define SBIC_CMD_RCV_DATA 0x11 /* ( T ) lev II */ -#define SBIC_CMD_RCV_MSG_OUT 0x12 /* ( T ) lev II */ -#define SBIC_CMD_RCV 0x13 /* ( T ) lev II */ -#define SBIC_CMD_SND_STATUS 0x14 /* ( T ) lev II */ -#define SBIC_CMD_SND_DATA 0x15 /* ( T ) lev II */ -#define SBIC_CMD_SND_MSG_IN 0x16 /* ( T ) lev II */ -#define SBIC_CMD_SND 0x17 /* ( T ) lev II */ - - /* Disconnected state */ -#define SBIC_CMD_RESELECT 0x05 /* (D ) lev II */ -#define SBIC_CMD_SEL_ATN 0x06 /* (D ) lev II */ -#define SBIC_CMD_SEL 0x07 /* (D ) lev II */ -#define SBIC_CMD_SEL_ATN_XFER 0x08 /* (D I) lev II */ -#define SBIC_CMD_SEL_XFER 0x09 /* (D I) lev II */ -#define SBIC_CMD_RESELECT_RECV 0x0a /* (DT ) lev II */ -#define SBIC_CMD_RESELECT_SEND 0x0b /* (DT ) lev II */ -#define SBIC_CMD_WAIT_SEL_RECV 0x0c /* (DT ) lev II */ - -/* approximate, but we won't do SBT on selects */ -#define sbic_isa_select(cmd) (((cmd) > 0x5) && ((cmd) < 0xa)) - -#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA - -#define sbic_read_reg(iobase,regno,val) do { \ - outb(iobase, (regno)); \ - (val) = inb((iobase) + 2); \ - } while (0) - -#define sbic_write_reg(iobase,regno,val) do { \ - outb(iobase, (regno)); \ - outb((iobase) + 2, (val)); \ - } while (0) - -#define SET_SBIC_myid(iobase,val) sbic_write_reg(iobase,SBIC_myid,val) -#define GET_SBIC_myid(iobase,val) sbic_read_reg(iobase,SBIC_myid,val) -#define SET_SBIC_cdbsize(iobase,val) sbic_write_reg(iobase,SBIC_cdbsize,val) -#define GET_SBIC_cdbsize(iobase,val) sbic_read_reg(iobase,SBIC_cdbsize,val) -#define SET_SBIC_control(iobase,val) sbic_write_reg(iobase,SBIC_control,val) -#define GET_SBIC_control(iobase,val) sbic_read_reg(iobase,SBIC_control,val) -#define SET_SBIC_timeo(iobase,val) sbic_write_reg(iobase,SBIC_timeo,val) -#define GET_SBIC_timeo(iobase,val) sbic_read_reg(iobase,SBIC_timeo,val) -#define SET_SBIC_cdb1(iobase,val) sbic_write_reg(iobase,SBIC_cdb1,val) -#define GET_SBIC_cdb1(iobase,val) sbic_read_reg(iobase,SBIC_cdb1,val) -#define SET_SBIC_cdb2(iobase,val) sbic_write_reg(iobase,SBIC_cdb2,val) -#define GET_SBIC_cdb2(iobase,val) sbic_read_reg(iobase,SBIC_cdb2,val) -#define SET_SBIC_cdb3(iobase,val) sbic_write_reg(iobase,SBIC_cdb3,val) -#define GET_SBIC_cdb3(iobase,val) sbic_read_reg(iobase,SBIC_cdb3,val) -#define SET_SBIC_cdb4(iobase,val) sbic_write_reg(iobase,SBIC_cdb4,val) -#define GET_SBIC_cdb4(iobase,val) sbic_read_reg(iobase,SBIC_cdb4,val) -#define SET_SBIC_cdb5(iobase,val) sbic_write_reg(iobase,SBIC_cdb5,val) -#define GET_SBIC_cdb5(iobase,val) sbic_read_reg(iobase,SBIC_cdb5,val) -#define SET_SBIC_cdb6(iobase,val) sbic_write_reg(iobase,SBIC_cdb6,val) -#define GET_SBIC_cdb6(iobase,val) sbic_read_reg(iobase,SBIC_cdb6,val) -#define SET_SBIC_cdb7(iobase,val) sbic_write_reg(iobase,SBIC_cdb7,val) -#define GET_SBIC_cdb7(iobase,val) sbic_read_reg(iobase,SBIC_cdb7,val) -#define SET_SBIC_cdb8(iobase,val) sbic_write_reg(iobase,SBIC_cdb8,val) -#define GET_SBIC_cdb8(iobase,val) sbic_read_reg(iobase,SBIC_cdb8,val) -#define SET_SBIC_cdb9(iobase,val) sbic_write_reg(iobase,SBIC_cdb9,val) -#define GET_SBIC_cdb9(iobase,val) sbic_read_reg(iobase,SBIC_cdb9,val) -#define SET_SBIC_cdb10(iobase,val) sbic_write_reg(iobase,SBIC_cdb10,val) -#define GET_SBIC_cdb10(iobase,val) sbic_read_reg(iobase,SBIC_cdb10,val) -#define SET_SBIC_cdb11(iobase,val) sbic_write_reg(iobase,SBIC_cdb11,val) -#define GET_SBIC_cdb11(iobase,val) sbic_read_reg(iobase,SBIC_cdb11,val) -#define SET_SBIC_cdb12(iobase,val) sbic_write_reg(iobase,SBIC_cdb12,val) -#define GET_SBIC_cdb12(iobase,val) sbic_read_reg(iobase,SBIC_cdb12,val) -#define SET_SBIC_tlun(iobase,val) sbic_write_reg(iobase,SBIC_tlun,val) -#define GET_SBIC_tlun(iobase,val) sbic_read_reg(iobase,SBIC_tlun,val) -#define SET_SBIC_cmd_phase(iobase,val) sbic_write_reg(iobase,SBIC_cmd_phase,val) -#define GET_SBIC_cmd_phase(iobase,val) sbic_read_reg(iobase,SBIC_cmd_phase,val) -#define SET_SBIC_syn(iobase,val) sbic_write_reg(iobase,SBIC_syn,val) -#define GET_SBIC_syn(iobase,val) sbic_read_reg(iobase,SBIC_syn,val) -#define SET_SBIC_count_hi(iobase,val) sbic_write_reg(iobase,SBIC_count_hi,val) -#define GET_SBIC_count_hi(iobase,val) sbic_read_reg(iobase,SBIC_count_hi,val) -#define SET_SBIC_count_med(iobase,val) sbic_write_reg(iobase,SBIC_count_med,val) -#define GET_SBIC_count_med(iobase,val) sbic_read_reg(iobase,SBIC_count_med,val) -#define SET_SBIC_count_lo(iobase,val) sbic_write_reg(iobase,SBIC_count_lo,val) -#define GET_SBIC_count_lo(iobase,val) sbic_read_reg(iobase,SBIC_count_lo,val) -#define SET_SBIC_selid(iobase,val) sbic_write_reg(iobase,SBIC_selid,val) -#define GET_SBIC_selid(iobase,val) sbic_read_reg(iobase,SBIC_selid,val) -#define SET_SBIC_rselid(iobase,val) sbic_write_reg(iobase,SBIC_rselid,val) -#define GET_SBIC_rselid(iobase,val) sbic_read_reg(iobase,SBIC_rselid,val) -#define SET_SBIC_csr(iobase,val) sbic_write_reg(iobase,SBIC_csr,val) -#define GET_SBIC_csr(iobase,val) sbic_read_reg(iobase,SBIC_csr,val) -#define SET_SBIC_cmd(iobase,val) sbic_write_reg(iobase,SBIC_cmd,val) -#define GET_SBIC_cmd(iobase,val) sbic_read_reg(iobase,SBIC_cmd,val) -#define SET_SBIC_data(iobase,val) sbic_write_reg(iobase,SBIC_data,val) -#define GET_SBIC_data(iobase,val) sbic_read_reg(iobase,SBIC_data,val) -#define SET_SBIC_mem_bank(iobase,val) sbic_write_reg(iobase,SBIC_mem_bank,val) -#define GET_SBIC_mem_bank(iobase,val) sbic_read_reg(iobase,SBIC_mem_bank,val) -#define GET_SBIC_mem_win(iobase,val) sbic_read_reg(iobase,SBIC_mem_win,val) -#define GET_SBIC_reset_int(iobase,val) sbic_read_reg(iobase,SBIC_reset_int,val) - -#define SBIC_TC_PUT(iobase,val) do { \ - sbic_write_reg(iobase,SBIC_count_hi,((val)>>16)); \ - outb((iobase) + 2, ((val)>>8)); \ - outb((iobase) + 2, (val)); \ -} while (0) -#define SBIC_TC_GET(iobase,val) do { \ - sbic_read_reg(iobase,SBIC_count_hi,(val)); \ - (val) = ((val)<<8) | inb((iobase) + 2); \ - (val) = ((val)<<8) | inb((iobase) + 2); \ -} while (0) - -#define SBIC_LOAD_COMMAND(iobase,cmd,cmdsize) do { \ - int n=(cmdsize)-1; \ - char *ptr = (char*)(cmd); \ - sbic_write_reg(iobase,SBIC_cdb1,*ptr++); \ - while (n-- > 0) outb((iobase) + 2, *ptr++); \ -} while (0) - -#define GET_SBIC_asr(iobase,val) (val) = inb(iobase) - -#define WAIT_CIP(iobase) do { \ - while (inb(iobase) & SBIC_ASR_CIP) \ - ; \ -} while (0) - -/* transmit a byte in programmed I/O mode */ -#define SEND_BYTE(iobase,ch) do { \ - WAIT_CIP((iobase)->sc_base); \ - SET_SBIC_cmd((iobase)->sc_base, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \ - SBIC_WAIT(iobase, SBIC_ASR_DBR, 0); \ - SET_SBIC_data((iobase)->sc_base, ch); \ - } while (0) - -/* receive a byte in programmed I/O mode */ -#define RECV_BYTE(iobase,ch) do { \ - WAIT_CIP((iobase)->sc_base); \ - SET_SBIC_cmd((iobase)->sc_base, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \ - SBIC_WAIT(iobase, SBIC_ASR_DBR, 0); \ - GET_SBIC_data((iobase)->sc_base, ch); \ - } while (0) diff --git a/sys/pc98/pc98/sbicvar.h b/sys/pc98/pc98/sbicvar.h deleted file mode 100644 index d4de02c..0000000 --- a/sys/pc98/pc98/sbicvar.h +++ /dev/null @@ -1,157 +0,0 @@ -/* $NetBSD: sbicvar.h,v 1.5 1995/02/12 19:19:21 chopps Exp $ */ - -/* - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson of Lawrence Berkeley Laboratory. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. - * - * @(#)scsivar.h 7.1 (Berkeley) 5/8/90 - */ -/* - * Ported to PC-9801 by Yoshio Kimura, 1994 - * last update 09/23/1994 - */ -#ifndef _SBICVAR_H_ -#define _SBICVAR_H_ - -/* - * The largest single request will be MAXPHYS bytes which will require - * at most MAXPHYS/PAGE_SIZE+1 chain elements to describe, i.e. if none of - * the buffer pages are physically contiguous (MAXPHYS/PAGE_SIZE) and the - * buffer is not page aligned (+1). - */ -#define SBIC_NSEG 17 - -struct dma_chain { - int dc_count; - int dc_addr; -}; - -struct sbic_pending { - TAILQ_ENTRY(sbic_pending) link; - struct scsi_xfer *xs; -}; - -struct sbic_softc { -#ifndef __FreeBSD__ - struct device sc_dev; - struct pc98dev sc_id; - struct intrhand sc_ih; -#endif - -#ifdef __FreeBSD__ - int unit; /* unit number */ -#endif - u_short sc_base; - u_short sc_int; - u_short sc_dma; - int sc_scsi_dev; - u_long sc_clkfreq; - - struct target_sync { - u_char state; - u_char period; - u_char offset; - } sc_sync[8]; - struct scsi_link sc_link; /* proto for sub devices */ - TAILQ_HEAD(,sbic_pending) sc_xslist; /* LIFO */ - struct sbic_pending sc_xsstore[8][8]; /* one for every unit */ - struct scsi_xfer *sc_xs; /* transfer from high level code */ - u_char sc_flags; - u_char sc_stat[2]; - u_char sc_msg[7]; - struct dma_chain sc_chain[SBIC_NSEG]; - struct dma_chain *sc_cur; - struct dma_chain *sc_last; -}; - -/* sc_flags */ -#define SBICF_ALIVE 0x01 /* controller initialized */ -#define SBICF_DCFLUSH 0x02 /* need flush for overlap after dma finishes */ -#define SBICF_SELECTED 0x04 /* bus is in selected state. */ -#define SBICF_BADDMA 0x10 /* controller can only DMA to ztwobus space */ -#define SBICF_BBUF 0x20 /* DMA input needs to be copied from bounce */ -#define SBICF_INTR 0x40 /* SBICF interrupt expected */ -#define SBICF_INDMA 0x80 /* not used yet, DMA I/O in progress */ - -/* sync states */ -#define SYNC_START 0 /* no sync handshake started */ -#define SYNC_SENT 1 /* we sent sync request, no answer yet */ -#define SYNC_DONE 2 /* target accepted our (or inferior) settings, - or it rejected the request and we stay async */ -#ifdef DEBUG -#define DDB_FOLLOW 0x04 -#define DDB_IO 0x08 -#endif - -#define PHASE 0x07 /* mask for psns/pctl phase */ -#define DATA_OUT_PHASE 0x00 -#define DATA_IN_PHASE 0x01 -#define CMD_PHASE 0x02 -#define STATUS_PHASE 0x03 -#define BUS_FREE_PHASE 0x04 -#define ARB_SEL_PHASE 0x05 /* Fuji chip combines arbitration with sel. */ -#define MESG_OUT_PHASE 0x06 -#define MESG_IN_PHASE 0x07 - -#define MSG_CMD_COMPLETE 0x00 -#define MSG_EXT_MESSAGE 0x01 -#define MSG_SAVE_DATA_PTR 0x02 -#define MSG_RESTORE_PTR 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_INIT_DETECT_ERROR 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJECT 0x07 -#define MSG_NOOP 0x08 -#define MSG_PARITY_ERROR 0x09 -#define MSG_BUS_DEVICE_RESET 0x0C -#define MSG_IDENTIFY 0x80 -#define MSG_IDENTIFY_DR 0xc0 /* (disconnect/reconnect allowed) */ -#define MSG_SYNC_REQ 0x01 - - -#define STS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */ -#define STS_CONDMET 0x04 /* Condition Met (ie., search worked) */ -#define STS_BUSY 0x08 -#define STS_INTERMED 0x10 /* Intermediate status sent */ -#define STS_EXT 0x80 /* Extended status valid */ - -/* - * XXXX - */ -struct scsi_fmt_cdb { - int len; /* cdb length (in bytes) */ - u_char cdb[28]; /* cdb to use on next read/write */ -}; - -#endif /* _SBICVAR_H_ */ diff --git a/sys/pc98/pc98/scsireg.h b/sys/pc98/pc98/scsireg.h deleted file mode 100644 index cefe741..0000000 --- a/sys/pc98/pc98/scsireg.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson of Lawrence Berkeley Laboratory. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. - * - * @(#)scsireg.h 7.3 (Berkeley) 2/5/91 - */ - -/* - * AMD AM33C93A SCSI interface hardware description. - * - * Using parts of the Mach scsi driver for the 33C93 - */ - -#define SBIC_myid 0 -#define SBIC_cdbsize 0 -#define SBIC_control 1 -#define SBIC_timeo 2 -#define SBIC_cdb1 3 -#define SBIC_tsecs 3 -#define SBIC_cdb2 4 -#define SBIC_theads 4 -#define SBIC_cdb3 5 -#define SBIC_tcyl_hi 5 -#define SBIC_cdb4 6 -#define SBIC_tcyl_lo 6 -#define SBIC_cdb5 7 -#define SBIC_addr_hi 7 -#define SBIC_cdb6 8 -#define SBIC_addr_2 8 -#define SBIC_cdb7 9 -#define SBIC_addr_3 9 -#define SBIC_cdb8 10 -#define SBIC_addr_lo 10 -#define SBIC_cdb9 11 -#define SBIC_secno 11 -#define SBIC_cdb10 12 -#define SBIC_headno 12 -#define SBIC_cdb11 13 -#define SBIC_cylno_hi 13 -#define SBIC_cdb12 14 -#define SBIC_cylno_lo 14 -#define SBIC_tlun 15 -#define SBIC_cmd_phase 16 -#define SBIC_syn 17 -#define SBIC_count_hi 18 -#define SBIC_count_med 19 -#define SBIC_count_lo 20 -#define SBIC_selid 21 -#define SBIC_rselid 22 -#define SBIC_csr 23 -#define SBIC_cmd 24 -#define SBIC_data 25 -#define SBIC_bank 48 -#define SBIC_window 49 -#define SBIC_int 51 -/* sbic_asr is addressed directly */ - -/* - * Register defines - */ - -/* - * Auxiliary Status Register - */ - -#define SBIC_ASR_INT 0x80 /* Interrupt pending */ -#define SBIC_ASR_LCI 0x40 /* Last command ignored */ -#define SBIC_ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */ -#define SBIC_ASR_CIP 0x10 /* Busy, cmd unavail also */ -#define SBIC_ASR_xxx 0x0c -#define SBIC_ASR_PE 0x02 /* Parity error (even) */ -#define SBIC_ASR_DBR 0x01 /* Data Buffer Ready */ - -/* - * My ID register, and/or CDB Size - */ - -#define SBIC_ID_FS_8_10 0x00 /* Input clock is 8-10 Mhz */ - /* 11 Mhz is invalid */ -#define SBIC_ID_FS_12_15 0x40 /* Input clock is 12-15 Mhz */ -#define SBIC_ID_FS_16_20 0x80 /* Input clock is 16-20 Mhz */ -#define SBIC_ID_EHP 0x10 /* Enable host parity */ -#define SBIC_ID_EAF 0x08 /* Enable Advanced Features */ -#define SBIC_ID_MASK 0x07 -#define SBIC_ID_CBDSIZE_MASK 0x0f /* if unk SCSI cmd group */ - -/* - * Control register - */ - -#define SBIC_CTL_DMA 0x80 /* Single byte dma */ -#define SBIC_CTL_DBA_DMA 0x40 /* direct buffer acces (bus master)*/ -#define SBIC_CTL_BURST_DMA 0x20 /* continuous mode (8237) */ -#define SBIC_CTL_NO_DMA 0x00 /* Programmed I/O */ -#define SBIC_CTL_HHP 0x10 /* Halt on host parity error */ -#define SBIC_CTL_EDI 0x08 /* Ending disconnect interrupt */ -#define SBIC_CTL_IDI 0x04 /* Intermediate disconnect interrupt*/ -#define SBIC_CTL_HA 0x02 /* Halt on ATN */ -#define SBIC_CTL_HSP 0x01 /* Halt on SCSI parity error */ - -/* - * Timeout period register - * [val in msecs, input clk in Mhz] - */ - -#define SBIC_TIMEOUT(val,clk) ((((val)*(clk))/80)+1) - -/* - * CDBn registers, note that - * cdb11 is used for status byte in target mode (send-status-and-cc) - * cdb12 sez if linked command complete, and w/flag if so - */ - -/* - * Target LUN register - * [holds target status when select-and-xfer] - */ - -#define SBIC_TLUN_VALID 0x80 /* did we receive an Identify msg */ -#define SBIC_TLUN_DOK 0x40 /* Disconnect OK */ -#define SBIC_TLUN_xxx 0x38 -#define SBIC_TLUN_MASK 0x07 - -/* - * Command Phase register - */ - -#define SBIC_CPH_MASK 0x7f /* values/restarts are cmd specific */ -#define SBIC_CPH(p) ((p)&SBIC_CPH_MASK) - -/* - * FIFO register - */ - -#define SBIC_FIFO_DEEP 12 - -/* - * Synchronous xfer register - */ - -#define SBIC_SYN_OFF_MASK 0x0f -#define SBIC_SYN_MAX_OFFSET (SBIC_FIFO_DEEP-1) -#define SBIC_SYN_PER_MASK 0x70 -#define SBIC_SYN_MIN_PERIOD 2 /* upto 8, encoded as 0 */ - -#define SBIC_SYN(o,p) (((o)&SBIC_SYN_OFF_MASK)|(((p)<<4)&SBIC_SYN_PER_MASK)) - -/* - * Transfer count register - * optimal access macros depend on addressing - */ - -/* - * Destination ID (selid) register - */ - -#define SBIC_SID_SCC 0x80 /* Select command chaining (tgt) */ -#define SBIC_SID_DPD 0x40 /* Data phase direction (inittor) */ -# define SBIC_SID_FROM_SCSI 0x40 -# define SBIC_SID_TO_SCSI 0x00 -#define SBIC_SID_xxx 0x38 -#define SBIC_SID_IDMASK 0x07 - -/* - * Source ID (rselid) register - */ - -#define SBIC_RID_ER 0x80 /* Enable reselection */ -#define SBIC_RID_ES 0x40 /* Enable selection */ -#define SBIC_RID_DSP 0x20 /* Disable select parity */ -#define SBIC_RID_SIV 0x08 /* Source ID valid */ -#define SBIC_RID_MASK 0x07 - -/* - * Status register - */ - -#define SBIC_CSR_CAUSE 0xf0 -# define SBIC_CSR_RESET 0x00 /* chip was reset */ -# define SBIC_CSR_CMD_DONE 0x10 /* cmd completed */ -# define SBIC_CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/ -# define SBIC_CSR_CMD_ERR 0x40 /* end with error */ -# define SBIC_CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */ - -#define SBIC_CSR_QUALIFIER 0x0f - - /* Reset State Interrupts */ -# define SBIC_CSR_RESET 0x00 /* reset w/advanced features*/ -# define SBIC_CSR_RESET_AM 0x01 /* reset w/advanced features*/ - - /* Successful Completion Interrupts */ -# define SBIC_CSR_TARGET 0x10 /* reselect complete */ -# define SBIC_CSR_INITIATOR 0x11 /* select complete */ -# define SBIC_CSR_WO_ATN 0x13 /* tgt mode completion */ -# define SBIC_CSR_W_ATN 0x14 /* ditto */ -# define SBIC_CSR_XLATED 0x15 /* translate address cmd */ -# define SBIC_CSR_S_XFERRED 0x16 /* initiator mode completion*/ -# define SBIC_CSR_XFERRED 0x18 /* phase in low bits */ - - /* Paused or Aborted Interrupts */ -# define SBIC_CSR_MSGIN_W_ACK 0x20 /* (I) msgin, ACK asserted*/ -# define SBIC_CSR_SDP 0x21 /* (I) SDP msg received */ -# define SBIC_CSR_SEL_ABRT 0x22 /* sel/resel aborted */ -# define SBIC_CSR_XFR_PAUSED 0x23 /* (T) no ATN */ -# define SBIC_CSR_XFR_PAUSED_ATN 0x24 /* (T) ATN is asserted */ -# define SBIC_CSR_RSLT_AM 0x27 /* (I) lost selection (AM) */ -# define SBIC_CSR_MIS 0x28 /* (I) xfer aborted, ph mis */ - - /* Terminated Interrupts */ -# define SBIC_CSR_CMD_INVALID 0x40 -# define SBIC_CSR_DISC 0x41 /* (I) tgt disconnected */ -# define SBIC_CSR_SEL_TIMEO 0x42 -# define SBIC_CSR_PE 0x43 /* parity error */ -# define SBIC_CSR_PE_ATN 0x44 /* ditto, ATN is asserted */ -# define SBIC_CSR_XLATE_TOOBIG 0x45 -# define SBIC_CSR_RSLT_NOAM 0x46 /* (I) lost sel, no AM mode */ -# define SBIC_CSR_BAD_STATUS 0x47 /* status byte was nok */ -# define SBIC_CSR_MIS_1 0x48 /* ph mis, see low bits */ - -# define SBIC_MCI_DATA_OUT 0x00 /* Data Out phase */ -# define SBIC_MCI_DATA_IN 0x01 /* Data In phase */ -# define SBIC_MCI_CMD 0x02 /* Command phase */ -# define SBIC_MCI_STATUS 0x03 /* Status phase */ -# define SBIC_MCI_INFO_OUT 0x04 /* Unspecified Info Out phase */ -# define SBIC_MCI_INFO_IN 0x05 /* Unspecified Info In phase */ -# define SBIC_MCI_MES_OUT 0x06 /* Message Out phase */ -# define SBIC_MCI_MES_IN 0x07 /* Message In phase */ - - /* Service Required Interrupts */ -# define SBIC_CSR_RSLT_NI 0x80 /* reselected, no ify msg */ -# define SBIC_CSR_RSLT_IFY 0x81 /* ditto, AM mode, got ify */ -# define SBIC_CSR_SLT 0x82 /* selected, no ATN */ -# define SBIC_CSR_SLT_ATN 0x83 /* selected with ATN */ -# define SBIC_CSR_ATN 0x84 /* (T) ATN asserted */ -# define SBIC_CSR_DISC_1 0x85 /* (I) bus is free */ -# define SBIC_CSR_UNK_GROUP 0x87 /* strange CDB1 */ -# define SBIC_CSR_MIS_2 0x88 /* (I) ph mis, see low bits */ - -#define SBIC_PHASE(csr) SCSI_PHASE(csr) - -/* - * Command register (command codes) - */ - -#define SBIC_CMD_SBT 0x80 /* Single byte xfer qualifier */ -#define SBIC_CMD_MASK 0x7f - - /* Miscellaneous */ -#define SBIC_CMD_RESET 0x00 /* (DTI) lev I */ -#define SBIC_CMD_ABORT 0x01 /* (DTI) lev I */ -#define SBIC_CMD_DISC 0x04 /* ( TI) lev I */ -#define SBIC_CMD_SSCC 0x0d /* ( TI) lev I */ -#define SBIC_CMD_SET_IDI 0x0f /* (DTI) lev I */ -#define SBIC_CMD_XLATE 0x18 /* (DT ) lev II */ - - /* Initiator state */ -#define SBIC_CMD_SET_ATN 0x02 /* ( I) lev I */ -#define SBIC_CMD_CLR_ACK 0x03 /* ( I) lev I */ -#define SBIC_CMD_XFER_PAD 0x19 /* ( I) lev II */ -#define SBIC_CMD_XFER_INFO 0x20 /* ( I) lev II */ - - /* Target state */ -#define SBIC_CMD_SND_DISC 0x0e /* ( T ) lev II */ -#define SBIC_CMD_RCV_CMD 0x10 /* ( T ) lev II */ -#define SBIC_CMD_RCV_DATA 0x11 /* ( T ) lev II */ -#define SBIC_CMD_RCV_MSG_OUT 0x12 /* ( T ) lev II */ -#define SBIC_CMD_RCV 0x13 /* ( T ) lev II */ -#define SBIC_CMD_SND_STATUS 0x14 /* ( T ) lev II */ -#define SBIC_CMD_SND_DATA 0x15 /* ( T ) lev II */ -#define SBIC_CMD_SND_MSG_IN 0x16 /* ( T ) lev II */ -#define SBIC_CMD_SND 0x17 /* ( T ) lev II */ - - /* Disconnected state */ -#define SBIC_CMD_RESELECT 0x05 /* (D ) lev II */ -#define SBIC_CMD_SEL_ATN 0x06 /* (D ) lev II */ -#define SBIC_CMD_SEL 0x07 /* (D ) lev II */ -#define SBIC_CMD_SEL_ATN_XFER 0x08 /* (D I) lev II */ -#define SBIC_CMD_SEL_XFER 0x09 /* (D I) lev II */ -#define SBIC_CMD_RESELECT_RECV 0x0a /* (DT ) lev II */ -#define SBIC_CMD_RESELECT_SEND 0x0b /* (DT ) lev II */ -#define SBIC_CMD_WAIT_SEL_RECV 0x0c /* (DT ) lev II */ |