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

📄 isp.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN ||	    icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) {		PRINTF("%s: bad frame length (%d) from NVRAM- using %d\n",		    isp->isp_name, fcp->isp_maxfrmlen, ICB_DFLT_FRMLEN);		icbp->icb_maxfrmlen = ICB_DFLT_FRMLEN;	}	icbp->icb_maxalloc = fcp->isp_maxalloc;	if (icbp->icb_maxalloc < 16) {		PRINTF("%s: bad maximum allocation (%d)- using 16\n",		     isp->isp_name, fcp->isp_maxalloc);		icbp->icb_maxalloc = 16;	}	icbp->icb_execthrottle = fcp->isp_execthrottle;	if (icbp->icb_execthrottle < 1) {		PRINTF("%s: bad execution throttle of %d- using 16\n",		    isp->isp_name, fcp->isp_execthrottle);		icbp->icb_execthrottle = 16;	}	icbp->icb_retry_delay = fcp->isp_retry_delay;	icbp->icb_retry_count = fcp->isp_retry_count;	icbp->icb_hardaddr = loopid;	if (fcp->isp_wwn) {		MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, fcp->isp_wwn);		if (icbp->icb_fwoptions & ICBOPT_USE_PORTNAME) {			u_int64_t portname = fcp->isp_wwn | (2LL << 56);			MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, portname);		}	} else {		fcp->isp_fwoptions &= ~(ICBOPT_USE_PORTNAME|ICBOPT_FULL_LOGIN);	}	icbp->icb_rqstqlen = RQUEST_QUEUE_LEN;	icbp->icb_rsltqlen = RESULT_QUEUE_LEN;	icbp->icb_rqstaddr[RQRSP_ADDR0015] = DMA_LSW(isp->isp_rquest_dma);	icbp->icb_rqstaddr[RQRSP_ADDR1631] = DMA_MSW(isp->isp_rquest_dma);	icbp->icb_respaddr[RQRSP_ADDR0015] = DMA_LSW(isp->isp_result_dma);	icbp->icb_respaddr[RQRSP_ADDR1631] = DMA_MSW(isp->isp_result_dma);	MemoryBarrier();	for (count = 0; count < 10; count++) {		mbs.param[0] = MBOX_INIT_FIRMWARE;		mbs.param[1] = 0;		mbs.param[2] = DMA_MSW(fcp->isp_scdma);		mbs.param[3] = DMA_LSW(fcp->isp_scdma);		mbs.param[4] = 0;		mbs.param[5] = 0;		mbs.param[6] = 0;		mbs.param[7] = 0;		isp_mboxcmd(isp, &mbs);		switch (mbs.param[0]) {		case MBOX_COMMAND_COMPLETE:			count = 10;			break;		case ASYNC_PDB_CHANGED:			isp_mark_getpdb_all(isp);			/* FALL THROUGH */		case ASYNC_LIP_OCCURRED:		case ASYNC_LOOP_UP:		case ASYNC_LOOP_DOWN:		case ASYNC_LOOP_RESET:		case ASYNC_CHANGE_NOTIFY:			if (count > 9) {				PRINTF("%s: too many retries to get going- "				    "giving up\n", isp->isp_name);				return;			}			break;		default:			PRINTF("%s: INIT FIRMWARE failed\n", isp->isp_name);			return;		}	}	isp->isp_reqidx = isp->isp_reqodx = 0;	isp->isp_residx = 0;	isp->isp_sendmarker = 1;	/*	 * Whatever happens, we're now committed to being here.	 */	isp->isp_state = ISP_INITSTATE;	fcp->isp_fwstate = FW_CONFIG_WAIT;	isp_mark_getpdb_all(isp);#ifdef	ISP_TARGET_MODE	if (isp_modify_lun(isp, 0, 1, 1)) {		PRINTF("%s: failed to enable target mode\n", isp->isp_name);	}#endif}/* * Fibre Channel Support- get the port database for the id. * * Locks are held before coming here. Return 0 if success, * else failure. */static voidisp_mark_getpdb_all(isp)	struct ispsoftc *isp;{	isp_pdb_t *p;	fcparam *fcp = (fcparam *) isp->isp_param;	for (p = &fcp->isp_pdb[0]; p < &fcp->isp_pdb[MAX_FC_TARG]; p++) {		p->pdb_options = INVALID_PDB_OPTIONS;	}}static intisp_getpdb(isp, id, pdbp)	struct ispsoftc *isp;	int id;	isp_pdb_t *pdbp;{	fcparam *fcp = (fcparam *) isp->isp_param;	mbreg_t mbs;	mbs.param[0] = MBOX_GET_PORT_DB;	mbs.param[1] = id << 8;	mbs.param[2] = DMA_MSW(fcp->isp_scdma);	mbs.param[3] = DMA_LSW(fcp->isp_scdma);	/*	 * Unneeded. For the 2100, except for initializing f/w, registers	 * 4/5 have to not be written to.	 *	mbs.param[4] = 0;	 *	mbs.param[5] = 0;	 *	 */	mbs.param[6] = 0;	mbs.param[7] = 0;	isp_mboxcmd(isp, &mbs);	switch (mbs.param[0]) {	case MBOX_COMMAND_COMPLETE:		MemoryBarrier();		MEMCPY(pdbp, fcp->isp_scratch, sizeof (isp_pdb_t));		break;	case MBOX_HOST_INTERFACE_ERROR:		PRINTF("%s: DMA error getting port database\n", isp->isp_name);		return (-1);	case MBOX_COMMAND_PARAM_ERROR:		/* Not Logged In */		IDPRINTF(3, ("%s: Comand Param Error on Get Port Database\n",		    isp->isp_name));		return (-1);	default:		PRINTF("%s: error 0x%x getting port database for ID %d\n",		    isp->isp_name, mbs.param[0], id);		return (-1);	}	return (0);}/* * Make sure we have good FC link and know our Loop ID. */static intisp_fclink_test(isp, waitdelay)	struct ispsoftc *isp;	int waitdelay;{	mbreg_t mbs;	int count;	u_int8_t lwfs;	fcparam *fcp;	fcp = isp->isp_param;	/*	 * Wait up to N microseconds for F/W to go to a ready state.	 */	lwfs = FW_CONFIG_WAIT;	for (count = 0; count < waitdelay; count += 100) {		isp_fw_state(isp);		if (lwfs != fcp->isp_fwstate) {			PRINTF("%s: Firmware State %s -> %s\n",			    isp->isp_name, isp2100_fw_statename((int)lwfs),			    isp2100_fw_statename((int)fcp->isp_fwstate));			lwfs = fcp->isp_fwstate;		}		if (fcp->isp_fwstate == FW_READY) {			break;		}		SYS_DELAY(100);	/* wait 100 microseconds */	}	/*	 * If we haven't gone to 'ready' state, return.	 */	if (fcp->isp_fwstate != FW_READY) {		return (-1);	}	/*	 * Get our Loop ID (if possible). We really need to have it.	 */	mbs.param[0] = MBOX_GET_LOOP_ID;	isp_mboxcmd(isp, &mbs);	if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {		PRINTF("%s: GET LOOP ID failed\n", isp->isp_name);		return (-1);	}	fcp->isp_loopid = mbs.param[1];	fcp->isp_alpa = mbs.param[2];	PRINTF("%s: Loop ID %d, ALPA 0x%x\n", isp->isp_name,	    fcp->isp_loopid, fcp->isp_alpa);	return (0);}/* * Start a command. Locking is assumed done in the caller. */int32_tispscsicmd(xs)	ISP_SCSI_XFER_T *xs;{	struct ispsoftc *isp;	u_int8_t iptr, optr;	union {		ispreq_t *_reqp;		ispreqt2_t *_t2reqp;	} _u;#define	reqp	_u._reqp#define	t2reqp	_u._t2reqp#define	UZSIZE	max(sizeof (ispreq_t), sizeof (ispreqt2_t))	int i, rqidx;	XS_INITERR(xs);	isp = XS_ISP(xs);	if (isp->isp_state != ISP_RUNSTATE) {		PRINTF("%s: adapter not ready\n", isp->isp_name);		XS_SETERR(xs, HBA_BOTCH);		return (CMD_COMPLETE);	}	/*	 * We *could* do the different sequence type that has close	 * to the whole Queue Entry for the command...	 */	if (XS_CDBLEN(xs) > (IS_FC(isp) ? 16 : 12) || XS_CDBLEN(xs) == 0) {		PRINTF("%s: unsupported cdb length (%d, CDB[0]=0x%x)\n",		    isp->isp_name, XS_CDBLEN(xs), XS_CDBP(xs)[0]);		XS_SETERR(xs, HBA_BOTCH);		return (CMD_COMPLETE);	}	/*	 * Check to see whether we have good firmware state still or	 * need to refresh our port database for this target.	 */	if (IS_FC(isp)) {		fcparam *fcp = isp->isp_param;		isp_pdb_t *pdbp = &fcp->isp_pdb[XS_TGT(xs)];		/*		 * Check for f/w being in ready state. Well, okay,		 * our cached copy of it...		 */		if (fcp->isp_fwstate != FW_READY) {			if (isp_fclink_test(isp, FC_FW_READY_DELAY)) {				XS_SETERR(xs, HBA_SELTIMEOUT);				return (CMD_COMPLETE);			}		}		/*		 * Refresh our port database if needed.		 */		if (pdbp->pdb_options == INVALID_PDB_OPTIONS) {			if (isp_getpdb(isp, XS_TGT(xs), pdbp) == 0) {				isp_async(isp, ISPASYNC_PDB_CHANGE_COMPLETE,				    (void *) (long) XS_TGT(xs));			}		}	}	/*	 * Next check to see if any HBA or Device	 * parameters need to be updated.	 */	if (isp->isp_update != 0) {		isp_update(isp);	}	optr = isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4);	iptr = isp->isp_reqidx;	reqp = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr);	iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN);	if (iptr == optr) {		IDPRINTF(2, ("%s: Request Queue Overflow\n", isp->isp_name));		XS_SETERR(xs, HBA_BOTCH);		return (CMD_EAGAIN);	}	/*	 * Now see if we need to synchronize the ISP with respect to anything.	 * We do dual duty here (cough) for synchronizing for busses other	 * than which we got here to send a command to.	 */	if (isp->isp_sendmarker) {		u_int8_t niptr, n = (IS_12X0(isp)? 2: 1);		/*		 * Check ports to send markers for...		 */		for (i = 0; i < n; i++) {			if ((isp->isp_sendmarker & (1 << i)) == 0) {				continue;			}			MEMZERO((void *) reqp, sizeof (*reqp));			reqp->req_header.rqs_entry_count = 1;			reqp->req_header.rqs_entry_type = RQSTYPE_MARKER;			reqp->req_modifier = SYNC_ALL;			ISP_SBUSIFY_ISPHDR(isp, &reqp->req_header);			reqp->req_target = i << 7;			ISP_SBUSIFY_ISPREQ(isp, reqp);			/*			 * Unconditionally update the input pointer anyway.			 */			ISP_WRITE(isp, INMAILBOX4, iptr);			isp->isp_reqidx = iptr;			niptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN);			if (niptr == optr) {				IDPRINTF(2, ("%s: Request Queue Overflow+\n",				    isp->isp_name));				XS_SETERR(xs, HBA_BOTCH);				return (CMD_EAGAIN);			}			reqp = (ispreq_t *)			    ISP_QUEUE_ENTRY(isp->isp_rquest, iptr);			iptr = niptr;		}	}	MEMZERO((void *) reqp, UZSIZE);	reqp->req_header.rqs_entry_count = 1;	if (isp->isp_type & ISP_HA_FC) {		reqp->req_header.rqs_entry_type = RQSTYPE_T2RQS;	} else {		reqp->req_header.rqs_entry_type = RQSTYPE_REQUEST;	}	reqp->req_header.rqs_flags = 0;	reqp->req_header.rqs_seqno = isp->isp_seqno++;	ISP_SBUSIFY_ISPHDR(isp, &reqp->req_header);	for (rqidx = 0; rqidx < RQUEST_QUEUE_LEN; rqidx++) {		if (isp->isp_xflist[rqidx] == NULL)			break;	}	if (rqidx == RQUEST_QUEUE_LEN) {		IDPRINTF(2, ("%s: out of xflist pointers\n", isp->isp_name));		XS_SETERR(xs, HBA_BOTCH);		return (CMD_EAGAIN);	} else {		/*		 * Never have a handle that is zero, so		 * set req_handle off by one.		 */		isp->isp_xflist[rqidx] = xs;		reqp->req_handle = rqidx+1;	}	if (isp->isp_type & ISP_HA_FC) {		/*		 * See comment in isp_intr		 */		XS_RESID(xs) = 0;		/*		 * Fibre Channel always requires some kind of tag.		 * If we're marked as "Can't Tag", just do simple		 * instead of ordered tags. It's pretty clear to me		 * that we shouldn't do head of queue tagging in		 * this case.		 */		if (XS_CANTAG(xs)) {			t2reqp->req_flags = XS_KINDOF_TAG(xs);		} else {			t2reqp->req_flags = REQFLAG_STAG;		}	} else {		sdparam *sdp = (sdparam *)isp->isp_param;		if ((sdp->isp_devparam[XS_TGT(xs)].cur_dflags & DPARM_TQING) &&		    XS_CANTAG(xs)) {			reqp->req_flags = XS_KINDOF_TAG(xs);		} else {			reqp->req_flags = 0;		}	}	reqp->req_target = XS_TGT(xs) | (XS_CHANNEL(xs) << 7);	if (isp->isp_type & ISP_HA_SCSI) {		reqp->req_lun_trn = XS_LUN(xs);		reqp->req_cdblen = XS_CDBLEN(xs);	} else {#ifdef	ISP2100_SCCLUN		reqp->req_scclun = XS_LUN(xs);#else		reqp->req_lun_trn = XS_LUN(xs);#endif	}	MEMCPY(reqp->req_cdb, XS_CDBP(xs), XS_CDBLEN(xs));	IDPRINTF(5, ("%s(%d.%d.%d): START%d cmd 0x%x datalen %d\n",	    isp->isp_name, XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs),	    reqp->req_header.rqs_seqno, reqp->req_cdb[0], XS_XFRLEN(xs)));	reqp->req_time = XS_TIME(xs) / 1000;	if (reqp->req_time == 0 && XS_TIME(xs))		reqp->req_time = 1;	/*	 * Always give a bit more leeway to commands after a bus reset.	 * XXX: DOES NOT DISTINGUISH WHICH PORT MAY HAVE BEEN SYNCED	 */	if (isp->isp_sendmarker && reqp->req_time < 5)		reqp->req_time = 5;	i = ISP_DMASETUP(isp, xs, reqp, &iptr, optr);	if (i != CMD_QUEUED) {		/*		 * Take memory of it away...		 */		isp->isp_xflist[rqidx] = NULL;		/*		 * dmasetup sets actual error in packet, and		 * return what we were given to return.		 */		return (i);	}	XS_SETERR(xs, HBA_NOERROR);	ISP_SBUSIFY_ISPREQ(isp, reqp);	MemoryBarrier();	ISP_WRITE(isp, INMAILBOX4, iptr);	isp->isp_reqidx = iptr;	isp->isp_nactive++;	if (isp->isp_sendmarker)		isp->isp_sendmarker = 0;	return (CMD_QUEUED);#undef	reqp#undef	t2reqp}/* * isp control * Locks (ints blocked) assumed held. */intisp_control(isp, ctl, arg)	struct ispsoftc *isp;	ispctl_t ctl;	void *arg;{	ISP_SCSI_XFER_T *xs;	mbreg_t mbs;	int i, bus, tgt;	switch (ctl) {	default:		PRINTF("%s: isp_control unknown control op %x\n",		    isp->isp_name, ctl);		break;	case ISPCTL_RESET_BUS:		/*		 * Issue a bus reset.		 */		mbs.param[0] = MBOX_BUS_RESET;		if (isp->isp_type & ISP_HA_SCSI) {			mbs.param[1] =			    ((sdparam *) isp->isp_param)->isp_bus_reset_delay;			if (mbs.param[1] < 2)				mbs.param[1] = 2;		} else {			/*			 * Unparameterized.			 */			mbs.param[1] = 5;		}		bus = *((int *) arg);		mbs.param[2] = bus;		isp->isp_sendmarker = 1 << bus;		isp_mboxcmd(isp, &mbs);		if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {			isp_dumpregs(isp, "isp_control SCSI bus reset failed");			break;		}		PRINTF("%s: driver initiated bus reset of bus %d\n",		    isp->isp_name, bus);		return (0);	case ISPCTL_RESET_DEV:		tgt = (*((int *) arg)) & 0xffff;		bus = (*((int *) arg)) >> 16;		mbs.param[0] = MBOX_ABORT_TARGET;		mbs.param[1] = (tgt << 8) | (bus << 15);		mbs.param[2] = 3;	/* 'delay', in seconds */		isp_mboxcmd(isp, &mbs);		if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {			isp_dumpregs(isp, "Target Reset Failed");			break;

⌨️ 快捷键说明

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