[PATCH 6/7] [Target_Core_Mod/PERSISTENT_RESERVATION]: Add ServiceAction REGISTER logic

From: Nicholas A. Bellinger
Date: Mon Jan 26 2009 - 04:11:11 EST


>From efe89a76da4a6c065ab972884afecd786d6881f6 Mon Sep 17 00:00:00 2001
From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>
Date: Mon, 26 Jan 2009 00:41:53 -0800
Subject: [PATCH 6/7] [Target_Core_Mod/PERSISTENT_RESERVATION]: Add Service Action REGISTER logic

This patch adds a number of functions including proper support using sg3_utils
sg_persist --register. It also adds support for changing a registered registration
key and PERSISTENT_RESERVE_OUT Service Actions READ_KEYS and READ_RESERVATION.

This code follows spc4r14, and looks like the follwing from Target_Core_Mod/ConfigFS
for a *SINGLE* $HBA/$STORAGE_OBJECT:

/sys/kernel/config/target/core/
|-- iblock_0
| |-- hba_info
| `-- lvm_test0
| |-- attrib
| | |-- hw_max_sectors
| | |-- hw_queue_depth
| | |-- max_sectors
| | |-- queue_depth
| | |-- status_thread
| | |-- status_thread_tur
| | `-- task_timeout
| |-- control
| |-- enable
| |-- fd
| |-- info
| |-- pr
| | |-- res_holder
| | |-- res_pr_all_tgt_pts
| | |-- res_pr_generation
| | |-- res_pr_registered_i_pts
| | `-- res_type
| `-- wwn
| |-- evpd_assoc_logical_unit
| |-- evpd_assoc_scsi_target_device
| |-- evpd_assoc_target_port
| |-- evpd_protocol_identifier
| `-- evpd_unit_serial

Here is what it looks like from Target_Core_Mod/ConfigFS from a active
PR REGISTER invocation:

*) target_core_mod/IBLOCK: configfs

target:/mnt/sdb/lio-core-2.6# cat /sys/kernel/config/target/core/iblock_0/lvm_test0/pr/*
Not Implemented yet
Not Implemented Yet
0x00000004
iSCSI Node: iqn.1993-08.org.debian:01:2dadf92d0ef Key: 0x000000005678efff PRgen: 0x00000003
SPC3_PERSISTENT_RESERVATIONS

*) target_core_mod/IBLOCK: dmesg

SPC-3 PR [iSCSI] Service Action: REGISTER Initiator Node: iqn.1993-08.org.debian:01:2dadf92d0ef
SPC-3 PR [iSCSI] for SINGLE TCM Subsystem iblock Object Port(s)
SPC-3 PR [iSCSI] SA Res Key: 0x000000001234abcd PRgeneration: 0x00000000
SPC-3 PR [iSCSI] REGISTER: Changed Reservation Key for iqn.1993-08.org.debian:01:2dadf92d0ef to: 0x000000005678efff PRgeneration: 0x00000001

Here is what legacy SPC-2 Reservations looks like from ConfigFS

target:/mnt/sdb/lio-core-2.6# cat /sys/kernel/config/target/core/rd_mcp_0/ramdisk/pr/*
None
res_pr_generation only valid for SPC3_PERSISTENT_RESERVATIONS
res_pr_generation only valid for SPC3_PERSISTENT_RESERVATIONS
res_pr_registered_i_pts only valid for SPC3_PERSISTENT_RESERVATIONS
SPC2_RESERVATIONS

This code is a WIP for >= SPC-3 Persistent Rervations across
Target_Core_Mod/ConfigFS

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
drivers/lio-core/target_core_device.c | 5 +-
drivers/lio-core/target_core_pr.c | 495 ++++++++++++++++++++++++++++++++-
drivers/lio-core/target_core_pr.h | 18 ++
3 files changed, 501 insertions(+), 17 deletions(-)

diff --git a/drivers/lio-core/target_core_device.c b/drivers/lio-core/target_core_device.c
index 49d25b9..98334a4 100644
--- a/drivers/lio-core/target_core_device.c
+++ b/drivers/lio-core/target_core_device.c
@@ -50,6 +50,7 @@
#include <iscsi_target_error.h>
#include <target_core_device.h>
#include <target_core_hba.h>
+#include <target_core_pr.h>
#include <target_core_tpg.h>
#include <target_core_transport.h>
#include <target_core_fabric_ops.h>
@@ -565,9 +566,6 @@ done:
buf[2] = ((lun_count >> 8) & 0xff);
buf[3] = (lun_count & 0xff);

- se_task->task_scsi_status = GOOD;
- transport_complete_task(se_task, 1);
-
return(PYX_TRANSPORT_SENT_TO_TRANSPORT);
}

@@ -593,6 +591,7 @@ extern void se_release_device_for_hba (se_device_t *dev)
hba->dev_count--;
spin_unlock(&hba->device_lock);

+ core_scsi3_free_all_registrations(dev);
se_release_evpd_for_dev(dev);

kfree(dev->dev_status_queue_obj);
diff --git a/drivers/lio-core/target_core_pr.c b/drivers/lio-core/target_core_pr.c
index a81ceaf..ce1a5d3 100644
--- a/drivers/lio-core/target_core_pr.c
+++ b/drivers/lio-core/target_core_pr.c
@@ -42,6 +42,8 @@
#include <target_core_fabric_ops.h>
#include <target_core_configfs.h>

+extern struct kmem_cache *t10_pr_reg_cache;
+
#undef TARGET_CORE_PR_C

extern int core_scsi2_reservation_seq_non_holder (
@@ -149,6 +151,7 @@ extern int core_scsi2_reservation_reserve (se_cmd_t *cmd)
}

dev->dev_reserved_node_acl = sess->se_node_acl;
+ dev->dev_flags |= DF_SPC2_RESERVATIONS;
printk("SCSI-2 Reserved %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,
@@ -251,74 +254,536 @@ static int core_scsi3_pr_seq_non_holder (
return(1);
}

+static u32 core_scsi3_pr_generation (se_device_t *dev)
+{
+ se_subsystem_dev_t *su_dev = SU_DEV(dev);
+ u32 prg;
+ /*
+ * PRGeneration field shall contain the value of a 32-bit wrapping
+ * counter mainted by the device server.
+ *
+ * Note that this is done regardless of Active Persist across
+ * Target PowerLoss (APTPL)
+ *
+ * See spc4r17 section 6.3.12 READ_KEYS service action
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ prg = T10_RES(su_dev)->pr_generation++;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return(prg);
+}
+
static int core_scsi3_pr_reservation_check (se_cmd_t *cmd)
{
+ se_device_t *dev = cmd->se_dev;
+ se_session_t *sess = cmd->se_sess;
+ int ret;
+
+ if (!(sess))
+ return(0);
+
+ spin_lock(&dev->dev_reservation_lock);
+ if (!(dev->dev_pr_res_holder)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return(0);
+ }
+ ret = (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) ? -1 : 0;
+ spin_unlock(&dev->dev_reservation_lock);
+
return(0);
}

static int core_scsi3_legacy_reserve (se_cmd_t *cmd)
{
- return(0);
+ /*
+ * 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,
+ se_dev_entry_t *deve,
+ u64 sa_res_key,
+ int all_tg_pt)
+{
+ struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+ t10_reservation_template_t *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ t10_pr_registration_t *pr_reg;
+
+ if (!(pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_KERNEL))) {
+ printk(KERN_ERR "Unable to allocate t10_pr_registration_t\n");
+ return(NULL);
+ }
+
+ INIT_LIST_HEAD(&pr_reg->pr_reg_list);
+ pr_reg->pr_reg_nacl = nacl;
+ pr_reg->pr_reg_deve = deve;
+ pr_reg->pr_res_key = sa_res_key;
+ pr_reg->pr_reg_all_tg_pt = all_tg_pt;
+ /*
+ * Increment PRgeneration counter for se_device_t upon a successful
+ * REGISTER, see spc4r17 section 6.3.2 READ_KEYS service action
+ */
+ pr_reg->pr_res_generation = core_scsi3_pr_generation(dev);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list);
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ deve->deve_flags |= DEF_PR_REGISTERED;
+ printk("SPC-3 PR [%s] Service Action: REGISTER Initiator Node: %s\n",
+ tfo->get_fabric_name(), nacl->initiatorname);
+ printk("SPC-3 PR [%s] for %s TCM Subsystem %s Object Port(s)\n",
+ tfo->get_fabric_name(), (pr_reg->pr_reg_all_tg_pt) ?
+ "ALL" : "SINGLE", TRANSPORT(dev)->name);
+ printk("SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration: 0x%08x\n",
+ tfo->get_fabric_name(), pr_reg->pr_res_key,
+ pr_reg->pr_res_generation);
+
+ return(pr_reg);
+}
+
+static t10_pr_registration_t *core_scsi3_locate_pr_reg (
+ se_device_t *dev,
+ se_node_acl_t *nacl)
+{
+ t10_reservation_template_t *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ t10_pr_registration_t *pr_reg, *pr_reg_tmp;
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+ if (pr_reg->pr_reg_nacl == nacl) {
+ spin_unlock(&pr_tmpl->registration_lock);
+ return(pr_reg);
+ }
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ return(NULL);
+}
+
+static void core_scsi3_free_registration (
+ se_device_t *dev,
+ t10_pr_registration_t *pr_reg)
+{
+ se_node_acl_t *nacl = pr_reg->pr_reg_nacl;
+ struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+ t10_reservation_template_t *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+
+ pr_reg->pr_reg_deve->deve_flags &= ~DEF_PR_REGISTERED;
+
+ printk("SPC-3 PR [%s] Service Action: UNREGISTER Initiator Node: %s\n",
+ tfo->get_fabric_name(), nacl->initiatorname);
+ printk("SPC-3 PR [%s] for %s TCM Subsystem %s Object Port(s)\n",
+ tfo->get_fabric_name(), (pr_reg->pr_reg_all_tg_pt) ?
+ "ALL" : "SINGLE", TRANSPORT(dev)->name);
+ printk("SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration: 0x%08x\n",
+ tfo->get_fabric_name(), pr_reg->pr_res_key,
+ pr_reg->pr_res_generation);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_del(&pr_reg->pr_reg_list);
+ pr_reg->pr_reg_deve = NULL;
+ pr_reg->pr_reg_nacl = NULL;
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ return;
+}
+
+extern void core_scsi3_free_all_registrations (
+ se_device_t *dev)
+{
+ t10_reservation_template_t *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ t10_pr_registration_t *pr_reg, *pr_reg_tmp;
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+ list_del(&pr_reg->pr_reg_list);
+
+ pr_reg->pr_reg_deve->deve_flags &= ~DEF_PR_REGISTERED;
+ pr_reg->pr_reg_deve = NULL;
+ pr_reg->pr_reg_nacl = NULL;
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ return;
+}
+
+static int core_scsi3_emulate_pro_register (
+ se_cmd_t *cmd,
+ u64 res_key,
+ u64 sa_res_key,
+ int aptpl,
+ int all_tg_pt,
+ int spec_i_pt)
+{
+ se_subsystem_dev_t *su_dev = SU_DEV(cmd->se_dev);
+ se_session_t *se_sess = SE_SESS(cmd);
+ 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;
+
+ if (!(se_sess) || !(se_lun)) {
+ printk(KERN_ERR "SPC-3 PR: se_sess || se_lun_t is NULL!\n");
+ return(PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE);
+ }
+ se_tpg = se_sess->se_tpg;
+ se_deve = &se_sess->se_node_acl->device_list[se_lun->unpacked_lun];
+
+ if (aptpl) {
+ printk("Activate Persistence across Target Power Loss = 1"
+ " not implemented yet\n");
+ return(PYX_TRANSPORT_INVALID_PARAMETER_LIST);
+ }
+ /*
+ * Follow logic from spc4r17 Section 5.7.7, Register Behaviors Table 47
+ */
+ if (!(se_deve->deve_flags & DEF_PR_REGISTERED)) {
+ if (res_key) {
+ printk("SPC-3 PR: Reservation Key non-zero for SA REGISTER,"
+ " returning CONFLICT\n");
+ return(PYX_TRANSPORT_RESERVATION_CONFLICT);
+ }
+ /*
+ * Do nothing but return GOOD status.
+ */
+ if (!(sa_res_key))
+ return(PYX_TRANSPORT_SENT_TO_TRANSPORT);
+
+ if (!(spec_i_pt)) {
+ /*
+ * Perform the Service Action REGISTER on the Initiator Port
+ * Endpoint that the PRO was received from on the Logical Unit
+ * of the SCSI device server.
+ */
+ pr_reg = core_scsi3_alloc_registration(SE_DEV(cmd),
+ se_sess->se_node_acl, se_deve,
+ sa_res_key, all_tg_pt);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "Unable to allocate t10_pr_registration_t\n");
+ return(PYX_TRANSPORT_INVALID_PARAMETER_LIST);
+ }
+ } else {
+ /*
+ * FIXME: Extract SCSI TransportID from Parameter list and
+ * loop through parameter list while calling logic from of
+ * core_scsi3_alloc_registration()
+ */
+ printk("Specify Initiator Ports (SPEC_I_PT) = 1 not implemented yet\n");
+ return(PYX_TRANSPORT_INVALID_PARAMETER_LIST);
+ }
+ } else {
+ /*
+ * Locate the existing *pr_reg via se_node_acl_t pointers
+ */
+ pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate"
+ " PR_REGISTERED *pr_reg\n");
+ return(PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE);
+ }
+ if (res_key != pr_reg->pr_res_key) {
+ printk(KERN_ERR "SPC-3 PR: Received res_key: 0x%016Lx"
+ " does not match existing SA REGISTER res_key:"
+ " 0x%016Lx\n", res_key, pr_reg->pr_res_key);
+ return(PYX_TRANSPORT_RESERVATION_CONFLICT);
+ }
+ if (spec_i_pt) {
+ printk(KERN_ERR "SPC-3 PR UNREGISTER: SPEC_I_PT"
+ " set while sa_res_key=0\n");
+ return(PYX_TRANSPORT_INVALID_PARAMETER_LIST);
+ }
+ /*
+ * sa_res_key=0 Unregister Reservation Key for registered I_T Nexus
+ * sa_res_key=1 Change Reservation Key for registered I_T Nexus
+ */
+ if (!(sa_res_key))
+ core_scsi3_free_registration(SE_DEV(cmd), pr_reg);
+ else {
+ /*
+ * Increment PRgeneration counter for se_device_t"
+ * upon a successful REGISTER, see spc4r17 section 6.3.2
+ * READ_KEYS service action.
+ */
+ pr_reg->pr_res_generation = core_scsi3_pr_generation(SE_DEV(cmd));
+ pr_reg->pr_res_key = sa_res_key;
+ printk("SPC-3 PR [%s] REGISTER: Changed Reservation Key"
+ " for %s to: 0x%016Lx PRgeneration: 0x%08x\n",
+ CMD_TFO(cmd)->get_fabric_name(),
+ pr_reg->pr_reg_nacl->initiatorname,
+ pr_reg->pr_res_key, pr_reg->pr_res_generation);
+ }
+ }
+
+ return(0);
+}
+
+static int core_scsi3_emulate_pro_reserve (
+ se_cmd_t *cmd,
+ int type,
+ int scope,
+ u64 res_key)
+{
+ return(0);
+}
+
+static int core_scsi3_emulate_pro_release (
+ se_cmd_t *cmd,
+ int type,
+ int scope,
+ u64 res_key)
+{
+ return(0);
+}
+
+static int core_scsi3_emulate_pro_clear (
+ se_cmd_t *cmd,
+ u64 res_key)
+{
+ core_scsi3_pr_generation(SE_DEV(cmd));
return(0);
}

-static int core_scsi3_emulate_pro_register (se_cmd_t *cmd)
+static int core_scsi3_emulate_pro_preempt (
+ se_cmd_t *cmd,
+ int type,
+ int scope,
+ u64 res_key,
+ u64 sa_res_key)
{
+ core_scsi3_pr_generation(SE_DEV(cmd));
return(0);
}

-static int core_scsi3_emulate_pro_reserve (se_cmd_t *cmd)
+static int core_scsi3_emulate_pro_preempt_and_abort (
+ se_cmd_t *cmd,
+ int type,
+ int scope,
+ u64 res_key,
+ u64 sa_res_key)
{
+ core_scsi3_pr_generation(SE_DEV(cmd));
return(0);
}

-static int core_scsi3_emulate_pro_release (se_cmd_t *cmd)
+static int core_scsi3_emulate_pro_register_and_ignore_existing_key (
+ se_cmd_t *cmd,
+ int sa_res_key,
+ int aptpl,
+ int all_tg_pt)
{
+ core_scsi3_pr_generation(SE_DEV(cmd));
return(0);
}

-static int core_scsi3_emulate_pro_clear (se_cmd_t *cmd)
+static int core_scsi3_emulate_pro_register_and_move (
+ se_cmd_t *cmd,
+ int type,
+ int scope,
+ u64 res_key,
+ u64 sa_res_key)
{
+ core_scsi3_pr_generation(SE_DEV(cmd));
return(0);
}

+static unsigned long long core_scsi3_extract_reservation_key (unsigned char *cdb)
+{
+ unsigned int __v1, __v2;
+
+ __v1 = (cdb[0] << 24) | (cdb[1] << 16) | (cdb[2] << 8) | cdb[3];
+ __v2 = (cdb[4] << 24) | (cdb[5] << 16) | (cdb[6] << 8) | cdb[7];
+
+ return(((unsigned long long)__v2) | (unsigned long long)__v1 << 32);
+}
+
+/*
+ * See spc4r17 section 6.14 Table 170
+ */
static int core_scsi3_emulate_pr_out (se_cmd_t *cmd, unsigned char *cdb)
{
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u64 res_key, sa_res_key;
+ int scope, type, spec_i_pt, all_tg_pt, aptpl;
+
+ /*
+ * FIXME: A NULL se_session_t pointer means an this is not coming from
+ * a $FABRIC_MOD's nexus, but from internal passthrough ops.
+ */
+ if (!(SE_SESS(cmd)))
+ return(PYX_TRANSPORT_LOGICAL_UNIT_COMMUNICATION_FAILURE);
+
+ /*
+ * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB)
+ */
+ scope = (cdb[2] & 0xf0);
+ type = (cdb[2] & 0x0f);
+ /*
+ * From PERSISTENT_RESERVE_OUT parameter list (payload)
+ */
+ res_key = core_scsi3_extract_reservation_key(&buf[0]);
+ sa_res_key = core_scsi3_extract_reservation_key(&buf[8]);
+ spec_i_pt = (buf[20] & 0x08);
+ all_tg_pt = (buf[20] & 0x04);
+ aptpl = (buf[20] & 0x01);
+
+ /*
+ * SPEC_I_PT=1 is only valid for Service action: REGISTER
+ */
+ if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER))
+ return(PYX_TRANSPORT_INVALID_PARAMETER_LIST);
+ /*
+ * (core_scsi3_emulate_pro_* function parameters
+ * are defined by spc4r17 Table 174:
+ * PERSISTENT_RESERVE_OUT service actions and valid parameters.
+ */
switch (cdb[1] & 0x1f) {
case PRO_REGISTER:
- return(core_scsi3_emulate_pro_register(cmd));
+ return(core_scsi3_emulate_pro_register(cmd,
+ res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt));
+#if 0
case PRO_RESERVE:
- return(core_scsi3_emulate_pro_reserve(cmd));
+ return(core_scsi3_emulate_pro_reserve(cmd,
+ type, scope, res_key));
case PRO_RELEASE:
- return(core_scsi3_emulate_pro_release(cmd));
+ return(core_scsi3_emulate_pro_release(cmd,
+ type, scope, res_key));
case PRO_CLEAR:
- return(core_scsi3_emulate_pro_clear(cmd));
+ return(core_scsi3_emulate_pro_clear(cmd,
+ res_key));
case PRO_PREEMPT:
+ return(core_scsi3_emulate_pro_preempt(cmd,
+ type, scope, res_key, sa_res_key));
case PRO_PREEMPT_AND_ABORT:
+ return(core_scsi3_emulate_pro_preempt_and_abort(cmd,
+ type, scope, res_key, sa_res_key));
case PRO_REGISTER_AND_IGNORE_EXISTING_KEY:
+ return(core_scsi3_emulate_pro_register_and_ignore_existing_key(cmd,
+ sa_res_key, aptpl, all_tg_pt));
case PRO_REGISTER_AND_MOVE:
- printk(KERN_ERR "Unsupported PERSISTENT_RESERVE_OUT service"
- " action: 0x%02x\n", cdb[1] & 0x1f);
- return(-1);
+ return(core_scsi3_emulate_pro_register_and_move(cmd,
+ type, scope, res_key, sa_res_key));
+#endif
default:
printk(KERN_ERR "Unknown PERSISTENT_RESERVE_OUT service"
" action: 0x%02x\n", cdb[1] & 0x1f);
- return(-1);
+ return(PYX_TRANSPORT_INVALID_CDB_FIELD);
}

+ return(PYX_TRANSPORT_INVALID_CDB_FIELD);
}

+/*
+ * PERSISTENT_RESERVE_IN Service Action READ_KEYS
+ *
+ * See spc4r17 section 5.7.6.2 and section 6.13.2, Table 160
+ */
static int core_scsi3_pri_read_keys (se_cmd_t *cmd)
{
+ se_device_t *se_dev = SE_DEV(cmd);
+ se_subsystem_dev_t *su_dev = SU_DEV(se_dev);
+ t10_pr_registration_t *pr_reg;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u32 add_len = 0, off = 8;
+
+ 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(&T10_RES(su_dev)->registration_lock);
+ list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list,
+ pr_reg_list) {
+ /*
+ * Check for overflow of 8byte PRI READ_KEYS payload and
+ * next reservation key list descriptor.
+ */
+ if ((add_len + 8) > (cmd->data_length - 8))
+ break;
+
+ 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);
+
+ add_len += 8;
+ }
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+
+ 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);
}

+/*
+ * PERSISTENT_RESERVE_IN Service Action READ_RESERVATION
+ *
+ * See spc4r17 section 5.7.6.3 and section 6.13.3.2 Table 161 and 162
+ */
static int core_scsi3_pri_read_reservation (se_cmd_t *cmd)
{
+ se_device_t *se_dev = SE_DEV(cmd);
+ se_subsystem_dev_t *su_dev = SU_DEV(se_dev);
+ t10_pr_registration_t *pr_reg;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u32 add_len = 16; /* Hardcoded to 16 when a reservation is held. */
+
+ 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(&se_dev->dev_reservation_lock);
+ if ((pr_reg = se_dev->dev_pr_res_holder)) {
+ /*
+ * Set the hardcoded 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);
+ /*
+ * Set the Reservation key
+ */
+ buf[8] = ((pr_reg->pr_res_key >> 56) & 0xff);
+ buf[9] = ((pr_reg->pr_res_key >> 48) & 0xff);
+ buf[10] = ((pr_reg->pr_res_key >> 40) & 0xff);
+ buf[11] = ((pr_reg->pr_res_key >> 32) & 0xff);
+ buf[12] = ((pr_reg->pr_res_key >> 24) & 0xff);
+ buf[13] = ((pr_reg->pr_res_key >> 16) & 0xff);
+ buf[14] = ((pr_reg->pr_res_key >> 8) & 0xff);
+ buf[15] = (pr_reg->pr_res_key & 0xff);
+ /*
+ * Set the SCOPE and TYPE
+ */
+ buf[21] = ((pr_reg->pr_res_type << 8) & 0xff) |
+ (pr_reg->pr_res_scope & 0xff);
+ }
+ spin_unlock(&se_dev->dev_reservation_lock);
+
return(0);
}

@@ -339,14 +804,16 @@ static int core_scsi3_emulate_pr_in (se_cmd_t *cmd, unsigned char *cdb)
return(core_scsi3_pri_read_keys(cmd));
case PRI_READ_RESERVATION:
return(core_scsi3_pri_read_reservation(cmd));
+#if 0
case PRI_REPORT_CAPABILITIES:
return(core_scsi3_pri_report_capabilities(cmd));
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);
- return(-1);
+ return(PYX_TRANSPORT_INVALID_CDB_FIELD);
}

}
diff --git a/drivers/lio-core/target_core_pr.h b/drivers/lio-core/target_core_pr.h
index d32bbdd..3a3d646 100644
--- a/drivers/lio-core/target_core_pr.h
+++ b/drivers/lio-core/target_core_pr.h
@@ -20,6 +20,24 @@
#define PRI_READ_RESERVATION 0x01
#define PRI_REPORT_CAPABILITIES 0x02
#define PRI_READ_FULL_STATUS 0x03
+/*
+ * PERSISTENT_RESERVE_ SCOPE field
+ *
+ * spc4r17 section 6.13.3.3 Table 163
+ */
+#define PR_SCOPE_LU_SCOPE 0x00
+/*
+ * PERSISTENT_RESERVE_* TYPE field
+ *
+ * spc4r17 section 6.13.3.4 Table 164
+ */
+#define PR_TYPE_WRITE_EXCLUSIVE 0x01
+#define PR_TYPE_EXCLUSIVE_ACCESS 0x03
+#define PR_TYPE_WRITE_EXCLUSIVE_REGONLY 0x05
+#define PR_TYPE_EXCLUSIVE_ACCESS_REGONLY 0x06
+#define PR_TYPE_WRITE_EXCLUSIVE_ALLREG 0x07
+#define PR_TYPE_EXCLUSIVE_ACCESS_ALLREG 0x08

+extern void core_scsi3_free_all_registrations (struct se_device_s *);
extern int core_scsi3_emulate_pr (struct se_cmd_s *);
extern int core_setup_reservations (struct se_device_s *);
--
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/