[PATCH 1/3] [TCM/PR]: Add support for compatible reservation handling (CRH=1)

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

 



From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>

This patch adds proper support for compatible reservation handling (CRH=1) as defined by
SPC-4 Section 15.7.3 'Exceptions to SPC-2 RESERVE and RELEASE behavior' in a new function
core_scsi2_emulate_crh().  This CRH=1 logic allows legacy RESERVE and RELEASE to be completed GOOD
status in the following cases when an >= SPC-3 reservation or registration(s) exist:

                a) An I_T nexus that is a persistent reservation holder; or
                b) An I_T nexus that is registered if a registrants only or
                   all registrants type persistent reservation is present.

This patch also adds a SPC-2 defined check in the new core_scsi2_emulate_crh() to return
RESERVATION_CONFLICT when any other >= SPC-3 registrations exist that are not allowed by
CRH=1 logic.  It also adds the reserve check in core_scsi3_emulate_pr() to return RESERVATION_CONFLICT
for any received PERSISTENT_RESERVE_[IN,OUT] CDB when a legacy SPC-2 reservation is held.

Finally, this patch adds checks in core_scsi3_pr_seq_non_holder() and
core_scsi3_pr_reservation_check() to make the calls to core_scsi2_reservation_seq_non_holder()
and core_scsi2_reservation_check() respectively when a legacy SPC-2 reservation exists.

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
 drivers/target/target_core_pr.c |  176 +++++++++++++++++++++++++++++----------
 include/target/target_core_pr.h |    1 +
 2 files changed, 131 insertions(+), 46 deletions(-)

diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 93c4f7c..a1fcb56 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -2,10 +2,10 @@
  * Filename:  target_core_pr.c
  *
  * This file contains SPC-3 compliant persistent reservations and
- * legacy SPC-2 reservations.
+ * legacy SPC-2 reservations with compatible reservation handling (CRH=1)
  *
- * Copyright (c) 2009 Rising Tide, Inc.
- * Copyright (c) 2009 Linux-iSCSI.org
+ * Copyright (c) 2009, 2010 Rising Tide, Inc.
+ * Copyright (c) 2009, 2010 Linux-iSCSI.org
  *
  * Nicholas A. Bellinger <nab@xxxxxxxxxx>
  *
@@ -120,6 +120,7 @@ int core_scsi2_reservation_release(se_cmd_t *cmd)
 		return 0;
 	}
 	dev->dev_reserved_node_acl = NULL;
+	dev->dev_flags &= ~DF_SPC2_RESERVATIONS;
 	printk(KERN_INFO "SCSI-2 Released reservation for %s LUN: %u ->"
 		" MAPPED LUN: %u for %s\n", TPG_TFO(tpg)->get_fabric_name(),
 		SE_LUN(cmd)->unpacked_lun, cmd->se_deve->mapped_lun,
@@ -140,9 +141,8 @@ int core_scsi2_reservation_reserve(se_cmd_t *cmd)
 	    (T_TASK(cmd)->t_task_cdb[1] & 0x02)) {
 		printk(KERN_ERR "LongIO and Obselete Bits set, returning"
 				" ILLEGAL_REQUEST\n");
-		return -1;
+		return PYX_TRANSPORT_ILLEGAL_REQUEST;
 	}
-
 	/*
 	 * This is currently the case for target_core_mod passthrough se_cmd_t
 	 * ops
@@ -163,7 +163,7 @@ int core_scsi2_reservation_reserve(se_cmd_t *cmd)
 			cmd->se_deve->mapped_lun,
 			sess->se_node_acl->initiatorname);
 		spin_unlock(&dev->dev_reservation_lock);
-		return 1;
+		return PYX_TRANSPORT_RESERVATION_CONFLICT;
 	}
 
 	dev->dev_reserved_node_acl = sess->se_node_acl;
@@ -178,6 +178,99 @@ int core_scsi2_reservation_reserve(se_cmd_t *cmd)
 }
 EXPORT_SYMBOL(core_scsi2_reservation_reserve);
 
+static t10_pr_registration_t *core_scsi3_locate_pr_reg(se_device_t *,
+					se_node_acl_t *);
+static void core_scsi3_put_pr_reg(t10_pr_registration_t *);
+
+/*
+ * Setup in target_core_transport.c:transport_generic_cmd_sequencer()
+ * and called via struct se_cmd_s->transport_emulate_cdb() in TCM processing
+ * thread context.
+ */
+int core_scsi2_emulate_crh(struct se_cmd_s *cmd)
+{
+	se_session_t *se_sess = cmd->se_sess;
+	se_subsystem_dev_t *su_dev = cmd->se_dev->se_sub_dev;
+	t10_pr_registration_t *pr_reg;
+	t10_reservation_template_t *pr_tmpl = &su_dev->t10_reservation;
+	unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0];
+	int crh = (T10_RES(su_dev)->res_type == SPC3_PERSISTENT_RESERVATIONS);
+	int conflict = 0;
+
+	if (!(se_sess))
+		return 0;
+
+	if (!(crh))
+		goto after_crh;
+
+	pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl);
+	if (pr_reg) {
+		/*
+		 * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE
+		 * behavior
+		 *
+		 * A RESERVE(6) or RESERVE(10) command shall complete with GOOD
+		 * status, but no reservation shall be established and the
+		 * persistent reservation shall not be changed, if the command
+		 * is received from a) and b) below.
+		 *
+		 * A RELEASE(6) or RELEASE(10) command shall complete with GOOD
+		 * status, but the persistent reservation shall not be released,
+		 * if the command is received from a) and b)
+		 * 
+		 * a) An I_T nexus that is a persistent reservation holder; or
+		 * b) An I_T nexus that is registered if a registrants only or
+		 *    all registrants type persistent reservation is present.
+		 *
+		 * In all other cases, a RESERVE(6) command, RESERVE(10) command,
+		 * RELEASE(6) command, or RELEASE(10) command shall be processed
+		 * as defined in SPC-2.
+		 */
+		if (pr_reg->pr_res_holder) {
+			core_scsi3_put_pr_reg(pr_reg);
+			return 0;
+		}
+		if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
+		    (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) ||
+		    (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+		    (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+			core_scsi3_put_pr_reg(pr_reg);
+			return 0;
+		}
+		core_scsi3_put_pr_reg(pr_reg);
+		conflict = 1;
+	} else {
+		/*
+		 * Following spc2r20 5.5.1 Reservations overview:
+		 *
+		 * If a logical unit has executed a PERSISTENT RESERVE OUT
+		 * command with the REGISTER or the REGISTER AND IGNORE
+		 * EXISTING KEY service action and is still registered by any
+		 * initiator, all RESERVE commands and all RELEASE commands
+		 * regardless of initiator shall conflict and shall terminate
+		 * with a RESERVATION CONFLICT status.
+		 */
+		spin_lock(&pr_tmpl->registration_lock);	
+		conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1;
+		spin_unlock(&pr_tmpl->registration_lock);
+	}
+
+	if (conflict) {
+		printk(KERN_ERR "Received legacy SPC-2 RESERVE/RELEASE"
+			" while active SPC-3 registrations exist,"
+			" returning RESERVATION_CONFLICT\n");
+		return PYX_TRANSPORT_RESERVATION_CONFLICT;
+	}
+
+after_crh:
+	if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10))
+		return core_scsi2_reservation_reserve(cmd);
+	else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10))
+		return core_scsi2_reservation_release(cmd);
+	else
+		return PYX_TRANSPORT_INVALID_CDB_FIELD;		
+}
+
 /*
  * Begin SPC-3/SPC-4 Persistent Reservations emulation support
  *
@@ -197,6 +290,12 @@ static int core_scsi3_pr_seq_non_holder(
 	int we = 0; /* Write Exclusive */
 	int legacy = 0; /* Act like a legacy device and return
 			 * RESERVATION CONFLICT on some CDBs */
+	/*
+	 * A legacy SPC-2 reservation is being held.
+	 */
+	if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS)
+		return core_scsi2_reservation_seq_non_holder(cmd,
+					cdb, pr_reg_type);
 
 	se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
 
@@ -287,14 +386,15 @@ static int core_scsi3_pr_seq_non_holder(
 			return -1;
 		}
 		break;
-	/* FIXME PR + legacy RELEASE + RESERVE */
 	case RELEASE:
 	case RELEASE_10:
-		ret = 1; /* Conflict */
+		/* Handled by CRH=1 in core_scsi2_emulate_crh() */
+		ret = 0;
 		break;
 	case RESERVE:
 	case RESERVE_10:
-		ret = 1; /* Conflict */
+		/* Handled by CRH=1 in core_scsi2_emulate_crh() */
+		ret = 0;
 		break;
 	case TEST_UNIT_READY:
 		ret = (legacy) ? 1 : 0; /* Conflict for legacy */
@@ -447,6 +547,11 @@ static int core_scsi3_pr_reservation_check(
 
 	if (!(sess))
 		return 0;
+	/*
+	 * A legacy SPC-2 reservation is being held.
+	 */
+	if (dev->dev_flags & DF_SPC2_RESERVATIONS)
+		return core_scsi2_reservation_check(cmd, pr_reg_type);
 
 	spin_lock(&dev->dev_reservation_lock);
 	if (!(dev->dev_pr_res_holder)) {
@@ -462,22 +567,6 @@ static int core_scsi3_pr_reservation_check(
 	return ret;
 }
 
-static int core_scsi3_legacy_reserve(se_cmd_t *cmd)
-{
-	/*
-	 * FIXME: See spc4r17 Section 5.7.3
-	 */
-	return core_scsi2_reservation_reserve(cmd);
-}
-
-static int core_scsi3_legacy_release(se_cmd_t *cmd)
-{
-	/*
-	 * FIXME: See spc4r17 Section 5.7.3
-	 */
-	return core_scsi2_reservation_release(cmd);
-}
-
 static t10_pr_registration_t *__core_scsi3_alloc_registration(
 	se_device_t *dev,
 	se_node_acl_t *nacl,
@@ -3342,12 +3431,7 @@ static int core_scsi3_pri_report_capabilities(se_cmd_t *cmd)
 
 	buf[0] = ((add_len << 8) & 0xff);
 	buf[1] = (add_len & 0xff);
-	/*
-	 * FIXME: Leave these features disabled for now..
-	 */
-#if 0
 	buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */
-#endif
 	buf[2] |= 0x08; /* SIP_C: Specify Initiator Ports Capable bit */
 	buf[2] |= 0x04; /* ATP_C: All Target Ports Capable bit */
 	buf[2] |= 0x01; /* PTPL_C: Persistence across Target Power Loss bit */
@@ -3535,6 +3619,22 @@ static int core_scsi3_emulate_pr_in(se_cmd_t *cmd, unsigned char *cdb)
 int core_scsi3_emulate_pr(se_cmd_t *cmd)
 {
 	unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0];
+	se_device_t *dev = cmd->se_dev;
+	/*
+	 * Following spc2r20 5.5.1 Reservations overview:
+	 *
+	 * If a logical unit has been reserved by any RESERVE command and is
+	 * still reserved by any initiator, all PERSISTENT RESERVE IN and all
+	 * PERSISTENT RESERVE OUT commands shall conflict regardless of
+	 * initiator or service action and shall terminate with a RESERVATION
+	 * CONFLICT status.
+	 */
+	if (dev->dev_flags & DF_SPC2_RESERVATIONS) {
+		printk(KERN_ERR "Received PERSISTENT_RESERVE CDB while legacy"
+			" SPC-2 reservation is held, returning"
+			" RESERVATION_CONFLICT\n");
+		return PYX_TRANSPORT_RESERVATION_CONFLICT;
+	}
 
 	return (cdb[0] == PERSISTENT_RESERVE_OUT) ?
 	       core_scsi3_emulate_pr_out(cmd, cdb) :
@@ -3546,16 +3646,6 @@ static int core_pt_reservation_check(se_cmd_t *cmd, u32 *pr_res_type)
 	return 0;
 }
 
-static int core_pt_reserve(se_cmd_t *cmd)
-{
-	return 0;
-}
-
-static int core_pt_release(se_cmd_t *cmd)
-{
-	return 0;
-}
-
 static int core_pt_seq_non_holder(
 	se_cmd_t *cmd,
 	unsigned char *cdb,
@@ -3578,8 +3668,6 @@ int core_setup_reservations(se_device_t *dev)
 	    !(DEV_ATTRIB(dev)->emulate_reservations)) {
 		rest->res_type = SPC_PASSTHROUGH;
 		rest->t10_reservation_check = &core_pt_reservation_check;
-		rest->t10_reserve = &core_pt_reserve;
-		rest->t10_release = &core_pt_release;
 		rest->t10_seq_non_holder = &core_pt_seq_non_holder;
 		printk(KERN_INFO "%s: Using SPC_PASSTHROUGH, no reservation"
 			" emulation\n", TRANSPORT(dev)->name);
@@ -3592,16 +3680,12 @@ int core_setup_reservations(se_device_t *dev)
 	if (TRANSPORT(dev)->get_device_rev(dev) >= SCSI_3) {
 		rest->res_type = SPC3_PERSISTENT_RESERVATIONS;
 		rest->t10_reservation_check = &core_scsi3_pr_reservation_check;
-		rest->t10_reserve = &core_scsi3_legacy_reserve;
-		rest->t10_release = &core_scsi3_legacy_release;
 		rest->t10_seq_non_holder = &core_scsi3_pr_seq_non_holder;
 		printk(KERN_INFO "%s: Using SPC3_PERSISTENT_RESERVATIONS"
 			" emulation\n", TRANSPORT(dev)->name);
 	} else {
 		rest->res_type = SPC2_RESERVATIONS;
 		rest->t10_reservation_check = &core_scsi2_reservation_check;
-		rest->t10_reserve = &core_scsi2_reservation_reserve;
-		rest->t10_release = &core_scsi2_reservation_release;
 		rest->t10_seq_non_holder =
 				&core_scsi2_reservation_seq_non_holder;
 		printk(KERN_INFO "%s: Using SPC2_RESERVATIONS emulation\n",
diff --git a/include/target/target_core_pr.h b/include/target/target_core_pr.h
index c791506..08e365b 100644
--- a/include/target/target_core_pr.h
+++ b/include/target/target_core_pr.h
@@ -45,6 +45,7 @@
 
 extern struct kmem_cache *t10_pr_reg_cache;
 
+extern int core_scsi2_emulate_crh(struct se_cmd_s *);
 extern int core_scsi3_alloc_aptpl_registration(
 			struct t10_reservation_template_s *, u64,
 			unsigned char *, u32, unsigned char *, u16, u32,
-- 
1.5.6.5

--
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