📄 aic7xxx_osm.c
字号:
if (tok_end < end) *tok_end = ','; while (!done) { switch (*opt_arg) { case '{': if (instance == -1) { instance = 0; } else { if (depth > 1) { if (targ == -1) targ = 0; } else { printf("Malformed Option %s\n", opt_name); done = TRUE; } } opt_arg++; 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. aic7xxx=stpwlev:1,extended */static intaic7xxx_setup(char *s){ int i, n; char *p; char *end; static struct { const char *name; uint32_t *flag; } options[] = { { "extended", &aic7xxx_extended }, { "no_reset", &aic7xxx_no_reset }, { "verbose", &aic7xxx_verbose }, { "allow_memio", &aic7xxx_allow_memio},#ifdef AHC_DEBUG { "debug", &ahc_debug },#endif { "periodic_otag", &aic7xxx_periodic_otag }, { "pci_parity", &aic7xxx_pci_parity }, { "seltime", &aic7xxx_seltime }, { "tag_info", NULL }, { "global_tag_depth", NULL }, { "dv", 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) { ahc_linux_setup_tag_info_global(p + n); } else if (strncmp(p, "tag_info", n) == 0) { s = ahc_parse_brace_option("tag_info", p + n, end, 2, ahc_linux_setup_tag_info, 0); } else if (p[n] == ':') { *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); } else if (strncmp(p, "verbose", n) == 0) { *(options[i].flag) = 1; } else { *(options[i].flag) ^= 0xFFFFFFFF; } } return 1;}__setup("aic7xxx=", aic7xxx_setup);uint32_t aic7xxx_verbose;intahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *template){ char buf[80]; struct Scsi_Host *host; char *new_name; u_long s; template->name = ahc->description; host = scsi_host_alloc(template, sizeof(struct ahc_softc *)); if (host == NULL) return (ENOMEM); *((struct ahc_softc **)host->hostdata) = ahc; ahc_lock(ahc, &s); ahc->platform_data->host = host; host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; /* XXX No way to communicate the ID for multiple channels */ host->this_id = ahc->our_id; host->irq = ahc->platform_data->irq; host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8; host->max_lun = AHC_NUM_LUNS; host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; host->sg_tablesize = AHC_NSEG; ahc_set_unit(ahc, ahc_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); ahc_set_name(ahc, new_name); } host->unique_id = ahc->unit; ahc_linux_initialize_scsi_bus(ahc); ahc_intr_enable(ahc, TRUE); ahc_unlock(ahc, &s); host->transportt = ahc_linux_transport_template; scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */ scsi_scan_host(host); return (0);}/* * Place the SCSI bus into a known state by either resetting it, * or forcing transfer negotiations on the next command to any * target. */voidahc_linux_initialize_scsi_bus(struct ahc_softc *ahc){ int i; int numtarg; i = 0; numtarg = 0; if (aic7xxx_no_reset != 0) ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B); if ((ahc->flags & AHC_RESET_BUS_A) != 0) ahc_reset_channel(ahc, 'A', /*initiate_reset*/TRUE); else numtarg = (ahc->features & AHC_WIDE) ? 16 : 8; if ((ahc->features & AHC_TWIN) != 0) { if ((ahc->flags & AHC_RESET_BUS_B) != 0) { ahc_reset_channel(ahc, 'B', /*initiate_reset*/TRUE); } else { if (numtarg == 0) i = 8; numtarg += 8; } } /* * Force negotiation to async for all targets that * will not see an initial bus reset. */ for (; i < numtarg; i++) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *tinfo; struct ahc_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; channel = 'A'; our_id = ahc->our_id; target_id = i; if (i > 7 && (ahc->features & AHC_TWIN) != 0) { channel = 'B'; our_id = ahc->our_id_b; target_id = i % 8; } tinfo = ahc_fetch_transinfo(ahc, channel, our_id, target_id, &tstate); ahc_compile_devinfo(&devinfo, our_id, target_id, CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); ahc_update_neg_request(ahc, &devinfo, tstate, tinfo, AHC_NEG_ALWAYS); } /* Give the bus some time to recover */ if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { ahc_linux_freeze_simq(ahc); init_timer(&ahc->platform_data->reset_timer); ahc->platform_data->reset_timer.data = (u_long)ahc; ahc->platform_data->reset_timer.expires = jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; ahc->platform_data->reset_timer.function = ahc_linux_release_simq; add_timer(&ahc->platform_data->reset_timer); }}intahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg){ ahc->platform_data = malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT); if (ahc->platform_data == NULL) return (ENOMEM); memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); ahc->platform_data->irq = AHC_LINUX_NOIRQ; ahc_lockinit(ahc); init_MUTEX_LOCKED(&ahc->platform_data->eh_sem); ahc->seltime = (aic7xxx_seltime & 0x3) << 4; ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; if (aic7xxx_pci_parity == 0) ahc->flags |= AHC_DISABLE_PCI_PERR; return (0);}voidahc_platform_free(struct ahc_softc *ahc){ struct scsi_target *starget; int i, j; if (ahc->platform_data != NULL) { /* destroy all of the device and target objects */ for (i = 0; i < AHC_NUM_TARGETS; i++) { starget = ahc->platform_data->starget[i]; if (starget != NULL) { for (j = 0; j < AHC_NUM_LUNS; j++) { struct ahc_linux_target *targ = scsi_transport_target_data(starget); if (targ->sdev[j] == NULL) continue; targ->sdev[j] = NULL; } ahc->platform_data->starget[i] = NULL; } } if (ahc->platform_data->irq != AHC_LINUX_NOIRQ) free_irq(ahc->platform_data->irq, ahc); if (ahc->tag == BUS_SPACE_PIO && ahc->bsh.ioport != 0) release_region(ahc->bsh.ioport, 256); if (ahc->tag == BUS_SPACE_MEMIO && ahc->bsh.maddr != NULL) { iounmap(ahc->bsh.maddr); release_mem_region(ahc->platform_data->mem_busaddr, 0x1000); } if (ahc->platform_data->host) scsi_host_put(ahc->platform_data->host); free(ahc->platform_data, M_DEVBUF); }}voidahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb){ ahc_platform_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb), SCB_GET_CHANNEL(ahc, scb), SCB_GET_LUN(scb), SCB_LIST_NULL, ROLE_UNKNOWN, CAM_REQUEUE_REQ);}voidahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc_queue_alg alg){ struct scsi_target *starget; struct ahc_linux_target *targ; struct ahc_linux_device *dev; struct scsi_device *sdev; u_int target_offset; int was_queuing; int now_queuing; target_offset = devinfo->target; if (devinfo->channel != 'A') target_offset += 8; starget = ahc->platform_data->starget[target_offset]; 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); was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); switch (alg) { default: case AHC_QUEUE_NONE: now_queuing = 0; break; case AHC_QUEUE_BASIC: now_queuing = AHC_DEV_Q_BASIC; break; case AHC_QUEUE_TAGGED: now_queuing = AHC_DEV_Q_TAGGED; break; } if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 && (was_queuing != now_queuing) && (dev->active != 0)) { dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; dev->qfrozen++; } dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED|AHC_DEV_PERIODIC_OTAG); if (now_queuing) { u_int usertags; usertags = ahc_linux_user_tagdepth(ahc, 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 == AHC_QUEUE_TAGGED) { dev->flags |= AHC_DEV_Q_TAGGED; if (aic7xxx_periodic_otag != 0) dev->flags |= AHC_DEV_PERIODIC_OTAG; } else dev->flags |= AHC_DEV_Q_BASIC; } else { /* We can only have one opening. */ dev->maxtags = 0; dev->openings = 1 - dev->active; } switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) { case AHC_DEV_Q_BASIC: scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); scsi_activate_tcq(sdev, dev->openings + dev->active); break; case AHC_DEV_Q_TAGGED: scsi_set_tag_type(sdev, MSG_ORDERED_TAG); scsi_activate_tcq(sdev, 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_deactivate_tcq(sdev, 2); break; }}intahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status){ return 0;}static u_intahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo){ static int warned_user; u_int tags; tags = 0; if ((ahc->user_discenable & devinfo->target_mask) != 0) { if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { if (warned_user == 0) { printf(KERN_WARNING"aic7xxx: WARNING: Insufficient tag_info instances\n""aic7xxx: for installed controllers. Using defaults\n""aic7xxx: Please update the aic7xxx_tag_info array in\n""aic7xxx: the aic7xxx_osm..c source file.\n"); warned_user++; } tags = AHC_MAX_QUEUE; } else { adapter_tag_info_t *tag_info; tag_info = &aic7xxx_tag_info[ahc->unit]; tags = tag_info->tag_commands[devinfo->target_offset]; if (tags > AHC_MAX_QUEUE) tags = AHC_MAX_QUEUE; } } return (tags);}/* * Determines the queue depth for a given device. */static voidahc_linux_device_queue_depth(struct scsi_device *sdev){ struct ahc_devinfo devinfo; u_int tags; struct ahc_softc *ahc = *((struct ahc_softc **)sdev->host->hostdata); ahc_compile_devinfo(&devinfo, sdev->sdev_target->channel == 0 ? ahc->our_id : ahc->our_id_b, sdev->sdev_target->id, sdev->lun, sdev->sdev_target->channel == 0 ? 'A' : 'B', ROLE_INITIATOR); tags = ahc_linux_user_tagdepth(ahc, &devinfo); if (tags != 0 && sdev->tagged_supported != 0) { ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED); ahc_print_devinfo(ahc, &devinfo);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -