Commit f999f4c1 authored by Andrew Vasquez's avatar Andrew Vasquez Committed by James Bottomley

[SCSI] qla2xxx: Reduce lock-contention during do-work processing.

Queued work processing will now be serialized with its own
lower-priority spinlock.  This also simplifies the work-queue
interface for future work-queue consumers.
Signed-off-by: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 6805c150
...@@ -2561,6 +2561,8 @@ typedef struct scsi_qla_host { ...@@ -2561,6 +2561,8 @@ typedef struct scsi_qla_host {
struct list_head list; struct list_head list;
struct list_head vp_fcports; /* list of fcports */ struct list_head vp_fcports; /* list of fcports */
struct list_head work_list; struct list_head work_list;
spinlock_t work_lock;
/* Commonly used flags and state information. */ /* Commonly used flags and state information. */
struct Scsi_Host *host; struct Scsi_Host *host;
unsigned long host_no; unsigned long host_no;
......
...@@ -2533,6 +2533,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, ...@@ -2533,6 +2533,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
INIT_LIST_HEAD(&vha->work_list); INIT_LIST_HEAD(&vha->work_list);
INIT_LIST_HEAD(&vha->list); INIT_LIST_HEAD(&vha->list);
spin_lock_init(&vha->work_lock);
sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no);
return vha; return vha;
...@@ -2541,13 +2543,11 @@ fail: ...@@ -2541,13 +2543,11 @@ fail:
} }
static struct qla_work_evt * static struct qla_work_evt *
qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type, qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type)
int locked)
{ {
struct qla_work_evt *e; struct qla_work_evt *e;
e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC: e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC);
GFP_KERNEL);
if (!e) if (!e)
return NULL; return NULL;
...@@ -2558,17 +2558,15 @@ qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type, ...@@ -2558,17 +2558,15 @@ qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type,
} }
static int static int
qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e, int locked) qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e)
{ {
unsigned long uninitialized_var(flags); unsigned long flags;
struct qla_hw_data *ha = vha->hw;
if (!locked) spin_lock_irqsave(&vha->work_lock, flags);
spin_lock_irqsave(&ha->hardware_lock, flags);
list_add_tail(&e->list, &vha->work_list); list_add_tail(&e->list, &vha->work_list);
spin_unlock_irqrestore(&vha->work_lock, flags);
qla2xxx_wake_dpc(vha); qla2xxx_wake_dpc(vha);
if (!locked)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS; return QLA_SUCCESS;
} }
...@@ -2578,13 +2576,13 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code, ...@@ -2578,13 +2576,13 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code,
{ {
struct qla_work_evt *e; struct qla_work_evt *e;
e = qla2x00_alloc_work(vha, QLA_EVT_AEN, 1); e = qla2x00_alloc_work(vha, QLA_EVT_AEN);
if (!e) if (!e)
return QLA_FUNCTION_FAILED; return QLA_FUNCTION_FAILED;
e->u.aen.code = code; e->u.aen.code = code;
e->u.aen.data = data; e->u.aen.data = data;
return qla2x00_post_work(vha, e, 1); return qla2x00_post_work(vha, e);
} }
int int
...@@ -2592,25 +2590,27 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb) ...@@ -2592,25 +2590,27 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb)
{ {
struct qla_work_evt *e; struct qla_work_evt *e;
e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK, 1); e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK);
if (!e) if (!e)
return QLA_FUNCTION_FAILED; return QLA_FUNCTION_FAILED;
memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
return qla2x00_post_work(vha, e, 1); return qla2x00_post_work(vha, e);
} }
static void static void
qla2x00_do_work(struct scsi_qla_host *vha) qla2x00_do_work(struct scsi_qla_host *vha)
{ {
struct qla_work_evt *e; struct qla_work_evt *e, *tmp;
struct qla_hw_data *ha = vha->hw; unsigned long flags;
LIST_HEAD(work);
spin_lock_irqsave(&vha->work_lock, flags);
list_splice_init(&vha->work_list, &work);
spin_unlock_irqrestore(&vha->work_lock, flags);
spin_lock_irq(&ha->hardware_lock); list_for_each_entry_safe(e, tmp, &work, list) {
while (!list_empty(&vha->work_list)) {
e = list_entry(vha->work_list.next, struct qla_work_evt, list);
list_del_init(&e->list); list_del_init(&e->list);
spin_unlock_irq(&ha->hardware_lock);
switch (e->type) { switch (e->type) {
case QLA_EVT_AEN: case QLA_EVT_AEN:
...@@ -2623,10 +2623,9 @@ qla2x00_do_work(struct scsi_qla_host *vha) ...@@ -2623,10 +2623,9 @@ qla2x00_do_work(struct scsi_qla_host *vha)
} }
if (e->flags & QLA_EVT_FLAG_FREE) if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e); kfree(e);
spin_lock_irq(&ha->hardware_lock);
} }
spin_unlock_irq(&ha->hardware_lock);
} }
/* Relogins all the fcports of a vport /* Relogins all the fcports of a vport
* Context: dpc thread * Context: dpc thread
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment