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