summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJayamohan Kallickal <jayamohan.kallickal@emulex.com>2014-01-29 08:16:39 +0100
committerJames Bottomley <JBottomley@Parallels.com>2014-03-15 18:19:10 +0100
commit1957aa7f62462dc888dfc9a94373b27f936f2e10 (patch)
treedc059ae34b917d20a1525d8304085f46635e6a3a
parent[SCSI] hpsa: Add support for a few HP Storage controllers (diff)
downloadlinux-1957aa7f62462dc888dfc9a94373b27f936f2e10.tar.xz
linux-1957aa7f62462dc888dfc9a94373b27f936f2e10.zip
[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>
-rw-r--r--drivers/scsi/be2iscsi/be.h10
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c90
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h3
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c10
-rw-r--r--drivers/scsi/be2iscsi/be_main.c27
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c22
6 files changed, 117 insertions, 45 deletions
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 2e28f6c419fe..23c73fe42648 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -98,6 +98,14 @@ struct be_mcc_obj {
struct be_queue_info cq;
};
+struct beiscsi_mcc_tag_state {
+#define MCC_TAG_STATE_COMPLETED 0x00
+#define MCC_TAG_STATE_RUNNING 0x01
+#define MCC_TAG_STATE_TIMEOUT 0x02
+ uint8_t tag_state;
+ struct be_dma_mem tag_mem_state;
+};
+
struct be_ctrl_info {
u8 __iomem *csr;
u8 __iomem *db; /* Door Bell */
@@ -122,6 +130,8 @@ struct be_ctrl_info {
unsigned short mcc_alloc_index;
unsigned short mcc_free_index;
unsigned int mcc_tag_available;
+
+ struct beiscsi_mcc_tag_state ptag_state[MAX_MCC_CMD + 1];
};
#include "be_cmds.h"
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;
}
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 627ebbe0172c..770b6c8bcad8 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -709,7 +709,8 @@ unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba);
void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
int beiscsi_mccq_compl(struct beiscsi_hba *phba,
- uint32_t tag, struct be_mcc_wrb **wrb, void *cmd_va);
+ uint32_t tag, struct be_mcc_wrb **wrb,
+ struct be_dma_mem *mbx_cmd_mem);
/*ISCSI Functuions */
int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
int be_cmd_fw_uninit(struct be_ctrl_info *ctrl);
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 889066d9d6fb..bdd0f05a3342 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -1153,16 +1153,18 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
return -EAGAIN;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
+ ret = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
if (ret) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BS_%d : mgmt_open_connection Failed");
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ if (ret != -EBUSY)
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
beiscsi_free_ep(beiscsi_ep);
- return -EBUSY;
+ return ret;
}
ptcpcnct_out = (struct tcp_connect_and_offload_out *)nonemb_cmd.va;
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 5642a9b250c2..c8f90cef728d 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -228,6 +228,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
struct invalidate_command_table *inv_tbl;
struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, num_invalidate;
+ int rc;
cls_session = starget_to_session(scsi_target(sc->device));
session = cls_session->dd_data;
@@ -285,9 +286,11 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
return FAILED;
}
- beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ if (rc != -EBUSY)
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
return iscsi_eh_abort(sc);
}
@@ -303,6 +306,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
struct invalidate_command_table *inv_tbl;
struct be_dma_mem nonemb_cmd;
unsigned int cid, tag, i, num_invalidate;
+ int rc;
/* invalidate iocbs */
cls_session = starget_to_session(scsi_target(sc->device));
@@ -363,9 +367,10 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
return FAILED;
}
- beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
- pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
- nonemb_cmd.va, nonemb_cmd.dma);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
+ if (rc != -EBUSY)
+ pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
return iscsi_eh_device_reset(sc);
}
@@ -4360,12 +4365,16 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
goto boot_freemem;
}
- ret = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
+ ret = beiscsi_mccq_compl(phba, tag, NULL, &nonemb_cmd);
if (ret) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
"BM_%d : beiscsi_get_session_info Failed");
- goto boot_freemem;
+
+ if (ret != -EBUSY)
+ goto boot_freemem;
+ else
+ return ret;
}
session_resp = nonemb_cmd.va ;
@@ -5594,6 +5603,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
phba->ctrl.mcc_tag[i] = i + 1;
phba->ctrl.mcc_numtag[i + 1] = 0;
phba->ctrl.mcc_tag_available++;
+ memset(&phba->ctrl.ptag_state[i].tag_mem_state, 0,
+ sizeof(struct beiscsi_mcc_tag_state));
}
phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0;
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index b2fcac78feaa..088bdf752cfa 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -828,22 +828,25 @@ static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
be_mcc_notify(phba);
spin_unlock(&ctrl->mbox_lock);
- rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd->va);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd);
+
+ if (resp_buf)
+ memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
+
if (rc) {
- /* Check if the IOCTL needs to be re-issued */
+ /* Check if the MBX Cmd needs to be re-issued */
if (rc == -EAGAIN)
return rc;
- beiscsi_log(phba, KERN_ERR,
+ beiscsi_log(phba, KERN_WARNING,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : mgmt_exec_nonemb_cmd Failed status\n");
- goto free_cmd;
+ if (rc != -EBUSY)
+ goto free_cmd;
+ else
+ return rc;
}
-
- if (resp_buf)
- memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
-
free_cmd:
pci_free_consistent(ctrl->pdev, nonemb_cmd->size,
nonemb_cmd->va, nonemb_cmd->dma);
@@ -1348,7 +1351,6 @@ int mgmt_set_vlan(struct beiscsi_hba *phba,
{
int rc;
unsigned int tag;
- struct be_mcc_wrb *wrb = NULL;
tag = be_cmd_set_vlan(phba, vlan_tag);
if (!tag) {
@@ -1358,7 +1360,7 @@ int mgmt_set_vlan(struct beiscsi_hba *phba,
return -EBUSY;
}
- rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+ rc = beiscsi_mccq_compl(phba, tag, NULL, NULL);
if (rc) {
beiscsi_log(phba, KERN_ERR,
(BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),