[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>
This commit is contained in:
committed by
James Bottomley
parent
891478a244
commit
1c6f4ef5d6
@@ -1018,13 +1018,12 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|||||||
mempool_free(mboxq, phba->mbox_mem_pool);
|
mempool_free(mboxq, phba->mbox_mem_pool);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
spin_lock_irqsave(&phba->hbalock, flags);
|
||||||
phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
|
phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
|
||||||
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
|
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
|
||||||
if (vport->port_state != LPFC_FLOGI) {
|
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||||
spin_lock_irqsave(&phba->hbalock, flags);
|
if (vport->port_state != LPFC_FLOGI)
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
|
||||||
lpfc_initial_flogi(vport);
|
lpfc_initial_flogi(vport);
|
||||||
}
|
|
||||||
|
|
||||||
mempool_free(mboxq, phba->mbox_mem_pool);
|
mempool_free(mboxq, phba->mbox_mem_pool);
|
||||||
return;
|
return;
|
||||||
@@ -1460,12 +1459,15 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
|
|||||||
|
|
||||||
if (phba->link_state >= LPFC_LINK_UP)
|
if (phba->link_state >= LPFC_LINK_UP)
|
||||||
lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
|
lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
|
||||||
else
|
else {
|
||||||
/*
|
/*
|
||||||
* Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
|
* Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
|
||||||
* flag
|
* flag
|
||||||
*/
|
*/
|
||||||
|
spin_lock_irq(&phba->hbalock);
|
||||||
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
|
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
|
||||||
|
spin_unlock_irq(&phba->hbalock);
|
||||||
|
}
|
||||||
|
|
||||||
if (unreg_fcf) {
|
if (unreg_fcf) {
|
||||||
spin_lock_irq(&phba->hbalock);
|
spin_lock_irq(&phba->hbalock);
|
||||||
@@ -2264,7 +2266,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
|||||||
* This shost reference might have been taken at the beginning of
|
* This shost reference might have been taken at the beginning of
|
||||||
* lpfc_vport_delete()
|
* lpfc_vport_delete()
|
||||||
*/
|
*/
|
||||||
if (vport->load_flag & FC_UNLOADING)
|
if ((vport->load_flag & FC_UNLOADING) && (vport != phba->pport))
|
||||||
scsi_host_put(shost);
|
scsi_host_put(shost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2320,6 +2320,7 @@ lpfc_scsi_free(struct lpfc_hba *phba)
|
|||||||
|
|
||||||
spin_lock_irq(&phba->hbalock);
|
spin_lock_irq(&phba->hbalock);
|
||||||
/* Release all the lpfc_scsi_bufs maintained by this host. */
|
/* Release all the lpfc_scsi_bufs maintained by this host. */
|
||||||
|
spin_lock(&phba->scsi_buf_list_lock);
|
||||||
list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
|
list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
|
||||||
list_del(&sb->list);
|
list_del(&sb->list);
|
||||||
pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data,
|
pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data,
|
||||||
@@ -2327,6 +2328,7 @@ lpfc_scsi_free(struct lpfc_hba *phba)
|
|||||||
kfree(sb);
|
kfree(sb);
|
||||||
phba->total_scsi_bufs--;
|
phba->total_scsi_bufs--;
|
||||||
}
|
}
|
||||||
|
spin_unlock(&phba->scsi_buf_list_lock);
|
||||||
|
|
||||||
/* Release all the lpfc_iocbq entries maintained by this host. */
|
/* Release all the lpfc_iocbq entries maintained by this host. */
|
||||||
list_for_each_entry_safe(io, io_next, &phba->lpfc_iocb_list, list) {
|
list_for_each_entry_safe(io, io_next, &phba->lpfc_iocb_list, list) {
|
||||||
@@ -2334,9 +2336,7 @@ lpfc_scsi_free(struct lpfc_hba *phba)
|
|||||||
kfree(io);
|
kfree(io);
|
||||||
phba->total_iocbq_bufs--;
|
phba->total_iocbq_bufs--;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irq(&phba->hbalock);
|
spin_unlock_irq(&phba->hbalock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -59,6 +59,8 @@ static char *dif_op_str[] = {
|
|||||||
};
|
};
|
||||||
static void
|
static void
|
||||||
lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
|
lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
|
||||||
|
static void
|
||||||
|
lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lpfc_debug_save_data(struct lpfc_hba *phba, struct scsi_cmnd *cmnd)
|
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)
|
|||||||
iocb->ulpClass = CLASS3;
|
iocb->ulpClass = CLASS3;
|
||||||
psb->status = IOSTAT_SUCCESS;
|
psb->status = IOSTAT_SUCCESS;
|
||||||
/* Put it back into the SCSI buffer list */
|
/* Put it back into the SCSI buffer list */
|
||||||
lpfc_release_scsi_buf_s4(phba, psb);
|
lpfc_release_scsi_buf_s3(phba, psb);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2766,7 +2768,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
|
|||||||
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
||||||
struct lpfc_hba *phba = vport->phba;
|
struct lpfc_hba *phba = vport->phba;
|
||||||
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
||||||
struct lpfc_nodelist *ndlp = rdata->pnode;
|
struct lpfc_nodelist *ndlp;
|
||||||
struct lpfc_scsi_buf *lpfc_cmd;
|
struct lpfc_scsi_buf *lpfc_cmd;
|
||||||
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
|
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
|
||||||
int err;
|
int err;
|
||||||
@@ -2776,6 +2778,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
|
|||||||
cmnd->result = err;
|
cmnd->result = err;
|
||||||
goto out_fail_command;
|
goto out_fail_command;
|
||||||
}
|
}
|
||||||
|
ndlp = rdata->pnode;
|
||||||
|
|
||||||
if (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED) &&
|
if (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED) &&
|
||||||
scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) {
|
scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) {
|
||||||
@@ -3154,9 +3157,15 @@ static int
|
|||||||
lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
|
lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
|
||||||
{
|
{
|
||||||
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
||||||
struct lpfc_nodelist *pnode = rdata->pnode;
|
struct lpfc_nodelist *pnode;
|
||||||
unsigned long later;
|
unsigned long later;
|
||||||
|
|
||||||
|
if (!rdata) {
|
||||||
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
|
||||||
|
"0797 Tgt Map rport failure: rdata x%p\n", rdata);
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
pnode = rdata->pnode;
|
||||||
/*
|
/*
|
||||||
* If target is not in a MAPPED state, delay until
|
* If target is not in a MAPPED state, delay until
|
||||||
* target is rediscovered or devloss timeout expires.
|
* target is rediscovered or devloss timeout expires.
|
||||||
@@ -3241,12 +3250,18 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
|
|||||||
struct Scsi_Host *shost = cmnd->device->host;
|
struct Scsi_Host *shost = cmnd->device->host;
|
||||||
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
||||||
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
||||||
struct lpfc_nodelist *pnode = rdata->pnode;
|
struct lpfc_nodelist *pnode;
|
||||||
unsigned tgt_id = cmnd->device->id;
|
unsigned tgt_id = cmnd->device->id;
|
||||||
unsigned int lun_id = cmnd->device->lun;
|
unsigned int lun_id = cmnd->device->lun;
|
||||||
struct lpfc_scsi_event_header scsi_event;
|
struct lpfc_scsi_event_header scsi_event;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
if (!rdata) {
|
||||||
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
|
||||||
|
"0798 Device Reset rport failure: rdata x%p\n", rdata);
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
pnode = rdata->pnode;
|
||||||
fc_block_scsi_eh(cmnd);
|
fc_block_scsi_eh(cmnd);
|
||||||
|
|
||||||
status = lpfc_chk_tgt_mapped(vport, cmnd);
|
status = lpfc_chk_tgt_mapped(vport, cmnd);
|
||||||
@@ -3300,12 +3315,18 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
|
|||||||
struct Scsi_Host *shost = cmnd->device->host;
|
struct Scsi_Host *shost = cmnd->device->host;
|
||||||
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
||||||
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
||||||
struct lpfc_nodelist *pnode = rdata->pnode;
|
struct lpfc_nodelist *pnode;
|
||||||
unsigned tgt_id = cmnd->device->id;
|
unsigned tgt_id = cmnd->device->id;
|
||||||
unsigned int lun_id = cmnd->device->lun;
|
unsigned int lun_id = cmnd->device->lun;
|
||||||
struct lpfc_scsi_event_header scsi_event;
|
struct lpfc_scsi_event_header scsi_event;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
if (!rdata) {
|
||||||
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
|
||||||
|
"0799 Target Reset rport failure: rdata x%p\n", rdata);
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
pnode = rdata->pnode;
|
||||||
fc_block_scsi_eh(cmnd);
|
fc_block_scsi_eh(cmnd);
|
||||||
|
|
||||||
status = lpfc_chk_tgt_mapped(vport, cmnd);
|
status = lpfc_chk_tgt_mapped(vport, cmnd);
|
||||||
@@ -3486,6 +3507,8 @@ lpfc_slave_alloc(struct scsi_device *sdev)
|
|||||||
"Allocated %d buffers.\n",
|
"Allocated %d buffers.\n",
|
||||||
num_to_alloc, num_allocated);
|
num_to_alloc, num_allocated);
|
||||||
}
|
}
|
||||||
|
if (num_allocated > 0)
|
||||||
|
phba->total_scsi_bufs += num_allocated;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user