📄 aic79xx_osm.c
字号:
break; case '}': if (targ != -1) targ = -1; else if (instance != -1) instance = -1; opt_arg++; break; case ',': case '.': if (instance == -1) done = TRUE; else if (targ >= 0) targ++; else if (instance >= 0) instance++; opt_arg++; break; case '\0': done = TRUE; break; default: tok_end = end; for (i = 0; tok_list[i]; i++) { tok_end2 = strchr(opt_arg, tok_list[i]); if ((tok_end2) && (tok_end2 < tok_end)) tok_end = tok_end2; } callback(callback_arg, instance, targ, simple_strtol(opt_arg, NULL, 0)); opt_arg = tok_end; break; } } return (opt_arg);}/* * 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}, { "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 = ahd_parse_brace_option("tag_info", p + n, end, 2, ahd_linux_setup_tag_info, 0); } else if (strncmp(p, "slewrate", n) == 0) { s = ahd_parse_brace_option("slewrate", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_SLEWRATE_INDEX); } else if (strncmp(p, "precomp", n) == 0) { s = ahd_parse_brace_option("precomp", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_PRECOMP_INDEX); } else if (strncmp(p, "amplitude", n) == 0) { s = ahd_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, struct scsi_host_template *template){ char buf[80]; struct Scsi_Host *host; char *new_name; u_long s; 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); 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_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; ahd_linux_initialize_scsi_bus(ahd); ahd_intr_enable(ahd, TRUE); ahd_unlock(ahd, &s); host->transportt = ahd_linux_transport_template; scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ scsi_scan_host(host); return (0);}uint64_tahd_linux_get_memsize(void){ struct sysinfo si; si_meminfo(&si); return ((uint64_t)si.totalram << PAGE_SHIFT);}/* * 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)); ahd->platform_data->irq = AHD_LINUX_NOIRQ; ahd_lockinit(ahd); init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); ahd->seltime = (aic79xx_seltime & 0x3) << 4; return (0);}voidahd_platform_free(struct ahd_softc *ahd){ struct scsi_target *starget; int i, j; if (ahd->platform_data != NULL) { /* destroy all of the device and target objects */ for (i = 0; i < AHD_NUM_TARGETS; i++) { starget = ahd->platform_data->starget[i]; if (starget != NULL) { for (j = 0; j < AHD_NUM_LUNS; j++) { struct ahd_linux_target *targ = scsi_transport_target_data(starget); if (targ->sdev[j] == NULL) continue; targ->sdev[j] = NULL; } ahd->platform_data->starget[i] = NULL; } } if (ahd->platform_data->irq != AHD_LINUX_NOIRQ) free_irq(ahd->platform_data->irq, ahd); if (ahd->tags[0] == BUS_SPACE_PIO && ahd->bshs[0].ioport != 0) release_region(ahd->bshs[0].ioport, 256); if (ahd->tags[1] == BUS_SPACE_PIO && ahd->bshs[1].ioport != 0) release_region(ahd->bshs[1].ioport, 256); if (ahd->tags[0] == BUS_SPACE_MEMIO && ahd->bshs[0].maddr != NULL) { iounmap(ahd->bshs[0].maddr); release_mem_region(ahd->platform_data->mem_busaddr, 0x1000); } if (ahd->platform_data->host) scsi_host_put(ahd->platform_data->host); free(ahd->platform_data, M_DEVBUF); }}voidahd_platform_init(struct ahd_softc *ahd){ /* * Lookup and commit any modified IO Cell options. */ if (ahd->unit < NUM_ELEMENTS(aic79xx_iocell_info)) { struct ahd_linux_iocell_opts *iocell_opts; iocell_opts = &aic79xx_iocell_info[ahd->unit]; if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP) AHD_SET_PRECOMP(ahd, iocell_opts->precomp); if (iocell_opts->slewrate != AIC79XX_DEFAULT_SLEWRATE) AHD_SET_SLEWRATE(ahd, iocell_opts->slewrate); if (iocell_opts->amplitude != AIC79XX_DEFAULT_AMPLITUDE) AHD_SET_AMPLITUDE(ahd, iocell_opts->amplitude); }}voidahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb){ ahd_platform_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), SCB_GET_CHANNEL(ahd, scb), SCB_GET_LUN(scb), SCB_LIST_NULL, ROLE_UNKNOWN, CAM_REQUEUE_REQ);}voidahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd_queue_alg alg){ struct scsi_target *starget; struct ahd_linux_target *targ; struct ahd_linux_device *dev; struct scsi_device *sdev; int was_queuing; int now_queuing; starget = ahd->platform_data->starget[devinfo->target]; targ = scsi_transport_target_data(starget); BUG_ON(targ == NULL); sdev = targ->sdev[devinfo->lun]; if (sdev == NULL) return; dev = scsi_transport_device_data(sdev); if (dev == NULL) return; was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED); switch (alg) { default: case AHD_QUEUE_NONE: now_queuing = 0; break; case AHD_QUEUE_BASIC: now_queuing = AHD_DEV_Q_BASIC; break; case AHD_QUEUE_TAGGED: now_queuing = AHD_DEV_Q_TAGGED; break; } if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0 && (was_queuing != now_queuing) && (dev->active != 0)) { dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY; dev->qfrozen++; } dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG); if (now_queuing) { u_int usertags; usertags = ahd_linux_user_tagdepth(ahd, devinfo); if (!was_queuing) { /* * Start out agressively and allow our * dynamic queue depth algorithm to take * care of the rest. */ dev->maxtags = usertags; dev->openings = dev->maxtags - dev->active; } if (dev->maxtags == 0) { /* * Queueing is disabled by the user. */ dev->openings = 1; } else if (alg == AHD_QUEUE_TAGGED) { dev->flags |= AHD_DEV_Q_TAGGED; if (aic79xx_periodic_otag != 0) dev->flags |= AHD_DEV_PERIODIC_OTAG; } else dev->flags |= AHD_DEV_Q_BASIC; } else { /* We can only have one opening. */ dev->maxtags = 0; dev->openings = 1 - dev->active; } switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { case AHD_DEV_Q_BASIC: scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TASK, dev->openings + dev->active); break; case AHD_DEV_Q_TAGGED: scsi_adjust_queue_depth(sdev, MSG_ORDERED_TASK, dev->openings + dev->active); break; default: /* * We allow the OS to queue 2 untagged transactions to * us at any time even though we can only execute them * serially on the controller/device. This should * remove some latency. */ scsi_adjust_queue_depth(sdev, /*NON-TAGGED*/0, /*queue depth*/2); break; }}intahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, role_t role, uint32_t status){ return 0;}static u_intahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo){ static int warned_user; u_int tags; tags = 0; if ((ahd->user_discenable & devinfo->target_mask) != 0) { if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) { if (warned_user == 0) { printf(KERN_WARNING"aic79xx: WARNING: Insufficient tag_info instances\n""aic79xx: for installed controllers. Using defaults\n""aic79xx: Please update the aic79xx_tag_info array in\n""aic79xx: the aic79xx_osm.c source file.\n"); warned_user++; } tags = AHD_MAX_QUEUE; } else { adapter_tag_info_t *tag_info; tag_info = &aic79xx_tag_info[ahd->unit]; tags = tag_info->tag_commands[devinfo->target_offset]; if (tags > AHD_MAX_QUEUE) tags = AHD_MAX_QUEUE; } } return (tags);}/* * Determines the queue depth for a given device. */static voidahd_linux_device_queue_depth(struct scsi_device *sdev){ struct ahd_devinfo devinfo; u_int tags; struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata); ahd_compile_devinfo(&devinfo, ahd->our_id, sdev->sdev_target->id, sdev->lun, sdev->sdev_target->channel == 0 ? 'A' : 'B', ROLE_INITIATOR); tags = ahd_linux_user_tagdepth(ahd, &devinfo); if (tags != 0 && sdev->tagged_supported != 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -