aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/be2iscsi/be_cmds.c
diff options
context:
space:
mode:
authorJayamohan Kallickal <jayamohan.kallickal@emulex.com>2014-01-29 02:16:39 -0500
committerJames Bottomley <JBottomley@Parallels.com>2014-03-15 13:19:10 -0400
commit1957aa7f62462dc888dfc9a94373b27f936f2e10 (patch)
treedc059ae34b917d20a1525d8304085f46635e6a3a /drivers/scsi/be2iscsi/be_cmds.c
parent8e616a5ee6e389f855a9fa0ab57194b4b049d9c8 (diff)
[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.c90
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)
138 * @phba: Driver private structure 138 * @phba: Driver private structure
139 * @tag: Tag for the MBX Command 139 * @tag: Tag for the MBX Command
140 * @wrb: the WRB used for the MBX Command 140 * @wrb: the WRB used for the MBX Command
141 * @cmd_hdr: IOCTL Hdr for the MBX Cmd 141 * @mbx_cmd_mem: ptr to memory allocated for MBX Cmd
142 * 142 *
143 * Waits for MBX completion with the passed TAG. 143 * Waits for MBX completion with the passed TAG.
144 * 144 *
@@ -148,21 +148,26 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
148 **/ 148 **/
149int beiscsi_mccq_compl(struct beiscsi_hba *phba, 149int beiscsi_mccq_compl(struct beiscsi_hba *phba,
150 uint32_t tag, struct be_mcc_wrb **wrb, 150 uint32_t tag, struct be_mcc_wrb **wrb,
151 void *cmd_hdr) 151 struct be_dma_mem *mbx_cmd_mem)
152{ 152{
153 int rc = 0; 153 int rc = 0;
154 uint32_t mcc_tag_response; 154 uint32_t mcc_tag_response;
155 uint16_t status = 0, addl_status = 0, wrb_num = 0; 155 uint16_t status = 0, addl_status = 0, wrb_num = 0;
156 struct be_mcc_wrb *temp_wrb; 156 struct be_mcc_wrb *temp_wrb;
157 struct be_cmd_req_hdr *ioctl_hdr; 157 struct be_cmd_req_hdr *mbx_hdr;
158 struct be_cmd_resp_hdr *ioctl_resp_hdr; 158 struct be_cmd_resp_hdr *mbx_resp_hdr;
159 struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; 159 struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
160 160
161 if (beiscsi_error(phba)) { 161 if (beiscsi_error(phba)) {
162 free_mcc_tag(&phba->ctrl, tag); 162 free_mcc_tag(&phba->ctrl, tag);
163 return -EIO; 163 return -EPERM;
164 } 164 }
165 165
166 /* Set MBX Tag state to Active */
167 spin_lock(&phba->ctrl.mbox_lock);
168 phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_RUNNING;
169 spin_unlock(&phba->ctrl.mbox_lock);
170
166 /* wait for the mccq completion */ 171 /* wait for the mccq completion */
167 rc = wait_event_interruptible_timeout( 172 rc = wait_event_interruptible_timeout(
168 phba->ctrl.mcc_wait[tag], 173 phba->ctrl.mcc_wait[tag],
@@ -171,56 +176,71 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
171 BEISCSI_HOST_MBX_TIMEOUT)); 176 BEISCSI_HOST_MBX_TIMEOUT));
172 177
173 if (rc <= 0) { 178 if (rc <= 0) {
179 struct be_dma_mem *tag_mem;
180 /* Set MBX Tag state to timeout */
181 spin_lock(&phba->ctrl.mbox_lock);
182 phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_TIMEOUT;
183 spin_unlock(&phba->ctrl.mbox_lock);
184
185 /* Store resource addr to be freed later */
186 tag_mem = &phba->ctrl.ptag_state[tag].tag_mem_state;
187 if (mbx_cmd_mem) {
188 tag_mem->size = mbx_cmd_mem->size;
189 tag_mem->va = mbx_cmd_mem->va;
190 tag_mem->dma = mbx_cmd_mem->dma;
191 } else
192 tag_mem->size = 0;
193
174 beiscsi_log(phba, KERN_ERR, 194 beiscsi_log(phba, KERN_ERR,
175 BEISCSI_LOG_INIT | BEISCSI_LOG_EH | 195 BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
176 BEISCSI_LOG_CONFIG, 196 BEISCSI_LOG_CONFIG,
177 "BC_%d : MBX Cmd Completion timed out\n"); 197 "BC_%d : MBX Cmd Completion timed out\n");
178 rc = -EBUSY; 198 return -EBUSY;
179 199 } else {
180 /* decrement the mccq used count */
181 atomic_dec(&phba->ctrl.mcc_obj.q.used);
182
183 goto release_mcc_tag;
184 } else
185 rc = 0; 200 rc = 0;
201 /* Set MBX Tag state to completed */
202 spin_lock(&phba->ctrl.mbox_lock);
203 phba->ctrl.ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
204 spin_unlock(&phba->ctrl.mbox_lock);
205 }
186 206
187 mcc_tag_response = phba->ctrl.mcc_numtag[tag]; 207 mcc_tag_response = phba->ctrl.mcc_numtag[tag];
188 status = (mcc_tag_response & CQE_STATUS_MASK); 208 status = (mcc_tag_response & CQE_STATUS_MASK);
189 addl_status = ((mcc_tag_response & CQE_STATUS_ADDL_MASK) >> 209 addl_status = ((mcc_tag_response & CQE_STATUS_ADDL_MASK) >>
190 CQE_STATUS_ADDL_SHIFT); 210 CQE_STATUS_ADDL_SHIFT);
191 211
192 if (cmd_hdr) { 212 if (mbx_cmd_mem) {
193 ioctl_hdr = (struct be_cmd_req_hdr *)cmd_hdr; 213 mbx_hdr = (struct be_cmd_req_hdr *)mbx_cmd_mem->va;
194 } else { 214 } else {
195 wrb_num = (mcc_tag_response & CQE_STATUS_WRB_MASK) >> 215 wrb_num = (mcc_tag_response & CQE_STATUS_WRB_MASK) >>
196 CQE_STATUS_WRB_SHIFT; 216 CQE_STATUS_WRB_SHIFT;
197 temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num); 217 temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num);
198 ioctl_hdr = embedded_payload(temp_wrb); 218 mbx_hdr = embedded_payload(temp_wrb);
199 219
200 if (wrb) 220 if (wrb)
201 *wrb = temp_wrb; 221 *wrb = temp_wrb;
202 } 222 }
203 223
204 if (status || addl_status) { 224 if (status || addl_status) {
205 beiscsi_log(phba, KERN_ERR, 225 beiscsi_log(phba, KERN_WARNING,
206 BEISCSI_LOG_INIT | BEISCSI_LOG_EH | 226 BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
207 BEISCSI_LOG_CONFIG, 227 BEISCSI_LOG_CONFIG,
208 "BC_%d : MBX Cmd Failed for " 228 "BC_%d : MBX Cmd Failed for "
209 "Subsys : %d Opcode : %d with " 229 "Subsys : %d Opcode : %d with "
210 "Status : %d and Extd_Status : %d\n", 230 "Status : %d and Extd_Status : %d\n",
211 ioctl_hdr->subsystem, 231 mbx_hdr->subsystem,
212 ioctl_hdr->opcode, 232 mbx_hdr->opcode,
213 status, addl_status); 233 status, addl_status);
214 234
215 if (status == MCC_STATUS_INSUFFICIENT_BUFFER) { 235 if (status == MCC_STATUS_INSUFFICIENT_BUFFER) {
216 ioctl_resp_hdr = (struct be_cmd_resp_hdr *) ioctl_hdr; 236 mbx_resp_hdr = (struct be_cmd_resp_hdr *) mbx_hdr;
217 beiscsi_log(phba, KERN_WARNING, 237 beiscsi_log(phba, KERN_WARNING,
218 BEISCSI_LOG_INIT | BEISCSI_LOG_EH | 238 BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
219 BEISCSI_LOG_CONFIG, 239 BEISCSI_LOG_CONFIG,
220 "BC_%d : Insufficent Buffer Error " 240 "BC_%d : Insufficent Buffer Error "
221 "Resp_Len : %d Actual_Resp_Len : %d\n", 241 "Resp_Len : %d Actual_Resp_Len : %d\n",
222 ioctl_resp_hdr->response_length, 242 mbx_resp_hdr->response_length,
223 ioctl_resp_hdr->actual_resp_len); 243 mbx_resp_hdr->actual_resp_len);
224 244
225 rc = -EAGAIN; 245 rc = -EAGAIN;
226 goto release_mcc_tag; 246 goto release_mcc_tag;
@@ -319,6 +339,7 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
319int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, 339int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
320 struct be_mcc_compl *compl) 340 struct be_mcc_compl *compl)
321{ 341{
342 struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
322 u16 compl_status, extd_status; 343 u16 compl_status, extd_status;
323 unsigned short tag; 344 unsigned short tag;
324 345
@@ -338,7 +359,32 @@ int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl,
338 ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000); 359 ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000);
339 ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8; 360 ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8;
340 ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF); 361 ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF);
341 wake_up_interruptible(&ctrl->mcc_wait[tag]); 362
363 if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_RUNNING) {
364 wake_up_interruptible(&ctrl->mcc_wait[tag]);
365 } else if (ctrl->ptag_state[tag].tag_state == MCC_TAG_STATE_TIMEOUT) {
366 struct be_dma_mem *tag_mem;
367 tag_mem = &ctrl->ptag_state[tag].tag_mem_state;
368
369 beiscsi_log(phba, KERN_WARNING,
370 BEISCSI_LOG_MBOX | BEISCSI_LOG_INIT |
371 BEISCSI_LOG_CONFIG,
372 "BC_%d : MBX Completion for timeout Command "
373 "from FW\n");
374 /* Check if memory needs to be freed */
375 if (tag_mem->size)
376 pci_free_consistent(ctrl->pdev, tag_mem->size,
377 tag_mem->va, tag_mem->dma);
378
379 /* Change tag state */
380 spin_lock(&phba->ctrl.mbox_lock);
381 ctrl->ptag_state[tag].tag_state = MCC_TAG_STATE_COMPLETED;
382 spin_unlock(&phba->ctrl.mbox_lock);
383
384 /* Free MCC Tag */
385 free_mcc_tag(ctrl, tag);
386 }
387
342 return 0; 388 return 0;
343} 389}
344 390