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

📄 isp_target.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 3 页
字号:
/* @(#)isp_target.c 1.14 *//* * Machine and OS Independent Target Mode Code for the Qlogic SCSI/FC adapters. * * Copyright (c) 1999, 2000, 2001 by Matthew Jacob * All rights reserved. * mjacob@feral.com * * 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 immediately at the beginning of the file, without modification, *    this list of conditions, and the following disclaimer. * 2. 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 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 AUTHOR 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. *//* * Bug fixes gratefully acknowledged from: *	Oded Kedem <oded@kashya.com> *//* * Include header file appropriate for platform we're building on. */#ifdef	__NetBSD__#include <dev/ic/isp_netbsd.h>#endif#ifdef	__FreeBSD__#include <dev/isp/isp_freebsd.h>#endif#ifdef	__OpenBSD__#include <dev/ic/isp_openbsd.h>#endif#ifdef	__linux__#include "isp_linux.h"#endif#ifdef	ISP_TARGET_MODEstatic const char atiocope[] =    "ATIO returned for lun %d because it was in the middle of Bus Device Reset "    "on bus %d";static const char atior[] =    "ATIO returned on for lun %d on from IID %d because a Bus Reset occurred "    "on bus %d";static void isp_got_msg(struct ispsoftc *, int, in_entry_t *);static void isp_got_msg_fc(struct ispsoftc *, int, in_fcentry_t *);static void isp_notify_ack(struct ispsoftc *, void *);static void isp_handle_atio(struct ispsoftc *, at_entry_t *);static void isp_handle_atio2(struct ispsoftc *, at2_entry_t *);static void isp_handle_ctio(struct ispsoftc *, ct_entry_t *);static void isp_handle_ctio2(struct ispsoftc *, ct2_entry_t *);/* * The Qlogic driver gets an interrupt to look at response queue entries. * Some of these are status completions for initiatior mode commands, but * if target mode is enabled, we get a whole wad of response queue entries * to be handled here. * * Basically the split into 3 main groups: Lun Enable/Modification responses, * SCSI Command processing, and Immediate Notification events. * * You start by writing a request queue entry to enable target mode (and * establish some resource limitations which you can modify later). * The f/w responds with a LUN ENABLE or LUN MODIFY response with * the status of this action. If the enable was successful, you can expect... * * Response queue entries with SCSI commands encapsulate show up in an ATIO * (Accept Target IO) type- sometimes with enough info to stop the command at * this level. Ultimately the driver has to feed back to the f/w's request * queue a sequence of CTIOs (continue target I/O) that describe data to * be moved and/or status to be sent) and finally finishing with sending * to the f/w's response queue an ATIO which then completes the handshake * with the f/w for that command. There's a lot of variations on this theme, * including flags you can set in the CTIO for the Qlogic 2X00 fibre channel * cards that 'auto-replenish' the f/w's ATIO count, but this is the basic * gist of it. * * The third group that can show up in the response queue are Immediate * Notification events. These include things like notifications of SCSI bus * resets, or Bus Device Reset messages or other messages received. This * a classic oddbins area. It can get  a little weird because you then turn * around and acknowledge the Immediate Notify by writing an entry onto the * request queue and then the f/w turns around and gives you an acknowledgement * to *your* acknowledgement on the response queue (the idea being to let * the f/w tell you when the event is *really* over I guess). * *//* * A new response queue entry has arrived. The interrupt service code * has already swizzled it into the platform dependent from canonical form. * * Because of the way this driver is designed, unfortunately most of the * actual synchronization work has to be done in the platform specific * code- we have no synchroniation primitives in the common code. */intisp_target_notify(struct ispsoftc *isp, void *vptr, u_int16_t *optrp){	u_int16_t status, seqid;	union {		at_entry_t	*atiop;		at2_entry_t	*at2iop;		ct_entry_t	*ctiop;		ct2_entry_t	*ct2iop;		lun_entry_t	*lunenp;		in_entry_t	*inotp;		in_fcentry_t	*inot_fcp;		na_entry_t	*nackp;		na_fcentry_t	*nack_fcp;		isphdr_t	*hp;		void *		*vp;#define	atiop		unp.atiop#define	at2iop		unp.at2iop#define	ctiop		unp.ctiop#define	ct2iop		unp.ct2iop#define	lunenp		unp.lunenp#define	inotp		unp.inotp#define	inot_fcp	unp.inot_fcp#define	nackp		unp.nackp#define	nack_fcp	unp.nack_fcp#define	hdrp		unp.hp	} unp;	u_int8_t local[QENTRY_LEN];	int bus, type, rval = 0;	type = isp_get_response_type(isp, (isphdr_t *)vptr);	unp.vp = vptr;	ISP_TDQE(isp, "isp_target_notify", (int) *optrp, vptr);	switch(type) {	case RQSTYPE_ATIO:		isp_get_atio(isp, atiop, (at_entry_t *) local);		isp_handle_atio(isp, (at_entry_t *) local);		break;	case RQSTYPE_CTIO:		isp_get_ctio(isp, ctiop, (ct_entry_t *) local);		isp_handle_ctio(isp, (ct_entry_t *) local);		break;	case RQSTYPE_ATIO2:		isp_get_atio2(isp, at2iop, (at2_entry_t *) local);		isp_handle_atio2(isp, (at2_entry_t *) local);		break;	case RQSTYPE_CTIO2:		isp_get_ctio2(isp, ct2iop, (ct2_entry_t *) local);		isp_handle_ctio2(isp, (ct2_entry_t *) local);		break;	case RQSTYPE_ENABLE_LUN:	case RQSTYPE_MODIFY_LUN:		isp_get_enable_lun(isp, lunenp, (lun_entry_t *) local);		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, local);		break;	case RQSTYPE_NOTIFY:		/*		 * Either the ISP received a SCSI message it can't		 * handle, or it's returning an Immed. Notify entry		 * we sent. We can send Immed. Notify entries to		 * increment the firmware's resource count for them		 * (we set this initially in the Enable Lun entry).		 */		bus = 0;		if (IS_FC(isp)) {			isp_get_notify_fc(isp, inot_fcp, (in_fcentry_t *)local);			inot_fcp = (in_fcentry_t *) local;			status = inot_fcp->in_status;			seqid = inot_fcp->in_seqid;		} else {			isp_get_notify(isp, inotp, (in_entry_t *)local);			inotp = (in_entry_t *) local;			status = inotp->in_status & 0xff;			seqid = inotp->in_seqid;			if (IS_DUALBUS(isp)) {				bus = GET_BUS_VAL(inotp->in_iid);				SET_BUS_VAL(inotp->in_iid, 0);			}		}		isp_prt(isp, ISP_LOGTDEBUG0,		    "Immediate Notify On Bus %d, status=0x%x seqid=0x%x",		    bus, status, seqid);		/*		 * ACK it right away.		 */		isp_notify_ack(isp, (status == IN_RESET)? NULL : local);		switch (status) {		case IN_RESET:			(void) isp_async(isp, ISPASYNC_BUS_RESET, &bus);			break;		case IN_MSG_RECEIVED:		case IN_IDE_RECEIVED:			if (IS_FC(isp)) {				isp_got_msg_fc(isp, bus, (in_fcentry_t *)local);			} else {				isp_got_msg(isp, bus, (in_entry_t *)local);			}			break;		case IN_RSRC_UNAVAIL:			isp_prt(isp, ISP_LOGWARN, "Firmware out of ATIOs");			break;		case IN_ABORT_TASK:			isp_prt(isp, ISP_LOGWARN,			    "Abort Task from IID %d RX_ID 0x%x",			    inot_fcp->in_iid, seqid);			(void) isp_async(isp, ISPASYNC_TARGET_ACTION, &bus);			break;		case IN_PORT_LOGOUT:			isp_prt(isp, ISP_LOGWARN,			    "Port Logout for Initiator %d RX_ID 0x%x",			    inot_fcp->in_iid, seqid);			break;		case IN_PORT_CHANGED:			isp_prt(isp, ISP_LOGWARN,			    "Port Changed for Initiator %d RX_ID 0x%x",			    inot_fcp->in_iid, seqid);			break;		case IN_GLOBAL_LOGO:			isp_prt(isp, ISP_LOGWARN, "All ports logged out");			break;		default:			isp_prt(isp, ISP_LOGERR,			    "bad status (0x%x) in isp_target_notify", status);			break;		}		break;	case RQSTYPE_NOTIFY_ACK:		/*		 * The ISP is acknowledging our acknowledgement of an		 * Immediate Notify entry for some asynchronous event.		 */		if (IS_FC(isp)) {			isp_get_notify_ack_fc(isp, nack_fcp,			    (na_fcentry_t *)local);			nack_fcp = (na_fcentry_t *)local;			isp_prt(isp, ISP_LOGTDEBUG1,			    "Notify Ack status=0x%x seqid 0x%x",			    nack_fcp->na_status, nack_fcp->na_seqid);		} else {			isp_get_notify_ack(isp, nackp, (na_entry_t *)local);			nackp = (na_entry_t *)local;			isp_prt(isp, ISP_LOGTDEBUG1,			    "Notify Ack event 0x%x status=0x%x seqid 0x%x",			    nackp->na_event, nackp->na_status, nackp->na_seqid);		}		break;	default:		isp_prt(isp, ISP_LOGERR,		    "Unknown entry type 0x%x in isp_target_notify", type);		rval = -1;		break;	}#undef	atiop#undef	at2iop#undef	ctiop#undef	ct2iop#undef	lunenp#undef	inotp#undef	inot_fcp#undef	nackp#undef	nack_fcp#undef	hdrp	return (rval);} /* * Toggle (on/off) target mode for bus/target/lun * * The caller has checked for overlap and legality. * * Note that not all of bus, target or lun can be paid attention to. * Note also that this action will not be complete until the f/w writes * response entry. The caller is responsible for synchronizing this. */intisp_lun_cmd(struct ispsoftc *isp, int cmd, int bus, int tgt, int lun,    int cmd_cnt, int inot_cnt, u_int32_t opaque){	lun_entry_t el;	u_int16_t nxti, optr;	void *outp;	MEMZERO(&el, sizeof (el));	if (IS_DUALBUS(isp)) {		el.le_rsvd = (bus & 0x1) << 7;	}	el.le_cmd_count = cmd_cnt;	el.le_in_count = inot_cnt;	if (cmd == RQSTYPE_ENABLE_LUN) {		if (IS_SCSI(isp)) {			el.le_flags = LUN_TQAE|LUN_DISAD;			el.le_cdb6len = 12;			el.le_cdb7len = 12;		}	} else if (cmd == -RQSTYPE_ENABLE_LUN) {		cmd = RQSTYPE_ENABLE_LUN;		el.le_cmd_count = 0;		el.le_in_count = 0;	} else if (cmd == -RQSTYPE_MODIFY_LUN) {		cmd = RQSTYPE_MODIFY_LUN;		el.le_ops = LUN_CCDECR | LUN_INDECR;	} else {		el.le_ops = LUN_CCINCR | LUN_ININCR;	}	el.le_header.rqs_entry_type = cmd;	el.le_header.rqs_entry_count = 1;	el.le_reserved = opaque;	if (IS_SCSI(isp)) {		el.le_tgt = tgt;		el.le_lun = lun;	} else if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) {		el.le_lun = lun;	}	el.le_timeout = 2;	if (isp_getrqentry(isp, &nxti, &optr, &outp)) {		isp_prt(isp, ISP_LOGERR,		    "Request Queue Overflow in isp_lun_cmd");		return (-1);	}	ISP_TDQE(isp, "isp_lun_cmd", (int) optr, &el);	isp_put_enable_lun(isp, &el, outp);	ISP_ADD_REQUEST(isp, nxti);	return (0);}intisp_target_put_entry(struct ispsoftc *isp, void *ap){	void *outp;	u_int16_t nxti, optr;	u_int8_t etype = ((isphdr_t *) ap)->rqs_entry_type;	if (isp_getrqentry(isp, &nxti, &optr, &outp)) {		isp_prt(isp, ISP_LOGWARN,		    "Request Queue Overflow in isp_target_put_entry");		return (-1);	}	switch (etype) {	case RQSTYPE_ATIO:		isp_put_atio(isp, (at_entry_t *) ap, (at_entry_t *) outp);		break;	case RQSTYPE_ATIO2:		isp_put_atio2(isp, (at2_entry_t *) ap, (at2_entry_t *) outp);		break;	case RQSTYPE_CTIO:		isp_put_ctio(isp, (ct_entry_t *) ap, (ct_entry_t *) outp);		break;	case RQSTYPE_CTIO2:		isp_put_ctio2(isp, (ct2_entry_t *) ap, (ct2_entry_t *) outp);		break;	default:		isp_prt(isp, ISP_LOGERR,		    "Unknown type 0x%x in isp_put_entry", etype);		return (-1);	}	ISP_TDQE(isp, "isp_target_put_entry", (int) optr, ap);;	ISP_ADD_REQUEST(isp, nxti);	return (0);}intisp_target_put_atio(struct ispsoftc *isp, void *arg){	union {		at_entry_t _atio;		at2_entry_t _atio2;	} atun;	MEMZERO(&atun, sizeof atun);	if (IS_FC(isp)) {		at2_entry_t *aep = arg;		atun._atio2.at_header.rqs_entry_type = RQSTYPE_ATIO2;		atun._atio2.at_header.rqs_entry_count = 1;		if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {			atun._atio2.at_scclun = (u_int16_t) aep->at_scclun;		} else {			atun._atio2.at_lun = (u_int8_t) aep->at_lun;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -