in2000.c

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

C
2,045
字号
	return x;}static int in2000_bus_reset(Scsi_Cmnd * cmd){	struct Scsi_Host *instance;	struct IN2000_hostdata *hostdata;	int x;	unsigned long flags;	instance = cmd->device->host;	hostdata = (struct IN2000_hostdata *) instance->hostdata;	printk(KERN_WARNING "scsi%d: Reset. ", instance->host_no);	spin_lock_irqsave(instance->host_lock, flags);	/* do scsi-reset here */	reset_hardware(instance, RESET_CARD_AND_BUS);	for (x = 0; x < 8; x++) {		hostdata->busy[x] = 0;		hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);		hostdata->sync_stat[x] = SS_UNSET;	/* using default sync values */	}	hostdata->input_Q = NULL;	hostdata->selecting = NULL;	hostdata->connected = NULL;	hostdata->disconnected_Q = NULL;	hostdata->state = S_UNCONNECTED;	hostdata->fifo = FI_FIFO_UNUSED;	hostdata->incoming_ptr = 0;	hostdata->outgoing_len = 0;	cmd->result = DID_RESET << 16;	spin_unlock_irqrestore(instance->host_lock, flags);	return SUCCESS;}static int __in2000_abort(Scsi_Cmnd * cmd){	struct Scsi_Host *instance;	struct IN2000_hostdata *hostdata;	Scsi_Cmnd *tmp, *prev;	uchar sr, asr;	unsigned long timeout;	instance = cmd->device->host;	hostdata = (struct IN2000_hostdata *) instance->hostdata;	printk(KERN_DEBUG "scsi%d: Abort-", instance->host_no);	printk("(asr=%02x,count=%ld,resid=%d,buf_resid=%d,have_data=%d,FC=%02x)- ", READ_AUX_STAT(), read_3393_count(hostdata), cmd->SCp.this_residual, cmd->SCp.buffers_residual, cmd->SCp.have_data_in, read1_io(IO_FIFO_COUNT));/* * Case 1 : If the command hasn't been issued yet, we simply remove it *     from the inout_Q. */	tmp = (Scsi_Cmnd *) hostdata->input_Q;	prev = NULL;	while (tmp) {		if (tmp == cmd) {			if (prev)				prev->host_scribble = cmd->host_scribble;			cmd->host_scribble = NULL;			cmd->result = DID_ABORT << 16;			printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->serial_number);			cmd->scsi_done(cmd);			return SUCCESS;		}		prev = tmp;		tmp = (Scsi_Cmnd *) tmp->host_scribble;	}/* * Case 2 : If the command is connected, we're going to fail the abort *     and let the high level SCSI driver retry at a later time or *     issue a reset. * *     Timeouts, and therefore aborted commands, will be highly unlikely *     and handling them cleanly in this situation would make the common *     case of noresets less efficient, and would pollute our code.  So, *     we fail. */	if (hostdata->connected == cmd) {		printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->serial_number);		printk("sending wd33c93 ABORT command - ");		write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);		write_3393_cmd(hostdata, WD_CMD_ABORT);/* Now we have to attempt to flush out the FIFO... */		printk("flushing fifo - ");		timeout = 1000000;		do {			asr = READ_AUX_STAT();			if (asr & ASR_DBR)				read_3393(hostdata, WD_DATA);		} while (!(asr & ASR_INT) && timeout-- > 0);		sr = read_3393(hostdata, WD_SCSI_STATUS);		printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", asr, sr, read_3393_count(hostdata), timeout);		/*		 * Abort command processed.		 * Still connected.		 * We must disconnect.		 */		printk("sending wd33c93 DISCONNECT command - ");		write_3393_cmd(hostdata, WD_CMD_DISCONNECT);		timeout = 1000000;		asr = READ_AUX_STAT();		while ((asr & ASR_CIP) && timeout-- > 0)			asr = READ_AUX_STAT();		sr = read_3393(hostdata, WD_SCSI_STATUS);		printk("asr=%02x, sr=%02x.", asr, sr);		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);		hostdata->connected = NULL;		hostdata->state = S_UNCONNECTED;		cmd->result = DID_ABORT << 16;		cmd->scsi_done(cmd);		in2000_execute(instance);		return SUCCESS;	}/* * Case 3: If the command is currently disconnected from the bus, * we're not going to expend much effort here: Let's just return * an ABORT_SNOOZE and hope for the best... */	for (tmp = (Scsi_Cmnd *) hostdata->disconnected_Q; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble)		if (cmd == tmp) {			printk(KERN_DEBUG "scsi%d: unable to abort disconnected command.\n", instance->host_no);			return FAILED;		}/* * Case 4 : If we reached this point, the command was not found in any of *     the queues. * * We probably reached this point because of an unlikely race condition * between the command completing successfully and the abortion code, * so we won't panic, but we will notify the user in case something really * broke. */	in2000_execute(instance);	printk("scsi%d: warning : SCSI command probably completed successfully" "         before abortion. ", instance->host_no);	return SUCCESS;}static int in2000_abort(Scsi_Cmnd * cmd){	int rc;	spin_lock_irq(cmd->device->host->host_lock);	rc = __in2000_abort(cmd);	spin_unlock_irq(cmd->device->host->host_lock);	return rc;}#define MAX_IN2000_HOSTS 3#define MAX_SETUP_ARGS ARRAY_SIZE(setup_args)#define SETUP_BUFFER_SIZE 200static char setup_buffer[SETUP_BUFFER_SIZE];static char setup_used[MAX_SETUP_ARGS];static int done_setup = 0;static void __init in2000_setup(char *str, int *ints){	int i;	char *p1, *p2;	strlcpy(setup_buffer, str, SETUP_BUFFER_SIZE);	p1 = setup_buffer;	i = 0;	while (*p1 && (i < MAX_SETUP_ARGS)) {		p2 = strchr(p1, ',');		if (p2) {			*p2 = '\0';			if (p1 != p2)				setup_args[i] = p1;			p1 = p2 + 1;			i++;		} else {			setup_args[i] = p1;			break;		}	}	for (i = 0; i < MAX_SETUP_ARGS; i++)		setup_used[i] = 0;	done_setup = 1;}/* check_setup_args() returns index if key found, 0 if not */static int __init check_setup_args(char *key, int *val, char *buf){	int x;	char *cp;	for (x = 0; x < MAX_SETUP_ARGS; x++) {		if (setup_used[x])			continue;		if (!strncmp(setup_args[x], key, strlen(key)))			break;	}	if (x == MAX_SETUP_ARGS)		return 0;	setup_used[x] = 1;	cp = setup_args[x] + strlen(key);	*val = -1;	if (*cp != ':')		return ++x;	cp++;	if ((*cp >= '0') && (*cp <= '9')) {		*val = simple_strtoul(cp, NULL, 0);	}	return ++x;}/* The "correct" (ie portable) way to access memory-mapped hardware * such as the IN2000 EPROM and dip switch is through the use of * special macros declared in 'asm/io.h'. We use readb() and readl() * when reading from the card's BIOS area in in2000_detect(). */static u32 bios_tab[] in2000__INITDATA = {	0xc8000,	0xd0000,	0xd8000,	0};static unsigned short base_tab[] in2000__INITDATA = {	0x220,	0x200,	0x110,	0x100,};static int int_tab[] in2000__INITDATA = {	15,	14,	11,	10};static int probe_bios(u32 addr, u32 *s1, uchar *switches){	void __iomem *p = ioremap(addr, 0x34);	if (!p)		return 0;	*s1 = readl(p + 0x10);	if (*s1 == 0x41564f4e || readl(p + 0x30) == 0x61776c41) {		/* Read the switch image that's mapped into EPROM space */		*switches = ~readb(p + 0x20);		iounmap(p);		return 1;	}	iounmap(p);	return 0;}static int __init in2000_detect(struct scsi_host_template * tpnt){	struct Scsi_Host *instance;	struct IN2000_hostdata *hostdata;	int detect_count;	int bios;	int x;	unsigned short base;	uchar switches;	uchar hrev;	unsigned long flags;	int val;	char buf[32];/* Thanks to help from Bill Earnest, probing for IN2000 cards is a * pretty straightforward and fool-proof operation. There are 3 * possible locations for the IN2000 EPROM in memory space - if we * find a BIOS signature, we can read the dip switch settings from * the byte at BIOS+32 (shadowed in by logic on the card). From 2 * of the switch bits we get the card's address in IO space. There's * an image of the dip switch there, also, so we have a way to back- * check that this really is an IN2000 card. Very nifty. Use the * 'ioport:xx' command-line parameter if your BIOS EPROM is absent * or disabled. */	if (!done_setup && setup_strings)		in2000_setup(setup_strings, NULL);	detect_count = 0;	for (bios = 0; bios_tab[bios]; bios++) {		u32 s1 = 0;		if (check_setup_args("ioport", &val, buf)) {			base = val;			switches = ~inb(base + IO_SWITCHES) & 0xff;			printk("Forcing IN2000 detection at IOport 0x%x ", base);			bios = 2;		}/* * There have been a couple of BIOS versions with different layouts * for the obvious ID strings. We look for the 2 most common ones and * hope that they cover all the cases... */		else if (probe_bios(bios_tab[bios], &s1, &switches)) {			printk("Found IN2000 BIOS at 0x%x ", (unsigned int) bios_tab[bios]);/* Find out where the IO space is */			x = switches & (SW_ADDR0 | SW_ADDR1);			base = base_tab[x];/* Check for the IN2000 signature in IO space. */			x = ~inb(base + IO_SWITCHES) & 0xff;			if (x != switches) {				printk("Bad IO signature: %02x vs %02x.\n", x, switches);				continue;			}		} else			continue;/* OK. We have a base address for the IO ports - run a few safety checks */		if (!(switches & SW_BIT7)) {	/* I _think_ all cards do this */			printk("There is no IN-2000 SCSI card at IOport 0x%03x!\n", base);			continue;		}/* Let's assume any hardware version will work, although the driver * has only been tested on 0x21, 0x22, 0x25, 0x26, and 0x27. We'll * print out the rev number for reference later, but accept them all. */		hrev = inb(base + IO_HARDWARE);		/* Bit 2 tells us if interrupts are disabled */		if (switches & SW_DISINT) {			printk("The IN-2000 SCSI card at IOport 0x%03x ", base);			printk("is not configured for interrupt operation!\n");			printk("This driver requires an interrupt: cancelling detection.\n");			continue;		}/* Ok. We accept that there's an IN2000 at ioaddr 'base'. Now * initialize it. */		tpnt->proc_name = "in2000";		instance = scsi_register(tpnt, sizeof(struct IN2000_hostdata));		if (instance == NULL)			continue;		detect_count++;		hostdata = (struct IN2000_hostdata *) instance->hostdata;		instance->io_port = hostdata->io_base = base;		hostdata->dip_switch = switches;		hostdata->hrev = hrev;		write1_io(0, IO_FIFO_WRITE);	/* clear fifo counter */		write1_io(0, IO_FIFO_READ);	/* start fifo out in read mode */		write1_io(0, IO_INTR_MASK);	/* allow all ints */		x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];		if (request_irq(x, in2000_intr, IRQF_DISABLED, "in2000", instance)) {			printk("in2000_detect: Unable to allocate IRQ.\n");			detect_count--;			continue;		}		instance->irq = x;		instance->n_io_port = 13;		request_region(base, 13, "in2000");	/* lock in this IO space for our use */		for (x = 0; x < 8; x++) {			hostdata->busy[x] = 0;			hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);			hostdata->sync_stat[x] = SS_UNSET;	/* using default sync values */#ifdef PROC_STATISTICS			hostdata->cmd_cnt[x] = 0;			hostdata->disc_allowed_cnt[x] = 0;			hostdata->disc_done_cnt[x] = 0;#endif		}		hostdata->input_Q = NULL;		hostdata->selecting = NULL;		hostdata->connected = NULL;		hostdata->disconnected_Q = NULL;		hostdata->state = S_UNCONNECTED;		hostdata->fifo = FI_FIFO_UNUSED;		hostdata->level2 = L2_BASIC;		hostdata->disconnect = DIS_ADAPTIVE;		hostdata->args = DEBUG

⌨️ 快捷键说明

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