📄 sym_glue.c
字号:
*/#ifndef SYM_CONF_IOMAPPED devp->s.mmio_va = ioremap(devp->s.base_c, 128); if (!devp->s.mmio_va) return;#endif sym_read_nvram(devp, nvp); /* * Release access to chip IO registers */#ifndef SYM_CONF_IOMAPPED iounmap(devp->s.mmio_va);#endif}#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_pci_chip *chip; struct pci_dev *pdev = device->pdev; u_char revision; unsigned long io_port = device->s.io_port; unsigned long base = device->s.base; int i; /* * 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 -ENODEV; } } /* * 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 -ENODEV; }#else if (!base) { printf_info("%s: MMIO base address disabled.\n", sym_name(device)); return -ENODEV; }#endif /* * 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_pci_chip_table(pdev->device, revision); if (!chip) { printf_info("%s: device not supported\n", sym_name(device)); 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 long base_2_c = device->s.base_2_c; unsigned int ram_size, ram_val; void __iomem *ram_ptr; if (!base_2_c) return 0; if (device->chip.features & FE_RAM8K) ram_size = 8192; else ram_size = 4096; ram_ptr = ioremap(base_2_c, ram_size); if (!ram_ptr) return 0; ram_val = readl(ram_ptr + ram_size - 16); iounmap(ram_ptr); if (ram_val != 0x52414944) return 0; printf_info("%s: not initializing, driven by RAID controller.\n", sym_name(device)); return -ENODEV;}static int __devinit sym_set_workarounds(struct sym_device *device){ struct sym_pci_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){ unsigned long base, base_2; int i; device->host_id = SYM_SETUP_HOST_ID; device->pdev = pdev; device->s.irq = pdev->irq; /* 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->s.io_port = pdev->resource[0].start; device->s.base_c = pdev->resource[1].start; i = pci_get_base_address(pdev, 1, &base); device->s.base = base & PCI_BASE_ADDRESS_MEM_MASK; device->s.base_2_c = pdev->resource[i].start; pci_get_base_address(pdev, i, &base_2); device->s.base_2 = base_2 & PCI_BASE_ADDRESS_MEM_MASK;}/* * 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){ 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;}/* * 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)) 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)); 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); pci_release_regions(pdev); pci_disable_device(pdev); attach_count--;}static void sym2_get_signalling(struct Scsi_Host *shost){ struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb; 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_get_offset(struct scsi_target *starget){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; spi_offset(starget) = tp->tinfo.curr.offset;}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 = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; tp->tinfo.goal.offset = offset;}static void sym2_get_period(struct scsi_target *starget){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; spi_period(starget) = tp->tinfo.curr.period;}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 = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; /* have to have DT for these transfers */ if (period <= np->minsync) tp->tinfo.goal.options |= PPR_OPT_DT; tp->tinfo.goal.period = period;}static void sym2_get_width(struct scsi_target *starget){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; spi_width(starget) = tp->tinfo.curr.width ? 1 : 0;}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 = ((struct host_data *)shost->hostdata)->ncb; 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->tinfo.goal.options &= ~PPR_OPT_MASK; tp->tinfo.goal.width = width;}static void sym2_get_dt(struct scsi_target *starget){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; spi_dt(starget) = (tp->tinfo.curr.options & PPR_OPT_DT) ? 1 : 0;}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 = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; /* We must clear QAS and IU if DT is clear */ if (dt) tp->tinfo.goal.options |= PPR_OPT_DT; else tp->tinfo.goal.options &= ~PPR_OPT_MASK;}static void sym2_get_iu(struct scsi_target *starget){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; spi_iu(starget) = (tp->tinfo.curr.options & PPR_OPT_IU) ? 1 : 0;}static void sym2_set_iu(struct scsi_target *starget, int iu){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; if (iu) tp->tinfo.goal.options |= PPR_OPT_IU | PPR_OPT_DT; else tp->tinfo.goal.options &= ~PPR_OPT_IU;}static void sym2_get_qas(struct scsi_target *starget){ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; spi_qas(starget) = (tp->tinfo.curr.options & PPR_OPT_QAS) ? 1 : 0;}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 = ((struct host_data *)shost->hostdata)->ncb; struct sym_tcb *tp = &np->target[starget->id]; if (qas) tp->tinfo.goal.options |= PPR_OPT_QAS | PPR_OPT_DT; else tp->tinfo.goal.options &= ~PPR_OPT_QAS;}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, .get_iu = sym2_get_iu, .set_iu = sym2_set_iu, .show_iu = 1, .get_qas = sym2_get_qas, .set_qas = sym2_set_qas, .show_qas = 1, .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_module_init(&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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -