📄 sym_glue.c
字号:
instance->max_channel = 0; instance->this_id = np->myaddr; instance->max_id = np->maxwide ? 16 : 8; instance->max_lun = SYM_CONF_MAX_LUN; instance->unique_id = pci_resource_start(pdev, 0); instance->cmd_per_lun = SYM_CONF_MAX_TAG; instance->can_queue = (SYM_CONF_MAX_START-2); instance->sg_tablesize = SYM_CONF_MAX_SG; instance->max_cmd_len = 16; BUG_ON(sym2_transport_template == NULL); instance->transportt = sym2_transport_template; spin_unlock_irqrestore(instance->host_lock, flags); return instance; reset_failed: printf_err("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, " "TERMINATION, DEVICE POWER etc.!\n", sym_name(np)); spin_unlock_irqrestore(instance->host_lock, flags); attach_failed: if (!instance) return NULL; printf_info("%s: giving up ...\n", sym_name(np)); if (np) sym_free_resources(np, pdev); 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; device->host_id = SYM_SETUP_HOST_ID; device->pdev = pdev; i = pci_get_base_address(pdev, 1, &device->mmio_base); pci_get_base_address(pdev, i, &device->ram_base);#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED 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, .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), 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -