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

📄 asc.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
	case DS_3MAX:	default:	    asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR);	    asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM);	    bufsiz = PER_TGT_DMA_SIZE;	    asc->dma_start = tb_dma_start;	    asc->dma_end = tb_dma_end;	};	/*	 * Now for timing. The 3max has a 25Mhz tb whereas the 3min and	 * maxine are 12.5Mhz.	 */	switch (pmax_boardtype) {	case DS_3MAX:	case DS_3MAXPLUS:		asc->min_period = ASC_MIN_PERIOD25;		asc->max_period = ASC_MAX_PERIOD25;		asc->ccf = ASC_CCF(25);		asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf);		asc->tb_ticks = 10;		break;	case DS_3MIN:	case DS_MAXINE:	default:		asc->min_period = ASC_MIN_PERIOD12;		asc->max_period = ASC_MAX_PERIOD12;		asc->ccf = ASC_CCF(13);		asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf);		asc->tb_ticks = 20;		break;	};	asc->state = ASC_STATE_IDLE;	asc->target = -1;	regs = asc->regs;	/*	 * Reset chip, fully.  Note that interrupts are already enabled.	 */	s = splbio();	/* preserve our ID for now */	asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;	asc->myidmask = ~(1 << asc->myid);	asc_reset(asc, regs);	/*	 * Our SCSI id on the bus.	 * The user can set this via the prom on 3maxen/pmaxen.	 * If this changes it is easy to fix: make a default that	 * can be changed as boot arg.	 */#ifdef	unneeded	regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) |			      (scsi_initiator_id[unit] & 0x7);#endif	id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID;	splx(s);	/*	 * Statically partition the DMA buffer between targets.	 * This way we will eventually be able to attach/detach	 * drives on-fly.  And 18k/target is plenty for normal use.	 */	/*	 * Give each target its own DMA buffer region.	 * We may want to try ping ponging buffers later.	 */	for (i = 0; i < ASC_NCMD; i++) {		asc->st[i].dmaBufAddr = asc->buff + bufsiz * i;		asc->st[i].dmaBufSize = bufsiz;	}	printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n",		unit, cp->pmax_addr, cp->pmax_pri, id);	return (1);}/* * Start activity on a SCSI device. * We maintain information on each device separately since devices can * connect/disconnect during an operation. */voidasc_start(scsicmd)	register ScsiCmd *scsicmd;	/* command to start */{	register struct scsi_device *sdp = scsicmd->sd;	register asc_softc_t asc = &asc_softc[sdp->sd_ctlr];	int s;	s = splbio();	/*	 * Check if another command is already in progress.	 * We may have to change this if we allow SCSI devices with	 * separate LUNs.	 */	if (asc->cmd[sdp->sd_drive]) {		printf("asc%d: device %s busy at start\n", sdp->sd_ctlr,			sdp->sd_driver->d_name);		(*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY,			scsicmd->buflen, 0);		splx(s);	}	asc->cmd[sdp->sd_drive] = scsicmd;	asc_startcmd(asc, sdp->sd_drive);	splx(s);}static voidasc_reset(asc, regs)	asc_softc_t asc;	asc_regmap_t *regs;{	/*	 * Reset chip and wait till done	 */	regs->asc_cmd = ASC_CMD_RESET;	MachEmptyWriteBuffer(); DELAY(25);	/* spec says this is needed after reset */	regs->asc_cmd = ASC_CMD_NOP;	MachEmptyWriteBuffer(); DELAY(25);	/*	 * Set up various chip parameters	 */	regs->asc_ccf = asc->ccf;	MachEmptyWriteBuffer(); DELAY(25);	regs->asc_sel_timo = asc->timeout_250;	/* restore our ID */	regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK;	/* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */	regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL;	regs->asc_cnfg3 = 0;	/* zero anything else */	ASC_TC_PUT(regs, 0);	regs->asc_syn_p = asc->min_period;	regs->asc_syn_o = 0;	/* async for now */	MachEmptyWriteBuffer();}/* * Start a SCSI command on a target. */static voidasc_startcmd(asc, target)	asc_softc_t asc;	int target;{	register asc_regmap_t *regs;	register ScsiCmd *scsicmd;	register State *state;	int len;	/*	 * See if another target is currently selected on this SCSI bus.	 */	if (asc->target >= 0)		return;	regs = asc->regs;	/*	 * If a reselection is in progress, it is Ok to ignore it since	 * the ASC will automatically cancel the command and flush	 * the FIFO if the ASC is reselected before the command starts.	 * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if	 * a reselect occurs before starting the command.	 */	asc->state = ASC_STATE_BUSY;	asc->target = target;	/* cache some pointers */	scsicmd = asc->cmd[target];	state = &asc->st[target];#ifdef DEBUG	if (asc_debug > 1) {		printf("asc_startcmd: %s target %d cmd %x len %d\n",			scsicmd->sd->sd_driver->d_name, target,			scsicmd->cmd[0], scsicmd->buflen);	}#endif	/*	 * Init the chip and target state.	 */	state->flags = state->flags & DID_SYNC;	state->error = 0;	state->script = (script_t *)0;	state->msg_out = SCSI_NO_OP;	/*	 * Copy command data to the DMA buffer.	 */	len = scsicmd->cmdlen;	state->dmalen = len;	bcopy(scsicmd->cmd, state->dmaBufAddr, len);	/* check for simple SCSI command with no data transfer */	if ((state->buflen = scsicmd->buflen) == 0) {		/* check for sync negotiation */		if ((scsicmd->flags & SCSICMD_USE_SYNC) &&		    !(state->flags & DID_SYNC)) {			asc->script = &asc_scripts[SCRIPT_TRY_SYNC];			state->flags |= TRY_SYNC;		} else			asc->script = &asc_scripts[SCRIPT_SIMPLE];		state->buf = (char *)0;	} else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) {		asc->script = &asc_scripts[SCRIPT_DATA_OUT];		state->buf = scsicmd->buf;		state->flags |= DMA_OUT;	} else {		asc->script = &asc_scripts[SCRIPT_DATA_IN];		state->buf = scsicmd->buf;		state->flags |= DMA_IN;	}#ifdef DEBUG	asc_debug_cmd = scsicmd->cmd[0];	if (scsicmd->cmd[0] == SCSI_READ_EXT) {		asc_debug_bn = (scsicmd->cmd[2] << 24) |			(scsicmd->cmd[3] << 16) |			(scsicmd->cmd[4] << 8) |			scsicmd->cmd[5];		asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8];	}	asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd);	asc_logp->target = asc->target;	asc_logp->state = asc->script - asc_scripts;	asc_logp->msg = SCSI_DIS_REC_IDENTIFY;	asc_logp->resid = scsicmd->buflen;	if (++asc_logp >= &asc_log[NLOG])		asc_logp = asc_log;#endif	/* preload the FIFO with the message to be sent */	regs->asc_fifo = SCSI_DIS_REC_IDENTIFY;	MachEmptyWriteBuffer();	/* initialize the DMA */	(*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE);	ASC_TC_PUT(regs, len);	readback(regs->asc_cmd);	regs->asc_dbus_id = target;	readback(regs->asc_dbus_id);	regs->asc_syn_p = state->sync_period;	readback(regs->asc_syn_p);	regs->asc_syn_o = state->sync_offset;	readback(regs->asc_syn_o);	if (state->flags & TRY_SYNC)		regs->asc_cmd = ASC_CMD_SEL_ATN_STOP;	else		regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA;	readback(regs->asc_cmd);}/* * Interrupt routine *	Take interrupts from the chip * * Implementation: *	Move along the current command's script if *	all is well, invoke error handler if not. */voidasc_intr(unit)	int unit;{	register asc_softc_t asc = &asc_softc[unit];	register asc_regmap_t *regs = asc->regs;	register State *state;	register script_t *scpt;	register int ss, ir, status;	/* collect ephemeral information */	status = regs->asc_status;again:	ss = regs->asc_ss;	ir = regs->asc_intr;	/* this resets the previous two */	scpt = asc->script;#ifdef DEBUG	asc_logp->status = PACK(unit, status, ss, ir);	asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1;	asc_logp->state = scpt - asc_scripts;	asc_logp->msg = -1;	asc_logp->resid = 0;	if (++asc_logp >= &asc_log[NLOG])		asc_logp = asc_log;	if (asc_debug > 2)		printf("asc_intr: status %x ss %x ir %x cond %d:%x\n",			status, ss, ir, scpt - asc_scripts, scpt->condition);#endif	/* check the expected state */	if (SCRIPT_MATCH(ir, status) == scpt->condition) {		/*		 * Perform the appropriate operation, then proceed.		 */		if ((*scpt->action)(asc, status, ss, ir)) {			regs->asc_cmd = scpt->command;			readback(regs->asc_cmd);			asc->script = scpt->next;		}		goto done;	}	/*	 * Check for parity error.	 * Hardware will automatically set ATN	 * to request the device for a MSG_OUT phase.	 */	if (status & ASC_CSR_PE) {		printf("asc%d: SCSI device %d: incomming parity error seen\n",			asc - asc_softc, asc->target);		asc->st[asc->target].flags |= PARITY_ERR;	}	/*	 * Check for gross error.	 * Probably a bug in a device driver.	 */	if (status & ASC_CSR_GE) {		printf("asc%d: SCSI device %d: gross error\n",			asc - asc_softc, asc->target);		goto abort;	}	/* check for message in or out */	if ((ir & ~ASC_INT_FC) == ASC_INT_BS) {		register int len, fifo;		state = &asc->st[asc->target];		switch (ASC_PHASE(status)) {		case ASC_PHASE_DATAI:		case ASC_PHASE_DATAO:			ASC_TC_GET(regs, len);			fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;			printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n",				state->buflen, state->dmalen, len, fifo);			goto abort;		case ASC_PHASE_MSG_IN:			break;		case ASC_PHASE_MSG_OUT:			/*			 * Check for parity error.			 * Hardware will automatically set ATN			 * to request the device for a MSG_OUT phase.			 */			if (state->flags & PARITY_ERR) {				state->flags &= ~PARITY_ERR;				state->msg_out = SCSI_MESSAGE_PARITY_ERROR;				/* reset message in counter */				state->msglen = 0;			} else				state->msg_out = SCSI_NO_OP;			regs->asc_fifo = state->msg_out;			regs->asc_cmd = ASC_CMD_XFER_INFO;			readback(regs->asc_cmd);			goto done;		case ASC_PHASE_STATUS:			/* probably an error in the SCSI command */			asc->script = &asc_scripts[SCRIPT_GET_STATUS];			regs->asc_cmd = ASC_CMD_I_COMPLETE;			readback(regs->asc_cmd);			goto done;		default:			goto abort;		}		if (state->script)			goto abort;		/* check for DMA in progress */		ASC_TC_GET(regs, len);		fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT;		/* flush any data in the FIFO */		if (fifo) {			if (state->flags & DMA_OUT)				len += fifo;			else if (state->flags & DMA_IN) {				u_char *cp;				printf("asc_intr: IN: dmalen %d len %d fifo %d\n",					state->dmalen, len, fifo); /* XXX */				len += fifo;				cp = state->dmaBufAddr + (state->dmalen - len);				while (fifo-- > 0)					*cp++ = regs->asc_fifo;			} else				printf("asc_intr: dmalen %d len %d fifo %d\n",					state->dmalen, len, fifo); /* XXX */			regs->asc_cmd = ASC_CMD_FLUSH;			readback(regs->asc_cmd);			DELAY(2);		}		if (len && (state->flags & DMA_IN_PROGRESS)) {			/* save number of bytes still to be sent or received */			state->dmaresid = len;			state->flags &= ~DMA_IN_PROGRESS;#ifdef DEBUG			if (asc_logp == asc_log)				asc_log[NLOG - 1].resid = len;			else				asc_logp[-1].resid = len;#endif			/* setup state to resume to */			if (state->flags & DMA_IN) {				/*				 * Since the ASC_CNFG3_SRB bit of the				 * cnfg3 register bit is not set,				 * we just transferred an extra byte.				 * Since we can't resume on an odd byte				 * boundary, we copy the valid data out				 * and resume DMA at the start address.				 */				if (len & 1) {					printf("asc_intr: msg in len %d (fifo %d)\n",						len, fifo); /* XXX */					len = state->dmalen - len;					goto do_in;				}				state->script =					&asc_scripts[SCRIPT_RESUME_DMA_IN];			} else if (state->flags & DMA_OUT)				state->script =					&asc_scripts[SCRIPT_RESUME_DMA_OUT];			else				state->script = asc->script;		} else if (state->flags & DMA_IN) {			if (len)				printf("asc_intr: 1: len %d (fifo %d)\n", len,					fifo); /* XXX */			/* setup state to resume to */			if (state->flags & DMA_IN_PROGRESS) {				len = state->dmalen;				state->flags &= ~DMA_IN_PROGRESS;			do_in:				(*asc->dma_end)(asc, state, ASCDMA_READ);				bcopy(state->dmaBufAddr, state->buf, len);				state->buf += len;				state->buflen -= len;			}			if (state->buflen)				state->script =				    &asc_scripts[SCRIPT_RESUME_IN];			else				state->script =				    &asc_scripts[SCRIPT_RESUME_NO_DATA];		} else if (state->flags & DMA_OUT) {			if (len)				printf("asc_intr: 2: len %d (fifo %d)\n", len,					fifo); /* XXX */			/*			 * If this is the last chunk, the next expected			 * state is to get status.			 */			if (state->flags & DMA_IN_PROGRESS) {				state->flags &= ~DMA_IN_PROGRESS;				(*asc->dma_end)(asc, state, ASCDMA_WRITE);				len = state->dmalen;				state->buf += len;				state->buflen -= len;			}			if (state->buflen)				state->script =				    &asc_scripts[SCRIPT_RESUME_OUT];			else				state->script =				    &asc_scripts[SCRIPT_RESUME_NO_DATA];		} else if (asc->script == &asc_scripts[SCRIPT_SIMPLE])			state->script = &asc_scripts[SCRIPT_RESUME_NO_DATA];		else			state->script = asc->script;		/* setup to receive a message */		asc->script = &asc_scripts[SCRIPT_MSG_IN];		state->msglen = 0;

⌨️ 快捷键说明

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