sym_glue.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,149 行 · 第 1/4 页
C
2,149 行
scsi_host_put(instance); return NULL; }/* * Detect and try to read SYMBIOS and TEKRAM NVRAM. */#if SYM_CONF_NVRAM_SUPPORTstatic void __devinit sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp){ devp->nvram = nvp; devp->device_id = devp->chip.device_id; nvp->type = 0; sym_read_nvram(devp, nvp);}#elsestatic inline void sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp){}#endif /* SYM_CONF_NVRAM_SUPPORT */static int __devinit sym_check_supported(struct sym_device *device){ struct sym_chip *chip; struct pci_dev *pdev = device->pdev; u_char revision; unsigned long io_port = pci_resource_start(pdev, 0); int i; /* * If user excluded this chip, do not initialize it. * I hate this code so much. Must kill it. */ if (io_port) { for (i = 0 ; i < 8 ; i++) { if (sym_driver_setup.excludes[i] == io_port) return -ENODEV; } } /* * Check if the chip is supported. Then copy the chip description * to our device structure so we can make it match the actual device * and options. */ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); chip = sym_lookup_chip_table(pdev->device, revision); if (!chip) { dev_info(&pdev->dev, "device not supported\n"); return -ENODEV; } memcpy(&device->chip, chip, sizeof(device->chip)); device->chip.revision_id = revision; return 0;}/* * Ignore Symbios chips controlled by various RAID controllers. * These controllers set value 0x52414944 at RAM end - 16. */static int __devinit sym_check_raid(struct sym_device *device){ unsigned int ram_size, ram_val; if (!device->s.ramaddr) return 0; if (device->chip.features & FE_RAM8K) ram_size = 8192; else ram_size = 4096; ram_val = readl(device->s.ramaddr + ram_size - 16); if (ram_val != 0x52414944) return 0; dev_info(&device->pdev->dev, "not initializing, driven by RAID controller.\n"); return -ENODEV;}static int __devinit sym_set_workarounds(struct sym_device *device){ struct sym_chip *chip = &device->chip; struct pci_dev *pdev = device->pdev; u_short status_reg; /* * (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 (pdev->device == PCI_DEVICE_ID_NCR_53C896 && chip->revision_id < 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 -ENODEV; } /* * 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); } } return 0;}/* * Read and check the PCI configuration for any detected NCR * boards and save data for attaching after all boards have * been detected. */static void __devinitsym_init_device(struct pci_dev *pdev, struct sym_device *device){ int i = 2; struct pci_bus_region bus_addr; device->host_id = SYM_SETUP_HOST_ID; device->pdev = pdev; pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]); device->mmio_base = bus_addr.start; /* * If the BAR is 64-bit, resource 2 will be occupied by the * upper 32 bits */ if (!pdev->resource[i].flags) i++; pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]); device->ram_base = bus_addr.start;#ifdef CONFIG_SCSI_SYM53C8XX_MMIO if (device->mmio_base) device->s.ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));#endif if (!device->s.ioaddr) device->s.ioaddr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); if (device->ram_base) device->s.ramaddr = pci_iomap(pdev, i, pci_resource_len(pdev, i));}/* * 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. */static void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev){ int slot; u8 tmp; for (slot = 0; slot < 256; slot++) { struct pci_dev *memc = pci_get_slot(pdev->bus, slot); if (!memc || memc->vendor != 0x101a || memc->device == 0x0009) { pci_dev_put(memc); continue; } /* bit 1: allow individual 875 configuration */ pci_read_config_byte(memc, 0x44, &tmp); if ((tmp & 0x2) == 0) { 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); if ((tmp & 0x4) == 0) { tmp |= 0x4; pci_write_config_byte(memc, 0x45, tmp); } pci_dev_put(memc); break; } pci_read_config_byte(pdev, 0x84, &tmp); sym_dev->host_id = tmp;}/* * 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, struct pci_dev *pdev){ 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(np, nc_istat, SRST); INB(np, nc_mbox1); udelay(10); OUTB(np, nc_istat, 0); sym_free_resources(np, pdev); return 1;}/* * Driver host template. */static struct scsi_host_template sym2_template = { .module = THIS_MODULE, .name = "sym53c8xx", .info = sym53c8xx_info, .queuecommand = sym53c8xx_queue_command, .slave_alloc = sym53c8xx_slave_alloc, .slave_configure = sym53c8xx_slave_configure, .slave_destroy = sym53c8xx_slave_destroy, .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 = ENABLE_CLUSTERING, .max_sectors = 0xFFFF,#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)) goto leave; pci_set_master(pdev); if (pci_request_regions(pdev, NAME53C8XX)) goto disable; sym_init_device(pdev, &sym_dev); if (sym_check_supported(&sym_dev)) goto free; if (sym_check_raid(&sym_dev)) goto leave; /* Don't disable the device */ if (sym_set_workarounds(&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), pdev); free: pci_release_regions(pdev); disable: pci_disable_device(pdev); leave: 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, pdev); pci_release_regions(pdev); pci_disable_device(pdev); attach_count--;}static void sym2_get_signalling(struct Scsi_Host *shost){ struct sym_hcb *np = sym_get_hcb(shost); enum spi_signal_type type; switch (np->scsi_mode) { case SMODE_SE: type = SPI_SIGNAL_SE; break; case SMODE_LVD: type = SPI_SIGNAL_LVD; break; case SMODE_HVD: type = SPI_SIGNAL_HVD; break; default: type = SPI_SIGNAL_UNKNOWN; break; } spi_signalling(shost) = type;}static void sym2_set_offset(struct scsi_target *starget, int offset){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = sym_get_hcb(shost); struct sym_tcb *tp = &np->target[starget->id]; tp->tgoal.offset = offset; tp->tgoal.check_nego = 1;}static void sym2_set_period(struct scsi_target *starget, int period){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = sym_get_hcb(shost); struct sym_tcb *tp = &np->target[starget->id]; /* have to have DT for these transfers, but DT will also * set width, so check that this is allowed */ if (period <= np->minsync && spi_width(starget)) tp->tgoal.dt = 1; tp->tgoal.period = period; tp->tgoal.check_nego = 1;}static void sym2_set_width(struct scsi_target *starget, int width){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = sym_get_hcb(shost); struct sym_tcb *tp = &np->target[starget->id]; /* It is illegal to have DT set on narrow transfers. If DT is * clear, we must also clear IU and QAS. */ if (width == 0) tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; tp->tgoal.width = width; tp->tgoal.check_nego = 1;}static void sym2_set_dt(struct scsi_target *starget, int dt){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = sym_get_hcb(shost); struct sym_tcb *tp = &np->target[starget->id]; /* We must clear QAS and IU if DT is clear */ if (dt) tp->tgoal.dt = 1; else tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; tp->tgoal.check_nego = 1;}#if 0static void sym2_set_iu(struct scsi_target *starget, int iu){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = sym_get_hcb(shost); struct sym_tcb *tp = &np->target[starget->id]; if (iu) tp->tgoal.iu = tp->tgoal.dt = 1; else tp->tgoal.iu = 0; tp->tgoal.check_nego = 1;}static void sym2_set_qas(struct scsi_target *starget, int qas){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = sym_get_hcb(shost); struct sym_tcb *tp = &np->target[starget->id]; if (qas) tp->tgoal.dt = tp->tgoal.qas = 1; else tp->tgoal.qas = 0; tp->tgoal.check_nego = 1;}#endifstatic struct spi_function_template sym2_transport_functions = { .set_offset = sym2_set_offset, .show_offset = 1, .set_period = sym2_set_period, .show_period = 1, .set_width = sym2_set_width, .show_width = 1, .set_dt = sym2_set_dt, .show_dt = 1,#if 0 .set_iu = sym2_set_iu, .show_iu = 1, .set_qas = sym2_set_qas, .show_qas = 1,#endif .get_signalling = sym2_get_signalling,};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){ int error; sym2_setup_params(); sym2_transport_template = spi_attach_transport(&sym2_transport_functions); if (!sym2_transport_template) return -ENODEV; error = pci_register_driver(&sym2_driver); if (error) spi_release_transport(sym2_transport_template); return error;}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 + -
显示快捷键?