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

📄 ncr.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			 *			 * ncr_dopoll will return when ncr->n_state ==			 * STATE_FREE, but this can also mean a reselection			 * preempt occurred.			 */			PRINTF3("ncr_start: poll_res\n");			if (ncr_dopoll(ncr)) {				(void) splx(s);				return (FALSE);			}		}		PRINTF3("ncr_start: start next slot= %x\n", NEXTSLOT(slot));		(void) ncr_ustart(ncr, NEXTSLOT(slot));	}	(void) splx(s);	PRINTF3("ncr_start: done\n");	return (TRUE);}/*ARGSUSED*/static intncr_abort(ap, pkt)struct scsi_address *ap;struct scsi_pkt *pkt;{	PRINTF3("ncr_abort: pkt= %x\n", pkt);	if (pkt != (struct scsi_pkt *) 0) {	    PRINTF3("ncr_abort: call ncr_do_abort(RESET)\n");	    ncr_do_abort((struct ncr *)ap->a_cookie,		NCR_RESET_ALL, RESET_NOMSG);	    return (TRUE);	} else {	    return (FALSE);	}}static intncr_reset(ap, level)		/* clear jobs & reset H/W for external-req */struct scsi_address *ap;int level;{	struct ncr *ncr = (struct ncr *) ap->a_cookie;	PRINTF3("ncr_reset: level= %x\n", level);	/*	 * if RESET_ALL requested, call "ncr_do_abort()" to clear all	 * outstanding jobs in the queue	 */	if (level == RESET_ALL) {		ncr_do_abort(ncr, NCR_RESET_ALL, RESET_NOMSG);		return (TRUE);	} else		return (FALSE);}/*ARGSUSED*/static intncr_getcap(ap, cap)		/* return host-adapter's capabilities */struct scsi_address *ap;char *cap;{	PRINTF3("ncr_getcap:\n");	/*	 * Check requested function (such as "dma_max, msg_out, sync,	 * disconnect, parity, and Ids) support on the behave of	 * host_adapter H/W platfrom and S/W driver	 */	if (cap == (char *) 0)		return (UNDEFINED);	else if (strncmp("dma_max", cap, 7) == 0)		return (1<<16);	else if (strncmp("msg_out", cap, 7) == 0)		return (TRUE);		/* 1 */	else if (strncmp("disconnect", cap, 10) == 0)		return (TRUE);		/* 1 */	else if (strncmp("synchronous", cap, 11) == 0)		return (FALSE);		/* 0 */	else if (strncmp("parity", cap, 6) == 0)		return (FALSE);	else if (strncmp("initiator-id", cap, 12) == 0) {		struct ncr *ncr = (struct ncr *) ap->a_cookie;		return (ncr->n_id);	} else		return (UNDEFINED);}/*ARGSUSED*/static intncr_setcap(ap, cap, value)	/* set host-adapter actions per request */struct scsi_address *ap;char *cap;int value;{	PRINTF3("ncr_setcap: val= %x\n", value);	/* set host_adapter driver's action based on inputted request */	return (UNDEFINED);}/* * Internal start and finish routines *//* * Start the next command on the host adapter. * Search from start_slot for work to do. * * *	input:  (struct ncr) *ncr= pointer to a ncr software structure; *		(short) start_slot= requested slot (target/lun combo); *	return: (int) TRUE(1)= command started okay; *		(int) FALSE(0)= not started (due to reselection or no work) */static intncr_ustart(ncr, start_slot)register struct ncr *ncr;short start_slot;{	register struct scsi_cmd *sp;	register short slot = start_slot;	int found = 0;	int i;	char dkn;	PRINTF3("ncr_ustart: start_slot= %x\n", start_slot);	/*	 * Start off a new job in the queue ONLY number of running cmds	 * is less than disconnected cmds, in hope of NOT floating the bus	 * and allow the previously disconnected jobs to be finished first,	 * if more currently disconnected jobs, return ACTION_ABORT	 *	 * XXX: mjacob sez that this doesn't make him happy	 */	if ((ncr->n_ncmds - ncr->n_ndisc) <= 0) {		PRINTF3("ncr_ustart: NO new-job\n");		return (FALSE);	}	/*	 * search for any ready cmd available (started first with the req	 * slot, then move to next slot until reaching req_one)	 */	do {		sp = ncr->n_slots[slot];		if (sp && ((sp->cmd_flags & CFLAG_CMDDISC) == 0)) {			found++;		} else {			slot = NEXTSLOT(slot);		}	} while ((found == 0) && (slot != start_slot));	if (!found) {		return (FALSE);	}	UPDATE_STATE(STATE_STARTING);	PRINTF3("ncr_ustart: starting %d.%d\n", Tgt(sp), Lun(sp));	ncr->n_cur_slot = slot;	ncr->n_omsgidx = ncr->n_omsglen = 0;	/*	 * Attempt to arbitrate for the bus and select the target.	 *	 * ncr_select() can return one of SEL_TRUE (target selected),	 * SEL_ARBFAIL (unable to get the bus), SEL_FALSE (target did	 * not respond to selection), or SEL_RESEL (a reselection attempt	 * is in progress). As a side effect, if SEL_TRUE is the return,	 * DMA (and interrupts) from the SBC are disabled.	 *	 */	switch (ncr_select(ncr)) {	case SEL_ARBFAIL:		/*		 * XXX: Should we treat arbitration failures		 * XXX: differently than selection failures?		 */	case SEL_FALSE:		(void) ncr_finish(ncr);		return (FALSE);	case SEL_TRUE:		if ((sp->cmd_flags & CFLAG_DMAVALID) &&		    (dkn = sp->cmd_pkt.pkt_pmon) >= 0) {			dk_busy |= (1<<dkn);			dk_xfer[dkn]++;			if ((sp->cmd_flags & CFLAG_DMASEND) == 0)				dk_read[dkn]++;			dk_wds[dkn] += sp->cmd_dmacount >> 6;		}		UPDATE_STATE(ACTS_UNKNOWN);		if (NON_INTR(sp))			ncr_phasemanage(ncr);		return (TRUE);	case SEL_RESEL:		/*		 * Couldn't select due to a reselection coming in.		 * Push the state of this command back to what it was.		 */		ncr_preempt(ncr);		return (FALSE);	}}/* * Finish routine */static voidncr_finish(ncr)register struct ncr *ncr;{	short last_slot;	register int span_states = 0;	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	char dkn;	PRINTF3("ncr_finish:\n");	if ((dkn = sp->cmd_pkt.pkt_pmon) >= 0) {		dk_busy &= ~(1<<dkn);	}	if (ncr->n_last_msgin == MSG_LINK_CMPLT ||		ncr->n_last_msgin == MSG_LINK_CMPLT_FLAG) {		span_states++;	}	if (sp->cmd_pkt.pkt_state & STATE_XFERRED_DATA) {		register struct dataseg *segtmp = sp->cmd_subseg.d_next;		register i;		/*		 * XXX : FIX ME NEED TO MERGE TOGETHER OVERLAPPING AND		 * XXX : ADJACENT SEGMENTS!!!		 */		if (segtmp != (struct dataseg *) 0 && segtmp->d_count) {			panic("ncr_finish: more than one segment with data");			/* NOTREACHED */		}		/*		 * Walk through all data segments and count up transfer counts		 */		i = 0;		for (segtmp = &sp->cmd_subseg; segtmp;		    segtmp = segtmp->d_next) {			i += segtmp->d_count;		}		sp->cmd_pkt.pkt_resid = sp->cmd_dmacount - i;		if (INFORMATIVE && sp->cmd_pkt.pkt_resid) {			PRINTF2("ncr_finish: %d.%d finishes with %d resid\n",				Tgt(sp), Lun(sp), sp->cmd_pkt.pkt_resid);		}	}	ncr->n_ncmds -= 1;	last_slot = ncr->n_last_slot = ncr->n_cur_slot;	ncr->n_lastcount = 0;	ncr->n_cur_slot = UNDEFINED;	ncr->n_slots[last_slot] = (struct scsi_cmd *) 0;	ncr->n_omsglen = ncr->n_omsgidx = 0;	ncr->n_last_msgin = 0xfe;	UPDATE_STATE(STATE_FREE);	PRINTF3("ncr_finish: span= %x, flag= %x\n",		span_states, sp->cmd_pkt.pkt_flags);	if (NON_INTR(sp)) {		PRINTF3("ncr_finish: poll= calling upper target to finish\n");		ncr->n_npolling -= 1;		(*sp->cmd_pkt.pkt_comp)(sp);	} else if (span_states > 0) {		ncr->n_state = ACTS_SPANNING;		(*sp->cmd_pkt.pkt_comp)(sp);		/*		 * This is we can check upon return that		 * the target driver did the right thing...		 *		 * If the target driver didn't do the right		 * thing, we have to abort the operation.		 */		if (ncr->n_slots[last_slot] == 0) {			ncr_internal_abort(ncr);		} else {			PRINTF2("%s%d: linked command start\n", CNAME, CNUM);			ncr->n_cur_slot = last_slot;			ncr->n_nlinked++;			if (ncr_ACKmsg(ncr)) {				ncr_do_abort(ncr, NCR_RESET_ALL, RESET_NOMSG);			} else {				sp = CURRENT_CMD(ncr);				if ((sp->cmd_flags & CFLAG_DMAVALID) &&				    (dkn = sp->cmd_pkt.pkt_pmon) >= 0) {					dk_busy |= (1<<dkn);					dk_xfer[dkn]++;					if (!(sp->cmd_flags & CFLAG_DMASEND))					dk_read[dkn]++;					dk_wds[dkn] += sp->cmd_dmacount >> 6;				}				UPDATE_STATE(ACTS_UNKNOWN);				ncr_phasemanage(ncr);			}		}	} else {		(*sp->cmd_pkt.pkt_comp)(sp);		if (ncr->n_state == STATE_FREE) {			(void) ncr_ustart(ncr, last_slot);		}	}}/* * Interrupt Service Routines *//* * polled service routine - called when interrupts are not feasible * * Note that we call ncrpoll() rather than ncrsvc directly. This is * so we can service other ncr controllers while we're polling this * one. */static intncr_dopoll(ncr)register struct ncr *ncr;{	register int i;	PRINTF3("ncr_dopoll: state= %x\n", ncr->n_state);	while (ncr->n_state != STATE_FREE) {	    PRINTF3("ncr_dopoll: n_state= %x\n", ncr->n_state);	    for (i = 0; (i < 3*120000) && (ncr->n_state != STATE_FREE); i++) {		if (ncrpoll()) {	/* 1 is Okay */			if (ncr->n_state == STATE_FREE)				continue;			else				i = 0;		} else {			DELAY(100);		}		if (i >= 3*120000 && ncr->n_state != STATE_FREE) {			EPRINTF("ncr_dopoll: poll_cmd timeout, state= %x\n",				ncr->n_state);			return (FAILURE);		}	    }	}	return (SUCCESS);}/* * polled (autovector) interrupt entry point */static intncrpoll(){	register struct ncr *ncr;	int serviced = 0;	for (ncr = ncr_softc; ncr < &ncr_softc[NNCR]; ncr++) {		if (ncrctlr[ncr-ncr_softc]) {			ncr->n_ints++;			while (INTPENDING(ncr)) {				ncrsvc(ncr);				serviced = 1;			}		}	}	return (serviced);}/* * vectored interrupt entry point(s) */voidncrintr(ncr)struct ncr *ncr;{	if (ncrctlr[CNUM]) {		ncr->n_ints++;		while (INTPENDING(ncr)) {			ncrsvc(ncr);		}	} else {		printf("%s%d: spurious vectored interrupt\n", CNAME, CNUM);	}}/* * Common interrupt service code- called asynchronously from ncrpoll() or * ncrintr(), or synchronously from varying places in the rest of the * driver to service interrupts. * * What kind of interrupts we'll get: * *	* RESELECTION interrupts *	* End of DATA PHASE interrupts (PHASE MISMATCH) *	* Some specific PHASE MISMATCH interrupts (driven by *	  enabling DMA mode in the sbc mr register after setting *	  a bogus phase into the tcr register- when REQ* is asserted *	  this causes a phase mismatch interrupt. * * XXX:	* Monitor LOSS OF BUSY interrupts * XXX:	* PARITY Errors */static voidncrsvc(ncr)register struct ncr *ncr;{	register u_char binary_id = NUM_TO_BIT(ncr->n_id);	register u_char uctmp;	/*	 * 'Disabling' DMA also allows access to SBC registers	 */	if (ncr->n_type != IS_3_50)		DISABLE_DMA(ncr);	uctmp = N_SBC->cbsr;	if (ncr->n_type != IS_COBRA && ncr->n_type != IS_3E) {		ncr->n_lastbcr = GET_BCR(ncr);	}	/*	 * First check for a reselect interrupt coming in	 */	if (RESELECTING(uctmp, N_SBC->cdr, binary_id)) {		if (ncr_reselect(ncr)) {			uctmp = 0;			ncr_do_abort(ncr, NCR_RESET_ALL, RESET_NOMSG);		} else {			uctmp = 1;		}	} else if (IN_DATA_STATE(ncr)) {		/*		 * XXX: should be able to return and await another REQ*		 * XXX: here? Probably wouldn't help because interrupt		 * XXX: latency + dma cleanup generally will give the		 * XXX: targets time to shift to status and/or msg in		 * XXX: phase.		 */		if ((*ncr->n_dma_cleanup)(ncr)) {			ncr_do_abort(ncr, NCR_RESET_ALL, RESET_NOMSG);			uctmp = 0;		} else {			uctmp = 1;		}	} else if (ncr->n_state == STATE_FREE) {		if (ncr_debug) {			printf("%s%d: spurious interrupt\n", CNAME, CNUM);			ncr_printstate(ncr);		}		uctmp = N_SBC->clr;		ncr->n_spurint++;		uctmp = 0;	} else {		switch (ncr->n_laststate) {		case STATE_SELECTED:			ncr->n_pmints[PM_SEL]++;			break;		case ACTS_MSG_IN:			ncr->n_pmints[PM_MSGIN]++;			break;		case ACTS_MSG_OUT:			ncr->n_pmints[PM_MSGOUT]++;			break;		case ACTS_STATUS:			ncr->n_pmints[PM_STATUS]++;			break;		case ACTS_COMMAND:			ncr->n_pmints[PM_CMD]++;			break;		}		/*		 * dismiss cause of interrupt		 */		N_SBC->mr &= ~NCR_MR_DMA;		uctmp = N_SBC->clr;		uctmp = 1;	}	if (uctmp) {		if (ncr->n_state != ACTS_UNKNOWN) {			UPDATE_STATE(ACTS_UNKNOWN);		}		ncr_phasemanage(ncr);	}	/*	 * Enabling dma also enables SBC interrupts	 */	if (ncr->n_type != IS_3_50)		ENABLE_DMA(ncr);}/* * Complete reselection */static intncr_reselect(ncr)register struct ncr *ncr;{	struct scsi_cmd *sp;	register s, target, lun;	register u_char cdr;	short slot;	u_char msgin, binary_id = NUM_TO_BIT(ncr->n_id);	if (ncr->n_ndisc == 0) {		printf("%s%d: reselection with no disconnected jobs\n",			CNAME, CNUM);		return (FAILURE);	} else if (ncr->n_state != STATE_FREE) {		printf("%s%d: reselection while not in free state\n",			CNAME, CNUM);		return (FAILURE);	}	/*	 * CRITICAL CODE SECTION DON'T TOUCH	 */	s = splhigh();	cdr = N_SBC->clr;	/* clear int */	/*	 * get reselecting target scsi id	 */	cdr = N_SBC->cdr & ~binary_id;	/*	 * make sure there are only 2 scsi id's set	 */	for (target = 0; target < 8; target++) {		if (cdr & (1 << target))			break;	}	N_SBC->ser = 0; 	/* clear (re)sel int */	cdr &= ~(1 << target);	if (cdr != 0) {		(void) splx(s);		printf("%s%d: reselection w > 2 SCSI ids on the bus\n",			CNAME, CNUM);		return (FAILURE);	}	/*	 * Respond to reselection by asserting BSY*	 */	N_SBC->icr |= NCR_ICR_BUSY;	(void) splx(s);	/*	 * If reselection ok, target should drop select	 */	if (ncr_sbcwait(&CBSR, NCR_CBSR_SEL, NCR_WAIT_COUNT, 0)) {		printf("%s%d: target didn't drop select on reselection\n",			CNAME, CNUM);

⌨️ 快捷键说明

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