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

📄 asc.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
		regs->asc_cmd = ASC_CMD_XFER_INFO;		readback(regs->asc_cmd);		goto done;	}	/* check for SCSI bus reset */	if (ir & ASC_INT_RESET) {		register int i;		printf("asc%d: SCSI bus reset!!\n", asc - asc_softc);		/* need to flush any pending commands */		for (i = 0; i < ASC_NCMD; i++) {			if (!asc->cmd[i])				continue;			asc->st[i].error = EIO;			asc_end(asc, 0, 0, 0);		}		/* rearbitrate synchronous offset */		for (i = 0; i < ASC_NCMD; i++) {			asc->st[i].sync_offset = 0;			asc->st[i].flags = 0;		}		asc->target = -1;		return;	}	/* check for command errors */	if (ir & ASC_INT_ILL)		goto abort;	/* check for disconnect */	if (ir & ASC_INT_DISC) {		state = &asc->st[asc->target];		switch (ASC_SS(ss)) {		case 0: /* device did not respond */			/* check for one of the starting scripts */			switch (asc->script - asc_scripts) {			case SCRIPT_TRY_SYNC:			case SCRIPT_SIMPLE:			case SCRIPT_DATA_IN:			case SCRIPT_DATA_OUT:				if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) {					regs->asc_cmd = ASC_CMD_FLUSH;					readback(regs->asc_cmd);				}				state->error = ENXIO;				asc_end(asc, status, ss, ir);				return;			}			/* FALLTHROUGH */		default:			printf("asc%d: SCSI device %d: unexpected disconnect\n",				asc - asc_softc, asc->target);			/*			 * On rare occasions my RZ24 does a disconnect during			 * data in phase and the following seems to keep it			 * happy.			 * XXX Should a scsi disk ever do this??			 */			asc->script = &asc_scripts[SCRIPT_RESEL];			asc->state = ASC_STATE_RESEL;			state->flags |= DISCONN;			regs->asc_cmd = ASC_CMD_ENABLE_SEL;			readback(regs->asc_cmd);			return;		}	}	/* check for reselect */	if (ir & ASC_INT_RESEL) {		unsigned fifo, id, msg;		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;		if (fifo < 2)			goto abort;		/* read unencoded SCSI ID and convert to binary */		msg = regs->asc_fifo & asc->myidmask;		for (id = 0; (msg & 1) == 0; id++)			msg >>= 1;		/* read identify message */		msg = regs->asc_fifo;#ifdef DEBUG		if (asc_logp == asc_log)			asc_log[NLOG - 1].msg = msg;		else			asc_logp[-1].msg = msg;#endif		asc->state = ASC_STATE_BUSY;		asc->target = id;		state = &asc->st[id];		asc->script = state->script;		state->script = (script_t *)0;		if (!(state->flags & DISCONN))			goto abort;		state->flags &= ~DISCONN;		regs->asc_syn_p = state->sync_period;		regs->asc_syn_o = state->sync_offset;		regs->asc_cmd = ASC_CMD_MSG_ACPT;		readback(regs->asc_cmd);		goto done;	}	/* check if we are being selected as a target */	if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN))		goto abort;	/*	 * 'ir' must be just ASC_INT_FC.	 * This is normal if canceling an ASC_ENABLE_SEL.	 */done:	MachEmptyWriteBuffer();	/* watch out for HW race conditions and setup & hold time violations */	ir = regs->asc_status;	while (ir != (status = regs->asc_status))		ir = status;	if (status & ASC_CSR_INT)		goto again;	return;abort:#ifdef DEBUG	asc_DumpLog("asc_intr");#endif#if 0	panic("asc_intr");#else	for (;;);#endif}/* * All the many little things that the interrupt * routine might switch to. *//* ARGSUSED */static intscript_nop(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	return (1);}/* ARGSUSED */static intasc_get_status(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	register asc_regmap_t *regs = asc->regs;	register int data;	/*	 * Get the last two bytes in the FIFO.	 */	if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) {		printf("asc_get_status: fifo cnt %d\n", data); /* XXX */		asc_DumpLog("get_status"); /* XXX */		if (data < 2) {			asc->regs->asc_cmd = ASC_CMD_MSG_ACPT;			readback(asc->regs->asc_cmd);			return (0);		}		do {			data = regs->asc_fifo;		} while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2);	}	/* save the status byte */	asc->st[asc->target].statusByte = data = regs->asc_fifo;#ifdef DEBUG	if (asc_logp == asc_log)		asc_log[NLOG - 1].msg = data;	else		asc_logp[-1].msg = data;#endif	/* get the (presumed) command_complete message */	if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE)		return (1);#ifdef DEBUG	printf("asc_get_status: status %x cmd %x\n",		asc->st[asc->target].statusByte, data);	asc_DumpLog("asc_get_status");#endif	return (0);}/* ARGSUSED */static intasc_end(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	register ScsiCmd *scsicmd;	register State *state;	register int i, target;	asc->state = ASC_STATE_IDLE;	target = asc->target;	asc->target = -1;	scsicmd = asc->cmd[target];	asc->cmd[target] = (ScsiCmd *)0;	state = &asc->st[target];#ifdef DEBUG	if (asc_debug > 1) {		printf("asc_end: %s target %d cmd %x err %d resid %d\n",			scsicmd->sd->sd_driver->d_name, target,			scsicmd->cmd[0], state->error, state->buflen);	}#endif#ifdef DIAGNOSTIC	if (target < 0 || !scsicmd)		panic("asc_end");#endif	/* look for disconnected devices */	for (i = 0; i < ASC_NCMD; i++) {		if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN))			continue;		asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL;		readback(asc->regs->asc_cmd);		asc->state = ASC_STATE_RESEL;		asc->script = &asc_scripts[SCRIPT_RESEL];		break;	}	/*	 * Look for another device that is ready.	 * May want to keep last one started and increment for fairness	 * rather than always starting at zero.	 */	for (i = 0; i < ASC_NCMD; i++) {		/* don't restart a disconnected command */		if (!asc->cmd[i] || (asc->st[i].flags & DISCONN))			continue;		asc_startcmd(asc, i);		break;	}	/* signal device driver that the command is done */	(*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error,		state->buflen, state->statusByte);	return (0);}/* ARGSUSED */static intasc_dma_in(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	register asc_regmap_t *regs = asc->regs;	register State *state = &asc->st[asc->target];	register int len;	/* check for previous chunk in buffer */	if (state->flags & DMA_IN_PROGRESS) {		/*		 * Only count bytes that have been copied to memory.		 * There may be some bytes in the FIFO if synchonous transfers		 * are in progress.		 */		(*asc->dma_end)(asc, state, ASCDMA_READ);		ASC_TC_GET(regs, len);		len = state->dmalen - len;		bcopy(state->dmaBufAddr, state->buf, len);		state->buf += len;		state->buflen -= len;	}	/* setup to start reading the next chunk */	len = state->buflen;	if (len > state->dmaBufSize)		len = state->dmaBufSize;	state->dmalen = len;	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);	ASC_TC_PUT(regs, len);#ifdef DEBUG	if (asc_debug > 2)		printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len);#endif	/* check for next chunk */	state->flags |= DMA_IN_PROGRESS;	if (len != state->buflen) {		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;		readback(regs->asc_cmd);		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];		return (0);	}	return (1);}/* ARGSUSED */static intasc_last_dma_in(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	register asc_regmap_t *regs = asc->regs;	register State *state = &asc->st[asc->target];	register int len, fifo;	/* copy data from buffer to main memory */	(*asc->dma_end)(asc, state, ASCDMA_READ);	ASC_TC_GET(regs, len);	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;#ifdef DEBUG	if (asc_debug > 2)		printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n",			state->buflen, state->dmalen, len, fifo);#endif	if (fifo) {		/* device must be trying to send more than we expect */		regs->asc_cmd = ASC_CMD_FLUSH;		readback(regs->asc_cmd);	}	state->flags &= ~DMA_IN_PROGRESS;	len = state->dmalen - len;	state->buflen -= len;	bcopy(state->dmaBufAddr, state->buf, len);	return (1);}/* ARGSUSED */static intasc_resume_in(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	register asc_regmap_t *regs = asc->regs;	register State *state = &asc->st[asc->target];	register int len;	/* setup to start reading the next chunk */	len = state->buflen;	if (len > state->dmaBufSize)		len = state->dmaBufSize;	state->dmalen = len;	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ);	ASC_TC_PUT(regs, len);#ifdef DEBUG	if (asc_debug > 2)		printf("asc_resume_in: buflen %d, len %d\n", state->buflen,			len);#endif	/* check for next chunk */	state->flags |= DMA_IN_PROGRESS;	if (len != state->buflen) {		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;		readback(regs->asc_cmd);		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];		return (0);	}	return (1);}/* ARGSUSED */static intasc_resume_dma_in(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	register asc_regmap_t *regs = asc->regs;	register State *state = &asc->st[asc->target];	register int len, off;	/* setup to finish reading the current chunk */	len = state->dmaresid;	off = state->dmalen - len;	if ((off & 1) && state->sync_offset) {		printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n",			state->dmalen, len, off); /* XXX */		regs->asc_res_fifo = state->dmaBufAddr[off];	}	(*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ);	ASC_TC_PUT(regs, len);#ifdef DEBUG	if (asc_debug > 2)		printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n",			state->dmalen, state->buflen, len, off);#endif	/* check for next chunk */	state->flags |= DMA_IN_PROGRESS;	if (state->dmalen != state->buflen) {		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;		readback(regs->asc_cmd);		asc->script = &asc_scripts[SCRIPT_CONTINUE_IN];		return (0);	}	return (1);}/* ARGSUSED */static intasc_dma_out(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	register asc_regmap_t *regs = asc->regs;	register State *state = &asc->st[asc->target];	register int len, fifo;	if (state->flags & DMA_IN_PROGRESS) {		/* check to be sure previous chunk was finished */		ASC_TC_GET(regs, len);		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;		if (len || fifo)			printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n",				state->buflen, state->dmalen, len, fifo); /* XXX */		len += fifo;		len = state->dmalen - len;		state->buf += len;		state->buflen -= len;	}	/* setup for this chunk */	len = state->buflen;	if (len > state->dmaBufSize)		len = state->dmaBufSize;	state->dmalen = len;	bcopy(state->buf, state->dmaBufAddr, len);	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);	ASC_TC_PUT(regs, len);#ifdef DEBUG	if (asc_debug > 2)		printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len);#endif	/* check for next chunk */	state->flags |= DMA_IN_PROGRESS;	if (len != state->buflen) {		regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA;		readback(regs->asc_cmd);		asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT];		return (0);	}	return (1);}/* ARGSUSED */static intasc_last_dma_out(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	register asc_regmap_t *regs = asc->regs;	register State *state = &asc->st[asc->target];	register int len, fifo;	ASC_TC_GET(regs, len);	fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;#ifdef DEBUG	if (asc_debug > 2)		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",			state->buflen, state->dmalen, len, fifo);#endif	if (fifo) {		len += fifo;		regs->asc_cmd = ASC_CMD_FLUSH;		readback(regs->asc_cmd);		printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n",			state->buflen, state->dmalen, len, fifo);	}	state->flags &= ~DMA_IN_PROGRESS;	len = state->dmalen - len;	state->buflen -= len;	return (1);}/* ARGSUSED */static intasc_resume_out(asc, status, ss, ir)	register asc_softc_t asc;	register int status, ss, ir;{	register asc_regmap_t *regs = asc->regs;	register State *state = &asc->st[asc->target];	register int len;

⌨️ 快捷键说明

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