[PATCH 2/2] [Target_Core_Mod/Persistent_Reservations]: Add UNITATTENTION support for PROUT SAs

From: Nicholas A. Bellinger
Date: Wed Mar 25 2009 - 02:07:48 EST


>From d3aed0204976bffa99505e606f2909fd61b3b8f3 Mon Sep 17 00:00:00 2001
From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>
Date: Tue, 24 Mar 2009 22:25:36 -0700
Subject: [PATCH 2/2] [Target_Core_Mod/Persistent_Reservations]: Add UNIT ATTENTION support for PROUT SAs

This patch adds support for SAM4 defined UNIT ATTENTION conditions in SPC-3 compliant
Persistent Reservations PROUT Service Actions REGISTER + SARK=0 (UNREGISTER), RELEASE,
and CLEAR.

The respective UNIT ATTENTION ASCQs for the non PROUT SA calling I_T Nexus
ports are ASCQ_2AH_RESERVATIONS_RELEASED, ASCQ_2AH_RESERVATIONS_RELEASED,
and ASCQ_2AH_RESERVATIONS_PREEMPTED.

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
drivers/lio-core/target_core_pr.c | 107 +++++++++++++++++++++++++++++++++---
1 files changed, 98 insertions(+), 9 deletions(-)

diff --git a/drivers/lio-core/target_core_pr.c b/drivers/lio-core/target_core_pr.c
index d733bae..0ddf54c 100644
--- a/drivers/lio-core/target_core_pr.c
+++ b/drivers/lio-core/target_core_pr.c
@@ -38,6 +38,7 @@
#include <target_core_hba.h>
#include <target_core_transport.h>
#include <target_core_pr.h>
+#include <target_core_ua.h>
#include <target_core_transport_plugin.h>
#include <target_core_fabric_ops.h>
#include <target_core_configfs.h>
@@ -532,12 +533,13 @@ static void core_scsi3_put_pr_reg(t10_pr_registration_t *pr_reg)
smp_mb__after_atomic_dec();
}

-static void core_scsi3_check_implict_release(
+static int core_scsi3_check_implict_release(
se_device_t *dev,
t10_pr_registration_t *pr_reg)
{
se_node_acl_t *nacl = pr_reg->pr_reg_nacl;
t10_pr_registration_t *pr_res_holder;
+ int ret = 0;

spin_lock(&dev->dev_reservation_lock);
pr_res_holder = dev->dev_pr_res_holder;
@@ -556,10 +558,12 @@ static void core_scsi3_check_implict_release(
* field set to zero (see 5.7.11.3).
*/
__core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0);
-#warning FIXME: Registrants only, UA + RESERVATIONS RELEASED
+ ret = 1;
#warning FIXME: All Registrants, only release reservation when last registration is freed.
}
spin_unlock(&dev->dev_reservation_lock);
+
+ return ret;
}

/*
@@ -681,9 +685,9 @@ static int core_scsi3_emulate_pro_register(
se_dev_entry_t *se_deve;
se_lun_t *se_lun = SE_LUN(cmd);
se_portal_group_t *se_tpg;
- t10_pr_registration_t *pr_reg;
+ t10_pr_registration_t *pr_reg, *pr_reg_p;
t10_reservation_template_t *pr_tmpl = &SU_DEV(dev)->t10_reservation;
- int ret = 0;
+ int pr_holder = 0, ret = 0, type;

if (!(se_sess) || !(se_lun)) {
printk(KERN_ERR "SPC-3 PR: se_sess || se_lun_t is NULL!\n");
@@ -748,6 +752,8 @@ static int core_scsi3_emulate_pro_register(
core_scsi3_put_pr_reg(pr_reg);
return PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
+ type = pr_reg->pr_res_type;
+
if (!(ignore_key)) {
if (res_key != pr_reg->pr_res_key) {
printk(KERN_ERR "SPC-3 PR REGISTER: Received"
@@ -771,9 +777,38 @@ static int core_scsi3_emulate_pro_register(
* Nexus.
*/
if (!(sa_res_key)) {
- core_scsi3_check_implict_release(SE_DEV(cmd), pr_reg);
+ pr_holder = core_scsi3_check_implict_release(
+ SE_DEV(cmd), pr_reg);
+
spin_lock(&pr_tmpl->registration_lock);
+ /*
+ * Release the calling I_T Nexus registration now..
+ */
__core_scsi3_free_registration(SE_DEV(cmd), pr_reg, 1);
+ /*
+ * From spc4r17, section 5.7.11.3 Unregistering
+ *
+ * If the persistent reservation is a registrants only
+ * type, the device server shall establish a unit
+ * attention condition for the initiator port associated
+ * with every registered I_T nexus except for the I_T
+ * nexus on which the PERSISTENT RESERVE OUT command was
+ * received, with the additional sense code set to
+ * RESERVATIONS RELEASED.
+ */
+ if (pr_holder &&
+ ((type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
+ (type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY))) {
+ list_for_each_entry(pr_reg_p,
+ &pr_tmpl->registration_list,
+ pr_reg_list) {
+
+ core_scsi3_ua_allocate(
+ pr_reg_p->pr_reg_nacl,
+ cmd->orig_fe_lun, 0x2A,
+ ASCQ_2AH_RESERVATIONS_RELEASED);
+ }
+ }
spin_unlock(&pr_tmpl->registration_lock);
} else {
/*
@@ -1047,7 +1082,8 @@ static int core_scsi3_emulate_pro_release(
se_device_t *dev = cmd->se_dev;
se_session_t *se_sess = SE_SESS(cmd);
se_lun_t *se_lun = SE_LUN(cmd);
- t10_pr_registration_t *pr_reg, *pr_res_holder;
+ t10_pr_registration_t *pr_reg, *pr_reg_p, *pr_res_holder;
+ t10_reservation_template_t *pr_tmpl = &SU_DEV(dev)->t10_reservation;

if (!(se_sess) || !(se_lun)) {
printk(KERN_ERR "SPC-3 PR: se_sess || se_lun_t is NULL!\n");
@@ -1137,10 +1173,50 @@ static int core_scsi3_emulate_pro_release(
core_scsi3_put_pr_reg(pr_reg);
return PYX_TRANSPORT_RESERVATION_CONFLICT;
}
+ /*
+ * In response to a persistent reservation release request from the
+ * persistent reservation holder the device server shall perform a
+ * release by doing the following as an uninterrupted series of actions:
+ * a) Release the persistent reservation;
+ * b) Not remove any registration(s);
+ * c) If the released persistent reservation is a registrants only type
+ * or all registrants type persistent reservation,
+ * the device server shall establish a unit attention condition for
+ * the initiator port associated with every regis-
+ * tered I_T nexus other than I_T nexus on which the PERSISTENT
+ * RESERVE OUT command with RELEASE service action was received,
+ * with the additional sense code set to RESERVATIONS RELEASED; and
+ * d) If the persistent reservation is of any other type, the device
+ * server shall not establish a unit attention condition.
+ */
__core_scsi3_complete_pro_release(dev, se_sess->se_node_acl,
pr_reg, 1);
+
+ if ((type != PR_TYPE_WRITE_EXCLUSIVE_REGONLY) &&
+ (type != PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) &&
+ (type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) &&
+ (type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return 0;
+ }
spin_unlock(&dev->dev_reservation_lock);

+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry(pr_reg_p, &pr_tmpl->registration_list,
+ pr_reg_list) {
+ /*
+ * Do not establish a UNIT ATTENTION condition
+ * for the calling I_T Nexus
+ */
+ if (pr_reg_p == pr_reg)
+ continue;
+
+ core_scsi3_ua_allocate(pr_reg_p->pr_reg_nacl, cmd->orig_fe_lun,
+ 0x2A, ASCQ_2AH_RESERVATIONS_RELEASED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
core_scsi3_put_pr_reg(pr_reg);
return 0;
}
@@ -1150,9 +1226,11 @@ static int core_scsi3_emulate_pro_clear(
u64 res_key)
{
se_device_t *dev = cmd->se_dev;
+ se_node_acl_t *pr_reg_nacl;
se_session_t *se_sess = SE_SESS(cmd);
t10_reservation_template_t *pr_tmpl = &SU_DEV(dev)->t10_reservation;
t10_pr_registration_t *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder;
+ int calling_it_nexus = 0;
/*
* Locate the existing *pr_reg via se_node_acl_t pointers
*/
@@ -1199,9 +1277,20 @@ static int core_scsi3_emulate_pro_clear(
spin_lock(&pr_tmpl->registration_lock);
list_for_each_entry_safe(pr_reg, pr_reg_tmp,
&pr_tmpl->registration_list, pr_reg_list) {
-#warning FIXME: UA + RESERVATIONS PREEMPTED for all other registered I_T nexuses
- __core_scsi3_free_registration(dev, pr_reg,
- (pr_reg_n == pr_reg) ? 1 : 0);
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ __core_scsi3_free_registration(dev, pr_reg, calling_it_nexus);
+ /*
+ * e) Establish a unit attention condition for the initiator
+ * port associated with every registered I_T nexus other
+ * than the I_T nexus on which the PERSISTENT RESERVE OUT
+ * command with CLEAR service action was received, with the
+ * additional sense code set to RESERVATIONS PREEMPTED.
+ */
+ if (!(calling_it_nexus))
+ core_scsi3_ua_allocate(pr_reg_nacl, cmd->orig_fe_lun,
+ 0x2A, ASCQ_2AH_RESERVATIONS_PREEMPTED);
}
spin_unlock(&pr_tmpl->registration_lock);

--
1.5.4.1



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