⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bs.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	$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 + -