summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c19
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c19
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c6
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h4
4 files changed, 45 insertions, 3 deletions
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 5d6c874c44e7..61745f590916 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1204,6 +1204,20 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
psli = &phba->sli;
+ /*
+ * If freeing the queues have already started, don't access them.
+ * Otherwise set FREE_WAIT to indicate that queues are being used
+ * to hold the freeing process until we finish.
+ */
+ spin_lock_irq(&phba->hbalock);
+ if (!(psli->sli_flag & LPFC_QUEUE_FREE_INIT)) {
+ psli->sli_flag |= LPFC_QUEUE_FREE_WAIT;
+ } else {
+ spin_unlock_irq(&phba->hbalock);
+ goto skip_wait;
+ }
+ spin_unlock_irq(&phba->hbalock);
+
/* Wait a little for things to settle down, but not
* long enough for dev loss timeout to expire.
*/
@@ -1225,6 +1239,11 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
}
}
out:
+ spin_lock_irq(&phba->hbalock);
+ psli->sli_flag &= ~LPFC_QUEUE_FREE_WAIT;
+ spin_unlock_irq(&phba->hbalock);
+
+skip_wait:
init_completion(&online_compl);
rc = lpfc_workq_post_event(phba, &status, &online_compl, type);
if (rc == 0)
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 4644cea2e5ce..05fbb4765d70 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -9135,6 +9135,20 @@ lpfc_sli4_release_hdwq(struct lpfc_hba *phba)
void
lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
{
+ /*
+ * Set FREE_INIT before beginning to free the queues.
+ * Wait until the users of queues to acknowledge to
+ * release queues by clearing FREE_WAIT.
+ */
+ spin_lock_irq(&phba->hbalock);
+ phba->sli.sli_flag |= LPFC_QUEUE_FREE_INIT;
+ while (phba->sli.sli_flag & LPFC_QUEUE_FREE_WAIT) {
+ spin_unlock_irq(&phba->hbalock);
+ msleep(20);
+ spin_lock_irq(&phba->hbalock);
+ }
+ spin_unlock_irq(&phba->hbalock);
+
/* Release HBA eqs */
if (phba->sli4_hba.hdwq)
lpfc_sli4_release_hdwq(phba);
@@ -9173,6 +9187,11 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
/* Everything on this list has been freed */
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_wq_list);
+
+ /* Done with freeing the queues */
+ spin_lock_irq(&phba->hbalock);
+ phba->sli.sli_flag &= ~LPFC_QUEUE_FREE_INIT;
+ spin_unlock_irq(&phba->hbalock);
}
int
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 32ded3e9b32e..4b084a408e71 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -14417,6 +14417,9 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
if (!queue)
return;
+ if (!list_empty(&queue->wq_list))
+ list_del(&queue->wq_list);
+
while (!list_empty(&queue->page_list)) {
list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf,
list);
@@ -14432,9 +14435,6 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
if (!list_empty(&queue->cpu_list))
list_del(&queue->cpu_list);
- if (!list_empty(&queue->wq_list))
- list_del(&queue->wq_list);
-
kfree(queue);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 1153a6c91bde..467b8270f7fd 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -327,6 +327,10 @@ struct lpfc_sli {
#define LPFC_SLI_ASYNC_MBX_BLK 0x2000 /* Async mailbox is blocked */
#define LPFC_SLI_SUPPRESS_RSP 0x4000 /* Suppress RSP feature is supported */
#define LPFC_SLI_USE_EQDR 0x8000 /* EQ Delay Register is supported */
+#define LPFC_QUEUE_FREE_INIT 0x10000 /* Queue freeing is in progress */
+#define LPFC_QUEUE_FREE_WAIT 0x20000 /* Hold Queue free as it is being
+ * used outside worker thread
+ */
struct lpfc_sli_ring *sli3_ring;