📄 aic7xxx_osm.c
字号:
return (bp);}/* * Queue an SCB to the controller. */static intahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)){ struct ahc_softc *ahc; struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device); int rtn = SCSI_MLQUEUE_HOST_BUSY; unsigned long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; ahc_lock(ahc, &flags); if (ahc->platform_data->qfrozen == 0) { cmd->scsi_done = scsi_done; cmd->result = CAM_REQ_INPROG << 16; rtn = ahc_linux_run_command(ahc, dev, cmd); } ahc_unlock(ahc, &flags); return rtn;}static inline struct scsi_target **ahc_linux_target_in_softc(struct scsi_target *starget){ struct ahc_softc *ahc = *((struct ahc_softc **)dev_to_shost(&starget->dev)->hostdata); unsigned int target_offset; target_offset = starget->id; if (starget->channel != 0) target_offset += 8; return &ahc->platform_data->starget[target_offset];}static intahc_linux_target_alloc(struct scsi_target *starget){ struct ahc_softc *ahc = *((struct ahc_softc **)dev_to_shost(&starget->dev)->hostdata); struct seeprom_config *sc = ahc->seep_config; unsigned long flags; struct scsi_target **ahc_targp = ahc_linux_target_in_softc(starget); struct ahc_linux_target *targ = scsi_transport_target_data(starget); unsigned short scsirate; struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *tinfo; struct ahc_tmode_tstate *tstate; char channel = starget->channel + 'A'; unsigned int our_id = ahc->our_id; unsigned int target_offset; target_offset = starget->id; if (starget->channel != 0) target_offset += 8; if (starget->channel) our_id = ahc->our_id_b; ahc_lock(ahc, &flags); BUG_ON(*ahc_targp != NULL); *ahc_targp = starget; memset(targ, 0, sizeof(*targ)); if (sc) { int maxsync = AHC_SYNCRATE_DT; int ultra = 0; int flags = sc->device_flags[target_offset]; if (ahc->flags & AHC_NEWEEPROM_FMT) { if (flags & CFSYNCHISULTRA) ultra = 1; } else if (flags & CFULTRAEN) ultra = 1; /* AIC nutcase; 10MHz appears as ultra = 1, CFXFER = 0x04 * change it to ultra=0, CFXFER = 0 */ if(ultra && (flags & CFXFER) == 0x04) { ultra = 0; flags &= ~CFXFER; } if ((ahc->features & AHC_ULTRA2) != 0) { scsirate = (flags & CFXFER) | (ultra ? 0x8 : 0); } else { scsirate = (flags & CFXFER) << 4; maxsync = ultra ? AHC_SYNCRATE_ULTRA : AHC_SYNCRATE_FAST; } spi_max_width(starget) = (flags & CFWIDEB) ? 1 : 0; if (!(flags & CFSYNCH)) spi_max_offset(starget) = 0; spi_min_period(starget) = ahc_find_period(ahc, scsirate, maxsync); tinfo = ahc_fetch_transinfo(ahc, channel, ahc->our_id, starget->id, &tstate); } ahc_compile_devinfo(&devinfo, our_id, starget->id, CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); ahc_set_syncrate(ahc, &devinfo, NULL, 0, 0, 0, AHC_TRANS_GOAL, /*paused*/FALSE); ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, AHC_TRANS_GOAL, /*paused*/FALSE); ahc_unlock(ahc, &flags); return 0;}static voidahc_linux_target_destroy(struct scsi_target *starget){ struct scsi_target **ahc_targp = ahc_linux_target_in_softc(starget); *ahc_targp = NULL;}static intahc_linux_slave_alloc(struct scsi_device *sdev){ struct ahc_softc *ahc = *((struct ahc_softc **)sdev->host->hostdata); struct scsi_target *starget = sdev->sdev_target; struct ahc_linux_target *targ = scsi_transport_target_data(starget); struct ahc_linux_device *dev; if (bootverbose) printf("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id); BUG_ON(targ->sdev[sdev->lun] != NULL); dev = scsi_transport_device_data(sdev); memset(dev, 0, sizeof(*dev)); /* * We start out life using untagged * transactions of which we allow one. */ dev->openings = 1; /* * Set maxtags to 0. This will be changed if we * later determine that we are dealing with * a tagged queuing capable device. */ dev->maxtags = 0; targ->sdev[sdev->lun] = sdev; spi_period(starget) = 0; return 0;}static intahc_linux_slave_configure(struct scsi_device *sdev){ struct ahc_softc *ahc; ahc = *((struct ahc_softc **)sdev->host->hostdata); if (bootverbose) sdev_printk(KERN_INFO, sdev, "Slave Configure\n"); ahc_linux_device_queue_depth(sdev); /* Initial Domain Validation */ if (!spi_initial_dv(sdev->sdev_target)) spi_dv_device(sdev); return 0;}static voidahc_linux_slave_destroy(struct scsi_device *sdev){ struct ahc_softc *ahc; struct ahc_linux_device *dev = scsi_transport_device_data(sdev); struct ahc_linux_target *targ = scsi_transport_target_data(sdev->sdev_target); ahc = *((struct ahc_softc **)sdev->host->hostdata); if (bootverbose) printf("%s: Slave Destroy %d\n", ahc_name(ahc), sdev->id); BUG_ON(dev->active); targ->sdev[sdev->lun] = NULL;}#if defined(__i386__)/* * Return the disk geometry for the given SCSI device. */static intahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]){ uint8_t *bh; int heads; int sectors; int cylinders; int ret; int extended; struct ahc_softc *ahc; u_int channel; ahc = *((struct ahc_softc **)sdev->host->hostdata); channel = sdev_channel(sdev); bh = scsi_bios_ptable(bdev); if (bh) { ret = scsi_partsize(bh, capacity, &geom[2], &geom[0], &geom[1]); kfree(bh); if (ret != -1) return (ret); } heads = 64; sectors = 32; cylinders = aic_sector_div(capacity, heads, sectors); if (aic7xxx_extended != 0) extended = 1; else if (channel == 0) extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0; else extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0; if (extended && cylinders >= 1024) { heads = 255; sectors = 63; cylinders = aic_sector_div(capacity, heads, sectors); } geom[0] = heads; geom[1] = sectors; geom[2] = cylinders; return (0);}#endif/* * Abort the current SCSI command(s). */static intahc_linux_abort(struct scsi_cmnd *cmd){ int error; error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); if (error != 0) printf("aic7xxx_abort returns 0x%x\n", error); return (error);}/* * Attempt to send a target reset message to the device that timed out. */static intahc_linux_dev_reset(struct scsi_cmnd *cmd){ int error; error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); if (error != 0) printf("aic7xxx_dev_reset returns 0x%x\n", error); return (error);}/* * Reset the SCSI bus. */static intahc_linux_bus_reset(struct scsi_cmnd *cmd){ struct ahc_softc *ahc; int found; unsigned long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; ahc_lock(ahc, &flags); found = ahc_reset_channel(ahc, scmd_channel(cmd) + 'A', /*initiate reset*/TRUE); ahc_unlock(ahc, &flags); if (bootverbose) printf("%s: SCSI bus reset delivered. " "%d SCBs aborted.\n", ahc_name(ahc), found); return SUCCESS;}struct scsi_host_template aic7xxx_driver_template = { .module = THIS_MODULE, .name = "aic7xxx", .proc_name = "aic7xxx", .proc_info = ahc_linux_proc_info, .info = ahc_linux_info, .queuecommand = ahc_linux_queue, .eh_abort_handler = ahc_linux_abort, .eh_device_reset_handler = ahc_linux_dev_reset, .eh_bus_reset_handler = ahc_linux_bus_reset,#if defined(__i386__) .bios_param = ahc_linux_biosparam,#endif .can_queue = AHC_MAX_QUEUE, .this_id = -1, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, .slave_alloc = ahc_linux_slave_alloc, .slave_configure = ahc_linux_slave_configure, .slave_destroy = ahc_linux_slave_destroy, .target_alloc = ahc_linux_target_alloc, .target_destroy = ahc_linux_target_destroy,};/**************************** Tasklet Handler *********************************//******************************** Macros **************************************/#define BUILD_SCSIID(ahc, cmd) \ ((((cmd)->device->id << TID_SHIFT) & TID) \ | (((cmd)->device->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \ | (((cmd)->device->channel == 0) ? 0 : TWIN_CHNLB))/******************************** Bus DMA *************************************/intahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent, bus_size_t alignment, bus_size_t boundary, dma_addr_t lowaddr, dma_addr_t highaddr, bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, int nsegments, bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag){ bus_dma_tag_t dmat; dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); if (dmat == NULL) return (ENOMEM); /* * Linux is very simplistic about DMA memory. For now don't * maintain all specification information. Once Linux supplies * better facilities for doing these operations, or the * needs of this particular driver change, we might need to do * more here. */ dmat->alignment = alignment; dmat->boundary = boundary; dmat->maxsize = maxsize; *ret_tag = dmat; return (0);}voidahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat){ free(dmat, M_DEVBUF);}intahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr, int flags, bus_dmamap_t *mapp){ *vaddr = pci_alloc_consistent(ahc->dev_softc, dmat->maxsize, mapp); if (*vaddr == NULL) return ENOMEM; return 0;}voidahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat, void* vaddr, bus_dmamap_t map){ pci_free_consistent(ahc->dev_softc, dmat->maxsize, vaddr, map);}intahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, void *cb_arg, int flags){ /* * Assume for now that this will only be used during * initialization and not for per-transaction buffer mapping. */ bus_dma_segment_t stack_sg; stack_sg.ds_addr = map; stack_sg.ds_len = dmat->maxsize; cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); return (0);}voidahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map){}intahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map){ /* Nothing to do */ return (0);}static voidahc_linux_setup_tag_info_global(char *p){ int tags, i, j; tags = simple_strtoul(p + 1, NULL, 0) & 0xff; printf("Setting Global Tags= %d\n", tags); for (i = 0; i < NUM_ELEMENTS(aic7xxx_tag_info); i++) { for (j = 0; j < AHC_NUM_TARGETS; j++) { aic7xxx_tag_info[i].tag_commands[j] = tags; } }}static voidahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value){ if ((instance >= 0) && (targ >= 0) && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) && (targ < AHC_NUM_TARGETS)) { aic7xxx_tag_info[instance].tag_commands[targ] = value & 0xff; if (bootverbose) printf("tag_info[%d:%d] = %d\n", instance, targ, value); }}static char *ahc_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, void (*callback)(u_long, int, int, int32_t), u_long callback_arg){ char *tok_end; char *tok_end2; int i; int instance; int targ; int done; char tok_list[] = {'.', ',', '{', '}', '\0'}; /* All options use a ':' name/arg separator */ if (*opt_arg != ':') return (opt_arg); opt_arg++; instance = -1; targ = -1; done = FALSE; /* * Restore separator that may be in * the middle of our option argument. */ tok_end = strchr(opt_arg, '\0');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -