📄 aic79xx_osm.c
字号:
free(map, M_DEVBUF);}intahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map){ /* Nothing to do */ return (0);}/********************* Platform Dependent Functions ***************************//* * Compare "left hand" softc with "right hand" softc, returning: * < 0 - lahd has a lower priority than rahd * 0 - Softcs are equal * > 0 - lahd has a higher priority than rahd */intahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd){ int value; /* * Under Linux, cards are ordered as follows: * 1) PCI devices that are marked as the boot controller. * 2) PCI devices with BIOS enabled sorted by bus/slot/func. * 3) All remaining PCI devices sorted by bus/slot/func. */#if 0 value = (lahd->flags & AHD_BOOT_CHANNEL) - (rahd->flags & AHD_BOOT_CHANNEL); if (value != 0) /* Controllers set for boot have a *higher* priority */ return (value);#endif value = (lahd->flags & AHD_BIOS_ENABLED) - (rahd->flags & AHD_BIOS_ENABLED); if (value != 0) /* Controllers with BIOS enabled have a *higher* priority */ return (value); /* Still equal. Sort by bus/slot/func. */ if (aic79xx_reverse_scan != 0) value = ahd_get_pci_bus(lahd->dev_softc) - ahd_get_pci_bus(rahd->dev_softc); else value = ahd_get_pci_bus(rahd->dev_softc) - ahd_get_pci_bus(lahd->dev_softc); if (value != 0) return (value); if (aic79xx_reverse_scan != 0) value = ahd_get_pci_slot(lahd->dev_softc) - ahd_get_pci_slot(rahd->dev_softc); else value = ahd_get_pci_slot(rahd->dev_softc) - ahd_get_pci_slot(lahd->dev_softc); if (value != 0) return (value); value = rahd->channel - lahd->channel; return (value);}static voidahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value){ if ((instance >= 0) && (targ >= 0) && (instance < NUM_ELEMENTS(aic79xx_tag_info)) && (targ < AHD_NUM_TARGETS)) { aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF; if (bootverbose) printf("tag_info[%d:%d] = %d\n", instance, targ, value); }}static voidahd_linux_setup_rd_strm_info(u_long arg, int instance, int targ, int32_t value){ if ((instance >= 0) && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) { aic79xx_rd_strm_info[instance] = value & 0xFFFF; if (bootverbose) printf("rd_strm[%d] = 0x%x\n", instance, value); }}static voidahd_linux_setup_dv(u_long arg, int instance, int targ, int32_t value){ if ((instance >= 0) && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) { aic79xx_dv_settings[instance] = value; if (bootverbose) printf("dv[%d] = %d\n", instance, value); }}static voidahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value){ if ((instance >= 0) && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) { uint8_t *iocell_info; iocell_info = (uint8_t*)&aic79xx_iocell_info[instance]; iocell_info[index] = value & 0xFFFF; if (bootverbose) printf("iocell[%d:%ld] = %d\n", instance, index, value); }}static voidahd_linux_setup_tag_info_global(char *p){ int tags, i, j; tags = simple_strtoul(p + 1, NULL, 0) & 0xff; printf("Setting Global Tags= %d\n", tags); for (i = 0; i < NUM_ELEMENTS(aic79xx_tag_info); i++) { for (j = 0; j < AHD_NUM_TARGETS; j++) { aic79xx_tag_info[i].tag_commands[j] = tags; } }}/* * Handle Linux boot parameters. This routine allows for assigning a value * to a parameter with a ':' between the parameter and the value. * ie. aic79xx=stpwlev:1,extended */static intaic79xx_setup(char *s){ int i, n; char *p; char *end; static struct { const char *name; uint32_t *flag; } options[] = { { "extended", &aic79xx_extended }, { "no_reset", &aic79xx_no_reset }, { "verbose", &aic79xx_verbose }, { "allow_memio", &aic79xx_allow_memio},#ifdef AHD_DEBUG { "debug", &ahd_debug },#endif { "reverse_scan", &aic79xx_reverse_scan }, { "periodic_otag", &aic79xx_periodic_otag }, { "pci_parity", &aic79xx_pci_parity }, { "seltime", &aic79xx_seltime }, { "tag_info", NULL }, { "global_tag_depth", NULL}, { "rd_strm", NULL }, { "dv", NULL }, { "slewrate", NULL }, { "precomp", NULL }, { "amplitude", NULL }, }; end = strchr(s, '\0'); /* * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS * will never be 0 in this case. */ n = 0; while ((p = strsep(&s, ",.")) != NULL) { if (*p == '\0') continue; for (i = 0; i < NUM_ELEMENTS(options); i++) { n = strlen(options[i].name); if (strncmp(options[i].name, p, n) == 0) break; } if (i == NUM_ELEMENTS(options)) continue; if (strncmp(p, "global_tag_depth", n) == 0) { ahd_linux_setup_tag_info_global(p + n); } else if (strncmp(p, "tag_info", n) == 0) { s = aic_parse_brace_option("tag_info", p + n, end, 2, ahd_linux_setup_tag_info, 0); } else if (strncmp(p, "rd_strm", n) == 0) { s = aic_parse_brace_option("rd_strm", p + n, end, 1, ahd_linux_setup_rd_strm_info, 0); } else if (strncmp(p, "dv", n) == 0) { s = aic_parse_brace_option("dv", p + n, end, 1, ahd_linux_setup_dv, 0); } else if (strncmp(p, "slewrate", n) == 0) { s = aic_parse_brace_option("slewrate", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_SLEWRATE_INDEX); } else if (strncmp(p, "precomp", n) == 0) { s = aic_parse_brace_option("precomp", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_PRECOMP_INDEX); } else if (strncmp(p, "amplitude", n) == 0) { s = aic_parse_brace_option("amplitude", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_AMPLITUDE_INDEX); } else if (p[n] == ':') { *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); } else if (!strncmp(p, "verbose", n)) { *(options[i].flag) = 1; } else { *(options[i].flag) ^= 0xFFFFFFFF; } } return 1;}__setup("aic79xx=", aic79xx_setup);uint32_t aic79xx_verbose;intahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template){ char buf[80]; struct Scsi_Host *host; char *new_name; u_long s; u_long target; template->name = ahd->description; host = scsi_host_alloc(template, sizeof(struct ahd_softc *)); if (host == NULL) return (ENOMEM); *((struct ahd_softc **)host->hostdata) = ahd; ahd_lock(ahd, &s);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_assign_lock(host, &ahd->platform_data->spin_lock);#elif AHD_SCSI_HAS_HOST_LOCK != 0 host->lock = &ahd->platform_data->spin_lock;#endif ahd->platform_data->host = host; host->can_queue = AHD_MAX_QUEUE; host->cmd_per_lun = 2; host->sg_tablesize = AHD_NSEG; host->this_id = ahd->our_id; host->irq = ahd->platform_data->irq; host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8; host->max_lun = AHD_NUM_LUNS; host->max_channel = 0; host->sg_tablesize = AHD_NSEG; ahd_set_unit(ahd, ahd_linux_next_unit()); sprintf(buf, "scsi%d", host->host_no); new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (new_name != NULL) { strcpy(new_name, buf); ahd_set_name(ahd, new_name); } host->unique_id = ahd->unit;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) scsi_set_pci_device(host, ahd->dev_softc);#endif ahd_linux_setup_user_rd_strm_settings(ahd); ahd_linux_initialize_scsi_bus(ahd); ahd_unlock(ahd, &s); ahd->platform_data->dv_pid = kernel_thread(ahd_linux_dv_thread, ahd, 0); ahd_lock(ahd, &s); if (ahd->platform_data->dv_pid < 0) { printf("%s: Failed to create DV thread, error= %d\n", ahd_name(ahd), ahd->platform_data->dv_pid); return (-ahd->platform_data->dv_pid); } /* * Initially allocate *all* of our linux target objects * so that the DV thread will scan them all in parallel * just after driver initialization. Any device that * does not exist will have its target object destroyed * by the selection timeout handler. In the case of a * device that appears after the initial DV scan, async * negotiation will occur for the first command, and DV * will comence should that first command be successful. */ for (target = 0; target < host->max_id; target++) { /* * Skip our own ID. Some Compaq/HP storage devices * have enclosure management devices that respond to * single bit selection (i.e. selecting ourselves). * It is expected that either an external application * or a modified kernel will be used to probe this * ID if it is appropriate. To accommodate these * installations, ahc_linux_alloc_target() will allocate * for our ID if asked to do so. */ if (target == ahd->our_id) continue; ahd_linux_alloc_target(ahd, 0, target); } ahd_intr_enable(ahd, TRUE); ahd_linux_start_dv(ahd); ahd_unlock(ahd, &s);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ scsi_scan_host(host);#endif return (0);}uint64_tahd_linux_get_memsize(void){ struct sysinfo si; si_meminfo(&si); return ((uint64_t)si.totalram << PAGE_SHIFT);}/* * Find the smallest available unit number to use * for a new device. We don't just use a static * count to handle the "repeated hot-(un)plug" * scenario. */static intahd_linux_next_unit(void){ struct ahd_softc *ahd; int unit; unit = 0;retry: TAILQ_FOREACH(ahd, &ahd_tailq, links) { if (ahd->unit == unit) { unit++; goto retry; } } return (unit);}/* * Place the SCSI bus into a known state by either resetting it, * or forcing transfer negotiations on the next command to any * target. */static voidahd_linux_initialize_scsi_bus(struct ahd_softc *ahd){ u_int target_id; u_int numtarg; target_id = 0; numtarg = 0; if (aic79xx_no_reset != 0) ahd->flags &= ~AHD_RESET_BUS_A; if ((ahd->flags & AHD_RESET_BUS_A) != 0) ahd_reset_channel(ahd, 'A', /*initiate_reset*/TRUE); else numtarg = (ahd->features & AHD_WIDE) ? 16 : 8; /* * Force negotiation to async for all targets that * will not see an initial bus reset. */ for (; target_id < numtarg; target_id++) { struct ahd_devinfo devinfo; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, target_id, &tstate); ahd_compile_devinfo(&devinfo, ahd->our_id, target_id, CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR); ahd_update_neg_request(ahd, &devinfo, tstate, tinfo, AHD_NEG_ALWAYS); } /* Give the bus some time to recover */ if ((ahd->flags & AHD_RESET_BUS_A) != 0) { ahd_freeze_simq(ahd); init_timer(&ahd->platform_data->reset_timer); ahd->platform_data->reset_timer.data = (u_long)ahd; ahd->platform_data->reset_timer.expires = jiffies + (AIC79XX_RESET_DELAY * HZ)/1000; ahd->platform_data->reset_timer.function = (ahd_linux_callback_t *)ahd_release_simq; add_timer(&ahd->platform_data->reset_timer); }}intahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg){ ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT); if (ahd->platform_data == NULL) return (ENOMEM); memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); TAILQ_INIT(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->device_runq); ahd->platform_data->irq = AHD_LINUX_NOIRQ; ahd->platform_data->hw_dma_mask = 0xFFFFFFFF; ahd_lockinit(ahd); ahd_done_lockinit(ahd); init_timer(&ahd->platform_data->completeq_timer); ahd->platform_data->completeq_timer.data = (u_long)ahd; ahd->platform_data->completeq_timer.function = (ahd_linux_callback_t *)ahd_linux_thread_run_complete_queue; init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); init_MUTEX_LOCKED(&ahd->platform_data->dv_sem); init_MUTEX_LOCKED(&ahd->platform_data->dv_cmd_sem); ahd_setup_runq_tasklet(ahd); ahd->seltime = (aic79xx_seltime & 0x3) << 4; return (0);}voidahd_platform_free(struct ahd_softc *ahd){ struct ahd_linux_target *targ; struct ahd_linux_device *dev; int i, j; if (ahd->platform_data != NULL) { del_timer_sync(&ahd->platform_data->completeq_timer); ahd_linux_kill_dv_thread(ahd); ahd_teardown_runq_tasklet(ahd); if (ahd->platform_data->host != NULL) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahd->platform_data->host);#endif scsi_h
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -