📄 aic7xxx_linux.c
字号:
char *tok; char *tok_end; char *tok_end2; int i; int instance; int targ; int done; char tok_list[] = {'.', ',', '{', '}', '\0'}; if (*p != ':') 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; else if (targ == -1) targ = 0; tok++; break; case '}': if (targ != -1) targ = -1; else if (instance != -1) instance = -1; tok++; break; case ',': case '.': if (instance == -1) done = TRUE; else if (targ >= 0) targ++; else if (instance >= 0) instance++; if ((targ >= AHC_NUM_TARGETS) || (instance >= NUM_ELEMENTS(aic7xxx_tag_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) && (targ >= 0) && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) && (targ < AHC_NUM_TARGETS)) { aic7xxx_tag_info[instance].tag_commands[targ] = simple_strtoul(tok, NULL, 0) & 0xff; } 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. aic7xxx=stpwlev:1,extended */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 }, { "reverse_scan", &aic7xxx_reverse_scan }, { "no_probe", &aic7xxx_no_probe }, { "periodic_otag", &aic7xxx_periodic_otag }, { "pci_parity", &aic7xxx_pci_parity }, { "seltime", &aic7xxx_seltime }, { "tag_info", 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) { ahc_linux_setup_tag_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; } } register_reboot_notifier(&ahc_linux_notifier); return 1;}#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)__setup("aic7xxx=", aic7xxx_setup);#endifint aic7xxx_verbose;/* * Try to detect an Adaptec 7XXX controller. */intahc_linux_detect(Scsi_Host_Template *template){ struct ahc_softc *ahc; int found; /* * Sanity checking of Linux SCSI data structures so * that some of our hacks^H^H^H^H^Hassumptions aren't * violated. */ if (offsetof(struct ahc_cmd_internal, end) > offsetof(struct scsi_cmnd, host_scribble)) { printf("ahc_linux_detect: SCSI data structures changed.\n"); printf("ahc_linux_detect: Unable to attach\n"); return (0); }#ifdef MODULE /* * If we've been passed any parameters, process them now. */ if (aic7xxx) aic7xxx_setup(aic7xxx); if (dummy_buffer[0] != 'P') printk(KERN_WARNING"aic7xxx: Please read the file /usr/src/linux/drivers/scsi/README.aic7xxx\n""aic7xxx: to see the proper way to specify options to the aic7xxx module\n""aic7xxx: Specifically, don't use any commas when passing arguments to\n""aic7xxx: insmod or else it might trash certain memory areas.\n");#endif#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) template->proc_name = "aic7xxx";#else template->proc_dir = &proc_scsi_aic7xxx;#endif template->sg_tablesize = AHC_NSEG;#ifdef CONFIG_PCI ahc_linux_pci_probe(template);#endif if (aic7xxx_no_probe == 0) aic7770_linux_probe(template); /* * Register with the SCSI layer all * controllers we've found. */ found = 0; TAILQ_FOREACH(ahc, &ahc_tailq, links) { if (ahc_linux_register_host(ahc, template) == 0) found++; } aic7xxx_detect_complete++; return (found);}intahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template){ char buf[80]; struct Scsi_Host *host; char *new_name; u_long s; template->name = ahc->description; host = scsi_register(template, sizeof(struct ahc_softc *)); if (host == NULL) return (ENOMEM); ahc_lock(ahc, &s); *((struct ahc_softc **)host->hostdata) = ahc; ahc->platform_data->host = host; host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; host->sg_tablesize = AHC_NSEG; host->select_queue_depths = ahc_linux_select_queue_depth; /* 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; ahc_set_unit(ahc, ahc_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); ahc_set_name(ahc, new_name); } host->unique_id = ahc->unit;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) scsi_set_pci_device(host, ahc->dev_softc);#endif ahc_linux_initialize_scsi_bus(ahc); ahc_unlock(ahc, &s); return (0);}uint64_tahc_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 intahc_linux_next_unit(){ struct ahc_softc *ahc; int unit; unit = 0;retry: TAILQ_FOREACH(ahc, &ahc_tailq, links) { if (ahc->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. */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; } } 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); 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; ahc_compile_devinfo(&devinfo, our_id, target_id, CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); ahc_update_neg_request(ahc, &devinfo, tstate, tinfo, /*force*/FALSE); } /* Give the bus some time to recover */ if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { ahc_linux_freeze_sim_queue(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_sim_queue; 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)); TAILQ_INIT(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->device_runq); ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; ahc_lockinit(ahc); ahc_done_lockinit(ahc);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) init_MUTEX_LOCKED(&ahc->platform_data->eh_sem);#else ahc->platform_data->eh_sem = MUTEX_LOCKED;#endif ahc->seltime = (aic7xxx_seltime & 0x3) << 4; ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; return (0);}voidahc_platform_free(struct ahc_softc *ahc){ if (ahc->platform_data != NULL) { if (ahc->platform_data->host != NULL) scsi_unregister(ahc->platform_data->host); if (ahc->platform_data->irq) 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) { u_long base_addr; base_addr = (u_long)ahc->bsh.maddr; base_addr &= PAGE_MASK; iounmap((void *)base_addr);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) release_mem_region(ahc->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 (ahc->dev_softc != NULL) ahc->dev_softc->driver = NULL;#endif 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 ahc_linux_device *dev; int was_queuing; int now_queuing; dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', devinfo->target, devinfo->lun, /*alloc*/FALSE); if (dev == NULL) return; was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); now_queuing = alg != AHC_QUEUE_NONE; 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) { if (!was_queuing) { /* * Start out agressively and allow our * dynamic queue depth algorithm to take * care of the rest. */ dev->maxtags = AHC_MAX_QUEUE; dev->openings = dev->maxtags - dev->active; } if (alg == AHC_QUEUE_TAGGED) { dev->flags |= AHC_DEV_Q_TAGGED; if (aic7xxx_periodic_otag != 0) dev->flags |= AHC_DEV_PERIODIC_OTAG;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -