wd7000.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,669 行 · 第 1/4 页
C
1,669 行
return (0); } if (request_dma(host->dma, "wd7000")) { printk("wd7000_init: can't get DMA channel %d.\n", host->dma); free_irq(host->irq, host); return (0); } wd7000_enable_dma(host); wd7000_enable_intr(host); if (!wd7000_diagnostics(host, ICB_DIAG_FULL)) { free_dma(host->dma); free_irq(host->irq, NULL); return (0); } return (1);}static void wd7000_revision(Adapter * host){ static IcbRevLvl icb = { ICB_OP_GET_REVISION }; icb.phase = 1; /* * Like diagnostics, this is only done at init time, in fact, from * wd7000_detect, so there should be OGMBs available. If it fails, * the only damage will be that the revision will show up as 0.0, * which in turn means that scatter/gather will be disabled. */ mail_out(host, (struct scb *) &icb); while (icb.phase) { cpu_relax(); /* wait for completion */ barrier(); } host->rev1 = icb.primary; host->rev2 = icb.secondary;}#undef SPRINTF#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host){ dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length); /* * Currently this is a no-op */ dprintk("Sorry, this function is currently out of order...\n"); return (length);}static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout){ Adapter *adapter = (Adapter *)host->hostdata; unsigned long flags; char *pos = buffer;#ifdef WD7000_DEBUG Mailbox *ogmbs, *icmbs; short count;#endif /* * Has data been written to the file ? */ if (inout) return (wd7000_set_info(buffer, length, host)); spin_lock_irqsave(host->host_lock, flags); SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2); SPRINTF(" IO base: 0x%x\n", adapter->iobase); SPRINTF(" IRQ: %d\n", adapter->irq); SPRINTF(" DMA channel: %d\n", adapter->dma); SPRINTF(" Interrupts: %d\n", adapter->int_counter); SPRINTF(" BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125); SPRINTF(" BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);#ifdef WD7000_DEBUG ogmbs = adapter->mb.ogmb; icmbs = adapter->mb.icmb; SPRINTF("\nControl port value: 0x%x\n", adapter->control); SPRINTF("Incoming mailbox:\n"); SPRINTF(" size: %d\n", ICMB_CNT); SPRINTF(" queued messages: "); for (i = count = 0; i < ICMB_CNT; i++) if (icmbs[i].status) { count++; SPRINTF("0x%x ", i); } SPRINTF(count ? "\n" : "none\n"); SPRINTF("Outgoing mailbox:\n"); SPRINTF(" size: %d\n", OGMB_CNT); SPRINTF(" next message: 0x%x\n", adapter->next_ogmb); SPRINTF(" queued messages: "); for (i = count = 0; i < OGMB_CNT; i++) if (ogmbs[i].status) { count++; SPRINTF("0x%x ", i); } SPRINTF(count ? "\n" : "none\n");#endif spin_unlock_irqrestore(host->host_lock, flags); /* * Calculate start of next buffer, and return value. */ *start = buffer + offset; if ((pos - buffer) < offset) return (0); else if ((pos - buffer - offset) < length) return (pos - buffer - offset); else return (length);}/* * Returns the number of adapters this driver is supporting. * * The source for hosts.c says to wait to call scsi_register until 100% * sure about an adapter. We need to do it a little sooner here; we * need the storage set up by scsi_register before wd7000_init, and * changing the location of an Adapter structure is more trouble than * calling scsi_unregister. * */static int wd7000_detect(struct scsi_host_template *tpnt){ short present = 0, biosaddr_ptr, sig_ptr, i, pass; short biosptr[NUM_CONFIGS]; unsigned iobase; Adapter *host = NULL; struct Scsi_Host *sh; int unit = 0; dprintk("wd7000_detect: started\n");#ifdef MODULE if (wd7000) wd7000_setup(wd7000);#endif for (i = 0; i < UNITS; wd7000_host[i++] = NULL); for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1); tpnt->proc_name = "wd7000"; tpnt->proc_info = &wd7000_proc_info; /* * Set up SCB free list, which is shared by all adapters */ init_scbs(); for (pass = 0; pass < NUM_CONFIGS; pass++) { /* * First, search for BIOS SIGNATURE... */ for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++) for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) { for (i = 0; i < pass; i++) if (biosptr[i] == biosaddr_ptr) break; if (i == pass) { void *biosaddr = ioremap(wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs, signatures[sig_ptr].len); short bios_match = 0; if (biosaddr) bios_match = memcmp((char *) biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len); iounmap(biosaddr); if (!bios_match) goto bios_matched; } } bios_matched: /* * BIOS SIGNATURE has been found. */#ifdef WD7000_DEBUG dprintk("wd7000_detect: pass %d\n", pass + 1); if (biosaddr_ptr == NUM_ADDRS) dprintk("WD-7000 SST BIOS not detected...\n"); else dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n", wd7000_biosaddr[biosaddr_ptr]);#endif if (configs[pass].irq < 0) continue; if (unit == UNITS) continue; iobase = configs[pass].iobase; dprintk("wd7000_detect: check IO 0x%x region...\n", iobase); if (request_region(iobase, 4, "wd7000")) { dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase); /* * ASC reset... */ outb(ASC_RES, iobase + ASC_CONTROL); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 100); outb(0, iobase + ASC_CONTROL); if (WAIT(iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { dprintk("failed!\n"); goto err_release; } else dprintk("ok!\n"); if (inb(iobase + ASC_INTR_STAT) == 1) { /* * We register here, to get a pointer to the extra space, * which we'll use as the Adapter structure (host) for * this adapter. It is located just after the registered * Scsi_Host structure (sh), and is located by the empty * array hostdata. */ sh = scsi_register(tpnt, sizeof(Adapter)); if (sh == NULL) goto err_release; host = (Adapter *) sh->hostdata; dprintk("wd7000_detect: adapter allocated at 0x%x\n", (int) host); memset(host, 0, sizeof(Adapter)); host->irq = configs[pass].irq; host->dma = configs[pass].dma; host->iobase = iobase; host->int_counter = 0; host->bus_on = configs[pass].bus_on; host->bus_off = configs[pass].bus_off; host->sh = wd7000_host[unit] = sh; unit++; dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma); if (!wd7000_init(host)) /* Initialization failed */ goto err_unregister; /* * OK from here - we'll use this adapter/configuration. */ wd7000_revision(host); /* important for scatter/gather */ /* * For boards before rev 6.0, scatter/gather isn't supported. */ if (host->rev1 < 6) sh->sg_tablesize = SG_NONE; present++; /* count it */ if (biosaddr_ptr != NUM_ADDRS) biosptr[pass] = biosaddr_ptr; printk(KERN_INFO "Western Digital WD-7000 (rev %d.%d) ", host->rev1, host->rev2); printk("using IO 0x%x, IRQ %d, DMA %d.\n", host->iobase, host->irq, host->dma); printk(" BUS_ON time: %dns, BUS_OFF time: %dns\n", host->bus_on * 125, host->bus_off * 125); } } else dprintk("wd7000_detect: IO 0x%x region already allocated!\n", iobase); continue; err_unregister: scsi_unregister(sh); err_release: release_region(iobase, 4); } if (!present) printk("Failed initialization of WD-7000 SCSI card!\n"); return (present);}static int wd7000_release(struct Scsi_Host *shost){ if (shost->irq) free_irq(shost->irq, NULL); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); scsi_unregister(shost); return 0;}#if 0/* * I have absolutely NO idea how to do an abort with the WD7000... */static int wd7000_abort(Scsi_Cmnd * SCpnt){ Adapter *host = (Adapter *) SCpnt->device->host->hostdata; if (inb(host->iobase + ASC_STAT) & INT_IM) { printk("wd7000_abort: lost interrupt\n"); wd7000_intr_handle(host->irq, NULL, NULL); return FAILED; } return FAILED;}#endif/* * Last resort. Reinitialize the board. */static int wd7000_host_reset(struct scsi_cmnd *SCpnt){ Adapter *host = (Adapter *) SCpnt->device->host->hostdata; if (wd7000_adapter_reset(host) < 0) return FAILED; wd7000_enable_intr(host); return SUCCESS;}/* * This was borrowed directly from aha1542.c. (Zaga) */static int wd7000_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *ip){ char b[BDEVNAME_SIZE]; dprintk("wd7000_biosparam: dev=%s, size=%d, ", bdevname(bdev, b), capacity); (void)b; /* unused var warning? */ /* * try default translation */ ip[0] = 64; ip[1] = 32; ip[2] = capacity >> 11; /* * for disks >1GB do some guessing */ if (ip[2] >= 1024) { int info[3]; /* * try to figure out the geometry from the partition table */ if ((scsicam_bios_param(bdev, capacity, info) < 0) || !(((info[0] == 64) && (info[1] == 32)) || ((info[0] == 255) && (info[1] == 63)))) { printk("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" " using extended translation.\n"); ip[0] = 255; ip[1] = 63; ip[2] = (unsigned long) capacity / (255 * 63); } else { ip[0] = info[0]; ip[1] = info[1]; ip[2] = info[2]; if (info[0] == 255) printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __FUNCTION__); } } dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]); dprintk("WARNING: check, if the bios geometry is correct.\n"); return (0);}MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");MODULE_LICENSE("GPL");static struct scsi_host_template driver_template = { .proc_name = "wd7000", .proc_info = wd7000_proc_info, .name = "Western Digital WD-7000", .detect = wd7000_detect, .release = wd7000_release, .queuecommand = wd7000_queuecommand, .eh_host_reset_handler = wd7000_host_reset, .bios_param = wd7000_biosparam, .can_queue = WD7000_Q, .this_id = 7, .sg_tablesize = WD7000_SG, .cmd_per_lun = 1, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING,};#include "scsi_module.c"
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?