[SCSI] lpfc 8.3.39: Reduced spinlock contention on SCSI buffer list

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
James Smart 2013-04-17 20:17:40 -04:00 committed by James Bottomley
parent d5ce53b7dd
commit a40fc5f0d0
3 changed files with 101 additions and 50 deletions

View file

@ -813,8 +813,10 @@ struct lpfc_hba {
uint64_t bg_reftag_err_cnt;
/* fastpath list. */
spinlock_t scsi_buf_list_lock;
struct list_head lpfc_scsi_buf_list;
spinlock_t scsi_buf_list_get_lock; /* SCSI buf alloc list lock */
spinlock_t scsi_buf_list_put_lock; /* SCSI buf free list lock */
struct list_head lpfc_scsi_buf_list_get;
struct list_head lpfc_scsi_buf_list_put;
uint32_t total_scsi_bufs;
struct list_head lpfc_iocb_list;
uint32_t total_iocbq_bufs;

View file

@ -911,9 +911,9 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)
psb->pCmd = NULL;
psb->status = IOSTAT_SUCCESS;
}
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
list_splice(&aborts, &phba->lpfc_scsi_buf_list);
spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
spin_lock_irqsave(&phba->scsi_buf_list_put_lock, iflag);
list_splice(&aborts, &phba->lpfc_scsi_buf_list_put);
spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, iflag);
return 0;
}
@ -2854,16 +2854,30 @@ lpfc_scsi_free(struct lpfc_hba *phba)
struct lpfc_iocbq *io, *io_next;
spin_lock_irq(&phba->hbalock);
/* 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) {
spin_lock(&phba->scsi_buf_list_put_lock);
list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list_put,
list) {
list_del(&sb->list);
pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data,
sb->dma_handle);
kfree(sb);
phba->total_scsi_bufs--;
}
spin_unlock(&phba->scsi_buf_list_lock);
spin_unlock(&phba->scsi_buf_list_put_lock);
spin_lock(&phba->scsi_buf_list_get_lock);
list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list_get,
list) {
list_del(&sb->list);
pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data,
sb->dma_handle);
kfree(sb);
phba->total_scsi_bufs--;
}
spin_unlock(&phba->scsi_buf_list_get_lock);
/* Release all the lpfc_iocbq entries maintained by this host. */
list_for_each_entry_safe(io, io_next, &phba->lpfc_iocb_list, list) {
@ -2999,9 +3013,12 @@ lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
phba->sli4_hba.scsi_xri_cnt,
phba->sli4_hba.scsi_xri_max);
spin_lock_irq(&phba->scsi_buf_list_lock);
list_splice_init(&phba->lpfc_scsi_buf_list, &scsi_sgl_list);
spin_unlock_irq(&phba->scsi_buf_list_lock);
spin_lock_irq(&phba->scsi_buf_list_get_lock);
spin_lock_irq(&phba->scsi_buf_list_put_lock);
list_splice_init(&phba->lpfc_scsi_buf_list_get, &scsi_sgl_list);
list_splice(&phba->lpfc_scsi_buf_list_put, &scsi_sgl_list);
spin_unlock_irq(&phba->scsi_buf_list_put_lock);
spin_unlock_irq(&phba->scsi_buf_list_get_lock);
if (phba->sli4_hba.scsi_xri_cnt > phba->sli4_hba.scsi_xri_max) {
/* max scsi xri shrinked below the allocated scsi buffers */
@ -3015,9 +3032,9 @@ lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
psb->dma_handle);
kfree(psb);
}
spin_lock_irq(&phba->scsi_buf_list_lock);
spin_lock_irq(&phba->scsi_buf_list_get_lock);
phba->sli4_hba.scsi_xri_cnt -= scsi_xri_cnt;
spin_unlock_irq(&phba->scsi_buf_list_lock);
spin_unlock_irq(&phba->scsi_buf_list_get_lock);
}
/* update xris associated to remaining allocated scsi buffers */
@ -3035,9 +3052,12 @@ lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
psb->cur_iocbq.sli4_lxritag = lxri;
psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri];
}
spin_lock_irq(&phba->scsi_buf_list_lock);
list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list);
spin_unlock_irq(&phba->scsi_buf_list_lock);
spin_lock_irq(&phba->scsi_buf_list_get_lock);
spin_lock_irq(&phba->scsi_buf_list_put_lock);
list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list_get);
INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list_put);
spin_unlock_irq(&phba->scsi_buf_list_put_lock);
spin_unlock_irq(&phba->scsi_buf_list_get_lock);
return 0;
@ -5334,8 +5354,10 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba)
init_waitqueue_head(&phba->work_waitq);
/* Initialize the scsi buffer list used by driver for scsi IO */
spin_lock_init(&phba->scsi_buf_list_lock);
INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
spin_lock_init(&phba->scsi_buf_list_get_lock);
INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list_get);
spin_lock_init(&phba->scsi_buf_list_put_lock);
INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list_put);
/* Initialize the fabric iocb list */
INIT_LIST_HEAD(&phba->fabric_iocb_list);

View file

@ -899,9 +899,12 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
int num_posted, rc = 0;
/* get all SCSI buffers need to repost to a local list */
spin_lock_irq(&phba->scsi_buf_list_lock);
list_splice_init(&phba->lpfc_scsi_buf_list, &post_sblist);
spin_unlock_irq(&phba->scsi_buf_list_lock);
spin_lock_irq(&phba->scsi_buf_list_get_lock);
spin_lock_irq(&phba->scsi_buf_list_put_lock);
list_splice_init(&phba->lpfc_scsi_buf_list_get, &post_sblist);
list_splice(&phba->lpfc_scsi_buf_list_put, &post_sblist);
spin_unlock_irq(&phba->scsi_buf_list_put_lock);
spin_unlock_irq(&phba->scsi_buf_list_get_lock);
/* post the list of scsi buffer sgls to port if available */
if (!list_empty(&post_sblist)) {
@ -1053,9 +1056,9 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
/* add the scsi buffer to a post list */
list_add_tail(&psb->list, &post_sblist);
spin_lock_irq(&phba->scsi_buf_list_lock);
spin_lock_irq(&phba->scsi_buf_list_get_lock);
phba->sli4_hba.scsi_xri_cnt++;
spin_unlock_irq(&phba->scsi_buf_list_lock);
spin_unlock_irq(&phba->scsi_buf_list_get_lock);
}
lpfc_printf_log(phba, KERN_INFO, LOG_BG,
"3021 Allocate %d out of %d requested new SCSI "
@ -1104,17 +1107,23 @@ static struct lpfc_scsi_buf*
lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
struct lpfc_scsi_buf * lpfc_cmd = NULL;
struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
unsigned long iflag = 0;
struct list_head *scsi_buf_list_get = &phba->lpfc_scsi_buf_list_get;
unsigned long gflag = 0;
unsigned long pflag = 0;
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
if (lpfc_cmd) {
lpfc_cmd->seg_cnt = 0;
lpfc_cmd->nonsg_phys = 0;
lpfc_cmd->prot_seg_cnt = 0;
spin_lock_irqsave(&phba->scsi_buf_list_get_lock, gflag);
list_remove_head(scsi_buf_list_get, lpfc_cmd, struct lpfc_scsi_buf,
list);
if (!lpfc_cmd) {
spin_lock_irqsave(&phba->scsi_buf_list_put_lock, pflag);
list_splice(&phba->lpfc_scsi_buf_list_put,
&phba->lpfc_scsi_buf_list_get);
INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list_put);
list_remove_head(scsi_buf_list_get, lpfc_cmd,
struct lpfc_scsi_buf, list);
spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, pflag);
}
spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
spin_unlock_irqrestore(&phba->scsi_buf_list_get_lock, gflag);
return lpfc_cmd;
}
/**
@ -1132,28 +1141,39 @@ static struct lpfc_scsi_buf*
lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
struct lpfc_scsi_buf *lpfc_cmd ;
unsigned long iflag = 0;
unsigned long gflag = 0;
unsigned long pflag = 0;
int found = 0;
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list,
list) {
spin_lock_irqsave(&phba->scsi_buf_list_get_lock, gflag);
list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list_get, list) {
if (lpfc_test_rrq_active(phba, ndlp,
lpfc_cmd->cur_iocbq.sli4_lxritag))
continue;
list_del(&lpfc_cmd->list);
found = 1;
lpfc_cmd->seg_cnt = 0;
lpfc_cmd->nonsg_phys = 0;
lpfc_cmd->prot_seg_cnt = 0;
break;
}
spin_unlock_irqrestore(&phba->scsi_buf_list_lock,
iflag);
if (!found) {
spin_lock_irqsave(&phba->scsi_buf_list_put_lock, pflag);
list_splice(&phba->lpfc_scsi_buf_list_put,
&phba->lpfc_scsi_buf_list_get);
INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list_put);
spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, pflag);
list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list_get,
list) {
if (lpfc_test_rrq_active(
phba, ndlp, lpfc_cmd->cur_iocbq.sli4_lxritag))
continue;
list_del(&lpfc_cmd->list);
found = 1;
break;
}
}
spin_unlock_irqrestore(&phba->scsi_buf_list_get_lock, gflag);
if (!found)
return NULL;
else
return lpfc_cmd;
return lpfc_cmd;
}
/**
* lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
@ -1185,10 +1205,14 @@ lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
{
unsigned long iflag = 0;
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
psb->seg_cnt = 0;
psb->nonsg_phys = 0;
psb->prot_seg_cnt = 0;
spin_lock_irqsave(&phba->scsi_buf_list_put_lock, iflag);
psb->pCmd = NULL;
list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list);
spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list_put);
spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, iflag);
}
/**
@ -1206,6 +1230,10 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
{
unsigned long iflag = 0;
psb->seg_cnt = 0;
psb->nonsg_phys = 0;
psb->prot_seg_cnt = 0;
if (psb->exch_busy) {
spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock,
iflag);
@ -1215,11 +1243,10 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock,
iflag);
} else {
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
psb->pCmd = NULL;
list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list);
spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
spin_lock_irqsave(&phba->scsi_buf_list_put_lock, iflag);
list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list_put);
spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, iflag);
}
}