]> Pileus Git - ~andy/linux/blobdiff - drivers/scsi/qla2xxx/tcm_qla2xxx.c
ARM: at91: fix network interface ordering for sama5d36
[~andy/linux] / drivers / scsi / qla2xxx / tcm_qla2xxx.c
index 7eb19be35d461cfff2cc9f27897fd8b91bf8d17b..75a141bbe74d178834a9f58c6fc723734e63758f 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 */
@@ -777,6 +767,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);
 }
@@ -957,7 +950,6 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
        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;
@@ -977,12 +969,12 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
                atomic_set(&tpg->lport_tpg_enabled, 1);
                qlt_enable_vha(vha);
        } else {
-               if (!ha->tgt.qla_tgt) {
-                       pr_err("truct qla_hw_data *ha->tgt.qla_tgt is NULL\n");
+               if (!vha->vha_tgt.qla_tgt) {
+                       pr_err("struct qla_hw_data *vha->vha_tgt.qla_tgt is NULL\n");
                        return -ENODEV;
                }
                atomic_set(&tpg->lport_tpg_enabled, 0);
-               qlt_stop_phase1(ha->tgt.qla_tgt);
+               qlt_stop_phase1(vha->vha_tgt.qla_tgt);
        }
 
        return count;
@@ -1011,7 +1003,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 +1030,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,19 +1042,17 @@ 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;
 
        kfree(tpg);
@@ -1095,12 +1082,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 +1108,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 +1217,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 +1336,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 +1353,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 +1387,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 +1451,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 +1559,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 +1602,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 +1621,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 +1629,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 +1641,70 @@ 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 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;
+       }
+
+       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);
@@ -1666,12 +1718,19 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
                        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 +1740,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);
 }
 
@@ -1769,14 +1830,16 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
        .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 +1934,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_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;