📄 bs.c
字号:
/* $NecBSD: bs.c,v 1.1 1997/07/18 09:18:59 kmatsuda Exp $ *//* $NetBSD$ *//* * [NetBSD for NEC PC98 series] * Copyright (c) 1994, 1995, 1996 NetBSD/pc98 porting staff. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *//* * Copyright (c) 1994, 1995, 1996 Naofumi HONDA. All rights reserved. */#ifdef __NetBSD__#include <i386/Cbus/dev/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_INT32Tbs_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. */intbscmdstart(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 voidbshoststart(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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -