diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2009-06-03 12:55:28 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-06-08 15:46:57 -0400 |
commit | f999f4c1961fe5399fd66c95860cc2d5d67e591e (patch) | |
tree | aa1b4389021f1676f04aa3a79e8b7f00ecfbb2c7 /drivers/scsi | |
parent | 6805c1504eb4cfd4a31c05ed88fdeb56228eb3ba (diff) |
[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: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 45 |
2 files changed, 24 insertions, 23 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 88ddae0e2b88..00aa48d975a6 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -2561,6 +2561,8 @@ typedef struct scsi_qla_host { | |||
2561 | struct list_head list; | 2561 | struct list_head list; |
2562 | struct list_head vp_fcports; /* list of fcports */ | 2562 | struct list_head vp_fcports; /* list of fcports */ |
2563 | struct list_head work_list; | 2563 | struct list_head work_list; |
2564 | spinlock_t work_lock; | ||
2565 | |||
2564 | /* Commonly used flags and state information. */ | 2566 | /* Commonly used flags and state information. */ |
2565 | struct Scsi_Host *host; | 2567 | struct Scsi_Host *host; |
2566 | unsigned long host_no; | 2568 | unsigned long host_no; |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 128b3d5c9663..dcf011679c8b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -2533,6 +2533,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, | |||
2533 | INIT_LIST_HEAD(&vha->work_list); | 2533 | INIT_LIST_HEAD(&vha->work_list); |
2534 | INIT_LIST_HEAD(&vha->list); | 2534 | INIT_LIST_HEAD(&vha->list); |
2535 | 2535 | ||
2536 | spin_lock_init(&vha->work_lock); | ||
2537 | |||
2536 | sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); | 2538 | sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); |
2537 | return vha; | 2539 | return vha; |
2538 | 2540 | ||
@@ -2541,13 +2543,11 @@ fail: | |||
2541 | } | 2543 | } |
2542 | 2544 | ||
2543 | static struct qla_work_evt * | 2545 | static struct qla_work_evt * |
2544 | qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type, | 2546 | qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) |
2545 | int locked) | ||
2546 | { | 2547 | { |
2547 | struct qla_work_evt *e; | 2548 | struct qla_work_evt *e; |
2548 | 2549 | ||
2549 | e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC: | 2550 | e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC); |
2550 | GFP_KERNEL); | ||
2551 | if (!e) | 2551 | if (!e) |
2552 | return NULL; | 2552 | return NULL; |
2553 | 2553 | ||
@@ -2558,17 +2558,15 @@ qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type, | |||
2558 | } | 2558 | } |
2559 | 2559 | ||
2560 | static int | 2560 | static int |
2561 | qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e, int locked) | 2561 | qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e) |
2562 | { | 2562 | { |
2563 | unsigned long uninitialized_var(flags); | 2563 | unsigned long flags; |
2564 | struct qla_hw_data *ha = vha->hw; | ||
2565 | 2564 | ||
2566 | if (!locked) | 2565 | spin_lock_irqsave(&vha->work_lock, flags); |
2567 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
2568 | list_add_tail(&e->list, &vha->work_list); | 2566 | list_add_tail(&e->list, &vha->work_list); |
2567 | spin_unlock_irqrestore(&vha->work_lock, flags); | ||
2569 | qla2xxx_wake_dpc(vha); | 2568 | qla2xxx_wake_dpc(vha); |
2570 | if (!locked) | 2569 | |
2571 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2572 | return QLA_SUCCESS; | 2570 | return QLA_SUCCESS; |
2573 | } | 2571 | } |
2574 | 2572 | ||
@@ -2578,13 +2576,13 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code, | |||
2578 | { | 2576 | { |
2579 | struct qla_work_evt *e; | 2577 | struct qla_work_evt *e; |
2580 | 2578 | ||
2581 | e = qla2x00_alloc_work(vha, QLA_EVT_AEN, 1); | 2579 | e = qla2x00_alloc_work(vha, QLA_EVT_AEN); |
2582 | if (!e) | 2580 | if (!e) |
2583 | return QLA_FUNCTION_FAILED; | 2581 | return QLA_FUNCTION_FAILED; |
2584 | 2582 | ||
2585 | e->u.aen.code = code; | 2583 | e->u.aen.code = code; |
2586 | e->u.aen.data = data; | 2584 | e->u.aen.data = data; |
2587 | return qla2x00_post_work(vha, e, 1); | 2585 | return qla2x00_post_work(vha, e); |
2588 | } | 2586 | } |
2589 | 2587 | ||
2590 | int | 2588 | int |
@@ -2592,25 +2590,27 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb) | |||
2592 | { | 2590 | { |
2593 | struct qla_work_evt *e; | 2591 | struct qla_work_evt *e; |
2594 | 2592 | ||
2595 | e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK, 1); | 2593 | e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK); |
2596 | if (!e) | 2594 | if (!e) |
2597 | return QLA_FUNCTION_FAILED; | 2595 | return QLA_FUNCTION_FAILED; |
2598 | 2596 | ||
2599 | memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); | 2597 | memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); |
2600 | return qla2x00_post_work(vha, e, 1); | 2598 | return qla2x00_post_work(vha, e); |
2601 | } | 2599 | } |
2602 | 2600 | ||
2603 | static void | 2601 | static void |
2604 | qla2x00_do_work(struct scsi_qla_host *vha) | 2602 | qla2x00_do_work(struct scsi_qla_host *vha) |
2605 | { | 2603 | { |
2606 | struct qla_work_evt *e; | 2604 | struct qla_work_evt *e, *tmp; |
2607 | struct qla_hw_data *ha = vha->hw; | 2605 | unsigned long flags; |
2606 | LIST_HEAD(work); | ||
2608 | 2607 | ||
2609 | spin_lock_irq(&ha->hardware_lock); | 2608 | spin_lock_irqsave(&vha->work_lock, flags); |
2610 | while (!list_empty(&vha->work_list)) { | 2609 | list_splice_init(&vha->work_list, &work); |
2611 | e = list_entry(vha->work_list.next, struct qla_work_evt, list); | 2610 | spin_unlock_irqrestore(&vha->work_lock, flags); |
2611 | |||
2612 | list_for_each_entry_safe(e, tmp, &work, list) { | ||
2612 | list_del_init(&e->list); | 2613 | list_del_init(&e->list); |
2613 | spin_unlock_irq(&ha->hardware_lock); | ||
2614 | 2614 | ||
2615 | switch (e->type) { | 2615 | switch (e->type) { |
2616 | case QLA_EVT_AEN: | 2616 | case QLA_EVT_AEN: |
@@ -2623,10 +2623,9 @@ qla2x00_do_work(struct scsi_qla_host *vha) | |||
2623 | } | 2623 | } |
2624 | if (e->flags & QLA_EVT_FLAG_FREE) | 2624 | if (e->flags & QLA_EVT_FLAG_FREE) |
2625 | kfree(e); | 2625 | kfree(e); |
2626 | spin_lock_irq(&ha->hardware_lock); | ||
2627 | } | 2626 | } |
2628 | spin_unlock_irq(&ha->hardware_lock); | ||
2629 | } | 2627 | } |
2628 | |||
2630 | /* Relogins all the fcports of a vport | 2629 | /* Relogins all the fcports of a vport |
2631 | * Context: dpc thread | 2630 | * Context: dpc thread |
2632 | */ | 2631 | */ |