ncr5380.c

来自「linux 内核源代码」· C语言 代码 · 共 2,036 行 · 第 1/5 页

C
2,036
字号
/** *	NCR5380_print	-	print scsi bus signals *	@instance:	adapter state to dump * *	Print the SCSI bus signals for debugging purposes * *	Locks: caller holds hostdata lock (not essential) */static void NCR5380_print(struct Scsi_Host *instance){	NCR5380_local_declare();	unsigned char status, data, basr, mr, icr, i;	NCR5380_setup(instance);	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);	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");}/*  *	NCR5380_print_phase	-	show SCSI phase *	@instance: adapter to dump * * 	Print the current SCSI phase for debugging purposes * *	Locks: none */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/* * 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#endif/*  * Function : int should_disconnect (unsigned char cmd) * * Purpose : decide whether 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;	}}static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout){	hostdata->time_expires = jiffies + timeout;	schedule_delayed_work(&hostdata->coroutine, timeout);}static int probe_irq __initdata = 0;/** *	probe_intr	-	helper for IRQ autoprobe *	@irq: interrupt number *	@dev_id: unused *	@regs: unused * *	Set a flag to indicate the IRQ in question was received. This is *	used by the IRQ probe code. */ static irqreturn_t __init probe_intr(int irq, void *dev_id){	probe_irq = irq;	return IRQ_HANDLED;}/** *	NCR5380_probe_irq	-	find the IRQ of an NCR5380 *	@instance: NCR5380 controller *	@possible: bitmask of ISA IRQ lines * *	Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ *	and then looking to see what interrupt actually turned up. * *	Locks: none, irqs must be enabled on entry */static int __init __maybe_unused 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, IRQF_DISABLED, "NCR-probe", NULL) == 0))			trying_irqs |= mask;	timeout = jiffies + (250 * HZ / 1000);	probe_irq = SCSI_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 == SCSI_IRQ_NONE && time_before(jiffies, timeout))		schedule_timeout_uninterruptible(1);		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;}/** *	NCR58380_print_options	-	show options *	@instance: unused for now * *	Called by probe code indicating the NCR5380 driver options that  *	were selected. At some point this will switch to runtime options *	read from the adapter in question * *	Locks: none */static void __init __maybe_unusedNCR5380_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 UNSAFE	       " UNSAFE "#endif	    );	printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP);	printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);	if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) {		printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE);	}}/** *	NCR5380_print_status 	-	dump controller info *	@instance: controller to dump * *	Print commands in the various queues, called from NCR5380_abort  *	and NCR5380_debug to aid debugging. * *	Locks: called functions disable irqs */static void NCR5380_print_status(struct Scsi_Host *instance){	NCR5380_dprint(NDEBUG_ANY, instance);	NCR5380_dprint_phase(NDEBUG_ANY, instance);}/******************************************//* * /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);static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,	char *buffer, char **start, off_t offset, int length, int inout){	char *pos = buffer;	struct NCR5380_hostdata *hostdata;	Scsi_Cmnd *ptr;	hostdata = (struct NCR5380_hostdata *) instance->hostdata;	if (inout) {		/* Has data been written to the file ? */#ifdef DTC_PUBLIC_RELEASE		dtc_wmaxi = dtc_maxi = 0;#endif#ifdef PAS16_PUBLIC_RELEASE		pas_wmaxi = pas_maxi = 0;#endif		return (-ENOSYS);	/* Currently this is a no-op */	}	SPRINTF("NCR5380 core release=%d.   ", NCR5380_PUBLIC_RELEASE);	if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400)		SPRINTF("ncr53c400 release=%d.  ", NCR53C400_PUBLIC_RELEASE);#ifdef DTC_PUBLIC_RELEASE	SPRINTF("DTC 3180/3280 release %d", DTC_PUBLIC_RELEASE);#endif#ifdef T128_PUBLIC_RELEASE	SPRINTF("T128 release %d", T128_PUBLIC_RELEASE);#endif#ifdef GENERIC_NCR5380_PUBLIC_RELEASE	SPRINTF("Generic5380 release %d", GENERIC_NCR5380_PUBLIC_RELEASE);#endif#ifdef PAS16_PUBLIC_RELEASE	SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);#endif	SPRINTF("\nBase Addr: 0x%05lX    ", (long) instance->base);	SPRINTF("io_port: %04x      ", (int) instance->io_port);	if (instance->irq == SCSI_IRQ_NONE)		SPRINTF("IRQ: None.\n");	else		SPRINTF("IRQ: %d.\n", instance->irq);#ifdef DTC_PUBLIC_RELEASE	SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n", dtc_wmaxi, dtc_maxi);#endif#ifdef PAS16_PUBLIC_RELEASE	SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n", pas_wmaxi, pas_maxi);#endif	spin_lock_irq(instance->host_lock);	if (!hostdata->connected)		SPRINTF("scsi%d: no currently connected command\n", instance->host_no);	else		pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, pos, buffer, length);	SPRINTF("scsi%d: issue_queue\n", instance->host_no);	for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)		pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);	SPRINTF("scsi%d: disconnected_queue\n", instance->host_no);	for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)		pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);	spin_unlock_irq(instance->host_lock);		*start = buffer;	if (pos - buffer < offset)		return 0;	else if (pos - buffer - offset < length)		return pos - buffer - offset;	return length;}static char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length){	SPRINTF("scsi%d : destination target %d, lun %d\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun);	SPRINTF("        command = ");	pos = lprint_command(cmd->cmnd, pos, buffer, length);	return (pos);}static char *lprint_command(unsigned char *command, char *pos, char *buffer, int length){	int i, s;	pos = lprint_opcode(command[0], pos, buffer, length);	for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)		SPRINTF("%02x ", command[i]);	SPRINTF("\n");	return (pos);}static char *lprint_opcode(int opcode, char *pos, char *buffer, int length){	SPRINTF("%2d (0x%02x)", opcode, opcode);	return (pos);}/** *	NCR5380_init	-	initialise an NCR5380 *	@instance: adapter to configure *	@flags: control flags * *	Initializes *instance and corresponding 5380 chip, *      with flags OR'd into the initial flags value. * *	Notes : I assume that the host, hostno, and id bits have been *      set correctly.  I don't care about the irq and other fields.  * *	Returns 0 for success * *	Locks: interrupts must be enabled when we are called  */

⌨️ 快捷键说明

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