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

📄 ncr.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		return (ACTION_CONTINUE);	} else {		return (ACTION_RETURN);	}}static intncr_recvstatus(ncr)register struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	register int amt, maxsb, action;	maxsb = (((u_int) sp->cmd_pkt.pkt_scbp) + sp->cmd_scblen) -		((u_int) sp->cmd_scbp);	if (maxsb <= 0) {		printf("%s%d: status overrun\n", CNAME, CNUM);		/*		 * XXX: reset bus		 */		sp->cmd_pkt.pkt_reason = CMD_STS_OVR;		return (ACTION_FINISH);	}	if (NON_INTR(sp)) {		amt = ncr_xfrin(ncr, PHASE_STATUS, sp->cmd_scbp, maxsb);		if (amt <= 0) {			return (ACTION_ABORT);		}		PRINTF3("ncr_recvstatus: status= %x\n", *sp->cmd_scbp);		sp->cmd_scbp += amt;		UPDATE_STATE(ACTS_UNKNOWN);		action = ACTION_CONTINUE;	} else {		if (ncr_xfrin_noack(ncr, PHASE_STATUS, sp->cmd_scbp)) {			return (ACTION_ABORT);		}		PRINTF3("ncr_recvstatus: status= %x\n", *sp->cmd_scbp);		sp->cmd_scbp += amt;		N_SBC->tcr = TCR_UNSPECIFIED;		amt = N_SBC->clr;		N_SBC->icr |= NCR_ICR_ACK;		if (!REQ_DROPPED(ncr)) {			return (ACTION_ABORT);		}		N_SBC->mr |= NCR_MR_DMA;		N_SBC->icr = 0;		if (ncr->n_type != IS_3_50)			ENABLE_DMA(ncr);		action = ACTION_RETURN;	}	UPDATE_STATE(ACTS_UNKNOWN);	return (action);}/* * Utility Functions *//* * Perform Arbitration and SCSI selection * *	input:  (struct ncr) *ncr= pointer to a ncr software structure; *	return: (int) SEL_TRUE		= target arb/selected successful; *		(int) SEL_ARBFAIL	= Arbitration failed (bus busy) *		(int) SEL_FALSE		= selection timed out *		(int) SEL_RESEL		= Reselection attempt underway *//* local defines */#define	WON_ARB	(((sbc->icr & NCR_ICR_LA) == 0) && ((CDR & ~binid) < binid))static intncr_select(ncr)struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	register struct ncrsbc *sbc = ncr->n_sbc;	register int s, rval, retry;	u_char uctmp;	u_char binid = NUM_TO_BIT(ncr->n_id);	PRINTF3("ncr_select: ready to do ARB/SEL for tgt %d\n", Tgt(sp));	if (INTPENDING(ncr)) {		if (ncr_debug > 2) {			ncr_printstate(ncr);			printf("ncr_select: preempting\n");		}		return (SEL_RESEL);	}	if (ncr->n_type != IS_3_50)		DISABLE_DMA(ncr);	if (ncr_debug > 1)		ncr_printstate(ncr);	/*	 * Attempt to arbitrate for the SCSI bus.	 *	 * It seems that the tcr must be 0 for arbitration to work.	 */	sbc->tcr = 0;	sbc->mr &= ~NCR_MR_ARB;    /* turn off arb */	sbc->icr = 0;	sbc->odr = binid;	UPDATE_STATE(STATE_ARBITRATION);	rval = SEL_ARBFAIL;	for (retry = 0; retry < NCR_ARB_RETRIES; retry++) {		/* wait for scsi bus to become free */		if (ncr_sbcwait(&CBSR, NCR_CBSR_BSY, NCR_WAIT_COUNT, 0)) {			PRINTF3("%s%d: scsi bus continuously busy, cbsr= %x\n",			    CNAME, CNUM, sbc->cbsr);			break;		}		PRINTF3("ncr_select: bus free, current cbsr= %x\n", CBSR);		/*		 * If the bus is now FREE, turn on ARBitration		 */		sbc->mr |= NCR_MR_ARB;		/*		 * wait for ncr to begin arbitration by calling ncr_sbcwait().		 * If failed due to reselection, turn off ARB, preempt the job		 * and return SEL_RESEL.		 */		if (ncr_sbcwait(&sbc->icr, NCR_ICR_AIP, NCR_ARB_WAIT, 1)) {			/*			 * sbc may never begin arbitration			 * due to a target reselecting us.			 * (time critical)			 */			s = splhigh();			sbc->mr &= ~NCR_MR_ARB;	/* turn off arb */			if (RESELECTING(CBSR, CDR, binid)) {				(void) splx(s);				rval = SEL_RESEL;				break;			}			(void) splx(s);			printf ("%s%d: AIP never set, cbsr= 0x%x\n", CNAME,			    CNUM, CBSR);		} else {			/*			 * check to see if we won arbitration			 * (time critical)			 */			s = splhigh();			DELAY(ncr_arbitration_delay);			if (WON_ARB) {				(void) splx(s);				rval = SEL_FALSE;				break;			}			(void) splx(s);		}		PRINTF3("ncr_select: lost_arb, current cbsr= %x\n", CBSR);		/*		 * Lost arbitration. Maybe try again in a nano or two		 * (time critical)		 */		s = splhigh();		sbc->mr &= ~NCR_MR_ARB;	/* turn off ARB */		if (RESELECTING(CBSR, CDR, binid)) {			(void) splx(s);			rval = SEL_RESEL;			break;		}		(void) splx(s);	}	if (rval == SEL_ARBFAIL) {		/*		 * FAILED ARBITRATION even with retries.		 * This shouldn't happen since we (usually)		 * have the highest priority id on the scsi bus.		 */		sbc->icr = 0;		sbc->mr = 0;		uctmp = sbc->clr;		/*		 * After exhausting retries, and if there		 * are any outstanding disconnected cmds,		 * enable reselection attempts from them		 * and return SEL_FALSE.		 *		 */		PRINTF3("ncr_select: failed arb, target= %x\n", Tgt(sp));		if (ncr->n_ndisc > 0) {			sbc->ser = 0;			sbc->ser = binid;			if (ncr->n_type != IS_3_50)				ENABLE_DMA(ncr);		}		return (rval);	} else if (rval == SEL_RESEL) {		sbc->mr = 0;		if (ncr->n_type != IS_3_50)			ENABLE_DMA(ncr);		return (rval);	}	/*	 * Okay. We got the bus. Now attempt to select the target.	 */#ifdef	DO_NOT_DO_THIS_HERE	/*	 * Don't mark that we got the bus yet, because	 * we may in fact have *not* got it (see below)	 */	sp->cmd_pkt.pkt_state |= STATE_GOT_BUS;#endif	/*	 * XXX: ???	 */	sp->cmd_pkt.pkt_reason = CMD_INCOMPLETE;	UPDATE_STATE(STATE_SELECTING);	/*	 * calculate binary of target_id and host_id	 * and or them together to send out.	 */	uctmp = ((1 << Tgt(sp)) | binid);	sbc->odr = uctmp;	uctmp = (NCR_ICR_SEL | NCR_ICR_BUSY | NCR_ICR_DATA);	if ((scsi_options & SCSI_OPTIONS_DR) &&	    (sp->cmd_pkt.pkt_flags & FLAG_NODISCON) == 0) {		ncr->n_cur_msgout[0] = MSG_DR_IDENTIFY | Lun (sp);		ncr->n_omsglen = 1;		ncr->n_omsgidx = 0;		uctmp |= NCR_ICR_ATN;	}	sbc->icr = uctmp;		/* start selection */	sbc->mr &= ~NCR_MR_ARB;		/* turn off arb */	DELAY(ncr_bus_clear_delay + ncr_bus_settle_delay);	/*	 * Drop our assertion of BSY* (left on during arbitration)	 */	sbc->icr &= ~NCR_ICR_BUSY;	DELAY(1);	/*	 * Apparently the ncr chip lies about actually	 * getting the bus, hence we'll check for a reselection	 * attempt here.	 */	for (retry = 0; retry < NCR_SHORT_WAIT; retry ++) {		/*		 * If BSY asserted, then the target has selected.		 * If not, check for a reselection attempt.		 */		if (CBSR & NCR_CBSR_BSY) {			PRINTF3("ncr_select: cbsr= 0x%b\n", CBSR, cbsr_bits);			break;		} else if (RESELECTING(CBSR, CDR, binid)) {			sbc->mr = 0;			sbc->icr = 0;			if (ncr->n_type != IS_3_50)				ENABLE_DMA(ncr);			PRINTF3("ncr_select: arb_won, but preempt again\n");			return (SEL_RESEL);		}		DELAY(10);	}	/*	 * Say that we got the bus here rather than earlier.	 */	sp->cmd_pkt.pkt_state |= STATE_GOT_BUS;	if (retry >= NCR_SHORT_WAIT) {		/*		 * Target failed selection		 */		sbc->icr = 0;		sbc->mr = 0;		uctmp = sbc->clr;		/*		 * if failed to select target, enable disconnect,		 * if any discon_job pending		 */		if (ncr->n_ndisc > 0) {			sbc->ser = 0;			sbc->ser = binid;			if (ncr->n_type != IS_3_50)				ENABLE_DMA(ncr);		}		sp->cmd_pkt.pkt_reason = CMD_INCOMPLETE;		return (SEL_FALSE);	}	/*	 * Drop SEL* and DATA*	 */	sbc->tcr = TCR_UNSPECIFIED;	if (!NON_INTR(sp)) {		/*		 * Time critical		 */		s = splhigh();		if (sp->cmd_flags & CFLAG_DMAVALID) {			(*ncr->n_dma_setup)(ncr);		}		sbc->mr |= NCR_MR_DMA;		sbc->icr &= ~(NCR_ICR_SEL | NCR_ICR_DATA);		(void) splx(s);		if (ncr->n_type != IS_3_50)			ENABLE_DMA(ncr);	} else {		if (sp->cmd_flags & CFLAG_DMAVALID) {			(*ncr->n_dma_setup)(ncr);		}		sbc->icr &= ~(NCR_ICR_SEL | NCR_ICR_DATA);	}	/*	 * Flag that we have selected the target...	 */	sp->cmd_pkt.pkt_state |= STATE_GOT_TARGET;	UPDATE_STATE(STATE_SELECTED);	PRINTF3("ncr_select: select ok\n");	return (SEL_TRUE);}static voidncr_preempt(ncr)register struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	UPDATE_STATE(STATE_FREE);	UPDATE_SLOT(UNDEFINED);	ncr->n_preempt++;	if (NON_INTR(sp) && INTPENDING(ncr)) {		ncrsvc(ncr);	}}static voidncr_disconnect(ncr)struct ncr *ncr;{	struct scsi_cmd *sp = CURRENT_CMD(ncr);	sp->cmd_pkt.pkt_statistics |= STAT_DISCON;	sp->cmd_flags |= CFLAG_CMDDISC;	ncr->n_ndisc++;	ncr->n_last_slot = ncr->n_cur_slot;	ncr->n_cur_slot = UNDEFINED;	ncr->n_lastcount = 0;	ncr->n_disconnects++;	ncr->n_omsglen = ncr->n_omsgidx = 0;	ncr->n_last_msgin = 0xff;	UPDATE_STATE(STATE_FREE);	if (NON_INTR(sp) == 0) {		short nextslot;		nextslot = Tgt(sp) + NLUNS_PER_TARGET;		if (nextslot >= NLUNS_PER_TARGET*NTARGETS)			nextslot = 0;		(void) ncr_ustart(ncr, nextslot);	}}/* * Programmed I/O Routines */static intncr_xfrin(ncr, phase, datap, amt)	/* pick up incoming data byte(s) */register struct ncr *ncr;int phase;register caddr_t datap;register int amt;{	register int i, s;	register struct ncrsbc *sbc = N_SBC;	register u_char icr;	PRINTF3("ncr_xfrin: amt= %x\n", amt);	/*	 * Get data from the scsi bus.	 */	if ((sbc->cbsr & NCR_CBSR_REQ) == 0) {		sbc->tcr = TCR_UNSPECIFIED;		EPRINTF("ncr_xfrin: bad REQ, cbsr= 0x%b\n", CBSR, cbsr_bits);		return (FAILURE);	} else if ((sbc->bsr & NCR_BSR_PMTCH) == 0) {		sbc->tcr = TCR_UNSPECIFIED;		EPRINTF("ncr_xfrin: bad bus match, bsr= %x\n", sbc->bsr);		return (FAILURE);	}	for (i = 0; i < amt; i++) {		/* wait for target request */		if (i && !REQ_ASSERTED(ncr)) {			sbc->tcr = TCR_UNSPECIFIED;			return (FAILURE);		}		if (i && (sbc->bsr & NCR_BSR_PMTCH) == 0) {			/*			 * phase is not matched. Check to			 * see whether we should match it			 */			if ((sbc->cbsr & (0x7<<2)) == phase)				sbc->tcr = phase >> 2;			else				break;		}		/* grab data and complete req/ack handshake */		*datap++ = sbc->cdr;		s = splhigh();		sbc->icr |= NCR_ICR_ACK;		sbc->tcr = TCR_UNSPECIFIED;		(void) splx(s);		if (!REQ_DROPPED(ncr)) {			EPRINTF("ncr_xfrin: REQ not dropped, cbsr=0x%b\n",				CBSR, cbsr_bits);			sbc->icr = 0;			return (FAILURE);		}		/* Drop acknowledgement...  */		sbc->icr = 0;	}	sbc->tcr = TCR_UNSPECIFIED;	sbc->icr = 0;		/* duplicate */	PRINTF3("ncr_xfrin: picked up %d\n", i);	return (i);}static intncr_xfrin_noack(ncr, phase, datap)register struct ncr *ncr;int phase;caddr_t datap;{	register u_char indata;	PRINTF3("ncr_xfrin_noack: phase= %x\n", phase);	if ((N_SBC->cbsr & NCR_CBSR_REQ) == 0) {		N_SBC->tcr = TCR_UNSPECIFIED;		EPRINTF("ncr_xfrin_noack: bad REQ, cbsr=0x%b\n",			CBSR, cbsr_bits);		return (FAILURE);	} else if ((N_SBC->bsr & NCR_BSR_PMTCH) == 0) {		N_SBC->tcr = TCR_UNSPECIFIED;		return (FAILURE);	}	/*	 * Get data from the scsi bus, but NO acknowlegment; if current phase	 * is MESSAGE_IN, clear TCR	 */	indata = N_SBC->cdr;	if (phase == PHASE_MSG_IN) {		/*		 * We've picked up the message byte, but not acknowledged it		 * yet. Perhaps here is the best place to clear the tcr		 * register in the case that a COMMAND COMPLETE or a		 * DISCONNECT message was just sent and the target is gonna		 * clear the SCSI bus just as soon as it is acknowledged. We		 * have to have tcr 0 to recognize other targets then		 * attempting to reselect us...		 */		N_SBC->tcr = 0;	}	*datap = indata;	PRINTF3("ncr_xfrin_noack: indata= %x\n", indata);	return (SUCCESS);}/* * Dma Subroutines */#ifdef	sun4static intncr_cobra_dma_chkerr(ncr, bcr)	/* check for any DMA error */register struct ncr *ncr;u_int bcr;{	struct scsi_cmd *sp = CURRENT_CMD(ncr);	u_int csr;	csr = GET_CSR(ncr);	PRINTF3("ncr_dma_chkerr: csr= %x, bcr= %x\n", csr, bcr);	/* check any abormal DMA conditions */	if (csr & NCR_CSR_DMA_CONFLICT) {		EPRINTF("ncr_dma_cleanup: dma conflict\n");		return (FAILURE);	} else if (csr & NCR_CSR_DMA_BUS_ERR) {		/*		 * Note from sw.c:		 *		 * Early Cobra units have a faulty gate array. It can cause an		 * illegal memory access if full page DMA is being used.  For		 * less than a full page, no problem.  This problem typically		 * shows up when dumping core (in polled mode) where the last		 * page of DVMA was being used.		 *		 * What this means is that if you camp on the dma gate array		 * csr in polled mode, the ncr chip may attempt to prefetch		 * across a page boundary into an invalid page, causing a		 * spurious DMA error.		 */		if (!((ncr->n_type == IS_COBRA) && (bcr > 2) && NON_INTR(sp))) {			EPRINTF("ncr_dma_chkerr: dma bus error\n");			return (FAILURE);		}	}	return (SUCCESS);}static intncr_cobra_dma_recv(ncr)register struct ncr *ncr;{	register u_long addr, offset, bpr;	/*	 * if partial bytes left on the dma longword transfers, manually take	 * care of this and return back how many bytes moved	 */	/*	 * Grabs last few bytes which may not have been dma'd. Worst case is	 * when longword dma transfers are being done and there are 3 bytes	 * leftover.	 *	 * Note: limiting dma address to 20 bits (1 mb).	 *	 */	addr = GET_DMA_ADDR(ncr);	addr &= 0xfffff;	offset = addr & ~3;	bpr = GET_BPR(ncr);	switch (addr & 0x3) {	case 3:		if (ncr_flushbyte(ncr, offset+2, (u_char) ((bpr>>8)&0xff)))			return (FAILURE);		/* FALLTHROUGH */	case 2:		if (ncr_flushbyte(ncr, offset+1, (u_char) ((bpr>>16)&0xff)))			return (FAILURE);		/* FALLTHROUGH */	case 1:

⌨️ 快捷键说明

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