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

📄 esp.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
		spin_unlock_irqrestore(&esp->lock, flags);		return SCSI_ABORT_PENDING;	}	/* If it is still in the issue queue then we can safely	 * call the completion routine and report abort success.	 */	don = (sbus_readl(esp->dregs + DMA_CSR) & DMA_INT_ENAB);	if (don) {		ESP_INTSOFF(esp->dregs);	}	if (esp->issue_SC) {		Scsi_Cmnd **prev, *this;		for (prev = (&esp->issue_SC), this = esp->issue_SC;		     this != NULL;		     prev = (Scsi_Cmnd **) &(this->host_scribble),			     this = (Scsi_Cmnd *) this->host_scribble) {			if (this == SCptr) {				*prev = (Scsi_Cmnd *) this->host_scribble;				this->host_scribble = NULL;				spin_unlock_irqrestore(&esp->lock, flags);				esp_release_dmabufs(esp, this);				this->result = DID_ABORT << 16;				this->scsi_done(this);				if (don)					ESP_INTSON(esp->dregs);				return SCSI_ABORT_SUCCESS;			}		}	}	/* Yuck, the command to abort is disconnected, it is not	 * worth trying to abort it now if something else is live	 * on the bus at this time.  So, we let the SCSI code wait	 * a little bit and try again later.	 */	if (esp->current_SC) {		if (don)			ESP_INTSON(esp->dregs);		spin_unlock_irqrestore(&esp->lock, flags);		return SCSI_ABORT_BUSY;	}	/* It's disconnected, we have to reconnect to re-establish	 * the nexus and tell the device to abort.  However, we really	 * cannot 'reconnect' per se, therefore we tell the upper layer	 * the safest thing we can.  This is, wait a bit, if nothing	 * happens, we are really hung so reset the bus.	 */	if (don)		ESP_INTSON(esp->dregs);	spin_unlock_irqrestore(&esp->lock, flags);	return SCSI_ABORT_SNOOZE;}/* We've sent ESP_CMD_RS to the ESP, the interrupt had just * arrived indicating the end of the SCSI bus reset.  Our job * is to clean out the command queues and begin re-execution * of SCSI commands once more. */static int esp_finish_reset(struct esp *esp){	Scsi_Cmnd *sp = esp->current_SC;	/* Clean up currently executing command, if any. */	if (sp != NULL) {		esp->current_SC = NULL;		spin_unlock(&esp->lock);		esp_release_dmabufs(esp, sp);		sp->result = (DID_RESET << 16);		spin_lock(&io_request_lock);		sp->scsi_done(sp);		spin_unlock(&io_request_lock);		spin_lock(&esp->lock);	}	/* Clean up disconnected queue, they have been invalidated	 * by the bus reset.	 */	if (esp->disconnected_SC) {		while ((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) {			spin_unlock(&esp->lock);			esp_release_dmabufs(esp, sp);			sp->result = (DID_RESET << 16);			spin_lock(&io_request_lock);			sp->scsi_done(sp);			spin_unlock(&io_request_lock);			spin_lock(&esp->lock);		}	}	/* SCSI bus reset is complete. */	esp->resetting_bus = 0;	/* Ok, now it is safe to get commands going once more. */	if (esp->issue_SC)		esp_exec_cmd(esp);	return do_intr_end;}static int esp_do_resetbus(struct esp *esp){	ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));	esp->resetting_bus = 1;	esp_cmd(esp, ESP_CMD_RS);	return do_intr_end;}/* Reset ESP chip, reset hanging bus, then kill active and * disconnected commands for targets without soft reset. */int esp_reset(Scsi_Cmnd *SCptr, unsigned int how){	struct esp *esp = (struct esp *) SCptr->host->hostdata;	unsigned long flags;	spin_lock_irqsave(&esp->lock, flags);	(void) esp_do_resetbus(esp);	spin_unlock_irqrestore(&esp->lock, flags);	return SCSI_RESET_PENDING;}/* Internal ESP done function. */static void esp_done(struct esp *esp, int error){	Scsi_Cmnd *done_SC = esp->current_SC;	esp->current_SC = NULL;	spin_unlock(&esp->lock);	esp_release_dmabufs(esp, done_SC);	done_SC->result = error;	spin_lock(&io_request_lock);	done_SC->scsi_done(done_SC);	spin_unlock(&io_request_lock);	/* Bus is free, issue any commands in the queue. */	spin_lock(&esp->lock);	if (esp->issue_SC && !esp->current_SC)		esp_exec_cmd(esp);}/* Wheee, ESP interrupt engine. */  /* Forward declarations. */static int esp_do_phase_determine(struct esp *esp);static int esp_do_data_finale(struct esp *esp);static int esp_select_complete(struct esp *esp);static int esp_do_status(struct esp *esp);static int esp_do_msgin(struct esp *esp);static int esp_do_msgindone(struct esp *esp);static int esp_do_msgout(struct esp *esp);static int esp_do_cmdbegin(struct esp *esp);#define sreg_datainp(__sreg)  (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)/* Read any bytes found in the FAS366 fifo, storing them into * the ESP driver software state structure. */static void hme_fifo_read(struct esp *esp){	u8 count = 0;	u8 status = esp->sreg;	/* Cannot safely frob the fifo for these following cases, but	 * we must always read the fifo when the reselect interrupt	 * is pending.	 */	if (((esp->ireg & ESP_INTR_RSEL) == 0)	&&	    (sreg_datainp(status)		||	     sreg_dataoutp(status)		||	     (esp->current_SC &&	      esp->current_SC->SCp.phase == in_data_done))) {		ESPHME(("<wkaround_skipped>"));	} else {		unsigned long fcnt = sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES;		/* The HME stores bytes in multiples of 2 in the fifo. */		ESPHME(("hme_fifo[fcnt=%d", (int)fcnt));		while (fcnt) {			esp->hme_fifo_workaround_buffer[count++] =				sbus_readb(esp->eregs + ESP_FDATA);			esp->hme_fifo_workaround_buffer[count++] =				sbus_readb(esp->eregs + ESP_FDATA);			ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1]));			fcnt--;		}		if (sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_F1BYTE) {			ESPHME(("<poke_byte>"));			sbus_writeb(0, esp->eregs + ESP_FDATA);			esp->hme_fifo_workaround_buffer[count++] =				sbus_readb(esp->eregs + ESP_FDATA);			ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1]));			ESPHME(("CMD_FLUSH"));			esp_cmd(esp, ESP_CMD_FLUSH);		} else {			ESPHME(("no_xtra_byte"));		}	}	ESPHME(("wkarnd_cnt=%d]", (int)count));	esp->hme_fifo_workaround_count = count;}static inline void hme_fifo_push(struct esp *esp, u8 *bytes, u8 count){	esp_cmd(esp, ESP_CMD_FLUSH);	while (count) {		u8 tmp = *bytes++;		sbus_writeb(tmp, esp->eregs + ESP_FDATA);		sbus_writeb(0, esp->eregs + ESP_FDATA);		count--;	}}/* We try to avoid some interrupts by jumping ahead and see if the ESP * has gotten far enough yet.  Hence the following. */static inline int skipahead1(struct esp *esp, Scsi_Cmnd *scp,			     int prev_phase, int new_phase){	if (scp->SCp.sent_command != prev_phase)		return 0;	if (ESP_IRQ_P(esp->dregs)) {		/* Yes, we are able to save an interrupt. */		if (esp->erev == fashme)			esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);		esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));		esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);		if (esp->erev == fashme) {			/* This chip is really losing. */			ESPHME(("HME["));			/* Must latch fifo before reading the interrupt			 * register else garbage ends up in the FIFO			 * which confuses the driver utterly.			 * Happy Meal indeed....			 */			ESPHME(("fifo_workaround]"));			if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||			    (esp->sreg2 & ESP_STAT2_F1BYTE))				hme_fifo_read(esp);		}		if (!(esp->ireg & ESP_INTR_SR))			return 0;		else			return do_reset_complete;	}	/* Ho hum, target is taking forever... */	scp->SCp.sent_command = new_phase; /* so we don't recurse... */	return do_intr_end;}static inline int skipahead2(struct esp *esp, Scsi_Cmnd *scp,			     int prev_phase1, int prev_phase2, int new_phase){	if (scp->SCp.sent_command != prev_phase1 &&	    scp->SCp.sent_command != prev_phase2)		return 0;	if (ESP_IRQ_P(esp->dregs)) {		/* Yes, we are able to save an interrupt. */		if (esp->erev == fashme)			esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);		esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));		esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);		if (esp->erev == fashme) {			/* This chip is really losing. */			ESPHME(("HME["));			/* Must latch fifo before reading the interrupt			 * register else garbage ends up in the FIFO			 * which confuses the driver utterly.			 * Happy Meal indeed....			 */			ESPHME(("fifo_workaround]"));			if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||			    (esp->sreg2 & ESP_STAT2_F1BYTE))				hme_fifo_read(esp);		}		if (!(esp->ireg & ESP_INTR_SR))			return 0;		else			return do_reset_complete;	}	/* Ho hum, target is taking forever... */	scp->SCp.sent_command = new_phase; /* so we don't recurse... */	return do_intr_end;}/* Now some dma helpers. */static void dma_setup(struct esp *esp, __u32 addr, int count, int write){	u32 nreg = sbus_readl(esp->dregs + DMA_CSR);	if (write)		nreg |= DMA_ST_WRITE;	else		nreg &= ~(DMA_ST_WRITE);	nreg |= DMA_ENABLE;	sbus_writel(nreg, esp->dregs + DMA_CSR);	if (esp->dma->revision == dvmaesc1) {		/* This ESC gate array sucks! */		__u32 src = addr;		__u32 dest = src + count;		if (dest & (PAGE_SIZE - 1))			count = PAGE_ALIGN(count);		sbus_writel(count, esp->dregs + DMA_COUNT);	}	sbus_writel(addr, esp->dregs + DMA_ADDR);}static void dma_drain(struct esp *esp){	u32 tmp;	if (esp->dma->revision == dvmahme)		return;	if ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_FIFO_ISDRAIN) {		switch (esp->dma->revision) {		default:			tmp |= DMA_FIFO_STDRAIN;			sbus_writel(tmp, esp->dregs + DMA_CSR);		case dvmarev3:		case dvmaesc1:			while (sbus_readl(esp->dregs + DMA_CSR) & DMA_FIFO_ISDRAIN)				udelay(1);		};	}}static void dma_invalidate(struct esp *esp){	u32 tmp;	if (esp->dma->revision == dvmahme) {		sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);		esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |					 (DMA_PARITY_OFF | DMA_2CLKS |					  DMA_SCSI_DISAB | DMA_INT_ENAB)) &					~(DMA_ST_WRITE | DMA_ENABLE));		sbus_writel(0, esp->dregs + DMA_CSR);		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);		/* This is necessary to avoid having the SCSI channel		 * engine lock up on us.		 */		sbus_writel(0, esp->dregs + DMA_ADDR);	} else {		while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ)			udelay(1);		tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);		tmp |= DMA_FIFO_INV;		sbus_writel(tmp, esp->dregs + DMA_CSR);		tmp &= ~DMA_FIFO_INV;		sbus_writel(tmp, esp->dregs + DMA_CSR);	}}static inline void dma_flashclear(struct esp *esp){	dma_drain(esp);	dma_invalidate(esp);}static int dma_can_transfer(struct esp *esp, Scsi_Cmnd *sp){	__u32 base, end, sz;	if (esp->dma->revision == dvmarev3) {		sz = sp->SCp.this_residual;		if (sz > 0x1000000)			sz = 0x1000000;	} else {		base = ((__u32)((unsigned long)sp->SCp.ptr));		base &= (0x1000000 - 1);		end = (base + sp->SCp.this_residual);		if (end > 0x1000000)			end = 0x1000000;		sz = (end - base);	}	return sz;}/* Misc. esp helper macros. */#define esp_setcount(__eregs, __cnt, __hme) \	sbus_writeb(((__cnt)&0xff), (__eregs) + ESP_TCLOW); \	sbus_writeb((((__cnt)>>8)&0xff), (__eregs) + ESP_TCMED); \	if (__hme) { \		sbus_writeb((((__cnt)>>16)&0xff), (__eregs) + FAS_RLO); \		sbus_writeb(0, (__eregs) + FAS_RHI); \	}#define esp_getcount(__eregs, __hme) \	((sbus_readb((__eregs) + ESP_TCLOW)&0xff) | \	 ((sbus_readb((__eregs) + ESP_TCMED)&0xff) << 8) | \         ((__hme) ? sbus_readb((__eregs) + FAS_RLO) << 16 : 0))#define fcount(__esp) \	(((__esp)->erev == fashme) ? \	  (__esp)->hme_fifo_workaround_count : \	  sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_FBYTES)#define fnzero(__esp) \	(((__esp)->erev == fashme) ? 0 : \	 sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_ONOTZERO)/* XXX speculative nops unnecessary when continuing amidst a data phase * XXX even on esp100!!!  another case of flooding the bus with I/O reg * XXX writes... */#define esp_maybe_nop(__esp) \	if ((__esp)->erev == esp100) \		esp_cmd((__esp), ESP_CMD_NULL)#define sreg_to_dataphase(__sreg) \	((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)/* The ESP100 when in synchronous data phase, can mistake a long final * REQ pulse from the target as an extra byte, it places whatever is on * the data lines into the fifo.  For now, we will assume when this * happens that the target is a bit quirky and we don't want to * be talking synchronously to it anyways.  Regardless, we need to * tell the ESP to eat the extraneous byte so that we can proceed * to the next phase. */static int esp100_sync_hwbug(struct esp *esp, Scsi_Cmnd *sp, int fifocnt){	/* Do not touch this piece of code. */	if ((!(esp->erev == esp100)) ||	    (!(sreg_datainp((esp->sreg = sbus_readb(esp->eregs + ESP_STATUS))) &&	       !fifocnt) &&	     !(sreg_dataoutp(esp->sreg) && !fnzero(esp)))) {		if (sp->SCp.phase == in_dataout)			esp_cmd(esp, ESP_CMD_FLUSH);		return 0;	} else {		/* Async mode for this guy. */		build_sync_nego_msg(esp, 0, 0);		/* Ack the bogus byte, but set ATN first. */		esp_cmd(esp, ESP_CMD_SATN);		esp_cmd(esp, ESP_CMD_MOK);		return 1;	}}/* This closes the window during a selection with a reselect pending, because * we use DMA for the selection process the FIFO should hold the correct * contents if we get reselected during this process.  So we just need to * ack the possible illegal cmd interrupt pending on the esp100. */static inline int esp100_reconnect_hwbug(struct esp *esp){	u8 tmp;	if (esp->erev != esp100)		return 0;	tmp = sbus_readb(esp->eregs + ESP_INTRPT);	if (tmp & ESP_INTR_SR)		return 1;	return 0;}/* This verifies the BUSID bits during a reselection so 

⌨️ 快捷键说明

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