diff options
author | James Smart <James.Smart@Emulex.Com> | 2009-11-18 15:40:49 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-04 13:01:52 -0500 |
commit | 1c6f4ef5d6be7ef4cbe92a86286217971f52e2cd (patch) | |
tree | 6415ea806d637bae7e3894f509f08a3196147337 /drivers/scsi/lpfc | |
parent | 891478a2442d8d0077651bc8316afaec8d85dd4d (diff) |
[SCSI] lpfc 8.3.6 : Fix critical errors
Fix errors relating to crashes and hangs.
- Fix crash due to list corruption while unloading driver.
- Fix panic during pci-hot-plug testing.
- Fix panic when unmapping luns.
- Fixed total_scsi_bufs counting could cause exhausted memory.
- Fixed locking issue causing hang.
- Fixed the call from lpfc_new_scsi_buf_s3 to use lpfc_release_scsi_buf_s3.
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/lpfc')
-rwxr-xr-x | drivers/scsi/lpfc/lpfc_hbadisc.c | 14 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 33 |
3 files changed, 38 insertions, 13 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 4d7d8846b4da..3b9424427652 100755 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -1018,13 +1018,12 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) | |||
1018 | mempool_free(mboxq, phba->mbox_mem_pool); | 1018 | mempool_free(mboxq, phba->mbox_mem_pool); |
1019 | return; | 1019 | return; |
1020 | } | 1020 | } |
1021 | spin_lock_irqsave(&phba->hbalock, flags); | ||
1021 | phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE); | 1022 | phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE); |
1022 | phba->hba_flag &= ~FCF_DISC_INPROGRESS; | 1023 | phba->hba_flag &= ~FCF_DISC_INPROGRESS; |
1023 | if (vport->port_state != LPFC_FLOGI) { | 1024 | spin_unlock_irqrestore(&phba->hbalock, flags); |
1024 | spin_lock_irqsave(&phba->hbalock, flags); | 1025 | if (vport->port_state != LPFC_FLOGI) |
1025 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
1026 | lpfc_initial_flogi(vport); | 1026 | lpfc_initial_flogi(vport); |
1027 | } | ||
1028 | 1027 | ||
1029 | mempool_free(mboxq, phba->mbox_mem_pool); | 1028 | mempool_free(mboxq, phba->mbox_mem_pool); |
1030 | return; | 1029 | return; |
@@ -1460,12 +1459,15 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) | |||
1460 | 1459 | ||
1461 | if (phba->link_state >= LPFC_LINK_UP) | 1460 | if (phba->link_state >= LPFC_LINK_UP) |
1462 | lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST); | 1461 | lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST); |
1463 | else | 1462 | else { |
1464 | /* | 1463 | /* |
1465 | * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS | 1464 | * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS |
1466 | * flag | 1465 | * flag |
1467 | */ | 1466 | */ |
1467 | spin_lock_irq(&phba->hbalock); | ||
1468 | phba->hba_flag &= ~FCF_DISC_INPROGRESS; | 1468 | phba->hba_flag &= ~FCF_DISC_INPROGRESS; |
1469 | spin_unlock_irq(&phba->hbalock); | ||
1470 | } | ||
1469 | 1471 | ||
1470 | if (unreg_fcf) { | 1472 | if (unreg_fcf) { |
1471 | spin_lock_irq(&phba->hbalock); | 1473 | spin_lock_irq(&phba->hbalock); |
@@ -2264,7 +2266,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
2264 | * This shost reference might have been taken at the beginning of | 2266 | * This shost reference might have been taken at the beginning of |
2265 | * lpfc_vport_delete() | 2267 | * lpfc_vport_delete() |
2266 | */ | 2268 | */ |
2267 | if (vport->load_flag & FC_UNLOADING) | 2269 | if ((vport->load_flag & FC_UNLOADING) && (vport != phba->pport)) |
2268 | scsi_host_put(shost); | 2270 | scsi_host_put(shost); |
2269 | } | 2271 | } |
2270 | 2272 | ||
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 93679f30a5af..5f5b2283d58c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -2320,6 +2320,7 @@ lpfc_scsi_free(struct lpfc_hba *phba) | |||
2320 | 2320 | ||
2321 | spin_lock_irq(&phba->hbalock); | 2321 | spin_lock_irq(&phba->hbalock); |
2322 | /* Release all the lpfc_scsi_bufs maintained by this host. */ | 2322 | /* Release all the lpfc_scsi_bufs maintained by this host. */ |
2323 | spin_lock(&phba->scsi_buf_list_lock); | ||
2323 | list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { | 2324 | list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { |
2324 | list_del(&sb->list); | 2325 | list_del(&sb->list); |
2325 | pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data, | 2326 | pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data, |
@@ -2327,6 +2328,7 @@ lpfc_scsi_free(struct lpfc_hba *phba) | |||
2327 | kfree(sb); | 2328 | kfree(sb); |
2328 | phba->total_scsi_bufs--; | 2329 | phba->total_scsi_bufs--; |
2329 | } | 2330 | } |
2331 | spin_unlock(&phba->scsi_buf_list_lock); | ||
2330 | 2332 | ||
2331 | /* Release all the lpfc_iocbq entries maintained by this host. */ | 2333 | /* Release all the lpfc_iocbq entries maintained by this host. */ |
2332 | list_for_each_entry_safe(io, io_next, &phba->lpfc_iocb_list, list) { | 2334 | list_for_each_entry_safe(io, io_next, &phba->lpfc_iocb_list, list) { |
@@ -2334,9 +2336,7 @@ lpfc_scsi_free(struct lpfc_hba *phba) | |||
2334 | kfree(io); | 2336 | kfree(io); |
2335 | phba->total_iocbq_bufs--; | 2337 | phba->total_iocbq_bufs--; |
2336 | } | 2338 | } |
2337 | |||
2338 | spin_unlock_irq(&phba->hbalock); | 2339 | spin_unlock_irq(&phba->hbalock); |
2339 | |||
2340 | return 0; | 2340 | return 0; |
2341 | } | 2341 | } |
2342 | 2342 | ||
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index bf80cdefb506..a246410ce9df 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -59,6 +59,8 @@ static char *dif_op_str[] = { | |||
59 | }; | 59 | }; |
60 | static void | 60 | static void |
61 | lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb); | 61 | lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb); |
62 | static void | ||
63 | lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb); | ||
62 | 64 | ||
63 | static void | 65 | static void |
64 | lpfc_debug_save_data(struct lpfc_hba *phba, struct scsi_cmnd *cmnd) | 66 | lpfc_debug_save_data(struct lpfc_hba *phba, struct scsi_cmnd *cmnd) |
@@ -596,7 +598,7 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) | |||
596 | iocb->ulpClass = CLASS3; | 598 | iocb->ulpClass = CLASS3; |
597 | psb->status = IOSTAT_SUCCESS; | 599 | psb->status = IOSTAT_SUCCESS; |
598 | /* Put it back into the SCSI buffer list */ | 600 | /* Put it back into the SCSI buffer list */ |
599 | lpfc_release_scsi_buf_s4(phba, psb); | 601 | lpfc_release_scsi_buf_s3(phba, psb); |
600 | 602 | ||
601 | } | 603 | } |
602 | 604 | ||
@@ -2766,7 +2768,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) | |||
2766 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | 2768 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; |
2767 | struct lpfc_hba *phba = vport->phba; | 2769 | struct lpfc_hba *phba = vport->phba; |
2768 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | 2770 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; |
2769 | struct lpfc_nodelist *ndlp = rdata->pnode; | 2771 | struct lpfc_nodelist *ndlp; |
2770 | struct lpfc_scsi_buf *lpfc_cmd; | 2772 | struct lpfc_scsi_buf *lpfc_cmd; |
2771 | struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); | 2773 | struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); |
2772 | int err; | 2774 | int err; |
@@ -2776,6 +2778,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) | |||
2776 | cmnd->result = err; | 2778 | cmnd->result = err; |
2777 | goto out_fail_command; | 2779 | goto out_fail_command; |
2778 | } | 2780 | } |
2781 | ndlp = rdata->pnode; | ||
2779 | 2782 | ||
2780 | if (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED) && | 2783 | if (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED) && |
2781 | scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { | 2784 | scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { |
@@ -3154,9 +3157,15 @@ static int | |||
3154 | lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) | 3157 | lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) |
3155 | { | 3158 | { |
3156 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | 3159 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; |
3157 | struct lpfc_nodelist *pnode = rdata->pnode; | 3160 | struct lpfc_nodelist *pnode; |
3158 | unsigned long later; | 3161 | unsigned long later; |
3159 | 3162 | ||
3163 | if (!rdata) { | ||
3164 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | ||
3165 | "0797 Tgt Map rport failure: rdata x%p\n", rdata); | ||
3166 | return FAILED; | ||
3167 | } | ||
3168 | pnode = rdata->pnode; | ||
3160 | /* | 3169 | /* |
3161 | * If target is not in a MAPPED state, delay until | 3170 | * If target is not in a MAPPED state, delay until |
3162 | * target is rediscovered or devloss timeout expires. | 3171 | * target is rediscovered or devloss timeout expires. |
@@ -3241,12 +3250,18 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | |||
3241 | struct Scsi_Host *shost = cmnd->device->host; | 3250 | struct Scsi_Host *shost = cmnd->device->host; |
3242 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | 3251 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; |
3243 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | 3252 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; |
3244 | struct lpfc_nodelist *pnode = rdata->pnode; | 3253 | struct lpfc_nodelist *pnode; |
3245 | unsigned tgt_id = cmnd->device->id; | 3254 | unsigned tgt_id = cmnd->device->id; |
3246 | unsigned int lun_id = cmnd->device->lun; | 3255 | unsigned int lun_id = cmnd->device->lun; |
3247 | struct lpfc_scsi_event_header scsi_event; | 3256 | struct lpfc_scsi_event_header scsi_event; |
3248 | int status; | 3257 | int status; |
3249 | 3258 | ||
3259 | if (!rdata) { | ||
3260 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
3261 | "0798 Device Reset rport failure: rdata x%p\n", rdata); | ||
3262 | return FAILED; | ||
3263 | } | ||
3264 | pnode = rdata->pnode; | ||
3250 | fc_block_scsi_eh(cmnd); | 3265 | fc_block_scsi_eh(cmnd); |
3251 | 3266 | ||
3252 | status = lpfc_chk_tgt_mapped(vport, cmnd); | 3267 | status = lpfc_chk_tgt_mapped(vport, cmnd); |
@@ -3300,12 +3315,18 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) | |||
3300 | struct Scsi_Host *shost = cmnd->device->host; | 3315 | struct Scsi_Host *shost = cmnd->device->host; |
3301 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | 3316 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; |
3302 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | 3317 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; |
3303 | struct lpfc_nodelist *pnode = rdata->pnode; | 3318 | struct lpfc_nodelist *pnode; |
3304 | unsigned tgt_id = cmnd->device->id; | 3319 | unsigned tgt_id = cmnd->device->id; |
3305 | unsigned int lun_id = cmnd->device->lun; | 3320 | unsigned int lun_id = cmnd->device->lun; |
3306 | struct lpfc_scsi_event_header scsi_event; | 3321 | struct lpfc_scsi_event_header scsi_event; |
3307 | int status; | 3322 | int status; |
3308 | 3323 | ||
3324 | if (!rdata) { | ||
3325 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
3326 | "0799 Target Reset rport failure: rdata x%p\n", rdata); | ||
3327 | return FAILED; | ||
3328 | } | ||
3329 | pnode = rdata->pnode; | ||
3309 | fc_block_scsi_eh(cmnd); | 3330 | fc_block_scsi_eh(cmnd); |
3310 | 3331 | ||
3311 | status = lpfc_chk_tgt_mapped(vport, cmnd); | 3332 | status = lpfc_chk_tgt_mapped(vport, cmnd); |
@@ -3486,6 +3507,8 @@ lpfc_slave_alloc(struct scsi_device *sdev) | |||
3486 | "Allocated %d buffers.\n", | 3507 | "Allocated %d buffers.\n", |
3487 | num_to_alloc, num_allocated); | 3508 | num_to_alloc, num_allocated); |
3488 | } | 3509 | } |
3510 | if (num_allocated > 0) | ||
3511 | phba->total_scsi_bufs += num_allocated; | ||
3489 | return 0; | 3512 | return 0; |
3490 | } | 3513 | } |
3491 | 3514 | ||