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 + -
显示快捷键?