From 36d266e237b1ec4e992b175d5aee9780e03a5d4d Mon Sep 17 00:00:00 2001
From: David Disseldorp <ddiss@suse.de>
Date: Wed, 26 Aug 2015 22:27:27 +0200
Subject: [PATCH] target/rbd: add pr_read_reservation support
Patch-mainline: Not yet, SES2 clustered LIO/RBD
References: fate#318836
Add a tcm_rbd_pr_ops handler for PR READ RESERVATION requests.
Signed-off-by: David Disseldorp <ddiss@suse.de>
---
drivers/target/target_core_rbd.c | 77 +++++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
--- a/drivers/target/target_core_rbd.c
+++ b/drivers/target/target_core_rbd.c
@@ -46,6 +46,7 @@
#include <target/target_core_backend.h>
#include <target/target_core_fabric.h>
+#include "target_core_pr.h"
#include "target_core_rbd.h"
static inline struct tcm_rbd_dev *TCM_RBD_DEV(struct se_device *dev)
@@ -1541,6 +1542,81 @@ tcm_rbd_execute_pr_read_keys(struct se_c
return TCM_NO_SENSE;
}
+static sense_reason_t
+tcm_rbd_execute_pr_read_reservation(struct se_cmd *cmd, unsigned char *buf,
+ u32 buf_len)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct tcm_rbd_dev *tcm_rbd_dev = TCM_RBD_DEV(dev);
+ struct tcm_rbd_pr_info *pr_info = NULL;
+ u64 pr_res_key;
+ u32 add_len = 16; /* Hardcoded to 16 when a reservation is held. */
+ int rc;
+
+ BUG_ON(buf_len < 8);
+
+ dout("getting pr_info for buf: %p, %u\n", buf, buf_len);
+
+ rc = tcm_rbd_pr_info_get(tcm_rbd_dev, &pr_info, NULL, NULL);
+ if (rc == -ENODATA) {
+ dout("PR info not present for read, mocking empty\n");
+ rc = tcm_rbd_pr_info_mock_empty(tcm_rbd_dev, &pr_info);
+ }
+ if (rc < 0)
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ buf[0] = ((pr_info->gen >> 24) & 0xff);
+ buf[1] = ((pr_info->gen >> 16) & 0xff);
+ buf[2] = ((pr_info->gen >> 8) & 0xff);
+ buf[3] = (pr_info->gen & 0xff);
+
+ if (pr_info->rsv) {
+ buf[4] = ((add_len >> 24) & 0xff);
+ buf[5] = ((add_len >> 16) & 0xff);
+ buf[6] = ((add_len >> 8) & 0xff);
+ buf[7] = (add_len & 0xff);
+
+ if (buf_len < 22)
+ goto out;
+
+ if ((pr_info->rsv->type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_info->rsv->type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+ /*
+ * a) For a persistent reservation of the type Write
+ * Exclusive - All Registrants or Exclusive Access -
+ * All Registrants, the reservation key shall be set
+ * to zero; or
+ */
+ pr_res_key = 0;
+ } else {
+ /*
+ * b) For all other persistent reservation types, the
+ * reservation key shall be set to the registered
+ * reservation key for the I_T nexus that holds the
+ * persistent reservation.
+ */
+ pr_res_key = pr_info->rsv->key;
+ }
+
+ buf[8] = ((pr_res_key >> 56) & 0xff);
+ buf[9] = ((pr_res_key >> 48) & 0xff);
+ buf[10] = ((pr_res_key >> 40) & 0xff);
+ buf[11] = ((pr_res_key >> 32) & 0xff);
+ buf[12] = ((pr_res_key >> 24) & 0xff);
+ buf[13] = ((pr_res_key >> 16) & 0xff);
+ buf[14] = ((pr_res_key >> 8) & 0xff);
+ buf[15] = (pr_res_key & 0xff);
+ /*
+ * Set the SCOPE and TYPE
+ */
+ buf[21] = (PR_SCOPE_LU_SCOPE & 0xf0) |
+ (pr_info->rsv->type & 0x0f);
+ }
+
+out:
+ return TCM_NO_SENSE;
+}
+
/* handle PR registration for a currently unregistered I_T nexus */
static sense_reason_t
tcm_rbd_execute_pr_register_new(struct tcm_rbd_pr_info *pr_info, u64 old_key,
@@ -1987,6 +2063,7 @@ err_info_free:
static struct target_pr_ops tcm_rbd_pr_ops = {
.pr_read_keys = tcm_rbd_execute_pr_read_keys,
+ .pr_read_reservation = tcm_rbd_execute_pr_read_reservation,
.pr_register = tcm_rbd_execute_pr_register,
.pr_reserve = tcm_rbd_execute_pr_reserve,