Blob Blame History Raw
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,