diff mbox series

[6/7] scsi: target: core: Add RTPI attribute for target port

Message ID 20220906154519.27487-7-d.bogdanov@yadro.com
State New
Headers show
Series scsi: target: make RTPI an TPG identifier | expand

Commit Message

Dmitry Bogdanov Sept. 6, 2022, 3:45 p.m. UTC
From: Roman Bolshakov <r.bolshakov@yadro.com>

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>
Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
---
 drivers/target/target_core_tpg.c | 70 ++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

Comments

Mike Christie Sept. 30, 2022, 12:03 a.m. UTC | #1
On 9/6/22 10:45 AM, Dmitry Bogdanov wrote:
> +
> +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;
> +	bool rtpi_changed = false;
> +	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 */
> +	spin_lock(&g_tpg_lock);
> +
> +	list_for_each_entry(tpg, &g_tpg_list, tpg_list) {
> +		if (se_tpg != tpg && val == tpg->tpg_rtpi) {
> +			spin_unlock(&g_tpg_lock);
> +			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));
> +			return -EINVAL;
> +		}
> +	}
> +
> +	if (se_tpg->tpg_rtpi != val) {
> +		se_tpg->tpg_rtpi = val;
> +		rtpi_changed = true;
> +	}
> +	spin_unlock(&g_tpg_lock);
> +
> +	if (rtpi_changed)
> +		core_tpg_ua(se_tpg, 0x3f, ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED);
> +	ret = count;
> +
> +	return ret;

Just return count.
Dmitry Bogdanov Oct. 4, 2022, 4:12 p.m. UTC | #2
On Thu, Sep 29, 2022 at 07:03:52PM -0500, Mike Christie wrote:
> 
> On 9/6/22 10:45 AM, Dmitry Bogdanov wrote:
> > +
> > +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;
> > +     bool rtpi_changed = false;
> > +     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 */
> > +     spin_lock(&g_tpg_lock);
> > +
> > +     list_for_each_entry(tpg, &g_tpg_list, tpg_list) {
> > +             if (se_tpg != tpg && val == tpg->tpg_rtpi) {
> > +                     spin_unlock(&g_tpg_lock);
> > +                     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));
> > +                     return -EINVAL;
> > +             }
> > +     }
> > +
> > +     if (se_tpg->tpg_rtpi != val) {
> > +             se_tpg->tpg_rtpi = val;
> > +             rtpi_changed = true;
> > +     }
> > +     spin_unlock(&g_tpg_lock);
> > +
> > +     if (rtpi_changed)
> > +             core_tpg_ua(se_tpg, 0x3f, ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED);
> > +     ret = count;
> > +
> > +     return ret;
> 
> Just return count.

Yes, will do.
diff mbox series

Patch

diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index b359c83a99c6..85c9473a38fd 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -715,6 +715,76 @@  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;
+	bool rtpi_changed = false;
+	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 */
+	spin_lock(&g_tpg_lock);
+
+	list_for_each_entry(tpg, &g_tpg_list, tpg_list) {
+		if (se_tpg != tpg && val == tpg->tpg_rtpi) {
+			spin_unlock(&g_tpg_lock);
+			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));
+			return -EINVAL;
+		}
+	}
+
+	if (se_tpg->tpg_rtpi != val) {
+		se_tpg->tpg_rtpi = val;
+		rtpi_changed = true;
+	}
+	spin_unlock(&g_tpg_lock);
+
+	if (rtpi_changed)
+		core_tpg_ua(se_tpg, 0x3f, ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED);
+	ret = count;
+
+	return ret;
+}
+
+CONFIGFS_ATTR(core_tpg_, rtpi);
+
 struct configfs_attribute *core_tpg_attrib_attrs[] = {
+	&core_tpg_attr_rtpi,
 	NULL,
 };