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

📄 ncr.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		return (FAILURE);	}	/*	 * We respond by dropping our assertion of BSY*	 */	N_SBC->icr &= ~NCR_ICR_BUSY;	N_SBC->tcr = TCR_UNSPECIFIED;	N_SBC->ser = 0;	/* clear int */	N_SBC->ser = binary_id; /* enable (re)sel int */	UPDATE_STATE(STATE_RESELECT);	if (ncr_getphase(ncr) != ACTION_CONTINUE) {		printf("%s%d: no REQ during reselect\n", CNAME, CNUM);		return (FAILURE);	}	if (ncr->n_state != ACTS_MSG_IN) {		printf("%s%d: reselect not followed by a MSG IN phase\n",			CNAME, CNUM);		return (FAILURE);	}	/*	 * Now pick up identify message byte, and acknowledge it.	 */	if (ncr_xfrin_noack(ncr, PHASE_MSG_IN, &msgin)) {		printf("%s%d: can't get IDENTIFY message on reselect\n",			CNAME, CNUM);		return (FAILURE);	}	if ((msgin & MSG_IDENTIFY) == 0 ||	    (msgin & (INI_CAN_DISCON|BAD_IDENTIFY))) {		printf("%s%d: mangled identify message 0x%x\n", msgin);		return (FAILURE);	}	lun = msgin & (NLUNS_PER_TARGET-1);	/*	 * now search for lun to reconnect to	 */	lun &= (NLUNS_PER_TARGET-1);	slot = (target * NLUNS_PER_TARGET) | lun;	if (ncr->n_slots[slot] == 0) {		printf("%s%d: Cannot Reconnect Lun %d on Target %d\n",			CNAME, CNUM, lun, target);		return (FAILURE);	}	ncr->n_cur_slot = slot;	ncr->n_ndisc--;	sp = CURRENT_CMD(ncr);	/*	 * A reconnect implies a restore pointers operation	 */	sp->cmd_cdbp = sp->cmd_pkt.pkt_cdbp;	sp->cmd_scbp = sp->cmd_pkt.pkt_scbp;	sp->cmd_data = sp->cmd_saved_data;	sp->cmd_flags &= ~CFLAG_CMDDISC;	/*	 * and finally acknowledge the identify message	 */	ncr->n_last_msgin = msgin;	UPDATE_STATE(ACTS_RESELECTING);	if (ncr_ACKmsg(ncr)) {		printf("%s%d: unable to acknowledge identify message\n",			CNAME, CNUM);		return (FAILURE);	}	return (SUCCESS);}/* * State Management Section *//* * manage phases on the SCSI bus * * We assume (on entry) that we are connected to a * target and that CURRENT_CMD(ncr) is valid. We * also assume that the phase is unknown. We continue * calling one of a set of phase management routines * until we either are going to return (to ncrsvc * or ncr_ustart()), or have to abort the command, * or are going to call ncr_finish() (to complete * this command), or are going to turn aroung and * call ncr_ustart() again to start another command. * */static voidncr_phasemanage(ncr)register struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	register int i, action;	/*	 * Important: The order of functions in this array *must* match	 * the defines in ncrreg.h with respect to the linear sequence	 * of states from ACTS_UNKNOWN thru ACTS_COMMAND.	 */	static int (*itvec[])() = {		ncr_getphase,		ncr_sendmsg,		ncr_recvmsg,		ncr_recvstatus,		ncr_sendcmd,		ncr_recvdata,		ncr_senddata	};	static char *itnames[] = {		"unknown", "msg out", "msg in", "status",		"cmd", "data in", "data out"	};	action = ACTION_CONTINUE;	do {		i = ncr->n_state - ACTS_ITPHASE_BASE;		PRINTF3("ncr_phasemanage: state = %s\n", itnames[i]);		action = (*itvec[i])(ncr);	} while (action == ACTION_CONTINUE);	switch (action) {	case ACTION_RETURN:		break;	case ACTION_ABORT:		ncr_do_abort(ncr, NCR_RESET_ALL, RESET_NOMSG);		break;	case ACTION_FINISH:		ncr_finish(ncr);		break;	case ACTION_SEARCH:		ncr_disconnect(ncr);		break;	}}static intncr_getphase(ncr)register struct ncr *ncr;{	register u_char cbsr;	register int lim, phase;	u_long usecs = 0;	static char phasetab[8] = {		ACTS_DATA_OUT,		ACTS_DATA_IN,		ACTS_COMMAND,		ACTS_STATUS,		-1,	/* 4 is undefined */		-1,	/* 5 is undefined */		ACTS_MSG_OUT,		ACTS_MSG_IN	};	usecs = 10000000;	for (lim = 0; lim < usecs; lim++) {		cbsr = N_SBC->cbsr;		if ((cbsr & NCR_CBSR_BSY) == 0) {			/*			 * Unexpected loss of busy!			 */			printf("%s%d: target dropped BSY*\n", CNAME, CNUM);			ncr_printstate(ncr);			return (ACTION_ABORT);		} else if ((cbsr & NCR_CBSR_REQ) == 0) {			/*			 * If REQ* is not asserted, than the phase bits			 * are not valid. Delay a few u-secs before checking			 * again..			 */			DELAY(2);			continue;		}		phase = (cbsr >> 2) & 0x7;		PRINTF3("ncr_getphase: phase= 0x%x\n", phase);		if (phasetab[phase] == -1) {			printf("%s%d: garbage phase. CBSR = 0x%b\n",				CNAME, CNUM, cbsr, cbsr_bits);			return (ACTION_ABORT);		}		/*		 * Note that if the phase is a data phase, we don't attempt		 * to match it. We leave that action to the discretion of the		 * dma routines.		 */		if (phase > 1 && (N_SBC->bsr & NCR_BSR_PMTCH) == 0) {			N_SBC->tcr = phase;		}		UPDATE_STATE(phasetab[phase]);		return (ACTION_CONTINUE);	}	printf("%s%d: REQ* never set\n", CNAME, CNUM);	return (ACTION_ABORT);}/* * Send command bytes out the SCSI bus. REQ* should be asserted for us * to get here, and the phase should already be matched in the tcr register * (i.e., ncr_getphase() has done the right thing for us already). * * If this is a non-interrupting command, we should actually be able to * set up for a phase-mismatch interrupt after sending the command. * */static intncr_sendcmd(ncr)register struct ncr *ncr;{	register u_char junk;	register struct ncrsbc *sbc = N_SBC;	register int s, nonintr;	struct scsi_cmd *sp = CURRENT_CMD(ncr);	nonintr = (NON_INTR(sp) ? 1: 0);	/*	 * We send a single byte of a command out here.	 * We could probably check to see whether REQ* is	 * asserted quickly again here, rather than awaiting	 * it in ncr_getphase() (for non-interrupting commands)	 * or spotting it in either ncrpoll() or ncrintr().	 *	 * XXX: We should check for command overflow here!	 */	sbc->odr = *(sp->cmd_cdbp++);	/* load data */	sbc->icr = NCR_ICR_DATA;	/* enable sbc to send data */	/*	 * complete req/ack handshake	 */	s = splhigh();	sbc->icr |= NCR_ICR_ACK;	sbc->tcr = TCR_UNSPECIFIED;	(void) splx(s);	if (!REQ_DROPPED(ncr)) {		EPRINTF("ncr_sendcmd: REQ not dropped, cbsr=0x%b\n",			CBSR, cbsr_bits);		sbc->icr = 0;		return (ACTION_ABORT);	}	if (nonintr == 0) {		sbc->mr |= NCR_MR_DMA;		junk = sbc->clr;	}	sbc->icr = 0;	/* clear ack */	sp->cmd_pkt.pkt_state |= STATE_SENT_CMD;	UPDATE_STATE(ACTS_UNKNOWN);	if (nonintr) {		return (ACTION_CONTINUE);	} else {		if (ncr->n_type != IS_3_50)			ENABLE_DMA(ncr);		return (ACTION_RETURN);	}}/* * Send out a message. We assume on entry that phase is matched in the tcr * register of the SBC, and that REQ* has been asserted by the target (i.e., * ncr_getphase() has done the right thing). * * If this is a non-interrupting command, set up to get a phase-mismatch * interrupt on the next assertion of REQ* by the target. * */static intncr_sendmsg(ncr)register struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	register struct ncrsbc *sbc = N_SBC;	u_char junk;	register s, nonintr;	nonintr = (NON_INTR(sp) ? 1: 0);	if (ncr->n_omsglen == 0 || ncr->n_omsgidx >= ncr->n_omsglen) {		/*		 * No message to send or previous message exhausted.		 * Send a NO-OP message instead.		 */		printf("%s%d: unexpected message out phase for target %d\n",			CNAME, CNUM, Tgt(sp));		ncr->n_omsglen = 1;		ncr->n_omsgidx = 0;		ncr->n_cur_msgout[0] = MSG_NOP;	}	if (ncr->n_omsgidx == 0) {		ncr->n_last_msgout = ncr->n_cur_msgout[0];	}	/*	 * load data	 */	PRINTF3("ncr_sendmsg: sending msg byte %d = 0x%x of %d len msg\n",		ncr->n_omsgidx, ncr->n_cur_msgout[ncr->n_omsgidx],		ncr->n_omsglen);	sbc->odr = ncr->n_cur_msgout[ncr->n_omsgidx++];	sbc->icr |= NCR_ICR_DATA;	if (ncr->n_omsgidx >= ncr->n_omsglen) {		ncr->n_omsgidx = ncr->n_omsglen = 0;		sbc->icr &= ~NCR_ICR_ATN;	}	/*	 * complete req/ack handshake	 */	s = splhigh();	sbc->icr |= NCR_ICR_ACK;	sbc->tcr = TCR_UNSPECIFIED;	(void) splx(s);	if (!REQ_DROPPED(ncr)) {		sbc->icr = 0;		return (ACTION_ABORT);	}	if (nonintr == 0) {		sbc->mr |= NCR_MR_DMA;		junk = sbc->clr;	}	/*	 * Deassert ACK*. Note that this uses a mask-equal-not instead of	 * a straight clear because we may wish to leave ATN* asserted.	 */	junk = sbc->icr & (NCR_ICR_ACK|NCR_ICR_DATA|NCR_ICR_ATN);	junk &= ~(NCR_ICR_ACK|NCR_ICR_DATA);	sbc->icr = junk;	UPDATE_STATE(ACTS_UNKNOWN);	if (nonintr) {		return (ACTION_CONTINUE);	} else {		if (ncr->n_type != IS_3_50)			ENABLE_DMA(ncr);		return (ACTION_RETURN);	}}static intncr_recvmsg(ncr)register struct ncr *ncr;{	auto u_char msgin;	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	static char *messages[] = {		"Command Complete",		"Extended Message",		"Save Data Pointer",		"Restore Pointers",		"Disconnect",		"Initiator Detected Error",		"Abort",		"No-op",		"Message Reject",		"Message Parity Error",		"Linked Command Complete",		"Linked Command Complete (w/flag)",		"Bus Device Reset"	};	/*	 * Pick up a message byte from the SCSI bus. Delay giving an ack	 * until we know if we can handle this message- that way we can	 * assert the ATN line before the ACK so that the target knows we are	 * gonna reject this message.	 */	if (ncr_xfrin_noack(ncr, PHASE_MSG_IN, &msgin)) {		return (ACTION_ABORT);	} else		ncr->n_last_msgin = msgin;	if (msgin & MSG_IDENTIFY) {		/*		 * We shouldn't be getting an identify message here.		 */		printf("%s%d: out of sequence identify message: 0x%x\n",			CNAME, CNUM, msgin);		if (ncr_ACKmsg(ncr)) {			return (ACTION_ABORT);		}		UPDATE_STATE(ACTS_UNKNOWN);		return (ACTION_CONTINUE);	}	if (ncr_debug > 2) {		if (msgin <= MSG_DEVICE_RESET) {			printf("%s%d: msg=%s\n", CNAME, CNUM, messages[msgin]);		} else {			printf("%s%d: msg=0x%x\n", CNAME, CNUM, msgin);		}	}	switch (msgin) {	case MSG_DISCONNECT:		/*		 * Important! Set state *before calling ncr_ACKmsg()		 * because ncr_ACKmsg() bases some actions on the		 * new state!		 */		UPDATE_STATE(ACTS_CLEARING_DISC);		if (ncr_ACKmsg(ncr)) {			return (ACTION_ABORT);		}		return (ACTION_SEARCH);	case MSG_LINK_CMPLT:	case MSG_LINK_CMPLT_FLAG:	case MSG_COMMAND_COMPLETE:	{		/*		 * Note well that we *do NOT* ACK the message if it		 * is a LINKED COMMAND COMPLETE or LINKED COMMAND		 * COMPLETE (with flag) message. We leave that for		 * ncr_finish() to do once the target driver has		 * given us the next command to send. This is so		 * that the DMA engine can be set up for the new		 * command prior to ACKing this message.		 */		/*		 * Important! Set state *before calling ncr_ACKmsg()		 * because ncr_ACKmsg() bases some actions on the		 * new state!		 */		sp->cmd_pkt.pkt_reason = CMD_CMPLT;		if (msgin == MSG_COMMAND_COMPLETE) {			UPDATE_STATE(ACTS_CLEARING_DONE);			if (ncr_ACKmsg(ncr)) {				return (ACTION_ABORT);			}		} else {			UPDATE_STATE(ACTS_UNKNOWN);		}		return (ACTION_FINISH);	}	case MSG_SAVE_DATA_PTR:		sp->cmd_saved_data = (int) sp->cmd_data;		break;	case MSG_RESTORE_PTRS:		sp->cmd_cdbp = sp->cmd_pkt.pkt_cdbp;		sp->cmd_scbp = sp->cmd_pkt.pkt_scbp;		if (sp->cmd_data != sp->cmd_saved_data) {			sp->cmd_data = sp->cmd_saved_data;			sp->cmd_flags |= CFLAG_NEEDSEG;			PRINTF3("%s%d: %d.%d needs new data segment\n",				CNAME, CNUM, Tgt(sp), Lun(sp));		}		break;	case MSG_NOP:		break;	default:		if (ncr_NACKmsg(ncr)) {			return (ACTION_ABORT);		}		UPDATE_STATE(ACTS_UNKNOWN);		return (ACTION_CONTINUE);	}	if (ncr_ACKmsg(ncr)) {		return (ACTION_ABORT);	}	UPDATE_STATE(ACTS_UNKNOWN);	return (ACTION_CONTINUE);}/* * Enable DMA. If this is a non-interrupting command, await for DMA completion. */static intncr_senddata(ncr)register struct ncr *ncr;{	struct scsi_cmd *sp = CURRENT_CMD(ncr);	register int reqamt;	reqamt = ncr->n_lastcount;	PRINTF3("ncr_senddata:\n", reqamt);	if ((sp->cmd_flags & CFLAG_DMASEND) == 0) {		printf("%s%d: unwanted data out phase\n", CNAME, CNUM);		return (ACTION_ABORT);	}	if (reqamt == -1) {		/*		 * XXXX		 */		printf("%s%d: odd byte dma send\n", CNAME, CNUM);		return (ACTION_ABORT);	}	if (reqamt == 0) {		ncr_dump_datasegs(sp);		panic("ncr_senddata: no data to send\n");	}	ncr_dma_enable(ncr, 0);	/* 0 = send */	if (NON_INTR(sp)) {		if (ncr_dma_wait(ncr)) {			printf("%s%d: wait for dma timed out\n", CNAME, CNUM);			return (ACTION_ABORT);		}		sp->cmd_pkt.pkt_state |= STATE_XFERRED_DATA;		UPDATE_STATE(ACTS_UNKNOWN);		return (ACTION_CONTINUE);	} else {		return (ACTION_RETURN);	}}/* * Enable DMA. If this is a non-interrupting command, await for DMA completion. */static intncr_recvdata(ncr)register struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	register reqamt;	if (sp->cmd_flags & CFLAG_DMASEND) {		printf("%s%d: unwanted data in phase\n", CNAME, CNUM);		return (ACTION_ABORT);	}	reqamt = ncr->n_lastcount;	if (reqamt == -1) {		/*		 * XXXX		 */		printf("%s%d: odd byte dma send\n", CNAME, CNUM);		return (ACTION_ABORT);	}	if (reqamt == 0) {		panic("ncr_rcvdata: no place to put data");		/* NOTREACHED */	}	ncr_dma_enable(ncr, 1);	/* 1 = recv */	if (NON_INTR(sp)) {		if (ncr_dma_wait(ncr)) {			printf("%s%d: wait for dma timed out\n", CNAME, CNUM);			return (ACTION_ABORT);		}		sp->cmd_pkt.pkt_state |= STATE_XFERRED_DATA;		UPDATE_STATE(ACTS_UNKNOWN);

⌨️ 快捷键说明

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