📄 aic79xx_osm.c
字号:
return; instance = -1; targ = -1; done = FALSE; base = p; /* Forward us just past the ':' */ tok = base + 1; tok_end = strchr(tok, '\0'); if (tok_end < end) *tok_end = ','; while (!done) { switch (*tok) { case '{': if (instance == -1) instance = 0; tok++; break; case '}': if (instance != -1) instance = -1; tok++; break; case ',': case '.': if (instance == -1) done = TRUE; else if (instance >= 0) instance++; if (instance >= NUM_ELEMENTS(aic79xx_rd_strm_info)) done = TRUE; tok++; if (!done) { base = tok; } break; case '\0': done = TRUE; break; default: done = TRUE; tok_end = strchr(tok, '\0'); for (i = 0; tok_list[i]; i++) { tok_end2 = strchr(tok, tok_list[i]); if ((tok_end2) && (tok_end2 < tok_end)) { tok_end = tok_end2; done = FALSE; } } if ((instance >= 0) && (instance < NUM_ELEMENTS(aic79xx_tag_info))) { aic79xx_rd_strm_info[instance] = simple_strtoul(tok, NULL, 0) & 0xffff; } tok = tok_end; break; } } while ((p != base) && (p != NULL)) p = strtok(NULL, ",.");}/* * 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 */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 },#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 }, { "rd_strm", NULL } }; end = strchr(s, '\0'); for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) { for (i = 0; i < NUM_ELEMENTS(options); i++) { n = strlen(options[i].name); if (strncmp(options[i].name, p, n) != 0) continue; if (strncmp(p, "tag_info", n) == 0) { ahd_linux_setup_tag_info(p + n, end); } else if (strncmp(p, "rd_strm", n) == 0) { ahd_linux_setup_rd_strm_info(p + n, end); } 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) = ~(*(options[i].flag)); } break; } } return 1;}#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)__setup("aic79xx=", aic79xx_setup);#endifint aic79xx_verbose;/* * Try to detect an Adaptec 79XX controller. */intahd_linux_detect(Scsi_Host_Template *template){ struct ahd_softc *ahd; int found; /* * It is a bug that the upper layer takes * this lock just prior to calling us. */ spin_unlock_irq(&io_request_lock); /* * Sanity checking of Linux SCSI data structures so * that some of our hacks^H^H^H^H^Hassumptions aren't * violated. */ if (offsetof(struct ahd_cmd_internal, end) > offsetof(struct scsi_cmnd, host_scribble)) { printf("ahd_linux_detect: SCSI data structures changed.\n"); printf("ahd_linux_detect: Unable to attach\n"); return (0); }#ifdef MODULE /* * If we've been passed any parameters, process them now. */ if (aic79xx) aic79xx_setup(aic79xx); if (dummy_buffer[0] != 'P') printk(KERN_WARNING"aic79xx: Please read the file /usr/src/linux/drivers/scsi/README.aic79xx\n""aic79xx: to see the proper way to specify options to the aic79xx module\n""aic79xx: Specifically, don't use any commas when passing arguments to\n""aic79xx: insmod or else it might trash certain memory areas.\n");#endif#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) template->proc_name = "aic79xx";#else template->proc_dir = &proc_scsi_aic79xx;#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) /* * We can only map 16MB per-SG * so create a sector limit of * "16MB" in 2K sectors. */ template->max_sectors = 8192;#endif /* * Initialize our softc list lock prior to * probing for any adapters. */ ahd_list_lockinit();#ifdef CONFIG_PCI ahd_linux_pci_probe(template);#endif /* * Register with the SCSI layer all * controllers we've found. */ spin_lock_irq(&io_request_lock); found = 0; TAILQ_FOREACH(ahd, &ahd_tailq, links) { if (ahd_linux_register_host(ahd, template) == 0) found++; } aic79xx_detect_complete++; return (found);}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; template->name = ahd->description; host = scsi_register(template, sizeof(struct ahd_softc *)); if (host == NULL) return (ENOMEM); ahd_lock(ahd, &s); *((struct ahd_softc **)host->hostdata) = ahd; ahd->platform_data->host = host; host->can_queue = AHD_MAX_QUEUE; host->cmd_per_lun = 2; host->sg_tablesize = AHD_NSEG; host->select_queue_depths = ahd_linux_select_queue_depth; 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; 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,4,4) scsi_set_pci_device(host, ahd->dev_softc);#endif ahd_linux_initialize_scsi_bus(ahd); ahd_unlock(ahd, &s); return (0);}uint64_tahd_linux_get_memsize(){ struct sysinfo si; si_meminfo(&si); return (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(){ 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. */voidahd_linux_initialize_scsi_bus(struct ahd_softc *ahd){ int i; int numtarg; i = 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; for (; i < numtarg; i++) { struct ahd_devinfo devinfo; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; u_int our_id; u_int target_id; char channel; channel = 'A'; our_id = ahd->our_id; target_id = i; tinfo = ahd_fetch_transinfo(ahd, channel, our_id, target_id, &tstate); tinfo->goal = tinfo->user; /* * Don't try negotiations that require PPR messages * until we successfully retrieve Inquiry data. */ tinfo->goal.ppr_options = 0; if (tinfo->goal.transport_version > SCSI_REV_2) tinfo->goal.transport_version = SCSI_REV_2; ahd_compile_devinfo(&devinfo, our_id, target_id, CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); ahd_update_neg_request(ahd, &devinfo, tstate, tinfo, /*force*/FALSE); } /* 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);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) init_MUTEX_LOCKED(&ahd->platform_data->eh_sem);#else ahd->platform_data->eh_sem = MUTEX_LOCKED;#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet, (unsigned long)ahd);#endif ahd->seltime = (aic79xx_seltime & 0x3) << 4; if (TAILQ_EMPTY(&ahd_tailq)) register_reboot_notifier(&ahd_linux_notifier); return (0);}voidahd_platform_free(struct ahd_softc *ahd){ if (ahd->platform_data != NULL) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tasklet_kill(&ahd->platform_data->runq_tasklet);#endif if (ahd->platform_data->host != NULL) scsi_unregister(ahd->platform_data->host); 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) { u_long base_addr; base_addr = (u_long)ahd->bshs[0].maddr; base_addr &= PAGE_MASK; iounmap((void *)base_addr);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) release_mem_region(ahd->platform_data->mem_busaddr, 0x1000);#endif }#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* XXX Need an instance detach in the PCI code */ if (ahd->dev_softc != NULL) ahd->dev_softc->driver = NULL;#endif free(ahd->platform_data, M_DEVBUF); } if (TAILQ_EMPTY(&ahd_tailq)) { unregister_reboot_notifier(&ahd_linux_notifier);#ifdef CONFIG_PCI#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pci_unregister_driver(&aic79xx_pci_driver);#endif#endif }}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 ahd_linux_device *dev; int was_queuing; int now_queuing; dev = ahd_linux_get_device(ahd, devinfo->channel - 'A', devinfo->target, devinfo->lun, /*alloc*/FALSE); if (dev == NULL) return; was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED); now_queuing = alg != AHD_QUEUE_NONE; 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 (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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -