[PATCH 3/4] [Target_Core_Mod/PERSISTENT_RESERVATION]: Add support for PRIN SA READ_FULL_STATUS

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From 652c67d6ff1cfbb5a2e42613f65854b7993bba3e Mon Sep 17 00:00:00 2001
From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>
Date: Fri, 30 Jan 2009 00:29:32 -0800
Subject: [PATCH 3/4] [Target_Core_Mod/PERSISTENT_RESERVATION]: Add support for PRIN SA READ_FULL_STATUS

This patch adds support for PRIN Service Action READ_FULL_STATUS as defined
by spc4r17.  This patch adds struct target_core_fabric_ops->tpg_get_pr_transport_id()
and struct target_core_fabric_ops->tpg_get_pr_transport_id_len() for this purpose
as calls into loaded $FABRIC_MOD SCSI Target Ports and Logical Units from the
Target_Core_Mod/ConfigFS SCSI device server.

This patch defines the $FABRIC_MOD independent aspects of Target_Core_Mod/ConfigFS
SPC-3 compliant Persistent Reservations support.  Here is what it looks like
with multiple PR registrations from two different Linux/iSCSI Initiatior nodes with
a WRITE_EXCLUSIVE reservation held:

opensuse:~# sg_persist -in --read-full-status -v /dev/sdb
    Persistent Reservation In cmd: 5e 03 00 00 00 00 00 20 00 00
  PR generation=0x2
    Key=0x5678efff
      All target ports bit set
      << Reservation holder >>
      scope: LU_SCOPE,  type: Write Exclusive
      Transport Id of initiator:
        iSCSI world wide unique port id: iqn.1993-08.org.debian:01:2dadf92d0ef
    Key=0x1234ffff
      All target ports bit clear
      Relative port address: 0x1
      not reservation holder
      Transport Id of initiator:
        iSCSI world wide unique port id: iqn.1996-04.de.suse:01:1661f9ee7b5

Tested with ALL_TG_PT=[1,0] bits using sg_persist on v2.6.29-rc2 32-bit HVM

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
 drivers/lio-core/target_core_base.h       |    1 +
 drivers/lio-core/target_core_fabric_ops.h |    4 +-
 drivers/lio-core/target_core_pr.c         |  129 ++++++++++++++++++++++++++++-
 3 files changed, 130 insertions(+), 4 deletions(-)

diff --git a/drivers/lio-core/target_core_base.h b/drivers/lio-core/target_core_base.h
index c773c13..c900517 100644
--- a/drivers/lio-core/target_core_base.h
+++ b/drivers/lio-core/target_core_base.h
@@ -225,6 +225,7 @@ typedef struct t10_reservation_template_s {
 
 typedef struct t10_pr_registration_s {
 	int pr_reg_all_tg_pt; /* Reservation effects all target ports */
+	int pr_res_holder;
 	int pr_res_type;
 	int pr_res_scope;
 	u32 pr_res_generation;
diff --git a/drivers/lio-core/target_core_fabric_ops.h b/drivers/lio-core/target_core_fabric_ops.h
index 5693dac..3fdf305 100644
--- a/drivers/lio-core/target_core_fabric_ops.h
+++ b/drivers/lio-core/target_core_fabric_ops.h
@@ -1,8 +1,10 @@
 struct target_core_fabric_ops {
 	char *(*get_fabric_name)(void);
 	char *(*tpg_get_wwn)(struct se_portal_group_s *);
-	u32 (*tpg_get_tag)(struct se_portal_group_s *);
+	u16 (*tpg_get_tag)(struct se_portal_group_s *);
 	u32 (*tpg_get_default_depth)(struct se_portal_group_s *);
+	u32 (*tpg_get_pr_transport_id)(struct se_portal_group_s *, struct se_node_acl_s *, int *, unsigned char *);
+	u32 (*tpg_get_pr_transport_id_len)(struct se_portal_group_s *, struct se_node_acl_s *, int *);
 	int (*tpg_check_demo_mode)(struct se_portal_group_s *);
 	int (*tpg_check_demo_mode_cache)(struct se_portal_group_s *);
 	int (*tpg_check_demo_mode_write_protect)(struct se_portal_group_s *);
diff --git a/drivers/lio-core/target_core_pr.c b/drivers/lio-core/target_core_pr.c
index f48b092..3b50ff2 100644
--- a/drivers/lio-core/target_core_pr.c
+++ b/drivers/lio-core/target_core_pr.c
@@ -698,6 +698,7 @@ static int core_scsi3_pro_reserve (
 	 */
 	pr_reg->pr_res_scope = scope;
 	pr_reg->pr_res_type = type;
+	pr_reg->pr_res_holder = 1;
 	dev->dev_pr_res_holder = pr_reg;
 
 	printk("SPC-3 PR [%s] Service Action: RESERVE created new reservation"
@@ -875,7 +876,7 @@ static int core_scsi3_emulate_pro_release (
 	/*
 	 * Clear TYPE and SCOPE for the next PROUT Service Action: RESERVE
 	 */
-	pr_reg->pr_res_type = pr_reg->pr_res_scope = 0;
+	pr_reg->pr_res_holder = pr_reg->pr_res_type = pr_reg->pr_res_scope = 0;
 	spin_unlock(&dev->dev_reservation_lock);
 
 	return(0);
@@ -1162,8 +1163,132 @@ static int core_scsi3_pri_report_capabilities (se_cmd_t *cmd)
 	return(0);
 }
 
+/*
+ * PERSISTENT_RESERVE_IN Service Action READ_FULL_STATUS
+ *
+ * See spc4r17 section 6.13.5 Table 168 and 169
+ */
 static int core_scsi3_pri_read_full_status (se_cmd_t *cmd)
 {
+	se_device_t *se_dev = SE_DEV(cmd);
+	se_node_acl_t *se_nacl;
+	se_subsystem_dev_t *su_dev = SU_DEV(se_dev);
+	se_portal_group_t *se_tpg;
+	t10_pr_registration_t *pr_reg, *pr_reg_tmp;
+	t10_reservation_template_t *pr_tmpl = &SU_DEV(se_dev)->t10_reservation;
+	unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+	u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len;
+	u32 off = 8; /* off into first Full Status descriptor */
+	int format_code = 0;
+	
+	buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff);
+	buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff);
+	buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff);
+	buf[3] = (T10_RES(su_dev)->pr_generation & 0xff);
+
+	spin_lock(&pr_tmpl->registration_lock);
+	list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+			&pr_tmpl->registration_list, pr_reg_list) {
+
+		se_nacl = pr_reg->pr_reg_nacl;
+		se_tpg = pr_reg->pr_reg_nacl->se_tpg;
+		add_desc_len = 0;
+		/*
+		 * Determine expected length of $FABRIC_MOD specific
+		 * TransportID full status descriptor..
+		 */
+		exp_desc_len = TPG_TFO(se_tpg)->tpg_get_pr_transport_id_len(
+				se_tpg, se_nacl, &format_code);
+
+		if (((exp_desc_len > add_desc_len) + add_len) > cmd->data_length) {
+			printk(KERN_WARNING "SPC-3 PRIN READ_FULL_STATUS ran"
+				" out of buffer: %d\n", cmd->data_length);
+			break;
+		}
+		/*
+		 * Set RESERVATION KEY
+		 */
+		buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff);
+		buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff);
+		buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff);
+		buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff);
+		buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff);
+		buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff);
+		buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff);
+		buf[off++] = (pr_reg->pr_res_key & 0xff);
+		off += 4; /* Skip Over Reserved area */
+
+		/*
+		 * Set ALL_TG_PT bit if PROUT SA REGISTER had this set.
+		 */
+		if (pr_reg->pr_reg_all_tg_pt)
+			buf[off] = 0x02;
+		/*
+		 * The se_lun_t pointer will be present for the
+		 * reservation holder for PR_HOLDER bit.
+		 *
+		 * Also, if this registration is the reservation
+		 * holder, fill in SCOPE and TYPE in the next byte.
+		 */
+		if (pr_reg->pr_res_holder) {	
+			buf[off++] |= 0x01;
+			buf[off++] = (pr_reg->pr_res_scope & 0xf0) |
+				     (pr_reg->pr_res_type & 0x0f);
+		} else
+			off += 2;
+		
+		off += 4; /* Skip over reserved area */
+		/*
+		 * From spc4r17 6.3.15:
+		 *
+		 * If the ALL_TG_PT bit set to zero, the RELATIVE TARGET PORT
+		 * IDENTIFIER field contains the relative port identifier (see
+		 * 3.1.120) of the target port that is part of the I_T nexus
+		 * described by this full status descriptor. If the ALL_TG_PT
+		 * bit is set to one, the contents of the RELATIVE TARGET PORT
+		 * IDENTIFIER field are not defined by this standard.
+		 */
+		if (!(pr_reg->pr_reg_all_tg_pt)) {
+			u16 tpgt = TPG_TFO(se_tpg)->tpg_get_tag(se_tpg);
+
+			buf[off++] = ((tpgt >> 8) & 0xff);
+			buf[off++] = (tpgt & 0xff);
+		} else
+			off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFER */
+
+		/*
+		 * Now, have the $FABRIC_MOD fill in the protocol identifier
+		 */
+		desc_len = TPG_TFO(se_tpg)->tpg_get_pr_transport_id(se_tpg,
+				se_nacl, &format_code, &buf[off+4]);
+		/*
+		 * Set the ADDITIONAL DESCRIPTOR LENGTH
+		 */
+		buf[off++] = ((desc_len >> 24) & 0xff);
+		buf[off++] = ((desc_len >> 16) & 0xff);
+		buf[off++] = ((desc_len >> 8) & 0xff);
+		buf[off++] = (desc_len & 0xff);
+		/*
+		 * Size of full desctipor header minus TransportID
+		 * containing $FABRIC_MOD specific) initiator device/port
+		 * WWN information.
+		 * 
+		 *  See spc4r17 Section 6.13.5 Table 169
+		 */
+		add_desc_len = (24 + desc_len);
+
+		off += desc_len;
+		add_len += add_desc_len;
+	}
+	spin_unlock(&pr_tmpl->registration_lock);
+	/*
+	 * Set ADDITIONAL_LENGTH
+	 */
+	buf[4] = ((add_len >> 24) & 0xff);
+	buf[5] = ((add_len >> 16) & 0xff);
+	buf[6] = ((add_len >> 8) & 0xff);
+	buf[7] = (add_len & 0xff);
+
 	return(0);
 }
 
@@ -1176,10 +1301,8 @@ static int core_scsi3_emulate_pr_in (se_cmd_t *cmd, unsigned char *cdb)
 		return(core_scsi3_pri_read_reservation(cmd));
 	case PRI_REPORT_CAPABILITIES:
 		return(core_scsi3_pri_report_capabilities(cmd));
-#if 0
 	case PRI_READ_FULL_STATUS:
 		return(core_scsi3_pri_read_full_status(cmd));
-#endif
 	default:
 		printk(KERN_ERR "Unknown PERSISTENT_RESERVE_IN service"
 			" action: 0x%02x\n", cdb[1] & 0x1f);
-- 
1.5.4.1



--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux