]> Pileus Git - ~andy/linux/blobdiff - drivers/scsi/qla2xxx/tcm_qla2xxx.c
Merge branches 'acpi-resources', 'acpi-ec' and 'acpi-sleep'
[~andy/linux] / drivers / scsi / qla2xxx / tcm_qla2xxx.c
index 7eb19be35d461cfff2cc9f27897fd8b91bf8d17b..788c4fe2b0c9ec7a8113078c318421d7407ae855 100644 (file)
 struct workqueue_struct *tcm_qla2xxx_free_wq;
 struct workqueue_struct *tcm_qla2xxx_cmd_wq;
 
-static int tcm_qla2xxx_check_true(struct se_portal_group *se_tpg)
-{
-       return 1;
-}
-
-static int tcm_qla2xxx_check_false(struct se_portal_group *se_tpg)
-{
-       return 0;
-}
-
 /*
  * Parse WWN.
  * If strict, we require lower-case hex and colon separators to be sure
@@ -174,7 +164,7 @@ static int tcm_qla2xxx_npiv_parse_wwn(
        *wwnn = 0;
 
        /* count may include a LF at end of string */
-       if (name[cnt-1] == '\n')
+       if (name[cnt-1] == '\n' || name[cnt-1] == 0)
                cnt--;
 
        /* validate we have enough characters for WWPN */
@@ -192,20 +182,6 @@ static int tcm_qla2xxx_npiv_parse_wwn(
        return 0;
 }
 
-static ssize_t tcm_qla2xxx_npiv_format_wwn(char *buf, size_t len,
-                                       u64 wwpn, u64 wwnn)
-{
-       u8 b[8], b2[8];
-
-       put_unaligned_be64(wwpn, b);
-       put_unaligned_be64(wwnn, b2);
-       return snprintf(buf, len,
-               "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x,"
-               "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
-               b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
-               b2[0], b2[1], b2[2], b2[3], b2[4], b2[5], b2[6], b2[7]);
-}
-
 static char *tcm_qla2xxx_npiv_get_fabric_name(void)
 {
        return "qla2xxx_npiv";
@@ -237,15 +213,6 @@ static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg)
        return lport->lport_naa_name;
 }
 
-static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
-       struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
-                               struct tcm_qla2xxx_tpg, se_tpg);
-       struct tcm_qla2xxx_lport *lport = tpg->lport;
-
-       return &lport->lport_npiv_name[0];
-}
-
 static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg)
 {
        struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
@@ -777,6 +744,9 @@ static void tcm_qla2xxx_put_session(struct se_session *se_sess)
 
 static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess)
 {
+       if (!sess)
+               return;
+
        assert_spin_locked(&sess->vha->hw->hardware_lock);
        kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session);
 }
@@ -948,16 +918,41 @@ static ssize_t tcm_qla2xxx_tpg_show_enable(
                        atomic_read(&tpg->lport_tpg_enabled));
 }
 
+static void tcm_qla2xxx_depend_tpg(struct work_struct *work)
+{
+       struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+                               struct tcm_qla2xxx_tpg, tpg_base_work);
+       struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+       struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+       if (!configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
+                                 &se_tpg->tpg_group.cg_item)) {
+               atomic_set(&base_tpg->lport_tpg_enabled, 1);
+               qlt_enable_vha(base_vha);
+       }
+       complete(&base_tpg->tpg_base_comp);
+}
+
+static void tcm_qla2xxx_undepend_tpg(struct work_struct *work)
+{
+       struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+                               struct tcm_qla2xxx_tpg, tpg_base_work);
+       struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+       struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+       if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) {
+               atomic_set(&base_tpg->lport_tpg_enabled, 0);
+               configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
+                                      &se_tpg->tpg_group.cg_item);
+       }
+       complete(&base_tpg->tpg_base_comp);
+}
+
 static ssize_t tcm_qla2xxx_tpg_store_enable(
        struct se_portal_group *se_tpg,
        const char *page,
        size_t count)
 {
-       struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
-       struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
-                       struct tcm_qla2xxx_lport, lport_wwn);
-       struct scsi_qla_host *vha = lport->qla_vha;
-       struct qla_hw_data *ha = vha->hw;
        struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
                        struct tcm_qla2xxx_tpg, se_tpg);
        unsigned long op;
@@ -972,19 +967,28 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
                pr_err("Illegal value for tpg_enable: %lu\n", op);
                return -EINVAL;
        }
-
        if (op) {
-               atomic_set(&tpg->lport_tpg_enabled, 1);
-               qlt_enable_vha(vha);
+               if (atomic_read(&tpg->lport_tpg_enabled))
+                       return -EEXIST;
+
+               INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_depend_tpg);
        } else {
-               if (!ha->tgt.qla_tgt) {
-                       pr_err("truct qla_hw_data *ha->tgt.qla_tgt is NULL\n");
-                       return -ENODEV;
-               }
-               atomic_set(&tpg->lport_tpg_enabled, 0);
-               qlt_stop_phase1(ha->tgt.qla_tgt);
+               if (!atomic_read(&tpg->lport_tpg_enabled))
+                       return count;
+
+               INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_undepend_tpg);
        }
+       init_completion(&tpg->tpg_base_comp);
+       schedule_work(&tpg->tpg_base_work);
+       wait_for_completion(&tpg->tpg_base_comp);
 
+       if (op) {
+               if (!atomic_read(&tpg->lport_tpg_enabled))
+                       return -ENODEV;
+       } else {
+               if (atomic_read(&tpg->lport_tpg_enabled))
+                       return -EPERM;
+       }
        return count;
 }
 
@@ -1011,7 +1015,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(
        if (kstrtoul(name + 5, 10, &tpgt) || tpgt > USHRT_MAX)
                return ERR_PTR(-EINVAL);
 
-       if (!lport->qla_npiv_vp && (tpgt != 1)) {
+       if ((tpgt != 1)) {
                pr_err("In non NPIV mode, a single TPG=1 is used for HW port mappings\n");
                return ERR_PTR(-ENOSYS);
        }
@@ -1038,11 +1042,8 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(
                kfree(tpg);
                return NULL;
        }
-       /*
-        * Setup local TPG=1 pointer for non NPIV mode.
-        */
-       if (lport->qla_npiv_vp == NULL)
-               lport->tpg_1 = tpg;
+
+       lport->tpg_1 = tpg;
 
        return &tpg->se_tpg;
 }
@@ -1053,24 +1054,75 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg)
                        struct tcm_qla2xxx_tpg, se_tpg);
        struct tcm_qla2xxx_lport *lport = tpg->lport;
        struct scsi_qla_host *vha = lport->qla_vha;
-       struct qla_hw_data *ha = vha->hw;
        /*
         * Call into qla2x_target.c LLD logic to shutdown the active
         * FC Nexuses and disable target mode operation for this qla_hw_data
         */
-       if (ha->tgt.qla_tgt && !ha->tgt.qla_tgt->tgt_stop)
-               qlt_stop_phase1(ha->tgt.qla_tgt);
+       if (vha->vha_tgt.qla_tgt && !vha->vha_tgt.qla_tgt->tgt_stop)
+               qlt_stop_phase1(vha->vha_tgt.qla_tgt);
 
        core_tpg_deregister(se_tpg);
        /*
         * Clear local TPG=1 pointer for non NPIV mode.
         */
-       if (lport->qla_npiv_vp == NULL)
-               lport->tpg_1 = NULL;
-
+       lport->tpg_1 = NULL;
        kfree(tpg);
 }
 
+static ssize_t tcm_qla2xxx_npiv_tpg_show_enable(
+       struct se_portal_group *se_tpg,
+       char *page)
+{
+       return tcm_qla2xxx_tpg_show_enable(se_tpg, page);
+}
+
+static ssize_t tcm_qla2xxx_npiv_tpg_store_enable(
+       struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
+       struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
+                       struct tcm_qla2xxx_lport, lport_wwn);
+       struct scsi_qla_host *vha = lport->qla_vha;
+       struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
+                       struct tcm_qla2xxx_tpg, se_tpg);
+       unsigned long op;
+       int rc;
+
+       rc = kstrtoul(page, 0, &op);
+       if (rc < 0) {
+               pr_err("kstrtoul() returned %d\n", rc);
+               return -EINVAL;
+       }
+       if ((op != 1) && (op != 0)) {
+               pr_err("Illegal value for tpg_enable: %lu\n", op);
+               return -EINVAL;
+       }
+       if (op) {
+               if (atomic_read(&tpg->lport_tpg_enabled))
+                       return -EEXIST;
+
+               atomic_set(&tpg->lport_tpg_enabled, 1);
+               qlt_enable_vha(vha);
+       } else {
+               if (!atomic_read(&tpg->lport_tpg_enabled))
+                       return count;
+
+               atomic_set(&tpg->lport_tpg_enabled, 0);
+               qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+       }
+
+       return count;
+}
+
+TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = {
+        &tcm_qla2xxx_npiv_tpg_enable.attr,
+        NULL,
+};
+
 static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
        struct se_wwn *wwn,
        struct config_group *group,
@@ -1095,12 +1147,22 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
        tpg->lport = lport;
        tpg->lport_tpgt = tpgt;
 
+       /*
+        * By default allow READ-ONLY TPG demo-mode access w/ cached dynamic
+        * NodeACLs
+        */
+       tpg->tpg_attrib.generate_node_acls = 1;
+       tpg->tpg_attrib.demo_mode_write_protect = 1;
+       tpg->tpg_attrib.cache_dynamic_acls = 1;
+       tpg->tpg_attrib.demo_mode_login_only = 1;
+
        ret = core_tpg_register(&tcm_qla2xxx_npiv_fabric_configfs->tf_ops, wwn,
                                &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
        if (ret < 0) {
                kfree(tpg);
                return NULL;
        }
+       lport->tpg_1 = tpg;
        return &tpg->se_tpg;
 }
 
@@ -1111,13 +1173,12 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
        scsi_qla_host_t *vha,
        const uint8_t *s_id)
 {
-       struct qla_hw_data *ha = vha->hw;
        struct tcm_qla2xxx_lport *lport;
        struct se_node_acl *se_nacl;
        struct tcm_qla2xxx_nacl *nacl;
        u32 key;
 
-       lport = ha->tgt.target_lport_ptr;
+       lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
                pr_err("Unable to locate struct tcm_qla2xxx_lport\n");
                dump_stack();
@@ -1221,13 +1282,12 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
        scsi_qla_host_t *vha,
        const uint16_t loop_id)
 {
-       struct qla_hw_data *ha = vha->hw;
        struct tcm_qla2xxx_lport *lport;
        struct se_node_acl *se_nacl;
        struct tcm_qla2xxx_nacl *nacl;
        struct tcm_qla2xxx_fc_loopid *fc_loopid;
 
-       lport = ha->tgt.target_lport_ptr;
+       lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
                pr_err("Unable to locate struct tcm_qla2xxx_lport\n");
                dump_stack();
@@ -1341,6 +1401,7 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess)
 {
        struct qla_tgt *tgt = sess->tgt;
        struct qla_hw_data *ha = tgt->ha;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        struct se_session *se_sess;
        struct se_node_acl *se_nacl;
        struct tcm_qla2xxx_lport *lport;
@@ -1357,7 +1418,7 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess)
        se_nacl = se_sess->se_node_acl;
        nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl);
 
-       lport = ha->tgt.target_lport_ptr;
+       lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
                pr_err("Unable to locate struct tcm_qla2xxx_lport\n");
                dump_stack();
@@ -1391,7 +1452,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        unsigned char port_name[36];
        unsigned long flags;
 
-       lport = ha->tgt.target_lport_ptr;
+       lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
                pr_err("Unable to locate struct tcm_qla2xxx_lport\n");
                dump_stack();
@@ -1455,7 +1516,8 @@ static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id,
 {
        struct qla_tgt *tgt = sess->tgt;
        struct qla_hw_data *ha = tgt->ha;
-       struct tcm_qla2xxx_lport *lport = ha->tgt.target_lport_ptr;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+       struct tcm_qla2xxx_lport *lport = vha->vha_tgt.target_lport_ptr;
        struct se_node_acl *se_nacl = sess->se_sess->se_node_acl;
        struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl,
                        struct tcm_qla2xxx_nacl, se_node_acl);
@@ -1562,15 +1624,18 @@ static int tcm_qla2xxx_init_lport(struct tcm_qla2xxx_lport *lport)
        return 0;
 }
 
-static int tcm_qla2xxx_lport_register_cb(struct scsi_qla_host *vha)
+static int tcm_qla2xxx_lport_register_cb(struct scsi_qla_host *vha,
+                                        void *target_lport_ptr,
+                                        u64 npiv_wwpn, u64 npiv_wwnn)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct tcm_qla2xxx_lport *lport;
+       struct tcm_qla2xxx_lport *lport =
+                       (struct tcm_qla2xxx_lport *)target_lport_ptr;
        /*
-        * Setup local pointer to vha, NPIV VP pointer (if present) and
-        * vha->tcm_lport pointer
+        * Setup tgt_ops, local pointer to vha and target_lport_ptr
         */
-       lport = (struct tcm_qla2xxx_lport *)ha->tgt.target_lport_ptr;
+       ha->tgt.tgt_ops = &tcm_qla2xxx_template;
+       vha->vha_tgt.target_lport_ptr = target_lport_ptr;
        lport->qla_vha = vha;
 
        return 0;
@@ -1602,8 +1667,8 @@ static struct se_wwn *tcm_qla2xxx_make_lport(
        if (ret != 0)
                goto out;
 
-       ret = qlt_lport_register(&tcm_qla2xxx_template, wwpn,
-                               tcm_qla2xxx_lport_register_cb, lport);
+       ret = qlt_lport_register(lport, wwpn, 0, 0,
+                                tcm_qla2xxx_lport_register_cb);
        if (ret != 0)
                goto out_lport;
 
@@ -1621,7 +1686,6 @@ static void tcm_qla2xxx_drop_lport(struct se_wwn *wwn)
        struct tcm_qla2xxx_lport *lport = container_of(wwn,
                        struct tcm_qla2xxx_lport, lport_wwn);
        struct scsi_qla_host *vha = lport->qla_vha;
-       struct qla_hw_data *ha = vha->hw;
        struct se_node_acl *node;
        u32 key = 0;
 
@@ -1630,8 +1694,8 @@ static void tcm_qla2xxx_drop_lport(struct se_wwn *wwn)
         * shutdown of struct qla_tgt after the call to
         * qlt_stop_phase1() from tcm_qla2xxx_drop_tpg() above..
         */
-       if (ha->tgt.qla_tgt && !ha->tgt.qla_tgt->tgt_stopped)
-               qlt_stop_phase2(ha->tgt.qla_tgt);
+       if (vha->vha_tgt.qla_tgt && !vha->vha_tgt.qla_tgt->tgt_stopped)
+               qlt_stop_phase2(vha->vha_tgt.qla_tgt);
 
        qlt_lport_deregister(vha);
 
@@ -1642,17 +1706,79 @@ static void tcm_qla2xxx_drop_lport(struct se_wwn *wwn)
        kfree(lport);
 }
 
+static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
+                                             void *target_lport_ptr,
+                                             u64 npiv_wwpn, u64 npiv_wwnn)
+{
+       struct fc_vport *vport;
+       struct Scsi_Host *sh = base_vha->host;
+       struct scsi_qla_host *npiv_vha;
+       struct tcm_qla2xxx_lport *lport =
+                       (struct tcm_qla2xxx_lport *)target_lport_ptr;
+       struct tcm_qla2xxx_lport *base_lport =
+                       (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr;
+       struct tcm_qla2xxx_tpg *base_tpg;
+       struct fc_vport_identifiers vport_id;
+
+       if (!qla_tgt_mode_enabled(base_vha)) {
+               pr_err("qla2xxx base_vha not enabled for target mode\n");
+               return -EPERM;
+       }
+
+       if (!base_lport || !base_lport->tpg_1 ||
+           !atomic_read(&base_lport->tpg_1->lport_tpg_enabled)) {
+               pr_err("qla2xxx base_lport or tpg_1 not available\n");
+               return -EPERM;
+       }
+       base_tpg = base_lport->tpg_1;
+
+       memset(&vport_id, 0, sizeof(vport_id));
+       vport_id.port_name = npiv_wwpn;
+       vport_id.node_name = npiv_wwnn;
+       vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR;
+       vport_id.vport_type = FC_PORTTYPE_NPIV;
+       vport_id.disable = false;
+
+       vport = fc_vport_create(sh, 0, &vport_id);
+       if (!vport) {
+               pr_err("fc_vport_create failed for qla2xxx_npiv\n");
+               return -ENODEV;
+       }
+       /*
+        * Setup local pointer to NPIV vhba + target_lport_ptr
+        */
+       npiv_vha = (struct scsi_qla_host *)vport->dd_data;
+       npiv_vha->vha_tgt.target_lport_ptr = target_lport_ptr;
+       lport->qla_vha = npiv_vha;
+       scsi_host_get(npiv_vha->host);
+       return 0;
+}
+
+
 static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
        struct target_fabric_configfs *tf,
        struct config_group *group,
        const char *name)
 {
        struct tcm_qla2xxx_lport *lport;
-       u64 npiv_wwpn, npiv_wwnn;
+       u64 phys_wwpn, npiv_wwpn, npiv_wwnn;
+       char *p, tmp[128];
        int ret;
 
-       if (tcm_qla2xxx_npiv_parse_wwn(name, strlen(name)+1,
-                               &npiv_wwpn, &npiv_wwnn) < 0)
+       snprintf(tmp, 128, "%s", name);
+
+       p = strchr(tmp, '@');
+       if (!p) {
+               pr_err("Unable to locate NPIV '@' seperator\n");
+               return ERR_PTR(-EINVAL);
+       }
+       *p++ = '\0';
+
+       if (tcm_qla2xxx_parse_wwn(tmp, &phys_wwpn, 1) < 0)
+               return ERR_PTR(-EINVAL);
+
+       if (tcm_qla2xxx_npiv_parse_wwn(p, strlen(p)+1,
+                                      &npiv_wwpn, &npiv_wwnn) < 0)
                return ERR_PTR(-EINVAL);
 
        lport = kzalloc(sizeof(struct tcm_qla2xxx_lport), GFP_KERNEL);
@@ -1662,16 +1788,21 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
        }
        lport->lport_npiv_wwpn = npiv_wwpn;
        lport->lport_npiv_wwnn = npiv_wwnn;
-       tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0],
-                       TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn);
        sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn);
 
-/* FIXME: tcm_qla2xxx_npiv_make_lport */
-       ret = -ENOSYS;
+       ret = tcm_qla2xxx_init_lport(lport);
        if (ret != 0)
                goto out;
 
+       ret = qlt_lport_register(lport, phys_wwpn, npiv_wwpn, npiv_wwnn,
+                                tcm_qla2xxx_lport_register_npiv_cb);
+       if (ret != 0)
+               goto out_lport;
+
        return &lport->lport_wwn;
+out_lport:
+       vfree(lport->lport_loopid_map);
+       btree_destroy32(&lport->lport_fcport_map);
 out:
        kfree(lport);
        return ERR_PTR(ret);
@@ -1681,14 +1812,16 @@ static void tcm_qla2xxx_npiv_drop_lport(struct se_wwn *wwn)
 {
        struct tcm_qla2xxx_lport *lport = container_of(wwn,
                        struct tcm_qla2xxx_lport, lport_wwn);
-       struct scsi_qla_host *vha = lport->qla_vha;
-       struct Scsi_Host *sh = vha->host;
+       struct scsi_qla_host *npiv_vha = lport->qla_vha;
+       struct qla_hw_data *ha = npiv_vha->hw;
+       scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+
+       scsi_host_put(npiv_vha->host);
        /*
-        * Notify libfc that we want to release the lport->npiv_vport
+        * Notify libfc that we want to release the vha->fc_vport
         */
-       fc_vport_terminate(lport->npiv_vport);
-
-       scsi_host_put(sh);
+       fc_vport_terminate(npiv_vha->fc_vport);
+       scsi_host_put(base_vha->host);
        kfree(lport);
 }
 
@@ -1763,20 +1896,22 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
 static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
        .get_fabric_name                = tcm_qla2xxx_npiv_get_fabric_name,
        .get_fabric_proto_ident         = tcm_qla2xxx_get_fabric_proto_ident,
-       .tpg_get_wwn                    = tcm_qla2xxx_npiv_get_fabric_wwn,
+       .tpg_get_wwn                    = tcm_qla2xxx_get_fabric_wwn,
        .tpg_get_tag                    = tcm_qla2xxx_get_tag,
        .tpg_get_default_depth          = tcm_qla2xxx_get_default_depth,
        .tpg_get_pr_transport_id        = tcm_qla2xxx_get_pr_transport_id,
        .tpg_get_pr_transport_id_len    = tcm_qla2xxx_get_pr_transport_id_len,
        .tpg_parse_pr_out_transport_id  = tcm_qla2xxx_parse_pr_out_transport_id,
-       .tpg_check_demo_mode            = tcm_qla2xxx_check_false,
-       .tpg_check_demo_mode_cache      = tcm_qla2xxx_check_true,
-       .tpg_check_demo_mode_write_protect = tcm_qla2xxx_check_true,
-       .tpg_check_prod_mode_write_protect = tcm_qla2xxx_check_false,
+       .tpg_check_demo_mode            = tcm_qla2xxx_check_demo_mode,
+       .tpg_check_demo_mode_cache      = tcm_qla2xxx_check_demo_mode_cache,
+       .tpg_check_demo_mode_write_protect = tcm_qla2xxx_check_demo_mode,
+       .tpg_check_prod_mode_write_protect =
+           tcm_qla2xxx_check_prod_write_protect,
        .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only,
        .tpg_alloc_fabric_acl           = tcm_qla2xxx_alloc_fabric_acl,
        .tpg_release_fabric_acl         = tcm_qla2xxx_release_fabric_acl,
        .tpg_get_inst_index             = tcm_qla2xxx_tpg_get_inst_index,
+       .check_stop_free                = tcm_qla2xxx_check_stop_free,
        .release_cmd                    = tcm_qla2xxx_release_cmd,
        .put_session                    = tcm_qla2xxx_put_session,
        .shutdown_session               = tcm_qla2xxx_shutdown_session,
@@ -1871,7 +2006,8 @@ static int tcm_qla2xxx_register_configfs(void)
         * Setup default attribute lists for various npiv_fabric->tf_cit_tmpl
         */
        npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
-       npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;
+       npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs =
+           tcm_qla2xxx_npiv_tpg_attrs;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;