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

📄 ncr5380.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
						/*						 * A successful selection is defined as one that 						 * leaves us with the command connected and 						 * in hostdata->connected, OR has terminated the						 * command.						 *						 * With successful commands, we fall through						 * and see if we can do an information transfer,						 * with failures we will restart.						 */#ifdef USLEEP						hostdata->selecting = 0; /* RvC: have to preset this							to indicate a new command is being performed */#endif						if (!NCR5380_select(instance, tmp,						/* 						 * REQUEST SENSE commands are issued without tagged						 * queueing, even on SCSI-II devices because the 						 * contingent allegiance condition exists for the 						 * entire unit.						 */								    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :							     TAG_NEXT)) {							break;						} else {							cli();							LIST(tmp, hostdata->issue_queue);							tmp->host_scribble = (unsigned char *)							    hostdata->issue_queue;							hostdata->issue_queue = tmp;							done = 0;							restore_flags(flags);#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))							printk("scsi%d : main(): select() failed, returned to issue_queue\n",							       instance->host_no);#endif						}					}	/* if target/lun is not busy */				}	/* for */			}	/* if (!hostdata->connected) */#ifdef USLEEP			if (hostdata->selecting) 			{				tmp = (Scsi_Cmnd *)hostdata->selecting;				if (!NCR5380_select(instance, tmp, 					(tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) 				{					/* Ok ?? */				}				else				{					/* RvC: device failed, so we wait a long time					this is needed for Mustek scanners, that					do not respond to commands immediately					after a scan */					printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n",						instance->host_no, tmp->target);					cli();					LIST(tmp, hostdata->issue_queue);					tmp->host_scribble = (unsigned char *) hostdata->issue_queue;					hostdata->issue_queue = tmp;					restore_flags(flags);					hostdata->time_expires = jiffies + USLEEP_WAITLONG;					NCR5380_set_timer (instance);				}			} /* if hostdata->selecting */#endif			if (hostdata->connected#ifdef REAL_DMA			    && !hostdata->dmalen#endif#ifdef USLEEP			    && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))#endif			    ) {				restore_flags(flags);#if (NDEBUG & NDEBUG_MAIN)				printk("scsi%d : main() : performing information transfer\n",				       instance->host_no);#endif				NCR5380_information_transfer(instance);#if (NDEBUG & NDEBUG_MAIN)				printk("scsi%d : main() : done set false\n", instance->host_no);#endif				done = 0;			} else				break;		}		/* for instance */	} while (!done);	spin_lock_irq(&io_request_lock);  /* 	cli();*/	main_running = 0;}#ifndef DONT_USE_INTR#include <linux/blk.h>#include <linux/spinlock.h>/* * Function : void NCR5380_intr (int irq) *  * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses *      from the disconnected queue, and restarting NCR5380_main()  *      as required. * * Inputs : int irq, irq that caused this interrupt. * */static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) {	NCR5380_local_declare();	struct Scsi_Host *instance;	int done;	unsigned char basr;	unsigned long flags;	 save_flags(flags);	 cli();#if (NDEBUG & NDEBUG_INTR)	 printk("scsi : NCR5380 irq %d triggered\n", irq);#endif	do {		done = 1;		for (instance = first_instance; instance && (instance->hostt ==				the_template); instance = instance->next)			if (instance->irq == irq) {				/* Look for pending interrupts */				NCR5380_setup(instance);				basr = NCR5380_read(BUS_AND_STATUS_REG);				/* XXX dispatch to appropriate routine if found and done=0 */				if (basr & BASR_IRQ) {#if (NDEBUG & NDEBUG_INTR)					NCR5380_print(instance);#endif					if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==					    (SR_SEL | SR_IO)) {						done = 0;						restore_flags(flags);#if (NDEBUG & NDEBUG_INTR)						printk("scsi%d : SEL interrupt\n", instance->host_no);#endif						NCR5380_reselect(instance);						(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);					} else if (basr & BASR_PARITY_ERROR) {#if (NDEBUG & NDEBUG_INTR)						printk("scsi%d : PARITY interrupt\n", instance->host_no);#endif						(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);					} else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {#if (NDEBUG & NDEBUG_INTR)						printk("scsi%d : RESET interrupt\n", instance->host_no);#endif						(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);					} else {/*   * XXX the rest of the interrupt conditions should *only* occur during a  * DMA transfer, which I haven't gotten around to fixing yet. */#if defined(REAL_DMA)						/*						 * We should only get PHASE MISMATCH and EOP interrupts						 * if we have DMA enabled, so do a sanity check based on						 * the current setting of the MODE register.						 */						if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr &						BASR_END_DMA_TRANSFER) ||											  !(basr & BASR_PHASE_MATCH))) {							int transfered;							if (!hostdata->connected)								panic("scsi%d : received end of DMA interrupt with no connected cmd\n",								      instance->hostno);							transfered = (hostdata->dmalen - NCR5380_dma_residual(instance));							hostdata->connected->SCp.this_residual -= transferred;							hostdata->connected->SCp.ptr += transferred;							hostdata->dmalen = 0;							(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);#if NCR_TIMEOUT							{								unsigned long timeout = jiffies + NCR_TIMEOUT;								spin_unlock_irq(&io_request_lock);								while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK								       && time_before(jiffies, timeout));								spin_lock_irq(&io_request_lock);																if (time_after_eq(jiffies, timeout) )									printk("scsi%d: timeout at NCR5380.c:%d\n",									       host->host_no, __LINE__);							}#else				/* NCR_TIMEOUT */							while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);#endif							NCR5380_write(MODE_REG, MR_BASE);							NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);						}#else#if (NDEBUG & NDEBUG_INTR)						printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));#endif						(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);#endif					}				}	/* if BASR_IRQ */				if (!done)					run_main();			}	/* if (instance->irq == irq) */	} while (!done);}static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) {	unsigned long flags;	 spin_lock_irqsave(&io_request_lock, flags);	 NCR5380_intr(irq, dev_id, regs);	 spin_unlock_irqrestore(&io_request_lock, flags);}#endif#ifdef NCR5380_STATSstatic void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) {#ifdef NCR5380_STAT_LIMIT	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)#endif		switch (cmd->cmnd[0]) {			case WRITE:			    case WRITE_6:			    case WRITE_10:			    hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);			/*hostdata->bytes_write[cmd->target] += cmd->request_bufflen; */			hostdata->pendingw--;			break;			case READ:			case READ_6:			case READ_10:			hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);			/*hostdata->bytes_read[cmd->target] += cmd->request_bufflen; */			hostdata->pendingr--;			break;		}}#endif/*  * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,  *      int tag); * * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, *      including ARBITRATION, SELECTION, and initial message out for  *      IDENTIFY and queue messages.  * * Inputs : instance - instantiation of the 5380 driver on which this  *      target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for  *      new tag, TAG_NONE for untagged queueing, otherwise set to the tag for  *      the command that is presently connected. *  * Returns : -1 if selection could not execute for some reason, *      0 if selection succeeded or failed because the target  *      did not respond. * * Side effects :  *      If bus busy, arbitration failed, etc, NCR5380_select() will exit  *              with registers as they should have been on entry - ie *              SELECT_ENABLE will be set appropriately, the NCR5380 *              will cease to drive any SCSI bus signals. * *      If successful : I_T_L or I_T_L_Q nexus will be established,  *              instance->connected will be set to cmd.   *              SELECT interrupt will be disabled. * *      If failed (no target) : cmd->scsi_done() will be called, and the  *              cmd->result host byte set to DID_BAD_TARGET. */static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) {	NCR5380_local_declare();	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;	unsigned char tmp[3], phase;	unsigned char *data;	int len;	unsigned long timeout;	unsigned long flags;#ifdef USLEEP	unsigned char value;#endif	NCR5380_setup(instance);#ifdef USLEEP	if (hostdata->selecting) 	{		goto part2;	/* RvC: sorry prof. Dijkstra, but it keeps the				   rest of the code nearly the same */	}#endif	 hostdata->restart_select = 0;#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION)	 NCR5380_print(instance);	 printk("scsi%d : starting arbitration, id = %d\n", instance->host_no,		instance->this_id);#endif	 save_flags(flags);	 cli();	/* 	 * Set the phase bits to 0, otherwise the NCR5380 won't drive the 	 * data bus during SELECTION.	 */	 NCR5380_write(TARGET_COMMAND_REG, 0);	/* 	 * Start arbitration.	 */	 NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);	 NCR5380_write(MODE_REG, MR_ARBITRATE);	 restore_flags(flags);	/* Wait for arbitration logic to complete */#if NCR_TIMEOUT	{		unsigned long timeout = jiffies + 2 * NCR_TIMEOUT;		spin_unlock_irq(&io_request_lock);		while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)		       && time_before(jiffies,timeout));		spin_lock_irq(&io_request_lock);		       		if (time_after_eq(jiffies,timeout)) {			printk("scsi: arbitration timeout at %d\n", __LINE__);			NCR5380_write(MODE_REG, MR_BASE);			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);			return -1;		}	}#else				/* NCR_TIMEOUT */	while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS));#endif#if (NDEBUG & NDEBUG_ARBITRATION)	 printk("scsi%d : arbitration complete\n", instance->host_no);/* Avoid GCC 2.4.5 asm needs to many reloads error */	 __asm__("nop");#endif	/* 	 * The arbitration delay is 2.2us, but this is a minimum and there is 	 * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate	 * the integral nature of udelay().	 *	 */	 udelay(3);	/* Check for lost arbitration */	if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||	     (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||	  (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {		NCR5380_write(MODE_REG, MR_BASE);#if (NDEBUG & NDEBUG_ARBITRATION)		printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n",		       instance->host_no);#endif		return -1;	}	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);	if (!(hostdata->flags & FLAG_DTC3181E) &&		/* RvC: DTC3181E has some trouble with this		 *	so we simply removed it. Seems to work with		 *	only Mustek scanner attached		 */		(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) 	{		NCR5380_write(MODE_REG, MR_BASE);		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);#if (NDEBUG & NDEBUG_ARBITRATION)		printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n",		       instance->host_no);#endif		return -1;	}	/* 	 * Again, bus clear + bus settle time is 1.2us, however, this is 	 * a minimum so we'll udelay ceil(1.2)	 */	udelay(2);#if (NDEBUG & NDEBUG_ARBITRATION)	printk("scsi%d : won arbitration\n", instance->host_no);#endif	/* 	 * Now that we have won arbitration, start Selection process, asserting 	 * the host and target ID's on the SCSI bus.	 */	NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));	/* 	 * Raise ATN while SEL is true before BSY goes false from arbitration,	 * since this is the only way to guarantee that we'll get a MESSAGE OUT	 * phase immediately after selection.	 */	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |		     ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));	NCR5380_write(MODE_REG, MR_BASE);	/* 	 * Reselect interrupts must be turned off prior to the dropping of BSY,	 * otherwise we will trigger an interrupt.	 */	NCR5380_write(SELECT_ENABLE_REG, 0);	/*	 * The initiator shall then wait at least two deskew delays and release 	 * the BSY signal.	 */	udelay(1);		/* wingel -- wait two bus deskew delay >2*45ns */	/* Reset BSY */	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |				       ICR_ASSERT_ATN | ICR_ASSERT_SEL));	/* 	 * Something weird happens when we cease to drive BSY - looks	 * like the board/chip is letting us do another read before the 

⌨️ 快捷键说明

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