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

📄 esp.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
struct scsi_address *ap;char *cap;int val, tgtonly, doset;{	register struct esp *esp = (struct esp *) ap->a_cookie;	register cidx;	register u_char tshift = (1<<ap->a_target);	register u_char ntshift = ~tshift;	register rval = FALSE;	if ((tgtonly != 0 && tgtonly != 1) || cap == (char *) 0) {		return (rval);	}	for (cidx = 0; scsi_capstrings[cidx]; cidx++) {		if (strcmp(cap, scsi_capstrings[cidx]) == 0)			break;	}	if (scsi_capstrings[cidx] == (char *) 0) {		rval = UNDEFINED;	} else if (doset && (val == 0 || val == 1)) {		/*		 * At present, we can only set binary (0/1) values		 */		switch (cidx) {		case SCSI_CAP_DMA_MAX:		case SCSI_CAP_MSG_OUT:		case SCSI_CAP_PARITY:		case SCSI_CAP_INITIATOR_ID:			/*			 * None of these are settable via			 * the capability interface.			 */			break;		case SCSI_CAP_DISCONNECT:			if ((scsi_options & SCSI_OPTIONS_DR) == 0) {				break;			} else if (tgtonly) {				if (val)					esp->e_nodisc &= ntshift;				else					esp->e_nodisc |= tshift;			} else {				esp->e_nodisc = (val) ? 0 : 0xff;			}			rval = TRUE;			break;		case SCSI_CAP_SYNCHRONOUS:			if ((scsi_options & SCSI_OPTIONS_SYNC) == 0) {				break;			} else if (tgtonly) {				if (val) {					esp->e_weak &= ntshift;				} else {					esp->e_weak |= tshift;				}				esp->e_sync_known &= ntshift;			} else {				if (val) {					esp->e_weak = 0;				} else {					esp->e_weak = 0xff;				}				esp->e_sync_known = 0;			}			rval = TRUE;			break;		case SCSI_CAP_WIDE_XFER:		case SCSI_CAP_UNTAGGED_QING:		case SCSI_CAP_TAGGED_QING:		default:			rval = UNDEFINED;			break;		}	} else if (doset == 0) {		switch (cidx) {		case SCSI_CAP_DMA_MAX:			switch (DMAGA_REV(esp->e_dma)) {			default:			case DMA_REV1:			case DMA_REV2:			case ESC1_REV1:				rval = 1<<24;				break;			case DMA_REV3:				rval = 1<<30;				break;			}			break;		case SCSI_CAP_MSG_OUT:			rval = TRUE;			break;		case SCSI_CAP_DISCONNECT:			if ((scsi_options & SCSI_OPTIONS_DR) &&			    (tgtonly == 0 || (esp->e_nodisc & tshift) == 0)) {				rval = TRUE;			}			break;		case SCSI_CAP_SYNCHRONOUS:			if ((scsi_options & SCSI_OPTIONS_SYNC) &&			    (tgtonly == 0 || esp->e_offset[ap->a_target])) {				rval = TRUE;			}			break;		case SCSI_CAP_PARITY:			if (scsi_options & SCSI_OPTIONS_PARITY)				rval = TRUE;			break;		case SCSI_CAP_INITIATOR_ID:			rval = MY_ID(esp);			break;		default:			rval = UNDEFINED;			break;		}	}	return (rval);}static intesp_getcap(ap, cap, whom)struct scsi_address *ap;char *cap;int whom;{	return (esp_commoncap(ap, cap, 0, whom, 0));}static intesp_setcap(ap, cap, value, whom)struct scsi_address *ap;char *cap;int value, whom;{	return (esp_commoncap(ap, cap, value, whom, 1));}/* * Internal Search Routine. * * Search for a command to start. */static intesp_ustart(esp, start_slot)register struct esp *esp;short start_slot;{	register struct scsi_cmd *sp;	register short slot, found = 0;	char dkn;	if (start_slot == UNDEFINED)		start_slot = 0;	slot = start_slot;	/*	 * If all commands queued up here are	 * disconnected, there is no work to do.	 *	 * e_ndisc should always be <= e_ncmds.	 *	 */	if (esp->e_ncmds <= esp->e_ndisc) {		return (FALSE);	}	do {		sp = esp->e_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);	}	esp->e_cur_slot = slot;	if ((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;	}	return (esp_startcmd(esp));}/* * Start a command off */static intesp_startcmd(esp)register struct esp *esp;{	register struct espreg *ep = esp->e_reg;	register struct dmaga *dmar = esp->e_dma;	register struct scsi_cmd *sp = CURRENT_CMD(esp);	int legal_cmd_len, i;	u_char cmd, nstate, tshift, target;	register caddr_t tp = (caddr_t) esp->e_cmdarea;	/*	 * The only reason that this should happen	 * is if we have a re-selection attempt starting.	 */	if (INTPENDING(esp)) {		ESP_PREEMPT(esp);		LOG_STATE(ACTS_PREEMPTED, esp->e_stat, Tgt(sp), Lun(sp));		(void) esp_poll();		return (FALSE);	}	esp->e_sdtr = esp->e_omsglen = 0;	target = Tgt(sp);	tshift = 1<<target;#ifdef	ESPDEBUG	esp->e_xfer = sp->cmd_dmacount;#endif	/* ESPDEBUG */	/*	 * The ESP chip will only automatically	 * send 6, 10 or 12 byte SCSI cmds.	 */	switch (legal_cmd_len = sp->cmd_cdblen) {	case CDB_GROUP0:	case CDB_GROUP1:	case CDB_GROUP5:		break;	default:		legal_cmd_len = 0;		break;	}	if (((esp->e_targets & tshift) == 0) || (esp->e_nodisc & tshift) ||	    (sp->cmd_pkt.pkt_flags & FLAG_NODISCON) ||	    (scsi_options & SCSI_OPTIONS_DR) == 0) {		cmd = CMD_SEL_NOATN;		nstate = STATE_SELECT_NOATN;	} else {		/*		 * Okay, we're at least going to send an identify message.		 */		*tp++ = MSG_DR_IDENTIFY | Lun(sp);		if (sp->cmd_flags & CFLAG_CMDPROXY) {			/*			 * This is a proxy command. It will have			 * a message to send as part of post-selection			 * (e.g, MSG_ABORT or MSG_DEVICE_RESET)			 */			/*			 * XXX: We should check to make sure that			 * this is a valid PROXY command, i.e,			 * a  valid message length.			 */			esp->e_omsglen = sp->cmd_cdb[ESP_PROXY_DATA];			i = 0;			while (i < esp->e_omsglen) {				esp->e_cur_msgout[i] =				    sp->cmd_cdb[ESP_PROXY_DATA+1+i];				i++;			}			sp->cmd_cdb[ESP_PROXY_RESULT] = FALSE;			cmd = CMD_SEL_STOP;			nstate = STATE_SELECT_N_SENDMSG;			legal_cmd_len = 0;			LOG_STATE(ACTS_PROXY, esp->e_stat,				esp->e_cur_msgout[0], nstate);		} else if ((esp->e_sync_known & tshift) ||		    (scsi_options & SCSI_OPTIONS_SYNC) == 0) {			if (legal_cmd_len) {				cmd = CMD_SEL_ATN;				nstate = STATE_SELECT_NORMAL;			} else {				cmd = CMD_SEL_STOP;				nstate = STATE_SELECT_N_STOP;			}		} else {			/*			 * Set up to send an extended message after			 * we select and send the identify message.			 */			if (esp->e_weak & tshift) {				esp_make_sdtr(esp, 0, 0);			} else {				esp_make_sdtr(esp,				    (int) esp->e_default_period,				    (int) DEFAULT_OFFSET);			}			legal_cmd_len = 0;			cmd = CMD_SEL_STOP;			nstate = STATE_SELECT_N_SENDMSG;			LOG_STATE(ACTS_SYNCHOUT, esp->e_stat,				esp->e_default_period, DEFAULT_OFFSET);			/*			 * XXX: Set sync known here because the Sony CDrom			 * ignores the synch negotiation msg. Net effect			 * is we negotiate on every I/O request forever.			 */			esp->e_sync_known |= (1<<target);		}	}	/*	 * If we are a ESP100A or a ESP236, and in SCSI-2 mode	 * we could also load another message here.	 */	/*	 * Now load cdb (if any)	 */	for (i = 0; i < legal_cmd_len; i++) {		*tp++ = sp->cmd_cdbp[i];	}	if (legal_cmd_len) {		LOG_STATE(ACTS_CMD_START, esp->e_stat, sp->cmd_cdbp[0], nstate);	}	/*	 * calculate total dma amount:	 */	esp->e_lastcount = ((u_long) tp) - ((u_long) esp->e_cmdarea);	/*	 * load rest of chip registers	 */	ep->esp_busid = target;	ep->esp_sync_period = esp->e_period[target] & SYNC_PERIOD_MASK;	ep->esp_sync_offset = esp->e_offset[target] | esp->e_req_ack_delay;	if ((esp->e_type == FAS236) || (esp->e_type == FAS100A)) {		ep->esp_conf3 = esp->e_espconf3[target];	}	if ((scsi_options & SCSI_OPTIONS_PARITY) &&	    (sp->cmd_pkt.pkt_flags & FLAG_NOPARITY)) {		ep->esp_conf = esp->e_espconf & ~ESP_CONF_PAREN;	}	SET_ESP_COUNT(ep, esp->e_lastcount);	if (DMAGA_REV(dmar) == ESC1_REV1) {		SET_DMAESC_COUNT(dmar, esp->e_lastcount);	}	dmar->dmaga_addr = esp->e_lastdma =	    (((caddr_t)esp->e_cmdarea) - DVMA) | esp->e_dma_base;	if (DMAGA_REV(dmar) == ESC1_REV1) {		dmar->dmaga_csr |= (dmar->dmaga_csr & ~DMAGA_WRITE) |			(DMAGA_INTEN|DMAGA_ENDVMA);	} else {		dmar->dmaga_csr = (dmar->dmaga_csr & ~DMAGA_WRITE) |			(DMAGA_INTEN|DMAGA_ENDVMA);	}	if (dmar->dmaga_csr & DMAGA_INT_MASK) {		ESP_PREEMPT(esp);		LOG_STATE(ACTS_PREEMPTED, esp->e_stat, Tgt(sp), Lun(sp));		(void) esp_poll();		return (FALSE);	}	ep->esp_cmd = cmd | CMD_DMA;	New_state(esp, nstate);	LOG_STATE(nstate, esp->e_stat, target, Lun(sp));#ifdef	ESPDEBUG	if (DEBUGGING) {		eprintf(esp, "sel %d.%d cmd[ ", target, Lun(sp));		for (i = 0; i < sp->cmd_cdblen; i++)			printf("0x%x ", sp->cmd_cdbp[i]&0xff);		printf("]\n\tstate=%s\n", esp_state_name(esp->e_state));	}#endif	/* ESPDEBUG */	return (TRUE);}static intesp_link_start(esp)register struct esp *esp;{	esp->e_nlinked++;	if ((esp->e_stat & ESP_PHASE_MASK) != ESP_PHASE_COMMAND) {		esp->e_stat = esp->e_reg->esp_stat & ~ESP_STAT_RES;	}	if ((esp->e_stat & ESP_PHASE_MASK) != ESP_PHASE_COMMAND) {		/*		 * XXX need a way to mark this particular failure		 */		esp_printstate(esp, "Linked command not in command phase");		/*		 * XXX: Needs to be 'soft' abort		 */		return (ACTION_ABORT_CURCMD);	}	/*	 * we'll let esp_phasemanage do the dirty work from here on out...	 */	New_state(esp, ACTS_CMD_START);	return (ACTION_PHASEMANAGE);}/* * Finish routines */static intesp_finish(esp)register struct esp *esp;{	short last_slot;	register int span_states = 0;	register struct scsi_cmd *sp = CURRENT_CMD(esp);	register action;	char dkn;	if ((dkn = sp->cmd_pkt.pkt_pmon) >= 0) {		dk_busy &= ~(1<<dkn);	}	last_slot = esp->e_last_slot = esp->e_cur_slot;	esp->e_cur_slot = UNDEFINED;	esp->e_ncmds -= 1;#ifdef	ESPDEBUG	if (DEBUGGING) {		eprintf(esp, "%d.%d; cmds=%d disc=%d npoll=%d; lastmsg 0x%x\n",			Tgt(sp), Lun(sp), esp->e_ncmds, esp->e_ndisc,			esp->e_npolling, esp->e_last_msgin);		printf("\treason '%s'; cmd state 0x%b\n",			scsi_rname(sp->cmd_pkt.pkt_reason),			sp->cmd_pkt.pkt_state, state_bits);	}#endif	/* ESPDEBUG */	if (esp->e_last_msgin == MSG_LINK_CMPLT ||	    esp->e_last_msgin == MSG_LINK_CMPLT_FLAG) {		span_states++;	}	/*	 * XXX: ELSE WE NEED TO SET SPAN_STATES FOR COMMANDS COMPLETING	 * XXX: WITH A CHECK CONDITION.	 */	if ((sp->cmd_pkt.pkt_state & STATE_GOT_STATUS) &&	    ((struct scsi_status *) sp->cmd_pkt.pkt_scbp)->sts_chk) {		/*		 * In the case that we are getting a check condition		 * clear our knowledge of synchronous capabilities.		 * This will unambiguously force a renegotiation		 * prior to any possible data transfer (we hope),		 * including the data transfer for a UNIT ATTENTION		 * condition generated by somebody powering on and		 * off a target.		 */		if (esp->e_offset[Tgt(sp)] != 0) {			esp->e_sync_known &= ~(1<<Tgt(sp));		}	}	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("esp_finish: more than one segment with data");			/* NOTREACHED */		}		/*		 * Walk through all data segments and count up transfer counts		 */		i = 0;		segtmp = &sp->cmd_subseg;		while (segtmp) {			i += segtmp->d_count;			segtmp = segtmp->d_next;		}		sp->cmd_pkt.pkt_resid = sp->cmd_dmacount - i;#ifdef	ESPDEBUG		if (INFORMATIVE && sp->cmd_pkt.pkt_resid) {			eprintf(esp, "%d.%d finishes with %d resid\n",				Tgt(sp), Lun(sp), sp->cmd_pkt.pkt_resid);		}#endif	/* ESPDEBUG */	}	New_state(esp, STATE_FREE);	esp->e_slots[last_slot] = (struct scsi_cmd *) 0;	if (sp->cmd_pkt.pkt_flags & FLAG_NOINTR) {		esp->e_npolling -= 1;		(*sp->cmd_pkt.pkt_comp)(sp);		action = ACTION_RETURN;	} else if (span_states > 0) {		/*		 * If we're going to start a linked command,		 * hold open the state of the host adapter...		 */		esp->e_state = ACTS_SPANNING;		(*sp->cmd_pkt.pkt_comp)(sp);		esp->e_state = STATE_FREE;		/*		 * 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 (esp->e_slots[last_slot] == 0) {			/*			 * XXX: HERE IS WHERE WE NEED A PROXY COMMAND IN			 * XXX: IN ORDER TO SEND AN ABORT OPERATION MESSAGE			 * XXX: TO THE TARGET!!!			 */			esplog(esp, LOG_ERR,

⌨️ 快捷键说明

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