[PATCH 14/24] scsi-multipath: add PR support

John Garry john.g.garry at oracle.com
Wed Feb 25 07:36:17 PST 2026


Add path_pr_ops structure with callbacks.

Since PR ops are related to mpath_disk, add new structure type
scsi_mpath_pr_ops, which allows PR ops be executed for a scsi_device.

Since PR are related to mpath_disk, provide scsi_driver member to allow
scsi_disk driver set it PR ops calllback.

Signed-off-by: John Garry <john.g.garry at oracle.com>
---
 drivers/scsi/scsi_multipath.c | 110 ++++++++++++++++++++++++++++++++++
 include/scsi/scsi_driver.h    |   1 +
 include/scsi/scsi_multipath.h |  17 ++++++
 3 files changed, 128 insertions(+)

diff --git a/drivers/scsi/scsi_multipath.c b/drivers/scsi/scsi_multipath.c
index 73afcbaf2d7de..1489c7e979167 100644
--- a/drivers/scsi/scsi_multipath.c
+++ b/drivers/scsi/scsi_multipath.c
@@ -381,6 +381,115 @@ static bool scsi_mpath_available_path(struct mpath_device *mpath_device, bool *a
 	return scsi_device_online(sdev);
 }
 
+static int scsi_mpath_pr_register(struct mpath_device *mpath_device,
+			u64 old_key, u64 new_key, u32 flags)
+{
+	struct scsi_mpath_device *scsi_mpath_dev =
+				to_scsi_mpath_device(mpath_device);
+	struct scsi_device *sdev = scsi_mpath_dev->sdev;
+	struct scsi_driver *drv = to_scsi_driver(sdev->sdev_gendev.driver);
+
+	if (!drv->mpath_pr_ops)
+		return -EOPNOTSUPP;
+
+	return drv->mpath_pr_ops->pr_register(sdev, old_key, new_key, flags);
+}
+
+static int scsi_mpath_pr_reserve(struct mpath_device *mpath_device, u64 key,
+			enum pr_type type, u32 flags)
+{
+	struct scsi_mpath_device *scsi_mpath_dev =
+				to_scsi_mpath_device(mpath_device);
+	struct scsi_device *sdev = scsi_mpath_dev->sdev;
+	struct scsi_driver *drv = to_scsi_driver(sdev->sdev_gendev.driver);
+
+	if (!drv->mpath_pr_ops)
+		return -EOPNOTSUPP;
+
+	return drv->mpath_pr_ops->pr_reserve(sdev, key, type, flags);
+}
+
+static int scsi_mpath_pr_release(struct mpath_device *mpath_device, u64 key,
+			enum pr_type type)
+{
+	struct scsi_mpath_device *scsi_mpath_dev =
+				to_scsi_mpath_device(mpath_device);
+	struct scsi_device *sdev = scsi_mpath_dev->sdev;
+	struct scsi_driver *drv = to_scsi_driver(sdev->sdev_gendev.driver);
+
+	if (!drv->mpath_pr_ops)
+		return -EOPNOTSUPP;
+
+	return drv->mpath_pr_ops->pr_release(sdev, key, type);
+}
+
+static int scsi_mpath_pr_preempt(struct mpath_device *mpath_device,
+			u64 old_key, u64 new_key, enum pr_type type,
+			bool abort)
+{
+	struct scsi_mpath_device *scsi_mpath_dev =
+				to_scsi_mpath_device(mpath_device);
+	struct scsi_device *sdev = scsi_mpath_dev->sdev;
+	struct scsi_driver *drv = to_scsi_driver(sdev->sdev_gendev.driver);
+
+	if (!drv->mpath_pr_ops)
+		return -EOPNOTSUPP;
+
+	return drv->mpath_pr_ops->pr_preempt(sdev, old_key, new_key,
+			type, abort);
+}
+
+static int scsi_mpath_pr_clear(struct mpath_device *mpath_device, u64 key)
+{
+	struct scsi_mpath_device *scsi_mpath_dev =
+				to_scsi_mpath_device(mpath_device);
+	struct scsi_device *sdev = scsi_mpath_dev->sdev;
+	struct scsi_driver *drv = to_scsi_driver(sdev->sdev_gendev.driver);
+
+	if (!drv->mpath_pr_ops)
+		return -EOPNOTSUPP;
+
+	return drv->mpath_pr_ops->pr_clear(sdev, key);
+}
+
+static int scsi_mpath_pr_read_keys(struct mpath_device *mpath_device,
+				struct pr_keys *keys_info)
+{
+	struct scsi_mpath_device *scsi_mpath_dev =
+				to_scsi_mpath_device(mpath_device);
+	struct scsi_device *sdev = scsi_mpath_dev->sdev;
+	struct scsi_driver *drv = to_scsi_driver(sdev->sdev_gendev.driver);
+
+	if (!drv->mpath_pr_ops)
+		return -EOPNOTSUPP;
+
+	return drv->mpath_pr_ops->pr_read_keys(sdev, keys_info);
+}
+
+static int scsi_mpath_pr_read_reservation(struct mpath_device *mpath_device,
+				  struct pr_held_reservation *rsv)
+{
+	struct scsi_mpath_device *scsi_mpath_dev =
+				to_scsi_mpath_device(mpath_device);
+	struct scsi_device *sdev = scsi_mpath_dev->sdev;
+	struct scsi_driver *drv = to_scsi_driver(sdev->sdev_gendev.driver);
+
+	if (!drv->mpath_pr_ops)
+		return -EOPNOTSUPP;
+
+	return drv->mpath_pr_ops->pr_read_reservation(sdev, rsv);
+}
+
+static const struct mpath_pr_ops scsi_mpath_pr_ops = {
+	.pr_register	= scsi_mpath_pr_register,
+	.pr_reserve	= scsi_mpath_pr_reserve,
+	.pr_release	= scsi_mpath_pr_release,
+	.pr_preempt	= scsi_mpath_pr_preempt,
+	.pr_clear	= scsi_mpath_pr_clear,
+	.pr_read_keys	= scsi_mpath_pr_read_keys,
+	.pr_read_reservation = scsi_mpath_pr_read_reservation,
+};
+
 struct mpath_head_template smpdt_pr = {
 	.is_disabled = scsi_mpath_is_disabled,
 	.is_optimized = scsi_mpath_is_optimized,
@@ -389,6 +498,7 @@ struct mpath_head_template smpdt_pr = {
 	.available_path = scsi_mpath_available_path,
 	.get_iopolicy = scsi_mpath_get_iopolicy,
 	.clone_bio = scsi_mpath_clone_bio,
+	.pr_ops = &scsi_mpath_pr_ops,
 	.device_groups = mpath_device_groups,
 };
 
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index 799071b8bdee2..2aaa5d270d818 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -25,6 +25,7 @@ struct scsi_driver {
 	int (*mpath_ioctl)(struct scsi_device *sdev, blk_mode_t mode,
 					unsigned int cmd, unsigned long arg);
 	struct mpath_disk *(*to_mpath_disk)(struct request *);
+	const struct scsi_mpath_pr_ops *mpath_pr_ops;
 	#endif
 };
 #define to_scsi_driver(drv) \
diff --git a/include/scsi/scsi_multipath.h b/include/scsi/scsi_multipath.h
index 6cb3107260952..cb63c6536b854 100644
--- a/include/scsi/scsi_multipath.h
+++ b/include/scsi/scsi_multipath.h
@@ -40,6 +40,23 @@ struct scsi_mpath_device {
 
 	char			device_id_str[SCSI_MPATH_DEVICE_ID_LEN];
 };
+
+struct scsi_mpath_pr_ops {
+	int (*pr_register)(struct scsi_device *, u64 old_key,
+			u64 new_key, u32 flags);
+	int (*pr_reserve)(struct scsi_device *e, u64 key,
+			enum pr_type type, u32 flags);
+	int (*pr_release)(struct scsi_device *, u64 key,
+			enum pr_type type);
+	int (*pr_preempt)(struct scsi_device *, u64 old_key,
+			u64 new_key, enum pr_type type, bool abort);
+	int (*pr_clear)(struct scsi_device *, u64 key);
+	int (*pr_read_keys)(struct scsi_device *,
+			struct pr_keys *keys_info);
+	int (*pr_read_reservation)(struct scsi_device *,
+			struct pr_held_reservation *rsv);
+};
+
 #define to_scsi_mpath_device(d) \
 	container_of(d, struct scsi_mpath_device, mpath_device)
 
-- 
2.43.5




More information about the Linux-nvme mailing list