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

📄 ncr53c9x.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			esp->dma_mmu_get_scsi_sgl(esp, sp);		else			sp->SCp.ptr =				(char *) virt_to_phys(sp->SCp.buffer->address);	}}static void esp_release_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp){	if(sp->use_sg == 0) {		if (esp->dma_mmu_release_scsi_one)			esp->dma_mmu_release_scsi_one(esp, sp);	} else {		if (esp->dma_mmu_release_scsi_sgl)			esp->dma_mmu_release_scsi_sgl(esp, sp);	}}static void esp_restore_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp){	struct esp_pointers *ep = &esp->data_pointers[sp->target];	sp->SCp.ptr = ep->saved_ptr;	sp->SCp.buffer = ep->saved_buffer;	sp->SCp.this_residual = ep->saved_this_residual;	sp->SCp.buffers_residual = ep->saved_buffers_residual;}static void esp_save_pointers(struct NCR_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 NCR_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 NCR_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;}static void esp_exec_cmd(struct NCR_ESP *esp){	struct ESP_regs *eregs = esp->eregs;	Scsi_Cmnd *SCptr;	Scsi_Device *SDptr;	volatile unchar *cmdp = esp->esp_command;	unsigned char 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->dma_irq_p(esp))		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 */#ifdef CONFIG_SCSI_MAC_ESPdo_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 {		int toshiba_cdrom_hwbug_wkaround = 0;#ifdef CONFIG_SCSI_MAC_ESP		/* Never allow synchronous transfers (disconnect OK) on		 * Macintosh. Well, maybe later when we figured out how to 		 * do DMA on the machines that support it ...		 */		SDptr->disconnect = 1;		SDptr->sync_max_offset = 0;		SDptr->sync_min_period = 0;		SDptr->sync = 1;		esp->snip = 0;		goto do_sync_known;#endif		/* We've talked to this guy before,		 * but never negotiated.  Let's try		 * sync negotiation.		 */		if(!SDptr->borken) {			if((SDptr->type == TYPE_ROM) &&			   (!strncmp(SDptr->vendor, "TOSHIBA", 7))) {				/* Nice try sucker... */				ESPMISC(("esp%d: Disabling sync for buggy "					 "Toshiba CDROM.\n", esp->esp_id));				toshiba_cdrom_hwbug_wkaround = 1;				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;		/* 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)) ||		   toshiba_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];	esp_write(eregs->esp_busid, (target & 7));	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_write(eregs->esp_soff, esp->prev_soff);		esp->prev_stp = SDptr->sync_min_period;		esp_write(eregs->esp_stp, esp->prev_stp); 		if(esp->erev > esp100a) {			esp->prev_cfg3 = esp->config3[target];			esp_write(eregs->esp_cfg3, esp->prev_cfg3);		}	}	i = (cmdp - esp->esp_command);	/* Set up the DMA and ESP counters */	if(esp->do_pio_cmds){		int j = 0;		/* 		 * XXX MSch:		 *		 * It seems this is required, at least to clean up		 * after failed commands when using PIO mode ...		 */		esp_cmd(esp, eregs, ESP_CMD_FLUSH);		for(;j<i;j++)			esp_write(eregs->esp_fdata, esp->esp_command[j]);		the_esp_command &= ~ESP_CMD_DMA;		/* Tell ESP to "go". */		esp_cmd(esp, eregs, the_esp_command);	} else {		/* Set up the ESP counters */		esp_write(eregs->esp_tclow, i);		esp_write(eregs->esp_tcmed, 0);		esp->dma_init_write(esp, esp->esp_command_dvma, i);		/* Tell ESP to "go". */		esp_cmd(esp, eregs, 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 NCR_ESP *esp;	/* Set up func ptr and initial driver cmd-phase. */	SCpnt->scsi_done = done;	SCpnt->SCp.phase = not_issued;	esp = (struct NCR_ESP *) SCpnt->host->hostdata;	if(esp->dma_led_on)		esp->dma_led_on(esp);	/* 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_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;	/* 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);	return 0;}/* Only queuing supported in this ESP driver. */int esp_command(Scsi_Cmnd *SCpnt){#ifdef DEBUG_ESP	struct NCR_ESP *esp = (struct NCR_ESP *) SCpnt->host->hostdata;#endif	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 NCR_ESP *esp, 			   struct ESP_regs *eregs){	Scsi_Cmnd *SCptr = esp->current_SC;#ifdef DEBUG_ESP_CMDS	int i;#endif	ESPLOG(("esp%d: dumping state\n", esp->esp_id));		/* Print DMA status */	esp->dma_dump_state(esp);	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, esp_read(eregs->esp_status), esp_read(eregs->esp_sstep),		esp_read(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 NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata;	struct ESP_regs *eregs = esp->eregs;	int don;	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));	esp_dump_state(esp, eregs);	/* 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, eregs, ESP_CMD_SATN);		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 = esp->dma_ports_p(esp);	if(don) {		esp->dma_ints_off(esp);		synchronize_irq();	}	if(esp->issue_SC) {		Scsi_Cmnd **prev, *this;		for(prev = (&esp->issue_SC), this = esp->issue_SC;		    this;		    prev = (Scsi_Cmnd **) &(this->host_scribble),

⌨️ 快捷键说明

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