diff options
author | Jayamohan Kallickal <jayamohan.kallickal@emulex.com> | 2014-01-29 11:16:39 +0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2014-03-15 21:19:10 +0400 |
commit | 1957aa7f62462dc888dfc9a94373b27f936f2e10 (patch) | |
tree | dc059ae34b917d20a1525d8304085f46635e6a3a /drivers/scsi/be2iscsi/be_cmds.c | |
parent | 8e616a5ee6e389f855a9fa0ab57194b4b049d9c8 (diff) | |
download | linux-1957aa7f62462dc888dfc9a94373b27f936f2e10.tar.xz |
[SCSI] be2iscsi: Fix handling timed out MBX completion from FW
When an MBX command timeout happens,the resources associated with
the MBX command were freed. If FW were to give the response to
host after the timeout value set by driver then driver crashes as the MBX Cmd
resources were already freed.
This patch fixes this issue by maintaing a state flag for each of
the MBX command posted/timedout/completed.
Signed-off-by: John Soni Jose <sony.john-n@emulex.com>
Signed-off-by: Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/be2iscsi/be_cmds.c')
-rw-r--r-- | drivers/scsi/be2iscsi/be_cmds.c | 90 |
1 files changed, 68 insertions, 22 deletions
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 3338391b64de..b14949a71eda 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -138,7 +138,7 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba) * @phba: Driver private structure * @tag: Tag for the MBX Command * @wrb: the WRB used for the MBX Command - * @cmd_hdr: IOCTL Hdr for the MBX Cmd + * @mbx_cmd_mem: ptr to memory allocated for MBX Cmd * * Waits for MBX completion with the passed TAG. * @@ -148,21 +148,26 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba) **/ int beiscsi_mccq_compl(struct beiscsi_hba *phba, uint32_t tag, struct be_mcc_wrb **wrb, - void *cmd_hdr) + struct be_dma_mem *mbx_cmd_mem) { int rc = 0; uint32_t mcc_tag_response; uint16_t status = 0, addl_status = 0, wrb_num = 0; struct be_mcc_wrb *temp_wrb; - struct be_cmd_req_hdr *ioctl_hdr; - struct be_cmd_resp_hdr *ioctl_resp_hdr; + struct be_cmd_req_hdr *mbx_hdr; + struct be_cmd_resp_hdr *mbx_resp_hdr; struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; if (beiscsi_error(phba)) { free_mcc_tag(&phba->ctrl, tag); - return -EIO; + return -EPERM; } + /* Set MBX Tag state to Active */ + spin_lock(&phba->ctrl.mbox_lock); + phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_RUNNING; + spin_unlock(&phba->ctrl.mbox_lock); + /* wait for the mccq completion */ rc = wait_event_interruptible_timeout( phba->ctrl.mcc_wait[tag], @@ -171,56 +176,71 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba, BEISCSI_HOST_MBX_TIMEOUT)); if (rc <= 0) { + struct be_dma_mem *tag_mem; + /* Set MBX Tag state to timeout */ + spin_lock(&phba->ctrl.mbox_lock); + phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_TIMEOUT; + spin_unlock(&phba->ctrl.mbox_lock); + + /* Store resource addr to be freed later */ + tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state; + if (mbx_cmd_mem) { + tag_mem->size = mbx_cmd_mem->size; + tag_mem->va = mbx_cmd_mem->va; + tag_mem->dma = mbx_cmd_mem->dma; + } else + tag_mem->size = 0; + beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT | BEISCSI_LOG_EH | BEISCSI_LOG_CONFIG, "BC_%d : MBX Cmd Completion timed out\n"); - rc = -EBUSY; - - /* decrement the mccq used count */ - atomic_dec(&phba->ctrl.mcc_obj.q.used); - - goto release_mcc_tag; - } else + return -EBUSY; + } else { rc = 0; + /* Set MBX Tag state to completed */ + spin_lock(&phba->ctrl.mbox_lock); + phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED; + spin_unlock(&phba->ctrl.mbox_lock); + } mcc_tag_response = phba->ctrl.mcc_numtag[tag]; status = (mcc_tag_response & CQE_STATUS_MASK); addl_status = ((mcc_tag_response & CQE_STATUS_ADDL_MASK) >> CQE_STATUS_ADDL_SHIFT); - if (cmd_hdr) { - ioctl_hdr = (struct be_cmd_req_hdr *)cmd_hdr; + if (mbx_cmd_mem) { + mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va; } else { wrb_num = (mcc_tag_response & CQE_STATUS_WRB_MASK) >> CQE_STATUS_WRB_SHIFT; temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num); - ioctl_hdr = embedded_payload(temp_wrb); + mbx_hdr = embedded_payload(temp_wrb); if (wrb) *wrb = temp_wrb; } if (status || addl_status) { - beiscsi_log(phba, KERN_ERR, + beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT | BEISCSI_LOG_EH | BEISCSI_LOG_CONFIG, "BC_%d : MBX Cmd Failed for " "Subsys : %d Opcode : %d with " "Status : %d and Extd_Status : %d\n", - ioctl_hdr->subsystem, - ioctl_hdr->opcode, + mbx_hdr->subsystem, + mbx_hdr->opcode, status, addl_status); if (status == MCC_STATUS_INSUFFICIENT_BUFFER) { - ioctl_resp_hdr = (struct be_cmd_resp_hdr *) ioctl_hdr; + mbx_resp_hdr = (struct be_cmd_resp_hdr *) mbx_hdr; beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_INIT | BEISCSI_LOG_EH | BEISCSI_LOG_CONFIG, "BC_%d : Insufficent Buffer Error " "Resp_Len : %d Actual_Resp_Len : %d\n", - ioctl_resp_hdr->response_length, - ioctl_resp_hdr->actual_resp_len); + mbx_resp_hdr->response_length, + mbx_resp_hdr->actual_resp_len); rc = -EAGAIN; goto release_mcc_tag; @@ -319,6 +339,7 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl, int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, struct be_mcc_compl *compl) { + struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev); u16 compl_status, extd_status; unsigned short tag; @@ -338,7 +359,32 @@ int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000); ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8; ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF); - wake_up_interruptible(&ctrl->mcc_wait[tag]); + + if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_RUNNING) { + wake_up_interruptible(&ctrl->mcc_wait[tag]); + } else if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_TIMEOUT) { + struct be_dma_mem *tag_mem; + tag_mem = &ctrl->ptag_state[tag].tag_mem_state; + + beiscsi_log(phba, KERN_WARNING, + BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT | + BEISCSI_LOG_CONFIG, + "BC_%d : MBX Completion for timeout Command " + "from FW\n"); + /* Check if memory needs to be freed */ + if (tag_mem->size) + pci_free_consistent(ctrl->pdev, tag_mem->size, + tag_mem->va, tag_mem->dma); + + /* Change tag state */ + spin_lock(&phba->ctrl.mbox_lock); + ctrl->ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED; + spin_unlock(&phba->ctrl.mbox_lock); + + /* Free MCC Tag */ + free_mcc_tag(ctrl, tag); + } + return 0; } |