diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-02-19 19:53:07 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-02-20 16:01:17 -0500 |
commit | 7474f52a82d51da2e6110e91bba8b000cb9cf803 (patch) | |
tree | 7ea5e1f43284aa10debb071398abd4c10178a956 | |
parent | 394d62ba4580a74afc90bf0e007e10291bf447cc (diff) |
tcm_qla2xxx: Perform configfs depend/undepend for base_tpg
This patch performs configfs_depend_item() during TPG enable for
base_tpg (eg: non-NPIV) ports, and configfs_undepend_item() during
TPG disable for base_tpg.
This is done to ensure that any attempt to configfs rmdir a base_tpg
with active NPIV ports will fail with -EBUSY, until all associated
NPIV ports have been explicitly shutdown and base_tpg disabled.
Note that the actual configfs_[un]depend_item() is done from seperate
process context, as these are not intended to be called directly
from configfs callbacks.
Cc: Sawan Chandak <sawan.chandak@qlogic.com>
Cc: Quinn Tran <quinn.tran@qlogic.com>
Cc: Saurav Kashyap <saurav.kashyap@qlogic.com>
Cc: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/scsi/qla2xxx/tcm_qla2xxx.c | 72 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/tcm_qla2xxx.h | 3 |
2 files changed, 61 insertions, 14 deletions
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index db43b2893525..5bdc44035981 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c | |||
@@ -941,15 +941,41 @@ static ssize_t tcm_qla2xxx_tpg_show_enable( | |||
941 | atomic_read(&tpg->lport_tpg_enabled)); | 941 | atomic_read(&tpg->lport_tpg_enabled)); |
942 | } | 942 | } |
943 | 943 | ||
944 | static void tcm_qla2xxx_depend_tpg(struct work_struct *work) | ||
945 | { | ||
946 | struct tcm_qla2xxx_tpg *base_tpg = container_of(work, | ||
947 | struct tcm_qla2xxx_tpg, tpg_base_work); | ||
948 | struct se_portal_group *se_tpg = &base_tpg->se_tpg; | ||
949 | struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha; | ||
950 | |||
951 | if (!configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys, | ||
952 | &se_tpg->tpg_group.cg_item)) { | ||
953 | atomic_set(&base_tpg->lport_tpg_enabled, 1); | ||
954 | qlt_enable_vha(base_vha); | ||
955 | } | ||
956 | complete(&base_tpg->tpg_base_comp); | ||
957 | } | ||
958 | |||
959 | static void tcm_qla2xxx_undepend_tpg(struct work_struct *work) | ||
960 | { | ||
961 | struct tcm_qla2xxx_tpg *base_tpg = container_of(work, | ||
962 | struct tcm_qla2xxx_tpg, tpg_base_work); | ||
963 | struct se_portal_group *se_tpg = &base_tpg->se_tpg; | ||
964 | struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha; | ||
965 | |||
966 | if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) { | ||
967 | atomic_set(&base_tpg->lport_tpg_enabled, 0); | ||
968 | configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys, | ||
969 | &se_tpg->tpg_group.cg_item); | ||
970 | } | ||
971 | complete(&base_tpg->tpg_base_comp); | ||
972 | } | ||
973 | |||
944 | static ssize_t tcm_qla2xxx_tpg_store_enable( | 974 | static ssize_t tcm_qla2xxx_tpg_store_enable( |
945 | struct se_portal_group *se_tpg, | 975 | struct se_portal_group *se_tpg, |
946 | const char *page, | 976 | const char *page, |
947 | size_t count) | 977 | size_t count) |
948 | { | 978 | { |
949 | struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; | ||
950 | struct tcm_qla2xxx_lport *lport = container_of(se_wwn, | ||
951 | struct tcm_qla2xxx_lport, lport_wwn); | ||
952 | struct scsi_qla_host *vha = lport->qla_vha; | ||
953 | struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, | 979 | struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, |
954 | struct tcm_qla2xxx_tpg, se_tpg); | 980 | struct tcm_qla2xxx_tpg, se_tpg); |
955 | unsigned long op; | 981 | unsigned long op; |
@@ -964,19 +990,28 @@ static ssize_t tcm_qla2xxx_tpg_store_enable( | |||
964 | pr_err("Illegal value for tpg_enable: %lu\n", op); | 990 | pr_err("Illegal value for tpg_enable: %lu\n", op); |
965 | return -EINVAL; | 991 | return -EINVAL; |
966 | } | 992 | } |
967 | |||
968 | if (op) { | 993 | if (op) { |
969 | atomic_set(&tpg->lport_tpg_enabled, 1); | 994 | if (atomic_read(&tpg->lport_tpg_enabled)) |
970 | qlt_enable_vha(vha); | 995 | return -EEXIST; |
996 | |||
997 | INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_depend_tpg); | ||
971 | } else { | 998 | } else { |
972 | if (!vha->vha_tgt.qla_tgt) { | 999 | if (!atomic_read(&tpg->lport_tpg_enabled)) |
973 | pr_err("struct qla_hw_data *vha->vha_tgt.qla_tgt is NULL\n"); | 1000 | return count; |
974 | return -ENODEV; | 1001 | |
975 | } | 1002 | INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_undepend_tpg); |
976 | atomic_set(&tpg->lport_tpg_enabled, 0); | ||
977 | qlt_stop_phase1(vha->vha_tgt.qla_tgt); | ||
978 | } | 1003 | } |
1004 | init_completion(&tpg->tpg_base_comp); | ||
1005 | schedule_work(&tpg->tpg_base_work); | ||
1006 | wait_for_completion(&tpg->tpg_base_comp); | ||
979 | 1007 | ||
1008 | if (op) { | ||
1009 | if (!atomic_read(&tpg->lport_tpg_enabled)) | ||
1010 | return -ENODEV; | ||
1011 | } else { | ||
1012 | if (atomic_read(&tpg->lport_tpg_enabled)) | ||
1013 | return -EPERM; | ||
1014 | } | ||
980 | return count; | 1015 | return count; |
981 | } | 1016 | } |
982 | 1017 | ||
@@ -1703,6 +1738,9 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, | |||
1703 | struct scsi_qla_host *npiv_vha; | 1738 | struct scsi_qla_host *npiv_vha; |
1704 | struct tcm_qla2xxx_lport *lport = | 1739 | struct tcm_qla2xxx_lport *lport = |
1705 | (struct tcm_qla2xxx_lport *)target_lport_ptr; | 1740 | (struct tcm_qla2xxx_lport *)target_lport_ptr; |
1741 | struct tcm_qla2xxx_lport *base_lport = | ||
1742 | (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr; | ||
1743 | struct tcm_qla2xxx_tpg *base_tpg; | ||
1706 | struct fc_vport_identifiers vport_id; | 1744 | struct fc_vport_identifiers vport_id; |
1707 | 1745 | ||
1708 | if (!qla_tgt_mode_enabled(base_vha)) { | 1746 | if (!qla_tgt_mode_enabled(base_vha)) { |
@@ -1710,6 +1748,13 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, | |||
1710 | return -EPERM; | 1748 | return -EPERM; |
1711 | } | 1749 | } |
1712 | 1750 | ||
1751 | if (!base_lport || !base_lport->tpg_1 || | ||
1752 | !atomic_read(&base_lport->tpg_1->lport_tpg_enabled)) { | ||
1753 | pr_err("qla2xxx base_lport or tpg_1 not available\n"); | ||
1754 | return -EPERM; | ||
1755 | } | ||
1756 | base_tpg = base_lport->tpg_1; | ||
1757 | |||
1713 | memset(&vport_id, 0, sizeof(vport_id)); | 1758 | memset(&vport_id, 0, sizeof(vport_id)); |
1714 | vport_id.port_name = npiv_wwpn; | 1759 | vport_id.port_name = npiv_wwpn; |
1715 | vport_id.node_name = npiv_wwnn; | 1760 | vport_id.node_name = npiv_wwnn; |
@@ -1728,7 +1773,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, | |||
1728 | npiv_vha = (struct scsi_qla_host *)vport->dd_data; | 1773 | npiv_vha = (struct scsi_qla_host *)vport->dd_data; |
1729 | npiv_vha->vha_tgt.target_lport_ptr = target_lport_ptr; | 1774 | npiv_vha->vha_tgt.target_lport_ptr = target_lport_ptr; |
1730 | lport->qla_vha = npiv_vha; | 1775 | lport->qla_vha = npiv_vha; |
1731 | |||
1732 | scsi_host_get(npiv_vha->host); | 1776 | scsi_host_get(npiv_vha->host); |
1733 | return 0; | 1777 | return 0; |
1734 | } | 1778 | } |
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h index 275d8b9a7a34..a90966d3c0d6 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h | |||
@@ -43,6 +43,9 @@ struct tcm_qla2xxx_tpg { | |||
43 | struct tcm_qla2xxx_tpg_attrib tpg_attrib; | 43 | struct tcm_qla2xxx_tpg_attrib tpg_attrib; |
44 | /* Returned by tcm_qla2xxx_make_tpg() */ | 44 | /* Returned by tcm_qla2xxx_make_tpg() */ |
45 | struct se_portal_group se_tpg; | 45 | struct se_portal_group se_tpg; |
46 | /* Items for dealing with configfs_depend_item */ | ||
47 | struct completion tpg_base_comp; | ||
48 | struct work_struct tpg_base_work; | ||
46 | }; | 49 | }; |
47 | 50 | ||
48 | struct tcm_qla2xxx_fc_loopid { | 51 | struct tcm_qla2xxx_fc_loopid { |