aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2014-05-23 05:00:56 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2014-06-03 22:18:42 -0400
commit51a07f84649d2be206c4c2ad9a612956db0c2f8c (patch)
treec47878878397053090c5d0861134ea0c2b78122e
parente6dc783a38ec0f2a5a91edda3f76195dffb17a16 (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>
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c195
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h6
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c6
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.h5
4 files changed, 147 insertions, 65 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 */
107static struct kmem_cache *qla_tgt_cmd_cachep;
108static struct kmem_cache *qla_tgt_mgmt_cmd_cachep; 107static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
109static mempool_t *qla_tgt_mgmt_cmd_mempool; 108static mempool_t *qla_tgt_mgmt_cmd_mempool;
110static struct workqueue_struct *qla_tgt_wq; 109static struct workqueue_struct *qla_tgt_wq;
@@ -2165,11 +2164,18 @@ done:
2165 2164
2166void qlt_free_cmd(struct qla_tgt_cmd *cmd) 2165void 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}
2174EXPORT_SYMBOL(qlt_free_cmd); 2180EXPORT_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 */
2492static void qlt_do_work(struct work_struct *work) 2498static 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
2564static 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
2571static 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
2598static void qlt_send_busy(struct scsi_qla_host *, struct atio_from_isp *,
2599 uint16_t);
2600
2601static 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
2652out_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 */
2596static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, 2661static 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);
4956out_mgmt_cmd_cachep: 5026out_mgmt_cmd_cachep:
4957 kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); 5027 kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
4958out:
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}
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index ce33d8c26406..63283c58fb33 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -805,6 +805,12 @@ struct qla_tgt {
805 struct list_head tgt_list_entry; 805 struct list_head tgt_list_entry;
806}; 806};
807 807
808struct qla_tgt_sess_op {
809 struct scsi_qla_host *vha;
810 struct atio_from_isp atio;
811 struct work_struct work;
812};
813
808/* 814/*
809 * Equivilant to IT Nexus (Initiator-Target) 815 * Equivilant to IT Nexus (Initiator-Target)
810 */ 816 */
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 68fb66fdb757..7b3a97026934 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1465,6 +1465,8 @@ static int tcm_qla2xxx_check_initiator_node_acl(
1465 struct qla_tgt_sess *sess = qla_tgt_sess; 1465 struct qla_tgt_sess *sess = qla_tgt_sess;
1466 unsigned char port_name[36]; 1466 unsigned char port_name[36];
1467 unsigned long flags; 1467 unsigned long flags;
1468 int num_tags = (ha->fw_xcb_count) ? ha->fw_xcb_count :
1469 TCM_QLA2XXX_DEFAULT_TAGS;
1468 1470
1469 lport = vha->vha_tgt.target_lport_ptr; 1471 lport = vha->vha_tgt.target_lport_ptr;
1470 if (!lport) { 1472 if (!lport) {
@@ -1482,7 +1484,9 @@ static int tcm_qla2xxx_check_initiator_node_acl(
1482 } 1484 }
1483 se_tpg = &tpg->se_tpg; 1485 se_tpg = &tpg->se_tpg;
1484 1486
1485 se_sess = transport_init_session(TARGET_PROT_NORMAL); 1487 se_sess = transport_init_session_tags(num_tags,
1488 sizeof(struct qla_tgt_cmd),
1489 TARGET_PROT_NORMAL);
1486 if (IS_ERR(se_sess)) { 1490 if (IS_ERR(se_sess)) {
1487 pr_err("Unable to initialize struct se_session\n"); 1491 pr_err("Unable to initialize struct se_session\n");
1488 return PTR_ERR(se_sess); 1492 return PTR_ERR(se_sess);
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h
index 33aaac8c7d59..10c002145648 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h
@@ -4,6 +4,11 @@
4#define TCM_QLA2XXX_VERSION "v0.1" 4#define TCM_QLA2XXX_VERSION "v0.1"
5/* length of ASCII WWPNs including pad */ 5/* length of ASCII WWPNs including pad */
6#define TCM_QLA2XXX_NAMELEN 32 6#define TCM_QLA2XXX_NAMELEN 32
7/*
8 * Number of pre-allocated per-session tags, based upon the worst-case
9 * per port number of iocbs
10 */
11#define TCM_QLA2XXX_DEFAULT_TAGS 2088
7 12
8#include "qla_target.h" 13#include "qla_target.h"
9 14