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

📄 ncr5380.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * Input : instance - which NCR5380 */static void NCR5380_print(struct Scsi_Host *instance){	NCR5380_local_declare();	unsigned long flags;	unsigned char status, data, basr, mr, icr, i;	NCR5380_setup(instance);	save_flags(flags);	cli();	data = NCR5380_read(CURRENT_SCSI_DATA_REG);	status = NCR5380_read(STATUS_REG);	mr = NCR5380_read(MODE_REG);	icr = NCR5380_read(INITIATOR_COMMAND_REG);	basr = NCR5380_read(BUS_AND_STATUS_REG);	restore_flags(flags);	printk("STATUS_REG: %02x ", status);	for (i = 0; signals[i].mask; ++i)		if (status & signals[i].mask)			printk(",%s", signals[i].name);	printk("\nBASR: %02x ", basr);	for (i = 0; basrs[i].mask; ++i)		if (basr & basrs[i].mask)			printk(",%s", basrs[i].name);	printk("\nICR: %02x ", icr);	for (i = 0; icrs[i].mask; ++i)		if (icr & icrs[i].mask)			printk(",%s", icrs[i].name);	printk("\nMODE: %02x ", mr);	for (i = 0; mrs[i].mask; ++i)		if (mr & mrs[i].mask)			printk(",%s", mrs[i].name);	printk("\n");}static struct {	unsigned char value;	const char *name;} phases[] = {	{		PHASE_DATAOUT, "DATAOUT"	}, {		PHASE_DATAIN, "DATAIN"	}, {		PHASE_CMDOUT, "CMDOUT"	},	{		PHASE_STATIN, "STATIN"	}, {		PHASE_MSGOUT, "MSGOUT"	}, {		PHASE_MSGIN, "MSGIN"	},	{		PHASE_UNKNOWN, "UNKNOWN"	}};/*  * Function : void NCR5380_print_phase(struct Scsi_Host *instance) * * Purpose : print the current SCSI phase for debugging purposes * * Input : instance - which NCR5380 */static void NCR5380_print_phase(struct Scsi_Host *instance){	NCR5380_local_declare();	unsigned char status;	int i;	NCR5380_setup(instance);	status = NCR5380_read(STATUS_REG);	if (!(status & SR_REQ))		printk("scsi%d : REQ not asserted, phase unknown.\n",		       instance->host_no);	else {		for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&		     (phases[i].value != (status & PHASE_MASK)); ++i);		printk("scsi%d : phase %s\n", instance->host_no, phases[i].name);	}}#endif/* * We need to have our coroutine active given these constraints :  * 1.  The mutex flag, main_running, can only be set when the main  *     routine can actually process data, otherwise SCSI commands *     will never get issued. * * 2.  NCR5380_main() shouldn't be called before it has exited, because *     other drivers have had kernel stack overflows in similar *     situations. * * 3.  We don't want to inline NCR5380_main() because of space concerns, *     even though it is only called in two places. * * So, the solution is to set the mutex in an inline wrapper for the  * main coroutine, and have the main coroutine exit with interrupts  * disabled after the final search through the queues so that no race  * conditions are possible. */static volatile int main_running = 0;/*  * Function : run_main(void) *  * Purpose : insure that the coroutine is running and will process our  *      request.  main_running is checked/set here (in an inline function) *      rather than in NCR5380_main itself to reduce the chances of stack *      overflow. * */static __inline__ void run_main(void){	if (!main_running) {		main_running = 1;		NCR5380_main();	}}#ifdef USLEEP/* * These need tweaking, and would probably work best as per-device  * flags initialized differently for disk, tape, cd, etc devices. * People with broken devices are free to experiment as to what gives * the best results for them. * * USLEEP_SLEEP should be a minimum seek time. * * USLEEP_POLL should be a maximum rotational latency. */#ifndef USLEEP_SLEEP/* 20 ms (reasonable hard disk speed) */#define USLEEP_SLEEP (20*HZ/1000)#endif/* 300 RPM (floppy speed) */#ifndef USLEEP_POLL#define USLEEP_POLL (200*HZ/1000)#endif#ifndef USLEEP_WAITLONG/* RvC: (reasonable time to wait on select error) */#define USLEEP_WAITLONG USLEEP_SLEEP#endifstatic struct Scsi_Host *expires_first = NULL;/*  * Function : int should_disconnect (unsigned char cmd) * * Purpose : decide weather a command would normally disconnect or  *      not, since if it won't disconnect we should go to sleep. * * Input : cmd - opcode of SCSI command * * Returns : DISCONNECT_LONG if we should disconnect for a really long  *      time (ie always, sleep, look for REQ active, sleep),  *      DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal *      time-to-data delay, DISCONNECT_NONE if this command would return *      immediately. * *      Future sleep algorithms based on time to data can exploit  *      something like this so they can differentiate between "normal"  *      (ie, read, write, seek) and unusual commands (ie, * format). * * Note : We don't deal with commands that handle an immediate disconnect, *         */static int should_disconnect(unsigned char cmd){	switch (cmd) {		case READ_6:		    case WRITE_6:		    case SEEK_6:		    case READ_10:		    case WRITE_10:		    case SEEK_10:		    return DISCONNECT_TIME_TO_DATA;		case FORMAT_UNIT:		    case SEARCH_HIGH:		    case SEARCH_LOW:		    case SEARCH_EQUAL:		    return DISCONNECT_LONG;		default:		    return DISCONNECT_NONE;	}}/* * Assumes instance->time_expires has been set in higher level code. */static int NCR5380_set_timer(struct Scsi_Host *instance){	unsigned long flags;	struct Scsi_Host *tmp, **prev;	save_flags(flags);	cli();	if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) {		restore_flags(flags);		return -1;	}	for (prev = &expires_first, tmp = expires_first; tmp;		prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), 		tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer)		if (((struct NCR5380_hostdata *)instance->hostdata)->time_expires < 			((struct NCR5380_hostdata *)tmp->hostdata)->time_expires) 			break;	((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp;	*prev = instance;   	mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires);	restore_flags(flags);	return 0;}/* Doing something about unwanted reentrancy here might be useful */void NCR5380_timer_fn(unsigned long surplus_to_requirements){	unsigned long flags;	struct Scsi_Host *instance;	save_flags(flags);	cli();	for (; expires_first &&		time_before_eq(((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires, jiffies); )	{		instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer;		((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL;		((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires = 0;		expires_first = instance;	}	del_timer(&usleep_timer);	if (expires_first) 	{		usleep_timer.expires = ((struct NCR5380_hostdata *)expires_first->hostdata)->time_expires;		add_timer(&usleep_timer);	}	restore_flags(flags);	spin_lock_irqsave(&io_request_lock, flags);	run_main();	spin_unlock_irqrestore(&io_request_lock, flags);}#endif				/* def USLEEP */static inline void NCR5380_all_init(void){	static int done = 0;	if (!done) {#if (NDEBUG & NDEBUG_INIT)		printk("scsi : NCR5380_all_init()\n");#endif		done = 1;#ifdef USLEEP		init_timer(&usleep_timer);		usleep_timer.function = NCR5380_timer_fn;#endif	}}#ifdef AUTOPROBE_IRQ/* * Function : int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) *  * Purpose : autoprobe for the IRQ line used by the NCR5380.   * * Inputs : instance - pointer to this instance of the NCR5380 driver, *          possible - bitmask of permissible interrupts. * * Returns : number of the IRQ selected, IRQ_NONE if no interrupt fired. *  * XXX no effort is made to deal with spurious interrupts.  */static int probe_irq __initdata = 0;static void __init probe_intr(int irq, void *dev_id, struct pt_regs *regs){	probe_irq = irq;}static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible){	NCR5380_local_declare();	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)	instance->hostdata;	unsigned long timeout;	int trying_irqs, i, mask;	NCR5380_setup(instance);	for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)		if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL)					  == 0))			trying_irqs |= mask;	timeout = jiffies + (250 * HZ / 1000);	probe_irq = IRQ_NONE;/* * A interrupt is triggered whenever BSY = false, SEL = true * and a bit set in the SELECT_ENABLE_REG is asserted on the  * SCSI bus. * * Note that the bus is only driven when the phase control signals * (I/O, C/D, and MSG) match those in the TCR, so we must reset that * to zero. */	NCR5380_write(TARGET_COMMAND_REG, 0);	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);	NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |		      ICR_ASSERT_SEL);	while (probe_irq == IRQ_NONE && time_before(jiffies,timeout))		barrier();	NCR5380_write(SELECT_ENABLE_REG, 0);	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);	for (i = 0, mask = 1; i < 16; ++i, mask <<= 1)		if (trying_irqs & mask)			free_irq(i, NULL);	return probe_irq;}#endif				/* AUTOPROBE_IRQ *//* * Function : void NCR58380_print_options (struct Scsi_Host *instance) * * Purpose : called by probe code indicating the NCR5380 driver *           options that were selected. * * Inputs : instance, pointer to this instance.  Unused. */static void __init NCR5380_print_options(struct Scsi_Host *instance){	printk(" generic options"#ifdef AUTOPROBE_IRQ	       " AUTOPROBE_IRQ"#endif#ifdef AUTOSENSE	       " AUTOSENSE"#endif#ifdef DIFFERENTIAL	       " DIFFERENTIAL"#endif#ifdef REAL_DMA	       " REAL DMA"#endif#ifdef REAL_DMA_POLL	       " REAL DMA POLL"#endif#ifdef PARITY	       " PARITY"#endif#ifdef PSEUDO_DMA	       " PSEUDO DMA"#endif#ifdef SCSI2	       " SCSI-2"#endif#ifdef UNSAFE	       " UNSAFE "#endif	    );#ifdef USLEEP	printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP);#endif	printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);	if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) {		printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE);	}}/* * Function : void NCR5380_print_status (struct Scsi_Host *instance) * * Purpose : print commands in the various queues, called from *      NCR5380_abort and NCR5380_debug to aid debugging. * * Inputs : instance, pointer to this instance.   */static void NCR5380_print_status(struct Scsi_Host *instance){	static char pr_bfr[512];	char *start;	int len;	printk("NCR5380 : coroutine is%s running.\n",	       main_running ? "" : "n't");#ifdef NDEBUG	NCR5380_print(instance);	NCR5380_print_phase(instance);#endif	len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr),				instance->host_no, 0);	pr_bfr[len] = 0;	printk("\n%s\n", pr_bfr);}/******************************************//* * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED] * * *buffer: I/O buffer * **start: if inout == FALSE pointer into buffer where user read should start * offset: current offset * length: length of buffer * hostno: Scsi_Host host_no * inout: TRUE - user is writing; FALSE - user is reading * * Return the number of bytes read from or written */#undef SPRINTF#define SPRINTF(args...) do { if(pos < buffer + length-80) pos += sprintf(pos, ## args); } while(0)staticchar *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length);staticchar *lprint_command(unsigned char *cmd, char *pos, char *buffer, int len);staticchar *lprint_opcode(int opcode, char *pos, char *buffer, int length);#ifndef NCR5380_proc_infostatic#endifint NCR5380_proc_info(			     char *buffer, char **start, off_t offset,

⌨️ 快捷键说明

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