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

📄 esp.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
esp_handle_msg_out(esp)register struct esp *esp;{	register i;	register struct scsi_cmd *sp = CURRENT_CMD(esp);	register struct espreg *ep = esp->e_reg;	/*	 * Check to make *sure* that we are really	 * in MESSAGE OUT phase. If the last state	 * was ACTS_MSG_OUT_DONE, then we are trying	 * to resend a message that the target stated	 * had a parity error in it.	 *	 * If this is the case, and mark completion reason as CMD_NOMSGOUT.	 * XXX: Right now, we just *drive* on. Should we abort the command?	 */	if ((esp->e_stat & ESP_PHASE_MASK) != ESP_PHASE_MSG_OUT &&	    esp->e_laststate == ACTS_MSG_OUT_DONE) {		esplog(esp, LOG_WARNING,		    "Target %d refused message resend", Tgt(sp));		sp->cmd_pkt.pkt_reason = CMD_NOMSGOUT;		New_state(esp, ACTS_UNKNOWN);		return (ACTION_PHASEMANAGE);	}	/*	 * Clean the fifo.	 */	ep->esp_cmd = CMD_FLUSH;	/*	 * See if we have a valid message to send	 */	if (esp->e_omsglen == 0) {		/*		 * no valid message? Send a no-op anyway...		 */		esp->e_cur_msgout[0] = MSG_NOP;		esp->e_omsglen = 1;	}	for (i = 0; i < esp->e_omsglen; i++) {		ep->esp_fifo_data = esp->e_cur_msgout[i];	}	ep->esp_cmd = CMD_TRAN_INFO;#ifdef	ESPDEBUG	if (DEBUGGING) {		eprintf(esp, "msg out: %s", scsi_mname(esp->e_cur_msgout[0]));		for (i = 1; i < esp->e_omsglen; i++)			printf(" %x", esp->e_cur_msgout[i]);		printf("\n");	}#endif	/* ESPDEBUG */	New_state(esp, ACTS_MSG_OUT_DONE);	return (ACTION_RETURN);}static intesp_handle_msg_out_done(esp)register struct esp *esp;{	register struct scsi_cmd *sp = CURRENT_CMD(esp);	register struct espreg *ep = esp->e_reg;	register u_char msgout, phase, fifocnt;	register int target = Tgt(sp);	msgout = esp->e_cur_msgout[0];	/*	 * If the ESP disconnected, then the message we sent caused	 * the target to decide to drop BSY* and clear the bus.	 */	if (esp->e_intr == ESP_INT_DISCON) {		if (msgout == MSG_DEVICE_RESET || msgout == MSG_ABORT) {			esp_chip_disconnect(esp);			if (msgout == MSG_DEVICE_RESET) {				esp->e_offset[target] = 0;				esp->e_sync_known &= ~(1<<target);			}			EPRINTF2 ("Succesful %s message to target %d\n",			    scsi_mname(msgout), target);			sp->cmd_pkt.pkt_reason = CMD_CMPLT;			if (sp->cmd_flags & CFLAG_CMDPROXY) {				sp->cmd_cdb[ESP_PROXY_RESULT] = TRUE;			}			return (ACTION_FINISH);		}		/*		 * If the target dropped busy on any other message, it		 * wasn't expected. We will let the code in esp_phasemanage()		 * handle this unexpected bus free event.		 */		goto out;	}	/*	 * What phase have we transitioned to?	 */	phase = esp->e_stat & ESP_PHASE_MASK;	/*	 * Save current fifo count	 */	fifocnt = FIFO_CNT(ep);	/*	 * As per the ESP errata sheets, this must be done for	 * all ESP chip variants.	 *	 * This releases the FIFO counter from its latched state.	 * Note that we read the fifo counter above prior to doing	 * this.	 */	ep->esp_cmd = CMD_NOP;	/*	 * Clean the fifo? Yes, if and only if we haven't	 * transitioned to Synchronous DATA IN phase.	 * The ESP chip manual notes that in the case	 * that the target has shifted to Synchronous	 * DATA IN phase, that while the FIFO count	 * register stays latched up with the number	 * of bytes not transferred out, that the fifo	 * itself is cleared and will contain only	 * the incoming data bytes.	 *	 * The manual doesn't state what happens in	 * other receive cases (transition to STATUS,	 * MESSAGE IN, or asynchronous DATA IN phase),	 * but I'll assume that there is probably	 * a single-byte pad between the fifo and	 * the SCSI bus which the ESP uses to hold	 * the currently asserted data on the bus	 * (known valid by a true REQ* signal). In	 * the case of synchronous data in, up to	 * 15 bytes of data could arrive, so the	 * ESP must have to make room for by clearing	 * the fifo, but in other cases it can just	 * hold the current byte until the next	 * ESP chip command that would cause a	 * data transfer.	 */	if (fifocnt != 0 && (phase != ESP_PHASE_DATA_IN ||	    esp->e_offset[target] == 0)) {		ep->esp_cmd = CMD_FLUSH;	}	/*	 * If we finish sending a message out, and we are	 * still in message out phase, then the target has	 * detected one or more parity errors in the message	 * we just sent and it is asking us to resend the	 * previous message.	 */	if ((esp->e_intr & ESP_INT_BUS) && phase == ESP_PHASE_MSG_OUT) {		/*		 * As per SCSI-2 specification, if the message to		 * be re-sent is greater than one byte, then we		 * have to set ATN*.		 */		if (esp->e_omsglen > 1) {			ep->esp_cmd = CMD_SET_ATN;		}		esplog(esp, LOG_ERR,		    "SCSI bus MESSAGE OUT phase parity error");		sp->cmd_pkt.pkt_statistics |= STAT_PERR;		New_state(esp, ACTS_MSG_OUT);		return (ACTION_PHASEMANAGE);	}	/*	 * Count that we sent a SYNCHRONOUS DATA TRANSFER message.	 */	if (esp->e_omsglen == 5 && msgout == MSG_EXTENDED &&	    esp->e_cur_msgout[2] == MSG_SYNCHRONOUS) {		esp->e_sdtr++;	}out:	esp->e_last_msgout = msgout;	esp->e_omsglen = 0;	New_state(esp, ACTS_UNKNOWN);	return (ACTION_PHASEMANAGE);}static intesp_handle_clearing(esp)register struct esp *esp;{	register struct scsi_cmd *sp = CURRENT_CMD(esp);	register action;	register u_char lmsg = esp->e_last_msgin;	if (esp->e_intr != ESP_INT_DISCON) {		if (lmsg != MSG_LINK_CMPLT && lmsg != MSG_LINK_CMPLT_FLAG) {			/*			 * If the chip/target didn't disconnect from the			 * bus, that is a gross fatal error.			 */			esplog (esp, LOG_WARNING,			    "Target %d didn't disconnect after sending %s",			    Tgt(sp), scsi_mname(lmsg));			sp->cmd_pkt.pkt_reason = CMD_TRAN_ERR;			return (ACTION_ABORT_CURCMD);		} else {			/*			 * In this case, the last message in was a 'linked			 * command complete' message and the target stays			 * connected. We don't fiddle with any of the			 * settings on the ESP chip. We return state			 * such that the completing command is finished			 * up and depend upon the finish routine to			 * handle the case that a new command has to			 * be available to start right away for this target.			 */			esp->e_last_msgout = 0xff;			esp->e_omsglen = 0;			return (ACTION_FINISH);		}	}	/*	 * At this point the ESP chip has disconnected. The bus should	 * be either quiet or someone may be attempting a reselection	 * of us (or somebody else). Call the routine the sets the	 * chip back to a correct and known state.	 */	esp_chip_disconnect(esp);	/*	 * If the last message in was a disconnect, search	 * for new work to do, else return to call esp_finish()	 */	if (lmsg == MSG_DISCONNECT) {		sp->cmd_pkt.pkt_statistics |= STAT_DISCON;		sp->cmd_flags |= CFLAG_CMDDISC;		esp->e_disconnects++;		esp->e_ndisc++;		New_state(esp, STATE_FREE);		esp->e_last_slot = esp->e_cur_slot;		esp->e_cur_slot = UNDEFINED;		action = ACTION_SEARCH;		EPRINTF2 ("disconnecting %d.%d\n", Tgt(sp), Lun(sp));	} else {		action = ACTION_FINISH;	}	esp->e_last_msgout = 0xff;	esp->e_omsglen = 0;	return (action);}static intesp_handle_data(esp)struct esp *esp;{	register i;	struct espreg *ep = esp->e_reg;	struct dmaga *dmar = esp->e_dma;	struct scsi_cmd *sp = CURRENT_CMD(esp);	register int sending;	if (IS_53C90(esp)) {		ep->esp_cmd = CMD_NOP;	/* per ESP errata sheet */	}	if ((sp->cmd_flags & CFLAG_DMAVALID) == 0) {		esp_printstate(esp, "unexpected data phase");		/*		 * XXX: This isn't the right reason		 */		sp->cmd_pkt.pkt_reason = CMD_TRAN_ERR;		return (ACTION_ABORT_CURCMD);	} else {		sending = (sp->cmd_flags & CFLAG_DMASEND)? 1 : 0;	}	if (sp->cmd_flags & CFLAG_NEEDSEG) {		/*		 * We can currently handle truncating the current		 * subsegment (in case a restore pointers is followed		 * by a re-entry into data phase). XXX Else we die		 * horribly XXX		 */		register struct dataseg *segp = sp->cmd_cursubseg;		IPRINTF3 ("data new seg: datap 0x%x base 0x%x count 0x%x\n",		    sp->cmd_data, segp->d_base, segp->d_count);		if (sp->cmd_data >= segp->d_base &&		    (sp->cmd_data < (segp->d_base + segp->d_count))) {			/*			 * We are backing up within the current			 * segment. Adjust the count field of the			 * current segment to reflect that we			 * only got 'this far' with it to date.			 */			segp->d_count = sp->cmd_data - segp->d_base;			sp->cmd_flags ^= CFLAG_NEEDSEG;		} else {			/*			 * XXX: bad bad bad...			 */			panic("need new seg in esp");			/* NOTREACHED */		}	}	i = scsi_chkdma(sp, ESP_MAX_DMACOUNT);	if (i == 0) {		esp_printstate(esp, "data transfer overrun");		sp->cmd_pkt.pkt_reason = CMD_DATA_OVR;		/*		 * A fix for bug id 1048141- if we get data transfer		 * overruns, assume we have a weak scsi bus. Note that		 * this won't catch consistent underruns or other		 * noise related syndromes.		 */		esp_sync_backoff(esp, sp);		return (ACTION_ABORT_CURCMD);	}	esp->e_lastcount = i;#ifdef	ESPDEBUG	esp->e_xfer = i;#endif	/* ESPDEBUG */#ifdef	sun4m	if (sp->cmd_flags & CFLAG_DMAKEEP) {		dmar->dmaga_addr = esp->e_lastdma =		    (btop(sp->cmd_data) < dvmasize) ?		    (sp->cmd_data | esp->e_dma_base) : sp->cmd_data;	} else {		dmar->dmaga_addr = esp->e_lastdma =		    (btop(sp->cmd_data) < BIGSBUSMAP_SIZE) ?		    (sp->cmd_data | BIGSBUSDVMA_BASE) : sp->cmd_data;	}#else	/* sun4m */	dmar->dmaga_addr = esp->e_lastdma =	    (btop(sp->cmd_data) < dvmasize) ?	    (sp->cmd_data | esp->e_dma_base) : sp->cmd_data;#endif	/* sun4m */	SET_ESP_COUNT(ep, i);	if (DMAGA_REV(dmar) == ESC1_REV1) {		SET_DMAESC_COUNT(dmar, i);	}	EPRINTF4 ("%d.%d cmd 0x%x to xfer %x\n", Tgt(sp), Lun(sp),	    sp->cmd_pkt.pkt_cdbp[0], i);	if ((esp->e_stat & ESP_PHASE_MASK) == ESP_PHASE_DATA_OUT) {		if (!sending) {			esplog(esp, LOG_ERR,			    "unwanted data out for Target %d", Tgt(sp));			sp->cmd_pkt.pkt_reason = CMD_DMA_DERR;			return (ACTION_ABORT_CURCMD);		}		LOG_STATE(ACTS_DATAOUT, esp->e_stat, i, -1);	} else {		if (sending) {			esplog (esp, LOG_ERR,			    "unwanted data in for Target %d", Tgt(sp));			sp->cmd_pkt.pkt_reason = CMD_DMA_DERR;			return (ACTION_ABORT_CURCMD);		}		dmar->dmaga_csr |= DMAGA_WRITE;		LOG_STATE(ACTS_DATAIN, esp->e_stat, i, -1);	}#ifdef	ESP_TEST_PARITY	if (!sending && (esp_ptest_data_in & (1<<Tgt(sp)))) {		ep->esp_cmd = CMD_SET_ATN;	}#endif	/* ESP_TEST_PARITY */	dmar->dmaga_csr |= DMAGA_ENDVMA|DMAGA_INTEN;	ep->esp_cmd = CMD_TRAN_INFO|CMD_DMA;	New_state(esp, ACTS_DATA_DONE);	return (ACTION_RETURN);}static intesp_handle_data_done(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);	register u_long xfer_amt;	char spurious_data, do_drain_fifo, was_sending;	register u_char stat, tgt, fifoamt;	tgt = Tgt(sp);	stat = esp->e_stat;	was_sending = (sp->cmd_flags & CFLAG_DMASEND) ? 1 : 0;	spurious_data = do_drain_fifo = 0;	/*	 * Check for DMAGA errors (parity or memory fault)	 */	if (dmar->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 %s",		    (was_sending) ? "send" : "receive");		sp->cmd_pkt.pkt_reason = CMD_TRAN_ERR;		return (ACTION_RESET);	}	/*	 * Data Receive conditions:	 *	 * Check for parity errors. If we have a parity error upon	 * receive, the ESP chip has asserted ATN* for us already.	 *	 * For Rev-1 and Rev-2 dma gate arrayts,	 * make sure the last bytes have flushed.	 */	if (!was_sending) {#ifdef	ESP_TEST_PARITY		if (esp_ptest_data_in & (1<<tgt)) {			esp_ptest_data_in = 0;			stat |= ESP_STAT_PERR;		}#endif	/* ESP_TEST_PARITY */		if (stat & ESP_STAT_PERR) {			esplog (esp, LOG_ERR,			    "SCSI bus DATA IN phase parity error");			esp->e_cur_msgout[0] = MSG_INITIATOR_ERROR;			esp->e_omsglen = 1;			sp->cmd_pkt.pkt_statistics |= STAT_PERR;		}		xfer_amt = 0;		/*		 * For DMA gate arrays, the PACKCNT field of the DMA		 * CSR register indicates how many bytes are still		 * latched up and need to be drained to memory.		 *		 * For the DMA+ CSR, the PACKCNT field will either		 * be zero or non-zero, indicating a empty/non-empty		 * D_CACHE. The DRAIN bit has no effect.		 *		 * The DMA2 CSR (as of right now- 6/1/90) actually		 * requires a write to the CSR register to force		 * the drain of the D_CACHE, so the practice of		 * writing the otherwise null-effect DRAIN bit is		 * still required.		 */		while (DMAGA_NPACKED(dmar) != 0 && xfer_amt < 100) {			if (DMAGA_REV(dmar) != ESC1_REV1) {				dmar->dmaga_csr |= DMAGA_DRAIN;			}			DELAY(200);			xfer_amt++;		}		if (xfer_amt >= 100 && DMAGA_NPACKED(dmar)) {			esplog (esp, LOG_ERR, "DMA gate array won't drain");			/*			 * This isn't quite right...			 */			sp->cmd_pkt.pkt_reason = CMD_TRAN_ERR;			return (ACTION_ABORT_CURCMD);		}	}	/*	 * clear state of dma gate array	 */	dmar->dmaga_csr |= DMAGA_FLUSH;	dmar->dmaga_csr &= ~(DMAGA_ENDVMA|DMAGA_WRITE|DMAGA_ENATC);	/*	/*	 * Check to make sure we're still connected to the target.	 * If the target dropped the bus, that is a fatal error.	 * We don't even attempt to count what we were transferring	 * here. Let esp_handle_unknown clean up for us.	 */	if (esp->e_intr != ESP_INT_BUS) {		New_state(esp, ACTS_UNKNOWN);		return (ACTION_PHASEMANAGE);	}	/*	 * Figure out how far we got.	 * Latch up fifo amount first.	 */	fifoamt = FIFO_CNT(ep);	if (stat & ESP_STAT_XZERO) {		xfer_amt = esp->e_lastcount;	} else {		GET_ESP_COUNT(ep, xfer_amt);		xfer_amt = esp->e_lastcount - xfer_amt;	}	/*	 * Unconditionally knock off by the amount left	 * in the fifo if we were sending out the SCSI bus.	 *	 * If we were receiving from the SCSI bus, believe	 * what the chip told us (either XZERO or by the	 * value calculated from the counter register).	 * The reason we don't look at the fifo for	 * incoming data is that in synchronous mode	 * the fifo may have further data bytes, and	 * for async mode we assume that all data in	 * the fifo will have been transferred before	 * the esp asserts an interrupt.	 */	if (was_sending) {		xfer_amt -= fifoamt;	}	/*	 * If this was a synchronous transfer, flag it.	 * Also check for the errata condition of long	 * 

⌨️ 快捷键说明

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