sym_glue.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,552 行 · 第 1/5 页
C
2,552 行
#ifndef MODULE__setup("sym53c8xx=", sym53c8xx_setup);#endif/* * Read and check the PCI configuration for any detected NCR * boards and save data for attaching after all boards have * been detected. */static int __devinitsym53c8xx_pci_init(struct pci_dev *pdev, struct sym_device *device){ struct sym_pci_chip *chip; u_long base, base_2; u_long base_c, base_2_c, io_port; int i; u_short device_id, status_reg; u_char revision; /* Choose some short name for this device */ sprintf(device->s.inst_name, "sym.%d.%d.%d", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); device_id = pdev->device; io_port = pdev->resource[0].start; base_c = pdev->resource[1].start; i = pci_get_base_address(pdev, 1, &base); base_2_c = pdev->resource[i].start; pci_get_base_address(pdev, i, &base_2); base &= PCI_BASE_ADDRESS_MEM_MASK; base_2 &= PCI_BASE_ADDRESS_MEM_MASK; pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); /* * If user excluded this chip, do not initialize it. */ if (io_port) { for (i = 0 ; i < 8 ; i++) { if (sym_driver_setup.excludes[i] == io_port) return -1; } } /* * Check if the chip is supported. */ chip = sym_lookup_pci_chip_table(device_id, revision); if (!chip) { printf_info("%s: device not supported\n", sym_name(device)); return -1; } /* * Check if the chip has been assigned resources we need. * XXX: can this still happen with Linux 2.6's PCI layer? */#ifdef SYM_CONF_IOMAPPED if (!io_port) { printf_info("%s: IO base address disabled.\n", sym_name(device)); return -1; }#else if (!base) { printf_info("%s: MMIO base address disabled.\n", sym_name(device)); return -1; }#endif /* * Ignore Symbios chips controlled by various RAID controllers. * These controllers set value 0x52414944 at RAM end - 16. */#if defined(__i386__) if (base_2_c) { unsigned int ram_size, ram_val; void *ram_ptr; if (chip->features & FE_RAM8K) ram_size = 8192; else ram_size = 4096; ram_ptr = ioremap(base_2_c, ram_size); if (ram_ptr) { ram_val = readl_raw(ram_ptr + ram_size - 16); iounmap(ram_ptr); if (ram_val == 0x52414944) { printf_info("%s: not initializing, " "driven by RAID controller.\n", sym_name(device)); return -1; } } }#endif /* i386 and PCI MEMORY accessible */ /* * Copy the chip description to our device structure, * so we can make it match the actual device and options. */ memcpy(&device->chip, chip, sizeof(device->chip)); device->chip.revision_id = revision; /* * Some features are required to be enabled in order to * work around some chip problems. :) ;) * (ITEM 12 of a DEL about the 896 I haven't yet). * We must ensure the chip will use WRITE AND INVALIDATE. * The revision number limit is for now arbitrary. */ if (device_id == PCI_DEVICE_ID_NCR_53C896 && revision < 0x4) { chip->features |= (FE_WRIE | FE_CLSE); } /* If the chip can do Memory Write Invalidate, enable it */ if (chip->features & FE_WRIE) { if (pci_set_mwi(pdev)) return -1; } /* * Work around for errant bit in 895A. The 66Mhz * capable bit is set erroneously. Clear this bit. * (Item 1 DEL 533) * * Make sure Config space and Features agree. * * Recall: writes are not normal to status register - * write a 1 to clear and a 0 to leave unchanged. * Can only reset bits. */ pci_read_config_word(pdev, PCI_STATUS, &status_reg); if (chip->features & FE_66MHZ) { if (!(status_reg & PCI_STATUS_66MHZ)) chip->features &= ~FE_66MHZ; } else { if (status_reg & PCI_STATUS_66MHZ) { status_reg = PCI_STATUS_66MHZ; pci_write_config_word(pdev, PCI_STATUS, status_reg); pci_read_config_word(pdev, PCI_STATUS, &status_reg); } } /* * Initialise device structure with items required by sym_attach. */ device->pdev = pdev; device->s.base = base; device->s.base_2 = base_2; device->s.base_c = base_c; device->s.base_2_c = base_2_c; device->s.io_port = io_port; device->s.irq = pdev->irq; return 0;}/* * The NCR PQS and PDS cards are constructed as a DEC bridge * behind which sits a proprietary NCR memory controller and * either four or two 53c875s as separate devices. We can tell * if an 875 is part of a PQS/PDS or not since if it is, it will * be on the same bus as the memory controller. In its usual * mode of operation, the 875s are slaved to the memory * controller for all transfers. To operate with the Linux * driver, the memory controller is disabled and the 875s * freed to function independently. The only wrinkle is that * the preset SCSI ID (which may be zero) must be read in from * a special configuration space register of the 875. */void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev){ int slot; for (slot = 0; slot < 256; slot++) { u8 tmp; struct pci_dev *memc = pci_get_slot(pdev->bus, slot); if (!memc || memc->vendor != 0x101a || memc->device == 0x0009) { pci_dev_put(memc); continue; } /* * We set these bits in the memory controller once per 875. * This isn't a problem in practice. */ /* bit 1: allow individual 875 configuration */ pci_read_config_byte(memc, 0x44, &tmp); tmp |= 0x2; pci_write_config_byte(memc, 0x44, tmp); /* bit 2: drive individual 875 interrupts to the bus */ pci_read_config_byte(memc, 0x45, &tmp); tmp |= 0x4; pci_write_config_byte(memc, 0x45, tmp); pci_read_config_byte(pdev, 0x84, &tmp); sym_dev->host_id = tmp; pci_dev_put(memc); break; }}/* * Called before unloading the module. * Detach the host. * We have to free resources and halt the NCR chip. */static int sym_detach(struct sym_hcb *np){ printk("%s: detaching ...\n", sym_name(np)); del_timer_sync(&np->s.timer); /* * Reset NCR chip. * We should use sym_soft_reset(), but we don't want to do * so, since we may not be safe if interrupts occur. */ printk("%s: resetting chip\n", sym_name(np)); OUTB (nc_istat, SRST); UDELAY (10); OUTB (nc_istat, 0); sym_free_resources(np); return 1;}MODULE_LICENSE("Dual BSD/GPL");/* * Driver host template. */static struct scsi_host_template sym2_template = { .module = THIS_MODULE, .name = "sym53c8xx", .info = sym53c8xx_info, .queuecommand = sym53c8xx_queue_command, .slave_configure = sym53c8xx_slave_configure, .eh_abort_handler = sym53c8xx_eh_abort_handler, .eh_device_reset_handler = sym53c8xx_eh_device_reset_handler, .eh_bus_reset_handler = sym53c8xx_eh_bus_reset_handler, .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, .this_id = 7, .use_clustering = DISABLE_CLUSTERING,#ifdef SYM_LINUX_PROC_INFO_SUPPORT .proc_info = sym53c8xx_proc_info, .proc_name = NAME53C8XX,#endif};static int attach_count;static int __devinit sym2_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ struct sym_device sym_dev; struct sym_nvram nvram; struct Scsi_Host *instance; memset(&sym_dev, 0, sizeof(sym_dev)); memset(&nvram, 0, sizeof(nvram)); if (pci_enable_device(pdev)) return -ENODEV; pci_set_master(pdev); if (pci_request_regions(pdev, NAME53C8XX)) goto disable; sym_dev.host_id = SYM_SETUP_HOST_ID; if (sym53c8xx_pci_init(pdev, &sym_dev)) goto free; sym_config_pqs(pdev, &sym_dev); sym_get_nvram(&sym_dev, &nvram); instance = sym_attach(&sym2_template, attach_count, &sym_dev); if (!instance) goto free; if (scsi_add_host(instance, &pdev->dev)) goto detach; scsi_scan_host(instance); attach_count++; return 0; detach: sym_detach(pci_get_drvdata(pdev)); free: pci_release_regions(pdev); disable: pci_disable_device(pdev); return -ENODEV;}static void __devexit sym2_remove(struct pci_dev *pdev){ struct sym_hcb *np = pci_get_drvdata(pdev); struct Scsi_Host *host = np->s.host; scsi_remove_host(host); scsi_host_put(host); sym_detach(np); pci_release_regions(pdev); pci_disable_device(pdev); attach_count--;}static void sym2_get_offset(struct scsi_device *sdev){ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; spi_offset(sdev) = tp->tinfo.curr.offset;}static void sym2_set_offset(struct scsi_device *sdev, int offset){ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; if (tp->tinfo.curr.options & PPR_OPT_DT) { if (offset > np->maxoffs_dt) offset = np->maxoffs_dt; } else { if (offset > np->maxoffs) offset = np->maxoffs; } tp->tinfo.goal.offset = offset;}static void sym2_get_period(struct scsi_device *sdev){ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; spi_period(sdev) = tp->tinfo.curr.period;}static void sym2_set_period(struct scsi_device *sdev, int period){ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; if (period <= 9 && np->minsync_dt) { if (period < np->minsync_dt) period = np->minsync_dt; tp->tinfo.goal.options = PPR_OPT_DT; tp->tinfo.goal.period = period; if (!tp->tinfo.curr.offset || tp->tinfo.curr.offset > np->maxoffs_dt) tp->tinfo.goal.offset = np->maxoffs_dt; } else { if (period < np->minsync) period = np->minsync; tp->tinfo.goal.options = 0; tp->tinfo.goal.period = period; if (!tp->tinfo.curr.offset || tp->tinfo.curr.offset > np->maxoffs) tp->tinfo.goal.offset = np->maxoffs; }}static void sym2_get_width(struct scsi_device *sdev){ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; spi_width(sdev) = tp->tinfo.curr.width ? 1 : 0;}static void sym2_set_width(struct scsi_device *sdev, int width){ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; tp->tinfo.goal.width = width;}static void sym2_get_dt(struct scsi_device *sdev){ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; spi_dt(sdev) = (tp->tinfo.curr.options & PPR_OPT_DT) ? 1 : 0;}static void sym2_set_dt(struct scsi_device *sdev, int dt){ struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb; struct sym_tcb *tp = &np->target[sdev->id]; if (!dt) { /* if clearing DT, then we may need to reduce the * period and the offset */ if (tp->tinfo.curr.period < np->minsync) tp->tinfo.goal.period = np->minsync; if (tp->tinfo.curr.offset > np->maxoffs) tp->tinfo.goal.offset = np->maxoffs; tp->tinfo.goal.options &= ~PPR_OPT_DT; } else { tp->tinfo.goal.options |= PPR_OPT_DT; }} static struct spi_function_template sym2_transport_functions = { .set_offset = sym2_set_offset, .get_offset = sym2_get_offset, .show_offset = 1, .set_period = sym2_set_period, .get_period = sym2_get_period, .show_period = 1, .set_width = sym2_set_width, .get_width = sym2_get_width, .show_width = 1, .get_dt = sym2_get_dt, .set_dt = sym2_set_dt, .show_dt = 1,};static struct pci_device_id sym2_id_table[] __devinitdata = { { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */ { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C815, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C810AP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */ { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1510, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C896, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C895, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C885, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C1510, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */ { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C895A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C875A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1010_33, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1010_66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875J, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { 0, }};MODULE_DEVICE_TABLE(pci, sym2_id_table);static struct pci_driver sym2_driver = { .name = NAME53C8XX, .id_table = sym2_id_table, .probe = sym2_probe, .remove = __devexit_p(sym2_remove),};static int __init sym2_init(void){ sym2_transport_template = spi_attach_transport(&sym2_transport_functions); if (!sym2_transport_template) return -ENODEV; pci_register_driver(&sym2_driver); return 0;}static void __exit sym2_exit(void){ pci_unregister_driver(&sym2_driver); spi_release_transport(sym2_transport_template);}module_init(sym2_init);module_exit(sym2_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?