wd33c93.c

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

C
2,145
字号
		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... */	tmp = (struct scsi_cmnd *) hostdata->disconnected_Q;	while (tmp) {		if (tmp == cmd) {			printk			    ("scsi%d: Abort - command %ld found on disconnected_Q - ",			     instance->host_no, cmd->serial_number);			printk("Abort SNOOZE. ");			enable_irq(cmd->device->host->irq);			return FAILED;		}		tmp = (struct scsi_cmnd *) tmp->host_scribble;	}/* * 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. *//*   sti();*/	wd33c93_execute(instance);	enable_irq(cmd->device->host->irq);	printk("scsi%d: warning : SCSI command probably completed successfully"	       "         before abortion. ", instance->host_no);	return FAILED;}#define MAX_WD33C93_HOSTS 4#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 intwd33c93_setup(char *str){	int i;	char *p1, *p2;	/* The kernel does some processing of the command-line before calling	 * this function: If it begins with any decimal or hex number arguments,	 * ints[0] = how many numbers found and ints[1] through [n] are the values	 * themselves. str points to where the non-numeric arguments (if any)	 * start: We do our own parsing of those. We construct synthetic 'nosync'	 * keywords out of numeric args (to maintain compatibility with older	 * versions) and then add the rest of the arguments.	 */	p1 = setup_buffer;	*p1 = '\0';	if (str)		strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));	setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';	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;	return 1;}__setup("wd33c93=", wd33c93_setup);/* check_setup_args() returns index if key found, 0 if not */static intcheck_setup_args(char *key, int *flags, 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 (!strncmp(setup_args[x], "next", strlen("next")))			return 0;	}	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;}/* * Calculate internal data-transfer-clock cycle from input-clock * frequency (/MHz) and fill 'sx_table'. * * The original driver used to rely on a fixed sx_table, containing periods * for (only) the lower limits of the respective input-clock-frequency ranges * (8-10/12-15/16-20 MHz). Although it seems, that no problems ocurred with * this setting so far, it might be desirable to adjust the transfer periods * closer to the really attached, possibly 25% higher, input-clock, since * - the wd33c93 may really use a significant shorter period, than it has *   negotiated (eg. thrashing the target, which expects 4/8MHz, with 5/10MHz *   instead). * - the wd33c93 may ask the target for a lower transfer rate, than the target *   is capable of (eg. negotiating for an assumed minimum of 252ns instead of *   possible 200ns, which indeed shows up in tests as an approx. 10% lower *   transfer rate). */static inline unsigned intround_4(unsigned int x){	switch (x & 3) {		case 1: --x;			break;		case 2: ++x;		case 3: ++x;	}	return x;}static voidcalc_sx_table(unsigned int mhz, struct sx_period sx_table[9]){	unsigned int d, i;	if (mhz < 11)		d = 2;	/* divisor for  8-10 MHz input-clock */	else if (mhz < 16)		d = 3;	/* divisor for 12-15 MHz input-clock */	else		d = 4;	/* divisor for 16-20 MHz input-clock */	d = (100000 * d) / 2 / mhz; /* 100 x DTCC / nanosec */	sx_table[0].period_ns = 1;	sx_table[0].reg_value = 0x20;	for (i = 1; i < 8; i++) {		sx_table[i].period_ns = round_4((i+1)*d / 100);		sx_table[i].reg_value = (i+1)*0x10;	}	sx_table[7].reg_value = 0;	sx_table[8].period_ns = 0;	sx_table[8].reg_value = 0;}/* * check and, maybe, map an init- or "clock:"- argument. */static ucharset_clk_freq(int freq, int *mhz){	int x = freq;	if (WD33C93_FS_8_10 == freq)		freq = 8;	else if (WD33C93_FS_12_15 == freq)		freq = 12;	else if (WD33C93_FS_16_20 == freq)		freq = 16;	else if (freq > 7 && freq < 11)		x = WD33C93_FS_8_10;		else if (freq > 11 && freq < 16)		x = WD33C93_FS_12_15;		else if (freq > 15 && freq < 21)		x = WD33C93_FS_16_20;	else {			/* Hmm, wouldn't it be safer to assume highest freq here? */		x = WD33C93_FS_8_10;		freq = 8;	}	*mhz = freq;	return x;}/* * to be used with the resync: fast: ... options */static inline void set_resync ( struct WD33C93_hostdata *hd, int mask ){	int i;	for (i = 0; i < 8; i++)		if (mask & (1 << i))			hd->sync_stat[i] = SS_UNSET;}voidwd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,	     dma_setup_t setup, dma_stop_t stop, int clock_freq){	struct WD33C93_hostdata *hostdata;	int i;	int flags;	int val;	char buf[32];	if (!done_setup && setup_strings)		wd33c93_setup(setup_strings);	hostdata = (struct WD33C93_hostdata *) instance->hostdata;	hostdata->regs = regs;	hostdata->clock_freq = set_clk_freq(clock_freq, &i);	calc_sx_table(i, hostdata->sx_table);	hostdata->dma_setup = setup;	hostdata->dma_stop = stop;	hostdata->dma_bounce_buffer = NULL;	hostdata->dma_bounce_len = 0;	for (i = 0; i < 8; i++) {		hostdata->busy[i] = 0;		hostdata->sync_xfer[i] =			calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF,					0, hostdata->sx_table);		hostdata->sync_stat[i] = SS_UNSET;	/* using default sync values */#ifdef PROC_STATISTICS		hostdata->cmd_cnt[i] = 0;		hostdata->disc_allowed_cnt[i] = 0;		hostdata->disc_done_cnt[i] = 0;#endif	}	hostdata->input_Q = NULL;	hostdata->selecting = NULL;	hostdata->connected = NULL;	hostdata->disconnected_Q = NULL;	hostdata->state = S_UNCONNECTED;	hostdata->dma = D_DMA_OFF;	hostdata->level2 = L2_BASIC;	hostdata->disconnect = DIS_ADAPTIVE;	hostdata->args = DEBUG_DEFAULTS;	hostdata->incoming_ptr = 0;	hostdata->outgoing_len = 0;	hostdata->default_sx_per = DEFAULT_SX_PER;	hostdata->no_sync = 0xff;	/* sync defaults to off */	hostdata->no_dma = 0;	/* default is DMA enabled */	hostdata->fast = 0;	/* default is Fast SCSI transfers disabled */	hostdata->dma_mode = CTRL_DMA;	/* default is Single Byte DMA */#ifdef PROC_INTERFACE	hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS |	    PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP;#ifdef PROC_STATISTICS	hostdata->dma_cnt = 0;	hostdata->pio_cnt = 0;	hostdata->int_cnt = 0;#endif#endif	if (check_setup_args("clock", &flags, &val, buf)) {		hostdata->clock_freq = set_clk_freq(val, &val);		calc_sx_table(val, hostdata->sx_table);	}	if (check_setup_args("nosync", &flags, &val, buf))		hostdata->no_sync = val;	if (check_setup_args("nodma", &flags, &val, buf))		hostdata->no_dma = (val == -1) ? 1 : val;	if (check_setup_args("period", &flags, &val, buf))		hostdata->default_sx_per =		    hostdata->sx_table[round_period((unsigned int) val,		                                    hostdata->sx_table)].period_ns;	if (check_setup_args("disconnect", &flags, &val, buf)) {		if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))			hostdata->disconnect = val;		else			hostdata->disconnect = DIS_ADAPTIVE;	}	if (check_setup_args("level2", &flags, &val, buf))		hostdata->level2 = val;	if (check_setup_args("debug", &flags, &val, buf))		hostdata->args = val & DB_MASK;	if (check_setup_args("burst", &flags, &val, buf))		hostdata->dma_mode = val ? CTRL_BURST:CTRL_DMA;	if (WD33C93_FS_16_20 == hostdata->clock_freq /* divisor 4 */		&& check_setup_args("fast", &flags, &val, buf))		hostdata->fast = !!val;	if ((i = check_setup_args("next", &flags, &val, buf))) {		while (i)			setup_used[--i] = 1;	}#ifdef PROC_INTERFACE	if (check_setup_args("proc", &flags, &val, buf))		hostdata->proc = val;#endif	spin_lock_irq(&hostdata->lock);	reset_wd33c93(instance);	spin_unlock_irq(&hostdata->lock);	printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",	       instance->host_no,	       (hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip ==							    C_WD33C93A) ?	       "WD33c93A" : (hostdata->chip ==			     C_WD33C93B) ? "WD33c93B" : "unknown",	       hostdata->microcode, hostdata->no_sync, hostdata->no_dma);#ifdef DEBUGGING_ON	printk(" debug_flags=0x%02x\n", hostdata->args);#else	printk(" debugging=OFF\n");#endif	printk("           setup_args=");	for (i = 0; i < MAX_SETUP_ARGS; i++)		printk("%s,", setup_args[i]);	printk("\n");	printk("           Version %s - %s, Compiled %s at %s\n",	       WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__);}intwd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in){#ifdef PROC_INTERFACE	char *bp;	char tbuf[128];	struct WD33C93_hostdata *hd;	struct scsi_cmnd *cmd;	int x;	static int stop = 0;	hd = (struct WD33C93_hostdata *) instance->hostdata;/* If 'in' is TRUE we need to _read_ the proc file. We accept the following * keywords (same format as command-line, but arguments are not optional): *    debug *    disconnect *    period *    resync *    proc *    nodma *    level2 *    burst *    fast *    nosync */	if (in) {		buf[len] = '\0';		for (bp = buf; *bp; ) {			while (',' == *bp || ' ' == *bp)				++bp;		if (!strncmp(bp, "debug:", 6)) {				hd->args = simple_strtoul(bp+6, &bp, 0) & DB_MASK;		} else if (!strncmp(bp, "disconnect:", 11)) {				x = simple_strtoul(bp+11, &bp, 0);			if (x < DIS_NEVER || x > DIS_ALWAYS)				x = DIS_ADAPTIVE;			hd->disconnect = x;		} else if (!strncmp(bp, "period:", 7)) {			x = simple_strtoul(bp+7, &bp, 0);			hd->default_sx_per =				hd->sx_table[round_period((unsigned int) x,							  hd->sx_table)].period_ns;		} else if (!strncmp(bp, "resync:", 7)) {				set_resync(hd, (int)simple_strtoul(bp+7, &bp, 0));		} else if (!strncmp(bp, "proc:", 5)) {				hd->proc = simple_strtoul(bp+5, &bp, 0);		} else if (!strncmp(bp, "nodma:", 6)) {				hd->no_dma = simple_strtoul(bp+6, &bp, 0);		} else if (!strncmp(bp, "level2:", 7)) {				hd->level2 = simple_strtoul(bp+7, &bp, 0);			} else if (!strncmp(bp, "burst:", 6)) {				hd->dma_mode =					simple_strtol(bp+6, &bp, 0) ? CTRL_BURST:CTRL_DMA;			} else if (!strncmp(bp, "fast:", 5)) {				x = !!simple_strtol(bp+5, &bp, 0);				if (x != hd->fast)					set_resync(hd, 0xff);				hd->fast = x;			} else if (!strncmp(bp, "nosync:", 7)) {				x = simple_strtoul(bp+7, &bp, 0);				set_resync(hd, x ^ hd->no_sync);				hd->no_sync = x;			} else {				break; /* unknown keyword,syntax-error,... */			}		}		return len;	}	spin_lock_irq(&hd->lock);	bp = buf;	*bp = '\0';	if (hd->proc & PR_VERSION) {		sprintf(tbuf, "\nVersion %s - %s. Compiled %s %s",			WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__);		strcat(bp, tbuf);	}	if (hd->proc & PR_INFO) {		sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d"			" dma_mode=%02x fast=%d",			hd->clock_freq, hd->no_sync, hd->no_dma, hd->dma_mode, hd->fast);

⌨️ 快捷键说明

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