📄 mptscsih.c
字号:
* * Returns SUCCESS or FAILED. */intmptscsih_dev_reset(struct scsi_cmnd * SCpnt){ MPT_SCSI_HOST *hd; int retval; /* If we can't locate our host adapter structure, return FAILED status. */ if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: " "Can't locate host! (sc=%p)\n", SCpnt)); return FAILED; } if (hd->resetPending) return FAILED; printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n", hd->ioc->name, SCpnt); scsi_print_command(SCpnt); retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, SCpnt->device->channel, SCpnt->device->id, 0, 0, 5 /* 5 second timeout */); printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n", hd->ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); if (retval == 0) return SUCCESS; if(retval != FAILED ) { hd->tmPending = 0; hd->tmState = TM_STATE_NONE; } return FAILED;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to * * (linux scsi_host_template.eh_bus_reset_handler routine) * * Returns SUCCESS or FAILED. */intmptscsih_bus_reset(struct scsi_cmnd * SCpnt){ MPT_SCSI_HOST *hd; int retval; /* If we can't locate our host adapter structure, return FAILED status. */ if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: " "Can't locate host! (sc=%p)\n", SCpnt ) ); return FAILED; } printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n", hd->ioc->name, SCpnt); scsi_print_command(SCpnt); if (hd->timeouts < -1) hd->timeouts++; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */); printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n", hd->ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); if (retval == 0) return SUCCESS; if(retval != FAILED ) { hd->tmPending = 0; hd->tmState = TM_STATE_NONE; } return FAILED;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_host_reset - Perform a SCSI host adapter RESET! * new_eh variant * @SCpnt: Pointer to scsi_cmnd structure, IO which reset is due to * * (linux scsi_host_template.eh_host_reset_handler routine) * * Returns SUCCESS or FAILED. */intmptscsih_host_reset(struct scsi_cmnd *SCpnt){ MPT_SCSI_HOST * hd; int status = SUCCESS; /* If we can't locate the host to reset, then we failed. */ if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: " "Can't locate host! (sc=%p)\n", SCpnt ) ); return FAILED; } printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n", hd->ioc->name, SCpnt); /* If our attempts to reset the host failed, then return a failed * status. The host will be taken off line by the SCSI mid-layer. */ if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){ status = FAILED; } else { /* Make sure TM pending is cleared and TM state is set to * NONE. */ hd->tmPending = 0; hd->tmState = TM_STATE_NONE; } dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: " "Status = %s\n", (status == SUCCESS) ? "SUCCESS" : "FAILED" ) ); return status;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_tm_pending_wait - wait for pending task management request to * complete. * @hd: Pointer to MPT host structure. * * Returns {SUCCESS,FAILED}. */static intmptscsih_tm_pending_wait(MPT_SCSI_HOST * hd){ unsigned long flags; int loop_count = 4 * 10; /* Wait 10 seconds */ int status = FAILED; do { spin_lock_irqsave(&hd->ioc->FreeQlock, flags); if (hd->tmState == TM_STATE_NONE) { hd->tmState = TM_STATE_IN_PROGRESS; hd->tmPending = 1; spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); status = SUCCESS; break; } spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); msleep(250); } while (--loop_count); return status;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_tm_wait_for_completion - wait for completion of TM task * @hd: Pointer to MPT host structure. * * Returns {SUCCESS,FAILED}. */static intmptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ){ unsigned long flags; int loop_count = 4 * timeout; int status = FAILED; do { spin_lock_irqsave(&hd->ioc->FreeQlock, flags); if(hd->tmPending == 0) { status = SUCCESS; spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); break; } spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); msleep_interruptible(250); } while (--loop_count); return status;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver * @ioc: Pointer to MPT_ADAPTER structure * @mf: Pointer to SCSI task mgmt request frame * @mr: Pointer to SCSI task mgmt reply frame * * This routine is called from mptbase.c::mpt_interrupt() at the completion * of any SCSI task management request. * This routine is registered with the MPT (base) driver at driver * load/init time via the mpt_register() API call. * * Returns 1 indicating alloc'd request frame ptr should be freed. */intmptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr){ SCSITaskMgmtReply_t *pScsiTmReply; SCSITaskMgmt_t *pScsiTmReq; MPT_SCSI_HOST *hd; unsigned long flags; u16 iocstatus; u8 tmType; dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n", ioc->name, mf, mr)); if (ioc->sh) { /* Depending on the thread, a timer is activated for * the TM request. Delete this timer on completion of TM. * Decrement count of outstanding TM requests. */ hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; } else { dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name)); return 1; } if (mr == NULL) { dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf)); return 1; } else { pScsiTmReply = (SCSITaskMgmtReply_t*)mr; pScsiTmReq = (SCSITaskMgmt_t*)mf; /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */ tmType = pScsiTmReq->TaskType; dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n", ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount))); DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply); iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n", ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo))); /* Error? (anything non-zero?) */ if (iocstatus) { /* clear flags and continue. */ if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) hd->abortSCpnt = NULL; /* If an internal command is present * or the TM failed - reload the FW. * FC FW may respond FAILED to an ABORT */ if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { if ((hd->cmdPtr) || (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) { if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) { printk((KERN_WARNING " Firmware Reload FAILED!!\n")); } } } } else { dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name)); hd->abortSCpnt = NULL; } } spin_lock_irqsave(&ioc->FreeQlock, flags); hd->tmPending = 0; spin_unlock_irqrestore(&ioc->FreeQlock, flags); hd->tmState = TM_STATE_NONE; return 1;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * This is anyones guess quite frankly. */intmptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int geom[]){ int heads; int sectors; sector_t cylinders; ulong dummy; heads = 64; sectors = 32; dummy = heads * sectors; cylinders = capacity; sector_div(cylinders,dummy); /* * Handle extended translation size for logical drives * > 1Gb */ if ((ulong)capacity >= 0x200000) { heads = 255; sectors = 63; dummy = heads * sectors; cylinders = capacity; sector_div(cylinders,dummy); } /* return result */ geom[0] = heads; geom[1] = sectors; geom[2] = cylinders; dprintk((KERN_NOTICE ": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n", sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors)); return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * OS entry point to allow host driver to alloc memory * for each scsi device. Called once per device the bus scan. * Return non-zero if allocation fails. * Init memory once per id (not LUN). */intmptscsih_slave_alloc(struct scsi_device *device){ struct Scsi_Host *host = device->host; MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; VirtDevice *vdev; uint target = device->id; if (hd == NULL) return -ENODEV; if ((vdev = hd->Targets[target]) != NULL) goto out; vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL); if (!vdev) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", hd->ioc->name, sizeof(VirtDevice)); return -ENOMEM; } memset(vdev, 0, sizeof(VirtDevice)); vdev->tflags = MPT_TARGET_FLAGS_Q_YES; vdev->ioc_id = hd->ioc->id; vdev->target_id = device->id; vdev->bus_id = device->channel; vdev->raidVolume = 0; hd->Targets[device->id] = vdev; if (hd->ioc->bus_type == SCSI) { if (hd->ioc->raid_data.isRaid & (1 << device->id)) { vdev->raidVolume = 1; ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", device->id)); } } else { vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; } out: vdev->num_luns++; device->hostdata = vdev; return 0;}/* * OS entry point to allow for host driver to free allocated memory * Called if no device present or device being unloaded */voidmptscsih_slave_destroy(struct scsi_device *device){ struct Scsi_Host *host = device->host; MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; VirtDevice *vdev; uint target = device->id; uint lun = device->lun; if (hd == NULL) return; mptscsih_search_running_cmds(hd, target, lun); vdev = hd->Targets[target]; vdev->luns[0] &= ~(1 << lun); if (--vdev->num_luns) return; kfree(hd->Targets[target]); hd->Targets[target] = NULL; if (hd->ioc->bus_type == SCSI) { if (mptscsih_is_phys_disk(hd->ioc, target)) { hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3; } else { hd->ioc->spi_data.dvStatus[target] = MPT_SCSICFG_NEGOTIATE; if (!hd->negoNvram) { hd->ioc->spi_data.dvStatus[target] |= MPT_SCSICFG_DV_NOT_DONE; } } }}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mptscsih_change_queue_depth - This function will set a devices queue depth * @sdev: per scsi_device pointer * @qdepth: requested queue depth * * Adding support for new 'change_queue_depth' api.*/intmptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth){ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; VirtDevice *pTarget; int max_depth; int tagged; if (hd == NULL) return 0; if (!(pTarget = hd->Targets[sdev->id])) return 0; if (hd->ioc->bus_type == SCSI) { if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) max_depth = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -