From 523128e53b1e82a7eb422168eddd0c566973520d Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 10 Sep 2018 10:30:46 -0700 Subject: scsi: lpfc: Correct irq handling via locks when taking adapter offline When taking the board offline while performing i/o, unsafe locking errors occurred and irq level isn't properly managed. In lpfc_sli_hba_down, spin_lock_irqsave(&phba->hbalock, flags) does not disable softirqs raised from timer expiry. It is possible that a softirq is raised from the lpfc_els_retry_delay routine and recursively requests the same phba->hbalock spinlock causing deadlock. Address the deadlocks by creating a new port_list lock. The softirq behavior can then be managed a level deeper into the calling sequences. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_vport.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_vport.c') diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 1ff0f7de9105..c340e0e47473 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -207,7 +207,7 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) struct lpfc_vport *vport; unsigned long flags; - spin_lock_irqsave(&phba->hbalock, flags); + spin_lock_irqsave(&phba->port_list_lock, flags); list_for_each_entry(vport, &phba->port_list, listentry) { if (vport == new_vport) continue; @@ -215,11 +215,11 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) if (memcmp(&vport->fc_sparam.portName, &new_vport->fc_sparam.portName, sizeof(struct lpfc_name)) == 0) { - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->port_list_lock, flags); return 0; } } - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->port_list_lock, flags); return 1; } @@ -825,9 +825,9 @@ skip_logo: lpfc_free_vpi(phba, vport->vpi); vport->work_port_events = 0; - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, "1828 Vport Deleted.\n"); scsi_host_put(shost); @@ -844,7 +844,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) GFP_KERNEL); if (vports == NULL) return NULL; - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_for_each_entry(port_iterator, &phba->port_list, listentry) { if (port_iterator->load_flag & FC_UNLOADING) continue; @@ -856,7 +856,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) } vports[index++] = port_iterator; } - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); return vports; } -- cgit v1.2.3