📄 aic79xx_osm.c
字号:
dev->openings = 1 - dev->active; }}intahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, role_t role, uint32_t status){ int targ; int maxtarg; int maxlun; int clun; int count; if (tag != SCB_LIST_NULL) return (0); targ = 0; if (target != CAM_TARGET_WILDCARD) { targ = target; maxtarg = targ + 1; } else { maxtarg = (ahd->features & AHD_WIDE) ? 16 : 8; } clun = 0; if (lun != CAM_LUN_WILDCARD) { clun = lun; maxlun = clun + 1; } else { maxlun = AHD_NUM_LUNS; } count = 0; for (; targ < maxtarg; targ++) { for (; clun < maxlun; clun++) { struct ahd_linux_device *dev; struct ahd_busyq *busyq; struct ahd_cmd *acmd; dev = ahd_linux_get_device(ahd, /*chan*/0, targ, clun, /*alloc*/FALSE); if (dev == NULL) continue; busyq = &dev->busyq; while ((acmd = TAILQ_FIRST(busyq)) != NULL) { Scsi_Cmnd *cmd; cmd = &acmd_scsi_cmd(acmd); TAILQ_REMOVE(busyq, acmd, acmd_links.tqe); count++; cmd->result = status << 16; ahd_linux_queue_cmd_complete(ahd, cmd); } } } return (count);}/* * Sets the queue depth for each SCSI device hanging * off the input host adapter. */static voidahd_linux_select_queue_depth(struct Scsi_Host * host, Scsi_Device * scsi_devs){ Scsi_Device *device; struct ahd_softc *ahd; u_long flags; int scbnum; ahd = *((struct ahd_softc **)host->hostdata); ahd_lock(ahd, &flags); scbnum = 0; for (device = scsi_devs; device != NULL; device = device->next) { if (device->host == host) { ahd_linux_device_queue_depth(ahd, device); scbnum += device->queue_depth; } } ahd_unlock(ahd, &flags);}static u_intahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo){ static int warned_user; u_int tags; tags = 0; if ((ahd->user_discenable & devinfo->target_mask) != 0) { if (warned_user == 0 && ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) { printf("aic79xx: WARNING, insufficient " "tag_info instances for installed " "controllers. Using defaults\n"); printf("aic79xx: Please update the " "aic79xx_tag_info array in the " "aic79xx.c source file.\n"); tags = AHD_MAX_QUEUE; warned_user++; } else { adapter_tag_info_t *tag_info; tag_info = &aic79xx_tag_info[ahd->unit]; tags = tag_info->tag_commands[devinfo->target_offset]; if (tags > AHD_MAX_QUEUE) tags = AHD_MAX_QUEUE; } } return (tags);}/* * Determines the queue depth for a given device. */static voidahd_linux_device_queue_depth(struct ahd_softc *ahd, Scsi_Device * device){ struct ahd_devinfo devinfo; u_int tags; ahd_compile_devinfo(&devinfo, ahd->our_id, device->id, device->lun, device->channel == 0 ? 'A' : 'B', ROLE_INITIATOR); tags = ahd_linux_user_tagdepth(ahd, &devinfo); if (tags != 0 && device->tagged_supported != 0) { device->queue_depth = tags; ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED); printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n", ahd->platform_data->host->host_no, devinfo.channel, devinfo.target, devinfo.lun, tags); } else { /* * We allow the OS to queue 2 untagged transactions to * us at any time even though we can only execute them * serially on the controller/device. This should remove * some latency. */ device->queue_depth = 2; }}/* * Queue an SCB to the controller. */intahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)){ struct ahd_softc *ahd; struct ahd_linux_device *dev; u_long flags; ahd = *(struct ahd_softc **)cmd->host->hostdata; /* * Save the callback on completion function. */ cmd->scsi_done = scsi_done; ahd_lock(ahd, &flags); dev = ahd_linux_get_device(ahd, cmd->channel, cmd->target, cmd->lun, /*alloc*/TRUE); if (dev == NULL) { ahd_unlock(ahd, &flags); printf("aic79xx_linux_queue: Unable to allocate device!\n"); return (-ENOMEM); } if (cmd->cmd_len > MAX_CDB_LEN) return (-EINVAL); cmd->result = CAM_REQ_INPROG << 16; TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe); if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); dev->flags |= AHD_DEV_ON_RUN_LIST; ahd_linux_run_device_queues(ahd); } ahd_unlock(ahd, &flags); return (0);}static voidahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev){ struct ahd_cmd *acmd; struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; uint16_t mask; if ((dev->flags & AHD_DEV_ON_RUN_LIST) != 0) panic("running device on run list"); while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL && dev->openings > 0 && dev->qfrozen == 0) { /* * Schedule us to run later. The only reason we are not * running is because the whole controller Q is frozen. */ if (ahd->platform_data->qfrozen != 0) { TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); dev->flags |= AHD_DEV_ON_RUN_LIST; return; } /* * Get an scb to use. */ if ((scb = ahd_get_scb(ahd)) == NULL) { TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); dev->flags |= AHD_DEV_ON_RUN_LIST; ahd->flags |= AHD_RESOURCE_SHORTAGE; return; } TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe); cmd = &acmd_scsi_cmd(acmd); scb->io_ctx = cmd; scb->platform_data->dev = dev; hscb = scb->hscb; cmd->host_scribble = (char *)scb; /* * Fill out basics of the HSCB. */ hscb->control = 0; hscb->scsiid = BUILD_SCSIID(ahd, cmd); hscb->lun = cmd->lun; mask = SCB_GET_TARGET_MASK(ahd, scb); tinfo = ahd_fetch_transinfo(ahd, SCB_GET_CHANNEL(ahd, scb), SCB_GET_OUR_ID(scb), SCB_GET_TARGET(ahd, scb), &tstate); if ((ahd->user_discenable & mask) != 0) hscb->control |= DISCENB; if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) scb->flags |= SCB_PACKETIZED; if ((tstate->auto_negotiate & mask) != 0) { scb->flags |= SCB_AUTO_NEGOTIATE; scb->hscb->control |= MK_MESSAGE; } if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH && (dev->flags & AHD_DEV_Q_TAGGED) != 0) { hscb->control |= MSG_ORDERED_TASK; dev->commands_since_idle_or_otag = 0; } else { hscb->control |= MSG_SIMPLE_TASK; } } hscb->cdb_len = cmd->cmd_len; memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); scb->sg_count = 0; ahd_set_residual(scb, 0); ahd_set_sense_residual(scb, 0); if (cmd->use_sg != 0) { void *sg; struct scatterlist *cur_seg; u_int nseg; int dir; cur_seg = (struct scatterlist *)cmd->request_buffer; dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); nseg = pci_map_sg(ahd->dev_softc, cur_seg, cmd->use_sg, dir); scb->platform_data->xfer_len = 0; for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) { bus_addr_t addr; bus_size_t len; addr = sg_dma_address(cur_seg); len = sg_dma_len(cur_seg); scb->platform_data->xfer_len += len; sg = ahd_sg_setup(ahd, scb, sg, addr, len, /*last*/nseg == 1); } } else if (cmd->request_bufflen != 0) { void *sg; bus_addr_t addr; int dir; sg = scb->sg_list; dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); addr = pci_map_single(ahd->dev_softc, cmd->request_buffer, cmd->request_bufflen, dir); scb->platform_data->xfer_len = cmd->request_bufflen; scb->platform_data->buf_busaddr = addr; sg = ahd_sg_setup(ahd, scb, sg, addr, cmd->request_bufflen, /*last*/TRUE); } LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); dev->openings--; dev->active++; dev->commands_issued++; if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) dev->commands_since_idle_or_otag++; scb->flags |= SCB_ACTIVE; ahd_queue_scb(ahd, scb); }}/* * SCSI controller interrupt handler. */voidahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs){ struct ahd_softc *ahd; struct ahd_cmd *acmd; u_long flags; struct ahd_linux_device *next_dev; ahd = (struct ahd_softc *) dev_id; ahd_lock(ahd, &flags); ahd_intr(ahd); acmd = TAILQ_FIRST(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->completeq); next_dev = ahd_linux_next_device_to_run(ahd); ahd_unlock(ahd, &flags); if (next_dev) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tasklet_schedule(&ahd->platform_data->runq_tasklet);#else ahd_runq_tasklet((unsigned long)ahd);#endif } if (acmd != NULL) ahd_linux_run_complete_queue(ahd, acmd);}voidahd_platform_flushwork(struct ahd_softc *ahd){ struct ahd_cmd *acmd; acmd = TAILQ_FIRST(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->completeq); if (acmd != NULL) ahd_linux_run_complete_queue(ahd, acmd);}static struct ahd_linux_target*ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target){ struct ahd_linux_target *targ; u_int target_offset; targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT); if (targ == NULL) return (NULL); memset(targ, 0, sizeof(*targ)); targ->channel = channel; targ->target = target; targ->ahd = ahd; target_offset = target; if (channel != 0) target_offset += 8; ahd->platform_data->targets[target_offset] = targ; return (targ);}static voidahd_linux_free_target(struct ahd_softc *ahd, struct ahd_linux_target *targ){ u_int target_offset; target_offset = targ->target; if (targ->channel != 0) target_offset += 8; ahd->platform_data->targets[target_offset] = NULL; free(targ, M_DEVBUF);}static struct ahd_linux_device*ahd_linux_alloc_device(struct ahd_softc *ahd, struct ahd_linux_target *targ, u_int lun){ struct ahd_linux_device *dev; dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT); if (dev == NULL) return (NULL); memset(dev, 0, sizeof(*dev)); init_timer(&dev->timer); TAILQ_INIT(&dev->busyq); dev->flags = AHD_DEV_UNCONFIGURED; dev->lun = lun; dev->target = targ; /* * 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->refcount++; targ->devices[lun] = dev; return (dev);}static voidahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev){ struct ahd_linux_target *targ; del_timer(&dev->timer); targ = dev->target; targ->devices[dev->lun] = NULL; free(dev, M_DEVBUF); targ->refcount--; if (targ->refcount == 0) ahd_linux_free_target(ahd, targ);}/* * Return a string describing the driver. */const char *ahd_linux_info(struct Scsi_Host *host){ static char buffer[512]; char ahd_info[256]; char *bp; struct ahd_softc *ahd; bp = &buffer[0]; ahd = *(struct ahd_softc **)host->hostdata; memset(bp, 0, sizeof(buffer)); strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev "); strcat(bp, AIC79XX_DRIVER_VERSION); strcat(bp, "\n"); strcat(bp, " <"); strcat(bp, ahd->description); strcat(bp, ">\n"); strcat(bp, " "); ahd_controller_info(ahd, ahd_info); strcat(bp, ahd_info); strcat(bp, "\n"); return (bp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -