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

📄 ncr53c9x.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		    this = (Scsi_Cmnd *) this->host_scribble) {			if(this == SCptr) {				*prev = (Scsi_Cmnd *) this->host_scribble;				this->host_scribble = NULL;				esp_release_dmabufs(esp, this);				this->result = DID_ABORT << 16;				this->done(this);				if(don)					esp->dma_ints_on(esp);				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->dma_ints_on(esp);		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->dma_ints_on(esp);	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 NCR_ESP *esp,			    struct ESP_regs *eregs){	Scsi_Cmnd *sp = esp->current_SC;	/* Clean up currently executing command, if any. */	if (sp != NULL) {		esp_release_dmabufs(esp, sp);		sp->result = (DID_RESET << 16);		sp->scsi_done(sp);		esp->current_SC = NULL;	}	/* 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) {			esp_release_dmabufs(esp, sp);			sp->result = (DID_RESET << 16);			sp->scsi_done(sp);		}	}	/* 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 NCR_ESP *esp,			   struct ESP_regs *eregs){	ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));	esp->resetting_bus = 1;	esp_cmd(esp, eregs, 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 NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata;	(void) esp_do_resetbus(esp, esp->eregs);	return SCSI_RESET_PENDING;}/* Internal ESP done function. */static void esp_done(struct NCR_ESP *esp, int error){	Scsi_Cmnd *done_SC;	if(esp->current_SC) {		done_SC = esp->current_SC;		esp->current_SC = NULL;		esp_release_dmabufs(esp, done_SC);		done_SC->result = error;		done_SC->scsi_done(done_SC);		/* Bus is free, issue any commands in the queue. */		if(esp->issue_SC && !esp->current_SC)			esp_exec_cmd(esp);	} else {		/* Panic is safe as current_SC is null so we may still		 * be able to accept more commands to sync disk buffers.		 */		ESPLOG(("panicing\n"));		panic("esp: done() called with NULL esp->current_SC");	}}/* Wheee, ESP interrupt engine. */  /* Forward declarations. */static int esp_do_phase_determine(struct NCR_ESP *esp, 				  struct ESP_regs *eregs);static int esp_do_data_finale(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs);static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs);#define sreg_datainp(__sreg)  (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)/* 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 NCR_ESP *esp, struct ESP_regs *eregs,			     Scsi_Cmnd *scp, int prev_phase, int new_phase){	if(scp->SCp.sent_command != prev_phase)		return 0;	if(esp->dma_irq_p(esp)) {		/* Yes, we are able to save an interrupt. */		esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));		esp->ireg = esp_read(eregs->esp_intrpt);		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 NCR_ESP *esp,			     struct ESP_regs *eregs,			     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->dma_irq_p(esp)) {		/* Yes, we are able to save an interrupt. */		esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));		esp->ireg = esp_read(eregs->esp_intrpt);		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;}/* Misc. esp helper macros. */#define esp_setcount(__eregs, __cnt) \	esp_write((__eregs)->esp_tclow, ((__cnt) & 0xff)); \	esp_write((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff))#define esp_getcount(__eregs) \	((esp_read((__eregs)->esp_tclow)&0xff) | \	 ((esp_read((__eregs)->esp_tcmed)&0xff) << 8))#define fcount(__esp, __eregs) \	(esp_read((__eregs)->esp_fflags) & ESP_FF_FBYTES)#define fnzero(__esp, __eregs) \	(esp_read((__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, __eregs) \	if((__esp)->erev == esp100) \		esp_cmd((__esp), (__eregs), 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 inline int esp100_sync_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs,				    Scsi_Cmnd *sp, int fifocnt){	/* Do not touch this piece of code. */	if((!(esp->erev == esp100)) ||	   (!(sreg_datainp((esp->sreg = esp_read(eregs->esp_status))) && !fifocnt) &&	    !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {		if(sp->SCp.phase == in_dataout)			esp_cmd(esp, eregs, 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, eregs, ESP_CMD_SATN);		esp_cmd(esp, eregs, 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 NCR_ESP *esp,					 struct ESP_regs *eregs){	volatile unchar junk;	if(esp->erev != esp100)		return 0;	junk = esp_read(eregs->esp_intrpt);	if(junk & ESP_INTR_SR)		return 1;	return 0;}/* This verifies the BUSID bits during a reselection so that we know which * target is talking to us. */static inline int reconnect_target(struct NCR_ESP *esp, struct ESP_regs *eregs){	int it, me = esp->scsi_id_mask, targ = 0;	if(2 != fcount(esp, eregs))		return -1;	it = esp_read(eregs->esp_fdata);	if(!(it & me))		return -1;	it &= ~me;	if(it & (it - 1))		return -1;	while(!(it & 1))		targ++, it >>= 1;	return targ;}/* This verifies the identify from the target so that we know which lun is * being reconnected. */static inline int reconnect_lun(struct NCR_ESP *esp, struct ESP_regs *eregs){	int lun;	if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)		return -1;	lun = esp_read(eregs->esp_fdata);	/* Yes, you read this correctly.  We report lun of zero	 * if we see parity error.  ESP reports parity error for	 * the lun byte, and this is the only way to hope to recover	 * because the target is connected.	 */	if(esp->sreg & ESP_STAT_PERR)		return 0;	/* Check for illegal bits being set in the lun. */	if((lun & 0x40) || !(lun & 0x80))		return -1;	return lun & 7;}/* This puts the driver in a state where it can revitalize a command that * is being continued due to reselection. */static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs,			       Scsi_Cmnd *sp){	Scsi_Device *dp = sp->device;	if(esp->prev_soff  != dp->sync_max_offset ||	   esp->prev_stp   != dp->sync_min_period ||	   (esp->erev > esp100a &&	    esp->prev_cfg3 != esp->config3[sp->target])) {		esp->prev_soff = dp->sync_max_offset;		esp_write(eregs->esp_soff, esp->prev_soff);		esp->prev_stp = dp->sync_min_period;		esp_write(eregs->esp_stp, esp->prev_stp);		if(esp->erev > esp100a) {			esp->prev_cfg3 = esp->config3[sp->target];			esp_write(eregs->esp_cfg3, esp->prev_cfg3);		} 	}	esp->current_SC = sp;}/* This will place the current working command back into the issue queue * if we are to receive a reselection amidst a selection attempt. */static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp){	if(!esp->disconnected_SC)		ESPLOG(("esp%d: Weird, being reselected but disconnected "			"command queue is empty.\n", esp->esp_id));	esp->snip = 0;	esp->current_SC = 0;	sp->SCp.phase = not_issued;	append_SC(&esp->issue_SC, sp);}/* Begin message in phase. */static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs){	esp_cmd(esp, eregs, ESP_CMD_FLUSH);	esp_maybe_nop(esp, eregs);	esp_cmd(esp, eregs, ESP_CMD_TI);	esp->msgin_len = 1;	esp->msgin_ctr = 0;	esp_advance_phase(esp->current_SC, in_msgindone);	return do_work_bus;}static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp){	++sp->SCp.buffer;	--sp->SCp.buffers_residual;	sp->SCp.this_residual = sp->SCp.buffer->length;	if (esp->dma_advance_sg)		esp->dma_advance_sg (sp);	else		sp->SCp.ptr = (char *)virt_to_phys(sp->SCp.buffer->address);}/* Please note that the way I've coded these routines is that I _always_ * check for a disconnect during any and all information transfer * phases.  The SCSI standard states that the target _can_ cause a BUS * FREE condition by dropping all MSG/CD/IO/BSY signals.  Also note * that during information transfer phases the target controls every * change in phase, the only thing the initiator can do is "ask" for * a message out phase by driving ATN true.  The target can, and sometimes * will, completely ignore this request so we cannot assume anything when * we try to force a message out phase to abort/reset a target.  Most of * the time the target will eventually be nice and go to message out, so * we may have to hold on to our state about what we want to tell the target * for some period of time. *//* I think I have things working here correctly.  Even partial transfers * within a buffer or sub-buffer should not upset us at all no matter * how bad the target and/or ESP fucks things up. */static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs){	Scsi_Cmnd *SCptr = esp->current_SC;	int thisphase, hmuch;	ESPDATA(("esp_do_data: "));	esp_maybe_nop(esp, eregs);	thisphase = sreg_to_dataphase(esp->sreg);	esp_advance_phase(SCptr, thisphase);	ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));	hmuch = esp->dma_can_transfer(esp, SCptr);	/*	 * XXX MSch: cater for PIO transfer here; PIO used if hmuch == 0	 */	if (hmuch) {	/* DMA */		/*		 * DMA		 */		ESPDATA(("hmuch<%d> ", hmuch));		esp->current_transfer_size = hmuch;		esp_setcount(eregs, (esp->fas_premature_intr_workaround ?				     (hmuch + 0x40) : hmuch));		esp->dma_setup(esp, (__u32)((unsigned long)SCptr->SCp.ptr), 			       hmuch, (thisphase == in_datain));		ESPDATA(("DMA|TI --> do_intr_end\n"));		esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);		return do_intr_end;		/*		 * end DMA		 */	} else {		/*		 * PIO		 */		int oldphase, i = 0; /* or where we left off last time ?? esp->current_data ?? */		int fifocnt = 0;		oldphase = esp_read(eregs->esp_status) & ESP_STAT_PMASK;		/*		 * polled transfer; ugly, can we make this happen in a DRQ 		 * interrupt handler ??		 * requires keeping track of state information in host or 		 * command struct!		 * Problem: I've never seen a DRQ happen on Mac, not even		 * with ESP_CMD_DMA ...		 */		/* figure out how much needs to be transfered */		hmuch = SCptr->SCp.this_residual;		ESPDATA(("hmuch<%d> pio ", hmuch));		esp->current_transfer_size = hmuch;		/* tell the ESP ... */		esp_setcount(eregs, hmuch);		/* loop */		while (hmuch) {			int j, fifo_stuck = 0, newphase;			unsigned long flags, timeout;#if 0			if ( i % 10 )				ESPDATA(("\r"));			else				ESPDATA(( /*"\n"*/ "\r"));#endif			save_flags(flags);#if 0			cli();#endif			if(thisphase == in_datain) {				/* 'go' ... */ 				esp_cmd(esp, eregs, ESP_CMD_TI);				/* wait for data */				timeout = 1000000;				while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)					udelay(2);				if (timeout == 0)					printk("DRQ datain timeout! \n");				newphase = esp->sreg & ESP_STAT_PMASK;

⌨️ 快捷键说明

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