aic79xx_osm.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,358 行 · 第 1/5 页
C
2,358 行
if (starget->channel != 0) target_offset += 8; return &ahd->platform_data->starget[target_offset];}static intahd_linux_target_alloc(struct scsi_target *starget){ struct ahd_softc *ahd = *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata); struct seeprom_config *sc = ahd->seep_config; unsigned long flags; struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); struct ahd_linux_target *targ = scsi_transport_target_data(starget); struct ahd_devinfo devinfo; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; char channel = starget->channel + 'A'; ahd_lock(ahd, &flags); BUG_ON(*ahd_targp != NULL); *ahd_targp = starget; memset(targ, 0, sizeof(*targ)); if (sc) { int flags = sc->device_flags[starget->id]; tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, starget->id, &tstate); if ((flags & CFPACKETIZED) == 0) { /* Do not negotiate packetized transfers */ spi_rd_strm(starget) = 0; spi_pcomp_en(starget) = 0; spi_rti(starget) = 0; spi_wr_flow(starget) = 0; spi_hold_mcs(starget) = 0; } else { if ((ahd->features & AHD_RTI) == 0) spi_rti(starget) = 0; } if ((flags & CFQAS) == 0) spi_qas(starget) = 0; /* Transinfo values have been set to BIOS settings */ spi_max_width(starget) = (flags & CFWIDEB) ? 1 : 0; spi_min_period(starget) = tinfo->user.period; spi_max_offset(starget) = tinfo->user.offset; } tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id, starget->id, &tstate); ahd_compile_devinfo(&devinfo, ahd->our_id, starget->id, CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, AHD_TRANS_GOAL, /*paused*/FALSE); ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, AHD_TRANS_GOAL, /*paused*/FALSE); ahd_unlock(ahd, &flags); return 0;}static voidahd_linux_target_destroy(struct scsi_target *starget){ struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); *ahd_targp = NULL;}static intahd_linux_slave_alloc(struct scsi_device *sdev){ struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata); struct scsi_target *starget = sdev->sdev_target; struct ahd_linux_target *targ = scsi_transport_target_data(starget); struct ahd_linux_device *dev; if (bootverbose) printf("%s: Slave Alloc %d\n", ahd_name(ahd), 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; return (0);}static intahd_linux_slave_configure(struct scsi_device *sdev){ struct ahd_softc *ahd; ahd = *((struct ahd_softc **)sdev->host->hostdata); if (bootverbose) sdev_printk(KERN_INFO, sdev, "Slave Configure\n"); ahd_linux_device_queue_depth(sdev); /* Initial Domain Validation */ if (!spi_initial_dv(sdev->sdev_target)) spi_dv_device(sdev); return 0;}static voidahd_linux_slave_destroy(struct scsi_device *sdev){ struct ahd_softc *ahd; struct ahd_linux_device *dev = scsi_transport_device_data(sdev); struct ahd_linux_target *targ = scsi_transport_target_data(sdev->sdev_target); ahd = *((struct ahd_softc **)sdev->host->hostdata); if (bootverbose) printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id); BUG_ON(dev->active); targ->sdev[sdev->lun] = NULL;}#if defined(__i386__)/* * Return the disk geometry for the given SCSI device. */static intahd_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 ahd_softc *ahd; ahd = *((struct ahd_softc **)sdev->host->hostdata); 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 (aic79xx_extended != 0) extended = 1; else extended = (ahd->flags & AHD_EXTENDED_TRANS_A) != 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 intahd_linux_abort(struct scsi_cmnd *cmd){ int error; error = ahd_linux_queue_abort_cmd(cmd); return error;}/* * Attempt to send a target reset message to the device that timed out. */static intahd_linux_dev_reset(struct scsi_cmnd *cmd){ struct ahd_softc *ahd; struct ahd_linux_device *dev; struct scb *reset_scb; u_int cdb_byte; int retval = SUCCESS; int paused; int wait; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; unsigned long flags; DECLARE_COMPLETION(done); reset_scb = NULL; paused = FALSE; wait = FALSE; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; scmd_printk(KERN_INFO, cmd, "Attempting to queue a TARGET RESET message:"); printf("CDB:"); for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) printf(" 0x%x", cmd->cmnd[cdb_byte]); printf("\n"); /* * Determine if we currently own this command. */ dev = scsi_transport_device_data(cmd->device); if (dev == NULL) { /* * No target device for this command exists, * so we must not still own the command. */ scmd_printk(KERN_INFO, cmd, "Is not an active device\n"); return SUCCESS; } /* * Generate us a new SCB */ reset_scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX); if (!reset_scb) { scmd_printk(KERN_INFO, cmd, "No SCB available\n"); return FAILED; } tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, cmd->device->id, &tstate); reset_scb->io_ctx = cmd; reset_scb->platform_data->dev = dev; reset_scb->sg_count = 0; ahd_set_residual(reset_scb, 0); ahd_set_sense_residual(reset_scb, 0); reset_scb->platform_data->xfer_len = 0; reset_scb->hscb->control = 0; reset_scb->hscb->scsiid = BUILD_SCSIID(ahd,cmd); reset_scb->hscb->lun = cmd->device->lun; reset_scb->hscb->cdb_len = 0; reset_scb->hscb->task_management = SIU_TASKMGMT_LUN_RESET; reset_scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE; if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { reset_scb->flags |= SCB_PACKETIZED; } else { reset_scb->hscb->control |= MK_MESSAGE; } dev->openings--; dev->active++; dev->commands_issued++; ahd_lock(ahd, &flags); LIST_INSERT_HEAD(&ahd->pending_scbs, reset_scb, pending_links); ahd_queue_scb(ahd, reset_scb); ahd->platform_data->eh_done = &done; ahd_unlock(ahd, &flags); printf("%s: Device reset code sleeping\n", ahd_name(ahd)); if (!wait_for_completion_timeout(&done, 5 * HZ)) { ahd_lock(ahd, &flags); ahd->platform_data->eh_done = NULL; ahd_unlock(ahd, &flags); printf("%s: Device reset timer expired (active %d)\n", ahd_name(ahd), dev->active); retval = FAILED; } printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); return (retval);}/* * Reset the SCSI bus. */static intahd_linux_bus_reset(struct scsi_cmnd *cmd){ struct ahd_softc *ahd; int found; unsigned long flags; ahd = *(struct ahd_softc **)cmd->device->host->hostdata;#ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) printf("%s: Bus reset called for cmd %p\n", ahd_name(ahd), cmd);#endif ahd_lock(ahd, &flags); found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', /*initiate reset*/TRUE); ahd_unlock(ahd, &flags); if (bootverbose) printf("%s: SCSI bus reset delivered. " "%d SCBs aborted.\n", ahd_name(ahd), found); return (SUCCESS);}struct scsi_host_template aic79xx_driver_template = { .module = THIS_MODULE, .name = "aic79xx", .proc_name = "aic79xx", .proc_info = ahd_linux_proc_info, .info = ahd_linux_info, .queuecommand = ahd_linux_queue, .eh_abort_handler = ahd_linux_abort, .eh_device_reset_handler = ahd_linux_dev_reset, .eh_bus_reset_handler = ahd_linux_bus_reset,#if defined(__i386__) .bios_param = ahd_linux_biosparam,#endif .can_queue = AHD_MAX_QUEUE, .this_id = -1, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, .slave_alloc = ahd_linux_slave_alloc, .slave_configure = ahd_linux_slave_configure, .slave_destroy = ahd_linux_slave_destroy, .target_alloc = ahd_linux_target_alloc, .target_destroy = ahd_linux_target_destroy,};/******************************** Bus DMA *************************************/intahd_dma_tag_create(struct ahd_softc *ahd, 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);}voidahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat){ free(dmat, M_DEVBUF);}intahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr, int flags, bus_dmamap_t *mapp){ *vaddr = pci_alloc_consistent(ahd->dev_softc, dmat->maxsize, mapp); if (*vaddr == NULL) return (ENOMEM); return(0);}voidahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat, void* vaddr, bus_dmamap_t map){ pci_free_consistent(ahd->dev_softc, dmat->maxsize, vaddr, map);}intahd_dmamap_load(struct ahd_softc *ahd, 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);}voidahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map){}intahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map){ /* Nothing to do */ return (0);}/********************* Platform Dependent Functions ***************************/static voidahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value){ if ((instance >= 0) && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) { uint8_t *iocell_info; iocell_info = (uint8_t*)&aic79xx_iocell_info[instance]; iocell_info[index] = value & 0xFFFF; if (bootverbose) printf("iocell[%d:%ld] = %d\n", instance, index, value); }}static voidahd_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(aic79xx_tag_info); i++) { for (j = 0; j < AHD_NUM_TARGETS; j++) { aic79xx_tag_info[i].tag_commands[j] = tags; } }}static void
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?