📄 mptscsih.c
字号:
} 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;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/static voidmptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code){ char *desc; switch (response_code) { case MPI_SCSITASKMGMT_RSP_TM_COMPLETE: desc = "The task completed."; break; case MPI_SCSITASKMGMT_RSP_INVALID_FRAME: desc = "The IOC received an invalid frame status."; break; case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: desc = "The task type is not supported."; break; case MPI_SCSITASKMGMT_RSP_TM_FAILED: desc = "The requested task failed."; break; case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED: desc = "The task completed successfully."; break; case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN: desc = "The LUN request is invalid."; break; case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: desc = "The task is in the IOC queue and has not been sent to target."; break; default: desc = "unknown"; break; } printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n", ioc->name, response_code, desc);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** * 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; if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && pScsiTmReply->ResponseCode) mptscsih_taskmgmt_response_code(ioc, pScsiTmReply->ResponseCode); 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;}/* Search IOC page 3 to determine if this is hidden physical disk * */intmptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id){ int i; if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3) return 0; for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) return 1; } return 0;}EXPORT_SYMBOL(mptscsih_is_phys_disk);intmptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid){ int i; if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3) return -ENXIO; for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) { if (physdiskid == hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum; } return -ENXIO;}EXPORT_SYMBOL(mptscsih_raid_id_to_num);/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * OS entry point to allow host driver to alloc memory * for each scsi target. Called once per device the bus scan. * Return non-zero if allocation fails. */intmptscsih_target_alloc(struct scsi_target *starget){ VirtTarget *vtarget; vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); if (!vtarget) return -ENOMEM; starget->hostdata = vtarget; vtarget->starget = starget; 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. */intmptscsih_slave_alloc(struct scsi_device *sdev){ struct Scsi_Host *host = sdev->host; MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; VirtTarget *vtarget; VirtDevice *vdev; struct scsi_target *starget; vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); if (!vdev) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", hd->ioc->name, sizeof(VirtDevice)); return -ENOMEM; } vdev->lun = sdev->lun; sdev->hostdata = vdev; starget = scsi_target(sdev); vtarget = starget->hostdata; vdev->vtarget = vtarget; if (vtarget->num_luns == 0) { hd->Targets[sdev->id] = vtarget; vtarget->ioc_id = hd->ioc->id; vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; vtarget->target_id = sdev->id; vtarget->bus_id = sdev->channel; if (hd->ioc->bus_type == SPI && sdev->channel == 0 && hd->ioc->raid_data.isRaid & (1 << sdev->id)) { vtarget->raidVolume = 1; ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", sdev->id)); } } vtarget->num_luns++; return 0;}/* * OS entry point to allow for host driver to free allocated memory * Called if no device present or device being unloaded */voidmptscsih_target_destroy(struct scsi_target *starget){ if (starget->hostdata) kfree(starget->hostdata); starget->hostdata = NULL;}/* * 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 *sdev){ struct Scsi_Host *host = sdev->host; MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; VirtTarget *vtarget; VirtDevice *vdevice; struct scsi_target *starget; starget = scsi_target(sdev); vtarget = starget->hostdata; vdevice = sdev->hostdata; mptscsih_search_running_cmds(hd, vdevice); vtarget->luns[0] &= ~(1 << vdevice->lun); vtarget->num_luns--; if (vtarget->num_luns == 0) { hd->Targets[sdev->id] = NULL; } mptscsih_synchronize_cache(hd, vdevice); kfree(vdevice); sdev->hostdata = NULL;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * 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; VirtTarget *vtarget; struct scsi_target *starget; int max_depth; int tagged; starget = scsi_target(sdev); vtarget = starget->hostdata; if (hd->ioc->bus_type == SPI) { if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -