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

📄 ncr.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (ncr_flushbyte(ncr, offset, (u_char) (bpr>>24)))			return (FAILURE);		break;	default:		break;	}	ncr->n_lastbcr += (addr & 0x3);	return (SUCCESS);}static intncr_cobra_dma_cleanup(ncr)register struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	register u_long amt, reqamt;	register u_char junk;	DISABLE_DMA(ncr);	amt = GET_DMA_ADDR(ncr);	reqamt = ncr->n_lastcount;	/*	 * Now try and figure out how much actually transferred	 */	ncr->n_lastbcr = reqamt - ((amt & 0xfffff) -	    (unsigned int) sp->cmd_data & 0xfffff);	PRINTF3("ncr_dma_cleanup: count= %x, data= %x, amt= %x, bcr= %x\n",		reqamt, sp->cmd_data, amt, ncr->n_lastbcr);	if ((ncr->n_lastbcr != reqamt) && (!(N_SBC->tcr & NCR_TCR_LAST)) &&	    (sp->cmd_flags & CFLAG_DMASEND)) {		ncr->n_lastbcr++;	}	/*	 * Now check for dma related errors	 */	if (ncr_cobra_dma_chkerr(ncr, ncr->n_lastbcr)) {		sp->cmd_pkt.pkt_reason = CMD_DMA_DERR;		return (FAILURE);	}	/*	 * okay, now figure out an adjustment for bytes	 * left over in the or a byte pack register.	 */	if ((sp->cmd_flags & CFLAG_DMASEND) == 0) {		if (ncr_cobra_dma_recv(ncr))			return (FAILURE);	}	if (ncr->n_lastbcr < 0) {		EPRINTF("ncr_dma_cleanup: dma overrun by %d bytes\n",		    -ncr->n_lastbcr);		ncr->n_lastbcr = 0;	}	/*	 * Shut off dma engine	 */	SET_DMA_ADDR(ncr, 0);	SET_DMA_COUNT(ncr, 0);	/*	 * And return result of common cleanup routine	 */	return (ncr_dma_cleanup(ncr));}#endif	sun4#ifdef	sun3static voidncr_ob_dma_setup(ncr)struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	register int reqamt;	u_int dmaaddr;	if (sp->cmd_flags & CFLAG_NEEDSEG) {		panic("ncr_ob_dma_setup: need seg\n");		/*NOTREACHED*/	}	if ((sp->cmd_flags & CFLAG_DMAVALID) == 0) {		panic("ncr_ob_dma_setup: need seg\n");		/*NOTREACHED*/	}	if ((u_long) sp->cmd_data & 0x1) {		panic("dma not on word boundary");		/*NOTREACHED*/	}	ncr->n_lastcount = reqamt = scsi_chkdma(sp, NCR_MAX_DMACOUNT);	if (reqamt == 0)		return;	PRINTF3("ncr_ob_dma_setup: addr= %x, reqamt= %x\n",		sp->cmd_data, reqamt);	/* reset fifo */	SET_CSR(ncr, ((GET_CSR(ncr)) & ~NCR_CSR_FIFO_RES));	SET_CSR(ncr, ((GET_CSR(ncr)) | NCR_CSR_FIFO_RES));	if (sp->cmd_flags & CFLAG_DMASEND) {		SET_CSR(ncr, (GET_CSR(ncr)) | NCR_CSR_SEND);	} else {		SET_CSR(ncr, (GET_CSR(ncr)) & ~NCR_CSR_SEND);	}	/* Set bcr */	SET_BCR(ncr, reqamt);	/* reset udc */	N_DMA->udc_raddr = UDC_ADR_COMMAND;	DELAY(NCR_UDC_WAIT);	N_DMA->udc_rdata = UDC_CMD_RESET;	DELAY(NCR_UDC_WAIT);	/* set up udc dma information */	ncr->n_lastdma = dmaaddr = sp->cmd_data;	if (dmaaddr < Dmabase)		dmaaddr |= Dmabase;	ncr->n_udc->haddr = ((dmaaddr & 0xff0000) >> 8) | UDC_ADDR_INFO;	ncr->n_udc->laddr = dmaaddr & 0xffff;	ncr->n_udc->hcmr = UDC_CMR_HIGH;	ncr->n_udc->count = reqamt / 2; /* #bytes -> #words */	if (sp->cmd_flags & CFLAG_DMASEND) {		ncr->n_udc->rsel = UDC_RSEL_SEND;		ncr->n_udc->lcmr = UDC_CMR_LSEND;		if (reqamt & 1)			ncr->n_udc->count++;	} else {		ncr->n_udc->rsel = UDC_RSEL_RECV;		ncr->n_udc->lcmr = UDC_CMR_LRECV;	}	/* initialize udc chain address register */	N_DMA->udc_raddr = UDC_ADR_CAR_HIGH;	DELAY(NCR_UDC_WAIT);	N_DMA->udc_rdata = (((int)ncr->n_udc) & 0xff0000) >> 8;	DELAY(NCR_UDC_WAIT);	N_DMA->udc_raddr = UDC_ADR_CAR_LOW;	DELAY(NCR_UDC_WAIT);	N_DMA->udc_rdata = ((int)ncr->n_udc) & 0xffff;	DELAY(NCR_UDC_WAIT);	/* initialize udc master mode register */	N_DMA->udc_raddr = UDC_ADR_MODE;	DELAY(NCR_UDC_WAIT);	N_DMA->udc_rdata = UDC_MODE;	DELAY(NCR_UDC_WAIT);	/* issue channel interrupt enable command, in case of error, to udc */	N_DMA->udc_raddr = UDC_ADR_COMMAND;	DELAY(NCR_UDC_WAIT);	N_DMA->udc_rdata = UDC_CMD_CIE;	DELAY(NCR_UDC_WAIT);}/* * Cleanup up the SCSI control logic after a dma transfer. */static intncr_ob_dma_cleanup(ncr)struct ncr *ncr;{	struct scsi_cmd *sp = CURRENT_CMD(ncr);	u_char junk;	int amt, csr;	/*	 * okay, now figure out an adjustment for bytes left over in a fifo	 * or a byte pack register....	 */	if ((sp->cmd_flags & CFLAG_DMASEND) == 0) {		if (ncr_ob_dma_recv(ncr))			return (FAILURE);	}	/*	 * disable dma controller	 */	N_DMA->udc_raddr = UDC_ADR_COMMAND;	DELAY(NCR_UDC_WAIT);	N_DMA->udc_rdata = UDC_CMD_RESET;	DELAY(NCR_UDC_WAIT);	N_DMA->bcr = 0;	SET_CSR(ncr, (GET_CSR(ncr)) & ~NCR_CSR_SEND);	/*	 * reset fifo	 */	SET_CSR(ncr, ((GET_CSR(ncr)) & ~NCR_CSR_FIFO_RES));	SET_CSR(ncr, ((GET_CSR(ncr)) | NCR_CSR_FIFO_RES));	/*	 * And return result of common cleanup routine	 */	return (ncr_dma_cleanup(ncr));}/* * Handle special dma receive situations, e.g. an odd number of bytes in * a dma transfer. */static intncr_ob_dma_recv(ncr)register struct ncr *ncr;{	register int bcr, offset;	u_char byte;	/*	 * handle the onboard scsi situations	 */	offset = ncr->n_lastdma + (ncr->n_lastcount - ncr->n_lastbcr);	bcr = N_DMA->bcr;	N_DMA->udc_raddr = UDC_ADR_COUNT;	DELAY(NCR_UDC_WAIT);	/*	 * wait for the fifo to empty	 */	if (ncr_csrwait(ncr, NCR_CSR_FIFO_EMPTY, NCR_WAIT_COUNT*3, 1)) {		printf("%s%d: fifo never drained\n", CNAME, CNUM);		return (FAILURE);	}	/*	 * Didn't transfer any data.  "Just say no" and leave,	 * rather than erroneously executing left over byte code.	 * The bcr + 1 above wards against 5380 prefetch.	 */	if (bcr == ncr->n_lastcount) {		return (SUCCESS);	} else if ((bcr + 1) == ncr->n_lastcount) {		ncr->n_lastbcr = ncr->n_lastcount;	}	/*	 * For either of the following cases, it appears that the	 * n_lastbcr count latched up in ncrsvc is, in fact, correct.	 * Therefore, we don't need to adjust it here.	 */	/* handle odd byte */	if ((ncr->n_lastcount - bcr) & 1) {		byte = ((N_DMA->fifo_data & 0xff00) >> 8);		if (ncr_flushbyte(ncr, offset - 1, byte)) {			return (FAILURE);		}		PRINTF1("%s%d: odd byte recv: lastcount %d bcr %d\n",			CNAME, CNUM, ncr->n_lastcount, ncr->n_lastbcr);	} else if ((N_DMA->udc_rdata * 2) - bcr == 2) {		/*		 * The udc may not dma the last word from the fifo_data		 * register into memory due to how the hardware turns		 * off the udc at the end of the dma operation.		 */		byte = ((N_DMA->fifo_data & 0xff00) >> 8);		if (ncr_flushbyte(ncr, offset - 2, byte)) {			return (FAILURE);		}		byte = (N_DMA->fifo_data & 0xff);		if (ncr_flushbyte(ncr, offset - 1, byte)) {			return (FAILURE);		}		PRINTF1("%s%d: last word: lastcount %d bcr %d\n",			CNAME, CNUM, ncr->n_lastcount, ncr->n_lastbcr);	}	return (SUCCESS);}#endif	sun3static intncr_vme_dma_recv(ncr)register struct ncr *ncr;{	register amt, csr;	register u_short bprmsw, bprlsw;	u_long offset;	/*	 * 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.  If BPCON bit is set then longword dma	 * was being done, otherwise word dma was being done.	 */	csr = GET_CSR(ncr);	if ((amt = NCR_CSR_LOB_CNT(csr)) == 0) {		return (SUCCESS);	}	offset = ncr->n_lastdma + (ncr->n_lastcount - ncr->n_lastbcr);	PRINTF3("%s%d: receive flushing %d bytes to offset %d in xfer of %d\n",		CNAME, CNUM, amt, offset, ncr->n_lastcount);	/*	 * It *may* be that the order that	 * the byte pack register is read	 * is significant.	 *	 */	bprmsw = N_CTL->bpr.msw;	bprlsw = N_CTL->bpr.lsw;	if (csr & NCR_CSR_BPCON) {		return (ncr_flushbyte(ncr, offset-1, (u_char) hibyte(bprlsw)));	}	switch (amt) {	case 3:		if (ncr_flushbyte(ncr, offset-3, (u_char) hibyte(bprmsw)))			return (FAILURE);		if (ncr_flushbyte(ncr, offset-2, (u_char) lobyte(bprmsw)))			return (FAILURE);		if (ncr_flushbyte(ncr, offset-1, (u_char) hibyte(bprlsw)))			return (FAILURE);		break;	case 2:		if (ncr_flushbyte(ncr, offset-2, (u_char) hibyte(bprmsw)))			return (FAILURE);		if (ncr_flushbyte(ncr, offset-1, (u_char) lobyte(bprmsw)))			return (FAILURE);		break;	case 1:		if (ncr_flushbyte(ncr, offset-1, (u_char) hibyte(bprmsw)))			return (FAILURE);		break;	}	return (SUCCESS);}static intncr_vme_dma_cleanup(ncr)register struct ncr *ncr;{	struct scsi_cmd *sp = CURRENT_CMD(ncr);	register u_int bcr, reqamt;	DISABLE_DMA(ncr);	/*	 * Now try and figure out how much actually transferred	 */	bcr = GET_BCR(ncr);	reqamt = ncr->n_lastcount;	/*	 * bcr does not reflect how many bytes were actually	 * transferred for VME.	 *	 * SCSI-3 VME interface is a little funny on writes:	 * if we have a disconnect, the dma has overshot by	 * one byte and needs to be incremented.  This is	 * true if we have not transferred either all data	 * or no data.	 */	if ((sp->cmd_flags & CFLAG_DMASEND) && bcr != reqamt && bcr) {		if (ncr->n_lastbcr != 0)			bcr = ncr->n_lastbcr + 1;		else			bcr++;	} else if ((sp->cmd_flags & CFLAG_DMASEND) == 0) {		bcr = ncr->n_lastbcr;		if (ncr_vme_dma_recv(ncr)) {			return (FAILURE);		}	}	/*	 * rewrite last bcr count- it might have been changed by circumstances.	 */	ncr->n_lastbcr = bcr;	/*	 * Shut off dma engine	 */	SET_DMA_ADDR(ncr, 0);	SET_DMA_COUNT(ncr, 0);	SET_BCR(ncr, 0);	SET_CSR(ncr, (GET_CSR(ncr)) & ~NCR_CSR_SEND);	/*	 * reset fifo	 */	SET_CSR(ncr, ((GET_CSR(ncr)) & ~NCR_CSR_FIFO_RES));	SET_CSR(ncr, ((GET_CSR(ncr)) | NCR_CSR_FIFO_RES));	/*	 * And return result of common cleanup routine	 */	return (ncr_dma_cleanup(ncr));}static intncr_3e_dma_cleanup(ncr)register struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	/*	 * Now try and figure out how much actually transferred	 */	ncr->n_lastbcr = (u_long) (u_short) GET_DMA_COUNT(ncr);	if (sp->cmd_flags & CFLAG_DMASEND) {		/*		 * check for a pre-fetch botch		 * XXX: I'm not sure I believe this. It was lifted from se.c.		 */		if (ncr->n_lastbcr == 0xffff)			ncr->n_lastbcr = 0;		else			ncr->n_lastbcr++;	}	/*	 * Shut off dma engine	 */	SET_DMA_ADDR(ncr, 0);	SET_DMA_COUNT(ncr, 0);	/*	 * Copy out data from onboard dma buffer (if receive case)	 */	if ((sp->cmd_flags & CFLAG_DMASEND) == 0) {		if (ncr_3e_storedata(ncr)) {			return (FAILURE);		}	}	/*	 * And return result of common cleanup routine	 */	return (ncr_dma_cleanup(ncr));}/* * Cleanup operations, where the dma engine doesn't do it all. * * XXXXXXXXXXXXXXXXXXXXXXXXXXX: FIX ME :XXXXXXXXXXXXXXXXXXXXXXXXXXXX * XXXXXXXXX						XXXXXXXXXXXX * XXXXXXXXX		All These Routines Need to	XXXXXXXXXXXX * XXXXXXXXX		be rewritten to *not* refer	XXXXXXXXXXXX * XXXXXXXXX		to DVMA. This must happen!	XXXXXXXXXXXX * XXXXXXXXX						XXXXXXXXXXXX * XXXXXXXXXXXXXXXXXXXXXXXXXXX: FIX ME :XXXXXXXXXXXXXXXXXXXXXXXXXXXX * */static intncr_flushbyte (ncr, offset, byte)struct ncr *ncr;int offset;u_char byte;{	u_char *mapaddr;	u_int pv;	if (MBI_MR(offset) < dvmasize) {		DVMA[offset] = byte;		return (SUCCESS);	}#ifdef	sun3x	pv = btop (VME24D16_BASE + (offset & VME24D16_MASK));#else	sun3x	pv = PGT_VME_D16 | VME24_BASE | btop(offset & VME24_MASK);#endif	sun3x	mapaddr = (u_char *) ((u_long) kmxtob(ncr->n_kment) |				(u_long) MBI_OFFSET(offset));	segkmem_mapin(&kseg, (addr_t) (((int)mapaddr) & PAGEMASK),		(u_int) mmu_ptob(1), PROT_READ | PROT_WRITE, pv, 0);	*mapaddr = byte;	segkmem_mapout(&kseg,	    (addr_t) (((int)mapaddr) & PAGEMASK), (u_int) mmu_ptob(1));	return (SUCCESS);}static intncr_3e_fetchdata(ncr)struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	if (MBI_MR(sp->cmd_data) < dvmasize) {		bcopy(sp->cmd_data + (u_long) DVMA, ncr->n_dmabuf,		    ncr->n_lastcount);	} else {		panic("3/E dma from VME board");		/*NOTREACHED*/	}	return (SUCCESS);}static intncr_3e_storedata(ncr)struct ncr *ncr;{	register struct scsi_cmd *sp = CURRENT_CMD(ncr);	if (MBI_MR(sp->cmd_data) < dvmasize) {		bcopy(ncr->n_dmabuf, sp->cmd_data + (u_long) DVMA,		    ncr->n_lastcount);	} else {		panic("3/E dma to VME board");		/*NOTREACHED*/	}	return (SUCCESS);}/* * Common routine to enable the SBC for a dma operation. */static voidncr_dma_enable(ncr, direction)register struct ncr *ncr;int direction;{	register s;	u_char junk;	s = splhigh();	/* (possibly) time critical */	if (ncr->n_type == IS_3_50) {		/*		 * issue start chain command to udc		 */		N_DMA->udc_rdata = UDC_CMD_STRT_CHN;	} else if (ncr->n_type == IS_SCSI3) {		/*		 * Stuff count registers		 */		SET_DMA_COUNT(ncr, ncr->n_lastcount);		SET_BCR(ncr, ncr->n_lastcount);	}	if (direction) {	/* 1 = recv */		N_SBC->tcr = TCR_DATA_IN;		junk = N_SBC->clr;		N_SB

⌨️ 快捷键说明

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