diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-05-23 05:00:56 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-06-03 22:18:42 -0400 |
commit | 51a07f84649d2be206c4c2ad9a612956db0c2f8c (patch) | |
tree | c47878878397053090c5d0861134ea0c2b78122e /drivers/scsi/qla2xxx/qla_target.c | |
parent | e6dc783a38ec0f2a5a91edda3f76195dffb17a16 (diff) |
qla2xxx: Convert to percpu_ida session tag pre-allocation
This patch converts qla2xxx target code to use generic percpu_ida
tag allocation provided by target-core, thus removing the original
kmem_cache_zalloc() for each struct qla_tgt_cmd descriptor in the
incoming ATIO packet fast-path.
This includes the conversion of qlt_handle_cmd_for_atio() to perform
qla_tgt_sess lookup before dispatching a command descriptor into
qla_tgt_wq process context, along with handling the case where no
active session exists, and subsequently kicking off a seperate
process context for qlt_create_sess_from_atio() to create a new one.
It also includes moving tag allocation into generic code within
qlt_get_tag(), so that the same logic can be shared between
qlt_handle_cmd_for_atio() + qlt_create_sess_from_atio() contexts.
Also, __qlt_do_work() has been made generic between both normal
process context in qlt_do_work() + qlt_create_sess_from_atio().
Next, update qlt_free_cmd() to release the percpu-ida tags, and
drop the now-unused global qla_tgt_cmd_cachep.
Finally in tcm_qla2xxx code, tcm_qla2xxx_check_initiator_node_acl()
has been updated to use transport_init_session_tags() along with a
hardcoded TCM_QLA2XXX_DEFAULT_TAGS=2088 as the number of qla_tgt_cmd
descriptors to pre-allocate per qla_tgt_sess instance.
(Use ha->fw_xcb_count if available to calculate num_tags, and
also factor in extra pad tags - Quinn)
Cc: Saurav Kashyap <saurav.kashyap@qlogic.com>
Cc: Quinn Tran <quinn.tran@qlogic.com>
Cc: Giridhar Malavali <giridhar.malavali@qlogic.com>
Cc: Chad Dupuis <chad.dupuis@qlogic.com>
Cc: Roland Dreier <roland@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_target.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_target.c | 195 |
1 files changed, 131 insertions, 64 deletions
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 0cb73074c199..bd9c725c08e1 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c | |||
@@ -104,7 +104,6 @@ static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha, | |||
104 | /* | 104 | /* |
105 | * Global Variables | 105 | * Global Variables |
106 | */ | 106 | */ |
107 | static struct kmem_cache *qla_tgt_cmd_cachep; | ||
108 | static struct kmem_cache *qla_tgt_mgmt_cmd_cachep; | 107 | static struct kmem_cache *qla_tgt_mgmt_cmd_cachep; |
109 | static mempool_t *qla_tgt_mgmt_cmd_mempool; | 108 | static mempool_t *qla_tgt_mgmt_cmd_mempool; |
110 | static struct workqueue_struct *qla_tgt_wq; | 109 | static struct workqueue_struct *qla_tgt_wq; |
@@ -2165,11 +2164,18 @@ done: | |||
2165 | 2164 | ||
2166 | void qlt_free_cmd(struct qla_tgt_cmd *cmd) | 2165 | void qlt_free_cmd(struct qla_tgt_cmd *cmd) |
2167 | { | 2166 | { |
2167 | struct qla_tgt_sess *sess = cmd->sess; | ||
2168 | |||
2168 | BUG_ON(cmd->sg_mapped); | 2169 | BUG_ON(cmd->sg_mapped); |
2169 | 2170 | ||
2170 | if (unlikely(cmd->free_sg)) | 2171 | if (unlikely(cmd->free_sg)) |
2171 | kfree(cmd->sg); | 2172 | kfree(cmd->sg); |
2172 | kmem_cache_free(qla_tgt_cmd_cachep, cmd); | 2173 | |
2174 | if (!sess || !sess->se_sess) { | ||
2175 | WARN_ON(1); | ||
2176 | return; | ||
2177 | } | ||
2178 | percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); | ||
2173 | } | 2179 | } |
2174 | EXPORT_SYMBOL(qlt_free_cmd); | 2180 | EXPORT_SYMBOL(qlt_free_cmd); |
2175 | 2181 | ||
@@ -2489,13 +2495,12 @@ static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *, | |||
2489 | /* | 2495 | /* |
2490 | * Process context for I/O path into tcm_qla2xxx code | 2496 | * Process context for I/O path into tcm_qla2xxx code |
2491 | */ | 2497 | */ |
2492 | static void qlt_do_work(struct work_struct *work) | 2498 | static void __qlt_do_work(struct qla_tgt_cmd *cmd) |
2493 | { | 2499 | { |
2494 | struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); | ||
2495 | scsi_qla_host_t *vha = cmd->vha; | 2500 | scsi_qla_host_t *vha = cmd->vha; |
2496 | struct qla_hw_data *ha = vha->hw; | 2501 | struct qla_hw_data *ha = vha->hw; |
2497 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; | 2502 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; |
2498 | struct qla_tgt_sess *sess = NULL; | 2503 | struct qla_tgt_sess *sess = cmd->sess; |
2499 | struct atio_from_isp *atio = &cmd->atio; | 2504 | struct atio_from_isp *atio = &cmd->atio; |
2500 | unsigned char *cdb; | 2505 | unsigned char *cdb; |
2501 | unsigned long flags; | 2506 | unsigned long flags; |
@@ -2505,41 +2510,6 @@ static void qlt_do_work(struct work_struct *work) | |||
2505 | if (tgt->tgt_stop) | 2510 | if (tgt->tgt_stop) |
2506 | goto out_term; | 2511 | goto out_term; |
2507 | 2512 | ||
2508 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
2509 | sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, | ||
2510 | atio->u.isp24.fcp_hdr.s_id); | ||
2511 | /* Do kref_get() before dropping qla_hw_data->hardware_lock. */ | ||
2512 | if (sess) | ||
2513 | kref_get(&sess->se_sess->sess_kref); | ||
2514 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2515 | |||
2516 | if (unlikely(!sess)) { | ||
2517 | uint8_t *s_id = atio->u.isp24.fcp_hdr.s_id; | ||
2518 | |||
2519 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022, | ||
2520 | "qla_target(%d): Unable to find wwn login" | ||
2521 | " (s_id %x:%x:%x), trying to create it manually\n", | ||
2522 | vha->vp_idx, s_id[0], s_id[1], s_id[2]); | ||
2523 | |||
2524 | if (atio->u.raw.entry_count > 1) { | ||
2525 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023, | ||
2526 | "Dropping multy entry cmd %p\n", cmd); | ||
2527 | goto out_term; | ||
2528 | } | ||
2529 | |||
2530 | mutex_lock(&vha->vha_tgt.tgt_mutex); | ||
2531 | sess = qlt_make_local_sess(vha, s_id); | ||
2532 | /* sess has an extra creation ref. */ | ||
2533 | mutex_unlock(&vha->vha_tgt.tgt_mutex); | ||
2534 | |||
2535 | if (!sess) | ||
2536 | goto out_term; | ||
2537 | } | ||
2538 | |||
2539 | cmd->sess = sess; | ||
2540 | cmd->loop_id = sess->loop_id; | ||
2541 | cmd->conf_compl_supported = sess->conf_compl_supported; | ||
2542 | |||
2543 | cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; | 2513 | cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; |
2544 | cmd->tag = atio->u.isp24.exchange_addr; | 2514 | cmd->tag = atio->u.isp24.exchange_addr; |
2545 | cmd->unpacked_lun = scsilun_to_int( | 2515 | cmd->unpacked_lun = scsilun_to_int( |
@@ -2566,8 +2536,8 @@ static void qlt_do_work(struct work_struct *work) | |||
2566 | "qla_target: START qla command: %p lun: 0x%04x (tag %d)\n", | 2536 | "qla_target: START qla command: %p lun: 0x%04x (tag %d)\n", |
2567 | cmd, cmd->unpacked_lun, cmd->tag); | 2537 | cmd, cmd->unpacked_lun, cmd->tag); |
2568 | 2538 | ||
2569 | ret = vha->hw->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length, | 2539 | ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length, |
2570 | fcp_task_attr, data_dir, bidi); | 2540 | fcp_task_attr, data_dir, bidi); |
2571 | if (ret != 0) | 2541 | if (ret != 0) |
2572 | goto out_term; | 2542 | goto out_term; |
2573 | /* | 2543 | /* |
@@ -2586,17 +2556,114 @@ out_term: | |||
2586 | */ | 2556 | */ |
2587 | spin_lock_irqsave(&ha->hardware_lock, flags); | 2557 | spin_lock_irqsave(&ha->hardware_lock, flags); |
2588 | qlt_send_term_exchange(vha, NULL, &cmd->atio, 1); | 2558 | qlt_send_term_exchange(vha, NULL, &cmd->atio, 1); |
2589 | kmem_cache_free(qla_tgt_cmd_cachep, cmd); | 2559 | percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); |
2590 | if (sess) | 2560 | ha->tgt.tgt_ops->put_sess(sess); |
2561 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2562 | } | ||
2563 | |||
2564 | static void qlt_do_work(struct work_struct *work) | ||
2565 | { | ||
2566 | struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); | ||
2567 | |||
2568 | __qlt_do_work(cmd); | ||
2569 | } | ||
2570 | |||
2571 | static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, | ||
2572 | struct qla_tgt_sess *sess, | ||
2573 | struct atio_from_isp *atio) | ||
2574 | { | ||
2575 | struct se_session *se_sess = sess->se_sess; | ||
2576 | struct qla_tgt_cmd *cmd; | ||
2577 | int tag; | ||
2578 | |||
2579 | tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); | ||
2580 | if (tag < 0) | ||
2581 | return NULL; | ||
2582 | |||
2583 | cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; | ||
2584 | memset(cmd, 0, sizeof(struct qla_tgt_cmd)); | ||
2585 | |||
2586 | memcpy(&cmd->atio, atio, sizeof(*atio)); | ||
2587 | cmd->state = QLA_TGT_STATE_NEW; | ||
2588 | cmd->tgt = vha->vha_tgt.qla_tgt; | ||
2589 | cmd->vha = vha; | ||
2590 | cmd->se_cmd.map_tag = tag; | ||
2591 | cmd->sess = sess; | ||
2592 | cmd->loop_id = sess->loop_id; | ||
2593 | cmd->conf_compl_supported = sess->conf_compl_supported; | ||
2594 | |||
2595 | return cmd; | ||
2596 | } | ||
2597 | |||
2598 | static void qlt_send_busy(struct scsi_qla_host *, struct atio_from_isp *, | ||
2599 | uint16_t); | ||
2600 | |||
2601 | static void qlt_create_sess_from_atio(struct work_struct *work) | ||
2602 | { | ||
2603 | struct qla_tgt_sess_op *op = container_of(work, | ||
2604 | struct qla_tgt_sess_op, work); | ||
2605 | scsi_qla_host_t *vha = op->vha; | ||
2606 | struct qla_hw_data *ha = vha->hw; | ||
2607 | struct qla_tgt_sess *sess; | ||
2608 | struct qla_tgt_cmd *cmd; | ||
2609 | unsigned long flags; | ||
2610 | uint8_t *s_id = op->atio.u.isp24.fcp_hdr.s_id; | ||
2611 | |||
2612 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022, | ||
2613 | "qla_target(%d): Unable to find wwn login" | ||
2614 | " (s_id %x:%x:%x), trying to create it manually\n", | ||
2615 | vha->vp_idx, s_id[0], s_id[1], s_id[2]); | ||
2616 | |||
2617 | if (op->atio.u.raw.entry_count > 1) { | ||
2618 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023, | ||
2619 | "Dropping multy entry atio %p\n", &op->atio); | ||
2620 | goto out_term; | ||
2621 | } | ||
2622 | |||
2623 | mutex_lock(&vha->vha_tgt.tgt_mutex); | ||
2624 | sess = qlt_make_local_sess(vha, s_id); | ||
2625 | /* sess has an extra creation ref. */ | ||
2626 | mutex_unlock(&vha->vha_tgt.tgt_mutex); | ||
2627 | |||
2628 | if (!sess) | ||
2629 | goto out_term; | ||
2630 | /* | ||
2631 | * Now obtain a pre-allocated session tag using the original op->atio | ||
2632 | * packet header, and dispatch into __qlt_do_work() using the existing | ||
2633 | * process context. | ||
2634 | */ | ||
2635 | cmd = qlt_get_tag(vha, sess, &op->atio); | ||
2636 | if (!cmd) { | ||
2637 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
2638 | qlt_send_busy(vha, &op->atio, SAM_STAT_BUSY); | ||
2591 | ha->tgt.tgt_ops->put_sess(sess); | 2639 | ha->tgt.tgt_ops->put_sess(sess); |
2640 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2641 | kfree(op); | ||
2642 | return; | ||
2643 | } | ||
2644 | /* | ||
2645 | * __qlt_do_work() will call ha->tgt.tgt_ops->put_sess() to release | ||
2646 | * the extra reference taken above by qlt_make_local_sess() | ||
2647 | */ | ||
2648 | __qlt_do_work(cmd); | ||
2649 | kfree(op); | ||
2650 | return; | ||
2651 | |||
2652 | out_term: | ||
2653 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
2654 | qlt_send_term_exchange(vha, NULL, &op->atio, 1); | ||
2592 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 2655 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
2656 | kfree(op); | ||
2657 | |||
2593 | } | 2658 | } |
2594 | 2659 | ||
2595 | /* ha->hardware_lock supposed to be held on entry */ | 2660 | /* ha->hardware_lock supposed to be held on entry */ |
2596 | static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, | 2661 | static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, |
2597 | struct atio_from_isp *atio) | 2662 | struct atio_from_isp *atio) |
2598 | { | 2663 | { |
2664 | struct qla_hw_data *ha = vha->hw; | ||
2599 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; | 2665 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; |
2666 | struct qla_tgt_sess *sess; | ||
2600 | struct qla_tgt_cmd *cmd; | 2667 | struct qla_tgt_cmd *cmd; |
2601 | 2668 | ||
2602 | if (unlikely(tgt->tgt_stop)) { | 2669 | if (unlikely(tgt->tgt_stop)) { |
@@ -2605,18 +2672,31 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, | |||
2605 | return -EFAULT; | 2672 | return -EFAULT; |
2606 | } | 2673 | } |
2607 | 2674 | ||
2608 | cmd = kmem_cache_zalloc(qla_tgt_cmd_cachep, GFP_ATOMIC); | 2675 | sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); |
2676 | if (unlikely(!sess)) { | ||
2677 | struct qla_tgt_sess_op *op = kzalloc(sizeof(struct qla_tgt_sess_op), | ||
2678 | GFP_ATOMIC); | ||
2679 | if (!op) | ||
2680 | return -ENOMEM; | ||
2681 | |||
2682 | memcpy(&op->atio, atio, sizeof(*atio)); | ||
2683 | INIT_WORK(&op->work, qlt_create_sess_from_atio); | ||
2684 | queue_work(qla_tgt_wq, &op->work); | ||
2685 | return 0; | ||
2686 | } | ||
2687 | /* | ||
2688 | * Do kref_get() before returning + dropping qla_hw_data->hardware_lock. | ||
2689 | */ | ||
2690 | kref_get(&sess->se_sess->sess_kref); | ||
2691 | |||
2692 | cmd = qlt_get_tag(vha, sess, atio); | ||
2609 | if (!cmd) { | 2693 | if (!cmd) { |
2610 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05e, | 2694 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05e, |
2611 | "qla_target(%d): Allocation of cmd failed\n", vha->vp_idx); | 2695 | "qla_target(%d): Allocation of cmd failed\n", vha->vp_idx); |
2696 | ha->tgt.tgt_ops->put_sess(sess); | ||
2612 | return -ENOMEM; | 2697 | return -ENOMEM; |
2613 | } | 2698 | } |
2614 | 2699 | ||
2615 | memcpy(&cmd->atio, atio, sizeof(*atio)); | ||
2616 | cmd->state = QLA_TGT_STATE_NEW; | ||
2617 | cmd->tgt = vha->vha_tgt.qla_tgt; | ||
2618 | cmd->vha = vha; | ||
2619 | |||
2620 | INIT_WORK(&cmd->work, qlt_do_work); | 2700 | INIT_WORK(&cmd->work, qlt_do_work); |
2621 | queue_work(qla_tgt_wq, &cmd->work); | 2701 | queue_work(qla_tgt_wq, &cmd->work); |
2622 | return 0; | 2702 | return 0; |
@@ -4911,23 +4991,13 @@ int __init qlt_init(void) | |||
4911 | if (!QLA_TGT_MODE_ENABLED()) | 4991 | if (!QLA_TGT_MODE_ENABLED()) |
4912 | return 0; | 4992 | return 0; |
4913 | 4993 | ||
4914 | qla_tgt_cmd_cachep = kmem_cache_create("qla_tgt_cmd_cachep", | ||
4915 | sizeof(struct qla_tgt_cmd), __alignof__(struct qla_tgt_cmd), 0, | ||
4916 | NULL); | ||
4917 | if (!qla_tgt_cmd_cachep) { | ||
4918 | ql_log(ql_log_fatal, NULL, 0xe06c, | ||
4919 | "kmem_cache_create for qla_tgt_cmd_cachep failed\n"); | ||
4920 | return -ENOMEM; | ||
4921 | } | ||
4922 | |||
4923 | qla_tgt_mgmt_cmd_cachep = kmem_cache_create("qla_tgt_mgmt_cmd_cachep", | 4994 | qla_tgt_mgmt_cmd_cachep = kmem_cache_create("qla_tgt_mgmt_cmd_cachep", |
4924 | sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct | 4995 | sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct |
4925 | qla_tgt_mgmt_cmd), 0, NULL); | 4996 | qla_tgt_mgmt_cmd), 0, NULL); |
4926 | if (!qla_tgt_mgmt_cmd_cachep) { | 4997 | if (!qla_tgt_mgmt_cmd_cachep) { |
4927 | ql_log(ql_log_fatal, NULL, 0xe06d, | 4998 | ql_log(ql_log_fatal, NULL, 0xe06d, |
4928 | "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n"); | 4999 | "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n"); |
4929 | ret = -ENOMEM; | 5000 | return -ENOMEM; |
4930 | goto out; | ||
4931 | } | 5001 | } |
4932 | 5002 | ||
4933 | qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab, | 5003 | qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab, |
@@ -4955,8 +5025,6 @@ out_cmd_mempool: | |||
4955 | mempool_destroy(qla_tgt_mgmt_cmd_mempool); | 5025 | mempool_destroy(qla_tgt_mgmt_cmd_mempool); |
4956 | out_mgmt_cmd_cachep: | 5026 | out_mgmt_cmd_cachep: |
4957 | kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); | 5027 | kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); |
4958 | out: | ||
4959 | kmem_cache_destroy(qla_tgt_cmd_cachep); | ||
4960 | return ret; | 5028 | return ret; |
4961 | } | 5029 | } |
4962 | 5030 | ||
@@ -4968,5 +5036,4 @@ void qlt_exit(void) | |||
4968 | destroy_workqueue(qla_tgt_wq); | 5036 | destroy_workqueue(qla_tgt_wq); |
4969 | mempool_destroy(qla_tgt_mgmt_cmd_mempool); | 5037 | mempool_destroy(qla_tgt_mgmt_cmd_mempool); |
4970 | kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); | 5038 | kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); |
4971 | kmem_cache_destroy(qla_tgt_cmd_cachep); | ||
4972 | } | 5039 | } |