lpfc: Fix locking for lpfc_hba_down_post

Fix locking for lpfc_hba_down_post

Signed-off-by: James Smart <james.smart@emulex.com>
Reviewed-By: Dick Kennedy <dick.kennedy@emulex.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
James Smart 2014-04-04 13:51:34 -04:00 committed by Christoph Hellwig
parent 6acb348149
commit bcece5f557

View File

@ -819,8 +819,86 @@ lpfc_hba_down_prep(struct lpfc_hba *phba)
return 0; return 0;
} }
/**
* lpfc_hba_free_post_buf - Perform lpfc uninitialization after HBA reset
* @phba: pointer to lpfc HBA data structure.
*
* This routine will cleanup posted ELS buffers after the HBA is reset
* when bringing down the SLI Layer.
*
*
* Return codes
* void.
**/
static void
lpfc_hba_free_post_buf(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
struct lpfc_dmabuf *mp, *next_mp;
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
lpfc_sli_hbqbuf_free_all(phba);
else {
/* Cleanup preposted buffers on the ELS ring */
spin_lock_irq(&phba->hbalock);
pring = &psli->ring[LPFC_ELS_RING];
list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
list_del(&mp->list);
pring->postbufq_cnt--;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
spin_unlock_irq(&phba->hbalock);
}
}
/**
* lpfc_hba_clean_txcmplq - Perform lpfc uninitialization after HBA reset
* @phba: pointer to lpfc HBA data structure.
*
* This routine will cleanup the txcmplq after the HBA is reset when bringing
* down the SLI Layer.
*
* Return codes
* void
**/
static void
lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
LIST_HEAD(completions);
int i;
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
if (phba->sli_rev >= LPFC_SLI_REV4)
spin_lock_irq(&pring->ring_lock);
else
spin_lock_irq(&phba->hbalock);
/* At this point in time the HBA is either reset or DOA. Either
* way, nothing should be on txcmplq as it will NEVER complete.
*/
list_splice_init(&pring->txcmplq, &completions);
if (phba->sli_rev >= LPFC_SLI_REV4)
spin_unlock_irq(&pring->ring_lock);
else
spin_unlock_irq(&phba->hbalock);
/* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);
lpfc_sli_abort_iocb_ring(phba, pring);
}
}
/** /**
* lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset
int i;
* @phba: pointer to lpfc HBA data structure. * @phba: pointer to lpfc HBA data structure.
* *
* This routine will do uninitialization after the HBA is reset when bring * This routine will do uninitialization after the HBA is reset when bring
@ -833,44 +911,8 @@ lpfc_hba_down_prep(struct lpfc_hba *phba)
static int static int
lpfc_hba_down_post_s3(struct lpfc_hba *phba) lpfc_hba_down_post_s3(struct lpfc_hba *phba)
{ {
struct lpfc_sli *psli = &phba->sli; lpfc_hba_free_post_buf(phba);
struct lpfc_sli_ring *pring; lpfc_hba_clean_txcmplq(phba);
struct lpfc_dmabuf *mp, *next_mp;
LIST_HEAD(completions);
int i;
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
lpfc_sli_hbqbuf_free_all(phba);
else {
/* Cleanup preposted buffers on the ELS ring */
pring = &psli->ring[LPFC_ELS_RING];
list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
list_del(&mp->list);
pring->postbufq_cnt--;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
}
spin_lock_irq(&phba->hbalock);
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
/* At this point in time the HBA is either reset or DOA. Either
* way, nothing should be on txcmplq as it will NEVER complete.
*/
list_splice_init(&pring->txcmplq, &completions);
spin_unlock_irq(&phba->hbalock);
/* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);
lpfc_sli_abort_iocb_ring(phba, pring);
spin_lock_irq(&phba->hbalock);
}
spin_unlock_irq(&phba->hbalock);
return 0; return 0;
} }
@ -890,13 +932,12 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)
{ {
struct lpfc_scsi_buf *psb, *psb_next; struct lpfc_scsi_buf *psb, *psb_next;
LIST_HEAD(aborts); LIST_HEAD(aborts);
int ret;
unsigned long iflag = 0; unsigned long iflag = 0;
struct lpfc_sglq *sglq_entry = NULL; struct lpfc_sglq *sglq_entry = NULL;
ret = lpfc_hba_down_post_s3(phba); lpfc_hba_free_post_buf(phba);
if (ret) lpfc_hba_clean_txcmplq(phba);
return ret;
/* At this point in time the HBA is either reset or DOA. Either /* At this point in time the HBA is either reset or DOA. Either
* way, nothing should be on lpfc_abts_els_sgl_list, it needs to be * way, nothing should be on lpfc_abts_els_sgl_list, it needs to be
* on the lpfc_sgl_list so that it can either be freed if the * on the lpfc_sgl_list so that it can either be freed if the