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

📄 esp.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
static void esp_save_pointers(struct esp *esp, Scsi_Cmnd *sp){	struct esp_pointers *ep = &esp->data_pointers[sp->target];	ep->saved_ptr = sp->SCp.ptr;	ep->saved_buffer = sp->SCp.buffer;	ep->saved_this_residual = sp->SCp.this_residual;	ep->saved_buffers_residual = sp->SCp.buffers_residual;}/* Some rules: * *   1) Never ever panic while something is live on the bus. *      If there is to be any chance of syncing the disks this *      rule is to be obeyed. * *   2) Any target that causes a foul condition will no longer *      have synchronous transfers done to it, no questions *      asked. * *   3) Keep register accesses to a minimum.  Think about some *      day when we have Xbus machines this is running on and *      the ESP chip is on the other end of the machine on a *      different board from the cpu where this is running. *//* Fire off a command.  We assume the bus is free and that the only * case where we could see an interrupt is where we have disconnected * commands active and they are trying to reselect us. */static inline void esp_check_cmd(struct esp *esp, Scsi_Cmnd *sp){	switch (sp->cmd_len) {	case 6:	case 10:	case 12:		esp->esp_slowcmd = 0;		break;	default:		esp->esp_slowcmd = 1;		esp->esp_scmdleft = sp->cmd_len;		esp->esp_scmdp = &sp->cmnd[0];		break;	};}static inline void build_sync_nego_msg(struct esp *esp, int period, int offset){	esp->cur_msgout[0] = EXTENDED_MESSAGE;	esp->cur_msgout[1] = 3;	esp->cur_msgout[2] = EXTENDED_SDTR;	esp->cur_msgout[3] = period;	esp->cur_msgout[4] = offset;	esp->msgout_len = 5;}/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */static inline void build_wide_nego_msg(struct esp *esp, int size){	esp->cur_msgout[0] = EXTENDED_MESSAGE;	esp->cur_msgout[1] = 2;	esp->cur_msgout[2] = EXTENDED_WDTR;	switch (size) {	case 32:		esp->cur_msgout[3] = 2;		break;	case 16:		esp->cur_msgout[3] = 1;		break;	case 8:	default:		esp->cur_msgout[3] = 0;		break;	};	esp->msgout_len = 4;}static void esp_exec_cmd(struct esp *esp){	Scsi_Cmnd *SCptr;	Scsi_Device *SDptr;	volatile u8 *cmdp = esp->esp_command;	u8 the_esp_command;	int lun, target;	int i;	/* Hold off if we have disconnected commands and	 * an IRQ is showing...	 */	if (esp->disconnected_SC && ESP_IRQ_P(esp->dregs))		return;	/* Grab first member of the issue queue. */	SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);	/* Safe to panic here because current_SC is null. */	if (!SCptr)		panic("esp: esp_exec_cmd and issue queue is NULL");	SDptr = SCptr->device;	lun = SCptr->lun;	target = SCptr->target;	esp->snip = 0;	esp->msgout_len = 0;	/* Send it out whole, or piece by piece?   The ESP	 * only knows how to automatically send out 6, 10,	 * and 12 byte commands.  I used to think that the	 * Linux SCSI code would never throw anything other	 * than that to us, but then again there is the	 * SCSI generic driver which can send us anything.	 */	esp_check_cmd(esp, SCptr);	/* If arbitration/selection is successful, the ESP will leave	 * ATN asserted, causing the target to go into message out	 * phase.  The ESP will feed the target the identify and then	 * the target can only legally go to one of command,	 * datain/out, status, or message in phase, or stay in message	 * out phase (should we be trying to send a sync negotiation	 * message after the identify).  It is not allowed to drop	 * BSY, but some buggy targets do and we check for this	 * condition in the selection complete code.  Most of the time	 * we'll make the command bytes available to the ESP and it	 * will not interrupt us until it finishes command phase, we	 * cannot do this for command sizes the ESP does not	 * understand and in this case we'll get interrupted right	 * when the target goes into command phase.	 *	 * It is absolutely _illegal_ in the presence of SCSI-2 devices	 * to use the ESP select w/o ATN command.  When SCSI-2 devices are	 * present on the bus we _must_ always go straight to message out	 * phase with an identify message for the target.  Being that	 * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2	 * selections should not confuse SCSI-1 we hope.	 */	if (SDptr->sync) {		/* this targets sync is known */#ifndef __sparc_v9__do_sync_known:#endif		if (SDptr->disconnect)			*cmdp++ = IDENTIFY(1, lun);		else			*cmdp++ = IDENTIFY(0, lun);		if (esp->esp_slowcmd) {			the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);			esp_advance_phase(SCptr, in_slct_stop);		} else {			the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);			esp_advance_phase(SCptr, in_slct_norm);		}	} else if (!(esp->targets_present & (1<<target)) || !(SDptr->disconnect)) {		/* After the bootup SCSI code sends both the		 * TEST_UNIT_READY and INQUIRY commands we want		 * to at least attempt allowing the device to		 * disconnect.		 */		ESPMISC(("esp: Selecting device for first time. target=%d "			 "lun=%d\n", target, SCptr->lun));		if (!SDptr->borken && !SDptr->disconnect)			SDptr->disconnect = 1;		*cmdp++ = IDENTIFY(0, lun);		esp->prevmsgout = NOP;		esp_advance_phase(SCptr, in_slct_norm);		the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);		/* Take no chances... */		SDptr->sync_max_offset = 0;		SDptr->sync_min_period = 0;	} else {		/* Sorry, I have had way too many problems with		 * various CDROM devices on ESP. -DaveM		 */		int cdrom_hwbug_wkaround = 0;#ifndef __sparc_v9__		/* Never allow disconnects or synchronous transfers on		 * SparcStation1 and SparcStation1+.  Allowing those		 * to be enabled seems to lockup the machine completely.		 */		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {			/* But we are nice and allow tapes and removable			 * disks (but not CDROMs) to disconnect.			 */			if(SDptr->type == TYPE_TAPE ||			   (SDptr->type != TYPE_ROM && SDptr->removable))				SDptr->disconnect = 1;			else				SDptr->disconnect = 0;			SDptr->sync_max_offset = 0;			SDptr->sync_min_period = 0;			SDptr->sync = 1;			esp->snip = 0;			goto do_sync_known;		}#endif /* !(__sparc_v9__) */		/* We've talked to this guy before,		 * but never negotiated.  Let's try,		 * need to attempt WIDE first, before		 * sync nego, as per SCSI 2 standard.		 */		if (esp->erev == fashme && !SDptr->wide) {			if (!SDptr->borken &&			   SDptr->type != TYPE_ROM &&			   SDptr->removable == 0) {				build_wide_nego_msg(esp, 16);				SDptr->wide = 1;				esp->wnip = 1;				goto after_nego_msg_built;			} else {				SDptr->wide = 1;				/* Fall through and try sync. */			}		}		if (!SDptr->borken) {			if ((SDptr->type == TYPE_ROM)) {				/* Nice try sucker... */				ESPMISC(("esp%d: Disabling sync for buggy "					 "CDROM.\n", esp->esp_id));				cdrom_hwbug_wkaround = 1;				build_sync_nego_msg(esp, 0, 0);			} else if (SDptr->removable != 0) {				ESPMISC(("esp%d: Not negotiating sync/wide but "					 "allowing disconnect for removable media.\n",					 esp->esp_id));				build_sync_nego_msg(esp, 0, 0);			} else {				build_sync_nego_msg(esp, esp->sync_defp, 15);			}		} else {			build_sync_nego_msg(esp, 0, 0);		}		SDptr->sync = 1;		esp->snip = 1;after_nego_msg_built:		/* A fix for broken SCSI1 targets, when they disconnect		 * they lock up the bus and confuse ESP.  So disallow		 * disconnects for SCSI1 targets for now until we		 * find a better fix.		 *		 * Addendum: This is funny, I figured out what was going		 *           on.  The blotzed SCSI1 target would disconnect,		 *           one of the other SCSI2 targets or both would be		 *           disconnected as well.  The SCSI1 target would		 *           stay disconnected long enough that we start		 *           up a command on one of the SCSI2 targets.  As		 *           the ESP is arbitrating for the bus the SCSI1		 *           target begins to arbitrate as well to reselect		 *           the ESP.  The SCSI1 target refuses to drop it's		 *           ID bit on the data bus even though the ESP is		 *           at ID 7 and is the obvious winner for any		 *           arbitration.  The ESP is a poor sport and refuses		 *           to lose arbitration, it will continue indefinately		 *           trying to arbitrate for the bus and can only be		 *           stopped via a chip reset or SCSI bus reset.		 *           Therefore _no_ disconnects for SCSI1 targets		 *           thank you very much. ;-)		 */		if(((SDptr->scsi_level < 3) &&		    (SDptr->type != TYPE_TAPE) &&		    SDptr->removable == 0) ||		    cdrom_hwbug_wkaround || SDptr->borken) {			ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "				 "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));			SDptr->disconnect = 0;			*cmdp++ = IDENTIFY(0, lun);		} else {			*cmdp++ = IDENTIFY(1, lun);		}		/* ESP fifo is only so big...		 * Make this look like a slow command.		 */		esp->esp_slowcmd = 1;		esp->esp_scmdleft = SCptr->cmd_len;		esp->esp_scmdp = &SCptr->cmnd[0];		the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);		esp_advance_phase(SCptr, in_slct_msg);	}	if (!esp->esp_slowcmd)		for (i = 0; i < SCptr->cmd_len; i++)			*cmdp++ = SCptr->cmnd[i];	/* HME sucks... */	if (esp->erev == fashme)		sbus_writeb((target & 0xf) | (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT),			    esp->eregs + ESP_BUSID);	else		sbus_writeb(target & 7, esp->eregs + ESP_BUSID);	if (esp->prev_soff != SDptr->sync_max_offset ||	    esp->prev_stp  != SDptr->sync_min_period ||	    (esp->erev > esp100a &&	     esp->prev_cfg3 != esp->config3[target])) {		esp->prev_soff = SDptr->sync_max_offset;		esp->prev_stp = SDptr->sync_min_period;		sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);		sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);		if (esp->erev > esp100a) {			esp->prev_cfg3 = esp->config3[target];			sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);		}	}	i = (cmdp - esp->esp_command);	if (esp->erev == fashme) {		esp_cmd(esp, ESP_CMD_FLUSH); /* Grrr! */		/* Set up the DMA and HME counters */		sbus_writeb(i, esp->eregs + ESP_TCLOW);		sbus_writeb(0, esp->eregs + ESP_TCMED);		sbus_writeb(0, esp->eregs + FAS_RLO);		sbus_writeb(0, esp->eregs + FAS_RHI);		esp_cmd(esp, the_esp_command);		/* Talk about touchy hardware... */		esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |					 (DMA_SCSI_DISAB | DMA_ENABLE)) &					~(DMA_ST_WRITE));		sbus_writel(16, esp->dregs + DMA_COUNT);		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);	} else {		u32 tmp;		/* Set up the DMA and ESP counters */		sbus_writeb(i, esp->eregs + ESP_TCLOW);		sbus_writeb(0, esp->eregs + ESP_TCMED);		tmp = sbus_readl(esp->dregs + DMA_CSR);		tmp &= ~DMA_ST_WRITE;		tmp |= DMA_ENABLE;		sbus_writel(tmp, esp->dregs + DMA_CSR);		if (esp->dma->revision == dvmaesc1) {			if (i) /* Workaround ESC gate array SBUS rerun bug. */				sbus_writel(PAGE_SIZE, esp->dregs + DMA_COUNT);		}		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);		/* Tell ESP to "go". */		esp_cmd(esp, the_esp_command);	}}/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){	struct esp *esp;	unsigned long flags;	/* Set up func ptr and initial driver cmd-phase. */	SCpnt->scsi_done = done;	SCpnt->SCp.phase = not_issued;	/* We use the scratch area. */	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun));	ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun));	esp = (struct esp *) SCpnt->host->hostdata;	esp_get_dmabufs(esp, SCpnt);	esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */	SCpnt->SCp.Status           = CHECK_CONDITION;	SCpnt->SCp.Message          = 0xff;	SCpnt->SCp.sent_command     = 0;	spin_lock_irqsave(&esp->lock, flags);	/* Place into our queue. */	if (SCpnt->cmnd[0] == REQUEST_SENSE) {		ESPQUEUE(("RQSENSE\n"));		prepend_SC(&esp->issue_SC, SCpnt);	} else {		ESPQUEUE(("\n"));		append_SC(&esp->issue_SC, SCpnt);	}	/* Run it now if we can. */	if (!esp->current_SC && !esp->resetting_bus)		esp_exec_cmd(esp);	spin_unlock_irqrestore(&esp->lock, flags);	return 0;}/* Only queuing supported in this ESP driver. */int esp_command(Scsi_Cmnd *SCpnt){	struct esp *esp = (struct esp *) SCpnt->host->hostdata;	ESPLOG(("esp%d: esp_command() called...\n", esp->esp_id));	return -1;}/* Dump driver state. */static void esp_dump_cmd(Scsi_Cmnd *SCptr){	ESPLOG(("[tgt<%02x> lun<%02x> "		"pphase<%s> cphase<%s>]",		SCptr->target, SCptr->lun,		phase_string(SCptr->SCp.sent_command),		phase_string(SCptr->SCp.phase)));}static void esp_dump_state(struct esp *esp){	Scsi_Cmnd *SCptr = esp->current_SC;#ifdef DEBUG_ESP_CMDS	int i;#endif	ESPLOG(("esp%d: dumping state\n", esp->esp_id));	ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n",		esp->esp_id,		sbus_readl(esp->dregs + DMA_CSR),		sbus_readl(esp->dregs + DMA_ADDR)));	ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",		esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));	ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",		esp->esp_id,		sbus_readb(esp->eregs + ESP_STATUS),		sbus_readb(esp->eregs + ESP_SSTEP),		sbus_readb(esp->eregs + ESP_INTRPT)));#ifdef DEBUG_ESP_CMDS	printk("esp%d: last ESP cmds [", esp->esp_id);	i = (esp->espcmdent - 1) & 31;	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");	i = (i - 1) & 31;	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");	i = (i - 1) & 31;	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");	i = (i - 1) & 31;	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");	printk("]\n");#endif /* (DEBUG_ESP_CMDS) */	if (SCptr) {		ESPLOG(("esp%d: current command ", esp->esp_id));		esp_dump_cmd(SCptr);	}	ESPLOG(("\n"));	SCptr = esp->disconnected_SC;	ESPLOG(("esp%d: disconnected ", esp->esp_id));	while (SCptr) {		esp_dump_cmd(SCptr);		SCptr = (Scsi_Cmnd *) SCptr->host_scribble;	}	ESPLOG(("\n"));}/* Abort a command. */int esp_abort(Scsi_Cmnd *SCptr){	struct esp *esp = (struct esp *) SCptr->host->hostdata;	unsigned long flags;	int don;	spin_lock_irqsave(&esp->lock, flags);	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));	esp_dump_state(esp);	/* Wheee, if this is the current command on the bus, the	 * best we can do is assert ATN and wait for msgout phase.	 * This should even fix a hung SCSI bus when we lose state	 * in the driver and timeout because the eventual phase change	 * will cause the ESP to (eventually) give an interrupt.	 */	if (esp->current_SC == SCptr) {		esp->cur_msgout[0] = ABORT;		esp->msgout_len = 1;		esp->msgout_ctr = 0;		esp_cmd(esp, ESP_CMD_SATN);

⌨️ 快捷键说明

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