📄 sym_glue.c
字号:
* Now let the generic SCSI driver * look for the SCSI devices on the bus .. */ return 0;attach_failed: if (!instance) return -1; printf_info("%s: giving up ...\n", sym_name(np)); if (np) sym_free_resources(np); scsi_unregister(instance); return -1; }/* * Detect and try to read SYMBIOS and TEKRAM NVRAM. */#if SYM_CONF_NVRAM_SUPPORTstatic void __init sym_get_nvram(sym_device *devp, sym_nvram *nvp){ if (!nvp) return; devp->nvram = nvp; devp->device_id = devp->chip.device_id; nvp->type = 0; /* * Get access to chip IO registers */#ifdef SYM_CONF_IOMAPPED request_region(devp->s.io_port, 128, NAME53C8XX);#else devp->s.mmio_va = pci_map_mem(devp->s.base_c, 128); if (!devp->s.mmio_va) return;#endif /* * Try to read SYMBIOS|TEKRAM nvram. */ (void) sym_read_nvram(devp, nvp); /* * Release access to chip IO registers */#ifdef SYM_CONF_IOMAPPED release_region(devp->s.io_port, 128);#else pci_unmap_mem((u_long) devp->s.mmio_va, 128ul);#endif}#endif /* SYM_CONF_NVRAM_SUPPORT *//* * Driver setup from the boot command line */#ifdef SYM_LINUX_BOOT_COMMAND_LINE_SUPPORTstatic struct sym_driver_setup sym_driver_safe_setup __initdata = SYM_LINUX_DRIVER_SAFE_SETUP;#ifdef MODULEchar *sym53c8xx = 0; /* command line passed by insmod */MODULE_PARM(sym53c8xx, "s");#endifstatic void __init sym53c8xx_print_driver_setup(void){ printf_info (NAME53C8XX ": setup=" "mpar:%d,spar:%d,tags:%d,sync:%d,burst:%d," "led:%d,wide:%d,diff:%d,irqm:%d, buschk:%d\n", sym_driver_setup.pci_parity, sym_driver_setup.scsi_parity, sym_driver_setup.max_tag, sym_driver_setup.min_sync, sym_driver_setup.burst_order, sym_driver_setup.scsi_led, sym_driver_setup.max_wide, sym_driver_setup.scsi_diff, sym_driver_setup.irq_mode, sym_driver_setup.scsi_bus_check); printf_info (NAME53C8XX ": setup=" "hostid:%d,offs:%d,luns:%d,pcifix:%d,revprob:%d," "verb:%d,debug:0x%x,setlle_delay:%d\n", sym_driver_setup.host_id, sym_driver_setup.max_offs, sym_driver_setup.max_lun, sym_driver_setup.pci_fix_up, sym_driver_setup.reverse_probe, sym_driver_setup.verbose, sym_driver_setup.debug, sym_driver_setup.settle_delay);#ifdef DEBUG_2_0_XMDELAY(5000);#endif};#define OPT_PCI_PARITY 1#define OPT_SCSI_PARITY 2#define OPT_MAX_TAG 3#define OPT_MIN_SYNC 4#define OPT_BURST_ORDER 5#define OPT_SCSI_LED 6#define OPT_MAX_WIDE 7#define OPT_SCSI_DIFF 8#define OPT_IRQ_MODE 9#define OPT_SCSI_BUS_CHECK 10#define OPT_HOST_ID 11#define OPT_MAX_OFFS 12#define OPT_MAX_LUN 13#define OPT_PCI_FIX_UP 14#define OPT_REVERSE_PROBE 15#define OPT_VERBOSE 16#define OPT_DEBUG 17#define OPT_SETTLE_DELAY 18#define OPT_USE_NVRAM 19#define OPT_EXCLUDE 20#define OPT_SAFE_SETUP 21static char setup_token[] __initdata = "mpar:" "spar:" "tags:" "sync:" "burst:" "led:" "wide:" "diff:" "irqm:" "buschk:" "hostid:" "offset:" "luns:" "pcifix:" "revprob:" "verb:" "debug:" "settle:" "nvram:" "excl:" "safe:" ;#ifdef MODULE#define ARG_SEP ' '#else#define ARG_SEP ','#endifstatic int __init get_setup_token(char *p){ char *cur = setup_token; char *pc; int i = 0; while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { ++pc; ++i; if (!strncmp(p, cur, pc - cur)) return i; cur = pc; } return 0;}#endif /* SYM_LINUX_BOOT_COMMAND_LINE_SUPPORT */int __init sym53c8xx_setup(char *str){#ifdef SYM_LINUX_BOOT_COMMAND_LINE_SUPPORT char *cur = str; char *pc, *pv; unsigned long val; int i, c; int xi = 0; while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { char *pe; val = 0; pv = pc; c = *++pv; if (c == 'n') val = 0; else if (c == 'y') val = 1; else val = (int) simple_strtoul(pv, &pe, 0); switch (get_setup_token(cur)) { case OPT_MAX_TAG: sym_driver_setup.max_tag = val; if (!(pe && *pe == '/')) break; i = 0; while (*pe && *pe != ARG_SEP && i < sizeof(sym_driver_setup.tag_ctrl)-1) { sym_driver_setup.tag_ctrl[i++] = *pe++; } sym_driver_setup.tag_ctrl[i] = '\0'; break; case OPT_SAFE_SETUP: memcpy(&sym_driver_setup, &sym_driver_safe_setup, sizeof(sym_driver_setup)); break; case OPT_EXCLUDE: if (xi < 8) sym_driver_setup.excludes[xi++] = val; break;#define __SIMPLE_OPTION(NAME, name) \ case OPT_ ## NAME : \ sym_driver_setup.name = val;\ break; __SIMPLE_OPTION(PCI_PARITY, pci_parity) __SIMPLE_OPTION(SCSI_PARITY, scsi_parity) __SIMPLE_OPTION(MIN_SYNC, min_sync) __SIMPLE_OPTION(BURST_ORDER, burst_order) __SIMPLE_OPTION(SCSI_LED, scsi_led) __SIMPLE_OPTION(MAX_WIDE, max_wide) __SIMPLE_OPTION(SCSI_DIFF, scsi_diff) __SIMPLE_OPTION(IRQ_MODE, irq_mode) __SIMPLE_OPTION(SCSI_BUS_CHECK, scsi_bus_check) __SIMPLE_OPTION(HOST_ID, host_id) __SIMPLE_OPTION(MAX_OFFS, max_offs) __SIMPLE_OPTION(MAX_LUN, max_lun) __SIMPLE_OPTION(PCI_FIX_UP, pci_fix_up) __SIMPLE_OPTION(REVERSE_PROBE, reverse_probe) __SIMPLE_OPTION(VERBOSE, verbose) __SIMPLE_OPTION(DEBUG, debug) __SIMPLE_OPTION(SETTLE_DELAY, settle_delay) __SIMPLE_OPTION(USE_NVRAM, use_nvram)#undef __SIMPLE_OPTION default: printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); break; } if ((cur = strchr(cur, ARG_SEP)) != NULL) ++cur; }#endif /* SYM_LINUX_BOOT_COMMAND_LINE_SUPPORT */ return 1;}#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)#ifndef MODULE__setup("sym53c8xx=", sym53c8xx_setup);#endif#endif#ifdef SYM_CONF_PQS_PDS_SUPPORT/* * Detect all NCR PQS/PDS boards and keep track of their bus nr. * * The NCR PQS or PDS card is constructed as a DEC bridge * behind which sit a proprietary NCR memory controller and * four or two 53c875s as separate devices. In its usual mode * of operation, the 875s are slaved to the memory controller * for all transfers. 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. 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 */#ifndef SYM_CONF_MAX_PQS_BUS#define SYM_CONF_MAX_PQS_BUS 16#endifstatic int pqs_bus[SYM_CONF_MAX_PQS_BUS] __initdata = { 0 };static void __init sym_detect_pqs_pds(void){ short index; pcidev_t dev = PCIDEV_NULL; for(index=0; index < SYM_CONF_MAX_PQS_BUS; index++) { u_char tmp; dev = pci_find_device(0x101a, 0x0009, dev); if (dev == PCIDEV_NULL) { pqs_bus[index] = -1; break; } printf_info(NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", PciBusNumber(dev)); pci_read_config_byte(dev, 0x44, &tmp); /* bit 1: allow individual 875 configuration */ tmp |= 0x2; pci_write_config_byte(dev, 0x44, tmp); pci_read_config_byte(dev, 0x45, &tmp); /* bit 2: drive individual 875 interrupts to the bus */ tmp |= 0x4; pci_write_config_byte(dev, 0x45, tmp); pqs_bus[index] = PciBusNumber(dev); }}#endif /* SYM_CONF_PQS_PDS_SUPPORT *//* * Read and check the PCI configuration for any detected NCR * boards and save data for attaching after all boards have * been detected. */static int __initsym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, sym_device *device){ u_short vendor_id, device_id, command, status_reg; u_char cache_line_size; u_char suggested_cache_line_size = 0; u_char pci_fix_up = SYM_SETUP_PCI_FIX_UP; u_char revision; u_int irq; u_long base, base_2, base_io; u_long base_c, base_2_c, io_port; int i; sym_chip *chip; /* Choose some short name for this device */ sprintf(device->s.inst_name, "sym.%d.%d.%d", PciBusNumber(pdev), (int) (PciDeviceFn(pdev) & 0xf8) >> 3, (int) (PciDeviceFn(pdev) & 7)); /* * Read needed minimal info from the PCI config space. */ vendor_id = PciVendorId(pdev); device_id = PciDeviceId(pdev); irq = PciIrqLine(pdev); i = pci_get_base_address(pdev, 0, &base_io); io_port = pci_get_base_cookie(pdev, 0); base_c = pci_get_base_cookie(pdev, i); i = pci_get_base_address(pdev, i, &base); base_2_c = pci_get_base_cookie(pdev, i); (void) pci_get_base_address(pdev, i, &base_2); io_port &= PCI_BASE_ADDRESS_IO_MASK; 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, donnot initialize it. */ if (base_io) { for (i = 0 ; i < 8 ; i++) { if (sym_driver_setup.excludes[i] == base_io) return -1; } } /* * Leave here if another driver attached the chip. */ if (io_port && check_region (io_port, 128)) { printf_info("%s: IO region 0x%lx[0..127] is in use\n", sym_name(device), (long) 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. */#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__) && !defined(SYM_OPT_NO_BUS_MEMORY_MAPPING) if (base_2_c) { unsigned int ram_size, ram_val; u_long ram_ptr; if (chip->features & FE_RAM8K) ram_size = 8192; else ram_size = 4096; ram_ptr = pci_map_mem(base_2_c, ram_size); if (ram_ptr) { ram_val = readl_raw(ram_ptr + ram_size - 16); pci_unmap_mem(ram_ptr, ram_size); 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. */ bcopy(chip, &device->chip, sizeof(device->chip)); device->chip.revision_id = revision; /* * Read additionnal info from the configuration space. */ pci_read_config_word(pdev, PCI_COMMAND, &command); pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line_size); /* * Enable missing capabilities in the PCI COMMAND register. */#ifdef SYM_CONF_IOMAPPED#define PCI_COMMAND_BITS_TO_ENABLE (PCI_COMMAND_IO | \ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)#else#define PCI_COMMAND_BITS_TO_ENABLE \ (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)#endif if ((command & PCI_COMMAND_BITS_TO_ENABLE) != PCI_COMMAND_BITS_TO_ENABLE) { printf_info("%s: setting%s%s%s%s...\n", sym_name(device), (command & PCI_COMMAND_IO) ? "" : " PCI_COMMAND_IO", (command & PCI_COMMAND_MEMORY) ? "" : " PCI_COMMAND_MEMORY", (command & PCI_COMMAND_MASTER) ? "" : " PCI_COMMAND_MASTER", (command & PCI_COMMAND_PARITY) ? "" : " PCI_COMMAND_PARITY"); command |= PCI_COMMAND_BITS_TO_ENABLE; pci_write_config_word(pdev, PCI_COMMAND, command); }#undef PCI_COMMAND_BITS_TO_ENABLE /* * If cache line size is not configured, suggest * a value for well known CPUs. */#if defined(__i386__) && !defined(MODULE) if (!cache_line_size && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { switch(boot_cpu_data.x86) { case 4: suggested_cache_line_size = 4; break; case 6: if (boot_cpu_data.x86_model > 8) break; case 5: suggested_cache_line_size = 8; break; } }#endif /* __i386__ */ /* * 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); pci_fix_up |= 3; /* Force appropriate PCI fix-up */ }#ifdef SYM_CONF_PCI_FIX_UP /* * Try to fix up PCI config according to wished features. */ if ((pci_fix_up & 1) && (chip->features & FE_CLSE) && !cache_line_size && suggested_cache_line_size) { cache_line_size = suggested_cache_line_size; pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, cache_line_size); printf_info("%s: PCI_CACHE_LINE_SIZE set to %d.\n", sym_name(device), cache_line_size); } if ((pci_fix_up & 2) && cache_line_size && (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) { printf_info("%s: setting PCI_COMMAND_INVALIDATE.\n", sym_name(device)); command |= PCI_COMMAND_INVALIDATE; pci_write_config_word(pdev, PCI_COMMAND, command); }#endif /* SYM_CONF_PCI_FIX_UP */ /* * 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.bus = PciBusNumber(pdev); device->s.device_fn = PciDeviceFn(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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -