All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/11] scsi: target/core: Improve ALUA configuration for multi-node TCM
@ 2020-04-29  9:44 ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

Dear SCSI target developers,

The patch series is a backwards-compatible attempt to add flexibility and
consistency in ALUA configuration for multi-node TCM setups with multiple
target ports on each node. The series is based off 5.8/scsi-queue.

Patch 1 adds a way to hide default_tg_pt_gp. It is always returned in REPORT
TARGET PORT GROUP response in the current implementation even if there is no
need to report its presence.

Consider a backstore with non-default node1 that has target port group id 1.
If the group is assigned as a primary target port group to a LUN,
REPORT TARGET PORT GROUPS is going to return two groups:

T # echo node1 > $TARGET/tpgt_1/lun/lun_0/alua_tg_pt_gp
I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x0 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 00
  target port group id : 0x1 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x01

The patch adds a way to show only non-empty target port groups:

T # echo 1 > $BACKSTORE/alua/default_tg_pt_gp/hidden
I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x1 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x01

Patch 2 is a fix that improves SCSI conformance and sets MULTIP bit in the
standard inquiry data if a backstore is exported on multiple ports.

Patches 3 through 6 change RTPI allocation. They're aimed to tackle the
following misbehaviour.

SAM-5 4.6.5.2 (Relative Port Identifier attribute) defines the attribute
as unique across SCSI target ports.

The Relative Port Identifier attribute identifies a SCSI target port or
a SCSI initiator port relative to other SCSI ports in a SCSI target
device and any SCSI initiator devices contained within that SCSI target
device. A SCSI target device may assign relative port identifiers to its
SCSI target ports and any SCSI initiator ports. If relative port
identifiers are assigned, the SCSI target device shall assign each of
its SCSI target ports and any SCSI initiator ports a unique relative
port identifier from 1 to 65 535. SCSI target ports and SCSI initiator
ports share the same number space.

Examples of relative port identifiers usage are described in the
Device Identification VPD page, SCSI Ports VPD page and Reservations.
Relative port identifiers are not required to be contiguous.
Relative port identifier for a SCSI port shall not change once assigned unless
reconfiguration of the SCSI target device occurs.

In the current TCM implementation, auto-incremented lun_rtpi doesn't
follow the model outlined by SAM-5 and SPC-4. In case of multiple SCSI
target ports (se_portal_group's), which is common to scenario with
multiple HBAs or multiple iSCSI/FC targets, it's possible to have two
backstores (se_device's) with different values of lun_rtpi on the same
SCSI target port.

Consider we have backstores foo and bar and target ports A and B.
If foo is exported first on A and then on B but bar is exported on B and
then on A, we get the following:
  RTPI of foo on A is going to be 1, RTPI of bar on A is going to be 2
  RTPI of foo on B is going to be 2, RTPI of bar on B is going to be 1

Similar issue happens during re-export. If a LUN of a backstore is
removed from a target port and added again to the same target port, RTPI
is incremented again and will be different from the first time.

The two issues happen because each se_device increments RTPI for its own
LUNs independently.

The behaviour means that a SCSI application client can't reliably make any
sense of RTPI values reported by a LUN as it's not really related to SCSI
target ports. A conforming target implementation must ensure that RTPI field is
unique per port. The three patches resolve the issue.

Patches 7 and 8 add ability to set and read RTPI value for a target port after
initial configuration using configfs:

I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x1 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x01

T # echo 2 > $TARGET/tpgt_1/attrib/rtpi
I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x0 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x02

INQUIRY DATA HAS CHANGED unit attention is sent after RTPI change on all I_T
nexuses related to the port.

Patches 9 through 11 is a new feature that helps to return RTPI consistently on
all ports in a cluster running TCM. Together with previous RTPI changes, it
allows to assign RTPI values to a target port group that resides on the other
node and report it. Consider that node1 two primary target port groups, node1
and node2, with target port group id 1 and 2, respectively. node1 has real port
attached to it. node2 is a target portal group to represent state of the ports
on node2. Then it can be filled with fake peer ports using configfs:

T # mkdir $BACKSTORE/alua/node2/peers/2
I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x1 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x01
  target port group id : 0x2 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x02

And it's possible to have a similar config on node2 to report port groups
consistently regardless of where the command was received.

The patches also ensure that no LUN has duplicated RTPI values between SCSI
target ports and peer ports. Unfortunately, a global RTPI mutex had to be
introduced for that.

There are a few checkpatch.pl checks/warnings I had to keep to avoid breaking
80 char limit:
CHECK: Lines should not end with a '('
WARNING: quoted string split across lines

Thanks,
Roman

Roman Bolshakov (11):
  scsi: target/core: Add a way to hide a port group
  scsi: target/core: Set MULTIP bit for se_device with multiple ports
  scsi: target/core: Add cleanup sequence in core_tpg_register()
  scsi: target/core: Add RTPI field to target port
  scsi: target/core: Use RTPI from target port
  scsi: target/core: Drop device-based RTPI
  scsi: target/core: Add common port attributes
  scsi: target/core: Add RTPI attribute for target port
  scsi: target/core: Populate configfs for peer ports
  scsi: target/core: Prevent RTPI conflicts
  scsi: target/core: Show peer ports in RTPG response

 drivers/target/target_core_alua.c            |  44 +++-
 drivers/target/target_core_alua.h            |   1 +
 drivers/target/target_core_configfs.c        | 164 ++++++++++++-
 drivers/target/target_core_device.c          |  62 ++---
 drivers/target/target_core_fabric_configfs.c |  41 +++-
 drivers/target/target_core_internal.h        |   4 +-
 drivers/target/target_core_pr.c              |   8 +-
 drivers/target/target_core_spc.c             |  19 +-
 drivers/target/target_core_stat.c            |   6 +-
 drivers/target/target_core_tpg.c             | 246 +++++++++++++++++--
 drivers/target/target_core_transport.c       |  15 +-
 include/target/target_core_base.h            |  17 +-
 12 files changed, 549 insertions(+), 78 deletions(-)

-- 
2.26.1

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 00/11] scsi: target/core: Improve ALUA configuration for multi-node TCM
@ 2020-04-29  9:44 ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

Dear SCSI target developers,

The patch series is a backwards-compatible attempt to add flexibility and
consistency in ALUA configuration for multi-node TCM setups with multiple
target ports on each node. The series is based off 5.8/scsi-queue.

Patch 1 adds a way to hide default_tg_pt_gp. It is always returned in REPORT
TARGET PORT GROUP response in the current implementation even if there is no
need to report its presence.

Consider a backstore with non-default node1 that has target port group id 1.
If the group is assigned as a primary target port group to a LUN,
REPORT TARGET PORT GROUPS is going to return two groups:

T # echo node1 > $TARGET/tpgt_1/lun/lun_0/alua_tg_pt_gp
I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x0 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 00
  target port group id : 0x1 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x01

The patch adds a way to show only non-empty target port groups:

T # echo 1 > $BACKSTORE/alua/default_tg_pt_gp/hidden
I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x1 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x01

Patch 2 is a fix that improves SCSI conformance and sets MULTIP bit in the
standard inquiry data if a backstore is exported on multiple ports.

Patches 3 through 6 change RTPI allocation. They're aimed to tackle the
following misbehaviour.

SAM-5 4.6.5.2 (Relative Port Identifier attribute) defines the attribute
as unique across SCSI target ports.

The Relative Port Identifier attribute identifies a SCSI target port or
a SCSI initiator port relative to other SCSI ports in a SCSI target
device and any SCSI initiator devices contained within that SCSI target
device. A SCSI target device may assign relative port identifiers to its
SCSI target ports and any SCSI initiator ports. If relative port
identifiers are assigned, the SCSI target device shall assign each of
its SCSI target ports and any SCSI initiator ports a unique relative
port identifier from 1 to 65 535. SCSI target ports and SCSI initiator
ports share the same number space.

Examples of relative port identifiers usage are described in the
Device Identification VPD page, SCSI Ports VPD page and Reservations.
Relative port identifiers are not required to be contiguous.
Relative port identifier for a SCSI port shall not change once assigned unless
reconfiguration of the SCSI target device occurs.

In the current TCM implementation, auto-incremented lun_rtpi doesn't
follow the model outlined by SAM-5 and SPC-4. In case of multiple SCSI
target ports (se_portal_group's), which is common to scenario with
multiple HBAs or multiple iSCSI/FC targets, it's possible to have two
backstores (se_device's) with different values of lun_rtpi on the same
SCSI target port.

Consider we have backstores foo and bar and target ports A and B.
If foo is exported first on A and then on B but bar is exported on B and
then on A, we get the following:
  RTPI of foo on A is going to be 1, RTPI of bar on A is going to be 2
  RTPI of foo on B is going to be 2, RTPI of bar on B is going to be 1

Similar issue happens during re-export. If a LUN of a backstore is
removed from a target port and added again to the same target port, RTPI
is incremented again and will be different from the first time.

The two issues happen because each se_device increments RTPI for its own
LUNs independently.

The behaviour means that a SCSI application client can't reliably make any
sense of RTPI values reported by a LUN as it's not really related to SCSI
target ports. A conforming target implementation must ensure that RTPI field is
unique per port. The three patches resolve the issue.

Patches 7 and 8 add ability to set and read RTPI value for a target port after
initial configuration using configfs:

I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x1 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x01

T # echo 2 > $TARGET/tpgt_1/attrib/rtpi
I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x0 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x02

INQUIRY DATA HAS CHANGED unit attention is sent after RTPI change on all I_T
nexuses related to the port.

Patches 9 through 11 is a new feature that helps to return RTPI consistently on
all ports in a cluster running TCM. Together with previous RTPI changes, it
allows to assign RTPI values to a target port group that resides on the other
node and report it. Consider that node1 two primary target port groups, node1
and node2, with target port group id 1 and 2, respectively. node1 has real port
attached to it. node2 is a target portal group to represent state of the ports
on node2. Then it can be filled with fake peer ports using configfs:

T # mkdir $BACKSTORE/alua/node2/peers/2
I # sg_rtpg /dev/sda
Report target port groups:
  target port group id : 0x1 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x01
  target port group id : 0x2 , Pref=0, Rtpg_fmt=0
    target port group asymmetric access state : 0x00
    T_SUP : 1, O_SUP : 1, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
    status code : 0x00
    vendor unique status : 0x00
    target port count : 01
    Relative target port ids:
      0x02

And it's possible to have a similar config on node2 to report port groups
consistently regardless of where the command was received.

The patches also ensure that no LUN has duplicated RTPI values between SCSI
target ports and peer ports. Unfortunately, a global RTPI mutex had to be
introduced for that.

There are a few checkpatch.pl checks/warnings I had to keep to avoid breaking
80 char limit:
CHECK: Lines should not end with a '('
WARNING: quoted string split across lines

Thanks,
Roman

Roman Bolshakov (11):
  scsi: target/core: Add a way to hide a port group
  scsi: target/core: Set MULTIP bit for se_device with multiple ports
  scsi: target/core: Add cleanup sequence in core_tpg_register()
  scsi: target/core: Add RTPI field to target port
  scsi: target/core: Use RTPI from target port
  scsi: target/core: Drop device-based RTPI
  scsi: target/core: Add common port attributes
  scsi: target/core: Add RTPI attribute for target port
  scsi: target/core: Populate configfs for peer ports
  scsi: target/core: Prevent RTPI conflicts
  scsi: target/core: Show peer ports in RTPG response

 drivers/target/target_core_alua.c            |  44 +++-
 drivers/target/target_core_alua.h            |   1 +
 drivers/target/target_core_configfs.c        | 164 ++++++++++++-
 drivers/target/target_core_device.c          |  62 ++---
 drivers/target/target_core_fabric_configfs.c |  41 +++-
 drivers/target/target_core_internal.h        |   4 +-
 drivers/target/target_core_pr.c              |   8 +-
 drivers/target/target_core_spc.c             |  19 +-
 drivers/target/target_core_stat.c            |   6 +-
 drivers/target/target_core_tpg.c             | 246 +++++++++++++++++--
 drivers/target/target_core_transport.c       |  15 +-
 include/target/target_core_base.h            |  17 +-
 12 files changed, 549 insertions(+), 78 deletions(-)

-- 
2.26.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH 01/11] scsi: target/core: Add a way to hide a port group
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

Default target port group is always returned in the list of port groups,
even if the behaviour is unwanted, i.e. it has no members and
non-default port groups are primary port groups.

A new port group attribute - "hidden" can be used to hide empty port
groups with no ports in REPORT TARGET PORT GROUPS, including default
target port group:

  echo 1 > $DEVICE/alua/default_tg_pt_gp/hidden

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_alua.c     |  9 +++++++++
 drivers/target/target_core_configfs.c | 29 +++++++++++++++++++++++++++
 include/target/target_core_base.h     |  1 +
 3 files changed, 39 insertions(+)

diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 385e4cf9cfa6..b98a5b5fce49 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -164,6 +164,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
 	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
 			tg_pt_gp_list) {
+		if (tg_pt_gp->tg_pt_gp_hidden && !tg_pt_gp->tg_pt_gp_members)
+			continue;
 		/*
 		 * Check if the Target port group and Target port descriptor list
 		 * based on tg_pt_gp_members count will fit into the response payload.
@@ -308,6 +310,13 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
 		rc = TCM_UNSUPPORTED_SCSI_OPCODE;
 		goto out;
 	}
+	if (l_tg_pt_gp->tg_pt_gp_hidden && !tg_pt_gp->tg_pt_gp_members) {
+		spin_unlock(&l_lun->lun_tg_pt_gp_lock);
+		pr_err("Unable to change state for hidden port group"
+		       " with no members\n");
+		rc = TCM_INVALID_CDB_FIELD;
+		goto out;
+	}
 	valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
 	spin_unlock(&l_lun->lun_tg_pt_gp_lock);
 
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index ff82b21fdcce..42390ce9d4db 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -2908,6 +2908,33 @@ static ssize_t target_tg_pt_gp_preferred_store(struct config_item *item,
 	return core_alua_store_preferred_bit(to_tg_pt_gp(item), page, count);
 }
 
+static ssize_t target_tg_pt_gp_hidden_show(struct config_item *item,
+					   char *page)
+{
+	return sprintf(page, "%d\n", to_tg_pt_gp(item)->tg_pt_gp_hidden);
+}
+
+static ssize_t target_tg_pt_gp_hidden_store(struct config_item *item,
+					    const char *page, size_t count)
+{
+	struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item);
+	int tmp, ret;
+
+	ret = kstrtoint(page, 0, &tmp);
+	if (ret < 0) {
+		pr_err("Unable to extract hidden flag: %d\n", ret);
+		return ret;
+	}
+
+	if (tmp != 0 && tmp != 1) {
+		pr_err("Illegal value for hidden flag: %d\n", tmp);
+		return -EINVAL;
+	}
+	tg_pt_gp->tg_pt_gp_hidden = tmp;
+
+	return count;
+}
+
 static ssize_t target_tg_pt_gp_tg_pt_gp_id_show(struct config_item *item,
 		char *page)
 {
@@ -2996,6 +3023,7 @@ CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_standby);
 CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_active_optimized);
 CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_active_nonoptimized);
 CONFIGFS_ATTR(target_tg_pt_gp_, alua_write_metadata);
+CONFIGFS_ATTR(target_tg_pt_gp_, hidden);
 CONFIGFS_ATTR(target_tg_pt_gp_, nonop_delay_msecs);
 CONFIGFS_ATTR(target_tg_pt_gp_, trans_delay_msecs);
 CONFIGFS_ATTR(target_tg_pt_gp_, implicit_trans_secs);
@@ -3019,6 +3047,7 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {
 	&target_tg_pt_gp_attr_trans_delay_msecs,
 	&target_tg_pt_gp_attr_implicit_trans_secs,
 	&target_tg_pt_gp_attr_preferred,
+	&target_tg_pt_gp_attr_hidden,
 	&target_tg_pt_gp_attr_tg_pt_gp_id,
 	&target_tg_pt_gp_attr_members,
 	NULL,
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 6d4a694f6ea7..922b3086e408 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -292,6 +292,7 @@ struct t10_alua_tg_pt_gp {
 	int	tg_pt_gp_trans_delay_msecs;
 	int	tg_pt_gp_implicit_trans_secs;
 	int	tg_pt_gp_pref;
+	int	tg_pt_gp_hidden;
 	int	tg_pt_gp_write_metadata;
 	u32	tg_pt_gp_members;
 	int	tg_pt_gp_alua_access_state;
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 01/11] scsi: target/core: Add a way to hide a port group
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

Default target port group is always returned in the list of port groups,
even if the behaviour is unwanted, i.e. it has no members and
non-default port groups are primary port groups.

A new port group attribute - "hidden" can be used to hide empty port
groups with no ports in REPORT TARGET PORT GROUPS, including default
target port group:

  echo 1 > $DEVICE/alua/default_tg_pt_gp/hidden

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_alua.c     |  9 +++++++++
 drivers/target/target_core_configfs.c | 29 +++++++++++++++++++++++++++
 include/target/target_core_base.h     |  1 +
 3 files changed, 39 insertions(+)

diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 385e4cf9cfa6..b98a5b5fce49 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -164,6 +164,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
 	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
 			tg_pt_gp_list) {
+		if (tg_pt_gp->tg_pt_gp_hidden && !tg_pt_gp->tg_pt_gp_members)
+			continue;
 		/*
 		 * Check if the Target port group and Target port descriptor list
 		 * based on tg_pt_gp_members count will fit into the response payload.
@@ -308,6 +310,13 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
 		rc = TCM_UNSUPPORTED_SCSI_OPCODE;
 		goto out;
 	}
+	if (l_tg_pt_gp->tg_pt_gp_hidden && !tg_pt_gp->tg_pt_gp_members) {
+		spin_unlock(&l_lun->lun_tg_pt_gp_lock);
+		pr_err("Unable to change state for hidden port group"
+		       " with no members\n");
+		rc = TCM_INVALID_CDB_FIELD;
+		goto out;
+	}
 	valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
 	spin_unlock(&l_lun->lun_tg_pt_gp_lock);
 
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index ff82b21fdcce..42390ce9d4db 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -2908,6 +2908,33 @@ static ssize_t target_tg_pt_gp_preferred_store(struct config_item *item,
 	return core_alua_store_preferred_bit(to_tg_pt_gp(item), page, count);
 }
 
+static ssize_t target_tg_pt_gp_hidden_show(struct config_item *item,
+					   char *page)
+{
+	return sprintf(page, "%d\n", to_tg_pt_gp(item)->tg_pt_gp_hidden);
+}
+
+static ssize_t target_tg_pt_gp_hidden_store(struct config_item *item,
+					    const char *page, size_t count)
+{
+	struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item);
+	int tmp, ret;
+
+	ret = kstrtoint(page, 0, &tmp);
+	if (ret < 0) {
+		pr_err("Unable to extract hidden flag: %d\n", ret);
+		return ret;
+	}
+
+	if (tmp != 0 && tmp != 1) {
+		pr_err("Illegal value for hidden flag: %d\n", tmp);
+		return -EINVAL;
+	}
+	tg_pt_gp->tg_pt_gp_hidden = tmp;
+
+	return count;
+}
+
 static ssize_t target_tg_pt_gp_tg_pt_gp_id_show(struct config_item *item,
 		char *page)
 {
@@ -2996,6 +3023,7 @@ CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_standby);
 CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_active_optimized);
 CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_active_nonoptimized);
 CONFIGFS_ATTR(target_tg_pt_gp_, alua_write_metadata);
+CONFIGFS_ATTR(target_tg_pt_gp_, hidden);
 CONFIGFS_ATTR(target_tg_pt_gp_, nonop_delay_msecs);
 CONFIGFS_ATTR(target_tg_pt_gp_, trans_delay_msecs);
 CONFIGFS_ATTR(target_tg_pt_gp_, implicit_trans_secs);
@@ -3019,6 +3047,7 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {
 	&target_tg_pt_gp_attr_trans_delay_msecs,
 	&target_tg_pt_gp_attr_implicit_trans_secs,
 	&target_tg_pt_gp_attr_preferred,
+	&target_tg_pt_gp_attr_hidden,
 	&target_tg_pt_gp_attr_tg_pt_gp_id,
 	&target_tg_pt_gp_attr_members,
 	NULL,
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 6d4a694f6ea7..922b3086e408 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -292,6 +292,7 @@ struct t10_alua_tg_pt_gp {
 	int	tg_pt_gp_trans_delay_msecs;
 	int	tg_pt_gp_implicit_trans_secs;
 	int	tg_pt_gp_pref;
+	int	tg_pt_gp_hidden;
 	int	tg_pt_gp_write_metadata;
 	u32	tg_pt_gp_members;
 	int	tg_pt_gp_alua_access_state;
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 02/11] scsi: target/core: Set MULTIP bit for se_device with multiple ports
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov, Konstantin Vinogradov, Ivan Efremov

SAM-5 4.8.3 (SCSI target device with multiple SCSI ports structure)
obligates to set MULTIP bit when there's multiple SCSI target ports:

> Each device server shall indicate the presence of multiple SCSI target
> ports by setting the MULTIP bit to one in its standard INQUIRY data
> (see SPC-4).

The change sets MULTIP bit automatically to indicate the presence of
multiple SCSI target ports within standard inquiry response data if
there are multiple target ports in all target port groups of the
se_device.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
Signed-off-by: Konstantin Vinogradov <k.vinogradov@yadro.com>
Signed-off-by: Ivan Efremov <i.efremov@yadro.com>
---
 drivers/target/target_core_spc.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index ca5579ebc81d..633dee9ac877 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -53,6 +53,8 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
 	struct se_lun *lun = cmd->se_lun;
 	struct se_device *dev = cmd->se_dev;
 	struct se_session *sess = cmd->se_sess;
+	struct t10_alua_tg_pt_gp *tg_pt_gp;
+	u64 dev_ports = 0;
 
 	/* Set RMB (removable media) for tape devices */
 	if (dev->transport->get_device_type(dev) = TYPE_TAPE)
@@ -93,6 +95,21 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
 			buf[5] |= 0x1;
 	}
 
+	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
+			    tg_pt_gp_list) {
+		dev_ports += tg_pt_gp->tg_pt_gp_members;
+		/* Exact number of ports does not matter for MULTIP bit */
+		if (dev_ports > 1)
+			break;
+	}
+	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+	/*
+	 * Set MULTIP bit to indicate presence of multiple SCSI target ports
+	 */
+	if (dev_ports > 1)
+		buf[6] |= 0x10;
+
 	buf[7] = 0x2; /* CmdQue=1 */
 
 	/*
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 02/11] scsi: target/core: Set MULTIP bit for se_device with multiple ports
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov, Konstantin Vinogradov, Ivan Efremov

SAM-5 4.8.3 (SCSI target device with multiple SCSI ports structure)
obligates to set MULTIP bit when there's multiple SCSI target ports:

> Each device server shall indicate the presence of multiple SCSI target
> ports by setting the MULTIP bit to one in its standard INQUIRY data
> (see SPC-4).

The change sets MULTIP bit automatically to indicate the presence of
multiple SCSI target ports within standard inquiry response data if
there are multiple target ports in all target port groups of the
se_device.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
Signed-off-by: Konstantin Vinogradov <k.vinogradov@yadro.com>
Signed-off-by: Ivan Efremov <i.efremov@yadro.com>
---
 drivers/target/target_core_spc.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index ca5579ebc81d..633dee9ac877 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -53,6 +53,8 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
 	struct se_lun *lun = cmd->se_lun;
 	struct se_device *dev = cmd->se_dev;
 	struct se_session *sess = cmd->se_sess;
+	struct t10_alua_tg_pt_gp *tg_pt_gp;
+	u64 dev_ports = 0;
 
 	/* Set RMB (removable media) for tape devices */
 	if (dev->transport->get_device_type(dev) == TYPE_TAPE)
@@ -93,6 +95,21 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
 			buf[5] |= 0x1;
 	}
 
+	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
+			    tg_pt_gp_list) {
+		dev_ports += tg_pt_gp->tg_pt_gp_members;
+		/* Exact number of ports does not matter for MULTIP bit */
+		if (dev_ports > 1)
+			break;
+	}
+	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+	/*
+	 * Set MULTIP bit to indicate presence of multiple SCSI target ports
+	 */
+	if (dev_ports > 1)
+		buf[6] |= 0x10;
+
 	buf[7] = 0x2; /* CmdQue=1 */
 
 	/*
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 03/11] scsi: target/core: Add cleanup sequence in core_tpg_register()
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

It does not change any functionality but allows to introduce more steps
in the cleanup sequence without code duplication later.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_tpg.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index d24e0a3ba3ff..d3896c3f2f95 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -484,10 +484,8 @@ int core_tpg_register(
 
 		ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0,
 				true, g_lun0_dev);
-		if (ret < 0) {
-			kfree(se_tpg->tpg_virt_lun0);
-			return ret;
-		}
+		if (ret < 0)
+			goto out_free_lun0;
 	}
 
 	pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, "
@@ -497,6 +495,10 @@ int core_tpg_register(
 		se_tpg->proto_id, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg));
 
 	return 0;
+
+out_free_lun0:
+	kfree(se_tpg->tpg_virt_lun0);
+	return ret;
 }
 EXPORT_SYMBOL(core_tpg_register);
 
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 03/11] scsi: target/core: Add cleanup sequence in core_tpg_register()
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

It does not change any functionality but allows to introduce more steps
in the cleanup sequence without code duplication later.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_tpg.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index d24e0a3ba3ff..d3896c3f2f95 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -484,10 +484,8 @@ int core_tpg_register(
 
 		ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0,
 				true, g_lun0_dev);
-		if (ret < 0) {
-			kfree(se_tpg->tpg_virt_lun0);
-			return ret;
-		}
+		if (ret < 0)
+			goto out_free_lun0;
 	}
 
 	pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, "
@@ -497,6 +495,10 @@ int core_tpg_register(
 		se_tpg->proto_id, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg));
 
 	return 0;
+
+out_free_lun0:
+	kfree(se_tpg->tpg_virt_lun0);
+	return ret;
 }
 EXPORT_SYMBOL(core_tpg_register);
 
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 04/11] scsi: target/core: Add RTPI field to target port
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

SAM-5 4.6.5.2 (Relative Port Identifier attribute) defines the attribute
as unique across SCSI target ports.

The change introduces RTPI attribute to se_portal group. The value is
auto-incremented and unique across all SCSI target ports. It also limits
number of SCSI target ports to 65535.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_tpg.c  | 80 +++++++++++++++++++++++++++++--
 include/target/target_core_base.h |  4 ++
 2 files changed, 80 insertions(+), 4 deletions(-)

diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index d3896c3f2f95..e9f6b0aadbcf 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -31,6 +31,10 @@
 #include "target_core_ua.h"
 
 extern struct se_device *g_lun0_dev;
+static u16 g_tpg_count;
+static u16 g_tpg_rtpi_counter = 1;
+static LIST_HEAD(g_tpg_list);
+static DEFINE_MUTEX(g_tpg_mutex);
 
 /*	__core_tpg_get_initiator_node_acl():
  *
@@ -439,6 +443,60 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref)
 	complete(&lun->lun_shutdown_comp);
 }
 
+static int core_tpg_register_rtpi(struct se_portal_group *se_tpg)
+{
+	struct se_portal_group *tpg;
+	int ret;
+
+	/*
+	 * Allocate the next RELATIVE TARGET PORT IDENTIFIER.
+	 * Here is the table from SPC-4 4.3.4:
+	 *
+	 *    Table 34 -- Relative target port identifier values
+	 *
+	 * Value		Description
+	 * 0h			Reserved
+	 * 1h			Relative port 1, historically known as port A
+	 * 2h			Relative port 2, historically known as port B
+	 * 3h to FFFFh		Relative port 3 through 65 535
+	 */
+	ret = mutex_lock_interruptible(&g_tpg_mutex);
+	if (ret < 0)
+		return ret;
+
+	if (g_tpg_count = 0xffff) {
+		mutex_unlock(&g_tpg_mutex);
+		pr_warn("Reached g_tpg_count = 0xffff\n");
+		return -ENOSPC;
+	}
+again:
+	se_tpg->tpg_rtpi = g_tpg_rtpi_counter++;
+	if (!se_tpg->tpg_rtpi)
+		goto again;
+
+	list_for_each_entry(tpg, &g_tpg_list, tpg_list) {
+		/*
+		 * Make sure RELATIVE TARGET PORT IDENTIFIER is unique
+		 * for 16-bit wrap..
+		 */
+		if (se_tpg->tpg_rtpi = tpg->tpg_rtpi)
+			goto again;
+	}
+	list_add(&se_tpg->tpg_list, &g_tpg_list);
+	g_tpg_count++;
+	mutex_unlock(&g_tpg_mutex);
+
+	return 0;
+}
+
+static void core_tpg_deregister_rtpi(struct se_portal_group *se_tpg)
+{
+	mutex_lock(&g_tpg_mutex);
+	list_del(&se_tpg->tpg_list);
+	g_tpg_count--;
+	mutex_unlock(&g_tpg_mutex);
+}
+
 /* Does not change se_wwn->priv. */
 int core_tpg_register(
 	struct se_wwn *se_wwn,
@@ -471,6 +529,7 @@ int core_tpg_register(
 	se_tpg->proto_id = proto_id;
 	se_tpg->se_tpg_wwn = se_wwn;
 	atomic_set(&se_tpg->tpg_pr_ref_count, 0);
+	INIT_LIST_HEAD(&se_tpg->tpg_list);
 	INIT_LIST_HEAD(&se_tpg->acl_node_list);
 	INIT_LIST_HEAD(&se_tpg->tpg_sess_list);
 	spin_lock_init(&se_tpg->session_lock);
@@ -478,9 +537,15 @@ int core_tpg_register(
 	mutex_init(&se_tpg->acl_node_mutex);
 
 	if (se_tpg->proto_id >= 0) {
+		ret = core_tpg_register_rtpi(se_tpg);
+		if (ret < 0)
+			return ret;
+
 		se_tpg->tpg_virt_lun0 = core_tpg_alloc_lun(se_tpg, 0);
-		if (IS_ERR(se_tpg->tpg_virt_lun0))
-			return PTR_ERR(se_tpg->tpg_virt_lun0);
+		if (IS_ERR(se_tpg->tpg_virt_lun0)) {
+			ret = PTR_ERR(se_tpg->tpg_virt_lun0);
+			goto out_deregister_rtpi;
+		}
 
 		ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0,
 				true, g_lun0_dev);
@@ -489,15 +554,20 @@ int core_tpg_register(
 	}
 
 	pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, "
-		 "Proto: %d, Portal Tag: %u\n", se_tpg->se_tpg_tfo->fabric_name,
+		 "Proto: %d, Portal Tag: %u, RTPI: %#2x\n",
+		se_tpg->se_tpg_tfo->fabric_name,
 		se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) ?
 		se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) : NULL,
-		se_tpg->proto_id, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg));
+		se_tpg->proto_id,
+		se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg),
+		se_tpg->tpg_rtpi);
 
 	return 0;
 
 out_free_lun0:
 	kfree(se_tpg->tpg_virt_lun0);
+out_deregister_rtpi:
+	core_tpg_deregister_rtpi(se_tpg);
 	return ret;
 }
 EXPORT_SYMBOL(core_tpg_register);
@@ -537,6 +607,8 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
 		kfree_rcu(se_tpg->tpg_virt_lun0, rcu_head);
 	}
 
+	core_tpg_deregister_rtpi(se_tpg);
+
 	return 0;
 }
 EXPORT_SYMBOL(core_tpg_deregister);
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 922b3086e408..cd7c29f46acc 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -875,6 +875,8 @@ struct se_portal_group {
 	 * Negative values can be used by fabric drivers for internal use TPGs.
 	 */
 	int			proto_id;
+	/* RELATIVE TARGET PORT IDENTIFIER */
+	u16			tpg_rtpi;
 	/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
 	atomic_t		tpg_pr_ref_count;
 	/* Spinlock for adding/removing ACLed Nodes */
@@ -882,6 +884,8 @@ struct se_portal_group {
 	/* Spinlock for adding/removing sessions */
 	spinlock_t		session_lock;
 	struct mutex		tpg_lun_mutex;
+	/* List of all SCSI target ports */
+	struct list_head	tpg_list;
 	/* linked list for initiator ACL list */
 	struct list_head	acl_node_list;
 	struct hlist_head	tpg_lun_hlist;
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 04/11] scsi: target/core: Add RTPI field to target port
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

SAM-5 4.6.5.2 (Relative Port Identifier attribute) defines the attribute
as unique across SCSI target ports.

The change introduces RTPI attribute to se_portal group. The value is
auto-incremented and unique across all SCSI target ports. It also limits
number of SCSI target ports to 65535.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_tpg.c  | 80 +++++++++++++++++++++++++++++--
 include/target/target_core_base.h |  4 ++
 2 files changed, 80 insertions(+), 4 deletions(-)

diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index d3896c3f2f95..e9f6b0aadbcf 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -31,6 +31,10 @@
 #include "target_core_ua.h"
 
 extern struct se_device *g_lun0_dev;
+static u16 g_tpg_count;
+static u16 g_tpg_rtpi_counter = 1;
+static LIST_HEAD(g_tpg_list);
+static DEFINE_MUTEX(g_tpg_mutex);
 
 /*	__core_tpg_get_initiator_node_acl():
  *
@@ -439,6 +443,60 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref)
 	complete(&lun->lun_shutdown_comp);
 }
 
+static int core_tpg_register_rtpi(struct se_portal_group *se_tpg)
+{
+	struct se_portal_group *tpg;
+	int ret;
+
+	/*
+	 * Allocate the next RELATIVE TARGET PORT IDENTIFIER.
+	 * Here is the table from SPC-4 4.3.4:
+	 *
+	 *    Table 34 -- Relative target port identifier values
+	 *
+	 * Value		Description
+	 * 0h			Reserved
+	 * 1h			Relative port 1, historically known as port A
+	 * 2h			Relative port 2, historically known as port B
+	 * 3h to FFFFh		Relative port 3 through 65 535
+	 */
+	ret = mutex_lock_interruptible(&g_tpg_mutex);
+	if (ret < 0)
+		return ret;
+
+	if (g_tpg_count == 0xffff) {
+		mutex_unlock(&g_tpg_mutex);
+		pr_warn("Reached g_tpg_count == 0xffff\n");
+		return -ENOSPC;
+	}
+again:
+	se_tpg->tpg_rtpi = g_tpg_rtpi_counter++;
+	if (!se_tpg->tpg_rtpi)
+		goto again;
+
+	list_for_each_entry(tpg, &g_tpg_list, tpg_list) {
+		/*
+		 * Make sure RELATIVE TARGET PORT IDENTIFIER is unique
+		 * for 16-bit wrap..
+		 */
+		if (se_tpg->tpg_rtpi == tpg->tpg_rtpi)
+			goto again;
+	}
+	list_add(&se_tpg->tpg_list, &g_tpg_list);
+	g_tpg_count++;
+	mutex_unlock(&g_tpg_mutex);
+
+	return 0;
+}
+
+static void core_tpg_deregister_rtpi(struct se_portal_group *se_tpg)
+{
+	mutex_lock(&g_tpg_mutex);
+	list_del(&se_tpg->tpg_list);
+	g_tpg_count--;
+	mutex_unlock(&g_tpg_mutex);
+}
+
 /* Does not change se_wwn->priv. */
 int core_tpg_register(
 	struct se_wwn *se_wwn,
@@ -471,6 +529,7 @@ int core_tpg_register(
 	se_tpg->proto_id = proto_id;
 	se_tpg->se_tpg_wwn = se_wwn;
 	atomic_set(&se_tpg->tpg_pr_ref_count, 0);
+	INIT_LIST_HEAD(&se_tpg->tpg_list);
 	INIT_LIST_HEAD(&se_tpg->acl_node_list);
 	INIT_LIST_HEAD(&se_tpg->tpg_sess_list);
 	spin_lock_init(&se_tpg->session_lock);
@@ -478,9 +537,15 @@ int core_tpg_register(
 	mutex_init(&se_tpg->acl_node_mutex);
 
 	if (se_tpg->proto_id >= 0) {
+		ret = core_tpg_register_rtpi(se_tpg);
+		if (ret < 0)
+			return ret;
+
 		se_tpg->tpg_virt_lun0 = core_tpg_alloc_lun(se_tpg, 0);
-		if (IS_ERR(se_tpg->tpg_virt_lun0))
-			return PTR_ERR(se_tpg->tpg_virt_lun0);
+		if (IS_ERR(se_tpg->tpg_virt_lun0)) {
+			ret = PTR_ERR(se_tpg->tpg_virt_lun0);
+			goto out_deregister_rtpi;
+		}
 
 		ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0,
 				true, g_lun0_dev);
@@ -489,15 +554,20 @@ int core_tpg_register(
 	}
 
 	pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, "
-		 "Proto: %d, Portal Tag: %u\n", se_tpg->se_tpg_tfo->fabric_name,
+		 "Proto: %d, Portal Tag: %u, RTPI: %#2x\n",
+		se_tpg->se_tpg_tfo->fabric_name,
 		se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) ?
 		se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) : NULL,
-		se_tpg->proto_id, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg));
+		se_tpg->proto_id,
+		se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg),
+		se_tpg->tpg_rtpi);
 
 	return 0;
 
 out_free_lun0:
 	kfree(se_tpg->tpg_virt_lun0);
+out_deregister_rtpi:
+	core_tpg_deregister_rtpi(se_tpg);
 	return ret;
 }
 EXPORT_SYMBOL(core_tpg_register);
@@ -537,6 +607,8 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
 		kfree_rcu(se_tpg->tpg_virt_lun0, rcu_head);
 	}
 
+	core_tpg_deregister_rtpi(se_tpg);
+
 	return 0;
 }
 EXPORT_SYMBOL(core_tpg_deregister);
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 922b3086e408..cd7c29f46acc 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -875,6 +875,8 @@ struct se_portal_group {
 	 * Negative values can be used by fabric drivers for internal use TPGs.
 	 */
 	int			proto_id;
+	/* RELATIVE TARGET PORT IDENTIFIER */
+	u16			tpg_rtpi;
 	/* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
 	atomic_t		tpg_pr_ref_count;
 	/* Spinlock for adding/removing ACLed Nodes */
@@ -882,6 +884,8 @@ struct se_portal_group {
 	/* Spinlock for adding/removing sessions */
 	spinlock_t		session_lock;
 	struct mutex		tpg_lun_mutex;
+	/* List of all SCSI target ports */
+	struct list_head	tpg_list;
 	/* linked list for initiator ACL list */
 	struct list_head	acl_node_list;
 	struct hlist_head	tpg_lun_hlist;
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 05/11] scsi: target/core: Use RTPI from target port
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

Replace all references to RTPI from LUN field to se_portal_group field.
It introduces consitent reporting of RTPI for all LUNs and all target
ports.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_alua.c   | 4 ++--
 drivers/target/target_core_device.c | 2 +-
 drivers/target/target_core_pr.c     | 8 ++++----
 drivers/target/target_core_spc.c    | 2 +-
 drivers/target/target_core_stat.c   | 6 +++---
 5 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index b98a5b5fce49..8053f3989bbb 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -224,7 +224,7 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 			/*
 			 * Set RELATIVE TARGET PORT IDENTIFIER
 			 */
-			put_unaligned_be16(lun->lun_rtpi, &buf[off]);
+			put_unaligned_be16(lun->lun_tpg->tpg_rtpi, &buf[off]);
 			off += 2;
 			rd_len += 4;
 		}
@@ -405,7 +405,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
 			spin_lock(&dev->se_port_lock);
 			list_for_each_entry(lun, &dev->dev_sep_list,
 							lun_dev_link) {
-				if (lun->lun_rtpi != rtpi)
+				if (lun->lun_tpg->tpg_rtpi != rtpi)
 					continue;
 
 				// XXX: racy unlock
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 4cee1138284b..cb4d8cc4ff45 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -227,7 +227,7 @@ struct se_dev_entry *core_get_se_deve_from_rtpi(
 				tpg->se_tpg_tfo->fabric_name);
 			continue;
 		}
-		if (lun->lun_rtpi != rtpi)
+		if (lun->lun_tpg->tpg_rtpi != rtpi)
 			continue;
 
 		kref_get(&deve->pr_kref);
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 5e931690e697..87af494c4e75 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -662,7 +662,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration(
 	}
 	pr_reg->pr_res_mapped_lun = mapped_lun;
 	pr_reg->pr_aptpl_target_lun = lun->unpacked_lun;
-	pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi;
+	pr_reg->tg_pt_sep_rtpi = lun->lun_tpg->tpg_rtpi;
 	pr_reg->pr_res_key = sa_res_key;
 	pr_reg->pr_reg_all_tg_pt = all_tg_pt;
 	pr_reg->pr_reg_aptpl = aptpl;
@@ -971,7 +971,7 @@ static int __core_scsi3_check_aptpl_registration(
 			rcu_read_unlock();
 
 			pr_reg->pr_reg_nacl = nacl;
-			pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi;
+			pr_reg->tg_pt_sep_rtpi = lun->lun_tpg->tpg_rtpi;
 			list_del(&pr_reg->pr_reg_aptpl_list);
 			spin_unlock(&pr_tmpl->aptpl_reg_lock);
 			/*
@@ -1589,7 +1589,7 @@ core_scsi3_decode_spec_i_port(
 			 */
 			if (tmp_tpg->proto_id != proto_ident)
 				continue;
-			dest_rtpi = tmp_lun->lun_rtpi;
+			dest_rtpi = tmp_lun->lun_tpg->tpg_rtpi;
 
 			i_str = target_parse_pr_out_transport_id(tmp_tpg,
 					ptr, &tid_len, &iport_ptr);
@@ -3225,7 +3225,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
 
 	spin_lock(&dev->se_port_lock);
 	list_for_each_entry(tmp_lun, &dev->dev_sep_list, lun_dev_link) {
-		if (tmp_lun->lun_rtpi != rtpi)
+		if (tmp_lun->lun_tpg->tpg_rtpi != rtpi)
 			continue;
 		dest_se_tpg = tmp_lun->lun_tpg;
 		dest_tf_ops = dest_se_tpg->se_tpg_tfo;
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 633dee9ac877..0b276c79fdba 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -301,7 +301,7 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
 		/* Skip over Obsolete field in RTPI payload
 		 * in Table 472 */
 		off += 2;
-		put_unaligned_be16(lun->lun_rtpi, &buf[off]);
+		put_unaligned_be16(lun->lun_tpg->tpg_rtpi, &buf[off]);
 		off += 2;
 		len += 8; /* Header size + Designation descriptor */
 		/*
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index 237309db4b33..9d5a2bc43d4e 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -458,7 +458,7 @@ static ssize_t target_stat_port_indx_show(struct config_item *item, char *page)
 	rcu_read_lock();
 	dev = rcu_dereference(lun->lun_se_dev);
 	if (dev)
-		ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi);
+		ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_tpg->tpg_rtpi);
 	rcu_read_unlock();
 	return ret;
 }
@@ -564,7 +564,7 @@ static ssize_t target_stat_tgt_port_indx_show(struct config_item *item,
 	rcu_read_lock();
 	dev = rcu_dereference(lun->lun_se_dev);
 	if (dev)
-		ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi);
+		ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_tpg->tpg_rtpi);
 	rcu_read_unlock();
 	return ret;
 }
@@ -582,7 +582,7 @@ static ssize_t target_stat_tgt_port_name_show(struct config_item *item,
 	if (dev)
 		ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n",
 			tpg->se_tpg_tfo->fabric_name,
-			lun->lun_rtpi);
+			lun->lun_tpg->tpg_rtpi);
 	rcu_read_unlock();
 	return ret;
 }
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 05/11] scsi: target/core: Use RTPI from target port
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

Replace all references to RTPI from LUN field to se_portal_group field.
It introduces consitent reporting of RTPI for all LUNs and all target
ports.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_alua.c   | 4 ++--
 drivers/target/target_core_device.c | 2 +-
 drivers/target/target_core_pr.c     | 8 ++++----
 drivers/target/target_core_spc.c    | 2 +-
 drivers/target/target_core_stat.c   | 6 +++---
 5 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index b98a5b5fce49..8053f3989bbb 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -224,7 +224,7 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 			/*
 			 * Set RELATIVE TARGET PORT IDENTIFIER
 			 */
-			put_unaligned_be16(lun->lun_rtpi, &buf[off]);
+			put_unaligned_be16(lun->lun_tpg->tpg_rtpi, &buf[off]);
 			off += 2;
 			rd_len += 4;
 		}
@@ -405,7 +405,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
 			spin_lock(&dev->se_port_lock);
 			list_for_each_entry(lun, &dev->dev_sep_list,
 							lun_dev_link) {
-				if (lun->lun_rtpi != rtpi)
+				if (lun->lun_tpg->tpg_rtpi != rtpi)
 					continue;
 
 				// XXX: racy unlock
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 4cee1138284b..cb4d8cc4ff45 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -227,7 +227,7 @@ struct se_dev_entry *core_get_se_deve_from_rtpi(
 				tpg->se_tpg_tfo->fabric_name);
 			continue;
 		}
-		if (lun->lun_rtpi != rtpi)
+		if (lun->lun_tpg->tpg_rtpi != rtpi)
 			continue;
 
 		kref_get(&deve->pr_kref);
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 5e931690e697..87af494c4e75 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -662,7 +662,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration(
 	}
 	pr_reg->pr_res_mapped_lun = mapped_lun;
 	pr_reg->pr_aptpl_target_lun = lun->unpacked_lun;
-	pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi;
+	pr_reg->tg_pt_sep_rtpi = lun->lun_tpg->tpg_rtpi;
 	pr_reg->pr_res_key = sa_res_key;
 	pr_reg->pr_reg_all_tg_pt = all_tg_pt;
 	pr_reg->pr_reg_aptpl = aptpl;
@@ -971,7 +971,7 @@ static int __core_scsi3_check_aptpl_registration(
 			rcu_read_unlock();
 
 			pr_reg->pr_reg_nacl = nacl;
-			pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi;
+			pr_reg->tg_pt_sep_rtpi = lun->lun_tpg->tpg_rtpi;
 			list_del(&pr_reg->pr_reg_aptpl_list);
 			spin_unlock(&pr_tmpl->aptpl_reg_lock);
 			/*
@@ -1589,7 +1589,7 @@ core_scsi3_decode_spec_i_port(
 			 */
 			if (tmp_tpg->proto_id != proto_ident)
 				continue;
-			dest_rtpi = tmp_lun->lun_rtpi;
+			dest_rtpi = tmp_lun->lun_tpg->tpg_rtpi;
 
 			i_str = target_parse_pr_out_transport_id(tmp_tpg,
 					ptr, &tid_len, &iport_ptr);
@@ -3225,7 +3225,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
 
 	spin_lock(&dev->se_port_lock);
 	list_for_each_entry(tmp_lun, &dev->dev_sep_list, lun_dev_link) {
-		if (tmp_lun->lun_rtpi != rtpi)
+		if (tmp_lun->lun_tpg->tpg_rtpi != rtpi)
 			continue;
 		dest_se_tpg = tmp_lun->lun_tpg;
 		dest_tf_ops = dest_se_tpg->se_tpg_tfo;
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 633dee9ac877..0b276c79fdba 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -301,7 +301,7 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
 		/* Skip over Obsolete field in RTPI payload
 		 * in Table 472 */
 		off += 2;
-		put_unaligned_be16(lun->lun_rtpi, &buf[off]);
+		put_unaligned_be16(lun->lun_tpg->tpg_rtpi, &buf[off]);
 		off += 2;
 		len += 8; /* Header size + Designation descriptor */
 		/*
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index 237309db4b33..9d5a2bc43d4e 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -458,7 +458,7 @@ static ssize_t target_stat_port_indx_show(struct config_item *item, char *page)
 	rcu_read_lock();
 	dev = rcu_dereference(lun->lun_se_dev);
 	if (dev)
-		ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi);
+		ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_tpg->tpg_rtpi);
 	rcu_read_unlock();
 	return ret;
 }
@@ -564,7 +564,7 @@ static ssize_t target_stat_tgt_port_indx_show(struct config_item *item,
 	rcu_read_lock();
 	dev = rcu_dereference(lun->lun_se_dev);
 	if (dev)
-		ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi);
+		ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_tpg->tpg_rtpi);
 	rcu_read_unlock();
 	return ret;
 }
@@ -582,7 +582,7 @@ static ssize_t target_stat_tgt_port_name_show(struct config_item *item,
 	if (dev)
 		ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n",
 			tpg->se_tpg_tfo->fabric_name,
-			lun->lun_rtpi);
+			lun->lun_tpg->tpg_rtpi);
 	rcu_read_unlock();
 	return ret;
 }
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 06/11] scsi: target/core: Drop device-based RTPI
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

The code is not needed since target port-based RTPI allocation replaced
it.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_device.c   | 41 ---------------------------
 drivers/target/target_core_internal.h |  1 -
 drivers/target/target_core_tpg.c      |  6 ----
 include/target/target_core_base.h     |  4 ---
 4 files changed, 52 deletions(-)

diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index cb4d8cc4ff45..24d358f942b8 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -474,47 +474,6 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg)
 	mutex_unlock(&tpg->acl_node_mutex);
 }
 
-int core_alloc_rtpi(struct se_lun *lun, struct se_device *dev)
-{
-	struct se_lun *tmp;
-
-	spin_lock(&dev->se_port_lock);
-	if (dev->export_count = 0x0000ffff) {
-		pr_warn("Reached dev->dev_port_count ="
-				" 0x0000ffff\n");
-		spin_unlock(&dev->se_port_lock);
-		return -ENOSPC;
-	}
-again:
-	/*
-	 * Allocate the next RELATIVE TARGET PORT IDENTIFIER for this struct se_device
-	 * Here is the table from spc4r17 section 7.7.3.8.
-	 *
-	 *    Table 473 -- RELATIVE TARGET PORT IDENTIFIER field
-	 *
-	 * Code      Description
-	 * 0h        Reserved
-	 * 1h        Relative port 1, historically known as port A
-	 * 2h        Relative port 2, historically known as port B
-	 * 3h to FFFFh    Relative port 3 through 65 535
-	 */
-	lun->lun_rtpi = dev->dev_rpti_counter++;
-	if (!lun->lun_rtpi)
-		goto again;
-
-	list_for_each_entry(tmp, &dev->dev_sep_list, lun_dev_link) {
-		/*
-		 * Make sure RELATIVE TARGET PORT IDENTIFIER is unique
-		 * for 16-bit wrap..
-		 */
-		if (lun->lun_rtpi = tmp->lun_rtpi)
-			goto again;
-	}
-	spin_unlock(&dev->se_port_lock);
-
-	return 0;
-}
-
 static void se_release_vpd_for_dev(struct se_device *dev)
 {
 	struct t10_vpd *vpd, *vpd_tmp;
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index 853344415963..aed38c9705f8 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -58,7 +58,6 @@ struct target_fabric_configfs {
 extern struct t10_alua_lu_gp *default_lu_gp;
 
 /* target_core_device.c */
-int	core_alloc_rtpi(struct se_lun *lun, struct se_device *dev);
 struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
 void	target_pr_kref_release(struct kref *);
 void	core_free_device_list_for_node(struct se_node_acl *,
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index e9f6b0aadbcf..32bc28afe93c 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -652,10 +652,6 @@ int core_tpg_add_lun(
 	if (ret < 0)
 		goto out;
 
-	ret = core_alloc_rtpi(lun, dev);
-	if (ret)
-		goto out_kill_ref;
-
 	if (!(dev->transport->transport_flags &
 	     TRANSPORT_FLAG_PASSTHROUGH_ALUA) &&
 	    !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
@@ -680,8 +676,6 @@ int core_tpg_add_lun(
 
 	return 0;
 
-out_kill_ref:
-	percpu_ref_exit(&lun->lun_ref);
 out:
 	return ret;
 }
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index cd7c29f46acc..cde2f986e9c0 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -724,8 +724,6 @@ struct se_lun {
 	bool			lun_access_ro;
 	u32			lun_index;
 
-	/* RELATIVE TARGET PORT IDENTIFER */
-	u16			lun_rtpi;
 	atomic_t		lun_acl_count;
 	struct se_device __rcu	*lun_se_dev;
 
@@ -762,8 +760,6 @@ struct se_dev_stat_grps {
 };
 
 struct se_device {
-	/* RELATIVE TARGET PORT IDENTIFER Counter */
-	u16			dev_rpti_counter;
 	/* Used for SAM Task Attribute ordering */
 	u32			dev_cur_ordered_id;
 	u32			dev_flags;
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 06/11] scsi: target/core: Drop device-based RTPI
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

The code is not needed since target port-based RTPI allocation replaced
it.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_device.c   | 41 ---------------------------
 drivers/target/target_core_internal.h |  1 -
 drivers/target/target_core_tpg.c      |  6 ----
 include/target/target_core_base.h     |  4 ---
 4 files changed, 52 deletions(-)

diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index cb4d8cc4ff45..24d358f942b8 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -474,47 +474,6 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg)
 	mutex_unlock(&tpg->acl_node_mutex);
 }
 
-int core_alloc_rtpi(struct se_lun *lun, struct se_device *dev)
-{
-	struct se_lun *tmp;
-
-	spin_lock(&dev->se_port_lock);
-	if (dev->export_count == 0x0000ffff) {
-		pr_warn("Reached dev->dev_port_count =="
-				" 0x0000ffff\n");
-		spin_unlock(&dev->se_port_lock);
-		return -ENOSPC;
-	}
-again:
-	/*
-	 * Allocate the next RELATIVE TARGET PORT IDENTIFIER for this struct se_device
-	 * Here is the table from spc4r17 section 7.7.3.8.
-	 *
-	 *    Table 473 -- RELATIVE TARGET PORT IDENTIFIER field
-	 *
-	 * Code      Description
-	 * 0h        Reserved
-	 * 1h        Relative port 1, historically known as port A
-	 * 2h        Relative port 2, historically known as port B
-	 * 3h to FFFFh    Relative port 3 through 65 535
-	 */
-	lun->lun_rtpi = dev->dev_rpti_counter++;
-	if (!lun->lun_rtpi)
-		goto again;
-
-	list_for_each_entry(tmp, &dev->dev_sep_list, lun_dev_link) {
-		/*
-		 * Make sure RELATIVE TARGET PORT IDENTIFIER is unique
-		 * for 16-bit wrap..
-		 */
-		if (lun->lun_rtpi == tmp->lun_rtpi)
-			goto again;
-	}
-	spin_unlock(&dev->se_port_lock);
-
-	return 0;
-}
-
 static void se_release_vpd_for_dev(struct se_device *dev)
 {
 	struct t10_vpd *vpd, *vpd_tmp;
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index 853344415963..aed38c9705f8 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -58,7 +58,6 @@ struct target_fabric_configfs {
 extern struct t10_alua_lu_gp *default_lu_gp;
 
 /* target_core_device.c */
-int	core_alloc_rtpi(struct se_lun *lun, struct se_device *dev);
 struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
 void	target_pr_kref_release(struct kref *);
 void	core_free_device_list_for_node(struct se_node_acl *,
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index e9f6b0aadbcf..32bc28afe93c 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -652,10 +652,6 @@ int core_tpg_add_lun(
 	if (ret < 0)
 		goto out;
 
-	ret = core_alloc_rtpi(lun, dev);
-	if (ret)
-		goto out_kill_ref;
-
 	if (!(dev->transport->transport_flags &
 	     TRANSPORT_FLAG_PASSTHROUGH_ALUA) &&
 	    !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
@@ -680,8 +676,6 @@ int core_tpg_add_lun(
 
 	return 0;
 
-out_kill_ref:
-	percpu_ref_exit(&lun->lun_ref);
 out:
 	return ret;
 }
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index cd7c29f46acc..cde2f986e9c0 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -724,8 +724,6 @@ struct se_lun {
 	bool			lun_access_ro;
 	u32			lun_index;
 
-	/* RELATIVE TARGET PORT IDENTIFER */
-	u16			lun_rtpi;
 	atomic_t		lun_acl_count;
 	struct se_device __rcu	*lun_se_dev;
 
@@ -762,8 +760,6 @@ struct se_dev_stat_grps {
 };
 
 struct se_device {
-	/* RELATIVE TARGET PORT IDENTIFER Counter */
-	u16			dev_rpti_counter;
 	/* Used for SAM Task Attribute ordering */
 	u32			dev_cur_ordered_id;
 	u32			dev_flags;
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 07/11] scsi: target/core: Add common port attributes
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

All SCSI target port attributes (tpgN/attribs/attrname) are defined and
implemented in fabric modules in existing implementation.

The change introduces a way to have common tpg attribs in configfs for
all fabrics without code duplication.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_configfs.c        |  9 ++++-
 drivers/target/target_core_fabric_configfs.c | 41 +++++++++++++++++++-
 drivers/target/target_core_internal.h        |  1 +
 drivers/target/target_core_tpg.c             |  4 ++
 4 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 42390ce9d4db..3311d29ecad8 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -464,13 +464,19 @@ int target_register_template(const struct target_core_fabric_ops *fo)
 	INIT_LIST_HEAD(&tf->tf_list);
 	atomic_set(&tf->tf_access_cnt, 0);
 	tf->tf_ops = fo;
-	target_fabric_setup_cits(tf);
+	ret = target_fabric_setup_cits(tf);
+	if (ret)
+		goto out;
 
 	mutex_lock(&g_tf_lock);
 	list_add_tail(&tf->tf_list, &g_tf_list);
 	mutex_unlock(&g_tf_lock);
 
 	return 0;
+
+out:
+	kfree(tf);
+	return ret;
 }
 EXPORT_SYMBOL(target_register_template);
 
@@ -490,6 +496,7 @@ void target_unregister_template(const struct target_core_fabric_ops *fo)
 			 * fabric driver unload of TFO->module to proceed.
 			 */
 			rcu_barrier();
+			kfree(t->tf_tpg_attrib_cit.ct_attrs);
 			kfree(t);
 			return;
 		}
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index ee85602213f7..883ec9cac835 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -795,7 +795,38 @@ TF_CIT_SETUP(tpg_lun, NULL, &target_fabric_lun_group_ops, NULL);
 
 /* End of tfc_tpg_lun_cit */
 
-TF_CIT_SETUP_DRV(tpg_attrib, NULL, NULL);
+static int
+target_fabric_setup_tpg_attrib_cit(struct target_fabric_configfs *tf)
+{
+	int i, k, len = 0;
+	struct config_item_type *cit = &tf->tf_tpg_attrib_cit;
+	struct configfs_attribute **attrs;
+
+	for (i = 0; core_tpg_attrib_attrs[i]; i++)
+		len += sizeof(struct configfs_attribute *);
+	if (tf->tf_ops->tfc_tpg_attrib_attrs)
+		for (i = 0; tf->tf_ops->tfc_tpg_attrib_attrs[i]; i++)
+			len += sizeof(struct configfs_attribute *);
+	len += sizeof(struct configfs_attribute *);
+
+	attrs = kzalloc(len, GFP_KERNEL);
+	if (!attrs)
+		return -ENOMEM;
+
+	for (i = 0; core_tpg_attrib_attrs[i]; i++)
+		attrs[i] = core_tpg_attrib_attrs[i];
+	if (tf->tf_ops->tfc_tpg_attrib_attrs)
+		for (k = 0; tf->tf_ops->tfc_tpg_attrib_attrs[k]; k++, i++)
+			attrs[i] = tf->tf_ops->tfc_tpg_attrib_attrs[k];
+	attrs[i] = NULL;
+
+	cit->ct_attrs = attrs;
+	cit->ct_owner = tf->tf_ops->module;
+	pr_debug("Setup generic tpg_attrib\n");
+
+	return 0;
+}
+
 TF_CIT_SETUP_DRV(tpg_auth, NULL, NULL);
 TF_CIT_SETUP_DRV(tpg_param, NULL, NULL);
 
@@ -971,6 +1002,8 @@ TF_CIT_SETUP_DRV(discovery, NULL, NULL);
 
 int target_fabric_setup_cits(struct target_fabric_configfs *tf)
 {
+	int ret;
+
 	target_fabric_setup_discovery_cit(tf);
 	target_fabric_setup_wwn_cit(tf);
 	target_fabric_setup_wwn_fabric_stats_cit(tf);
@@ -981,7 +1014,11 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf)
 	target_fabric_setup_tpg_lun_cit(tf);
 	target_fabric_setup_tpg_np_cit(tf);
 	target_fabric_setup_tpg_np_base_cit(tf);
-	target_fabric_setup_tpg_attrib_cit(tf);
+
+	ret = target_fabric_setup_tpg_attrib_cit(tf);
+	if (ret)
+		return ret;
+
 	target_fabric_setup_tpg_auth_cit(tf);
 	target_fabric_setup_tpg_param_cit(tf);
 	target_fabric_setup_tpg_nacl_cit(tf);
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index aed38c9705f8..e1aabb79467a 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -116,6 +116,7 @@ int	core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
 
 /* target_core_tpg.c */
 extern struct se_device *g_lun0_dev;
+extern struct configfs_attribute *core_tpg_attrib_attrs[];
 
 struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
 		const char *);
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 32bc28afe93c..67474690720d 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -719,3 +719,7 @@ void core_tpg_remove_lun(
 
 	percpu_ref_exit(&lun->lun_ref);
 }
+
+struct configfs_attribute *core_tpg_attrib_attrs[] = {
+	NULL,
+};
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 07/11] scsi: target/core: Add common port attributes
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

All SCSI target port attributes (tpgN/attribs/attrname) are defined and
implemented in fabric modules in existing implementation.

The change introduces a way to have common tpg attribs in configfs for
all fabrics without code duplication.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_configfs.c        |  9 ++++-
 drivers/target/target_core_fabric_configfs.c | 41 +++++++++++++++++++-
 drivers/target/target_core_internal.h        |  1 +
 drivers/target/target_core_tpg.c             |  4 ++
 4 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 42390ce9d4db..3311d29ecad8 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -464,13 +464,19 @@ int target_register_template(const struct target_core_fabric_ops *fo)
 	INIT_LIST_HEAD(&tf->tf_list);
 	atomic_set(&tf->tf_access_cnt, 0);
 	tf->tf_ops = fo;
-	target_fabric_setup_cits(tf);
+	ret = target_fabric_setup_cits(tf);
+	if (ret)
+		goto out;
 
 	mutex_lock(&g_tf_lock);
 	list_add_tail(&tf->tf_list, &g_tf_list);
 	mutex_unlock(&g_tf_lock);
 
 	return 0;
+
+out:
+	kfree(tf);
+	return ret;
 }
 EXPORT_SYMBOL(target_register_template);
 
@@ -490,6 +496,7 @@ void target_unregister_template(const struct target_core_fabric_ops *fo)
 			 * fabric driver unload of TFO->module to proceed.
 			 */
 			rcu_barrier();
+			kfree(t->tf_tpg_attrib_cit.ct_attrs);
 			kfree(t);
 			return;
 		}
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index ee85602213f7..883ec9cac835 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -795,7 +795,38 @@ TF_CIT_SETUP(tpg_lun, NULL, &target_fabric_lun_group_ops, NULL);
 
 /* End of tfc_tpg_lun_cit */
 
-TF_CIT_SETUP_DRV(tpg_attrib, NULL, NULL);
+static int
+target_fabric_setup_tpg_attrib_cit(struct target_fabric_configfs *tf)
+{
+	int i, k, len = 0;
+	struct config_item_type *cit = &tf->tf_tpg_attrib_cit;
+	struct configfs_attribute **attrs;
+
+	for (i = 0; core_tpg_attrib_attrs[i]; i++)
+		len += sizeof(struct configfs_attribute *);
+	if (tf->tf_ops->tfc_tpg_attrib_attrs)
+		for (i = 0; tf->tf_ops->tfc_tpg_attrib_attrs[i]; i++)
+			len += sizeof(struct configfs_attribute *);
+	len += sizeof(struct configfs_attribute *);
+
+	attrs = kzalloc(len, GFP_KERNEL);
+	if (!attrs)
+		return -ENOMEM;
+
+	for (i = 0; core_tpg_attrib_attrs[i]; i++)
+		attrs[i] = core_tpg_attrib_attrs[i];
+	if (tf->tf_ops->tfc_tpg_attrib_attrs)
+		for (k = 0; tf->tf_ops->tfc_tpg_attrib_attrs[k]; k++, i++)
+			attrs[i] = tf->tf_ops->tfc_tpg_attrib_attrs[k];
+	attrs[i] = NULL;
+
+	cit->ct_attrs = attrs;
+	cit->ct_owner = tf->tf_ops->module;
+	pr_debug("Setup generic tpg_attrib\n");
+
+	return 0;
+}
+
 TF_CIT_SETUP_DRV(tpg_auth, NULL, NULL);
 TF_CIT_SETUP_DRV(tpg_param, NULL, NULL);
 
@@ -971,6 +1002,8 @@ TF_CIT_SETUP_DRV(discovery, NULL, NULL);
 
 int target_fabric_setup_cits(struct target_fabric_configfs *tf)
 {
+	int ret;
+
 	target_fabric_setup_discovery_cit(tf);
 	target_fabric_setup_wwn_cit(tf);
 	target_fabric_setup_wwn_fabric_stats_cit(tf);
@@ -981,7 +1014,11 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf)
 	target_fabric_setup_tpg_lun_cit(tf);
 	target_fabric_setup_tpg_np_cit(tf);
 	target_fabric_setup_tpg_np_base_cit(tf);
-	target_fabric_setup_tpg_attrib_cit(tf);
+
+	ret = target_fabric_setup_tpg_attrib_cit(tf);
+	if (ret)
+		return ret;
+
 	target_fabric_setup_tpg_auth_cit(tf);
 	target_fabric_setup_tpg_param_cit(tf);
 	target_fabric_setup_tpg_nacl_cit(tf);
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index aed38c9705f8..e1aabb79467a 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -116,6 +116,7 @@ int	core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
 
 /* target_core_tpg.c */
 extern struct se_device *g_lun0_dev;
+extern struct configfs_attribute *core_tpg_attrib_attrs[];
 
 struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
 		const char *);
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 32bc28afe93c..67474690720d 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -719,3 +719,7 @@ void core_tpg_remove_lun(
 
 	percpu_ref_exit(&lun->lun_ref);
 }
+
+struct configfs_attribute *core_tpg_attrib_attrs[] = {
+	NULL,
+};
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 08/11] scsi: target/core: Add RTPI attribute for target port
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

RELATIVE TARGET PORT IDENTIFIER can be read and configured via configfs:
$ echo 0x10 > $TARGET/tpgt_N/attrib/rtpi

RTPI has to be unique among all target ports, otherwise the write fails.

Configuration of a new RTPI value triggers INQUIRY DATA HAS CHANGED unit
attention as defined in SPC-4 "6.6.1 INQUIRY command introduction":

> If INQUIRY data changes for any reason, the device server shall
> establish a unit attention condition for the initiator port associated
> with every I_T nexus (see SAM-5), with the additional sense code set to
> INQUIRY DATA HAS CHANGED.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_tpg.c | 69 ++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 67474690720d..c0d564f17951 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -720,6 +720,75 @@ void core_tpg_remove_lun(
 	percpu_ref_exit(&lun->lun_ref);
 }
 
+/* Set a Unit Attention on all I_T nexuses related to the port */
+static void core_tpg_ua(struct se_portal_group *se_tpg, u8 asc, u8 ascq)
+{
+	struct se_lun *lun;
+	struct se_dev_entry *se_deve;
+
+	mutex_lock(&se_tpg->tpg_lun_mutex);
+	hlist_for_each_entry_rcu(lun, &se_tpg->tpg_lun_hlist, link) {
+		spin_lock(&lun->lun_deve_lock);
+		list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link)
+			core_scsi3_ua_allocate(se_deve, asc, ascq);
+		spin_unlock(&lun->lun_deve_lock);
+	}
+	mutex_unlock(&se_tpg->tpg_lun_mutex);
+}
+
+static ssize_t core_tpg_rtpi_show(struct config_item *item, char *page)
+{
+	struct se_portal_group *se_tpg = attrib_to_tpg(item);
+
+	return sprintf(page, "%#x\n", se_tpg->tpg_rtpi);
+}
+
+static ssize_t core_tpg_rtpi_store(struct config_item *item,
+				   const char *page, size_t count)
+{
+	struct se_portal_group *se_tpg = attrib_to_tpg(item);
+	struct se_portal_group *tpg;
+	u16 val;
+	int ret;
+
+	ret = kstrtou16(page, 0, &val);
+	if (ret < 0)
+		return ret;
+	if (val = 0)
+		return -EINVAL;
+
+	/* RTPI shouldn't conflict with values of existing ports */
+	ret = mutex_lock_interruptible(&g_tpg_mutex);
+	if (ret < 0)
+		return ret;
+
+	list_for_each_entry(tpg, &g_tpg_list, tpg_list) {
+		if (se_tpg != tpg && val = tpg->tpg_rtpi) {
+			pr_err("TARGET_CORE[%s]->TPG[%u] - RTPI %#x conflicts"
+			       " with TARGET_CORE[%s]->TPG[%u]\n",
+			       se_tpg->se_tpg_tfo->fabric_name,
+			       se_tpg->se_tpg_tfo->tpg_get_tag(tpg),
+			       val,
+			       tpg->se_tpg_tfo->fabric_name,
+			       tpg->se_tpg_tfo->tpg_get_tag(tpg));
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	if (se_tpg->tpg_rtpi != val) {
+		se_tpg->tpg_rtpi = val;
+		core_tpg_ua(se_tpg, 0x3f, ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED);
+	}
+	ret = count;
+out:
+	mutex_unlock(&g_tpg_mutex);
+	return ret;
+}
+
+CONFIGFS_ATTR(core_tpg_, rtpi);
+
 struct configfs_attribute *core_tpg_attrib_attrs[] = {
+	&core_tpg_attr_rtpi,
 	NULL,
 };
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 08/11] scsi: target/core: Add RTPI attribute for target port
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

RELATIVE TARGET PORT IDENTIFIER can be read and configured via configfs:
$ echo 0x10 > $TARGET/tpgt_N/attrib/rtpi

RTPI has to be unique among all target ports, otherwise the write fails.

Configuration of a new RTPI value triggers INQUIRY DATA HAS CHANGED unit
attention as defined in SPC-4 "6.6.1 INQUIRY command introduction":

> If INQUIRY data changes for any reason, the device server shall
> establish a unit attention condition for the initiator port associated
> with every I_T nexus (see SAM-5), with the additional sense code set to
> INQUIRY DATA HAS CHANGED.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_tpg.c | 69 ++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 67474690720d..c0d564f17951 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -720,6 +720,75 @@ void core_tpg_remove_lun(
 	percpu_ref_exit(&lun->lun_ref);
 }
 
+/* Set a Unit Attention on all I_T nexuses related to the port */
+static void core_tpg_ua(struct se_portal_group *se_tpg, u8 asc, u8 ascq)
+{
+	struct se_lun *lun;
+	struct se_dev_entry *se_deve;
+
+	mutex_lock(&se_tpg->tpg_lun_mutex);
+	hlist_for_each_entry_rcu(lun, &se_tpg->tpg_lun_hlist, link) {
+		spin_lock(&lun->lun_deve_lock);
+		list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link)
+			core_scsi3_ua_allocate(se_deve, asc, ascq);
+		spin_unlock(&lun->lun_deve_lock);
+	}
+	mutex_unlock(&se_tpg->tpg_lun_mutex);
+}
+
+static ssize_t core_tpg_rtpi_show(struct config_item *item, char *page)
+{
+	struct se_portal_group *se_tpg = attrib_to_tpg(item);
+
+	return sprintf(page, "%#x\n", se_tpg->tpg_rtpi);
+}
+
+static ssize_t core_tpg_rtpi_store(struct config_item *item,
+				   const char *page, size_t count)
+{
+	struct se_portal_group *se_tpg = attrib_to_tpg(item);
+	struct se_portal_group *tpg;
+	u16 val;
+	int ret;
+
+	ret = kstrtou16(page, 0, &val);
+	if (ret < 0)
+		return ret;
+	if (val == 0)
+		return -EINVAL;
+
+	/* RTPI shouldn't conflict with values of existing ports */
+	ret = mutex_lock_interruptible(&g_tpg_mutex);
+	if (ret < 0)
+		return ret;
+
+	list_for_each_entry(tpg, &g_tpg_list, tpg_list) {
+		if (se_tpg != tpg && val == tpg->tpg_rtpi) {
+			pr_err("TARGET_CORE[%s]->TPG[%u] - RTPI %#x conflicts"
+			       " with TARGET_CORE[%s]->TPG[%u]\n",
+			       se_tpg->se_tpg_tfo->fabric_name,
+			       se_tpg->se_tpg_tfo->tpg_get_tag(tpg),
+			       val,
+			       tpg->se_tpg_tfo->fabric_name,
+			       tpg->se_tpg_tfo->tpg_get_tag(tpg));
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	if (se_tpg->tpg_rtpi != val) {
+		se_tpg->tpg_rtpi = val;
+		core_tpg_ua(se_tpg, 0x3f, ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED);
+	}
+	ret = count;
+out:
+	mutex_unlock(&g_tpg_mutex);
+	return ret;
+}
+
+CONFIGFS_ATTR(core_tpg_, rtpi);
+
 struct configfs_attribute *core_tpg_attrib_attrs[] = {
+	&core_tpg_attr_rtpi,
 	NULL,
 };
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 09/11] scsi: target/core: Populate configfs for peer ports
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

TCM can't report about ports of peer node in REPORT TARGET PORT GROUPS
command if TCM is used in a cluster. The change introduces a way to
store information about such ports in configfs.

Each port group except default_tg_pt_gp has "peers" subdirectory. It can
be used to store RTPI (RELATIVE TARGET PORT IDENTIFIER) of SCSI target
ports that reside on peer nodes:

  mkdir $BACKSTORE/alua/pg1/peers/$RTPI

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_alua.c      |  1 +
 drivers/target/target_core_alua.h      |  1 +
 drivers/target/target_core_configfs.c  | 86 ++++++++++++++++++++++++++
 drivers/target/target_core_transport.c | 15 ++++-
 include/target/target_core_base.h      |  8 +++
 5 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 8053f3989bbb..81ed79500376 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -1650,6 +1650,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev,
 	}
 	INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list);
 	INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_lun_list);
+	INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_peer_list);
 	mutex_init(&tg_pt_gp->tg_pt_gp_transition_mutex);
 	spin_lock_init(&tg_pt_gp->tg_pt_gp_lock);
 	atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0);
diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h
index fc9637cce825..bc6d47ed93e8 100644
--- a/drivers/target/target_core_alua.h
+++ b/drivers/target/target_core_alua.h
@@ -79,6 +79,7 @@
 extern struct kmem_cache *t10_alua_lu_gp_cache;
 extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
 extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
+extern struct kmem_cache *t10_alua_tg_pt_gp_peer_cache;
 extern struct kmem_cache *t10_alua_lba_map_cache;
 extern struct kmem_cache *t10_alua_lba_map_mem_cache;
 
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 3311d29ecad8..803e968659e3 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -3078,6 +3078,87 @@ static const struct config_item_type target_core_alua_tg_pt_gp_cit = {
 	.ct_owner		= THIS_MODULE,
 };
 
+static void target_core_alua_tg_pt_gp_peer_release(struct config_item *item)
+{
+	struct t10_alua_tg_pt_gp_peer *peer_port = container_of(item,
+			struct t10_alua_tg_pt_gp_peer, tg_pt_gp_peer_item);
+	kmem_cache_free(t10_alua_tg_pt_gp_peer_cache, peer_port);
+}
+
+static struct configfs_item_operations target_core_alua_tg_pt_gp_peer_ops = {
+	.release		= target_core_alua_tg_pt_gp_peer_release,
+};
+
+static struct config_item_type target_core_alua_tg_pt_gp_peer_cit = {
+	.ct_item_ops		= &target_core_alua_tg_pt_gp_peer_ops,
+	.ct_owner		= THIS_MODULE,
+};
+
+static struct config_item *
+target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
+				     const char *name)
+{
+	struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(group,
+			struct t10_alua_tg_pt_gp, tg_pt_gp_peers_group);
+	struct t10_alua_tg_pt_gp_peer *peer_port;
+	u16 val;
+	int ret;
+
+	peer_port = kmem_cache_zalloc(t10_alua_tg_pt_gp_peer_cache, GFP_KERNEL);
+	if (!peer_port) {
+		pr_err("Unable to allocate struct t10_alua_tg_pt_gp_peer\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	INIT_LIST_HEAD(&peer_port->tg_pt_gp_peer_list);
+
+	ret = kstrtou16(name, 0, &val);
+	if (ret < 0)
+		goto out_free;
+	if (!val) {
+		ret = -EINVAL;
+		goto out_free;
+	}
+
+	peer_port->tg_pt_gp_peer_rtpi = val;
+	config_item_init_type_name(&peer_port->tg_pt_gp_peer_item,
+				   name,
+				   &target_core_alua_tg_pt_gp_peer_cit);
+
+	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+	list_add_tail(&peer_port->tg_pt_gp_peer_list,
+		      &tg_pt_gp->tg_pt_gp_peer_list);
+	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+	return &peer_port->tg_pt_gp_peer_item;
+out_free:
+	kfree(peer_port);
+	return ERR_PTR(ret);
+}
+
+static void target_core_alua_tg_pt_gp_peers_drop(struct config_group *group,
+						 struct config_item *item)
+{
+	struct t10_alua_tg_pt_gp_peer *peer_port = container_of(item,
+			struct t10_alua_tg_pt_gp_peer, tg_pt_gp_peer_item);
+	struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(group,
+			struct t10_alua_tg_pt_gp, tg_pt_gp_peers_group);
+	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+	list_del(&peer_port->tg_pt_gp_peer_list);
+	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+	config_item_put(item);
+}
+
+static struct configfs_group_operations target_core_alua_tg_pt_gp_peers_ops = {
+	.make_item		= &target_core_alua_tg_pt_gp_peers_make,
+	.drop_item		= &target_core_alua_tg_pt_gp_peers_drop,
+};
+
+static struct config_item_type target_core_alua_tg_pt_gp_peers_cit = {
+	.ct_group_ops		= &target_core_alua_tg_pt_gp_peers_ops,
+	.ct_owner		= THIS_MODULE,
+};
+
 /* End functions for struct config_item_type target_core_alua_tg_pt_gp_cit */
 
 /* Start functions for struct config_item_type tb_alua_tg_pt_gps_cit */
@@ -3101,6 +3182,11 @@ static struct config_group *target_core_alua_create_tg_pt_gp(
 
 	config_group_init_type_name(alua_tg_pt_gp_cg, name,
 			&target_core_alua_tg_pt_gp_cit);
+	config_group_init_type_name(&tg_pt_gp->tg_pt_gp_peers_group,
+				    "peers",
+				    &target_core_alua_tg_pt_gp_peers_cit);
+	configfs_add_default_group(&tg_pt_gp->tg_pt_gp_peers_group,
+				   alua_tg_pt_gp_cg);
 
 	pr_debug("Target_Core_ConfigFS: Allocated ALUA Target Port"
 		" Group: alua/tg_pt_gps/%s\n",
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 594b724bbf79..c3b77b504143 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -47,6 +47,7 @@ struct kmem_cache *t10_pr_reg_cache;
 struct kmem_cache *t10_alua_lu_gp_cache;
 struct kmem_cache *t10_alua_lu_gp_mem_cache;
 struct kmem_cache *t10_alua_tg_pt_gp_cache;
+struct kmem_cache *t10_alua_tg_pt_gp_peer_cache;
 struct kmem_cache *t10_alua_lba_map_cache;
 struct kmem_cache *t10_alua_lba_map_mem_cache;
 
@@ -105,6 +106,15 @@ int init_se_kmem_caches(void)
 				"cache failed\n");
 		goto out_free_lu_gp_mem_cache;
 	}
+	t10_alua_tg_pt_gp_peer_cache = kmem_cache_create(
+			"t10_alua_tg_pt_gp_peer_cache",
+			sizeof(struct t10_alua_tg_pt_gp_peer),
+			__alignof__(struct t10_alua_tg_pt_gp_peer), 0, NULL);
+	if (!t10_alua_tg_pt_gp_peer_cache) {
+		pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_peer_cache"
+		       " failed\n");
+		goto out_free_tg_pt_gp_cache;
+	}
 	t10_alua_lba_map_cache = kmem_cache_create(
 			"t10_alua_lba_map_cache",
 			sizeof(struct t10_alua_lba_map),
@@ -112,7 +122,7 @@ int init_se_kmem_caches(void)
 	if (!t10_alua_lba_map_cache) {
 		pr_err("kmem_cache_create() for t10_alua_lba_map_"
 				"cache failed\n");
-		goto out_free_tg_pt_gp_cache;
+		goto out_free_tg_pt_gp_peer_cache;
 	}
 	t10_alua_lba_map_mem_cache = kmem_cache_create(
 			"t10_alua_lba_map_mem_cache",
@@ -135,6 +145,8 @@ int init_se_kmem_caches(void)
 	kmem_cache_destroy(t10_alua_lba_map_mem_cache);
 out_free_lba_map_cache:
 	kmem_cache_destroy(t10_alua_lba_map_cache);
+out_free_tg_pt_gp_peer_cache:
+	kmem_cache_destroy(t10_alua_tg_pt_gp_peer_cache);
 out_free_tg_pt_gp_cache:
 	kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
 out_free_lu_gp_mem_cache:
@@ -160,6 +172,7 @@ void release_se_kmem_caches(void)
 	kmem_cache_destroy(t10_alua_lu_gp_cache);
 	kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
 	kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+	kmem_cache_destroy(t10_alua_tg_pt_gp_peer_cache);
 	kmem_cache_destroy(t10_alua_lba_map_cache);
 	kmem_cache_destroy(t10_alua_lba_map_mem_cache);
 }
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index cde2f986e9c0..b4801d3f6bec 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -301,12 +301,20 @@ struct t10_alua_tg_pt_gp {
 	struct mutex tg_pt_gp_transition_mutex;
 	struct se_device *tg_pt_gp_dev;
 	struct config_group tg_pt_gp_group;
+	struct config_group tg_pt_gp_peers_group;
 	struct list_head tg_pt_gp_list;
 	struct list_head tg_pt_gp_lun_list;
+	struct list_head tg_pt_gp_peer_list;
 	struct se_lun *tg_pt_gp_alua_lun;
 	struct se_node_acl *tg_pt_gp_alua_nacl;
 };
 
+struct t10_alua_tg_pt_gp_peer {
+	u16    tg_pt_gp_peer_rtpi;
+	struct config_item tg_pt_gp_peer_item;
+	struct list_head tg_pt_gp_peer_list;
+};
+
 struct t10_vpd {
 	unsigned char device_identifier[INQUIRY_VPD_DEVICE_IDENTIFIER_LEN];
 	int protocol_identifier_set;
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 09/11] scsi: target/core: Populate configfs for peer ports
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

TCM can't report about ports of peer node in REPORT TARGET PORT GROUPS
command if TCM is used in a cluster. The change introduces a way to
store information about such ports in configfs.

Each port group except default_tg_pt_gp has "peers" subdirectory. It can
be used to store RTPI (RELATIVE TARGET PORT IDENTIFIER) of SCSI target
ports that reside on peer nodes:

  mkdir $BACKSTORE/alua/pg1/peers/$RTPI

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_alua.c      |  1 +
 drivers/target/target_core_alua.h      |  1 +
 drivers/target/target_core_configfs.c  | 86 ++++++++++++++++++++++++++
 drivers/target/target_core_transport.c | 15 ++++-
 include/target/target_core_base.h      |  8 +++
 5 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 8053f3989bbb..81ed79500376 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -1650,6 +1650,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev,
 	}
 	INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list);
 	INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_lun_list);
+	INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_peer_list);
 	mutex_init(&tg_pt_gp->tg_pt_gp_transition_mutex);
 	spin_lock_init(&tg_pt_gp->tg_pt_gp_lock);
 	atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0);
diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h
index fc9637cce825..bc6d47ed93e8 100644
--- a/drivers/target/target_core_alua.h
+++ b/drivers/target/target_core_alua.h
@@ -79,6 +79,7 @@
 extern struct kmem_cache *t10_alua_lu_gp_cache;
 extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
 extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
+extern struct kmem_cache *t10_alua_tg_pt_gp_peer_cache;
 extern struct kmem_cache *t10_alua_lba_map_cache;
 extern struct kmem_cache *t10_alua_lba_map_mem_cache;
 
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 3311d29ecad8..803e968659e3 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -3078,6 +3078,87 @@ static const struct config_item_type target_core_alua_tg_pt_gp_cit = {
 	.ct_owner		= THIS_MODULE,
 };
 
+static void target_core_alua_tg_pt_gp_peer_release(struct config_item *item)
+{
+	struct t10_alua_tg_pt_gp_peer *peer_port = container_of(item,
+			struct t10_alua_tg_pt_gp_peer, tg_pt_gp_peer_item);
+	kmem_cache_free(t10_alua_tg_pt_gp_peer_cache, peer_port);
+}
+
+static struct configfs_item_operations target_core_alua_tg_pt_gp_peer_ops = {
+	.release		= target_core_alua_tg_pt_gp_peer_release,
+};
+
+static struct config_item_type target_core_alua_tg_pt_gp_peer_cit = {
+	.ct_item_ops		= &target_core_alua_tg_pt_gp_peer_ops,
+	.ct_owner		= THIS_MODULE,
+};
+
+static struct config_item *
+target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
+				     const char *name)
+{
+	struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(group,
+			struct t10_alua_tg_pt_gp, tg_pt_gp_peers_group);
+	struct t10_alua_tg_pt_gp_peer *peer_port;
+	u16 val;
+	int ret;
+
+	peer_port = kmem_cache_zalloc(t10_alua_tg_pt_gp_peer_cache, GFP_KERNEL);
+	if (!peer_port) {
+		pr_err("Unable to allocate struct t10_alua_tg_pt_gp_peer\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	INIT_LIST_HEAD(&peer_port->tg_pt_gp_peer_list);
+
+	ret = kstrtou16(name, 0, &val);
+	if (ret < 0)
+		goto out_free;
+	if (!val) {
+		ret = -EINVAL;
+		goto out_free;
+	}
+
+	peer_port->tg_pt_gp_peer_rtpi = val;
+	config_item_init_type_name(&peer_port->tg_pt_gp_peer_item,
+				   name,
+				   &target_core_alua_tg_pt_gp_peer_cit);
+
+	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+	list_add_tail(&peer_port->tg_pt_gp_peer_list,
+		      &tg_pt_gp->tg_pt_gp_peer_list);
+	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+	return &peer_port->tg_pt_gp_peer_item;
+out_free:
+	kfree(peer_port);
+	return ERR_PTR(ret);
+}
+
+static void target_core_alua_tg_pt_gp_peers_drop(struct config_group *group,
+						 struct config_item *item)
+{
+	struct t10_alua_tg_pt_gp_peer *peer_port = container_of(item,
+			struct t10_alua_tg_pt_gp_peer, tg_pt_gp_peer_item);
+	struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(group,
+			struct t10_alua_tg_pt_gp, tg_pt_gp_peers_group);
+	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+	list_del(&peer_port->tg_pt_gp_peer_list);
+	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+	config_item_put(item);
+}
+
+static struct configfs_group_operations target_core_alua_tg_pt_gp_peers_ops = {
+	.make_item		= &target_core_alua_tg_pt_gp_peers_make,
+	.drop_item		= &target_core_alua_tg_pt_gp_peers_drop,
+};
+
+static struct config_item_type target_core_alua_tg_pt_gp_peers_cit = {
+	.ct_group_ops		= &target_core_alua_tg_pt_gp_peers_ops,
+	.ct_owner		= THIS_MODULE,
+};
+
 /* End functions for struct config_item_type target_core_alua_tg_pt_gp_cit */
 
 /* Start functions for struct config_item_type tb_alua_tg_pt_gps_cit */
@@ -3101,6 +3182,11 @@ static struct config_group *target_core_alua_create_tg_pt_gp(
 
 	config_group_init_type_name(alua_tg_pt_gp_cg, name,
 			&target_core_alua_tg_pt_gp_cit);
+	config_group_init_type_name(&tg_pt_gp->tg_pt_gp_peers_group,
+				    "peers",
+				    &target_core_alua_tg_pt_gp_peers_cit);
+	configfs_add_default_group(&tg_pt_gp->tg_pt_gp_peers_group,
+				   alua_tg_pt_gp_cg);
 
 	pr_debug("Target_Core_ConfigFS: Allocated ALUA Target Port"
 		" Group: alua/tg_pt_gps/%s\n",
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 594b724bbf79..c3b77b504143 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -47,6 +47,7 @@ struct kmem_cache *t10_pr_reg_cache;
 struct kmem_cache *t10_alua_lu_gp_cache;
 struct kmem_cache *t10_alua_lu_gp_mem_cache;
 struct kmem_cache *t10_alua_tg_pt_gp_cache;
+struct kmem_cache *t10_alua_tg_pt_gp_peer_cache;
 struct kmem_cache *t10_alua_lba_map_cache;
 struct kmem_cache *t10_alua_lba_map_mem_cache;
 
@@ -105,6 +106,15 @@ int init_se_kmem_caches(void)
 				"cache failed\n");
 		goto out_free_lu_gp_mem_cache;
 	}
+	t10_alua_tg_pt_gp_peer_cache = kmem_cache_create(
+			"t10_alua_tg_pt_gp_peer_cache",
+			sizeof(struct t10_alua_tg_pt_gp_peer),
+			__alignof__(struct t10_alua_tg_pt_gp_peer), 0, NULL);
+	if (!t10_alua_tg_pt_gp_peer_cache) {
+		pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_peer_cache"
+		       " failed\n");
+		goto out_free_tg_pt_gp_cache;
+	}
 	t10_alua_lba_map_cache = kmem_cache_create(
 			"t10_alua_lba_map_cache",
 			sizeof(struct t10_alua_lba_map),
@@ -112,7 +122,7 @@ int init_se_kmem_caches(void)
 	if (!t10_alua_lba_map_cache) {
 		pr_err("kmem_cache_create() for t10_alua_lba_map_"
 				"cache failed\n");
-		goto out_free_tg_pt_gp_cache;
+		goto out_free_tg_pt_gp_peer_cache;
 	}
 	t10_alua_lba_map_mem_cache = kmem_cache_create(
 			"t10_alua_lba_map_mem_cache",
@@ -135,6 +145,8 @@ int init_se_kmem_caches(void)
 	kmem_cache_destroy(t10_alua_lba_map_mem_cache);
 out_free_lba_map_cache:
 	kmem_cache_destroy(t10_alua_lba_map_cache);
+out_free_tg_pt_gp_peer_cache:
+	kmem_cache_destroy(t10_alua_tg_pt_gp_peer_cache);
 out_free_tg_pt_gp_cache:
 	kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
 out_free_lu_gp_mem_cache:
@@ -160,6 +172,7 @@ void release_se_kmem_caches(void)
 	kmem_cache_destroy(t10_alua_lu_gp_cache);
 	kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
 	kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+	kmem_cache_destroy(t10_alua_tg_pt_gp_peer_cache);
 	kmem_cache_destroy(t10_alua_lba_map_cache);
 	kmem_cache_destroy(t10_alua_lba_map_mem_cache);
 }
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index cde2f986e9c0..b4801d3f6bec 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -301,12 +301,20 @@ struct t10_alua_tg_pt_gp {
 	struct mutex tg_pt_gp_transition_mutex;
 	struct se_device *tg_pt_gp_dev;
 	struct config_group tg_pt_gp_group;
+	struct config_group tg_pt_gp_peers_group;
 	struct list_head tg_pt_gp_list;
 	struct list_head tg_pt_gp_lun_list;
+	struct list_head tg_pt_gp_peer_list;
 	struct se_lun *tg_pt_gp_alua_lun;
 	struct se_node_acl *tg_pt_gp_alua_nacl;
 };
 
+struct t10_alua_tg_pt_gp_peer {
+	u16    tg_pt_gp_peer_rtpi;
+	struct config_item tg_pt_gp_peer_item;
+	struct list_head tg_pt_gp_peer_list;
+};
+
 struct t10_vpd {
 	unsigned char device_identifier[INQUIRY_VPD_DEVICE_IDENTIFIER_LEN];
 	int protocol_identifier_set;
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 10/11] scsi: target/core: Prevent RTPI conflicts
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

RTPI values have to be unique per SAM-5 4.6.5.2 (Relative Port
Identifier attribute).

There are four sources of RTPI changes, where RTPI duplicates may
appear:

1. Automatically increased RTPI for new SCSI target ports. They have to
be unique among target ports. Simultaneous creation of SCSI target ports
is synchronized by g_tpg_mutex. No real LUNs are attached upon creation
(except virtual LUN 0) therefore, no synchronization is needed between
peer ports.

2. Manually configured RTPI values on SCSI target ports using rtpi attr
in configfs. They should be unique for all peer ports on the LUNs
available through the ports and among all SCSI target ports.

3. New peer ports created in configfs. They shouldn't conflict with other
peer ports on the se_device and RTPI values of the ports the se_device
is exported on.

4. Export of a backstore with peer ports on a SCSI target port. RTPI of
a peer port may have the same value as automatically or manually
configured RTPI of a SCSI target port.

The change introduces synchronization for 2-4. RTPI modification is
locked by global RTPI mutex. It can be used in sleeping context,
therefore it should be a mutex rather than a spinlock.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_configfs.c | 38 +++++++++++++
 drivers/target/target_core_device.c   | 19 +++++++
 drivers/target/target_core_internal.h |  2 +
 drivers/target/target_core_tpg.c      | 81 ++++++++++++++++++++++++++-
 4 files changed, 138 insertions(+), 2 deletions(-)

diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 803e968659e3..c43f244f8bd6 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -3100,7 +3100,9 @@ target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
 {
 	struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(group,
 			struct t10_alua_tg_pt_gp, tg_pt_gp_peers_group);
+	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
 	struct t10_alua_tg_pt_gp_peer *peer_port;
+	struct se_lun *lun;
 	u16 val;
 	int ret;
 
@@ -3119,6 +3121,38 @@ target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
 		goto out_free;
 	}
 
+	ret = mutex_lock_interruptible(&g_rtpi_mutex);
+	if (ret < 0)
+		goto out_free;
+
+	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+	if (core_dev_has_rtpi(dev, val)) {
+		pr_err("TARGET_CORE[0]: RTPI %#x conflicts with a peer port\n",
+		       val);
+		spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+		ret = -EINVAL;
+		goto out_unlock_rtpi;
+	}
+	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+
+	spin_lock(&dev->se_port_lock);
+	list_for_each_entry(lun, &dev->dev_sep_list, lun_dev_link) {
+		struct se_portal_group *tpg = lun->lun_tpg;
+
+		if (tpg->tpg_rtpi = val) {
+			pr_err("TARGET_CORE[0]: RTPI %#x conflicts with"
+			       " TARGET_CORE[%s]->TPG[%u]_LUN[%llu]\n",
+			       val,
+			       tpg->se_tpg_tfo->fabric_name,
+			       tpg->se_tpg_tfo->tpg_get_tag(tpg),
+			       lun->unpacked_lun);
+			spin_unlock(&dev->se_port_lock);
+			ret = -EINVAL;
+			goto out_unlock_rtpi;
+		}
+	}
+	spin_unlock(&dev->se_port_lock);
+
 	peer_port->tg_pt_gp_peer_rtpi = val;
 	config_item_init_type_name(&peer_port->tg_pt_gp_peer_item,
 				   name,
@@ -3128,8 +3162,12 @@ target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
 	list_add_tail(&peer_port->tg_pt_gp_peer_list,
 		      &tg_pt_gp->tg_pt_gp_peer_list);
 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+	mutex_unlock(&g_rtpi_mutex);
 
 	return &peer_port->tg_pt_gp_peer_item;
+
+out_unlock_rtpi:
+	mutex_unlock(&g_rtpi_mutex);
 out_free:
 	kfree(peer_port);
 	return ERR_PTR(ret);
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 24d358f942b8..f3c783c83fd6 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -975,6 +975,25 @@ void target_free_device(struct se_device *dev)
 	dev->transport->free_device(dev);
 }
 
+bool core_dev_has_rtpi(struct se_device *dev, u16 rtpi)
+{
+	struct t10_alua_tg_pt_gp *tg_pt_gp;
+	struct t10_alua_tg_pt_gp_peer *peer;
+
+	assert_spin_locked(&dev->t10_alua.tg_pt_gps_lock);
+
+	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
+			    tg_pt_gp_list) {
+		list_for_each_entry(peer, &tg_pt_gp->tg_pt_gp_peer_list,
+				    tg_pt_gp_peer_list) {
+			if (peer->tg_pt_gp_peer_rtpi = rtpi)
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
 int core_dev_setup_virtual_lun0(void)
 {
 	struct se_hba *hba;
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index e1aabb79467a..90a82abdc828 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -80,6 +80,7 @@ int	core_dev_del_initiator_node_lun_acl(struct se_lun *,
 		struct se_lun_acl *);
 void	core_dev_free_initiator_node_lun_acl(struct se_portal_group *,
 		struct se_lun_acl *lacl);
+bool	core_dev_has_rtpi(struct se_device *dev, u16 rtpi);
 int	core_dev_setup_virtual_lun0(void);
 void	core_dev_release_virtual_lun0(void);
 struct se_device *target_alloc_device(struct se_hba *hba, const char *name);
@@ -115,6 +116,7 @@ int	core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
 		struct list_head *, struct se_cmd *);
 
 /* target_core_tpg.c */
+extern struct mutex g_rtpi_mutex;
 extern struct se_device *g_lun0_dev;
 extern struct configfs_attribute *core_tpg_attrib_attrs[];
 
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index c0d564f17951..ca14d6d32b62 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -31,6 +31,8 @@
 #include "target_core_ua.h"
 
 extern struct se_device *g_lun0_dev;
+/* Synchronizes RTPI changes system-wide */
+DEFINE_MUTEX(g_rtpi_mutex);
 static u16 g_tpg_count;
 static u16 g_tpg_rtpi_counter = 1;
 static LIST_HEAD(g_tpg_list);
@@ -645,6 +647,8 @@ int core_tpg_add_lun(
 	bool lun_access_ro,
 	struct se_device *dev)
 {
+	const char *devname = config_item_name(&dev->dev_group.cg_item);
+	struct se_portal_group *tmp_tpg;
 	int ret;
 
 	ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release, 0,
@@ -652,10 +656,39 @@ int core_tpg_add_lun(
 	if (ret < 0)
 		goto out;
 
+	mutex_lock(&g_rtpi_mutex);
 	if (!(dev->transport->transport_flags &
 	     TRANSPORT_FLAG_PASSTHROUGH_ALUA) &&
-	    !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
+	    !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) {
+		/*
+		 * LUN won't be created if a peer RTPI in a port group
+		 * conflicts with Port RTPI.
+		 * RTPI values must be strictly unique.
+		 */
+		mutex_lock(&g_tpg_mutex);
+		list_for_each_entry(tmp_tpg, &g_tpg_list, tpg_list) {
+			spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+			if (core_dev_has_rtpi(dev, tmp_tpg->tpg_rtpi)) {
+				pr_err("TARGET_CORE[%s]->TPG[%u]_LUN[%llu]:"
+				       " RTPI %#x conflicts with peer port of"
+				       " %s\n",
+				       tmp_tpg->se_tpg_tfo->fabric_name,
+				       tmp_tpg->se_tpg_tfo->tpg_get_tag(
+					       tmp_tpg),
+				       lun->unpacked_lun,
+				       tmp_tpg->tpg_rtpi,
+				       devname);
+				spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+				mutex_unlock(&g_tpg_mutex);
+				ret = -EINVAL;
+				goto out_unlock_rtpi;
+			}
+			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+		}
+		mutex_unlock(&g_tpg_mutex);
+
 		target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp);
+	}
 
 	mutex_lock(&tpg->tpg_lun_mutex);
 
@@ -673,9 +706,13 @@ int core_tpg_add_lun(
 	if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
 		hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist);
 	mutex_unlock(&tpg->tpg_lun_mutex);
+	mutex_unlock(&g_rtpi_mutex);
 
 	return 0;
 
+out_unlock_rtpi:
+	mutex_unlock(&g_rtpi_mutex);
+	percpu_ref_exit(&lun->lun_ref);
 out:
 	return ret;
 }
@@ -747,6 +784,8 @@ static ssize_t core_tpg_rtpi_store(struct config_item *item,
 				   const char *page, size_t count)
 {
 	struct se_portal_group *se_tpg = attrib_to_tpg(item);
+	struct se_lun *lun;
+	struct se_device *dev;
 	struct se_portal_group *tpg;
 	u16 val;
 	int ret;
@@ -757,6 +796,10 @@ static ssize_t core_tpg_rtpi_store(struct config_item *item,
 	if (val = 0)
 		return -EINVAL;
 
+	ret = mutex_lock_interruptible(&g_rtpi_mutex);
+	if (ret < 0)
+		return ret;
+
 	/* RTPI shouldn't conflict with values of existing ports */
 	ret = mutex_lock_interruptible(&g_tpg_mutex);
 	if (ret < 0)
@@ -771,10 +814,44 @@ static ssize_t core_tpg_rtpi_store(struct config_item *item,
 			       val,
 			       tpg->se_tpg_tfo->fabric_name,
 			       tpg->se_tpg_tfo->tpg_get_tag(tpg));
+			mutex_unlock(&g_tpg_mutex);
 			ret = -EINVAL;
 			goto out;
 		}
 	}
+	mutex_unlock(&g_tpg_mutex);
+
+	/* RTPI shouldn't conflict with values of peer ports */
+	ret = mutex_lock_interruptible(&se_tpg->tpg_lun_mutex);
+	if (ret < 0)
+		goto out;
+
+	hlist_for_each_entry_rcu(lun, &se_tpg->tpg_lun_hlist, link) {
+		rcu_read_lock();
+		dev = rcu_dereference(lun->lun_se_dev);
+		if (dev) {
+			const char *devname;
+
+			devname = config_item_name(&dev->dev_group.cg_item);
+
+			spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+			if (core_dev_has_rtpi(dev, val)) {
+				pr_err("TARGET_CORE[%s]->TPG[%u] - RTPI"
+				       " conflicts with a peer port of %s\n",
+				       se_tpg->se_tpg_tfo->fabric_name,
+				       se_tpg->se_tpg_tfo->tpg_get_tag(tpg),
+				       devname);
+				spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+				rcu_read_unlock();
+				mutex_unlock(&se_tpg->tpg_lun_mutex);
+				ret = -EINVAL;
+				goto out;
+			}
+			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+		}
+		rcu_read_unlock();
+	}
+	mutex_unlock(&se_tpg->tpg_lun_mutex);
 
 	if (se_tpg->tpg_rtpi != val) {
 		se_tpg->tpg_rtpi = val;
@@ -782,7 +859,7 @@ static ssize_t core_tpg_rtpi_store(struct config_item *item,
 	}
 	ret = count;
 out:
-	mutex_unlock(&g_tpg_mutex);
+	mutex_unlock(&g_rtpi_mutex);
 	return ret;
 }
 
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 10/11] scsi: target/core: Prevent RTPI conflicts
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

RTPI values have to be unique per SAM-5 4.6.5.2 (Relative Port
Identifier attribute).

There are four sources of RTPI changes, where RTPI duplicates may
appear:

1. Automatically increased RTPI for new SCSI target ports. They have to
be unique among target ports. Simultaneous creation of SCSI target ports
is synchronized by g_tpg_mutex. No real LUNs are attached upon creation
(except virtual LUN 0) therefore, no synchronization is needed between
peer ports.

2. Manually configured RTPI values on SCSI target ports using rtpi attr
in configfs. They should be unique for all peer ports on the LUNs
available through the ports and among all SCSI target ports.

3. New peer ports created in configfs. They shouldn't conflict with other
peer ports on the se_device and RTPI values of the ports the se_device
is exported on.

4. Export of a backstore with peer ports on a SCSI target port. RTPI of
a peer port may have the same value as automatically or manually
configured RTPI of a SCSI target port.

The change introduces synchronization for 2-4. RTPI modification is
locked by global RTPI mutex. It can be used in sleeping context,
therefore it should be a mutex rather than a spinlock.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_configfs.c | 38 +++++++++++++
 drivers/target/target_core_device.c   | 19 +++++++
 drivers/target/target_core_internal.h |  2 +
 drivers/target/target_core_tpg.c      | 81 ++++++++++++++++++++++++++-
 4 files changed, 138 insertions(+), 2 deletions(-)

diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 803e968659e3..c43f244f8bd6 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -3100,7 +3100,9 @@ target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
 {
 	struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(group,
 			struct t10_alua_tg_pt_gp, tg_pt_gp_peers_group);
+	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
 	struct t10_alua_tg_pt_gp_peer *peer_port;
+	struct se_lun *lun;
 	u16 val;
 	int ret;
 
@@ -3119,6 +3121,38 @@ target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
 		goto out_free;
 	}
 
+	ret = mutex_lock_interruptible(&g_rtpi_mutex);
+	if (ret < 0)
+		goto out_free;
+
+	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+	if (core_dev_has_rtpi(dev, val)) {
+		pr_err("TARGET_CORE[0]: RTPI %#x conflicts with a peer port\n",
+		       val);
+		spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+		ret = -EINVAL;
+		goto out_unlock_rtpi;
+	}
+	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+
+	spin_lock(&dev->se_port_lock);
+	list_for_each_entry(lun, &dev->dev_sep_list, lun_dev_link) {
+		struct se_portal_group *tpg = lun->lun_tpg;
+
+		if (tpg->tpg_rtpi == val) {
+			pr_err("TARGET_CORE[0]: RTPI %#x conflicts with"
+			       " TARGET_CORE[%s]->TPG[%u]_LUN[%llu]\n",
+			       val,
+			       tpg->se_tpg_tfo->fabric_name,
+			       tpg->se_tpg_tfo->tpg_get_tag(tpg),
+			       lun->unpacked_lun);
+			spin_unlock(&dev->se_port_lock);
+			ret = -EINVAL;
+			goto out_unlock_rtpi;
+		}
+	}
+	spin_unlock(&dev->se_port_lock);
+
 	peer_port->tg_pt_gp_peer_rtpi = val;
 	config_item_init_type_name(&peer_port->tg_pt_gp_peer_item,
 				   name,
@@ -3128,8 +3162,12 @@ target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
 	list_add_tail(&peer_port->tg_pt_gp_peer_list,
 		      &tg_pt_gp->tg_pt_gp_peer_list);
 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+	mutex_unlock(&g_rtpi_mutex);
 
 	return &peer_port->tg_pt_gp_peer_item;
+
+out_unlock_rtpi:
+	mutex_unlock(&g_rtpi_mutex);
 out_free:
 	kfree(peer_port);
 	return ERR_PTR(ret);
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 24d358f942b8..f3c783c83fd6 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -975,6 +975,25 @@ void target_free_device(struct se_device *dev)
 	dev->transport->free_device(dev);
 }
 
+bool core_dev_has_rtpi(struct se_device *dev, u16 rtpi)
+{
+	struct t10_alua_tg_pt_gp *tg_pt_gp;
+	struct t10_alua_tg_pt_gp_peer *peer;
+
+	assert_spin_locked(&dev->t10_alua.tg_pt_gps_lock);
+
+	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
+			    tg_pt_gp_list) {
+		list_for_each_entry(peer, &tg_pt_gp->tg_pt_gp_peer_list,
+				    tg_pt_gp_peer_list) {
+			if (peer->tg_pt_gp_peer_rtpi == rtpi)
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
 int core_dev_setup_virtual_lun0(void)
 {
 	struct se_hba *hba;
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index e1aabb79467a..90a82abdc828 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -80,6 +80,7 @@ int	core_dev_del_initiator_node_lun_acl(struct se_lun *,
 		struct se_lun_acl *);
 void	core_dev_free_initiator_node_lun_acl(struct se_portal_group *,
 		struct se_lun_acl *lacl);
+bool	core_dev_has_rtpi(struct se_device *dev, u16 rtpi);
 int	core_dev_setup_virtual_lun0(void);
 void	core_dev_release_virtual_lun0(void);
 struct se_device *target_alloc_device(struct se_hba *hba, const char *name);
@@ -115,6 +116,7 @@ int	core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
 		struct list_head *, struct se_cmd *);
 
 /* target_core_tpg.c */
+extern struct mutex g_rtpi_mutex;
 extern struct se_device *g_lun0_dev;
 extern struct configfs_attribute *core_tpg_attrib_attrs[];
 
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index c0d564f17951..ca14d6d32b62 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -31,6 +31,8 @@
 #include "target_core_ua.h"
 
 extern struct se_device *g_lun0_dev;
+/* Synchronizes RTPI changes system-wide */
+DEFINE_MUTEX(g_rtpi_mutex);
 static u16 g_tpg_count;
 static u16 g_tpg_rtpi_counter = 1;
 static LIST_HEAD(g_tpg_list);
@@ -645,6 +647,8 @@ int core_tpg_add_lun(
 	bool lun_access_ro,
 	struct se_device *dev)
 {
+	const char *devname = config_item_name(&dev->dev_group.cg_item);
+	struct se_portal_group *tmp_tpg;
 	int ret;
 
 	ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release, 0,
@@ -652,10 +656,39 @@ int core_tpg_add_lun(
 	if (ret < 0)
 		goto out;
 
+	mutex_lock(&g_rtpi_mutex);
 	if (!(dev->transport->transport_flags &
 	     TRANSPORT_FLAG_PASSTHROUGH_ALUA) &&
-	    !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
+	    !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) {
+		/*
+		 * LUN won't be created if a peer RTPI in a port group
+		 * conflicts with Port RTPI.
+		 * RTPI values must be strictly unique.
+		 */
+		mutex_lock(&g_tpg_mutex);
+		list_for_each_entry(tmp_tpg, &g_tpg_list, tpg_list) {
+			spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+			if (core_dev_has_rtpi(dev, tmp_tpg->tpg_rtpi)) {
+				pr_err("TARGET_CORE[%s]->TPG[%u]_LUN[%llu]:"
+				       " RTPI %#x conflicts with peer port of"
+				       " %s\n",
+				       tmp_tpg->se_tpg_tfo->fabric_name,
+				       tmp_tpg->se_tpg_tfo->tpg_get_tag(
+					       tmp_tpg),
+				       lun->unpacked_lun,
+				       tmp_tpg->tpg_rtpi,
+				       devname);
+				spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+				mutex_unlock(&g_tpg_mutex);
+				ret = -EINVAL;
+				goto out_unlock_rtpi;
+			}
+			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+		}
+		mutex_unlock(&g_tpg_mutex);
+
 		target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp);
+	}
 
 	mutex_lock(&tpg->tpg_lun_mutex);
 
@@ -673,9 +706,13 @@ int core_tpg_add_lun(
 	if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
 		hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist);
 	mutex_unlock(&tpg->tpg_lun_mutex);
+	mutex_unlock(&g_rtpi_mutex);
 
 	return 0;
 
+out_unlock_rtpi:
+	mutex_unlock(&g_rtpi_mutex);
+	percpu_ref_exit(&lun->lun_ref);
 out:
 	return ret;
 }
@@ -747,6 +784,8 @@ static ssize_t core_tpg_rtpi_store(struct config_item *item,
 				   const char *page, size_t count)
 {
 	struct se_portal_group *se_tpg = attrib_to_tpg(item);
+	struct se_lun *lun;
+	struct se_device *dev;
 	struct se_portal_group *tpg;
 	u16 val;
 	int ret;
@@ -757,6 +796,10 @@ static ssize_t core_tpg_rtpi_store(struct config_item *item,
 	if (val == 0)
 		return -EINVAL;
 
+	ret = mutex_lock_interruptible(&g_rtpi_mutex);
+	if (ret < 0)
+		return ret;
+
 	/* RTPI shouldn't conflict with values of existing ports */
 	ret = mutex_lock_interruptible(&g_tpg_mutex);
 	if (ret < 0)
@@ -771,10 +814,44 @@ static ssize_t core_tpg_rtpi_store(struct config_item *item,
 			       val,
 			       tpg->se_tpg_tfo->fabric_name,
 			       tpg->se_tpg_tfo->tpg_get_tag(tpg));
+			mutex_unlock(&g_tpg_mutex);
 			ret = -EINVAL;
 			goto out;
 		}
 	}
+	mutex_unlock(&g_tpg_mutex);
+
+	/* RTPI shouldn't conflict with values of peer ports */
+	ret = mutex_lock_interruptible(&se_tpg->tpg_lun_mutex);
+	if (ret < 0)
+		goto out;
+
+	hlist_for_each_entry_rcu(lun, &se_tpg->tpg_lun_hlist, link) {
+		rcu_read_lock();
+		dev = rcu_dereference(lun->lun_se_dev);
+		if (dev) {
+			const char *devname;
+
+			devname = config_item_name(&dev->dev_group.cg_item);
+
+			spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+			if (core_dev_has_rtpi(dev, val)) {
+				pr_err("TARGET_CORE[%s]->TPG[%u] - RTPI"
+				       " conflicts with a peer port of %s\n",
+				       se_tpg->se_tpg_tfo->fabric_name,
+				       se_tpg->se_tpg_tfo->tpg_get_tag(tpg),
+				       devname);
+				spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+				rcu_read_unlock();
+				mutex_unlock(&se_tpg->tpg_lun_mutex);
+				ret = -EINVAL;
+				goto out;
+			}
+			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+		}
+		rcu_read_unlock();
+	}
+	mutex_unlock(&se_tpg->tpg_lun_mutex);
 
 	if (se_tpg->tpg_rtpi != val) {
 		se_tpg->tpg_rtpi = val;
@@ -782,7 +859,7 @@ static ssize_t core_tpg_rtpi_store(struct config_item *item,
 	}
 	ret = count;
 out:
-	mutex_unlock(&g_tpg_mutex);
+	mutex_unlock(&g_rtpi_mutex);
 	return ret;
 }
 
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 11/11] scsi: target/core: Show peer ports in RTPG response
  2020-04-29  9:44 ` Roman Bolshakov
@ 2020-04-29  9:44   ` Roman Bolshakov
  -1 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

The change makes peer ports visible in the response to REPORT TARGET
PORT GROUPS command. RTPI values of real SCSI target ports and peer
ports for each target port descriptor list are sorted in ascending
order.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_alua.c     | 32 +++++++++++++++++++++++----
 drivers/target/target_core_configfs.c |  2 ++
 2 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 81ed79500376..f7d88181d683 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -18,6 +18,7 @@
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/sort.h>
 #include <scsi/scsi_proto.h>
 #include <asm/unaligned.h>
 
@@ -127,6 +128,11 @@ target_emulate_report_referrals(struct se_cmd *cmd)
 	return 0;
 }
 
+static int cmp_rtpi(const void *a, const void *b)
+{
+	return *(u16 *)a - *(u16 *)b;
+}
+
 /*
  * REPORT_TARGET_PORT_GROUPS
  *
@@ -138,7 +144,11 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 	struct se_device *dev = cmd->se_dev;
 	struct t10_alua_tg_pt_gp *tg_pt_gp;
 	struct se_lun *lun;
+	struct t10_alua_tg_pt_gp_peer *peer;
 	unsigned char *buf;
+	u8 port_cnt;
+	u16 *ports = NULL;
+	int i = 0;
 	u32 rd_len = 0, off;
 	int ext_hdr = (cmd->t_task_cdb[1] & 0x20);
 
@@ -209,12 +219,24 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 		/*
 		 * TARGET PORT COUNT
 		 */
-		buf[off++] = (tg_pt_gp->tg_pt_gp_members & 0xff);
+		spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+		port_cnt = (tg_pt_gp->tg_pt_gp_members & 0xff);
+		buf[off++] = port_cnt;
 		rd_len += 8;
+		ports = kcalloc(tg_pt_gp->tg_pt_gp_members, sizeof(u16),
+				GFP_ATOMIC);
 
-		spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+		i = 0;
 		list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list,
-				lun_tg_pt_gp_link) {
+				    lun_tg_pt_gp_link)
+			ports[i++] = lun->lun_tpg->tpg_rtpi;
+
+		list_for_each_entry(peer, &tg_pt_gp->tg_pt_gp_peer_list,
+				    tg_pt_gp_peer_list)
+			ports[i++] = peer->tg_pt_gp_peer_rtpi;
+
+		sort(ports, port_cnt, sizeof(*ports), cmp_rtpi, NULL);
+		for (i = 0; i < port_cnt; i++) {
 			/*
 			 * Start Target Port descriptor format
 			 *
@@ -224,10 +246,12 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 			/*
 			 * Set RELATIVE TARGET PORT IDENTIFIER
 			 */
-			put_unaligned_be16(lun->lun_tpg->tpg_rtpi, &buf[off]);
+			put_unaligned_be16(ports[i], &buf[off]);
 			off += 2;
 			rd_len += 4;
 		}
+		kfree(ports);
+		ports = NULL;
 		spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
 	}
 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index c43f244f8bd6..4026debe30ca 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -3161,6 +3161,7 @@ target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
 	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
 	list_add_tail(&peer_port->tg_pt_gp_peer_list,
 		      &tg_pt_gp->tg_pt_gp_peer_list);
+	tg_pt_gp->tg_pt_gp_members++;
 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
 	mutex_unlock(&g_rtpi_mutex);
 
@@ -3181,6 +3182,7 @@ static void target_core_alua_tg_pt_gp_peers_drop(struct config_group *group,
 	struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(group,
 			struct t10_alua_tg_pt_gp, tg_pt_gp_peers_group);
 	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+	tg_pt_gp->tg_pt_gp_members--;
 	list_del(&peer_port->tg_pt_gp_peer_list);
 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
 
-- 
2.26.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH 11/11] scsi: target/core: Show peer ports in RTPG response
@ 2020-04-29  9:44   ` Roman Bolshakov
  0 siblings, 0 replies; 24+ messages in thread
From: Roman Bolshakov @ 2020-04-29  9:44 UTC (permalink / raw)
  To: target-devel, Mike Christie, Bart Van Assche, David Disseldorp
  Cc: linux-scsi, linux, Roman Bolshakov

The change makes peer ports visible in the response to REPORT TARGET
PORT GROUPS command. RTPI values of real SCSI target ports and peer
ports for each target port descriptor list are sorted in ascending
order.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
---
 drivers/target/target_core_alua.c     | 32 +++++++++++++++++++++++----
 drivers/target/target_core_configfs.c |  2 ++
 2 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 81ed79500376..f7d88181d683 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -18,6 +18,7 @@
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/sort.h>
 #include <scsi/scsi_proto.h>
 #include <asm/unaligned.h>
 
@@ -127,6 +128,11 @@ target_emulate_report_referrals(struct se_cmd *cmd)
 	return 0;
 }
 
+static int cmp_rtpi(const void *a, const void *b)
+{
+	return *(u16 *)a - *(u16 *)b;
+}
+
 /*
  * REPORT_TARGET_PORT_GROUPS
  *
@@ -138,7 +144,11 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 	struct se_device *dev = cmd->se_dev;
 	struct t10_alua_tg_pt_gp *tg_pt_gp;
 	struct se_lun *lun;
+	struct t10_alua_tg_pt_gp_peer *peer;
 	unsigned char *buf;
+	u8 port_cnt;
+	u16 *ports = NULL;
+	int i = 0;
 	u32 rd_len = 0, off;
 	int ext_hdr = (cmd->t_task_cdb[1] & 0x20);
 
@@ -209,12 +219,24 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 		/*
 		 * TARGET PORT COUNT
 		 */
-		buf[off++] = (tg_pt_gp->tg_pt_gp_members & 0xff);
+		spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+		port_cnt = (tg_pt_gp->tg_pt_gp_members & 0xff);
+		buf[off++] = port_cnt;
 		rd_len += 8;
+		ports = kcalloc(tg_pt_gp->tg_pt_gp_members, sizeof(u16),
+				GFP_ATOMIC);
 
-		spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+		i = 0;
 		list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list,
-				lun_tg_pt_gp_link) {
+				    lun_tg_pt_gp_link)
+			ports[i++] = lun->lun_tpg->tpg_rtpi;
+
+		list_for_each_entry(peer, &tg_pt_gp->tg_pt_gp_peer_list,
+				    tg_pt_gp_peer_list)
+			ports[i++] = peer->tg_pt_gp_peer_rtpi;
+
+		sort(ports, port_cnt, sizeof(*ports), cmp_rtpi, NULL);
+		for (i = 0; i < port_cnt; i++) {
 			/*
 			 * Start Target Port descriptor format
 			 *
@@ -224,10 +246,12 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
 			/*
 			 * Set RELATIVE TARGET PORT IDENTIFIER
 			 */
-			put_unaligned_be16(lun->lun_tpg->tpg_rtpi, &buf[off]);
+			put_unaligned_be16(ports[i], &buf[off]);
 			off += 2;
 			rd_len += 4;
 		}
+		kfree(ports);
+		ports = NULL;
 		spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
 	}
 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index c43f244f8bd6..4026debe30ca 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -3161,6 +3161,7 @@ target_core_alua_tg_pt_gp_peers_make(struct config_group *group,
 	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
 	list_add_tail(&peer_port->tg_pt_gp_peer_list,
 		      &tg_pt_gp->tg_pt_gp_peer_list);
+	tg_pt_gp->tg_pt_gp_members++;
 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
 	mutex_unlock(&g_rtpi_mutex);
 
@@ -3181,6 +3182,7 @@ static void target_core_alua_tg_pt_gp_peers_drop(struct config_group *group,
 	struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(group,
 			struct t10_alua_tg_pt_gp, tg_pt_gp_peers_group);
 	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+	tg_pt_gp->tg_pt_gp_members--;
 	list_del(&peer_port->tg_pt_gp_peer_list);
 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
 
-- 
2.26.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2020-04-29  9:45 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-29  9:44 [RFC PATCH 00/11] scsi: target/core: Improve ALUA configuration for multi-node TCM Roman Bolshakov
2020-04-29  9:44 ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 01/11] scsi: target/core: Add a way to hide a port group Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 02/11] scsi: target/core: Set MULTIP bit for se_device with multiple ports Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 03/11] scsi: target/core: Add cleanup sequence in core_tpg_register() Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 04/11] scsi: target/core: Add RTPI field to target port Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 05/11] scsi: target/core: Use RTPI from " Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 06/11] scsi: target/core: Drop device-based RTPI Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 07/11] scsi: target/core: Add common port attributes Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 08/11] scsi: target/core: Add RTPI attribute for target port Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 09/11] scsi: target/core: Populate configfs for peer ports Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 10/11] scsi: target/core: Prevent RTPI conflicts Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov
2020-04-29  9:44 ` [RFC PATCH 11/11] scsi: target/core: Show peer ports in RTPG response Roman Bolshakov
2020-04-29  9:44   ` Roman Bolshakov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.