diff mbox series

[v3,04/19] scsi: Add support for block PR read keys/reservation

Message ID 20221026231945.6609-5-michael.christie@oracle.com (mailing list archive)
State Not Applicable, archived
Delegated to: Mike Snitzer
Headers show
Series Use block pr_ops in LIO | expand

Commit Message

Mike Christie Oct. 26, 2022, 11:19 p.m. UTC
This adds support in sd.c for the block PR read keys and read reservation
callouts.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/sd.c            | 104 +++++++++++++++++++++++++++++++++++
 include/scsi/scsi_block_pr.h |  20 +++++++
 include/scsi/scsi_proto.h    |   5 ++
 3 files changed, 129 insertions(+)

Comments

kernel test robot Oct. 27, 2022, 6:08 a.m. UTC | #1
Hi Mike,

I love your patch! Perhaps something to improve:

[auto build test WARNING on mkp-scsi/for-next]
[also build test WARNING on jejb-scsi/for-next device-mapper-dm/for-next linus/master v6.1-rc2 next-20221026]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Mike-Christie/Use-block-pr_ops-in-LIO/20221027-072653
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next
patch link:    https://lore.kernel.org/r/20221026231945.6609-5-michael.christie%40oracle.com
patch subject: [PATCH v3 04/19] scsi: Add support for block PR read keys/reservation
config: m68k-allyesconfig
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/f8aa9652526890d87007c8a643bd69ac723c053b
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Mike-Christie/Use-block-pr_ops-in-LIO/20221027-072653
        git checkout f8aa9652526890d87007c8a643bd69ac723c053b
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/scsi/sd.c: In function 'sd_pr_in_command':
   drivers/scsi/sd.c:1692:29: error: array type has incomplete element type 'struct scsi_failure'
    1692 |         struct scsi_failure failures[] = {
         |                             ^~~~~~~~
   drivers/scsi/sd.c:1695:32: error: 'SCMD_FAILURE_ASC_ANY' undeclared (first use in this function)
    1695 |                         .asc = SCMD_FAILURE_ASC_ANY,
         |                                ^~~~~~~~~~~~~~~~~~~~
   drivers/scsi/sd.c:1695:32: note: each undeclared identifier is reported only once for each function it appears in
   drivers/scsi/sd.c:1696:33: error: 'SCMD_FAILURE_ASCQ_ANY' undeclared (first use in this function)
    1696 |                         .ascq = SCMD_FAILURE_ASCQ_ANY,
         |                                 ^~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/sd.c:1706:18: error: implicit declaration of function 'scsi_exec_req'; did you mean 'scsi_execute_req'? [-Werror=implicit-function-declaration]
    1706 |         result = scsi_exec_req(((struct scsi_exec_args) {
         |                  ^~~~~~~~~~~~~
         |                  scsi_execute_req
   drivers/scsi/sd.c:1707:42: error: 'struct scsi_exec_args' has no member named 'sdev'
    1707 |                                         .sdev = sdev,
         |                                          ^~~~
>> drivers/scsi/sd.c:1707:49: warning: excess elements in struct initializer
    1707 |                                         .sdev = sdev,
         |                                                 ^~~~
   drivers/scsi/sd.c:1707:49: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1708:42: error: 'struct scsi_exec_args' has no member named 'cmd'
    1708 |                                         .cmd = cmd,
         |                                          ^~~
   drivers/scsi/sd.c:1708:48: warning: excess elements in struct initializer
    1708 |                                         .cmd = cmd,
         |                                                ^~~
   drivers/scsi/sd.c:1708:48: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1709:42: error: 'struct scsi_exec_args' has no member named 'data_dir'
    1709 |                                         .data_dir = DMA_FROM_DEVICE,
         |                                          ^~~~~~~~
   drivers/scsi/sd.c:1709:53: warning: excess elements in struct initializer
    1709 |                                         .data_dir = DMA_FROM_DEVICE,
         |                                                     ^~~~~~~~~~~~~~~
   drivers/scsi/sd.c:1709:53: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1710:42: error: 'struct scsi_exec_args' has no member named 'buf'
    1710 |                                         .buf = data,
         |                                          ^~~
   drivers/scsi/sd.c:1710:48: warning: excess elements in struct initializer
    1710 |                                         .buf = data,
         |                                                ^~~~
   drivers/scsi/sd.c:1710:48: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1711:42: error: 'struct scsi_exec_args' has no member named 'buf_len'
    1711 |                                         .buf_len = data_len,
         |                                          ^~~~~~~
   drivers/scsi/sd.c:1711:52: warning: excess elements in struct initializer
    1711 |                                         .buf_len = data_len,
         |                                                    ^~~~~~~~
   drivers/scsi/sd.c:1711:52: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1712:42: error: 'struct scsi_exec_args' has no member named 'sshdr'
    1712 |                                         .sshdr = &sshdr,
         |                                          ^~~~~
   drivers/scsi/sd.c:1712:50: warning: excess elements in struct initializer
    1712 |                                         .sshdr = &sshdr,
         |                                                  ^
   drivers/scsi/sd.c:1712:50: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1713:42: error: 'struct scsi_exec_args' has no member named 'timeout'
    1713 |                                         .timeout = SD_TIMEOUT,
         |                                          ^~~~~~~
   In file included from drivers/scsi/sd.c:72:
>> drivers/scsi/sd.h:15:33: warning: excess elements in struct initializer
      15 | #define SD_TIMEOUT              (30 * HZ)
         |                                 ^
   drivers/scsi/sd.c:1713:52: note: in expansion of macro 'SD_TIMEOUT'
    1713 |                                         .timeout = SD_TIMEOUT,
         |                                                    ^~~~~~~~~~
   drivers/scsi/sd.h:15:33: note: (near initialization for '(anonymous)')
      15 | #define SD_TIMEOUT              (30 * HZ)
         |                                 ^
   drivers/scsi/sd.c:1713:52: note: in expansion of macro 'SD_TIMEOUT'
    1713 |                                         .timeout = SD_TIMEOUT,
         |                                                    ^~~~~~~~~~
   drivers/scsi/sd.c:1714:42: error: 'struct scsi_exec_args' has no member named 'retries'
    1714 |                                         .retries = sdkp->max_retries,
         |                                          ^~~~~~~
   drivers/scsi/sd.c:1714:52: warning: excess elements in struct initializer
    1714 |                                         .retries = sdkp->max_retries,
         |                                                    ^~~~
   drivers/scsi/sd.c:1714:52: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1715:42: error: 'struct scsi_exec_args' has no member named 'failures'
    1715 |                                         .failures = failures }));
         |                                          ^~~~~~~~
   drivers/scsi/sd.c:1715:53: warning: excess elements in struct initializer
    1715 |                                         .failures = failures }));
         |                                                     ^~~~~~~~
   drivers/scsi/sd.c:1715:53: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1706:57: error: invalid use of undefined type 'struct scsi_exec_args'
    1706 |         result = scsi_exec_req(((struct scsi_exec_args) {
         |                                                         ^
   drivers/scsi/sd.c:1692:29: warning: unused variable 'failures' [-Wunused-variable]
    1692 |         struct scsi_failure failures[] = {
         |                             ^~~~~~~~
   cc1: some warnings being treated as errors


vim +1707 drivers/scsi/sd.c

  1684	
  1685	static int sd_pr_in_command(struct block_device *bdev, u8 sa,
  1686				    unsigned char *data, int data_len)
  1687	{
  1688		struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
  1689		struct scsi_device *sdev = sdkp->device;
  1690		struct scsi_sense_hdr sshdr;
  1691		u8 cmd[10] = { PERSISTENT_RESERVE_IN, sa };
  1692		struct scsi_failure failures[] = {
  1693			{
  1694				.sense = UNIT_ATTENTION,
  1695				.asc = SCMD_FAILURE_ASC_ANY,
  1696				.ascq = SCMD_FAILURE_ASCQ_ANY,
  1697				.allowed = 5,
  1698				.result = SAM_STAT_CHECK_CONDITION,
  1699			},
  1700			{},
  1701		};
  1702		int result;
  1703	
  1704		put_unaligned_be16(data_len, &cmd[7]);
  1705	
  1706		result = scsi_exec_req(((struct scsi_exec_args) {
> 1707						.sdev = sdev,
  1708						.cmd = cmd,
  1709						.data_dir = DMA_FROM_DEVICE,
  1710						.buf = data,
  1711						.buf_len = data_len,
  1712						.sshdr = &sshdr,
  1713						.timeout = SD_TIMEOUT,
  1714						.retries = sdkp->max_retries,
  1715						.failures = failures }));
  1716		if (scsi_status_is_check_condition(result) &&
  1717		    scsi_sense_valid(&sshdr)) {
  1718			sdev_printk(KERN_INFO, sdev, "PR command failed: %d\n", result);
  1719			scsi_print_sense_hdr(sdev, NULL, &sshdr);
  1720		}
  1721	
  1722		return result;
  1723	}
  1724
kernel test robot Oct. 27, 2022, 7:59 a.m. UTC | #2
Hi Mike,

I love your patch! Perhaps something to improve:

[auto build test WARNING on mkp-scsi/for-next]
[also build test WARNING on jejb-scsi/for-next device-mapper-dm/for-next linus/master v6.1-rc2 next-20221026]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Mike-Christie/Use-block-pr_ops-in-LIO/20221027-072653
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next
patch link:    https://lore.kernel.org/r/20221026231945.6609-5-michael.christie%40oracle.com
patch subject: [PATCH v3 04/19] scsi: Add support for block PR read keys/reservation
config: x86_64-allyesconfig
compiler: gcc-11 (Debian 11.3.0-8) 11.3.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/f8aa9652526890d87007c8a643bd69ac723c053b
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Mike-Christie/Use-block-pr_ops-in-LIO/20221027-072653
        git checkout f8aa9652526890d87007c8a643bd69ac723c053b
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/scsi/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/scsi/sd.c: In function 'sd_pr_in_command':
   drivers/scsi/sd.c:1692:29: error: array type has incomplete element type 'struct scsi_failure'
    1692 |         struct scsi_failure failures[] = {
         |                             ^~~~~~~~
   drivers/scsi/sd.c:1695:32: error: 'SCMD_FAILURE_ASC_ANY' undeclared (first use in this function)
    1695 |                         .asc = SCMD_FAILURE_ASC_ANY,
         |                                ^~~~~~~~~~~~~~~~~~~~
   drivers/scsi/sd.c:1695:32: note: each undeclared identifier is reported only once for each function it appears in
   drivers/scsi/sd.c:1696:33: error: 'SCMD_FAILURE_ASCQ_ANY' undeclared (first use in this function)
    1696 |                         .ascq = SCMD_FAILURE_ASCQ_ANY,
         |                                 ^~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/sd.c:1706:18: error: implicit declaration of function 'scsi_exec_req'; did you mean 'scsi_execute_req'? [-Werror=implicit-function-declaration]
    1706 |         result = scsi_exec_req(((struct scsi_exec_args) {
         |                  ^~~~~~~~~~~~~
         |                  scsi_execute_req
   drivers/scsi/sd.c:1707:42: error: 'struct scsi_exec_args' has no member named 'sdev'
    1707 |                                         .sdev = sdev,
         |                                          ^~~~
   drivers/scsi/sd.c:1707:49: warning: excess elements in struct initializer
    1707 |                                         .sdev = sdev,
         |                                                 ^~~~
   drivers/scsi/sd.c:1707:49: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1708:42: error: 'struct scsi_exec_args' has no member named 'cmd'
    1708 |                                         .cmd = cmd,
         |                                          ^~~
   drivers/scsi/sd.c:1708:48: warning: excess elements in struct initializer
    1708 |                                         .cmd = cmd,
         |                                                ^~~
   drivers/scsi/sd.c:1708:48: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1709:42: error: 'struct scsi_exec_args' has no member named 'data_dir'
    1709 |                                         .data_dir = DMA_FROM_DEVICE,
         |                                          ^~~~~~~~
   drivers/scsi/sd.c:1709:53: warning: excess elements in struct initializer
    1709 |                                         .data_dir = DMA_FROM_DEVICE,
         |                                                     ^~~~~~~~~~~~~~~
   drivers/scsi/sd.c:1709:53: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1710:42: error: 'struct scsi_exec_args' has no member named 'buf'
    1710 |                                         .buf = data,
         |                                          ^~~
   drivers/scsi/sd.c:1710:48: warning: excess elements in struct initializer
    1710 |                                         .buf = data,
         |                                                ^~~~
   drivers/scsi/sd.c:1710:48: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1711:42: error: 'struct scsi_exec_args' has no member named 'buf_len'
    1711 |                                         .buf_len = data_len,
         |                                          ^~~~~~~
   drivers/scsi/sd.c:1711:52: warning: excess elements in struct initializer
    1711 |                                         .buf_len = data_len,
         |                                                    ^~~~~~~~
   drivers/scsi/sd.c:1711:52: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1712:42: error: 'struct scsi_exec_args' has no member named 'sshdr'
    1712 |                                         .sshdr = &sshdr,
         |                                          ^~~~~
   drivers/scsi/sd.c:1712:50: warning: excess elements in struct initializer
    1712 |                                         .sshdr = &sshdr,
         |                                                  ^
   drivers/scsi/sd.c:1712:50: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1713:42: error: 'struct scsi_exec_args' has no member named 'timeout'
    1713 |                                         .timeout = SD_TIMEOUT,
         |                                          ^~~~~~~
   In file included from drivers/scsi/sd.c:72:
   drivers/scsi/sd.h:15:33: warning: excess elements in struct initializer
      15 | #define SD_TIMEOUT              (30 * HZ)
         |                                 ^
   drivers/scsi/sd.c:1713:52: note: in expansion of macro 'SD_TIMEOUT'
    1713 |                                         .timeout = SD_TIMEOUT,
         |                                                    ^~~~~~~~~~
   drivers/scsi/sd.h:15:33: note: (near initialization for '(anonymous)')
      15 | #define SD_TIMEOUT              (30 * HZ)
         |                                 ^
   drivers/scsi/sd.c:1713:52: note: in expansion of macro 'SD_TIMEOUT'
    1713 |                                         .timeout = SD_TIMEOUT,
         |                                                    ^~~~~~~~~~
   drivers/scsi/sd.c:1714:42: error: 'struct scsi_exec_args' has no member named 'retries'
    1714 |                                         .retries = sdkp->max_retries,
         |                                          ^~~~~~~
   drivers/scsi/sd.c:1714:52: warning: excess elements in struct initializer
    1714 |                                         .retries = sdkp->max_retries,
         |                                                    ^~~~
   drivers/scsi/sd.c:1714:52: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1715:42: error: 'struct scsi_exec_args' has no member named 'failures'
    1715 |                                         .failures = failures }));
         |                                          ^~~~~~~~
   drivers/scsi/sd.c:1715:53: warning: excess elements in struct initializer
    1715 |                                         .failures = failures }));
         |                                                     ^~~~~~~~
   drivers/scsi/sd.c:1715:53: note: (near initialization for '(anonymous)')
   drivers/scsi/sd.c:1706:57: error: invalid use of undefined type 'struct scsi_exec_args'
    1706 |         result = scsi_exec_req(((struct scsi_exec_args) {
         |                                                         ^
>> drivers/scsi/sd.c:1692:29: warning: unused variable 'failures' [-Wunused-variable]
    1692 |         struct scsi_failure failures[] = {
         |                             ^~~~~~~~
   cc1: some warnings being treated as errors


vim +/failures +1692 drivers/scsi/sd.c

  1684	
  1685	static int sd_pr_in_command(struct block_device *bdev, u8 sa,
  1686				    unsigned char *data, int data_len)
  1687	{
  1688		struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
  1689		struct scsi_device *sdev = sdkp->device;
  1690		struct scsi_sense_hdr sshdr;
  1691		u8 cmd[10] = { PERSISTENT_RESERVE_IN, sa };
> 1692		struct scsi_failure failures[] = {
  1693			{
  1694				.sense = UNIT_ATTENTION,
  1695				.asc = SCMD_FAILURE_ASC_ANY,
  1696				.ascq = SCMD_FAILURE_ASCQ_ANY,
  1697				.allowed = 5,
  1698				.result = SAM_STAT_CHECK_CONDITION,
  1699			},
  1700			{},
  1701		};
  1702		int result;
  1703	
  1704		put_unaligned_be16(data_len, &cmd[7]);
  1705	
  1706		result = scsi_exec_req(((struct scsi_exec_args) {
  1707						.sdev = sdev,
  1708						.cmd = cmd,
  1709						.data_dir = DMA_FROM_DEVICE,
  1710						.buf = data,
  1711						.buf_len = data_len,
  1712						.sshdr = &sshdr,
  1713						.timeout = SD_TIMEOUT,
  1714						.retries = sdkp->max_retries,
  1715						.failures = failures }));
  1716		if (scsi_status_is_check_condition(result) &&
  1717		    scsi_sense_valid(&sshdr)) {
  1718			sdev_printk(KERN_INFO, sdev, "PR command failed: %d\n", result);
  1719			scsi_print_sense_hdr(sdev, NULL, &sshdr);
  1720		}
  1721	
  1722		return result;
  1723	}
  1724
Chaitanya Kulkarni Nov. 1, 2022, 5:45 a.m. UTC | #3
> +static inline enum pr_type scsi_pr_type_to_block(enum scsi_pr_type type)
> +{
> +	switch (type) {
> +	case SCSI_PR_WRITE_EXCLUSIVE:
> +		return PR_WRITE_EXCLUSIVE;
> +	case SCSI_PR_EXCLUSIVE_ACCESS:
> +		return PR_EXCLUSIVE_ACCESS;
> +	case SCSI_PR_WRITE_EXCLUSIVE_REG_ONLY:
> +		return PR_WRITE_EXCLUSIVE_REG_ONLY;
> +	case SCSI_PR_EXCLUSIVE_ACCESS_REG_ONLY:
> +		return PR_EXCLUSIVE_ACCESS_REG_ONLY;
> +	case SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS:
> +		return PR_WRITE_EXCLUSIVE_ALL_REGS;
> +	case SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS:
> +		return PR_EXCLUSIVE_ACCESS_ALL_REGS;
> +	default:
> +		return 0;
> +	}
> +}
> +

same here as previous comment, unless there is strong reason not to do
that ...

-ck

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel
Bart Van Assche Nov. 2, 2022, 10:54 p.m. UTC | #4
On 10/26/22 16:19, Mike Christie wrote:
> +static inline enum pr_type scsi_pr_type_to_block(enum scsi_pr_type type)
> +{
> +	switch (type) {
> +	case SCSI_PR_WRITE_EXCLUSIVE:
> +		return PR_WRITE_EXCLUSIVE;
> +	case SCSI_PR_EXCLUSIVE_ACCESS:
> +		return PR_EXCLUSIVE_ACCESS;
> +	case SCSI_PR_WRITE_EXCLUSIVE_REG_ONLY:
> +		return PR_WRITE_EXCLUSIVE_REG_ONLY;
> +	case SCSI_PR_EXCLUSIVE_ACCESS_REG_ONLY:
> +		return PR_EXCLUSIVE_ACCESS_REG_ONLY;
> +	case SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS:
> +		return PR_WRITE_EXCLUSIVE_ALL_REGS;
> +	case SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS:
> +		return PR_EXCLUSIVE_ACCESS_ALL_REGS;
> +	default:
> +		return 0;
> +	}
> +}

Also for this function, how about moving the "return 0" statement out of 
the switch statement?

Thanks,

Bart.

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel
diff mbox series

Patch

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index ad9374b07585..86b602399000 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1695,6 +1695,108 @@  static int sd_get_unique_id(struct gendisk *disk, u8 id[16],
 	return ret;
 }
 
+static int sd_pr_in_command(struct block_device *bdev, u8 sa,
+			    unsigned char *data, int data_len)
+{
+	struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
+	struct scsi_device *sdev = sdkp->device;
+	struct scsi_sense_hdr sshdr;
+	u8 cmd[10] = { PERSISTENT_RESERVE_IN, sa };
+	struct scsi_failure failures[] = {
+		{
+			.sense = UNIT_ATTENTION,
+			.asc = SCMD_FAILURE_ASC_ANY,
+			.ascq = SCMD_FAILURE_ASCQ_ANY,
+			.allowed = 5,
+			.result = SAM_STAT_CHECK_CONDITION,
+		},
+		{},
+	};
+	int result;
+
+	put_unaligned_be16(data_len, &cmd[7]);
+
+	result = scsi_exec_req(((struct scsi_exec_args) {
+					.sdev = sdev,
+					.cmd = cmd,
+					.data_dir = DMA_FROM_DEVICE,
+					.buf = data,
+					.buf_len = data_len,
+					.sshdr = &sshdr,
+					.timeout = SD_TIMEOUT,
+					.retries = sdkp->max_retries,
+					.failures = failures }));
+	if (scsi_status_is_check_condition(result) &&
+	    scsi_sense_valid(&sshdr)) {
+		sdev_printk(KERN_INFO, sdev, "PR command failed: %d\n", result);
+		scsi_print_sense_hdr(sdev, NULL, &sshdr);
+	}
+
+	return result;
+}
+
+static int sd_pr_read_keys(struct block_device *bdev, struct pr_keys *keys_info,
+			   u32 keys_len)
+{
+	int result, i, data_offset, num_copy_keys;
+	int data_len = keys_len + 8;
+	u8 *data;
+
+	data = kzalloc(data_len, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	result = sd_pr_in_command(bdev, READ_KEYS, data, data_len);
+	if (result)
+		goto free_data;
+
+	keys_info->generation = get_unaligned_be32(&data[0]);
+	keys_info->num_keys = get_unaligned_be32(&data[4]) / 8;
+
+	data_offset = 8;
+	num_copy_keys = min(keys_len / 8, keys_info->num_keys);
+
+	for (i = 0; i < num_copy_keys; i++) {
+		keys_info->keys[i] = get_unaligned_be64(&data[data_offset]);
+		data_offset += 8;
+	}
+
+free_data:
+	kfree(data);
+	return result;
+}
+
+static int sd_pr_read_reservation(struct block_device *bdev,
+				  struct pr_held_reservation *rsv)
+{
+	struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
+	struct scsi_device *sdev = sdkp->device;
+	u8 data[24] = { 0, };
+	int result, len;
+
+	result = sd_pr_in_command(bdev, READ_RESERVATION, data, sizeof(data));
+	if (result)
+		return result;
+
+	memset(rsv, 0, sizeof(*rsv));
+	len = get_unaligned_be32(&data[4]);
+	if (!len)
+		return result;
+
+	/* Make sure we have at least the key and type */
+	if (len < 14) {
+		sdev_printk(KERN_INFO, sdev,
+			    "READ RESERVATION failed due to short return buffer of %d bytes\n",
+			    len);
+		return -EINVAL;
+	}
+
+	rsv->generation = get_unaligned_be32(&data[0]);
+	rsv->key = get_unaligned_be64(&data[8]);
+	rsv->type = scsi_pr_type_to_block(data[21] & 0x0f);
+	return 0;
+}
+
 static int sd_pr_out_command(struct block_device *bdev, u8 sa,
 		u64 key, u64 sa_key, enum scsi_pr_type type, u8 flags)
 {
@@ -1787,6 +1889,8 @@  static const struct pr_ops sd_pr_ops = {
 	.pr_release	= sd_pr_release,
 	.pr_preempt	= sd_pr_preempt,
 	.pr_clear	= sd_pr_clear,
+	.pr_read_keys	= sd_pr_read_keys,
+	.pr_read_reservation = sd_pr_read_reservation,
 };
 
 static void scsi_disk_free_disk(struct gendisk *disk)
diff --git a/include/scsi/scsi_block_pr.h b/include/scsi/scsi_block_pr.h
index 6e99f844330d..137bf2247273 100644
--- a/include/scsi/scsi_block_pr.h
+++ b/include/scsi/scsi_block_pr.h
@@ -33,4 +33,24 @@  static inline enum scsi_pr_type block_pr_type_to_scsi(enum pr_type type)
 	}
 };
 
+static inline enum pr_type scsi_pr_type_to_block(enum scsi_pr_type type)
+{
+	switch (type) {
+	case SCSI_PR_WRITE_EXCLUSIVE:
+		return PR_WRITE_EXCLUSIVE;
+	case SCSI_PR_EXCLUSIVE_ACCESS:
+		return PR_EXCLUSIVE_ACCESS;
+	case SCSI_PR_WRITE_EXCLUSIVE_REG_ONLY:
+		return PR_WRITE_EXCLUSIVE_REG_ONLY;
+	case SCSI_PR_EXCLUSIVE_ACCESS_REG_ONLY:
+		return PR_EXCLUSIVE_ACCESS_REG_ONLY;
+	case SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS:
+		return PR_WRITE_EXCLUSIVE_ALL_REGS;
+	case SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS:
+		return PR_EXCLUSIVE_ACCESS_ALL_REGS;
+	default:
+		return 0;
+	}
+}
+
 #endif
diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h
index c03e35fc382c..0fd6e295375a 100644
--- a/include/scsi/scsi_proto.h
+++ b/include/scsi/scsi_proto.h
@@ -151,6 +151,11 @@ 
 #define ZO_FINISH_ZONE	      0x02
 #define ZO_OPEN_ZONE	      0x03
 #define ZO_RESET_WRITE_POINTER 0x04
+/* values for PR in service action */
+#define READ_KEYS             0x00
+#define READ_RESERVATION      0x01
+#define REPORT_CAPABILITES    0x02
+#define READ_FULL_STATUS      0x03
 /* values for variable length command */
 #define XDREAD_32	      0x03
 #define XDWRITE_32	      0x04