📄 aic7xxx_osm.c
字号:
switch (rvalue) { case AHC_PCI: { char primary_channel; if (aic7xxx_reverse_scan != 0) value = ahc_get_pci_bus(rahc->dev_softc) - ahc_get_pci_bus(lahc->dev_softc); else value = ahc_get_pci_bus(lahc->dev_softc) - ahc_get_pci_bus(rahc->dev_softc); if (value != 0) break; if (aic7xxx_reverse_scan != 0) value = ahc_get_pci_slot(rahc->dev_softc) - ahc_get_pci_slot(lahc->dev_softc); else value = ahc_get_pci_slot(lahc->dev_softc) - ahc_get_pci_slot(rahc->dev_softc); if (value != 0) break; /* * On multi-function devices, the user can choose * to have function 1 probed before function 0. * Give whichever channel is the primary channel * the lowest priority. */ primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A'; value = 1; if (lahc->channel == primary_channel) value = -1; break; } case AHC_EISA: if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { value = lahc->platform_data->bios_address - rahc->platform_data->bios_address; } else { value = lahc->bsh.ioport - rahc->bsh.ioport; } break; default: panic("ahc_softc_sort: invalid bus type"); } return (value);}static voidahc_linux_setup_tag_info(char *p, char *end){ char *base; 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; } } 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; /* * 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 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#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. */ ahc_list_lockinit();#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. */ spin_lock_irq(&io_request_lock); 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->irq = AHC_LINUX_NOIRQ; 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#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tasklet_init(&ahc->platform_data->runq_tasklet, ahc_runq_tasklet, (unsigned long)ahc);#endif ahc->seltime = (aic7xxx_seltime & 0x3) << 4; ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; if (TAILQ_EMPTY(&ahc_tailq)) register_reboot_notifier(&ahc_linux_notifier); return (0);}voidahc_platform_free(struct ahc_softc *ahc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -