📄 bsfunc.c
字号:
/* $NecBSD: bsfunc.c,v 1.2 1997/10/31 17:43:37 honda 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#ifdef BS_STATICSstruct bs_statics bs_statics[NTARGETS];u_int bs_linkcmd_count[NTARGETS];u_int bs_bounce_used[NTARGETS];#endif /* BS_STATICS */#ifdef BS_DEBUGint 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 voidbs_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; }}voidbstimeout(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;}intbs_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 voidbs_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 */intbs_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 voidbs_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");}intbs_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 */voidbs_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. */voidbs_scsibus_start(bsc) struct bs_softc *bsc;{ struct targ_info *ti, *nextti = NULL; int error = HASERROR; u_int querm, bits, skip = 0; querm = (bsc->sc_hstate == BSC_BOOTUP); bsc->sc_hstate = BSC_TARG_CHECK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -