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

📄 esp.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			    "linked command not started by driver");			action = ACTION_RESET;		} else {			esp->e_cur_slot = last_slot;			action = esp_link_start(esp);		}	} else {		(*sp->cmd_pkt.pkt_comp)(sp);		action = ACTION_SEARCH;	}	return (action);}/* * Interrupt Service Section *//* * Poll for command completion (i.e., no interrupts) * time is in usec (and will not be very accurate) */static intesp_dopoll(esp, limit)register struct esp *esp;int limit;{	register int i;	/*	 * timeout is not very accurate since we don't know how	 * long the poll takes	 * also if the packet gets started fairly late, we may	 * timeout prematurely	 */	if (limit == 0)		limit = POLL_TIMEOUT;	for (i = 0; i < limit; i += 100) {		if (esp_poll() == 0)			DELAY(100);		if (esp->e_state == STATE_FREE)			break;	}	if (i >= limit && esp->e_state != STATE_FREE) {		esp_printstate(esp, "polled command timeout");		return (-1);	}	return (0);}/* * Autovector Interrupt Entry Point. */static intesp_poll(){	register struct esp *esp;	register int serviced = 0;	register int search = TRUE;	if (esp_softc == (struct esp *) 0)		return (serviced);	while (search == TRUE) {		search = FALSE;		for (esp = esp_softc; esp != (struct esp *) 0;		    esp = esp->e_next) {			if (esp->e_tran.tran_start) {				register s = splr(esp->e_tran.tran_spl);#ifdef	sun4m				/*				 * If s > e_tran.tran_spl, it must be either				 * boot or dump time, or a polled command,				 * so just do it!				 */				if ((s <= esp->e_tran.tran_spl) &&				    (esp->e_npolling == 0)) {					if (s != esp->e_spl) {						(void) splx(s);						continue;					}				}#endif /* sun4m */				if (INTPENDING(esp)) {					espsvc(esp);					serviced |= (1<<(CNUM));					search = TRUE;				}				(void) splx(s);			}		}	}	if (serviced) {		/*		 * Did we service more than one host		 * adapter for this hardware interrupt?		 */		if (serviced & (serviced-1)) {			esp_nmultsvc++;		}		/*		 * Record the fact that we fielded a hard interrupt		 */		esp_nhardints++;		serviced = 1;	}	return (serviced);}#ifdef	VECTORED_INTERRUPTS/* * Vectored interrupt entry point */static intesp_intr(esp)struct esp *esp;{	register s = splr(esp->e_tran.tran_spl);	if (INTPENDING(esp)) {		espsvc(esp);	}	(void) splx(s);}#endif	/* VECTORED_INTERRUPTS *//* * General interrupt service routine. */static voidespsvc(esp)register struct esp *esp;{	static int (*evec[])() = {		esp_finish_select,		esp_reconnect,		esp_phasemanage,		esp_finish,		esp_reset_recovery,		esp_istart,		esp_abort_curcmd,		esp_abort_allcmds,		esp_reset_bus,		esp_handle_selection	};	register int action;	register u_char intr;	register struct espreg *ep = esp->e_reg;	register struct dmaga *dmar = esp->e_dma;	/*	 * Make sure that the DMAGA is *not* still active.	 * If we don't disable further interrupts, we	 * get Bus timeouts in trying to access the ESP	 * chip for Rev-1 DMA gate arrays.	 */	if (DMAGA_REV(dmar) == DMA_REV1) {		dmar->dmaga_csr &= ~DMAGA_INTEN;	}#ifdef	ESPDEBUG	if (DEBUGGING) {		eprintf (esp, "dma csr 0x%b addr 0x%x\n",		    esp->e_dma->dmaga_csr, dmaga_bits, esp->e_dma->dmaga_addr);	}#endif	/* ESPDEBUG */	/*	 * A read of ESP interrupt register clears interrupt,	 * so any other volatile information needs to be latched	 * up prior to reading the interrupt register.	 */	/*	 * Even if we aren't in STATE_SELECTING, latch	 * up the step register (for future handling	 * of being in target mode operation)	 */	esp->e_step = (ep->esp_step & ESP_STEP_MASK);	esp->e_stat = ep->esp_stat;	esp->e_intr = intr = ep->esp_intr;	/*	 * unclear what could cause a gross error;	 * most of the time we get a data overrun after this.	 */	if (esp->e_stat & ESP_STAT_GERR) {		esplog(esp, LOG_ERR,		    "gross error in esp status (%x)", esp->e_stat);		IPRINTF5(		    "esp_cmd=%x, stat=%x, intr=%x, step=%x, fifoflag=%x\n",		    ep->esp_cmd, esp->e_stat, esp->e_intr, esp->e_step,		    ep->esp_fifo_flag);		if (esp->e_cur_slot != UNDEFINED) {			struct scsi_cmd *sp = CURRENT_CMD(esp);			if (sp->cmd_pkt.pkt_reason == CMD_CMPLT) {				sp->cmd_pkt.pkt_reason = CMD_TRAN_ERR;			}		} else {			action = ACTION_ABORT_ALLCMDS;			goto start_action;		}	}	/*	 * was there a dmaga error that caused espsvc() to be called?	 */	if (esp->e_dma->dmaga_csr & DMAGA_ERRPEND) {		/*		 * It would be desirable to set the ATN* line and attempt to		 * do the whole schmear of INITIATOR DETECTED ERROR here,		 * but that is too hard to do at present.		 */		esplog(esp, LOG_ERR, "Unrecoverable DMA error on dma");		if (esp->e_cur_slot != UNDEFINED) {			struct scsi_cmd *sp = CURRENT_CMD(esp);			if (sp->cmd_pkt.pkt_reason == CMD_CMPLT)				sp->cmd_pkt.pkt_reason = CMD_TRAN_ERR;			action = ACTION_RESET;			goto start_action;		}	}	/*	 * While some documentation claims that the	 * ESP100A's msb in the stat register is an	 * INTERRUPT PENDING bit, an errata sheet	 * warned that you shouldn't depend on that	 * being so (unless you're an ESP-236)	 */	if (esp->e_type != ESP236) {		esp->e_stat &= ~ESP_STAT_RES;	}#ifdef	ESPDEBUG	if (DEBUGGING) {		esp_stat_int_print(esp);		printf("\tState %s Laststate %s\n",			esp_state_name(esp->e_state),			esp_state_name(esp->e_laststate));	}#endif	/* ESPDEBUG */	/*	 * Based upon the current state of the host adapter driver	 * we should be able to figure out what to do with an interrupt.	 * We have several possible interrupt sources, some of them	 * modified by various status conditions.	 *	 * Basically, we'll get an interrupt through the dma gate array	 * for one or more of the following three conditions:	 *	 *	1. The ESP is asserting an interrupt request.	 *	 *	2. The dma gate array counter has reached zero	 *	   and TERMINAL COUNT interrupts have been enabled.	 *	 *	3. There has been a memory exception of some kind.	 *	 * In the latter two cases we are either in one of the SCSI	 * DATA phases or are using dma in sending a command to a	 * target. We will let the various handlers for these kind	 * of states decode any error conditions in the gate array.	 *	 * The ESP asserts an interrupt with one or more of 8 possible	 * bits set in its interrupt register. These conditions are	 * SCSI bus reset detected, an illegal command fed to the ESP,	 * one of DISCONNECT, BUS SERVICE, FUNCTION COMPLETE conditions	 * for the ESP, a Reselection interrupt, or one of Selection	 * or Selection with Attention.	 *	 * Of these possible interrupts, we can deal with some right	 * here and now, irrespective of the current state of the driver.	 *	 */	if (intr & ESP_INT_RESET) {		/*		 * If we detect a SCSI reset, we blow away the current		 * command (if there is one) and all disconnected commands		 * because we now don't know the state of them at all.		 */		action = ACTION_FINRST;	} else if (intr & ESP_INT_ILLEGAL) {		/*		 * This should not happen. The one situation where		 * we can get an ILLEGAL COMMAND interrupt is due to		 * a bug in the ESP100 during reselection which we		 * should be handling in esp_reconnect().		 */		esp_printstate (esp, "ILLEGAL bit set");		action = ACTION_ABORT_CURCMD;	} else if (intr & (ESP_INT_SEL|ESP_INT_SELATN)) {		action = ACTION_SELECT;	} else if (intr & ESP_INT_RESEL) {		if (esp->e_state & STATE_SELECTING) {			action = ACTION_FINSEL;		} else if (esp->e_state != STATE_FREE) {			/*			 * this 'cannot happen'.			 */			esp_printstate(esp, "illegal reselection");			action = ACTION_RESET;		} else {			action = ACTION_RESEL;		}	} else {		/*		 * The rest of the reasons for an interrupt, including		 * interrupts just from the dma gate array itself, can		 * be handled based purely on the state that the driver		 * is currently in now.		 */		if (esp->e_state & STATE_SELECTING) {			action = ACTION_FINSEL;		} else if (esp->e_state & STATE_ITPHASES) {			action = ACTION_PHASEMANAGE;		} else {#ifdef	ESPDEBUG			if (INFORMATIVE) {				esp_printstate(esp, "spurious interrupt");			}#endif	/* ESPDEBUG */			esplog(esp, LOG_ERR, "spurious interrupt");			action = ACTION_RETURN;		}	}start_action:	while (action != ACTION_RETURN) {		action = (*evec[action])(esp);	}	/*	 * Reenable interrupts for the DMA gate array	 */	if (DMAGA_REV(dmar) == DMA_REV1) {		dmar->dmaga_csr |= DMAGA_INTEN;	}}/* * Manage phase transitions. */static intesp_phasemanage(esp)struct esp *esp;{	register u_char state;	register int action;	static int (*pvecs[])() = {		esp_handle_cmd_start,		esp_handle_cmd_done,		esp_handle_msg_out,		esp_handle_msg_out_done,		esp_handle_msg_in,		esp_handle_more_msgin,		esp_handle_msg_in_done,		esp_handle_clearing,		esp_handle_data,		esp_handle_data_done,		esp_handle_c_cmplt	};	do {		state = esp->e_state;		if (state == ACTS_UNKNOWN) {			action = esp_handle_unknown(esp);		} else if (state == STATE_FREE || state > ACTS_ENDVEC) {			esplog(esp, LOG_ERR, "lost state in phasemanage");			action = ACTION_ABORT_ALLCMDS;		} else {			action = (*pvecs[state-1]) (esp);		}	} while (action == ACTION_PHASEMANAGE);	return (action);}static intesp_handle_unknown(esp)register struct esp *esp;{	register u_char newstate;	if (esp->e_intr & ESP_INT_DISCON) {		/*		 * Okay. What to do now? Let's try (for the time being)		 * assuming that the target went south and dropped busy,		 * as a disconnect implies that either we received		 * a completion or a disconnect message, or that we		 * had sent an ABORT OPERATION or BUS DEVICE RESET		 * message. In either case, we expected the disconnect		 * and should have fielded it elsewhere.		 *		 * If we see a chip disconnect here, this is an unexpected		 * loss of BSY*. Clean up the state of the chip and return.		 *		 */#ifdef	ESPDEBUG		if (INFORMATIVE) {			esp_printstate(esp, "unexpected bus free");		}#endif	/* ESPDEBUG */		esp_chip_disconnect(esp);		CURRENT_CMD(esp)->cmd_pkt.pkt_reason = CMD_UNX_BUS_FREE;		LOG_STATE(ACTS_CMD_LOST, esp->e_stat, esp->e_xfer, -1);		return (ACTION_FINISH);	}	switch (esp->e_stat & ESP_PHASE_MASK) {	case ESP_PHASE_DATA_IN:	case ESP_PHASE_DATA_OUT:		newstate = ACTS_DATA;		break;	case ESP_PHASE_MSG_OUT:		newstate = ACTS_MSG_OUT;		break;	case ESP_PHASE_MSG_IN:		newstate = ACTS_MSG_IN;		break;	case ESP_PHASE_STATUS:		esp->e_reg->esp_cmd = CMD_FLUSH;#ifdef	ESP_TEST_PARITY		if (esp_ptest_status & (1<<Tgt(CURRENT_CMD(esp)))) {			esp->e_reg->esp_cmd = CMD_SET_ATN;		}#endif	/* ESP_TEST_PARITY */		esp->e_reg->esp_cmd = CMD_COMP_SEQ;		esp->e_state = ACTS_C_CMPLT;		LOG_STATE(ACTS_C_CMPLT, esp->e_stat, -1, -1);		return (ACTION_RETURN);	case ESP_PHASE_COMMAND:		newstate = ACTS_CMD_START;		break;	default:		esp_printstate(esp, "Unknown bus phase");		return (ACTION_RESET);	}	esp->e_state = newstate;	return (ACTION_PHASEMANAGE);}static intesp_handle_cmd_start(esp)struct esp *esp;{	register struct espreg *ep = esp->e_reg;	struct scsi_cmd *sp = CURRENT_CMD(esp);	register u_long cmd_distance;	/*	 * Check for command overflow.	 */	cmd_distance = (u_long) sp->cmd_cdbp - (u_long) sp->cmd_pkt.pkt_cdbp;	if (cmd_distance > (u_long) sp->cmd_cdblen) {		sp->cmd_pkt.pkt_reason = CMD_CMD_OVR;		return (ACTION_ABORT_CURCMD);	}	if (cmd_distance == 0) {		LOG_STATE(ACTS_CMD_START, esp->e_stat, sp->cmd_cdbp[0], -1);	}	/*	 * Stuff next command byte into fifo	 */	ep->esp_cmd = CMD_FLUSH;	SET_ESP_COUNT(ep, 1);	ep->esp_fifo_data = *(sp->cmd_cdbp++);	ep->esp_cmd = CMD_TRAN_INFO;	New_state(esp, ACTS_CMD_DONE);	return (ACTION_RETURN);}static intesp_handle_cmd_done(esp)register struct esp *esp;{	register struct scsi_cmd *sp = CURRENT_CMD(esp);	register u_char intr = esp->e_intr;	/*	 * The NOP command is required following a COMMAND	 * or MESSAGE OUT phase in order to unlatch the	 * FIFO flags register. This is needed for all	 * ESP chip variants.	 */	esp->e_reg->esp_cmd = CMD_NOP;	/*	 * We should have gotten a BUS SERVICE interrupt.	 * If it isn't that, and it isn't a DISCONNECT	 * interrupt, we have a "cannot happen" situation.	 */	if ((intr & ESP_INT_BUS) == 0) {		if ((intr & ESP_INT_DISCON) == 0) {			esp_printstate(esp, "cmd transmission error");			return (ACTION_ABORT_CURCMD);		}	} else {		sp->cmd_pkt.pkt_state |= STATE_SENT_CMD;	}	New_state(esp, ACTS_UNKNOWN);	return (ACTION_PHASEMANAGE);}/* * Begin to send a message out */static int

⌨️ 快捷键说明

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