All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/7] SED OPAL Library
@ 2016-11-16 23:17 ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, sagi

Changes from V0->V1:
1) Split the Nvme patche into two different patches (SEC_OPS and unlock)
2) Created work queues to send commands to the controllers:
  2a) Allows us to use correct blk API (blk_execute_rq_nowait)
  2b) Commands are no longer being sent in an IRQ but in the system_wq
3) Clean up left-over crud in nvme: pci.c and core.c
4) Implement fixes suggested by Jonathan Derrick
5) Actually allow a user to enable the Global Locking Range


This Patch series implements a large portion of the Opal protocol for
self encrypting devices. The driver has the capability of storing a
locking range's password, either directly in the driver, or in the
Kernel's key managment. The password can then be replayed during a
resume from previous suspend-to-RAM.

The driver also supports logic to bring the device out of a factory
default-inactive state into a functional Opal state.

The following logic is supported in order to bring the tper into a
working state:

1) Taking Ownership of the drive (Setting the Admin CPIN).
2) Activating the Locking SP (In Single User Mode or Normal Mode).
3) Setting up Locking Ranges (Single User or Normal Mode).
4) Adding users to Locking Ranges (Normal Mode Only).
5) Locking or Unlocking Locking Rangs (Single User Mode or Normal Mode).
6) Reverting the TPer (Restore to factory default).
7) Setting LR/User passwords (Single User Mode or Normal Mode).
8) Eabling/disabling Shadow MBR.
9) Enabling Users in the LockingSP (Normal Mode Only).
10) Saving Password for resume from suspend.


Each command above is exported through an ioctl in the block layer.

We have userland tooling staged in nvme-cli which can be used for
testing:
https://github.com/linux-nvme/nvme-cli/pull/137

Once we've fixed any nits and issues we will merge the userland tooling
into the master branch of nvme-cli.

I have a series of test scripts I've been using which can be helpful if
people want to test or immediately start using and testing the code:

https://github.com/ScottyBauer/nvme-cli-sed-sh

Scott Bauer (7):
  Include: Add definitions for sed
  lib: Add Sed-opal library
  lib: Add Sed to Kconfig and Makefile
  include: Add sec_ops to block device operations
  nvme: Implement SED Security Operations
  nvme: Implement SED Unlock from suspend
  block: ioctl: Wire up Sed to block ioctls

 block/compat_ioctl.c          |   14 +
 block/ioctl.c                 |  200 ++-
 drivers/nvme/host/core.c      |  118 ++
 drivers/nvme/host/nvme.h      |    4 +-
 drivers/nvme/host/pci.c       |    7 +-
 include/linux/blkdev.h        |    1 +
 include/linux/sed-opal.h      |   58 +
 include/linux/sed.h           |   91 ++
 include/uapi/linux/sed-opal.h |  118 ++
 include/uapi/linux/sed.h      |   55 +
 lib/Kconfig                   |   12 +
 lib/Makefile                  |    7 +
 lib/sed-opal.c                | 3338 +++++++++++++++++++++++++++++++++++++++++
 lib/sed-opal_internal.h       |  587 ++++++++
 lib/sed-opal_key.c            |   46 +
 lib/sed.c                     |  250 +++
 16 files changed, 4903 insertions(+), 3 deletions(-)
 create mode 100644 include/linux/sed-opal.h
 create mode 100644 include/linux/sed.h
 create mode 100644 include/uapi/linux/sed-opal.h
 create mode 100644 include/uapi/linux/sed.h
 create mode 100644 lib/sed-opal.c
 create mode 100644 lib/sed-opal_internal.h
 create mode 100644 lib/sed-opal_key.c
 create mode 100644 lib/sed.c



^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 0/7] SED OPAL Library
@ 2016-11-16 23:17 ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)


Changes from V0->V1:
1) Split the Nvme patche into two different patches (SEC_OPS and unlock)
2) Created work queues to send commands to the controllers:
  2a) Allows us to use correct blk API (blk_execute_rq_nowait)
  2b) Commands are no longer being sent in an IRQ but in the system_wq
3) Clean up left-over crud in nvme: pci.c and core.c
4) Implement fixes suggested by Jonathan Derrick
5) Actually allow a user to enable the Global Locking Range


This Patch series implements a large portion of the Opal protocol for
self encrypting devices. The driver has the capability of storing a
locking range's password, either directly in the driver, or in the
Kernel's key managment. The password can then be replayed during a
resume from previous suspend-to-RAM.

The driver also supports logic to bring the device out of a factory
default-inactive state into a functional Opal state.

The following logic is supported in order to bring the tper into a
working state:

1) Taking Ownership of the drive (Setting the Admin CPIN).
2) Activating the Locking SP (In Single User Mode or Normal Mode).
3) Setting up Locking Ranges (Single User or Normal Mode).
4) Adding users to Locking Ranges (Normal Mode Only).
5) Locking or Unlocking Locking Rangs (Single User Mode or Normal Mode).
6) Reverting the TPer (Restore to factory default).
7) Setting LR/User passwords (Single User Mode or Normal Mode).
8) Eabling/disabling Shadow MBR.
9) Enabling Users in the LockingSP (Normal Mode Only).
10) Saving Password for resume from suspend.


Each command above is exported through an ioctl in the block layer.

We have userland tooling staged in nvme-cli which can be used for
testing:
https://github.com/linux-nvme/nvme-cli/pull/137

Once we've fixed any nits and issues we will merge the userland tooling
into the master branch of nvme-cli.

I have a series of test scripts I've been using which can be helpful if
people want to test or immediately start using and testing the code:

https://github.com/ScottyBauer/nvme-cli-sed-sh

Scott Bauer (7):
  Include: Add definitions for sed
  lib: Add Sed-opal library
  lib: Add Sed to Kconfig and Makefile
  include: Add sec_ops to block device operations
  nvme: Implement SED Security Operations
  nvme: Implement SED Unlock from suspend
  block: ioctl: Wire up Sed to block ioctls

 block/compat_ioctl.c          |   14 +
 block/ioctl.c                 |  200 ++-
 drivers/nvme/host/core.c      |  118 ++
 drivers/nvme/host/nvme.h      |    4 +-
 drivers/nvme/host/pci.c       |    7 +-
 include/linux/blkdev.h        |    1 +
 include/linux/sed-opal.h      |   58 +
 include/linux/sed.h           |   91 ++
 include/uapi/linux/sed-opal.h |  118 ++
 include/uapi/linux/sed.h      |   55 +
 lib/Kconfig                   |   12 +
 lib/Makefile                  |    7 +
 lib/sed-opal.c                | 3338 +++++++++++++++++++++++++++++++++++++++++
 lib/sed-opal_internal.h       |  587 ++++++++
 lib/sed-opal_key.c            |   46 +
 lib/sed.c                     |  250 +++
 16 files changed, 4903 insertions(+), 3 deletions(-)
 create mode 100644 include/linux/sed-opal.h
 create mode 100644 include/linux/sed.h
 create mode 100644 include/uapi/linux/sed-opal.h
 create mode 100644 include/uapi/linux/sed.h
 create mode 100644 lib/sed-opal.c
 create mode 100644 lib/sed-opal_internal.h
 create mode 100644 lib/sed-opal_key.c
 create mode 100644 lib/sed.c

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 1/7] Include: Add definitions for sed
  2016-11-16 23:17 ` Scott Bauer
@ 2016-11-16 23:17   ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, sagi, Scott Bauer

This patch adds the definitions and structures for the SED
Opal code.

Signed-off-by: Scott Bauer <scott.bauer@intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli@intel.com>
---
 include/linux/sed-opal.h      |  58 +++++++++++++++++++++
 include/linux/sed.h           |  91 ++++++++++++++++++++++++++++++++
 include/uapi/linux/sed-opal.h | 118 ++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/sed.h      |  55 ++++++++++++++++++++
 4 files changed, 322 insertions(+)
 create mode 100644 include/linux/sed-opal.h
 create mode 100644 include/linux/sed.h
 create mode 100644 include/uapi/linux/sed-opal.h
 create mode 100644 include/uapi/linux/sed.h

diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
new file mode 100644
index 0000000..e0ee21e
--- /dev/null
+++ b/include/linux/sed-opal.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rafael Antognolli <rafael.antognolli@intel.com>
+ *    Scott  Bauer      <scott.bauer@intel.com>
+ */
+
+#ifndef LINUX_OPAL_H
+#define LINUX_OPAL_H
+
+#include <linux/sed.h>
+#include <linux/kernel.h>
+
+enum {
+	TCG_SECP_00 = 0,
+	TCG_SECP_01,
+};
+
+struct opal_suspend_unlk {
+	void *data;
+	const char *name;
+	struct sec_ops ops;
+};
+
+int opal_save(struct block_device *bdev, struct sed_key *key);
+int opal_lock_unlock(struct block_device *bdev, struct sed_key *key);
+int opal_take_ownership(struct block_device *bdev, struct sed_key *key);
+int opal_activate_lsp(struct block_device *bdev, struct sed_key *key);
+int opal_set_new_pw(struct block_device *bdev, struct sed_key *key);
+int opal_activate_user(struct block_device *bdev, struct sed_key *key);
+int opal_reverttper(struct block_device *bdev, struct sed_key *key);
+int opal_setup_locking_range(struct block_device *bdev, struct sed_key *key);
+int opal_add_user_to_lr(struct block_device *bdev, struct sed_key *key);
+int opal_enable_disable_shadow_mbr(struct block_device *bdev, struct sed_key *key);
+int opal_unlock_from_suspend(struct opal_suspend_unlk *data);
+int opal_erase_locking_range(struct block_device *bdev, struct sed_key *key);
+
+#endif /* LINUX_OPAL_H */
diff --git a/include/linux/sed.h b/include/linux/sed.h
new file mode 100644
index 0000000..6c9bae9
--- /dev/null
+++ b/include/linux/sed.h
@@ -0,0 +1,91 @@
+/*
+ * Self-Encrypting Drive interface - sed.h
+ *
+ * Copyright (C) 2016 Intel Corporation <jonathan.derrick@intel.com>
+ *
+ * This code is the generic layer to interface with self-encrypting
+ * drives. Specific command sets should advertise support to sed uapi
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef LINUX_SED_H
+#define LINUX_SED_H
+
+#include <linux/blkdev.h>
+#include <uapi/linux/sed.h>
+
+/*
+ * sec_ops - transport specific Trusted Send/Receive functions
+ * See SPC-4 for specific definitions
+ *
+ * @sec_send: sends the payload to the trusted peripheral
+ *	SPSP: Security Protocol Specific
+ *	SECP: Security Protocol
+ *	buf: Payload
+ *	len: Payload length
+ * @recv: Receives a payload from the trusted peripheral
+ *	SPSP: Security Protocol Specific
+ *	SECP: Security Protocol
+ *	buf: Payload
+ *	len: Payload length
+ */
+
+typedef void (sec_cb)(int error, void *data);
+
+struct sec_ops {
+	int (*send)(void *data, __u16 SPSP, __u8 SECP,
+			void *buffer, size_t len,
+			sec_cb *cb, void *cb_data);
+	int (*recv)(void *data, __u16 SPSP, __u8 SECP,
+			void *buffer, size_t len,
+			sec_cb *cb, void *cb_data);
+};
+
+
+#ifdef CONFIG_SED
+int sed_save(struct block_device *bdev, struct sed_key *key);
+int sed_lock_unlock(struct block_device *bdev, struct sed_key *key);
+int sed_take_ownership(struct block_device *bdev, struct sed_key *key);
+int sed_activate_lsp(struct block_device *bdev, struct sed_key *key);
+int sed_set_pw(struct block_device *bdev, struct sed_key *key);
+int sed_activate_user(struct block_device *bdev, struct sed_key *key);
+int sed_reverttper(struct block_device *bdev, struct sed_key *key);
+int sed_setup_locking_range(struct block_device *bdev, struct sed_key *key);
+int sed_adduser_to_lr(struct block_device *bdev, struct sed_key *key);
+int sed_do_mbr(struct block_device *bdev, struct sed_key *key);
+int sed_erase_lr(struct block_device *bdev, struct sed_key *key);
+#else
+static inline int sed_save(struct block_device *bdev, struct sed_key *key)
+		{ return -EOPNOTSUPP; }
+static inline int sed_lock_unlock(struct block_device *bdev, struct sed_key *key)
+		{ return -EOPNOTSUPP; }
+static inline int sed_take_ownership(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_activate_lsp(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_set_pw(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_activate_user(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_reverttper(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_setup_locking_range(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_adduser_to_lr(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_do_mbr(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_erase_lr(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+#endif
+
+#endif /* LINUX_SED_H */
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
new file mode 100644
index 0000000..527eb9a
--- /dev/null
+++ b/include/uapi/linux/sed-opal.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Author:
+ *    Rafael Antognolli <rafael.antognolli@intel.com>
+ *    Scott  Bauer      <rafael.antognolli@intel.com>
+ */
+
+#ifndef _UAPI_OPAL_H
+#define _UAPI_OPAL_H
+
+#include <linux/types.h>
+
+#define OPAL_KEY_MAX 256
+
+enum opal_mbr {
+	OPAL_MBR_ENABLE,
+	OPAL_MBR_DISABLE,
+};
+
+enum opal_user {
+	OPAL_ADMIN1,
+	OPAL_USER1,
+	OPAL_USER2,
+	OPAL_USER3,
+	OPAL_USER4,
+	OPAL_USER5,
+	OPAL_USER6,
+	OPAL_USER7,
+	OPAL_USER8,
+	OPAL_USER9,
+};
+
+struct opal_user_info {
+	bool SUM;
+	enum opal_user who;
+};
+
+enum opal_key_type {
+	OPAL_KEY_PLAIN,
+	OPAL_KEY_KEYRING,
+};
+
+enum opal_lock_state {
+	OPAL_RO = 0x01, /* 0001 */
+	OPAL_RW = 0x02, /* 0010 */
+	OPAL_LK = 0x04, /* 0100 */
+};
+
+struct opal_key {
+	__u8	lr;
+	__u8	key_type;
+	__u8	key_len;
+	__u8	key[OPAL_KEY_MAX];
+};
+
+struct opal_activate_user {
+	struct opal_user_info who;
+	struct opal_key key;
+};
+
+struct opal_user_lr_setup {
+	struct opal_user_info who;
+	struct opal_key key;
+	size_t range_start;
+	size_t range_length;
+	int    RLE; /* Read Lock enabled */
+	int    WLE; /* Write Lock Enabled */
+};
+
+struct opal_lock_unlock {
+	struct opal_user_info authority;
+	enum opal_lock_state l_state;
+	struct opal_key key;
+};
+
+struct opal_new_pw {
+	struct opal_user_info who;
+
+	/* When we're not operating in SUM, and we first set
+	 * passwords we need to set them via ADMIN authority.
+	 * After passwords are changed, we can set them via,
+	 * User authorities.
+	 * Because of this restriction we need to know about
+	 * Two different users. One in 'who' which we will use
+	 * to start the session and user_for_pw as the user we're
+	 * chaning the pw for.
+	 */
+	enum opal_user user_for_pw;
+	struct opal_key current_pin;
+	struct opal_key new_pin;
+};
+
+struct opal_mbr_data {
+	u8 enable_disable;
+	struct opal_key key;
+};
+
+#endif /* _UAPI_SED_H */
diff --git a/include/uapi/linux/sed.h b/include/uapi/linux/sed.h
new file mode 100644
index 0000000..6973044
--- /dev/null
+++ b/include/uapi/linux/sed.h
@@ -0,0 +1,55 @@
+/*
+ * Definitions for the self-encrypting drive interface
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _UAPI_SED_H
+#define _UAPI_SED_H
+
+#include <linux/types.h>
+
+enum sed_key_type {
+	OPAL,
+	OPAL_PW,
+	OPAL_ACT_USR,
+	OPAL_LR_SETUP,
+	OPAL_LOCK_UNLOCK,
+	OPAL_MBR_DATA,
+};
+
+struct sed_key {
+	__u32 sed_type;
+	union {
+		struct opal_key           __user *opal;
+		struct opal_new_pw        __user *opal_pw;
+		struct opal_activate_user __user *opal_act;
+		struct opal_user_lr_setup __user *opal_lrs;
+		struct opal_lock_unlock   __user *opal_lk_unlk;
+		struct opal_mbr_data      __user *opal_mbr;
+		/* additional command set key types */
+	};
+};
+
+
+#define IOC_SED_SAVE		   _IOW('p', 220, struct sed_key)
+#define IOC_SED_LOCK_UNLOCK	   _IOW('p', 221, struct sed_key)
+#define IOC_SED_TAKE_OWNERSHIP	   _IOW('p', 222, struct sed_key)
+#define IOC_SED_ACTIVATE_LSP       _IOW('p', 223, struct sed_key)
+#define IOC_SED_SET_PW             _IOW('p', 224, struct sed_key)
+#define IOC_SED_ACTIVATE_USR       _IOW('p', 225, struct sed_key)
+#define IOC_SED_REVERT_TPR         _IOW('p', 226, struct sed_key)
+#define IOC_SED_LR_SETUP           _IOW('p', 227, struct sed_key)
+#define IOC_SED_ADD_USR_TO_LR      _IOW('p', 228, struct sed_key)
+#define IOC_SED_ENABLE_DISABLE_MBR _IOW('p', 229, struct sed_key)
+#define IOC_SED_ERASE_LR           _IOW('p', 230, struct sed_key)
+
+#endif /* _UAPI_SED_H */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 1/7] Include: Add definitions for sed
@ 2016-11-16 23:17   ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)


This patch adds the definitions and structures for the SED
Opal code.

Signed-off-by: Scott Bauer <scott.bauer at intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli at intel.com>
---
 include/linux/sed-opal.h      |  58 +++++++++++++++++++++
 include/linux/sed.h           |  91 ++++++++++++++++++++++++++++++++
 include/uapi/linux/sed-opal.h | 118 ++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/sed.h      |  55 ++++++++++++++++++++
 4 files changed, 322 insertions(+)
 create mode 100644 include/linux/sed-opal.h
 create mode 100644 include/linux/sed.h
 create mode 100644 include/uapi/linux/sed-opal.h
 create mode 100644 include/uapi/linux/sed.h

diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
new file mode 100644
index 0000000..e0ee21e
--- /dev/null
+++ b/include/linux/sed-opal.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright ? 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rafael Antognolli <rafael.antognolli at intel.com>
+ *    Scott  Bauer      <scott.bauer at intel.com>
+ */
+
+#ifndef LINUX_OPAL_H
+#define LINUX_OPAL_H
+
+#include <linux/sed.h>
+#include <linux/kernel.h>
+
+enum {
+	TCG_SECP_00 = 0,
+	TCG_SECP_01,
+};
+
+struct opal_suspend_unlk {
+	void *data;
+	const char *name;
+	struct sec_ops ops;
+};
+
+int opal_save(struct block_device *bdev, struct sed_key *key);
+int opal_lock_unlock(struct block_device *bdev, struct sed_key *key);
+int opal_take_ownership(struct block_device *bdev, struct sed_key *key);
+int opal_activate_lsp(struct block_device *bdev, struct sed_key *key);
+int opal_set_new_pw(struct block_device *bdev, struct sed_key *key);
+int opal_activate_user(struct block_device *bdev, struct sed_key *key);
+int opal_reverttper(struct block_device *bdev, struct sed_key *key);
+int opal_setup_locking_range(struct block_device *bdev, struct sed_key *key);
+int opal_add_user_to_lr(struct block_device *bdev, struct sed_key *key);
+int opal_enable_disable_shadow_mbr(struct block_device *bdev, struct sed_key *key);
+int opal_unlock_from_suspend(struct opal_suspend_unlk *data);
+int opal_erase_locking_range(struct block_device *bdev, struct sed_key *key);
+
+#endif /* LINUX_OPAL_H */
diff --git a/include/linux/sed.h b/include/linux/sed.h
new file mode 100644
index 0000000..6c9bae9
--- /dev/null
+++ b/include/linux/sed.h
@@ -0,0 +1,91 @@
+/*
+ * Self-Encrypting Drive interface - sed.h
+ *
+ * Copyright (C) 2016 Intel Corporation <jonathan.derrick at intel.com>
+ *
+ * This code is the generic layer to interface with self-encrypting
+ * drives. Specific command sets should advertise support to sed uapi
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef LINUX_SED_H
+#define LINUX_SED_H
+
+#include <linux/blkdev.h>
+#include <uapi/linux/sed.h>
+
+/*
+ * sec_ops - transport specific Trusted Send/Receive functions
+ * See SPC-4 for specific definitions
+ *
+ * @sec_send: sends the payload to the trusted peripheral
+ *	SPSP: Security Protocol Specific
+ *	SECP: Security Protocol
+ *	buf: Payload
+ *	len: Payload length
+ * @recv: Receives a payload from the trusted peripheral
+ *	SPSP: Security Protocol Specific
+ *	SECP: Security Protocol
+ *	buf: Payload
+ *	len: Payload length
+ */
+
+typedef void (sec_cb)(int error, void *data);
+
+struct sec_ops {
+	int (*send)(void *data, __u16 SPSP, __u8 SECP,
+			void *buffer, size_t len,
+			sec_cb *cb, void *cb_data);
+	int (*recv)(void *data, __u16 SPSP, __u8 SECP,
+			void *buffer, size_t len,
+			sec_cb *cb, void *cb_data);
+};
+
+
+#ifdef CONFIG_SED
+int sed_save(struct block_device *bdev, struct sed_key *key);
+int sed_lock_unlock(struct block_device *bdev, struct sed_key *key);
+int sed_take_ownership(struct block_device *bdev, struct sed_key *key);
+int sed_activate_lsp(struct block_device *bdev, struct sed_key *key);
+int sed_set_pw(struct block_device *bdev, struct sed_key *key);
+int sed_activate_user(struct block_device *bdev, struct sed_key *key);
+int sed_reverttper(struct block_device *bdev, struct sed_key *key);
+int sed_setup_locking_range(struct block_device *bdev, struct sed_key *key);
+int sed_adduser_to_lr(struct block_device *bdev, struct sed_key *key);
+int sed_do_mbr(struct block_device *bdev, struct sed_key *key);
+int sed_erase_lr(struct block_device *bdev, struct sed_key *key);
+#else
+static inline int sed_save(struct block_device *bdev, struct sed_key *key)
+		{ return -EOPNOTSUPP; }
+static inline int sed_lock_unlock(struct block_device *bdev, struct sed_key *key)
+		{ return -EOPNOTSUPP; }
+static inline int sed_take_ownership(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_activate_lsp(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_set_pw(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_activate_user(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_reverttper(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_setup_locking_range(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_adduser_to_lr(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_do_mbr(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+static inline int sed_erase_lr(struct block_device *bdev, struct sed_key *key)
+                { return -EOPNOTSUPP; }
+#endif
+
+#endif /* LINUX_SED_H */
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
new file mode 100644
index 0000000..527eb9a
--- /dev/null
+++ b/include/uapi/linux/sed-opal.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright ? 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Author:
+ *    Rafael Antognolli <rafael.antognolli at intel.com>
+ *    Scott  Bauer      <rafael.antognolli at intel.com>
+ */
+
+#ifndef _UAPI_OPAL_H
+#define _UAPI_OPAL_H
+
+#include <linux/types.h>
+
+#define OPAL_KEY_MAX 256
+
+enum opal_mbr {
+	OPAL_MBR_ENABLE,
+	OPAL_MBR_DISABLE,
+};
+
+enum opal_user {
+	OPAL_ADMIN1,
+	OPAL_USER1,
+	OPAL_USER2,
+	OPAL_USER3,
+	OPAL_USER4,
+	OPAL_USER5,
+	OPAL_USER6,
+	OPAL_USER7,
+	OPAL_USER8,
+	OPAL_USER9,
+};
+
+struct opal_user_info {
+	bool SUM;
+	enum opal_user who;
+};
+
+enum opal_key_type {
+	OPAL_KEY_PLAIN,
+	OPAL_KEY_KEYRING,
+};
+
+enum opal_lock_state {
+	OPAL_RO = 0x01, /* 0001 */
+	OPAL_RW = 0x02, /* 0010 */
+	OPAL_LK = 0x04, /* 0100 */
+};
+
+struct opal_key {
+	__u8	lr;
+	__u8	key_type;
+	__u8	key_len;
+	__u8	key[OPAL_KEY_MAX];
+};
+
+struct opal_activate_user {
+	struct opal_user_info who;
+	struct opal_key key;
+};
+
+struct opal_user_lr_setup {
+	struct opal_user_info who;
+	struct opal_key key;
+	size_t range_start;
+	size_t range_length;
+	int    RLE; /* Read Lock enabled */
+	int    WLE; /* Write Lock Enabled */
+};
+
+struct opal_lock_unlock {
+	struct opal_user_info authority;
+	enum opal_lock_state l_state;
+	struct opal_key key;
+};
+
+struct opal_new_pw {
+	struct opal_user_info who;
+
+	/* When we're not operating in SUM, and we first set
+	 * passwords we need to set them via ADMIN authority.
+	 * After passwords are changed, we can set them via,
+	 * User authorities.
+	 * Because of this restriction we need to know about
+	 * Two different users. One in 'who' which we will use
+	 * to start the session and user_for_pw as the user we're
+	 * chaning the pw for.
+	 */
+	enum opal_user user_for_pw;
+	struct opal_key current_pin;
+	struct opal_key new_pin;
+};
+
+struct opal_mbr_data {
+	u8 enable_disable;
+	struct opal_key key;
+};
+
+#endif /* _UAPI_SED_H */
diff --git a/include/uapi/linux/sed.h b/include/uapi/linux/sed.h
new file mode 100644
index 0000000..6973044
--- /dev/null
+++ b/include/uapi/linux/sed.h
@@ -0,0 +1,55 @@
+/*
+ * Definitions for the self-encrypting drive interface
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _UAPI_SED_H
+#define _UAPI_SED_H
+
+#include <linux/types.h>
+
+enum sed_key_type {
+	OPAL,
+	OPAL_PW,
+	OPAL_ACT_USR,
+	OPAL_LR_SETUP,
+	OPAL_LOCK_UNLOCK,
+	OPAL_MBR_DATA,
+};
+
+struct sed_key {
+	__u32 sed_type;
+	union {
+		struct opal_key           __user *opal;
+		struct opal_new_pw        __user *opal_pw;
+		struct opal_activate_user __user *opal_act;
+		struct opal_user_lr_setup __user *opal_lrs;
+		struct opal_lock_unlock   __user *opal_lk_unlk;
+		struct opal_mbr_data      __user *opal_mbr;
+		/* additional command set key types */
+	};
+};
+
+
+#define IOC_SED_SAVE		   _IOW('p', 220, struct sed_key)
+#define IOC_SED_LOCK_UNLOCK	   _IOW('p', 221, struct sed_key)
+#define IOC_SED_TAKE_OWNERSHIP	   _IOW('p', 222, struct sed_key)
+#define IOC_SED_ACTIVATE_LSP       _IOW('p', 223, struct sed_key)
+#define IOC_SED_SET_PW             _IOW('p', 224, struct sed_key)
+#define IOC_SED_ACTIVATE_USR       _IOW('p', 225, struct sed_key)
+#define IOC_SED_REVERT_TPR         _IOW('p', 226, struct sed_key)
+#define IOC_SED_LR_SETUP           _IOW('p', 227, struct sed_key)
+#define IOC_SED_ADD_USR_TO_LR      _IOW('p', 228, struct sed_key)
+#define IOC_SED_ENABLE_DISABLE_MBR _IOW('p', 229, struct sed_key)
+#define IOC_SED_ERASE_LR           _IOW('p', 230, struct sed_key)
+
+#endif /* _UAPI_SED_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 2/7] lib: Add Sed-opal library
  2016-11-16 23:17 ` Scott Bauer
@ 2016-11-16 23:17   ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)
  To: linux-nvme
  Cc: keith.busch, sagi, hch, Rafael.Antognolli, axboe, linux-block,
	Scott Bauer, jonathan.derrick, j.naumann

VGhpcyBwYXRjaCBpbXBsZW1lbnRzIHRoZSBuZWNlc3NhcnkgbG9naWMgdG8gYnJpbmcgYW4gT3Bh
bAplbmFibGVkIGRyaXZlIG91dCBvZiBhIGZhY3RvcnktZW5hYmxlZCBpbnRvIGEgd29ya2luZwpP
cGFsIHN0YXRlLgoKVGhpcyBwYXRjaCBzZXQgYWxzbyBlbmFibGVzIGxvZ2ljIHRvIHNhdmUgYSBw
YXNzd29yZCB0bwpiZSByZXBsYXllZCBkdXJpbmcgYSByZXN1bWUgZnJvbSBzdXNwZW5kLiBUaGUg
a2V5IGNhbiBiZQpzYXZlZCBpbiB0aGUgZHJpdmVyIG9yIGluIHRoZSBLZXJuZWwncyBLZXkgbWFu
YWdtZW50LgoKU2lnbmVkLW9mZi1ieTogU2NvdHQgQmF1ZXIgPHNjb3R0LmJhdWVyQGludGVsLmNv
bT4KU2lnbmVkLW9mZi1ieTogUmFmYWVsIEFudG9nbm9sbGkgPFJhZmFlbC5BbnRvZ25vbGxpQGlu
dGVsLmNvbT4KLS0tCiBsaWIvc2VkLW9wYWwuYyAgICAgICAgICB8IDMzMzggKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIGxpYi9zZWQtb3BhbF9pbnRlcm5h
bC5oIHwgIDU4NyArKysrKysrKysKIGxpYi9zZWQtb3BhbF9rZXkuYyAgICAgIHwgICA0NiArCiBs
aWIvc2VkLmMgICAgICAgICAgICAgICB8ICAyNTAgKysrKwogNCBmaWxlcyBjaGFuZ2VkLCA0MjIx
IGluc2VydGlvbnMoKykKIGNyZWF0ZSBtb2RlIDEwMDY0NCBsaWIvc2VkLW9wYWwuYwogY3JlYXRl
IG1vZGUgMTAwNjQ0IGxpYi9zZWQtb3BhbF9pbnRlcm5hbC5oCiBjcmVhdGUgbW9kZSAxMDA2NDQg
bGliL3NlZC1vcGFsX2tleS5jCiBjcmVhdGUgbW9kZSAxMDA2NDQgbGliL3NlZC5jCgpkaWZmIC0t
Z2l0IGEvbGliL3NlZC1vcGFsLmMgYi9saWIvc2VkLW9wYWwuYwpuZXcgZmlsZSBtb2RlIDEwMDY0
NAppbmRleCAwMDAwMDAwLi4zY2UxMTI2Ci0tLSAvZGV2L251bGwKKysrIGIvbGliL3NlZC1vcGFs
LmMKQEAgLTAsMCArMSwzMzM4IEBACisvKgorICogQ29weXJpZ2h0IMKpIDIwMTYgSW50ZWwgQ29y
cG9yYXRpb24KKyAqCisgKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNo
YXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYQorICogY29weSBvZiB0aGlzIHNvZnR3YXJl
IGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwKKyAq
IHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3
aXRob3V0IGxpbWl0YXRpb24KKyAqIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1l
cmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLAorICogYW5kL29yIHNlbGwgY29w
aWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlCisg
KiBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2lu
ZyBjb25kaXRpb25zOgorICoKKyAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlz
IHBlcm1pc3Npb24gbm90aWNlIChpbmNsdWRpbmcgdGhlIG5leHQKKyAqIHBhcmFncmFwaCkgc2hh
bGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0
aGUKKyAqIFNvZnR3YXJlLgorICoKKyAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMi
LCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SCisgKiBJTVBMSUVELCBJ
TkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJ
TElUWSwKKyAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5H
RU1FTlQuICBJTiBOTyBFVkVOVCBTSEFMTAorICogVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhP
TERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKKyAqIExJQUJJ
TElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNF
LCBBUklTSU5HCisgKiBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZU
V0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTCisgKiBJTiBUSEUgU09GVFdBUkUuCisg
KgorICogQXV0aG9yczoKKyAqICAgIFJhZmFlbCBBbnRvZ25vbGxpIDxyYWZhZWwuYW50b2dub2xs
aUBpbnRlbC5jb20+CisgKiAgICBTY290dCAgQmF1ZXIgICAgICA8c2NvdHQuYmF1ZXJAaW50ZWwu
Y29tPgorICovCisKKyNkZWZpbmUgcHJfZm10KGZtdCkgS0JVSUxEX01PRE5BTUUgIjpPUEFMOiAi
IGZtdAorCisjaW5jbHVkZSA8bGludXgvZGVsYXkuaD4KKyNpbmNsdWRlIDxsaW51eC9kZXZpY2Uu
aD4KKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4KKyNpbmNsdWRlIDxsaW51eC9saXN0Lmg+Cisj
aW5jbHVkZSA8bGludXgvZ2VuaGQuaD4KKyNpbmNsdWRlIDxsaW51eC9zbGFiLmg+CisjaW5jbHVk
ZSA8bGludXgvdWFjY2Vzcy5oPgorI2luY2x1ZGUgPHVhcGkvbGludXgvc2VkLW9wYWwuaD4KKyNp
bmNsdWRlIDxsaW51eC9zZWQuaD4KKyNpbmNsdWRlIDxsaW51eC9zZWQtb3BhbC5oPgorI2luY2x1
ZGUgPGxpbnV4L3N0cmluZy5oPgorCisjaW5jbHVkZSAic2VkLW9wYWxfaW50ZXJuYWwuaCIKKwor
I2RlZmluZSBJT19CVUZGRVJfTEVOR1RIIDIwNDgKKworI2RlZmluZSBNQVhfVE9LUyA2NAorCitz
dHJ1Y3Qgb3BhbF9jbWQgeworCXN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXY7CisJc2VjX2NiICpj
YjsKKwl2b2lkICpjYl9kYXRhOworCisJc2l6ZV90IHBvczsKKwl1OCBjbWRfYnVmW0lPX0JVRkZF
Ul9MRU5HVEggKiAyXTsKKwl1OCByZXNwX2J1ZltJT19CVUZGRVJfTEVOR1RIICogMl07CisJdTgg
KmNtZDsKKwl1OCAqcmVzcDsKK307CisKKy8qCisgKiBPbiB0aGUgcGFyc2VkIHJlc3BvbnNlLCB3
ZSBkb24ndCBzdG9yZSBhZ2FpbiB0aGUgdG9rcyB0aGF0IGFyZSBhbHJlYWR5CisgKiBzdG9yZWQg
aW4gdGhlIHJlc3BvbnNlIGJ1ZmZlci4gSW5zdGVhZCwgZm9yIGVhY2ggdG9rZW4sIHdlIGp1c3Qg
c3RvcmUgYQorICogcG9pbnRlciB0byB0aGUgcG9zaXRpb24gaW4gdGhlIGJ1ZmZlciB3aGVyZSB0
aGUgdG9rZW4gc3RhcnRzLCBhbmQgdGhlIHNpemUKKyAqIG9mIHRoZSB0b2tlbiBpbiBieXRlcy4K
KyAqLworc3RydWN0IG9wYWxfcmVzcF90b2sgeworCWNvbnN0IHU4ICpwb3M7CisJc2l6ZV90IGxl
bjsKKwllbnVtIE9QQUxfUkVTUE9OU0VfVE9LRU4gdHlwZTsKKwllbnVtIE9QQUxfQVRPTV9XSURU
SCB3aWR0aDsKKwl1bmlvbiB7CisJCXU2NCB1OworCQlzNjQgczsKKwl9IHN0b3JlZDsKK307CisK
Ky8qCisgKiBGcm9tIHRoZSByZXNwb25zZSBoZWFkZXIgaXQncyBub3QgcG9zc2libGUgdG8ga25v
dyBob3cgbWFueSB0b2tlbnMgdGhlcmUgYXJlCisgKiBvbiB0aGUgcGF5bG9hZC4gU28gd2UgaGFy
ZGNvZGUgdGhhdCB0aGUgbWF4aW11bSB3aWxsIGJlIE1BWF9UT0tTLCBhbmQgbGF0ZXIKKyAqIGlm
IHdlIHN0YXJ0IGRlYWxpbmcgd2l0aCBtZXNzYWdlcyB0aGF0IGhhdmUgbW9yZSB0aGFuIHRoYXQs
IHdlIGNhbiBpbmNyZWFzZQorICogdGhpcyBudW1iZXIuIFRoaXMgaXMgZG9uZSB0byBhdm9pZCBo
YXZpbmcgdG8gbWFrZSB0d28gcGFzc2VzIHRocm91Z2ggdGhlCisgKiByZXNwb25zZSwgdGhlIGZp
cnN0IG9uZSBjb3VudGluZyBob3cgbWFueSB0b2tlbnMgd2UgaGF2ZSBhbmQgdGhlIHNlY29uZCBv
bmUKKyAqIGFjdHVhbGx5IHN0b3JpbmcgdGhlIHBvc2l0aW9ucy4KKyAqLworc3RydWN0IHBhcnNl
ZF9yZXNwIHsKKwlpbnQgbnVtOworCXN0cnVjdCBvcGFsX3Jlc3BfdG9rIHRva3NbTUFYX1RPS1Nd
OworfTsKKworc3RydWN0IG9wYWxfZGV2OworCit0eXBlZGVmIHZvaWQgKCpvcGFsX2NiKShpbnQg
ZXJyb3IsIHN0cnVjdCBvcGFsX2RldiAqZGV2KTsKKwordHlwZWRlZiBpbnQgKCpvcGFsX3N0ZXAp
KHN0cnVjdCBvcGFsX2RldiAqZGV2KTsKKworc3RydWN0IG9wYWxfY29tcGxldGlvbiB7CisJc3Ry
dWN0IGNvbXBsZXRpb24gY21kX2NvbXBsZXRpb247CisJaW50IGNvbXBsZXRpb25fc3RhdHVzOwor
fTsKKworc3RydWN0IG9wYWxfZGV2IHsKKwlzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2OworCXN0
cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247CisJc3RydWN0IG9wYWxfbG9ja191bmxv
Y2sgbGt1bDsKKwljb25zdCBvcGFsX3N0ZXAgKmZ1bmNzOworCXN0cnVjdCB3b3JrX3N0cnVjdCBv
cGFsX3NlbmRfd29yazsKKwlzdHJ1Y3Qgd29ya19zdHJ1Y3Qgb3BhbF9yZWN2X3dvcms7CisJdm9p
ZCAqKmZ1bmNfZGF0YTsKKwlib29sIHJlc3VtZV9mcm9tX3N1c3BlbmQ7CisJc3RydWN0IG9wYWxf
c3VzcGVuZF91bmxrICpyZXN1bWVfZGF0YTsKKwlzaXplX3QgbnVtX2Z1bmNfZGF0YTsKKwlhdG9t
aWNfdCBpbl91c2U7CisJc2VjdG9yX3Qgc3RhcnQ7CisJc2VjdG9yX3QgbGVuZ3RoOworCXU4IGxy
OworCXU4IGtleV90eXBlOworCXU4IGtleV9uYW1lW09QQUxfS0VZX01BWF07CisJc2l6ZV90IGtl
eV9uYW1lX2xlbjsKKwl1OCBrZXlbT1BBTF9LRVlfTUFYXTsKKwlzaXplX3Qga2V5X2xlbjsKKwl1
MTYgY29tSUQ7CisJdTMyIEhTTjsKKwl1MzIgVFNOOworCXU2NCBhbGlnbjsKKwl1NjQgbG93ZXN0
X2xiYTsKKwlzdHJ1Y3QgbGlzdF9oZWFkIG5vZGU7CisJY2hhciBkaXNrX25hbWVbRElTS19OQU1F
X0xFTl07CisJaW50IHN0YXRlOworCisJc3RydWN0IG9wYWxfY21kIGNtZDsKKwlzdHJ1Y3QgcGFy
c2VkX3Jlc3AgcGFyc2VkOworCisJc2l6ZV90IHByZXZfZF9sZW47CisJdm9pZCAqcHJldl9kYXRh
OworCisJc2VjX2NiICpmaW5hbF9jYjsKKwl2b2lkICpmaW5hbF9jYl9kYXRhOworCW9wYWxfc3Rl
cCBlcnJvcl9jYjsKKwl2b2lkICplcnJvcl9jYl9kYXRhOworCW9wYWxfY2Igb3Blcl9jYjsKK307
CisKK0xJU1RfSEVBRChvcGFsX2xpc3QpOworREVGSU5FX1NQSU5MT0NLKGxpc3Rfc3BpbmxvY2sp
OworCitzdGF0aWMgdm9pZCBwcmludF9idWZmZXIoY29uc3QgdTggKnB0ciwgdTMyIGxlbmd0aCkK
K3sKKyNpZmRlZiBERUJVRworCXByaW50X2hleF9kdW1wX2J5dGVzKCJPUEFMOiAiLCBEVU1QX1BS
RUZJWF9PRkZTRVQsIHB0ciwgbGVuZ3RoKTsKKwlwcl9kZWJ1ZygiXG4iKTsKKyNlbmRpZgorfQor
CisjZGVmaW5lIFRQRVJfU1lOQ19TVVBQT1JURUQgQklUKDApCisKK3N0YXRpYyBib29sIGNoZWNr
X3RwZXIoY29uc3Qgdm9pZCAqZGF0YSkKK3sKKwljb25zdCBzdHJ1Y3QgZDBfdHBlcl9mZWF0dXJl
cyAqdHBlciA9IGRhdGE7CisJdTggZmxhZ3MgPSB0cGVyLT5zdXBwb3J0ZWRfZmVhdHVyZXM7CisK
KwlpZiAoIShmbGFncyAmIFRQRVJfU1lOQ19TVVBQT1JURUQpKSB7CisJCXByX2VycigiVFBlciBz
eW5jIG5vdCBzdXBwb3J0ZWQuIGZsYWdzID0gJWRcbiIsCisJCSAgICAgICB0cGVyLT5zdXBwb3J0
ZWRfZmVhdHVyZXMpOworCQlyZXR1cm4gZmFsc2U7CisJfQorCisJcmV0dXJuIHRydWU7Cit9CisK
K3N0YXRpYyBib29sIGNoZWNrX1NVTShjb25zdCB2b2lkICpkYXRhKQoreworCWNvbnN0IHN0cnVj
dCBkMF9zaW5nbGVfdXNlcl9tb2RlICpzdW0gPSBkYXRhOworCXUzMiBubG8gPSBiZTMyX3RvX2Nw
dShzdW0tPm51bV9sb2NraW5nX29iamVjdHMpOworCisJaWYgKG5sbyA9PSAwKSB7CisJCXByX2Vy
cigiTmVlZCBhdCBsZWFzdCBvbmUgbG9ja2luZyBvYmplY3QuXG4iKTsKKwkJcmV0dXJuIGZhbHNl
OworCX0KKworCXByX2RlYnVnKCJOdW1iZXIgb2YgbG9ja2luZyBvYmplY3RzOiAlZFxuIiwgbmxv
KTsKKworCXJldHVybiB0cnVlOworfQorCitzdGF0aWMgdTE2IGdldF9jb21JRF92MTAwKGNvbnN0
IHZvaWQgKmRhdGEpCit7CisJY29uc3Qgc3RydWN0IGQwX29wYWxfdjEwMCAqdjEwMCA9IGRhdGE7
CisKKwlyZXR1cm4gYmUxNl90b19jcHUodjEwMC0+YmFzZUNvbUlEKTsKK30KKworc3RhdGljIHUx
NiBnZXRfY29tSURfdjIwMChjb25zdCB2b2lkICpkYXRhKQoreworCWNvbnN0IHN0cnVjdCBkMF9v
cGFsX3YyMDAgKnYyMDAgPSBkYXRhOworCisJcmV0dXJuIGJlMTZfdG9fY3B1KHYyMDAtPmJhc2VD
b21JRCk7Cit9CisKK3N0YXRpYyB2b2lkIG9wYWxfc2VuZF9jYl9jb250KGludCBlcnJvciwgdm9p
ZCAqZGF0YSkKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisJc2l6ZV90IGJ1Zmxl
biA9IElPX0JVRkZFUl9MRU5HVEg7CisJdm9pZCAqYnVmZmVyID0gZGV2LT5jbWQucmVzcDsKKwlz
dHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkciA9IGJ1ZmZlcjsKKworCXByX2RlYnVnKCIlczogU2VudCBP
UEFMIGNvbW1hbmQ6IGVycm9yPSVkLCBvdXRzdGFuZGluZz0lZCwgbWluVHJhbnNmZXI9JWRcbiIs
CisJICAgICAgIGRldi0+ZGlza19uYW1lLCBlcnJvciwgaGRyLT5jcC5vdXRzdGFuZGluZ0RhdGEs
CisJICAgICAgIGhkci0+Y3AubWluVHJhbnNmZXIpOworCisJaWYgKGVycm9yIHx8IGhkci0+Y3Au
b3V0c3RhbmRpbmdEYXRhID09IDAgfHwKKwkgICAgaGRyLT5jcC5taW5UcmFuc2ZlciAhPSAwKSB7
CisJCWlmIChkZXYtPmNtZC5jYikKKwkJCWRldi0+Y21kLmNiKGVycm9yLCBkZXYtPmNtZC5jYl9k
YXRhKTsKKwkJcmV0dXJuOworCX0KKworCW1lbXNldChidWZmZXIsIDAsIGJ1Zmxlbik7CisJc2No
ZWR1bGVfd29yaygmZGV2LT5vcGFsX3JlY3Zfd29yayk7Cit9CisKK3N0YXRpYyB2b2lkIG9wYWxf
c2VuZF9jYihpbnQgZXJyb3IsIHZvaWQgKmRhdGEpCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXYg
PSBkYXRhOworCXNpemVfdCBidWZsZW4gPSBJT19CVUZGRVJfTEVOR1RIOworCXZvaWQgKmJ1ZmZl
ciA9IGRldi0+Y21kLnJlc3A7CisKKwlpZiAoZXJyb3IpIHsKKwkJaWYgKGRldi0+Y21kLmNiKQor
CQkJZGV2LT5jbWQuY2IoZXJyb3IsIGRldi0+Y21kLmNiX2RhdGEpOworCQlyZXR1cm47CisJfQor
CisJbWVtc2V0KGJ1ZmZlciwgMCwgYnVmbGVuKTsKKwlzY2hlZHVsZV93b3JrKCZkZXYtPm9wYWxf
cmVjdl93b3JrKTsKK30KKworc3RhdGljIGlubGluZSB2b2lkIGdldF9kYXRhX29wcyhzdHJ1Y3Qg
b3BhbF9kZXYgKmRldiwgY29uc3Qgc3RydWN0IHNlY19vcHMgKipvcHMsCisJCQkJdm9pZCAqKmRh
dGEpCit7CisJaWYgKGRldi0+cmVzdW1lX2Zyb21fc3VzcGVuZCkgeworCQkqb3BzID0gJmRldi0+
cmVzdW1lX2RhdGEtPm9wczsKKwkJKmRhdGEgPSBkZXYtPnJlc3VtZV9kYXRhLT5kYXRhOworCX0g
ZWxzZSB7CisJCSpvcHMgPSBkZXYtPmJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHM7CisJCSpk
YXRhID0gZGV2LT5iZGV2LT5iZF9kaXNrLT5wcml2YXRlX2RhdGE7CisJfQorfQorCitzdGF0aWMg
dm9pZCBfb3BhbF9zZW5kX2NtZChzdHJ1Y3Qgd29ya19zdHJ1Y3QgKnNlbmRfd29yaykKK3sKKwlz
dHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGNvbnRhaW5lcl9vZihzZW5kX3dvcmssIHN0cnVjdCBvcGFs
X2RldiwKKwkJCQkJICAgIG9wYWxfc2VuZF93b3JrKTsKKwljb25zdCBzdHJ1Y3Qgc2VjX29wcyAq
b3BzID0gTlVMTDsKKwl2b2lkICpkYXRhID0gTlVMTDsKKworCWdldF9kYXRhX29wcyhkZXYsICZv
cHMsICZkYXRhKTsKKwlvcHMtPnNlbmQoZGF0YSwgZGV2LT5jb21JRCwgVENHX1NFQ1BfMDEsIGRl
di0+Y21kLmNtZCwKKwkJICBJT19CVUZGRVJfTEVOR1RILCBvcGFsX3NlbmRfY2IsIGRldik7CisK
K30KKworc3RhdGljIHZvaWQgX29wYWxfcmVjdl9jbWQoc3RydWN0IHdvcmtfc3RydWN0ICpyZWN2
X3dvcmspCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBjb250YWluZXJfb2YocmVjdl93b3Jr
LCBzdHJ1Y3Qgb3BhbF9kZXYsCisJCQkJCSAgICBvcGFsX3JlY3Zfd29yayk7CisJY29uc3Qgc3Ry
dWN0IHNlY19vcHMgKm9wczsKKwl2b2lkICpkYXRhOworCisJZ2V0X2RhdGFfb3BzKGRldiwgJm9w
cywgJmRhdGEpOworCW9wcy0+cmVjdihkYXRhLCBkZXYtPmNvbUlELCBUQ0dfU0VDUF8wMSwgZGV2
LT5jbWQucmVzcCwKKwkJICBJT19CVUZGRVJfTEVOR1RILCBvcGFsX3NlbmRfY2JfY29udCwgZGV2
KTsKK30KKworc3RhdGljIHZvaWQgb3BhbF9zZW5kX3JlY3Yoc3RydWN0IG9wYWxfZGV2ICpkZXYs
IHNlY19jYiAqY2IsIHZvaWQgKmNiX2RhdGEpCit7CisJZGV2LT5jbWQuY2IgPSBjYjsKKwlkZXYt
PmNtZC5jYl9kYXRhID0gY2JfZGF0YTsKKwlzY2hlZHVsZV93b3JrKCZkZXYtPm9wYWxfc2VuZF93
b3JrKTsKK30KKworc3RhdGljIHZvaWQgY2hlY2tfZ2VvbWV0cnkoc3RydWN0IG9wYWxfZGV2ICpk
ZXYsIGNvbnN0IHZvaWQgKmRhdGEpCit7CisJY29uc3Qgc3RydWN0IGQwX2dlb21ldHJ5X2ZlYXR1
cmVzICpnZW8gPSBkYXRhOworCisJZGV2LT5hbGlnbiA9IGdlby0+YWxpZ25tZW50X2dyYW51bGFy
aXR5OworCWRldi0+bG93ZXN0X2xiYSA9IGdlby0+bG93ZXN0X2FsaWduZWRfbGJhOworfQorCitz
dGF0aWMgdm9pZCBvcGFsX2Rpc2NvdmVyeTBfZW5kKGludCBlcnJvciwgdm9pZCAqZGF0YSkKK3sK
Kwlib29sIGZvdW5kQ29tSUQgPSBmYWxzZSwgc3VwcG9ydGVkID0gdHJ1ZSwgc2luZ2xlX3VzZXIg
PSBmYWxzZTsKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisJY29uc3Qgc3RydWN0IGQw
X2hlYWRlciAqaGRyOworCWNvbnN0IHU4ICplcG9zLCAqY3BvczsKKwl1MTYgY29tSUQgPSAwOwor
CisJaWYgKGVycm9yKSB7CisJCXByX2VycigiJXM6IFNlbmRpbmcgZGlzY292ZXJ5MCBmYWlsZWRc
biIsIGRldi0+ZGlza19uYW1lKTsKKwkJZ290byBlcnJfY2FsbGJhY2s7CisJfQorCisJZXBvcyA9
IGRldi0+Y21kLnJlc3A7CisJY3BvcyA9IGRldi0+Y21kLnJlc3A7CisJaGRyID0gKHN0cnVjdCBk
MF9oZWFkZXIgKilkZXYtPmNtZC5yZXNwOworCisJcHJpbnRfYnVmZmVyKGRldi0+Y21kLnJlc3As
IGJlMzJfdG9fY3B1KGhkci0+bGVuZ3RoKSk7CisKKwllcG9zICs9IGJlMzJfdG9fY3B1KGhkci0+
bGVuZ3RoKTsgLyogZW5kIG9mIGJ1ZmZlciAqLworCWNwb3MgKz0gc2l6ZW9mKCpoZHIpOyAvKiBj
dXJyZW50IHBvc2l0aW9uIG9uIGJ1ZmZlciAqLworCisJd2hpbGUgKGNwb3MgPCBlcG9zICYmIHN1
cHBvcnRlZCkgeworCQljb25zdCBzdHJ1Y3QgZDBfZmVhdHVyZXMgKmJvZHkgPQorCQkJKGNvbnN0
IHN0cnVjdCBkMF9mZWF0dXJlcyAqKWNwb3M7CisKKwkJc3dpdGNoIChiZTE2X3RvX2NwdShib2R5
LT5jb2RlKSkgeworCQljYXNlIEZDX1RQRVI6CisJCQlzdXBwb3J0ZWQgPSBjaGVja190cGVyKGJv
ZHktPmZlYXR1cmVzKTsKKwkJCWJyZWFrOworCQljYXNlIEZDX1NJTkdMRVVTRVI6CisJCQlzaW5n
bGVfdXNlciA9IGNoZWNrX1NVTShib2R5LT5mZWF0dXJlcyk7CisJCQlicmVhazsKKwkJY2FzZSBG
Q19HRU9NRVRSWToKKwkJCWNoZWNrX2dlb21ldHJ5KGRldiwgYm9keSk7CisJCQlicmVhazsKKwkJ
Y2FzZSBGQ19MT0NLSU5HOgorCQljYXNlIEZDX0VOVEVSUFJJU0U6CisJCWNhc2UgRkNfREFUQVNU
T1JFOgorCQkJLyogc29tZSBpZ25vcmVkIHByb3BlcnRpZXMgKi8KKwkJCXByX2RlYnVnKCIlczog
Rm91bmQgT1BBTCBmZWF0dXJlIGRlc2NyaXB0aW9uOiAlZFxuIiwKKwkJCQkgZGV2LT5kaXNrX25h
bWUsIGJlMTZfdG9fY3B1KGJvZHktPmNvZGUpKTsKKwkJCWJyZWFrOworCQljYXNlIEZDX09QQUxW
MTAwOgorCQkJY29tSUQgPSBnZXRfY29tSURfdjEwMChib2R5LT5mZWF0dXJlcyk7CisJCQlmb3Vu
ZENvbUlEID0gdHJ1ZTsKKwkJCWJyZWFrOworCQljYXNlIEZDX09QQUxWMjAwOgorCQkJY29tSUQg
PSBnZXRfY29tSURfdjIwMChib2R5LT5mZWF0dXJlcyk7CisJCQlmb3VuZENvbUlEID0gdHJ1ZTsK
KwkJCWJyZWFrOworCQljYXNlIDB4YmZmZiAuLi4gMHhmZmZmOgorCQkJLyogdmVuZG9yIHNwZWNp
ZmljLCBqdXN0IGlnbm9yZSAqLworCQkJYnJlYWs7CisJCWRlZmF1bHQ6CisJCQlwcl93YXJuKCIl
czogT1BBTCBVbmtub3duIGZlYXR1cmU6ICVkXG4iLAorCQkJCWRldi0+ZGlza19uYW1lLCBiZTE2
X3RvX2NwdShib2R5LT5jb2RlKSk7CisKKwkJfQorCQljcG9zICs9IGJvZHktPmxlbmd0aCArIDQ7
CisJfQorCisJaWYgKCFzdXBwb3J0ZWQpIHsKKwkJcHJfZXJyKCIlczogRGV2aWNlIG5vdCBzdXBw
b3J0ZWRcbiIsIGRldi0+ZGlza19uYW1lKTsKKwkJZ290byBlcnJfY2FsbGJhY2s7CisJfQorCisJ
aWYgKCFzaW5nbGVfdXNlcikKKwkJcHJfd2FybigiJXM6IERldmljZSBkb2Vzbid0IHN1cHBvcnQg
c2luZ2xlIHVzZXIgbW9kZVxuIiwKKwkJCWRldi0+ZGlza19uYW1lKTsKKworCWlmICghZm91bmRD
b21JRCkgeworCQlwcl93YXJuKCIlczogQ291bGQgbm90IGZpbmQgT1BBTCBjb21JRCBmb3IgZGV2
aWNlLiBPUEFMIGtlcm5lbCB1bmxvY2tpbmcgd2lsbCBiZSBkaXNhYmxlZFxuIiwKKwkJCWRldi0+
ZGlza19uYW1lKTsKKwkJZ290byBlcnJfY2FsbGJhY2s7CisJfQorCisJZGV2LT5jb21JRCA9IGNv
bUlEOworCitlcnJfY2FsbGJhY2s6CisJaWYgKGRldi0+b3Blcl9jYikKKwkJZGV2LT5vcGVyX2Ni
KGVycm9yLCBkZXYpOworfQorCitzdGF0aWMgaW50IG9wYWxfZGlzY292ZXJ5MChzdHJ1Y3Qgb3Bh
bF9kZXYgKmRldikKK3sKKwljb25zdCBzdHJ1Y3Qgc2VjX29wcyAqb3BzOworCXZvaWQgKmRhdGE7
CisKKwlnZXRfZGF0YV9vcHMoZGV2LCAmb3BzLCAmZGF0YSk7CisJbWVtc2V0KGRldi0+Y21kLnJl
c3AsIDAsIElPX0JVRkZFUl9MRU5HVEgpOworCXJldHVybiBvcHMtPnJlY3YoZGF0YSwgMHgwMDAx
LCBUQ0dfU0VDUF8wMSwgZGV2LT5jbWQucmVzcCwKKwkJCSBJT19CVUZGRVJfTEVOR1RILCBvcGFs
X2Rpc2NvdmVyeTBfZW5kLCBkZXYpOworfQorCitzdGF0aWMgdm9pZCBhZGRfdG9rZW5fdTgoc3Ry
dWN0IG9wYWxfY21kICpjbWQsIHU4IHRvaykKK3sKKwljbWQtPmNtZFtjbWQtPnBvcysrXSA9IHRv
azsKK30KKworc3RhdGljIHNzaXplX3QgdGVzdF9hbmRfYWRkX3Rva2VuX3U4KHN0cnVjdCBvcGFs
X2NtZCAqY21kLCB1OCB0b2spCit7CisJQlVJTERfQlVHX09OKElPX0JVRkZFUl9MRU5HVEggPj0g
U0laRV9NQVgpOworCisJaWYgKGNtZC0+cG9zID49IElPX0JVRkZFUl9MRU5HVEggLSAxKSB7CisJ
CXByX2VycigiRXJyb3IgYWRkaW5nIHU4OiBlbmQgb2YgYnVmZmVyLlxuIik7CisJCXJldHVybiAt
RVJBTkdFOworCX0KKworCWFkZF90b2tlbl91OChjbWQsIHRvayk7CisKKwlyZXR1cm4gMTsKK30K
KworI2RlZmluZSBUSU5ZX0FUT01fREFUQV9NQVNLIEdFTk1BU0soNSwgMCkKKyNkZWZpbmUgVElO
WV9BVE9NX1NJR05FRCBCSVQoNikKKworI2RlZmluZSBTSE9SVF9BVE9NX0lEIEJJVCg3KQorI2Rl
ZmluZSBTSE9SVF9BVE9NX0JZVEVTVFJJTkcgQklUKDUpCisjZGVmaW5lIFNIT1JUX0FUT01fU0lH
TkVEIEJJVCg0KQorI2RlZmluZSBTSE9SVF9BVE9NX0xFTl9NQVNLIEdFTk1BU0soMywgMCkKKwor
c3RhdGljIHZvaWQgYWRkX3Nob3J0X2F0b21faGVhZGVyKHN0cnVjdCBvcGFsX2NtZCAqY21kLCBi
b29sIGJ5dGVzdHJpbmcsCisJCQkJICBib29sIGhhc19zaWduLCBpbnQgbGVuKQoreworCXU4IGF0
b207CisKKwlhdG9tID0gU0hPUlRfQVRPTV9JRDsKKwlhdG9tIHw9IGJ5dGVzdHJpbmcgPyBTSE9S
VF9BVE9NX0JZVEVTVFJJTkcgOiAwOworCWF0b20gfD0gaGFzX3NpZ24gPyBTSE9SVF9BVE9NX1NJ
R05FRCA6IDA7CisJYXRvbSB8PSBsZW4gJiBTSE9SVF9BVE9NX0xFTl9NQVNLOworCisJYWRkX3Rv
a2VuX3U4KGNtZCwgYXRvbSk7Cit9CisKKyNkZWZpbmUgTUVESVVNX0FUT01fSUQgKEJJVCg3KSB8
IEJJVCg2KSkKKyNkZWZpbmUgTUVESVVNX0FUT01fQllURVNUUklORyBCSVQoNCkKKyNkZWZpbmUg
TUVESVVNX0FUT01fU0lHTkVEIEJJVCgzKQorI2RlZmluZSBNRURJVU1fQVRPTV9MRU5fTUFTSyBH
RU5NQVNLKDIsIDApCisKK3N0YXRpYyB2b2lkIGFkZF9tZWRpdW1fYXRvbV9oZWFkZXIoc3RydWN0
IG9wYWxfY21kICpjbWQsIGJvb2wgYnl0ZXN0cmluZywKKwkJCQkgICBib29sIGhhc19zaWduLCBp
bnQgbGVuKQoreworCXU4IGhlYWRlcjA7CisKKwloZWFkZXIwID0gTUVESVVNX0FUT01fSUQ7CisJ
aGVhZGVyMCB8PSBieXRlc3RyaW5nID8gTUVESVVNX0FUT01fQllURVNUUklORyA6IDA7CisJaGVh
ZGVyMCB8PSBoYXNfc2lnbiA/IE1FRElVTV9BVE9NX1NJR05FRCA6IDA7CisJaGVhZGVyMCB8PSAo
bGVuID4+IDgpICYgTUVESVVNX0FUT01fTEVOX01BU0s7CisJY21kLT5jbWRbY21kLT5wb3MrK10g
PSBoZWFkZXIwOworCWNtZC0+Y21kW2NtZC0+cG9zKytdID0gbGVuOworfQorCitzdGF0aWMgdm9p
ZCBhZGRfdG9rZW5fdTY0KHN0cnVjdCBvcGFsX2NtZCAqY21kLCB1NjQgbnVtYmVyLCBzaXplX3Qg
bGVuKQoreworCWFkZF9zaG9ydF9hdG9tX2hlYWRlcihjbWQsIGZhbHNlLCBmYWxzZSwgbGVuKTsK
KworCXdoaWxlIChsZW4tLSkgeworCQl1OCBuID0gbnVtYmVyID4+IChsZW4gKiA4KTsKKworCQlh
ZGRfdG9rZW5fdTgoY21kLCBuKTsKKwl9Cit9CisKK3N0YXRpYyBzc2l6ZV90IHRlc3RfYW5kX2Fk
ZF90b2tlbl91NjQoc3RydWN0IG9wYWxfY21kICpjbWQsIHU2NCBudW1iZXIpCit7CisJaW50IGxl
bjsKKwlpbnQgbXNiOworCisJaWYgKCEobnVtYmVyICYgflRJTllfQVRPTV9EQVRBX01BU0spKQor
CQlyZXR1cm4gdGVzdF9hbmRfYWRkX3Rva2VuX3U4KGNtZCwgbnVtYmVyKTsKKworCW1zYiA9IGZs
cyhudW1iZXIpOworCWxlbiA9IERJVl9ST1VORF9VUChtc2IsIDQpOworCisJaWYgKGNtZC0+cG9z
ID49IElPX0JVRkZFUl9MRU5HVEggLSBsZW4gLSAxKSB7CisJCXByX2VycigiRXJyb3IgYWRkaW5n
IHU2NDogZW5kIG9mIGJ1ZmZlci5cbiIpOworCQlyZXR1cm4gLUVSQU5HRTsKKwl9CisKKwlhZGRf
dG9rZW5fdTY0KGNtZCwgbnVtYmVyLCBsZW4pOworCisJLyogcmV0dXJuIGxlbmd0aCBvZiB0b2tl
biBwbHVzIGF0b20gKi8KKwlyZXR1cm4gbGVuICsgMTsKK30KKworc3RhdGljIHZvaWQgYWRkX3Rv
a2VuX2J5dGVzdHJpbmcoc3RydWN0IG9wYWxfY21kICpjbWQsCisJCQkJIGNvbnN0IHU4ICpieXRl
c3RyaW5nLCBzaXplX3QgbGVuKQoreworCW1lbWNweSgmY21kLT5jbWRbY21kLT5wb3NdLCBieXRl
c3RyaW5nLCBsZW4pOworCWNtZC0+cG9zICs9IGxlbjsKK30KKworc3RhdGljIHNzaXplX3QgdGVz
dF9hbmRfYWRkX3Rva2VuX2J5dGVzdHJpbmcoc3RydWN0IG9wYWxfY21kICpjbWQsCisJCQkJCSAg
ICAgY29uc3QgdTggKmJ5dGVzdHJpbmcsIHNpemVfdCBsZW4pCit7CisJc2l6ZV90IGhlYWRlcl9s
ZW4gPSAxOworCWJvb2wgaXNfc2hvcnRfYXRvbSA9IHRydWU7CisKKwlpZiAobGVuICYgflNIT1JU
X0FUT01fTEVOX01BU0spIHsKKwkJaGVhZGVyX2xlbiA9IDI7CisJCWlzX3Nob3J0X2F0b20gPSBm
YWxzZTsKKwl9CisKKwlpZiAoY21kLT5wb3MgPj0gSU9fQlVGRkVSX0xFTkdUSCAtIGxlbiAtIGhl
YWRlcl9sZW4pIHsKKwkJcHJfZXJyKCJFcnJvciBhZGRpbmcgYnl0ZXN0cmluZzogZW5kIG9mIGJ1
ZmZlci5cbiIpOworCQlyZXR1cm4gLUVSQU5HRTsKKwl9CisKKwlpZiAoaXNfc2hvcnRfYXRvbSkK
KwkJYWRkX3Nob3J0X2F0b21faGVhZGVyKGNtZCwgdHJ1ZSwgZmFsc2UsIGxlbik7CisJZWxzZQor
CQlhZGRfbWVkaXVtX2F0b21faGVhZGVyKGNtZCwgdHJ1ZSwgZmFsc2UsIGxlbik7CisKKwlhZGRf
dG9rZW5fYnl0ZXN0cmluZyhjbWQsIGJ5dGVzdHJpbmcsIGxlbik7CisKKwlyZXR1cm4gaGVhZGVy
X2xlbiArIGxlbjsKK30KKworI2RlZmluZSBMT0NLSU5HX1JBTkdFX05PTl9HTE9CQUwgMHgwMwor
CitzdGF0aWMgaW50IGJ1aWxkX2xvY2tpbmdfcmFuZ2UodTggKmJ1ZmZlciwgc2l6ZV90IGxlbmd0
aCwgdTggbHIpCit7CisJaWYgKGxlbmd0aCA8IE9QQUxfVUlEX0xFTkdUSCkKKwkJcmV0dXJuIC1F
UkFOR0U7CisKKwltZW1jcHkoYnVmZmVyLCBPUEFMVUlEW09QQUxfTE9DS0lOR1JBTkdFX0dMT0JB
TF0sIE9QQUxfVUlEX0xFTkdUSCk7CisKKwlpZiAobHIgPT0gMCkKKwkJcmV0dXJuIDA7CisJYnVm
ZmVyWzVdID0gTE9DS0lOR19SQU5HRV9OT05fR0xPQkFMOworCWJ1ZmZlcls3XSA9IGxyOworCisJ
cmV0dXJuIDA7Cit9CisKK3N0YXRpYyBpbnQgYnVpbGRfbG9ja2luZ191c2VyKHU4ICpidWZmZXIs
IHNpemVfdCBsZW5ndGgsIHU4IGxyKQoreworCWlmIChsZW5ndGggPCBPUEFMX1VJRF9MRU5HVEgp
CisJCXJldHVybiAtRVJBTkdFOworCisJbWVtY3B5KGJ1ZmZlciwgT1BBTFVJRFtPUEFMX1VTRVIx
X1VJRF0sIE9QQUxfVUlEX0xFTkdUSCk7CisKKwlidWZmZXJbN10gPSBsciArIDE7CisKKwlyZXR1
cm4gMDsKK30KKworLyoKKyAqIE4gPSBudW1iZXIgb2YgZm9ybWF0IHNwZWNpZmllcnMgKDEtOTk5
KSB0byBiZSByZXBsaWNhdGVkCisgKiBjID0gdTgKKyAqIHUgPSB1NjQKKyAqIHMgPSBieXRlc3Ry
aW5nLCBsZW5ndGgKKyAqCisgKiByZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYyIs
CisgKgkJCSAgICAgICB1OF92YWwxKTsKKyAqCisgKiByZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5f
dmEoY21kLCAiMmMydSIsCisgKgkJCSAgICAgICB1OF92YWwxLCB1OF92YWwyLCB1NjRfdmFsMSwg
dTY0X3ZhbDIpOworICoKKyAqIHJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICIzcyIs
CisgKgkJCSAgICAgICBieXRlc3RyaW5nMSwgbGVuZ3RoMSwKKyAqCQkJICAgICAgIGJ5dGVzdHJp
bmcyLCBsZW5ndGgyLAorICoJCQkgICAgICAgYnl0ZXN0cmluZzMsIGxlbmd0aDMpOworICovCitz
dGF0aWMgaW50IHRlc3RfYW5kX2FkZF90b2tlbl92YShzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwKKwkJ
CQkgY29uc3QgY2hhciAqZm10LCAuLi4pCit7CisJY29uc3QgdTggKml0ID0gZm10LCAqdG1wOwor
CWludCByZXQsIG51bSA9IDEsIHN1bSA9IDA7CisJdmFfbGlzdCBhcDsKKworCXZhX3N0YXJ0KGFw
LCBmbXQpOworCisJd2hpbGUgKCppdCAhPSAnXDAnKSB7CisJCXU2NCB0b2s2NCA9IDA7CisJCXU4
IHRvaywgKmJzdHI7CisJCXNpemVfdCBsZW47CisKKwkJcmV0ID0gMDsKKworCQlzd2l0Y2ggKCpp
dCkgeworCQljYXNlICcxJyAuLi4gJzknOgorCQkJdG1wID0gaXQ7CisJCQludW0gPSAwOworCQkJ
d2hpbGUgKCp0bXAgPj0gJzAnICYmICp0bXAgPD0gJzknKQorCQkJCW51bSA9IG51bSAqIDEwICsg
KCp0bXArKyAtICcwJyk7CisJCQlpdCA9IHRtcDsKKwkJCWNvbnRpbnVlOworCQljYXNlICdjJzoK
KwkJCXdoaWxlIChudW0tLSkgeworCQkJCXRvayA9IHZhX2FyZyhhcCwgdW5zaWduZWQgaW50KTsK
KwkJCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdTgoY21kLCB0b2spOworCQkJCWlmIChyZXQg
PCAwKQorCQkJCQlnb3RvIGVycjsKKwkJCX0KKwkJCW51bSA9IDE7CisJCQlicmVhazsKKwkJY2Fz
ZSAndSc6CisJCQl3aGlsZSAobnVtLS0pIHsKKwkJCQl0b2s2NCA9IHZhX2FyZyhhcCwgdTY0KTsK
KwkJCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdTY0KGNtZCwgdG9rNjQpOworCQkJCWlmIChy
ZXQgPCAwKQorCQkJCQlnb3RvIGVycjsKKwkJCX0KKwkJCW51bSA9IDE7CisJCQlicmVhazsKKwkJ
Y2FzZSAncyc6CisJCQl3aGlsZSAobnVtLS0pIHsKKwkJCQlic3RyID0gdmFfYXJnKGFwLCB1OCAq
KTsKKwkJCQlsZW4gPSB2YV9hcmcoYXAsIHNpemVfdCk7CisJCQkJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX2J5dGVzdHJpbmcoY21kLCBic3RyLAorCQkJCQkJCQkgICAgbGVuKTsKKwkJCQlpZiAo
cmV0IDwgMCkKKwkJCQkJZ290byBlcnI7CisJCQl9CisJCQludW0gPSAxOworCQkJYnJlYWs7CisJ
CWNhc2UgJyAnOgorCQljYXNlICdcdCc6CisJCQkvKiBpZ25vcmVkICovCisJCQlicmVhazsKKwkJ
ZGVmYXVsdDoKKwkJCXByX3dhcm4oIlVucmVjb2duaXplZCB0eXBlLlxuIik7CisJCX0KKworCQlp
dCsrOworCQlzdW0gKz0gcmV0OworCX0KKworCXZhX2VuZChhcCk7CisKKwlyZXR1cm4gc3VtOwor
CisgZXJyOgorCXByX2VycigiVG9rZW4gZmFpbGVkIHRvIGJlIGFkZGVkLlxuIik7CisJcmV0dXJu
IHJldDsKK30KKworc3RhdGljIHZvaWQgc2V0X2NvbUlEKHN0cnVjdCBvcGFsX2NtZCAqY21kLCB1
MTYgY29tSUQpCit7CisJc3RydWN0IG9wYWxfaGVhZGVyICpoZHIgPSAoc3RydWN0IG9wYWxfaGVh
ZGVyICopY21kLT5jbWQ7CisKKwloZHItPmNwLmV4dGVuZGVkQ29tSURbMF0gPSBjb21JRCA+PiA4
OworCWhkci0+Y3AuZXh0ZW5kZWRDb21JRFsxXSA9IGNvbUlEOworCWhkci0+Y3AuZXh0ZW5kZWRD
b21JRFsyXSA9IDA7CisJaGRyLT5jcC5leHRlbmRlZENvbUlEWzNdID0gMDsKK30KKworc3RhdGlj
IGludCBjbWRfZmluYWxpemUoc3RydWN0IG9wYWxfY21kICpjbWQsIHUzMiBoc24sIHUzMiB0c24p
Cit7CisJc3RydWN0IG9wYWxfaGVhZGVyICpoZHI7CisJaW50IHJldDsKKworCXJldCA9IHRlc3Rf
YW5kX2FkZF90b2tlbl92YShjbWQsICI2YyIsCisJCQkJICAgIE9QQUxfRU5ET0ZEQVRBLCBPUEFM
X1NUQVJUTElTVCwKKwkJCQkgICAgMCwgMCwgMCwgT1BBTF9FTkRMSVNUKTsKKworCWlmIChyZXQg
PCAwKSB7CisJCXByX2VycigiRXJyb3IgZmluYWxpemluZyBjb21tYW5kLlxuIik7CisJCXJldHVy
biAtRUZBVUxUOworCX0KKworCWhkciA9IChzdHJ1Y3Qgb3BhbF9oZWFkZXIgKikgY21kLT5jbWQ7
CisKKwloZHItPnBrdC5UU04gPSBjcHVfdG9fYmUzMih0c24pOworCWhkci0+cGt0LkhTTiA9IGNw
dV90b19iZTMyKGhzbik7CisKKwloZHItPnN1YnBrdC5sZW5ndGggPSBjcHVfdG9fYmUzMihjbWQt
PnBvcyAtIHNpemVvZigqaGRyKSk7CisJd2hpbGUgKGNtZC0+cG9zICUgNCkgeworCQlpZiAoY21k
LT5wb3MgPj0gSU9fQlVGRkVSX0xFTkdUSCkgeworCQkJcHJfZXJyKCJFcnJvcjogQnVmZmVyIG92
ZXJydW5cbiIpOworCQkJcmV0dXJuIC1FUkFOR0U7CisJCX0KKwkJY21kLT5jbWRbY21kLT5wb3Mr
K10gPSAwOworCX0KKwloZHItPnBrdC5sZW5ndGggPSBjcHVfdG9fYmUzMihjbWQtPnBvcyAtIHNp
emVvZihoZHItPmNwKSAtCisJCQkJICAgICAgc2l6ZW9mKGhkci0+cGt0KSk7CisJaGRyLT5jcC5s
ZW5ndGggPSBjcHVfdG9fYmUzMihjbWQtPnBvcyAtIHNpemVvZihoZHItPmNwKSk7CisKKwlyZXR1
cm4gMDsKK30KKworc3RhdGljIGVudW0gT1BBTF9SRVNQT05TRV9UT0tFTiB0b2tlbl90eXBlKGNv
bnN0IHN0cnVjdCBwYXJzZWRfcmVzcCAqcmVzcCwKKwkJCQkJICAgaW50IG4pCit7CisJY29uc3Qg
c3RydWN0IG9wYWxfcmVzcF90b2sgKnRvazsKKworCWlmIChuID49IHJlc3AtPm51bSkgeworCQlw
cl9lcnIoIlRva2VuIG51bWJlciBkb2Vzbid0IGV4aXN0OiAlZCwgcmVzcDogJWRcbiIsCisJCSAg
ICAgICBuLCByZXNwLT5udW0pOworCQlyZXR1cm4gT1BBTF9EVEFfVE9LRU5JRF9JTlZBTElEOwor
CX0KKworCXRvayA9ICZyZXNwLT50b2tzW25dOworCWlmICh0b2stPmxlbiA9PSAwKSB7CisJCXBy
X2VycigiVG9rZW4gbGVuZ3RoIG11c3QgYmUgbm9uLXplcm9cbiIpOworCQlyZXR1cm4gT1BBTF9E
VEFfVE9LRU5JRF9JTlZBTElEOworCX0KKworCXJldHVybiB0b2stPnR5cGU7Cit9CisKKy8qCisg
KiBUaGlzIGZ1bmN0aW9uIHJldHVybnMgMCBpbiBjYXNlIG9mIGludmFsaWQgdG9rZW4uIE9uZSBz
aG91bGQgY2FsbAorICogdG9rZW5fdHlwZSgpIGZpcnN0IHRvIGZpbmQgb3V0IGlmIHRoZSB0b2tl
biBpcyB2YWxpZCBvciBub3QuCisgKi8KK3N0YXRpYyBlbnVtIE9QQUxfVE9LRU4gcmVzcG9uc2Vf
Z2V0X3Rva2VuKGNvbnN0IHN0cnVjdCBwYXJzZWRfcmVzcCAqcmVzcCwKKwkJCQkJICBpbnQgbikK
K3sKKwljb25zdCBzdHJ1Y3Qgb3BhbF9yZXNwX3RvayAqdG9rOworCisJaWYgKG4gPj0gcmVzcC0+
bnVtKSB7CisJCXByX2VycigiVG9rZW4gbnVtYmVyIGRvZXNuJ3QgZXhpc3Q6ICVkLCByZXNwOiAl
ZFxuIiwKKwkJICAgICAgIG4sIHJlc3AtPm51bSk7CisJCXJldHVybiAwOworCX0KKworCXRvayA9
ICZyZXNwLT50b2tzW25dOworCWlmICh0b2stPmxlbiA9PSAwKSB7CisJCXByX2VycigiVG9rZW4g
bGVuZ3RoIG11c3QgYmUgbm9uLXplcm9cbiIpOworCQlyZXR1cm4gMDsKKwl9CisKKwlyZXR1cm4g
dG9rLT5wb3NbMF07Cit9CisKK3N0YXRpYyBzaXplX3QgcmVzcG9uc2VfcGFyc2VfdGlueShzdHJ1
Y3Qgb3BhbF9yZXNwX3RvayAqdG9rLAorCQkJCSAgY29uc3QgdTggKnBvcykKK3sKKwl0b2stPnBv
cyA9IHBvczsKKwl0b2stPmxlbiA9IDE7CisJdG9rLT53aWR0aCA9IE9QQUxfV0lEVEhfVElOWTsK
KworCWlmIChwb3NbMF0gJiBUSU5ZX0FUT01fU0lHTkVEKSB7CisJCXRvay0+dHlwZSA9IE9QQUxf
RFRBX1RPS0VOSURfU0lOVDsKKwl9IGVsc2UgeworCQl0b2stPnR5cGUgPSBPUEFMX0RUQV9UT0tF
TklEX1VJTlQ7CisJCXRvay0+c3RvcmVkLnUgPSBwb3NbMF0gJiAweDNmOworCX0KKworCXJldHVy
biB0b2stPmxlbjsKK30KKworc3RhdGljIHNpemVfdCByZXNwb25zZV9wYXJzZV9zaG9ydChzdHJ1
Y3Qgb3BhbF9yZXNwX3RvayAqdG9rLAorCQkJCSAgIGNvbnN0IHU4ICpwb3MpCit7CisJdG9rLT5w
b3MgPSBwb3M7CisJdG9rLT5sZW4gPSAocG9zWzBdICYgU0hPUlRfQVRPTV9MRU5fTUFTSykgKyAx
OworCXRvay0+d2lkdGggPSBPUEFMX1dJRFRIX1NIT1JUOworCisJaWYgKHBvc1swXSAmIFNIT1JU
X0FUT01fQllURVNUUklORykgeworCQl0b2stPnR5cGUgPSBPUEFMX0RUQV9UT0tFTklEX0JZVEVT
VFJJTkc7CisJfSBlbHNlIGlmIChwb3NbMF0gJiBTSE9SVF9BVE9NX1NJR05FRCkgeworCQl0b2st
PnR5cGUgPSBPUEFMX0RUQV9UT0tFTklEX1NJTlQ7CisJfSBlbHNlIHsKKwkJdTY0IHVfaW50ZWdl
ciA9IDA7CisJCWludCBpLCBiID0gMDsKKworCQl0b2stPnR5cGUgPSBPUEFMX0RUQV9UT0tFTklE
X1VJTlQ7CisJCWlmICh0b2stPmxlbiA+IDkpIHsKKwkJCXByX3dhcm4oInVpbnQ2NCB3aXRoIG1v
cmUgdGhhbiA4IGJ5dGVzXG4iKTsKKwkJCXJldHVybiAtRUlOVkFMOworCQl9CisJCWZvciAoaSA9
IHRvay0+bGVuIC0gMTsgaSA+IDA7IGktLSkgeworCQkJdV9pbnRlZ2VyIHw9ICgodTY0KXBvc1tp
XSA8PCAoOCAqIGIpKTsKKwkJCWIrKzsKKwkJfQorCQl0b2stPnN0b3JlZC51ID0gdV9pbnRlZ2Vy
OworCX0KKworCXJldHVybiB0b2stPmxlbjsKK30KKworc3RhdGljIHNpemVfdCByZXNwb25zZV9w
YXJzZV9tZWRpdW0oc3RydWN0IG9wYWxfcmVzcF90b2sgKnRvaywKKwkJCQkgICAgY29uc3QgdTgg
KnBvcykKK3sKKwl0b2stPnBvcyA9IHBvczsKKwl0b2stPmxlbiA9ICgoKHBvc1swXSAmIE1FRElV
TV9BVE9NX0xFTl9NQVNLKSA8PCA4KSB8IHBvc1sxXSkgKyAyOworCXRvay0+d2lkdGggPSBPUEFM
X1dJRFRIX01FRElVTTsKKworCWlmIChwb3NbMF0gJiBNRURJVU1fQVRPTV9CWVRFU1RSSU5HKQor
CQl0b2stPnR5cGUgPSBPUEFMX0RUQV9UT0tFTklEX0JZVEVTVFJJTkc7CisJZWxzZSBpZiAocG9z
WzBdICYgTUVESVVNX0FUT01fU0lHTkVEKQorCQl0b2stPnR5cGUgPSBPUEFMX0RUQV9UT0tFTklE
X1NJTlQ7CisJZWxzZQorCQl0b2stPnR5cGUgPSBPUEFMX0RUQV9UT0tFTklEX1VJTlQ7CisKKwly
ZXR1cm4gdG9rLT5sZW47Cit9CisKKyNkZWZpbmUgTE9OR19BVE9NX0lEIChCSVQoNykgfCBCSVQo
NikgfCBCSVQoNSkpCisjZGVmaW5lIExPTkdfQVRPTV9CWVRFU1RSSU5HIEJJVCgxKQorI2RlZmlu
ZSBMT05HX0FUT01fU0lHTkVEIEJJVCgwKQorc3RhdGljIHNpemVfdCByZXNwb25zZV9wYXJzZV9s
b25nKHN0cnVjdCBvcGFsX3Jlc3BfdG9rICp0b2ssCisJCQkJICBjb25zdCB1OCAqcG9zKQorewor
CXRvay0+cG9zID0gcG9zOworCXRvay0+bGVuID0gKChwb3NbMV0gPDwgMTYpIHwgKHBvc1syXSA8
PCA4KSB8IHBvc1szXSkgKyA0OworCXRvay0+d2lkdGggPSBPUEFMX1dJRFRIX0xPTkc7CisKKwlp
ZiAocG9zWzBdICYgTE9OR19BVE9NX0JZVEVTVFJJTkcpCisJCXRvay0+dHlwZSA9IE9QQUxfRFRB
X1RPS0VOSURfQllURVNUUklORzsKKwllbHNlIGlmIChwb3NbMF0gJiBMT05HX0FUT01fU0lHTkVE
KQorCQl0b2stPnR5cGUgPSBPUEFMX0RUQV9UT0tFTklEX1NJTlQ7CisJZWxzZQorCQl0b2stPnR5
cGUgPSBPUEFMX0RUQV9UT0tFTklEX1VJTlQ7CisKKwlyZXR1cm4gdG9rLT5sZW47Cit9CisKK3N0
YXRpYyBzaXplX3QgcmVzcG9uc2VfcGFyc2VfdG9rZW4oc3RydWN0IG9wYWxfcmVzcF90b2sgKnRv
aywKKwkJCQkgICBjb25zdCB1OCAqcG9zKQoreworCXRvay0+cG9zID0gcG9zOworCXRvay0+bGVu
ID0gMTsKKwl0b2stPnR5cGUgPSBPUEFMX0RUQV9UT0tFTklEX1RPS0VOOworCXRvay0+d2lkdGgg
PSBPUEFMX1dJRFRIX1RPS0VOOworCisJcmV0dXJuIHRvay0+bGVuOworfQorCitzdGF0aWMgaW50
IHJlc3BvbnNlX3BhcnNlKGNvbnN0IHU4ICpidWYsIHNpemVfdCBsZW5ndGgsCisJCQkgIHN0cnVj
dCBwYXJzZWRfcmVzcCAqcmVzcCkKK3sKKwljb25zdCBzdHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkcjsK
KwlzdHJ1Y3Qgb3BhbF9yZXNwX3RvayAqaXRlcjsKKwlpbnQgcmV0LCBudW1fZW50cmllcyA9IDA7
CisJdTMyIGNwb3MgPSAwLCB0b3RhbDsKKwlzaXplX3QgdG9rZW5fbGVuZ3RoOworCWNvbnN0IHU4
ICpwb3M7CisKKwlpZiAoIWJ1ZikKKwkJcmV0dXJuIC1FRkFVTFQ7CisKKwlpZiAoIXJlc3ApCisJ
CXJldHVybiAtRUZBVUxUOworCisJaGRyID0gKHN0cnVjdCBvcGFsX2hlYWRlciAqKWJ1ZjsKKwlw
b3MgPSBidWY7CisJcG9zICs9IHNpemVvZigqaGRyKTsKKworCXByX2RlYnVnKCJSZXNwb25zZSBz
aXplOiBjcDogJWQsIHBrdDogJWQsIHN1YnBrdDogJWRcbiIsCisJCSBiZTMyX3RvX2NwdShoZHIt
PmNwLmxlbmd0aCksCisJCSBiZTMyX3RvX2NwdShoZHItPnBrdC5sZW5ndGgpLAorCQkgYmUzMl90
b19jcHUoaGRyLT5zdWJwa3QubGVuZ3RoKSk7CisKKwlpZiAoKGhkci0+Y3AubGVuZ3RoID09IDAp
CisJICAgIHx8IChoZHItPnBrdC5sZW5ndGggPT0gMCkKKwkgICAgfHwgKGhkci0+c3VicGt0Lmxl
bmd0aCA9PSAwKSkgeworCQlwcl9lcnIoIkJhZCBoZWFkZXIgbGVuZ3RoLiBjcDogJWQsIHBrdDog
JWQsIHN1YnBrdDogJWRcbiIsCisJCSAgICAgICBiZTMyX3RvX2NwdShoZHItPmNwLmxlbmd0aCks
CisJCSAgICAgICBiZTMyX3RvX2NwdShoZHItPnBrdC5sZW5ndGgpLAorCQkgICAgICAgYmUzMl90
b19jcHUoaGRyLT5zdWJwa3QubGVuZ3RoKSk7CisJCXByaW50X2J1ZmZlcihwb3MsIHNpemVvZigq
aGRyKSk7CisJCXJldCA9IC1FSU5WQUw7CisJCWdvdG8gZXJyOworCX0KKworCWlmIChwb3MgPiBi
dWYgKyBsZW5ndGgpIHsKKwkJcmV0ID0gLUVGQVVMVDsKKwkJZ290byBlcnI7CisJfQorCisJaXRl
ciA9IHJlc3AtPnRva3M7CisJdG90YWwgPSBiZTMyX3RvX2NwdShoZHItPnN1YnBrdC5sZW5ndGgp
OworCXByaW50X2J1ZmZlcihwb3MsIHRvdGFsKTsKKwl3aGlsZSAoY3BvcyA8IHRvdGFsKSB7CisJ
CWlmICghKHBvc1swXSAmIDB4ODApKSAvKiB0aW55IGF0b20gKi8KKwkJCXRva2VuX2xlbmd0aCA9
IHJlc3BvbnNlX3BhcnNlX3RpbnkoaXRlciwgcG9zKTsKKwkJZWxzZSBpZiAoIShwb3NbMF0gJiAw
eDQwKSkgLyogc2hvcnQgYXRvbSAqLworCQkJdG9rZW5fbGVuZ3RoID0gcmVzcG9uc2VfcGFyc2Vf
c2hvcnQoaXRlciwgcG9zKTsKKwkJZWxzZSBpZiAoIShwb3NbMF0gJiAweDIwKSkgLyogbWVkaXVt
IGF0b20gKi8KKwkJCXRva2VuX2xlbmd0aCA9IHJlc3BvbnNlX3BhcnNlX21lZGl1bShpdGVyLCBw
b3MpOworCQllbHNlIGlmICghKHBvc1swXSAmIDB4MTApKSAvKiBsb25nIGF0b20gKi8KKwkJCXRv
a2VuX2xlbmd0aCA9IHJlc3BvbnNlX3BhcnNlX2xvbmcoaXRlciwgcG9zKTsKKwkJZWxzZSAvKiBU
T0tFTiAqLworCQkJdG9rZW5fbGVuZ3RoID0gcmVzcG9uc2VfcGFyc2VfdG9rZW4oaXRlciwgcG9z
KTsKKworCQlpZiAodG9rZW5fbGVuZ3RoID09IC1FSU5WQUwpIHsKKwkJCXJldCA9IC1FSU5WQUw7
CisJCQlnb3RvIGVycjsKKwkJfQorCisJCXBvcyArPSB0b2tlbl9sZW5ndGg7CisJCWNwb3MgKz0g
dG9rZW5fbGVuZ3RoOworCQlpdGVyKys7CisJCW51bV9lbnRyaWVzKys7CisJfQorCisJaWYgKG51
bV9lbnRyaWVzID09IDApIHsKKwkJcHJfZXJyKCJDb3VsZG4ndCBwYXJzZSByZXNwb25zZS5cbiIp
OworCQlyZXQgPSAtRUlOVkFMOworCQlnb3RvIGVycjsKKwl9CisJcmVzcC0+bnVtID0gbnVtX2Vu
dHJpZXM7CisKKwlyZXR1cm4gMDsKK2VycjoKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgc2l6
ZV90IHJlc3BvbnNlX2dldF9zdHJpbmcoY29uc3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNwLCBp
bnQgbiwKKwkJCQkgIGNvbnN0IGNoYXIgKipzdG9yZSkKK3sKKwkqc3RvcmUgPSBOVUxMOworCWlm
ICghcmVzcCkgeworCQlwcl9lcnIoIlJlc3BvbnNlIGlzIE5VTExcbiIpOworCQlyZXR1cm4gMDsK
Kwl9CisKKwlpZiAobiA+IHJlc3AtPm51bSkgeworCQlwcl9lcnIoIlJlc3BvbnNlIGhhcyAlZCB0
b2tlbnMuIENhbid0IGFjY2VzcyAlZFxuIiwKKwkJICAgICAgIHJlc3AtPm51bSwgbik7CisJCXJl
dHVybiAwOworCX0KKworCWlmIChyZXNwLT50b2tzW25dLnR5cGUgIT0gT1BBTF9EVEFfVE9LRU5J
RF9CWVRFU1RSSU5HKSB7CisJCXByX2VycigiVG9rZW4gaXMgbm90IGEgYnl0ZSBzdHJpbmchXG4i
KTsKKwkJcmV0dXJuIDA7CisJfQorCisJKnN0b3JlID0gcmVzcC0+dG9rc1tuXS5wb3MgKyAxOwor
CXJldHVybiByZXNwLT50b2tzW25dLmxlbiAtIDE7Cit9CisKK3N0YXRpYyB1NjQgcmVzcG9uc2Vf
Z2V0X3U2NChjb25zdCBzdHJ1Y3QgcGFyc2VkX3Jlc3AgKnJlc3AsIGludCBuKQoreworCWlmICgh
cmVzcCkgeworCQlwcl9lcnIoIlJlc3BvbnNlIGlzIE5VTExcbiIpOworCQlyZXR1cm4gMDsKKwl9
CisKKwlpZiAobiA+IHJlc3AtPm51bSkgeworCQlwcl9lcnIoIlJlc3BvbnNlIGhhcyAlZCB0b2tl
bnMuIENhbid0IGFjY2VzcyAlZFxuIiwKKwkJICAgICAgIHJlc3AtPm51bSwgbik7CisJCXJldHVy
biAwOworCX0KKworCWlmIChyZXNwLT50b2tzW25dLnR5cGUgIT0gT1BBTF9EVEFfVE9LRU5JRF9V
SU5UKSB7CisJCXByX2VycigiVG9rZW4gaXMgbm90IHVuc2lnbmVkIGl0OiAlZFxuIiwKKwkJICAg
ICAgIHJlc3AtPnRva3Nbbl0udHlwZSk7CisJCXJldHVybiAwOworCX0KKworCWlmICghKChyZXNw
LT50b2tzW25dLndpZHRoID09IE9QQUxfV0lEVEhfVElOWSkgfHwKKwkgICAgICAocmVzcC0+dG9r
c1tuXS53aWR0aCA9PSBPUEFMX1dJRFRIX1NIT1JUKSkpIHsKKwkJcHJfZXJyKCJBdG9tIGlzIG5v
dCBzaG9ydCBvciB0aW55OiAlZFxuIiwKKwkJICAgICAgIHJlc3AtPnRva3Nbbl0ud2lkdGgpOwor
CQlyZXR1cm4gMDsKKwl9CisKKwlyZXR1cm4gcmVzcC0+dG9rc1tuXS5zdG9yZWQudTsKK30KKwor
c3RhdGljIHU4IHJlc3BvbnNlX3N0YXR1cyhjb25zdCBzdHJ1Y3QgcGFyc2VkX3Jlc3AgKnJlc3Ap
Cit7CisJaWYgKCh0b2tlbl90eXBlKHJlc3AsIDApID09IE9QQUxfRFRBX1RPS0VOSURfVE9LRU4p
CisJICAgICYmIChyZXNwb25zZV9nZXRfdG9rZW4ocmVzcCwgMCkgPT0gT1BBTF9FTkRPRlNFU1NJ
T04pKSB7CisJCXJldHVybiAwOworCX0KKworCWlmIChyZXNwLT5udW0gPCA1KQorCQlyZXR1cm4g
RFRBRVJST1JfTk9fTUVUSE9EX1NUQVRVUzsKKworCWlmICgodG9rZW5fdHlwZShyZXNwLCByZXNw
LT5udW0gLSAxKSAhPSBPUEFMX0RUQV9UT0tFTklEX1RPS0VOKSB8fAorCSAgICAodG9rZW5fdHlw
ZShyZXNwLCByZXNwLT5udW0gLSA1KSAhPSBPUEFMX0RUQV9UT0tFTklEX1RPS0VOKSB8fAorCSAg
ICAocmVzcG9uc2VfZ2V0X3Rva2VuKHJlc3AsIHJlc3AtPm51bSAtIDEpICE9IE9QQUxfRU5ETElT
VCkgfHwKKwkgICAgKHJlc3BvbnNlX2dldF90b2tlbihyZXNwLCByZXNwLT5udW0gLSA1KSAhPSBP
UEFMX1NUQVJUTElTVCkpCisJCXJldHVybiBEVEFFUlJPUl9OT19NRVRIT0RfU1RBVFVTOworCisJ
cmV0dXJuIHJlc3BvbnNlX2dldF91NjQocmVzcCwgcmVzcC0+bnVtIC0gNCk7Cit9CisKKy8qIFBh
cnNlcyBhbmQgY2hlY2tzIGZvciBlcnJvcnMgKi8KK3N0YXRpYyBpbnQgcGFyc2VfYW5kX2NoZWNr
X3N0YXR1cyhzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsK
KwlpbnQgZXJyb3I7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJcHJpbnRfYnVmZmVyKGNtZC0+Y21k
LCBjbWQtPnBvcyk7CisKKwllcnJvciA9IHJlc3BvbnNlX3BhcnNlKGNtZC0+cmVzcCwgSU9fQlVG
RkVSX0xFTkdUSCwgJmRldi0+cGFyc2VkKTsKKwlpZiAoZXJyb3IpIHsKKwkJcHJfZXJyKCIlczog
Q291bGRuJ3QgcGFyc2UgcmVzcG9uc2UuXG4iLCBkZXYtPmRpc2tfbmFtZSk7CisJCWdvdG8gZXJy
X3JldHVybjsKKwl9CisKKwllcnJvciA9IHJlc3BvbnNlX3N0YXR1cygmZGV2LT5wYXJzZWQpOwor
CWlmIChlcnJvcikKKwkJcHJfZXJyKCIlczogUmVzcG9uc2UgU3RhdHVzOiAlZFxuIiwgZGV2LT5k
aXNrX25hbWUsCisJCSAgICAgICBlcnJvcik7CisKKyBlcnJfcmV0dXJuOgorCXJldHVybiBlcnJv
cjsKK30KKworc3RhdGljIHZvaWQgY2xlYXJfb3BhbF9jbWQoc3RydWN0IG9wYWxfY21kICpjbWQp
Cit7CisJY21kLT5wb3MgPSBzaXplb2Yoc3RydWN0IG9wYWxfaGVhZGVyKTsKKwltZW1zZXQoY21k
LT5jbWQsIDAsIElPX0JVRkZFUl9MRU5HVEgpOworCWNtZC0+Y2IgPSBOVUxMOworCWNtZC0+Y2Jf
ZGF0YSA9IE5VTEw7Cit9CisKK3N0YXRpYyB2b2lkIHN0YXJ0X29wYWxfc2Vzc2lvbl9jb250KGlu
dCBlcnJvciwgdm9pZCAqZGF0YSkKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisJ
dTMyIEhTTiwgVFNOOworCisJaWYgKGVycm9yKQorCQlnb3RvIGVycl9yZXR1cm47CisKKwllcnJv
ciA9IHBhcnNlX2FuZF9jaGVja19zdGF0dXMoZGV2KTsKKwlpZiAoZXJyb3IpCisJCWdvdG8gZXJy
X3JldHVybjsKKworCUhTTiA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFyc2VkLCA0KTsKKwlU
U04gPSByZXNwb25zZV9nZXRfdTY0KCZkZXYtPnBhcnNlZCwgNSk7CisKKwlpZiAoSFNOID09IDAg
JiYgVFNOID09IDApIHsKKwkJcHJfZXJyKCIlczogQ291bGRuJ3QgYXV0aGVudGljYXRlIHNlc3Np
b25cbiIsIGRldi0+ZGlza19uYW1lKTsKKwkJZXJyb3IgPSAtRVBFUk07CisJCWdvdG8gZXJyX3Jl
dHVybjsKKwl9CisKKwlkZXYtPkhTTiA9IEhTTjsKKwlkZXYtPlRTTiA9IFRTTjsKKworZXJyX3Jl
dHVybjoKKwlpZiAoZGV2LT5vcGVyX2NiKQorCQlkZXYtPm9wZXJfY2IoZXJyb3IsIGRldik7Cit9
CisKK3N0YXRpYyBpbnQgZ2V0X29wYWxfa2V5KHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXN0
cnVjdCBrZXkgKnVrZXkgPSBOVUxMOworCWNvbnN0IHU4ICp0bXBrZXkgPSBOVUxMOworCXNpemVf
dCB0bXBsZW47CisJaW50IHJldCA9IDA7CisKKwlpZiAoZGV2LT5rZXlfdHlwZSA9PSBPUEFMX0tF
WV9QTEFJTikgeworCQl0bXBrZXkgPSBkZXYtPmtleV9uYW1lOworCQl0bXBsZW4gPSBkZXYtPmtl
eV9uYW1lX2xlbjsKKwl9IGVsc2UgaWYgKGRldi0+a2V5X3R5cGUgPT0gT1BBTF9LRVlfS0VZUklO
RykgeworCQl1a2V5ID0gcmVxdWVzdF91c2VyX2tleShkZXYtPmtleV9uYW1lLCAmdG1wa2V5LCAm
dG1wbGVuKTsKKwkJaWYgKElTX0VSUih1a2V5KSkgeworCQkJcHJfZXJyKCIlczogQ2FuJ3QgcmV0
cmlldmUga2V5OiAlbGRcbiIsIGRldi0+ZGlza19uYW1lLAorCQkJICAgICAgIFBUUl9FUlIodWtl
eSkpOworCQkJcmV0dXJuIFBUUl9FUlIodWtleSk7CisJCX0KKwl9IGVsc2UgeworCQlwcl9lcnIo
IlJlcXVlc3RlZCBpbnZhbGlkIGtleSB0eXBlOiAlZFxuIiwgZGV2LT5rZXlfdHlwZSk7CisJCXJl
dHVybiAtRUlOVkFMOworCX0KKworCWlmICh0bXBsZW4gPiBPUEFMX0tFWV9NQVgpIHsKKwkJcHJf
ZXJyKCJSZXF1ZXN0ZWQga2V5IHdpdGggaW52YWxpZCBzaXplOiAlemRcbiIsIHRtcGxlbik7CisJ
CXJldCA9IC1FSU5WQUw7CisJCWdvdG8gZXJyX2V4aXQ7CisJfQorCisJZGV2LT5rZXlfbGVuID0g
dG1wbGVuOworCWlmICghbWVtY3B5KGRldi0+a2V5LCB0bXBrZXksIHRtcGxlbikpIHsKKwkJcHJf
ZXJyKCJFcnJvciB3aGVuIGNvcHlpbmcga2V5Iik7CisJCXJldCA9IC1FRkFVTFQ7CisJCWdvdG8g
ZXJyX2V4aXQ7CisJfQorCitlcnJfZXhpdDoKKwlrZXlfcHV0KHVrZXkpOworCisJcmV0dXJuIDA7
Cit9CisKK3N0YXRpYyB2b2lkIGNsZWFuX29wYWxfa2V5KHN0cnVjdCBvcGFsX2RldiAqZGV2KQor
eworCW1lbXNldChkZXYtPmtleSwgMCwgT1BBTF9LRVlfTUFYKTsKKwlkZXYtPmtleV9sZW4gPSAw
OworfQorCitzdGF0aWMgaW5saW5lIHZvaWQgY2xlYW5fZnVuY3Rpb25fZGF0YShzdHJ1Y3Qgb3Bh
bF9kZXYgKmRldikKK3sKKwkJZGV2LT5mdW5jX2RhdGEgPSBOVUxMOworCQlkZXYtPm51bV9mdW5j
X2RhdGEgPSAwOworfQorCisvKiBUaGlzIGlzIGEgZ2VuZXJpYyBjb250aW51ZSBmbi4KKyAqIFdl
IHVzZSB0aGlzIHdoZW4gd2UgZG9uJ3QgY2FyZSBhYm91dCB0aGUgcmVzcG9uc2UgZGF0YQorICog
YW5kIHNpbXBseSB3YW50IHRvIGNoZWNrIHRoZSBzdGF0dXMgYW5kIGNvbnRpbnVlLgorICovCitz
dGF0aWMgdm9pZCBnZW5lcmljX2NvbnQoaW50IGVycm9yLCB2b2lkICpkYXRhKQoreworCXN0cnVj
dCBvcGFsX2RldiAqZGV2ID0gZGF0YTsKKworCWlmIChlcnJvcikKKwkJZ290byBlcnJfcmV0dXJu
OworCisJZXJyb3IgPSBwYXJzZV9hbmRfY2hlY2tfc3RhdHVzKGRldik7CisKKyBlcnJfcmV0dXJu
OgorCWlmIChkZXYtPm9wZXJfY2IpCisJCWRldi0+b3Blcl9jYihlcnJvciwgZGV2KTsKK30KKwor
c3RhdGljIHZvaWQgZW5kX3Nlc3Npb25fY29udChpbnQgZXJyb3IsIHZvaWQgKmRhdGEpCit7CisJ
c3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOworCisJZGV2LT5IU04gPSAwOworCWRldi0+VFNO
ID0gMDsKKwlnZW5lcmljX2NvbnQoZXJyb3IsIGRhdGEpOworfQorCitzdGF0aWMgaW50IGZpbmFs
aXplX2FuZF9zZW5kKHN0cnVjdCBvcGFsX2RldiAqZGV2LCBzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwK
KwkJCSAgICAgc2VjX2NiIGNvbnQpCit7CisJaW50IHJldDsKKworCXJldCA9IGNtZF9maW5hbGl6
ZShjbWQsIGRldi0+SFNOLCBkZXYtPlRTTik7CisJaWYgKHJldCkgeworCQlwcl9lcnIoIiVzOiBF
cnJvciBmaW5hbGl6aW5nIGNvbW1hbmQgYnVmZmVyOiAlZFxuIiwKKwkJICAgICAgIGRldi0+ZGlz
a19uYW1lLCByZXQpOworCQlyZXR1cm4gcmV0OworCX0KKworCXByaW50X2J1ZmZlcihjbWQtPmNt
ZCwgY21kLT5wb3MpOworCisJb3BhbF9zZW5kX3JlY3YoZGV2LCBjb250LCBkZXYpOworCXJldHVy
biByZXQ7Cit9CisKK3N0YXRpYyBpbnQgd2FpdF9mb3JfY21kX2NvbXBsZXRpb24oc3RydWN0IG9w
YWxfY29tcGxldGlvbiAqY29tcGxldGlvbikKK3sKKwl3YWl0X2Zvcl9jb21wbGV0aW9uX2ludGVy
cnVwdGlibGUoJmNvbXBsZXRpb24tPmNtZF9jb21wbGV0aW9uKTsKKwlyZXR1cm4gY29tcGxldGlv
bi0+Y29tcGxldGlvbl9zdGF0dXM7Cit9CisKK3N0YXRpYyBpbnQgZ2VuX2tleShzdHJ1Y3Qgb3Bh
bF9kZXYgKmRldikKK3sKKwljb25zdCB1OCAqbWV0aG9kOworCXU4IHVpZFtPUEFMX1VJRF9MRU5H
VEhdOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisKKwljbWQgPSAmZGV2LT5j
bWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsK
KworCW1lbWNweSh1aWQsIGRldi0+cHJldl9kYXRhLCBtaW4oc2l6ZW9mKHVpZCksIGRldi0+cHJl
dl9kX2xlbikpOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9HRU5LRVldOworCWtmcmVlKGRl
di0+cHJldl9kYXRhKTsKKwlkZXYtPnByZXZfZGF0YSA9IE5VTEw7CisKKwlyZXQgPSB0ZXN0X2Fu
ZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAg
ICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5H
VEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfRU5ETElTVCk7CisJ
aWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgZ2VuIGtleSBjb21t
YW5kXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKwor
CXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKwor
c3RhdGljIHZvaWQgZ2V0X2FjdGl2ZV9rZXlfY29udChpbnQgZXJyb3IsIHZvaWQgKmRhdGEpCit7
CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOworCWNvbnN0IGNoYXIgKmFjdGl2ZWtleTsK
KwlzaXplX3Qga2V5bGVuOworCisJaWYgKGVycm9yKQorCQlnb3RvIGVycl9yZXR1cm47CisKKwll
cnJvciA9IHBhcnNlX2FuZF9jaGVja19zdGF0dXMoZGV2KTsKKwlpZiAoZXJyb3IpCisJCWdvdG8g
ZXJyX3JldHVybjsKKwlrZXlsZW4gPSByZXNwb25zZV9nZXRfc3RyaW5nKCZkZXYtPnBhcnNlZCwg
NCwgJmFjdGl2ZWtleSk7CisJaWYgKCFhY3RpdmVrZXkpIHsKKwkJcHJfZXJyKCIlczogQ291bGRu
J3QgZXh0cmFjdCB0aGUgQWN0aXZla2V5IGZyb20gdGhlIHJlc3BvbnNlXG4iLAorCQkgICAgICAg
X19mdW5jX18pOworCQllcnJvciA9IDB4MEE7CisJCWdvdG8gZXJyX3JldHVybjsKKwl9CisJZGV2
LT5wcmV2X2RhdGEgPSBrbWVtZHVwKGFjdGl2ZWtleSwga2V5bGVuLCBHRlBfS0VSTkVMKTsKKwor
CWlmICghZGV2LT5wcmV2X2RhdGEpCisJCWVycm9yID0gLUVOT01FTTsKKworCWRldi0+cHJldl9k
X2xlbiA9IGtleWxlbjsKKworZXJyX3JldHVybjoKKwlpZiAoZGV2LT5vcGVyX2NiKQorCQlkZXYt
Pm9wZXJfY2IoZXJyb3IsIGRldik7Cit9CisKK3N0YXRpYyBpbnQgZ2V0X2FjdGl2ZV9rZXkoc3Ry
dWN0IG9wYWxfZGV2ICpkZXYpCit7CisJY29uc3QgdTggKm1ldGhvZDsKKwl1OCB1aWRbT1BBTF9V
SURfTEVOR1RIXTsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlpbnQgcmV0OworCisJY21kID0g
JmRldi0+Y21kOworCWNsZWFyX29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5j
b21JRCk7CisKKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfR0VUXTsKKworCXJldCA9IGJ1aWxk
X2xvY2tpbmdfcmFuZ2UodWlkLCBzaXplb2YodWlkKSwgZGV2LT5scik7CisJaWYgKHJldCA8IDAp
IHsKKwkJcHJfZXJyKCIlczogQ2FuJ3QgYnVpbGQgbG9ja2luZyByYW5nZVxuIiwgZGV2LT5kaXNr
X25hbWUpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9r
ZW5fdmEoY21kLCAiYzJzIDZjIDRjIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICB1
aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgs
CisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJ
CSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIHN0YXJ0
Q2xvdW1uICovCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzEwLCAvKiBBY3RpdmVLZXkgKi8KKwkJ
CQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBP
UEFMX1RJTllfVUlOVF8wNCwgLyogZW5kQ29sdW1uICovCisJCQkJICAgIE9QQUxfVElOWV9VSU5U
XzEwLCAvKiBBY3RpdmVLZXkgKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9Q
QUxfRU5ETElTVCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKwlpZiAocmV0IDwgMCkgeworCQlw
cl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBnZXQgYWN0aXZlIGtleSBjb21tYW5kXG4iLAorCQkg
ICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5h
bGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2V0X2FjdGl2ZV9rZXlfY29udCk7Cit9CisKK3N0YXRp
YyBpbmxpbmUgaW50IGVuYWJsZV9nbG9iYWxfbHIoc3RydWN0IG9wYWxfY21kICpjbWQsIHU4ICp1
aWQsCisJCQkJICAgc3RydWN0IG9wYWxfdXNlcl9scl9zZXR1cCAqc2V0dXApCit7CisJY29uc3Qg
dTggKm1ldGhvZDsKKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU0VUXTsKKwlyZXR1cm4gdGVz
dF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyA0YyAyY3VjIDJjdSA0YyIsCisJCQkJICAgICBP
UEFMX0NBTEwsCisJCQkJICAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgIG1ldGhv
ZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkg
ICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICAgT1BBTF9WQUxVRVMsCisJCQkJICAgICBPUEFM
X1NUQVJUTElTVCwKKworCQkJCSAgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgICBPUEFMX1RJ
TllfVUlOVF8wNSwgLyogUmVhZExvY2tFbmFibGVkICovCisJCQkJICAgICAhIXNldHVwLT5STEUs
CisJCQkJICAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgIE9QQUxfU1RBUlROQU1FLAorCQkJ
CSAgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIFdyaXRlTG9ja0VuYWJsZWQgKi8KKwkJCQkgICAg
ICEhc2V0dXAtPldMRSwKKworCQkJCSAgICAgT1BBTF9FTkROQU1FLAorCQkJCSAgICAgT1BBTF9F
TkRMSVNULAorCQkJCSAgICAgT1BBTF9FTkROQU1FLAorCQkJCSAgICAgT1BBTF9FTkRMSVNUKTsK
K30KKworc3RhdGljIGludCBzZXR1cF9sb2NraW5nX3JhbmdlKHN0cnVjdCBvcGFsX2RldiAqZGV2
KQoreworCWNvbnN0IHU4ICptZXRob2Q7CisJdTggdWlkW09QQUxfVUlEX0xFTkdUSF07CisJc3Ry
dWN0IG9wYWxfY21kICpjbWQ7CisJc3RydWN0IG9wYWxfdXNlcl9scl9zZXR1cCAqc2V0dXA7CisJ
aW50IHJldDsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNl
dF9jb21JRChjbWQsIGRldi0+Y29tSUQpOworCisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NF
VF07CisJcmV0ID0gYnVpbGRfbG9ja2luZ19yYW5nZSh1aWQsIHNpemVvZih1aWQpLCBkZXYtPmxy
KTsKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBDYW4ndCBidWlsZCBsb2NraW5nIHJh
bmdlXG4iLCBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKwlzZXR1cCA9
IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKwlpZiAoZGV2LT5sciA9PSAwKQorCQly
ZXQgPSBlbmFibGVfZ2xvYmFsX2xyKGNtZCwgdWlkLCBzZXR1cCk7CisJZWxzZQorCQlyZXQgPSB0
ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzICA0YyAyY3VjIDJjdWMgMmN1YyAyY3UgNGMi
LAorCQkJCSAgICBPUEFMX0NBTEwsCisJCQkJICAgIHVpZCwgT1BBTF9VSURfTEVOR1RILAorCQkJ
CSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKworCQkJCSAgICBPUEFMX1NUQVJUTElT
VCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVkFMVUVTLAorCQkJCSAg
ICBPUEFMX1NUQVJUTElTVCwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BB
TF9USU5ZX1VJTlRfMDMsIC8qIFJhbmdlIFN0YXJ0ICovCisJCQkJICAgIHNldHVwLT5yYW5nZV9z
dGFydCwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAor
CQkJCSAgICBPUEFMX1RJTllfVUlOVF8wNCwgLyogUmFuZ2UgTGVuZ3RoICovCisJCQkJICAgIHNl
dHVwLT5yYW5nZV9sZW5ndGgsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKworCQkJCSAgICBPUEFM
X1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDUsIC8qIFJlYWRMb2NrRW5hYmxl
ZCAqLworCQkJCSAgICAhIXNldHVwLT5STEUsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKworCQkJ
CSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIFdyaXRl
TG9ja0VuYWJsZWQgKi8KKwkJCQkgICAgISFzZXR1cC0+V0xFLAorCisJCQkJICAgIE9QQUxfRU5E
TkFNRSwKKwkJCQkgICAgT1BBTF9FTkRMSVNULAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJ
ICAgIE9QQUxfRU5ETElTVCk7CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3Ig
YnVpbGRpbmcgU2V0dXAgTG9ja2luZyByYW5nZSBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+
ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRf
c2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBzdGFydF9hZG1p
bnNwX29wYWxfc2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldiwKKwkJCQkgICAgICBlbnVtIE9Q
QUxfVUlEIGF1dGgsCisJCQkJICAgICAgY29uc3QgY2hhciAqa2V5LAorCQkJCSAgICAgIHU4IGtl
eV9sZW4pCit7CisJY29uc3QgdTggKm1ldGhvZCwgKnNtdWlkLCAqYWRtaW5fc3AsICpoc2E7CisJ
c3RydWN0IG9wYWxfY21kICpjbWQ7CisJdTMyIEhTTjsKKwlpbnQgcmV0OworCisJaWYgKGtleSA9
PSBOVUxMICYmIGF1dGggIT0gT1BBTF9BTllCT0RZX1VJRCkgeworCQlwcl9lcnIoIiVzOiBBdHRl
bXB0ZWQgdG8gb3BlbiBBRE1JTl9TUCBTZXNzaW9uIHdpdGhvdXQgYSBIb3N0IiBcCisJCSAgICAg
ICAiQ2hhbGxlbmdlLCBhbmQgbm90IGFzIHRoZSBBbnlib2R5IFVJRFxuIiwgX19mdW5jX18pOwor
CQlyZXR1cm4gMTsKKwl9CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21k
KTsKKworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOworCUhTTiA9IEdFTkVSSUNfSE9TVF9T
RVNTSU9OX05VTTsKKworCXNtdWlkID0gT1BBTFVJRFtPUEFMX1NNVUlEX1VJRF07CisJbWV0aG9k
ID0gT1BBTE1FVEhPRFtPUEFMX1NUQVJUU0VTU0lPTl07CisJYWRtaW5fc3AgPSBPUEFMVUlEW09Q
QUxfQURNSU5TUF9VSURdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMy
cyBjdXNjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICBzbXVpZCwgT1BBTF9VSURfTEVO
R1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKwkJCQkgICAgT1BBTF9T
VEFSVExJU1QsCisJCQkJICAgIEhTTiwKKwkJCQkgICAgYWRtaW5fc3AsIE9QQUxfVUlEX0xFTkdU
SCwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDEpOworCWlmIChyZXQgPCAwKSB7CisJCXByX2Vy
cigiJXM6IEVycm9yIGJ1aWxkaW5nIHN0YXJ0IGFkbWluc3Agc2Vzc2lvbiBjb21tYW5kLlxuIiwK
KwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlzd2l0Y2gg
KGF1dGgpIHsKKwljYXNlIE9QQUxfQU5ZQk9EWV9VSUQ6CisJCS8qIG5vdGhpbmcgbGVmdCB0byBk
byBmb3IgYW55Ym9keSwganVzdCBlbmQgYW5kIGZpbmFsaXplICovCisJCXJldCA9IHRlc3RfYW5k
X2FkZF90b2tlbl92YShjbWQsICJjIiwKKwkJCQkJICAgIE9QQUxfRU5ETElTVCk7CisJCWJyZWFr
OworCWNhc2UgT1BBTF9TSURfVUlEOgorCQloc2EgPSBPUEFMVUlEW09QQUxfU0lEX1VJRF07CisJ
CXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICIyYyBzIDNjIHMgMmMiLAorCQkJCQkg
ICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMCwgLyogSG9zdENo
YWxsZW5nZSAqLworCQkJCQkgICAga2V5LCBrZXlfbGVuLAorCQkJCQkgICAgT1BBTF9FTkROQU1F
LAorCQkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywg
LyogSG9zdFNpZ25BdXRoICovCisJCQkJCSAgICBoc2EsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkJ
ICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkJICAgIE9QQUxfRU5ETElTVCk7CisJCWJyZWFrOworCWRl
ZmF1bHQ6CisJCXByX2VycigiQ2Fubm90IHN0YXJ0IEFkbWluIFNQIHNlc3Npb24gd2l0aCBhdXRo
ICVkXG4iLCBhdXRoKTsKKwkJcmV0dXJuIDE7CisJfQorCisJaWYgKHJldCA8IDApIHsKKwkJcHJf
ZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgc3RhcnQgYWRtaW5zcCBzZXNzaW9uIGNvbW1hbmQuXG4i
LAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVy
biBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgc3RhcnRfb3BhbF9zZXNzaW9uX2NvbnQpOwor
fQorCitzdGF0aWMgaW50IHN0YXJ0X2FueWJvZHlBU1Bfb3BhbF9zZXNzaW9uKHN0cnVjdCBvcGFs
X2RldiAqZGV2KQoreworCXJldHVybiBzdGFydF9hZG1pbnNwX29wYWxfc2Vzc2lvbihkZXYsIE9Q
QUxfQU5ZQk9EWV9VSUQsIE5VTEwsIDApOworfQorCitzdGF0aWMgaW50IHN0YXJ0X1NJREFTUF9v
cGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJaW50IHJldDsKKwljb25zdCB1
OCAqa2V5ID0gZGV2LT5wcmV2X2RhdGE7CisKKwlpZiAoIWtleSkKKwkJcmV0ID0gc3RhcnRfYWRt
aW5zcF9vcGFsX3Nlc3Npb24oZGV2LCBPUEFMX1NJRF9VSUQsIGRldi0+a2V5LAorCQkJCQkJIGRl
di0+a2V5X2xlbik7CisJZWxzZSB7CisJCXJldCA9IHN0YXJ0X2FkbWluc3Bfb3BhbF9zZXNzaW9u
KGRldiwgT1BBTF9TSURfVUlELCBrZXksCisJCQkJCQkgZGV2LT5wcmV2X2RfbGVuKTsKKwkJa2Zy
ZWUoa2V5KTsKKwkJZGV2LT5wcmV2X2RhdGEgPSBOVUxMOworCX0KKwlyZXR1cm4gcmV0OworfQor
CitzdGF0aWMgaW50IHN0YXJ0X2xvY2tpbmdzcF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2
ICpkZXYsCisJCQkJCWVudW0gT1BBTF9VSUQgYXV0aCwgY29uc3QgdTggKmtleSwKKwkJCQkJdTgg
a2V5X2xlbikKK3sKKworCWNvbnN0IHU4ICptZXRob2QsICpzbXVpZCwgKmxvY2tpbmdfc3AsICpo
c2E7CisJc3RydWN0IG9wYWxfY21kICpjbWQ7CisJc2l6ZV90IGtsZW4gPSBrZXlfbGVuOworCXUz
MiBIU047CisJaW50IHJldDsKKworCWlmIChrZXkgPT0gTlVMTCkgeworCQlwcl9lcnIoIkNhbm5v
dCBzdGFydCBMb2NraW5nIFNQIHNlc3Npb24gd2l0aG91dCBhIGtleVxuIik7CisJCXJldHVybiAt
RUlOVkFMOworCX0KKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOwor
CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisJSFNOID0gR0VORVJJQ19IT1NUX1NFU1NJ
T05fTlVNOworCisJc211aWQgPSBPUEFMVUlEW09QQUxfU01VSURfVUlEXTsKKwltZXRob2QgPSBP
UEFMTUVUSE9EW09QQUxfU1RBUlRTRVNTSU9OXTsKKwlsb2NraW5nX3NwID0gT1BBTFVJRFtPUEFM
X0xPQ0tJTkdTUF9VSURdOworCWhzYSA9IE9QQUxVSURbYXV0aF07CisKKwlyZXQgPSB0ZXN0X2Fu
ZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIGN1c2MgMmNzYyAyY3NjIGMiLAorCQkJCSAgICBPUEFM
X0NBTEwsCisJCQkJICAgIHNtdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1ldGhvZCwg
T1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBI
U04sCisJCQkJICAgIGxvY2tpbmdfc3AsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgT1BBTF9U
SU5ZX1VJTlRfMDEsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElO
WV9VSU5UXzAwLCAvKiBIb3N0Q2hhbGxlbmdlICovCisJCQkJICAgIGtleSwga2xlbiwKKwkJCQkg
ICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFM
X1RJTllfVUlOVF8wMywgLyogSG9zdCBTaWduIEF1dGhvcml0eSAqLworCQkJCSAgICBoc2EsIE9Q
QUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfRU5E
TElTVCk7CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBz
dGFydCBhZG1pbnNwIHNlc3Npb24gY29tbWFuZC5cbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFt
ZSk7CisJCXJldHVybiByZXQ7CisJfQorCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNt
ZCwgc3RhcnRfb3BhbF9zZXNzaW9uX2NvbnQpOworfQorCitzdGF0aWMgaW5saW5lIGludCBzdGFy
dF9hZG1pbjFMU1Bfb3BhbF9zZXNzaW9uKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXJldHVy
biBzdGFydF9sb2NraW5nc3Bfb3BhbF9zZXNzaW9uKGRldiwgT1BBTF9BRE1JTjFfVUlELAorCQkJ
CQkgICAgZGV2LT5rZXksIGRldi0+a2V5X2xlbik7Cit9CisKK3N0YXRpYyBpbnQgc3RhcnRfYXV0
aF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJY29uc3QgdTggKm1ldGhv
ZCwgKnNtdWlkLCAqbG9ja2luZ19zcDsKKwl1OCBsa191bF91c2VyW09QQUxfVUlEX0xFTkdUSF07
CisJc3RydWN0IG9wYWxfY21kICpjbWQ7CisJdTMyIEhTTjsKKwlpbnQgcmV0OworCXN0cnVjdCBv
cGFsX3VzZXJfaW5mbyAqdWluZm87CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9j
bWQoY21kKTsKKworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOworCisJSFNOID0gR0VORVJJ
Q19IT1NUX1NFU1NJT05fTlVNOworCisJdWluZm8gPSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0YXRl
IC0gMV07CisKKwlzbXVpZCA9IE9QQUxVSURbT1BBTF9TTVVJRF9VSURdOworCW1ldGhvZCA9IE9Q
QUxNRVRIT0RbT1BBTF9TVEFSVFNFU1NJT05dOworCWxvY2tpbmdfc3AgPSBPUEFMVUlEW09QQUxf
TE9DS0lOR1NQX1VJRF07CisKKwlpZiAodWluZm8tPlNVTSkgeworCQlyZXQgPSBidWlsZF9sb2Nr
aW5nX3VzZXIobGtfdWxfdXNlciwgc2l6ZW9mKGxrX3VsX3VzZXIpLAorCQkJCQkgZGV2LT5scik7
CisJCWlmIChyZXQgPCAwKSB7CisJCQlwcl9lcnIoIiVzOiBDYW4ndCBidWlsZCBsb2NraW5nIHVz
ZXJcbiIsCisJCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQkJcmV0dXJuIHJldDsKKwkJfQor
CX0gZWxzZSBpZiAodWluZm8tPndobyAhPSBPUEFMX0FETUlOMSAmJiAhdWluZm8tPlNVTSkgewor
CQlyZXQgPSBidWlsZF9sb2NraW5nX3VzZXIobGtfdWxfdXNlciwgc2l6ZW9mKGxrX3VsX3VzZXIp
LAorCQkJCQkgdWluZm8tPndobyAtIDEpOworCQlpZiAocmV0IDwgMCkgeworCQkJcHJfZXJyKCIl
czogQ2FuJ3QgYnVpbGQgbG9ja2luZyB1c2VyXG4iLAorCQkJICAgICAgIGRldi0+ZGlza19uYW1l
KTsKKwkJCXJldHVybiByZXQ7CisJCX0KKwl9IGVsc2UKKwkJbWVtY3B5KGxrX3VsX3VzZXIsIE9Q
QUxVSURbT1BBTF9BRE1JTjFfVUlEXSwgT1BBTF9VSURfTEVOR1RIKTsKKworCisJcmV0ID0gdGVz
dF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyBjdXMzY3MzYyBzIDJjIiwKKwkJCQkgICAgT1BB
TF9DQUxMLAorCQkJCSAgICBzbXVpZCwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICBtZXRob2Qs
IE9QQUxfTUVUSE9EX0xFTkdUSCwKKworCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkgICAg
SFNOLAorCQkJCSAgICBsb2NraW5nX3NwLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIE9QQUxf
VElOWV9VSU5UXzAxLAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5Z
X1VJTlRfMDAsCisJCQkJICAgIGRldi0+a2V5LCBkZXYtPmtleV9sZW4sCisJCQkJICAgIE9QQUxf
RU5ETkFNRSwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElOWV9VSU5U
XzAzLAorCisJCQkJICAgIGxrX3VsX3VzZXIsIE9QQUxfVUlEX0xFTkdUSCwKKworCQkJCSAgICBP
UEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgewor
CQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBTVEFSVFNFU1NJT04gY29tbWFuZC5cbiIsCisJ
CSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIGZp
bmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBzdGFydF9vcGFsX3Nlc3Npb25fY29udCk7Cit9CisK
K3N0YXRpYyBpbnQgcmV2ZXJ0X3RwZXIoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJY29uc3Qg
dTggKm1ldGhvZCwgKnNtdWlkOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisK
KwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKworCXNldF9jb21JRChj
bWQsIGRldi0+Y29tSUQpOworCisJc211aWQgPSBPUEFMVUlEW09QQUxfQURNSU5TUF9VSURdOwor
CW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9SRVZFUlRdOworCisJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgImMycyAyYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgc211
aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgs
CisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBPUEFMX0VORExJU1QpOworCWlmIChy
ZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIFJFVkVSVCBUUEVSIGNvbW1h
bmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKwor
CXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKwor
c3RhdGljIGludCBpbnRlcm5hbF9hY3RpdmF0ZV91c2VyKHN0cnVjdCBvcGFsX2RldiAqZGV2KQor
eworCWNvbnN0IHU4ICptZXRob2Q7CisJdTggdWlkW09QQUxfVUlEX0xFTkdUSF07CisJc3RydWN0
IG9wYWxfY21kICpjbWQ7CisJaW50IHJldDsKKwlzdHJ1Y3Qgb3BhbF9hY3RpdmF0ZV91c2VyICph
Y3Q7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29t
SUQoY21kLCBkZXYtPmNvbUlEKTsKKworCWFjdCA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUg
LSAxXTsKKworCW1lbWNweSh1aWQsIE9QQUxVSURbT1BBTF9VU0VSMV9VSURdLCBPUEFMX1VJRF9M
RU5HVEgpOworCXVpZFs3XSA9IGFjdC0+d2hvLndobzsKKworCW1ldGhvZCA9IE9QQUxNRVRIT0Rb
T1BBTF9TRVRdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAzYyBj
IDRjIDNjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdU
SCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9T
VEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlO
VF8wMSwgLyogVmFsdWVzICovCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisKKwkJCQkgICAg
T1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzA1LCAvKiBFbmFibGVkICov
CisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxLCAvKiBUcnVlICovCisJCQkJICAgIE9QQUxfRU5E
TkFNRSwKKworCQkJCSAgICBPUEFMX0VORExJU1QsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJ
CQkgICAgT1BBTF9FTkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVy
cm9yIGJ1aWxkaW5nIEFjdGl2YXRlIFVzZXJOIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5k
aXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2Vu
ZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBlcmFzZV9sb2NraW5n
X3JhbmdlKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCWNvbnN0IHU4ICptZXRob2Q7CisJdTgg
dWlkW09QQUxfVUlEX0xFTkdUSF07CisJc3RydWN0IG9wYWxfY21kICpjbWQ7CisJaW50IHJldDsK
KworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9jb21JRChj
bWQsIGRldi0+Y29tSUQpOworCisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX0VSQVNFXTsKKwor
CWlmIChidWlsZF9sb2NraW5nX3JhbmdlKHVpZCwgc2l6ZW9mKHVpZCksIGRldi0+bHIpIDwgMCkg
eworCQlwcl9lcnIoIiVzOiBDYW4ndCBidWlsZCBsb2NraW5nIHJhbmdlXG4iLCBkZXYtPmRpc2tf
bmFtZSk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCXJldCA9IHRlc3RfYW5kX2FkZF90b2tl
bl92YShjbWQsICJjMnMgMmMiLAorCQkJCSAgICBPUEFMX0NBTEwsCisJCQkJICAgIHVpZCwgT1BB
TF9VSURfTEVOR1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKworCQkJ
CSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKworCWlmIChyZXQg
PCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIEVyYXNlIExvY2tpbmcgUmFuZ2Ug
Q21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9
CisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOworfQor
CitzdGF0aWMgaW50IHNldF9tYnJfZG9uZShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwljb25z
dCB1OCAqbWV0aG9kLCAqdWlkOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisK
Kwl1OCBtYnJfZG9uZV90ZiA9ICoodTggKilkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0YXRlIC0gMV07
CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQo
Y21kLCBkZXYtPmNvbUlEKTsKKworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9TRVRdOworCXVp
ZCA9IE9QQUxVSURbT1BBTF9NQlJDT05UUk9MXTsKKworCXJldCA9IHRlc3RfYW5kX2FkZF90b2tl
bl92YShjbWQsICJjMnMgM2MgNmMgMmMiLAorCQkJCSAgICBPUEFMX0NBTEwsCisJCQkJICAgIHVp
ZCwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwK
KworCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJ
ICAgIE9QQUxfVkFMVUVTLAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBPUEFM
X1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDIsIC8qIERvbmUgKi8KKwkJCQkg
ICAgbWJyX2RvbmVfdGYsICAgICAgIC8qIERvbmUgVCBvciBGICovCisJCQkJICAgIE9QQUxfRU5E
TkFNRSwKKwkJCQkgICAgT1BBTF9FTkRMSVNULAorCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJ
CQkgICAgT1BBTF9FTkRMSVNUKTsKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJv
ciBCdWlsZGluZyBzZXQgTUJSIERvbmUgY29tbWFuZFxuIiwKKwkJICAgICAgIGRldi0+ZGlza19u
YW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2
LCBjbWQsIGdlbmVyaWNfY29udCk7Cit9CisKK3N0YXRpYyBpbnQgc2V0X21icl9lbmFibGVfZGlz
YWJsZShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwljb25zdCB1OCAqbWV0aG9kLCAqdWlkOwor
CXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisKKwl1OCBtYnJfZW5fZGlzID0gKih1
OCAqKWRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKworCWNtZCA9ICZkZXYtPmNtZDsK
KwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOworCisJ
bWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07CisJdWlkID0gT1BBTFVJRFtPUEFMX01CUkNP
TlRST0xdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAzYyA2YyAy
YyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJ
CQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRM
SVNULAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9WQUxVRVMsCisKKwkJ
CQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBP
UEFMX1RJTllfVUlOVF8wMSwgLyogRW5hYmxlICovCisJCQkJICAgIG1icl9lbl9kaXMsICAgICAg
ICAvKiBFbmFibGUgb3IgRGlzYWJsZSAqLworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAg
IE9QQUxfRU5ETElTVCwKKworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5E
TElTVCk7CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3IgQnVpbGRpbmcgc2V0
IE1CUiBkb25lIGNvbW1hbmRcbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVy
biByZXQ7CisJfQorCisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmlj
X2NvbnQpOworfQorCitzdGF0aWMgaW50IHNldF9uZXdfcHcoc3RydWN0IG9wYWxfZGV2ICpkZXYp
Cit7CisJY29uc3QgdTggKm1ldGhvZDsKKwl1OCBjcGluX3VpZFtPUEFMX1VJRF9MRU5HVEhdOwor
CXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisJc3RydWN0IG9wYWxfbmV3X3B3ICpw
dzsKKwlzaXplX3Qga2V5X2xlbjsKKwl1OCAqa2V5OworCisJY21kID0gJmRldi0+Y21kOworCWNs
ZWFyX29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwlwdyA9
IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKwlrZXkgPSBwdy0+bmV3X3Bpbi5rZXk7
CisJa2V5X2xlbiA9IHB3LT5uZXdfcGluLmtleV9sZW47CisJbWVtY3B5KGNwaW5fdWlkLCBPUEFM
VUlEW09QQUxfQ19QSU5fQURNSU4xXSwgT1BBTF9VSURfTEVOR1RIKTsKKworCWlmIChwdy0+dXNl
cl9mb3JfcHcgIT0gT1BBTF9BRE1JTjEpIHsKKwkJY3Bpbl91aWRbNV0gPSAweDAzOworCQlpZiAo
cHctPndoby5TVU0pCisJCQljcGluX3VpZFs3XSA9IHB3LT5uZXdfcGluLmxyICsgMTsKKwkJZWxz
ZQorCQkJY3Bpbl91aWRbN10gPSBwdy0+dXNlcl9mb3JfcHc7CisJfQorCisJbWV0aG9kID0gT1BB
TE1FVEhPRFtPUEFMX1NFVF07CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAi
YzJzIDNjIDNjczJjIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICBjcGluX3VpZCwg
T1BBTF9VSURfTEVOR1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKwor
CQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAg
IE9QQUxfVElOWV9VSU5UXzAxLCAvKiBWYWx1ZXMgKi8KKworCQkJCSAgICBPUEFMX1NUQVJUTElT
VCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLCAv
KiBQSU4gKi8KKwkJCQkgICAga2V5LCBrZXlfbGVuLAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisJ
CQkJICAgIE9QQUxfRU5ETElTVCwKKworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9Q
QUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWls
ZGluZyBTRVQgQU1JTjEgUElOIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUp
OworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNt
ZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBzZXRfc2lkX2NwaW5fcGluKHN0cnVj
dCBvcGFsX2RldiAqZGV2KQoreworCWNvbnN0IHU4ICptZXRob2QsICpjcGluX3VpZDsKKwlzdHJ1
Y3Qgb3BhbF9jbWQgKmNtZDsKKwlpbnQgcmV0OworCisJY21kID0gJmRldi0+Y21kOworCWNsZWFy
X29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwljcGluX3Vp
ZCA9IE9QQUxVSURbT1BBTF9DX1BJTl9TSURdOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9T
RVRdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAyYyA0Y3MyYyAy
YyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgY3Bpbl91aWQsIE9QQUxfVUlEX0xFTkdU
SCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9T
VEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCisJCQkJICAgIE9QQUxfVElOWV9V
SU5UXzAxLCAvKiBWYWx1ZXMgKi8KKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9Q
QUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogUElOICovCisJCQkJ
ICAgIGRldi0+a2V5LCBkZXYtPmtleV9sZW4sCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkg
ICAgT1BBTF9FTkRMSVNULAorCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9F
TkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5n
IFNFVCBDUElOIFBJTiBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJ
cmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdl
bmVyaWNfY29udCk7Cit9CisKK3N0YXRpYyB2b2lkIHF1ZXJ5X2xvY2tpbmdfcmFuZ2VfY29udChp
bnQgZXJyb3IsIHZvaWQgKmRhdGEpCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOwor
CisJaWYgKGVycm9yKQorCQlnb3RvIGVycl9yZXR1cm47CisKKwllcnJvciA9IHBhcnNlX2FuZF9j
aGVja19zdGF0dXMoZGV2KTsKKwlpZiAoZXJyb3IpCisJCWdvdG8gZXJyX3JldHVybjsKKworCWRl
di0+c3RhcnQgPSByZXNwb25zZV9nZXRfdTY0KCZkZXYtPnBhcnNlZCwgNCk7CisJZGV2LT5sZW5n
dGggPSByZXNwb25zZV9nZXRfdTY0KCZkZXYtPnBhcnNlZCwgOCk7CisKK2Vycl9yZXR1cm46CisJ
aWYgKGRldi0+b3Blcl9jYikKKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBkZXYpOworfQorCitzdGF0
aWMgaW50IHF1ZXJ5X2xvY2tpbmdfcmFuZ2Uoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJdTgg
bHJfYnVmZmVyW09QQUxfVUlEX0xFTkdUSF07CisJc3RydWN0IG9wYWxfY21kICpjbWQ7CisJY29u
c3QgdTggKm1ldGhvZDsKKwlpbnQgcmV0OworCisJY21kID0gJmRldi0+Y21kOworCWNsZWFyX29w
YWxfY21kKGNtZCk7CisKKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfR0VUXTsKKworCWlmIChi
dWlsZF9sb2NraW5nX3JhbmdlKGxyX2J1ZmZlciwgc2l6ZW9mKGxyX2J1ZmZlciksIGRldi0+bHIp
IDwgMCkgeworCQlwcl9lcnIoIiVzOiBDYW4ndCBidWlsZCBsb2NraW5nIHJhbmdlXG4iLCBkZXYt
PmRpc2tfbmFtZSk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCXNldF9jb21JRChjbWQsIGRl
di0+Y29tSUQpOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAxMmMi
LAorCQkJCSAgICBPUEFMX0NBTEwsCisJCQkJICAgIGxyX2J1ZmZlciwgT1BBTF9VSURfTEVOR1RI
LAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKworCQkJCSAgICBPUEFMX1NU
QVJUTElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1F
LAorCQkJCSAgICBPUEFMX1NUQVJUQ09MVU1OLAorCQkJCSAgICBPUEFMX1JBTkdFU1RBUlQsCisJ
CQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9Q
QUxfRU5EQ09MVU1OLAorCQkJCSAgICBPUEFMX1JBTkdFTEVOR1RILAorCQkJCSAgICBPUEFMX0VO
RE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElTVCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKwor
CWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIEdFVCBMb2NraW5n
IFJhbmdlIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4g
cmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgcXVlcnlfbG9j
a2luZ19yYW5nZV9jb250KTsKK30KKworc3RhdGljIGludCBhZGRfdXNlcl90b19scihzdHJ1Y3Qg
b3BhbF9kZXYgKmRldikKK3sKKwl1OCBscl9idWZmZXJbT1BBTF9VSURfTEVOR1RIXTsKKwl1OCB1
c2VyX3VpZFtPUEFMX1VJRF9MRU5HVEhdOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWNvbnN0
IHU4ICptZXRob2Q7CisJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrdWw7CisJaW50IHJldDsK
KworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9jb21JRChj
bWQsIGRldi0+Y29tSUQpOworCisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07CisKKwls
a3VsID0gZGV2LT5mdW5jX2RhdGFbZGV2LT5zdGF0ZSAtIDFdOworCisJbWVtY3B5KGxyX2J1ZmZl
ciwgT1BBTFVJRFtPUEFMX0xPQ0tJTkdSQU5HRV9BQ0VfUkRMT0NLRURdLAorCSAgICAgICBPUEFM
X1VJRF9MRU5HVEgpOworCisJaWYgKGxrdWwtPmxfc3RhdGUgPT0gT1BBTF9SVykKKwkJbWVtY3B5
KGxyX2J1ZmZlciwgT1BBTFVJRFtPUEFMX0xPQ0tJTkdSQU5HRV9BQ0VfV1JMT0NLRURdLAorCQkg
ICAgICAgT1BBTF9VSURfTEVOR1RIKTsKKworCWxyX2J1ZmZlcls3XSA9IGRldi0+bHI7CisKKwlt
ZW1jcHkodXNlcl91aWQsIE9QQUxVSURbT1BBTF9VU0VSMV9VSURdLCBPUEFMX1VJRF9MRU5HVEgp
OworCXVzZXJfdWlkWzddID0gbGt1bC0+YXV0aG9yaXR5LndobzsKKworCXJldCA9IHRlc3RfYW5k
X2FkZF90b2tlbl92YShjbWQsICJjMnMgM2MgM2MgMmMgMnNjIGMyc2MgY3MyYyA1YyIsCisJCQkJ
ICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgbHJfYnVmZmVyLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJ
ICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNU
LAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDEsIC8q
IFZhbHVlcyAqLworCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBPUEFMX1NUQVJU
TkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIEJvb2xlYW5FeHByICovCisKKwkJ
CQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCisJCQkJICAg
IE9QQUxVSURbT1BBTF9IQUxGX1VJRF9BVVRIT1JJVFlfT0JKX1JFRl0sCisJCQkJICAgIE9QQUxf
VUlEX0xFTkdUSF9IQUxGLAorCQkJCSAgICB1c2VyX3VpZCwgT1BBTF9VSURfTEVOR1RILAorCQkJ
CSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9Q
QUxVSURbT1BBTF9IQUxGX1VJRF9BVVRIT1JJVFlfT0JKX1JFRl0sCisJCQkJICAgIE9QQUxfVUlE
X0xFTkdUSF9IQUxGLAorCQkJCSAgICB1c2VyX3VpZCwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAg
ICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxV
SURbT1BBTF9IQUxGX1VJRF9CT09MRUFOX0FDRV0sCisJCQkJICAgIE9QQUxfVUlEX0xFTkdUSF9I
QUxGLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMSwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAor
CisJCQkJICAgIE9QQUxfRU5ETElTVCwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCQkJCSAgICBP
UEFMX0VORExJU1QsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9FTkRMSVNU
KTsKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBhZGQgdXNl
ciB0byBsb2NraW5nIHJhbmdlIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUp
OworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNt
ZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBsb2NrX3VubG9ja19sb2NraW5nX3Jh
bmdlKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXU4IGxyX2J1ZmZlcltPUEFMX1VJRF9MRU5H
VEhdOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWNvbnN0IHU4ICptZXRob2Q7CisJc3RydWN0
IG9wYWxfbG9ja191bmxvY2sgKmxrdWw7CisJaW50IHJldDsKKwl1OCByZWFkX2xvY2tlZCA9IDEs
IHdyaXRlX2xvY2tlZCA9IDE7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQo
Y21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsKKworCW1ldGhvZCA9IE9QQUxNRVRI
T0RbT1BBTF9TRVRdOworCWxrdWwgPSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0YXRlIC0gMV07CisJ
aWYgKGJ1aWxkX2xvY2tpbmdfcmFuZ2UobHJfYnVmZmVyLCBzaXplb2YobHJfYnVmZmVyKSwgZGV2
LT5scikgPCAwKSB7CisJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2VcbiIs
IGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJc3dpdGNoIChsa3Vs
LT5sX3N0YXRlKSB7CisJY2FzZSBPUEFMX1JPOgorCQlyZWFkX2xvY2tlZCA9IDA7CisJCXdyaXRl
X2xvY2tlZCA9IDE7CisJCWJyZWFrOworCWNhc2UgT1BBTF9SVzoKKwkJcmVhZF9sb2NrZWQgPSAw
OworCQl3cml0ZV9sb2NrZWQgPSAwOworCQlicmVhazsKKwljYXNlIE9QQUxfTEs6CisJCS8qIHZh
cnMgYXJlIGluaXRhbGl6ZWQgdG8gbG9ja2VkICovCisJCWJyZWFrOworCWRlZmF1bHQ6CisJCXBy
X2VycigiVHJpZWQgdG8gc2V0IGFuIGludmFsaWQgbG9ja2luZyBzdGF0ZS4uLiByZXR1cm5pbmcg
dG8gdWxhbmRcbiIpOworCQlyZXR1cm4gMTsKKwl9CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9r
ZW5fdmEoY21kLCAiYzJzYyAzYyA0YyA0YyAzYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkg
ICAgbHJfYnVmZmVyLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRI
T0RfTEVOR1RILAorCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKworCQkJCSAgICBPUEFMX1NUQVJU
TkFNRSwKKwkJCQkgICAgT1BBTF9WQUxVRVMsCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCisJ
CQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1JFQURMT0NLRUQsCisJCQkJICAg
IHJlYWRfbG9ja2VkLAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFS
VE5BTUUsCisJCQkJICAgIE9QQUxfV1JJVEVMT0NLRUQsCisJCQkJICAgIHdyaXRlX2xvY2tlZCwK
KwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfRU5ETElTVCwKKwkJCQkgICAg
T1BBTF9FTkROQU1FLAorCQkJCSAgICBPUEFMX0VORExJU1QpOworCisJaWYgKHJldCA8IDApIHsK
KwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgU0VUIGNvbW1hbmQuXG4iLCBkZXYtPmRpc2tf
bmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYs
IGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworCitzdGF0aWMgaW50IGxvY2tfdW5sb2NrX2xvY2tp
bmdfcmFuZ2VfU1VNKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXU4IGxyX2J1ZmZlcltPUEFM
X1VJRF9MRU5HVEhdOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWNvbnN0IHU4ICptZXRob2Q7
CisJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrdWw7CisJaW50IHJldDsKKwl1OCByZWFkX2xv
Y2tlZCA9IDEsIHdyaXRlX2xvY2tlZCA9IDE7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJf
b3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsKKworCW1ldGhvZCA9
IE9QQUxNRVRIT0RbT1BBTF9TRVRdOworCWxrdWwgPSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0YXRl
IC0gMV07CisJaWYgKGJ1aWxkX2xvY2tpbmdfcmFuZ2UobHJfYnVmZmVyLCBzaXplb2YobHJfYnVm
ZmVyKSwgZGV2LT5scikgPCAwKSB7CisJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcg
cmFuZ2VcbiIsIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJc3dp
dGNoIChsa3VsLT5sX3N0YXRlKSB7CisJY2FzZSBPUEFMX1JPOgorCQlyZWFkX2xvY2tlZCA9IDA7
CisJCXdyaXRlX2xvY2tlZCA9IDE7CisJCWJyZWFrOworCWNhc2UgT1BBTF9SVzoKKwkJcmVhZF9s
b2NrZWQgPSAwOworCQl3cml0ZV9sb2NrZWQgPSAwOworCQlicmVhazsKKwljYXNlIE9QQUxfTEs6
CisJCS8qIHZhcnMgYXJlIGluaXRhbGl6ZWQgdG8gbG9ja2VkICovCisJCWJyZWFrOworCWRlZmF1
bHQ6CisJCXByX2VycigiVHJpZWQgdG8gc2V0IGFuIGludmFsaWQgbG9ja2luZyBzdGF0ZS5cbiIp
OworCQlyZXR1cm4gMTsKKwl9CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAi
YzJzYyAzYyA0YyA0YyA0YyA0YyAzYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgbHJf
YnVmZmVyLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVO
R1RILAorCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwK
KwkJCQkgICAgT1BBTF9WQUxVRVMsCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCisJCQkJICAg
IE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1JFQURMT0NLRU5BQkxFRCwKKwkJCQkgICAg
T1BBTF9UUlVFLAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5B
TUUsCisJCQkJICAgIE9QQUxfV1JJVEVMT0NLRU5BQkxFRCwKKwkJCQkgICAgT1BBTF9UUlVFLAor
CQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAg
IE9QQUxfUkVBRExPQ0tFRCwKKwkJCQkgICAgcmVhZF9sb2NrZWQsCisJCQkJICAgIE9QQUxfRU5E
TkFNRSwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9XUklURUxPQ0tF
RCwKKwkJCQkgICAgd3JpdGVfbG9ja2VkLAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkg
ICAgT1BBTF9FTkRMSVNULAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5E
TElTVCk7CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgU0VU
IGNvbW1hbmQuXG4iLCBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCXJldHVy
biBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworaW50IGFj
dGl2YXRlX2xzcChzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwl1OCB1c2VyX2xyW09QQUxfVUlE
X0xFTkdUSF07CisJY29uc3QgdTggKm1ldGhvZCwgKnVpZDsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNt
ZDsKKwlpbnQgcmV0OworCXNpemVfdCB1aW50XzMgPSAweDgzOworCisJY21kID0gJmRldi0+Y21k
OworCisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsK
KworCXVpZCA9IE9QQUxVSURbT1BBTF9MT0NLSU5HU1BfVUlEXTsKKwltZXRob2QgPSBPUEFMTUVU
SE9EW09QQUxfQUNUSVZBVEVdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwg
ImMycyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJRF9MRU5HVEgs
CisJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RIKTsKKwlpZiAocmV0IDwgMCkgewor
CQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBBY3RpdmF0ZSBMb2NraW5nU1AgY29tbWFuZC5c
biIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCS8qIEFj
dGl2YXRpbmcgYXMgU1VNICovCisJaWYgKGRldi0+bHIgPiAwKSB7CisJCXJldCA9IGJ1aWxkX2xv
Y2tpbmdfcmFuZ2UodXNlcl9sciwgc2l6ZW9mKHVzZXJfbHIpLCBkZXYtPmxyKTsKKwkJaWYgKHJl
dCA8IDApIHsKKwkJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgdXNlclxuIiwKKwkJ
CSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCQlyZXR1cm4gcmV0OworCQl9CisJCXRlc3RfYW5k
X2FkZF90b2tlbl92YShjbWQsICIyYyA0YyBjc2MgMmMiLAorCQkJCSAgICAgIE9QQUxfU1RBUlRM
SVNULAorCQkJCSAgICAgIE9QQUxfU1RBUlROQU1FLAorCisJCQkJICAgICAgdWludF8zLAorCQkJ
CSAgICAgIE9QQUxfVElOWV9VSU5UXzA2LAorCQkJCSAgICAgIE9QQUxfVElOWV9VSU5UXzAwLAor
CQkJCSAgICAgIE9QQUxfVElOWV9VSU5UXzAwLAorCisJCQkJICAgICAgT1BBTF9TVEFSVExJU1Qs
CisJCQkJICAgICAgdXNlcl9sciwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICAgIE9QQUxfRU5E
TElTVCwKKworCQkJCSAgICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgICBPUEFMX0VORExJU1Qp
OworCX0gZWxzZSAvKiBBY3RpYXZlIE5vcm1hbCBNb2RlICovCisJCXJldCA9IHRlc3RfYW5kX2Fk
ZF90b2tlbl92YShjbWQsICIyYyIsCisJCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkJICAg
IE9QQUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBi
dWlsZGluZyBBY3RpdmF0ZSBMb2NraW5nU1AgY29tbWFuZC5cbiIsCisJCSAgICAgICBkZXYtPmRp
c2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5k
KGRldiwgY21kLCBnZW5lcmljX2NvbnQpOworfQorCitzdGF0aWMgdm9pZCBnZXRfbHNwX2xpZmVj
eWNsZV9jb250KGludCBlcnJvciwgdm9pZCAqZGF0YSkKK3sKKworCXN0cnVjdCBvcGFsX2RldiAq
ZGV2ID0gZGF0YTsKKwl1OCBsY19zdGF0dXM7CisKKwlpZiAoZXJyb3IpCisJCWdvdG8gZXJyX3Jl
dHVybjsKKworCWVycm9yID0gcGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhkZXYpOworCWlmIChlcnJv
cikKKwkJZ290byBlcnJfcmV0dXJuOworCisJbGNfc3RhdHVzID0gcmVzcG9uc2VfZ2V0X3U2NCgm
ZGV2LT5wYXJzZWQsIDQpOworCS8qIDB4MDggaXMgTWFudWZhY3VyZWQgSW5hY3RpdmUgKi8KKwkv
KiAweDA5IGlzIE1hbnVmYWN0dXJlZCAqLworCWlmIChsY19zdGF0dXMgIT0gMHgwOCkgeworCQlw
cl9lcnIoIiVzOiBDb3VsZG4ndCBkZXRlcm1pbmUgdGhlIHN0YXR1cyBvZiB0aGUgTGlmY3ljbGUg
c3RhdGVcbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCWVycm9yID0gLUVOT0RFVjsK
Kwl9CisKK2Vycl9yZXR1cm46CisJaWYgKGRldi0+b3Blcl9jYikKKwkJZGV2LT5vcGVyX2NiKGVy
cm9yLCBkZXYpOworfQorCisvKiBEZXRlcm1pbmUgaWYgd2UncmUgaW4gdGhlIE1hbnVmYWN0dXJl
ZCBJbmFjdGl2ZSBvciBBY3RpdmUgc3RhdGUgKi8KK2ludCBnZXRfbHNwX2xpZmVjeWNsZShzdHJ1
Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwljb25zdCB1OCAq
bWV0aG9kLCAqdWlkOworCWludCByZXQ7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisKKwljbGVhcl9v
cGFsX2NtZChjbWQpOworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOworCisJdWlkID0gT1BB
TFVJRFtPUEFMX0xPQ0tJTkdTUF9VSURdOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9HRVRd
OworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAyYyA0YyA0YyAyYyIs
CisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJ
ICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNU
LAorCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJ
CQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIFN0YXJ0IENvbHVtbiAqLworCQkJCSAgICBPUEFM
X1RJTllfVUlOVF8wNiwgLyogTGlmY3ljbGUgQ29sdW1uICovCisJCQkJICAgIE9QQUxfRU5ETkFN
RSwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDQs
IC8qIEVuZCBDb2x1bW4gKi8KKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIExpZmVjeWNs
ZSBDb2x1bW4gKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfRU5ETElT
VCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2Vycigi
JXM6IEVycm9yIEJ1aWxkaW5nIEdFVCBMaWZlY3ljbGUgU3RhdHVzIGNvbW1hbmRcbiIsCisJCSAg
ICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIGZpbmFs
aXplX2FuZF9zZW5kKGRldiwgY21kLCBnZXRfbHNwX2xpZmVjeWNsZV9jb250KTsKK30KKworc3Rh
dGljIHZvaWQgZ2V0X21zaWRfY3Bpbl9waW5fY29udChpbnQgZXJyb3IsIHZvaWQgKmRhdGEpCit7
CisJY29uc3QgY2hhciAqbXNpZF9waW47CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOwor
CXNpemVfdCBzdHJsZW47CisKKwlpZiAoZXJyb3IpCisJCWdvdG8gZXJyX3JldHVybjsKKworCWVy
cm9yID0gcGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhkZXYpOworCWlmIChlcnJvcikKKwkJZ290byBl
cnJfcmV0dXJuOworCisJc3RybGVuID0gcmVzcG9uc2VfZ2V0X3N0cmluZygmZGV2LT5wYXJzZWQs
IDQsICZtc2lkX3Bpbik7CisJaWYgKCFtc2lkX3BpbikgeworCQlwcl9lcnIoIiVzOiBDb3VsZG4n
dCBleHRyYWN0IFBJTiBmcm9tIHJlc3BvbnNlXG4iLCBfX2Z1bmNfXyk7CisJCWVycm9yID0gMTsK
KwkJZ290byBlcnJfcmV0dXJuOworCX0KKworCWRldi0+cHJldl9kYXRhID0ga21lbWR1cChtc2lk
X3Bpbiwgc3RybGVuLCBHRlBfS0VSTkVMKTsKKwlpZiAoIWRldi0+cHJldl9kYXRhKQorCQllcnJv
ciA9IC1FTk9NRU07CisKKwlkZXYtPnByZXZfZF9sZW4gPSBzdHJsZW47CisKKyBlcnJfcmV0dXJu
OgorCWlmIChkZXYtPm9wZXJfY2IpCisJCWRldi0+b3Blcl9jYihlcnJvciwgZGV2KTsKK30KKwor
c3RhdGljIGludCBnZXRfbXNpZF9jcGluX3BpbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlj
b25zdCB1OCAqbWV0aG9kLCAqc211aWQ7CisJaW50IHJldDsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNt
ZDsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9jb21J
RChjbWQsIGRldi0+Y29tSUQpOworCisJc211aWQgPSBPUEFMVUlEW09QQUxfQ19QSU5fTVNJRF07
CisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX0dFVF07CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRf
dG9rZW5fdmEoY21kLCAiYyAycyAxMmMiLAorCQkJCSAgICBPUEFMX0NBTEwsCisKKwkJCQkgICAg
c211aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5H
VEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAor
CQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIFNh
cnQgQ29sdW1uICovCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLCAvKiBQSU4gKi8KKwkJCQkg
ICAgT1BBTF9FTkROQU1FLAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9U
SU5ZX1VJTlRfMDQsIC8qIEVuZCBDb2x1bW4gKi8KKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMs
IC8qIFBJTiAqLworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElTVCwK
KwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6
IEVycm9yIGJ1aWxkaW5nIEdldCBNU0lEIENQSU4gUElOIGNvbW1hbmQuXG4iLAorCQkgICAgICAg
ZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9h
bmRfc2VuZChkZXYsIGNtZCwgZ2V0X21zaWRfY3Bpbl9waW5fY29udCk7Cit9CisKK3N0YXRpYyB2
b2lkIHVubG9ja19zdXNwZW5kX2ZpbmFsKGludCBlcnJvciwgdm9pZCAqZGF0YSkKK3sKKwlzdHJ1
Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisKKwlkZXYtPnJlc3VtZV9mcm9tX3N1c3BlbmQgPSBm
YWxzZTsKKwlkZXYtPnJlc3VtZV9kYXRhID0gTlVMTDsKKwlkZXYtPmZ1bmNfZGF0YSA9IE5VTEw7
CisJZGV2LT5iZGV2ID0gTlVMTDsKK30KKworc3RhdGljIGludCBidWlsZF9lbmRfb3BhbF9zZXNz
aW9uKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCisJ
Y21kID0gJmRldi0+Y21kOworCWNsZWFyX29wYWxfY21kKGNtZCk7CisKKwlzZXRfY29tSUQoY21k
LCBkZXYtPmNvbUlEKTsKKwlyZXR1cm4gdGVzdF9hbmRfYWRkX3Rva2VuX3U4KGNtZCwgT1BBTF9F
TkRPRlNFU1NJT04pOworfQorCitzdGF0aWMgaW50IGVuZF9vcGFsX3Nlc3Npb24oc3RydWN0IG9w
YWxfZGV2ICpkZXYpCit7CisJaW50IHJldCA9IGJ1aWxkX2VuZF9vcGFsX3Nlc3Npb24oZGV2KTsK
KwlpZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJldDsKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQo
ZGV2LCAmZGV2LT5jbWQsIGVuZF9zZXNzaW9uX2NvbnQpOworfQorCitzdGF0aWMgc3RydWN0IG9w
YWxfZGV2ICpmaW5kX29wYWxfZGV2KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHU4IGxyKQor
eworCXN0cnVjdCBvcGFsX2RldiAqaXRlciwgKm9wYWxfZGV2ID0gTlVMTDsKKworCWxpc3RfZm9y
X2VhY2hfZW50cnkoaXRlciwgJm9wYWxfbGlzdCwgbm9kZSkgeworCQlpZiAoc3RybmNtcChpdGVy
LT5kaXNrX25hbWUsIGJkZXYtPmJkX2Rpc2stPmRpc2tfbmFtZSwKKwkJCSAgICBESVNLX05BTUVf
TEVOKSkKKwkJCWNvbnRpbnVlOworCQlpZiAoaXRlci0+bHIgPT0gbHIpIHsKKwkJCW9wYWxfZGV2
ID0gaXRlcjsKKwkJCWJyZWFrOworCQl9CisJfQorCisJcmV0dXJuIG9wYWxfZGV2OworfQorCitz
dGF0aWMgaW50IHVwZGF0ZV9vcGFsX2RldihzdHJ1Y3Qgb3BhbF9kZXYgKm9sZF9kZXYsIHN0cnVj
dCBvcGFsX2RldiAqbmV3X2RldikKK3sKKwlpZiAoIWF0b21pY19hZGRfdW5sZXNzKCZvbGRfZGV2
LT5pbl91c2UsIDEsIDEpKSB7CisJCXByX2VycigiJXM6IGRldiB3YXMgaW4gdXNlXG4iLCBfX2Z1
bmNfXyk7CisJCXJldHVybiAtRUJVU1k7CisJfQorCisJb2xkX2Rldi0+a2V5X25hbWVfbGVuID0g
bmV3X2Rldi0+a2V5X25hbWVfbGVuOworCWlmICghbWVtY3B5KG9sZF9kZXYtPmtleV9uYW1lLCBu
ZXdfZGV2LT5rZXlfbmFtZSwgb2xkX2Rldi0+a2V5X25hbWVfbGVuKSkgeworCQlwcl9lcnIoIiVz
OiBFcnJvciB1cGRhdGluZyBkZXZpY2U6XG4iLCBvbGRfZGV2LT5kaXNrX25hbWUpOworCQlyZXR1
cm4gLUVGQVVMVDsKKwl9CisKKwlpZiAoIXN0cm5jcHkob2xkX2Rldi0+ZGlza19uYW1lLCBuZXdf
ZGV2LT5kaXNrX25hbWUsIERJU0tfTkFNRV9MRU4pKSB7CisJCXByX2VycigiJXM6IEVycm9yIHJl
Z2lzdGVyaW5nIGRldmljZTogY29weWluZyBkaXNrIG5hbWVcbiIsCisJCSAgICAgICBvbGRfZGV2
LT5kaXNrX25hbWUpOworCQlyZXR1cm4gLUVGQVVMVDsKKwl9CisKKwlvbGRfZGV2LT5jb21JRCA9
IG5ld19kZXYtPmNvbUlEOworCW9sZF9kZXYtPnN0YXJ0ID0gbmV3X2Rldi0+c3RhcnQ7CisJb2xk
X2Rldi0+bGVuZ3RoID0gbmV3X2Rldi0+bGVuZ3RoOworCW9sZF9kZXYtPmFsaWduID0gbmV3X2Rl
di0+YWxpZ247CisJb2xkX2Rldi0+bG93ZXN0X2xiYSA9IG5ld19kZXYtPmxvd2VzdF9sYmE7CisJ
b2xkX2Rldi0+YmRldiA9IE5VTEw7CisJb2xkX2Rldi0+ZmluYWxfY2IgPSBuZXdfZGV2LT5maW5h
bF9jYjsKKwlvbGRfZGV2LT5maW5hbF9jYl9kYXRhID0gbmV3X2Rldi0+ZmluYWxfY2JfZGF0YTsK
KwlvbGRfZGV2LT5vcGVyX2NiID0gbmV3X2Rldi0+b3Blcl9jYjsKKwlvbGRfZGV2LT5zdGF0ZSA9
IG5ld19kZXYtPnN0YXRlOworCW9sZF9kZXYtPmZ1bmNzID0gbmV3X2Rldi0+ZnVuY3M7CisKKwlr
ZnJlZShvbGRfZGV2LT5jb21wbGV0aW9uKTsKKwljbGVhbl9mdW5jdGlvbl9kYXRhKG9sZF9kZXYp
OworCisJb2xkX2Rldi0+Y29tcGxldGlvbiA9IG5ld19kZXYtPmNvbXBsZXRpb247CisKKwkvKgor
CSAqIFdvbid0IGJlIGFibGUgdG8gYXV0byB1bmxvY2sgdGhpcyBsb2NraW5nIHJhbmdlIGJhc2Vk
IG9uIGJsb2NrCisJICogcmVxdWVzdGVzLgorCSAqLworCWlmIChvbGRfZGV2LT5sZW5ndGggPT0g
MCkKKwkJcHJfd2FybigiJXM6IE1pc3NpbmcgYmxvY2sgaW5mb3JtYXRpb24gZm9yIGxvY2tpbmcg
cmFuZ2UgJWRcbiIsCisJCQlvbGRfZGV2LT5kaXNrX25hbWUsIG9sZF9kZXYtPmxyKTsKKworCXJl
dHVybiAwOworfQorCitpbnQgb3BhbF9yZWdpc3Rlcl9jb250KHN0cnVjdCBvcGFsX2RldiAqbmV3
X2RldikKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKm9sZF9kZXY7CisJdW5zaWduZWQgbG9uZyBmbGFn
czsKKwlpbnQgZXJyb3IgPSAwOworCisJc3Bpbl9sb2NrX2lycXNhdmUoJmxpc3Rfc3BpbmxvY2ss
IGZsYWdzKTsKKworCW9sZF9kZXYgPSBmaW5kX29wYWxfZGV2KG5ld19kZXYtPmJkZXYsIG5ld19k
ZXYtPmxyKTsKKwlpZiAoIW9sZF9kZXYpIHsKKwkJbGlzdF9hZGRfdGFpbCgmbmV3X2Rldi0+bm9k
ZSwgJm9wYWxfbGlzdCk7CisJCW9sZF9kZXYgPSBuZXdfZGV2OworCX0gZWxzZSB7CisJCWlmIChv
bGRfZGV2ID09IG5ld19kZXYpCisJCQllcnJvciA9IDA7CisJCWVsc2UgeworCQkJZXJyb3IgPSB1
cGRhdGVfb3BhbF9kZXYob2xkX2RldiwgbmV3X2Rldik7CisJCQljbGVhbl9vcGFsX2tleShuZXdf
ZGV2KTsKKwkJCWtmcmVlKG5ld19kZXYpOworCQl9CisJfQorCisJaWYgKGVycm9yKQorCQlsaXN0
X2RlbCgmb2xkX2Rldi0+bm9kZSk7CisKKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZsaXN0X3Nw
aW5sb2NrLCBmbGFncyk7CisKKwlpZiAoIWVycm9yKQorCQlwcl9pbmZvKCIlczogUmVnaXN0ZXJl
ZCBrZXkgZm9yIGxvY2tpbmcgcmFuZ2U6ICVkXG4iLAorCQkJb2xkX2Rldi0+ZGlza19uYW1lLCBv
bGRfZGV2LT5scik7CisKKwlpZiAob2xkX2Rldi0+b3Blcl9jYikKKwkJb2xkX2Rldi0+b3Blcl9j
YihlcnJvciwgb2xkX2Rldik7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHZvaWQgbmV4dChp
bnQgZXJyb3IsIHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCW9wYWxfc3RlcCBmdW5jID0gZGV2
LT5mdW5jc1tkZXYtPnN0YXRlXTsKKwl2b2lkICpjYl9kYXRhID0gZGV2LT5maW5hbF9jYl9kYXRh
OworCXNlY19jYiAqY2IgPSBkZXYtPmZpbmFsX2NiOworCWJvb2wgZG9uZSA9IGZhbHNlOworCisK
KwlpZiAoZXJyb3IgfHwgIWZ1bmMpIHsKKwkJZG9uZSA9IHRydWU7CisJCWdvdG8gbmV4dF9leGl0
OworCX0KKwlkZXYtPnN0YXRlKys7CisJZGV2LT5vcGVyX2NiID0gbmV4dDsKKwllcnJvciA9IGZ1
bmMoZGV2KTsKKyBuZXh0X2V4aXQ6CisJaWYgKGVycm9yKSB7CisJCXByX2VycigiJXM6IEVycm9y
IG9uIHN0ZXAgZnVuY3Rpb246ICVkIHdpdGggZXJyb3IgJWQ6ICVzXG4iLAorCQkgICAgICAgZGV2
LT5kaXNrX25hbWUsIGRldi0+c3RhdGUsIGVycm9yLAorCQkgICAgICAgb3BhbF9lcnJvcl90b19o
dW1hbihlcnJvcikpOworCisKKwkJYXRvbWljX2RlYygmZGV2LT5pbl91c2UpOworCQlpZiAoZGV2
LT5lcnJvcl9jYikgeworCQkJZGV2LT5lcnJvcl9jYihkZXYtPmVycm9yX2NiX2RhdGEpOworCQkJ
cmV0dXJuOworCQl9CisJCWlmIChjYikKKwkJCWNiKGVycm9yLCBjYl9kYXRhKTsKKworCQlkZXYt
PmNvbXBsZXRpb24tPmNvbXBsZXRpb25fc3RhdHVzID0gZXJyb3I7CisJCWNvbXBsZXRlKCZkZXYt
PmNvbXBsZXRpb24tPmNtZF9jb21wbGV0aW9uKTsKKwl9IGVsc2UgaWYgKCFlcnJvciAmJiBkb25l
KSB7CisJCWF0b21pY19kZWMoJmRldi0+aW5fdXNlKTsKKwkJaWYgKGNiKQorCQkJY2IoZXJyb3Is
IGNiX2RhdGEpOworCQlkZXYtPmNvbXBsZXRpb24tPmNvbXBsZXRpb25fc3RhdHVzID0gZXJyb3I7
CisJCWNvbXBsZXRlKCZkZXYtPmNvbXBsZXRpb24tPmNtZF9jb21wbGV0aW9uKTsKKwl9Cit9CisK
K2NvbnN0IG9wYWxfc3RlcCBlcnJvcl9lbmRfc2Vzc2lvbltdID0geworCWVuZF9vcGFsX3Nlc3Np
b24sCisJTlVMTCwKK307CitzdGF0aWMgaW50IGVuZF9vcGFsX3Nlc3Npb25fZXJyb3Ioc3RydWN0
IG9wYWxfZGV2ICpkZXYpCit7CisKKwlkZXYtPmZ1bmNzID0gZXJyb3JfZW5kX3Nlc3Npb247CisJ
ZGV2LT5zdGF0ZSA9IDA7CisJZGV2LT5lcnJvcl9jYiA9IE5VTEw7CisJbmV4dCgwLCBkZXYpOwor
CXJldHVybiAwOworfQorCitzdGF0aWMgc3RydWN0IG9wYWxfZGV2ICphbGxvY19vcGFsX2Rldihz
dHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCB1OCBscikKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKm9w
YWxfZGV2OworCXN0cnVjdCByZXF1ZXN0X3F1ZXVlICpxOworCXVuc2lnbmVkIGxvbmcgZG1hX2Fs
aWduOworCWNvbnN0IGNoYXIgKmRpc2tfbmFtZTsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlp
bnQgcmV0OworCisJb3BhbF9kZXYgPSBremFsbG9jKHNpemVvZigqb3BhbF9kZXYpLCBHRlBfS0VS
TkVMKTsKKwlpZiAoIW9wYWxfZGV2KQorCQlyZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsKKworCW9w
YWxfZGV2LT5iZGV2ID0gYmRldjsKKwlvcGFsX2Rldi0+bHIgPSBscjsKKwljbWQgPSAmb3BhbF9k
ZXYtPmNtZDsKKwljbWQtPmNtZCA9IGNtZC0+Y21kX2J1ZjsKKwljbWQtPnJlc3AgPSBjbWQtPnJl
c3BfYnVmOworCisJZGlza19uYW1lID0gYmRldi0+YmRfZGlzay0+ZGlza19uYW1lOworCWlmICgh
c3RybmNweShvcGFsX2Rldi0+ZGlza19uYW1lLCBkaXNrX25hbWUsIERJU0tfTkFNRV9MRU4pKSB7
CisJCXByX2VycigiJXM6IEVycm9yIHJlZ2lzdGVyaW5nIGRldmljZTogY29weWluZyBkaXNrIG5h
bWVcbiIsCisJCSAgICAgICBkaXNrX25hbWUpOworCQlyZXQgPSAtRUZBVUxUOworCQlnb3RvIGVy
cl9mcmVlX2RldjsKKwl9CisKKwlxID0gYmRldi0+YmRfcXVldWU7CisJZG1hX2FsaWduID0gKHF1
ZXVlX2RtYV9hbGlnbm1lbnQocSkgfCBxLT5kbWFfcGFkX21hc2spICsgMTsKKwljbWQtPmNtZCA9
ICh1OCAqKXJvdW5kX3VwKCh1aW50cHRyX3QpY21kLT5jbWQsIGRtYV9hbGlnbik7CisJY21kLT5y
ZXNwID0gKHU4ICopcm91bmRfdXAoKHVpbnRwdHJfdCljbWQtPnJlc3AsIGRtYV9hbGlnbik7CisK
KwlJTklUX0xJU1RfSEVBRCgmb3BhbF9kZXYtPm5vZGUpOworCWF0b21pY19zZXQoJm9wYWxfZGV2
LT5pbl91c2UsIDEpOworCisJb3BhbF9kZXYtPmNvbXBsZXRpb24gPSBremFsbG9jKHNpemVvZigq
b3BhbF9kZXYtPmNvbXBsZXRpb24pLAorCQkJCSAgICAgICBHRlBfS0VSTkVMKTsKKworCWlmICgh
b3BhbF9kZXYtPmNvbXBsZXRpb24pCisJCWdvdG8gZXJyX2ZyZWVfZGV2OworCisJaW5pdF9jb21w
bGV0aW9uKCZvcGFsX2Rldi0+Y29tcGxldGlvbi0+Y21kX2NvbXBsZXRpb24pOworCW9wYWxfZGV2
LT5jb21wbGV0aW9uLT5jb21wbGV0aW9uX3N0YXR1cyA9IDA7CisJb3BhbF9kZXYtPnN0YXRlID0g
MDsKKwlJTklUX1dPUksoJm9wYWxfZGV2LT5vcGFsX3NlbmRfd29yaywgX29wYWxfc2VuZF9jbWQp
OworCUlOSVRfV09SSygmb3BhbF9kZXYtPm9wYWxfcmVjdl93b3JrLCBfb3BhbF9yZWN2X2NtZCk7
CisKKworCXJldHVybiBvcGFsX2RldjsKKworZXJyX2ZyZWVfZGV2OgorCWtmcmVlKG9wYWxfZGV2
KTsKKwlyZXR1cm4gRVJSX1BUUihyZXQpOworfQorCitpbnQgb3BhbF9yZWdpc3RlcihzdHJ1Y3Qg
YmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgb3BhbF9rZXkgKmtleV9jbWQsCisJCSAgY29uc3Qg
b3BhbF9zdGVwICpmdW5jcykKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKm5ld19kZXYgPSBOVUxMOwor
CXU4IGtleV9sZW4gPSBrZXlfY21kLT5rZXlfbGVuOworCXU4IGxyID0ga2V5X2NtZC0+bHI7CisJ
c3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKKwlpbnQgcmV0OworCisJbmV3X2Rl
diA9IGFsbG9jX29wYWxfZGV2KGJkZXYsIGxyKTsKKwlpZiAoSVNfRVJSKG5ld19kZXYpKSB7CisJ
CXByX2VycigiJXM6IEVycm9yIHJlZ2lzdGVyaW5nIGRldmljZTogYWxsb2NhdGlvblxuIiwKKwkJ
ICAgICAgIGJkZXYtPmJkX2Rpc2stPmRpc2tfbmFtZSk7CisJCXJldHVybiBQVFJfRVJSKG5ld19k
ZXYpOworCX0KKworCWlmICghbWVtY3B5KG5ld19kZXYtPmtleV9uYW1lLCBrZXlfY21kLT5rZXks
IGtleV9sZW4pKSB7CisJCXByX2VycigiJXM6IEVycm9yIHJlZ2lzdGVyaW5nIGtleTogY291bGRu
J3QgY29weSBrZXlcbiIsCisJCSAgICAgICBuZXdfZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4g
LUVGQVVMVDsKKwl9CisKKwluZXdfZGV2LT5rZXlfbmFtZV9sZW4gPSBrZXlfbGVuOworCW5ld19k
ZXYtPmtleV90eXBlID0ga2V5X2NtZC0+a2V5X3R5cGU7CisJcmV0ID0gZ2V0X29wYWxfa2V5KG5l
d19kZXYpOworCWlmIChyZXQpIHsKKwkJcHJfZXJyKCIlczogQ291bGRuJ3QgZ2V0IGtleTogJWRc
biIsIG5ld19kZXYtPmRpc2tfbmFtZSwgcmV0KTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwluZXdf
ZGV2LT5mdW5jcyA9IGZ1bmNzOworCisJbmV3X2Rldi0+c3RhdGUgPSAwOworCWNvbXBsZXRpb24g
PSBuZXdfZGV2LT5jb21wbGV0aW9uOworCW5leHQoMCwgbmV3X2Rldik7CisKKwlyZXR1cm4gd2Fp
dF9mb3JfY21kX2NvbXBsZXRpb24oY29tcGxldGlvbik7Cit9CisKK3N0YXRpYyBzdHJ1Y3Qgb3Bh
bF9kZXYgKmdldF9yZWdpc3RlcmVkX29wYWxfZGV2KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYs
CisJCQkJCQl1OCBscikKK3sKKwljb25zdCBjaGFyICpkaXNrbmFtZSA9IGJkZXYtPmJkX2Rpc2st
PmRpc2tfbmFtZTsKKwlzdHJ1Y3Qgb3BhbF9kZXYgKml0ZXIsICpkZXYgPSBOVUxMOworCXVuc2ln
bmVkIGxvbmcgZmxhZ3M7CisJYm9vbCBpbl91c2UgPSBmYWxzZTsKKworCXNwaW5fbG9ja19pcnFz
YXZlKCZsaXN0X3NwaW5sb2NrLCBmbGFncyk7CisJbGlzdF9mb3JfZWFjaF9lbnRyeShpdGVyLCAm
b3BhbF9saXN0LCBub2RlKSB7CisJCWlmIChzdHJuY21wKGl0ZXItPmRpc2tfbmFtZSwgZGlza25h
bWUsIERJU0tfTkFNRV9MRU4pKQorCQkJY29udGludWU7CisJCWlmIChpdGVyLT5sciA9PSBscikg
eworCQkJZGV2ID0gaXRlcjsKKwkJCWlmICghYXRvbWljX2FkZF91bmxlc3MoJml0ZXItPmluX3Vz
ZSwgMSwgMSkpIHsKKwkJCQlkZXYgPSBOVUxMOworCQkJCWluX3VzZSA9IHRydWU7CisJCQl9CisJ
CQlicmVhazsKKwkJfQorCX0KKworCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJmxpc3Rfc3Bpbmxv
Y2ssIGZsYWdzKTsKKworCWlmICghZGV2KQorCQlyZXR1cm4gTlVMTDsKKworCWRldi0+YmRldiA9
IGJkZXY7CisJcmV0dXJuIGRldjsKK30KKworLyogRnJlZSB1cCB0aGUgT3BhbCBkZXYgYW5kIGl0
cyBrZXlzIGR1cmluZyB0d28gc2NlbmFyaW9zOgorICoKKyAqIDEpIFdoZW4gYSBjb21tYW5kIGlz
IGNvbXBsZXRlIHRoYXQgbm8gbG9uZ2VyIHJlcXVpcmVzCisgKiAgICB0aGUgb3BhbCBkZXYgdG8g
YmUgYXJvdW5kLgorICogMikgV2hlbiBhIGNvbW1hbmQsIGluY2x1ZGluZyBPcGFsIFNhdmUgZmFp
bHMgd2UgY2xlYW4KKyAqICAgIGFuZCBmcmVlIHRoZSBvcGFsIGRldi4KKyAqCisgKiAgICBJZiB3
ZSBmaW5kIHRoZSBvcGFsIGRldiBzdHJ1Y3R1cmUgaW4gdGhlIGxpc3Qgb2YKKyAqICAgIHNhdmVk
IHBhc3N3b3JkcyB3ZSB3aWxsICpub3QqIHJlbW92ZSBpdC4KKyAqLworc3RhdGljIHZvaWQgcmVt
b3ZlX2FuZF9jbGVhbl9vcGFsX2RldihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlzdHJ1Y3Qg
b3BhbF9kZXYgKml0ZXI7CisJYm9vbCBmb3VuZCA9IGZhbHNlOworCisJc3Bpbl9sb2NrKCZsaXN0
X3NwaW5sb2NrKTsKKwlsaXN0X2Zvcl9lYWNoX2VudHJ5KGl0ZXIsICZvcGFsX2xpc3QsIG5vZGUp
IHsKKwkJaWYgKGl0ZXIgPT0gZGV2KSB7CisJCQlmb3VuZCA9IHRydWU7CisJCQlicmVhazsKKwkJ
fQorCX0KKworCXNwaW5fdW5sb2NrKCZsaXN0X3NwaW5sb2NrKTsKKwlpZiAoIWZvdW5kKSB7CisJ
CWNsZWFuX29wYWxfa2V5KGRldik7CisJCWNsZWFuX2Z1bmN0aW9uX2RhdGEoZGV2KTsKKwkJa2Zy
ZWUoZGV2KTsKKwl9Cit9CisKK3N0YXRpYyBzdHJ1Y3Qgb3BhbF9kZXYgKmdldF9vcl9jcmVhdGVf
b3BhbF9kZXYoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKKwkJCQkJICAgICAgIHU4IGxyLCBi
b29sIHVzZV9uZXcpCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBOVUxMOworCisJaWYgKCF1
c2VfbmV3KQorCQlkZXYgPSBnZXRfcmVnaXN0ZXJlZF9vcGFsX2RldihiZGV2LCBscik7CisKKwlp
ZiAoIWRldikKKwkJZGV2ID0gYWxsb2Nfb3BhbF9kZXYoYmRldiwgbHIpOworCisJcmV0dXJuIGRl
djsKK30KKworc3RhdGljIHN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKnNldHVwX29wYWxfZGV2KHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJCQkJCSAgICAgIHN0cnVjdCBvcGFsX2RldiAqZGV2
LAorCQkJCQkgICAgICBjb25zdCBvcGFsX3N0ZXAgKmZ1bmNzLAorCQkJCQkgICAgICBzdHJ1Y3Qg
b3BhbF9rZXkgKmtleSkKK3sKKwlpbnQgcmV0OworCisJZGV2LT5iZGV2ID0gYmRldjsKKwlkZXYt
PnN0YXRlID0gMDsKKwlkZXYtPmZ1bmNzID0gZnVuY3M7CisJZGV2LT5UU04gPSAwOworCWRldi0+
SFNOID0gMDsKKwlkZXYtPmZpbmFsX2NiID0gTlVMTDsKKwlkZXYtPmZpbmFsX2NiX2RhdGEgPSBO
VUxMOworCWRldi0+bHIgPSBrZXktPmxyOworCWRldi0+ZXJyb3JfY2IgPSBlbmRfb3BhbF9zZXNz
aW9uX2Vycm9yOworCWRldi0+ZXJyb3JfY2JfZGF0YSA9IGRldjsKKworCWlmIChrZXkpIHsKKwkJ
bWVtY3B5KGRldi0+a2V5X25hbWUsIGtleS0+a2V5LCBrZXktPmtleV9sZW4pOworCQlkZXYtPmtl
eV9uYW1lX2xlbiA9IGtleS0+a2V5X2xlbjsKKwkJZGV2LT5rZXlfdHlwZSA9IGtleS0+a2V5X3R5
cGU7CisKKwkJcmV0ID0gZ2V0X29wYWxfa2V5KGRldik7CisJCWlmIChyZXQpIHsKKwkJCWtmcmVl
KGRldi0+Y29tcGxldGlvbik7CisJCQlwcl9lcnIoIiVzOiBDb3VsZG4ndCBnZXQga2V5OiAlZFxu
IiwKKwkJCSAgICAgICBkZXYtPmRpc2tfbmFtZSwgcmV0KTsKKwkJCXJldHVybiBFUlJfUFRSKHJl
dCk7CisJCX0KKwl9CisJZGV2LT5mdW5jX2RhdGEgPSBOVUxMOworCWRldi0+Y29tcGxldGlvbi0+
Y29tcGxldGlvbl9zdGF0dXMgPSAwOworCXJldHVybiBkZXYtPmNvbXBsZXRpb247Cit9CisKK3N0
YXRpYyBpbnQgaW50ZXJuYWxfc2V0dXBfbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKKwkJ
CSAgICAgc3RydWN0IG9wYWxfdXNlcl9scl9zZXR1cCAqc2V0dXApCit7CisJc3RydWN0IG9wYWxf
ZGV2ICpkZXY7CisJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKKwl2b2lkICpk
YXRhWzNdID0geyBOVUxMIH07CisJY29uc3Qgb3BhbF9zdGVwIGxyX2Z1bmNzW10gPSB7CisJCW9w
YWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCisJCXNldHVwX2xvY2tp
bmdfcmFuZ2UsCisJCWdldF9hY3RpdmVfa2V5LAorCQlnZW5fa2V5LAorCQllbmRfb3BhbF9zZXNz
aW9uLAorCQlOVUxMLAorCX07CisJaW50IHJldDsKKworCWRldiA9IGdldF9vcl9jcmVhdGVfb3Bh
bF9kZXYoYmRldiwgc2V0dXAtPmtleS5sciwgdHJ1ZSk7CisJaWYgKCFkZXYpCisJCXJldHVybiAt
RU5PTUVNOworCisJY29tcGxldGlvbiA9IHNldHVwX29wYWxfZGV2KGJkZXYsIGRldiwgbHJfZnVu
Y3MsICZzZXR1cC0+a2V5KTsKKwlpZiAoSVNfRVJSKGNvbXBsZXRpb24pKSB7CisJCXJldCA9IFBU
Ul9FUlIoY29tcGxldGlvbik7CisJCWdvdG8gZXJyb3JfcmV0dXJuOworCX0KKworCWRldi0+ZnVu
Y19kYXRhID0gZGF0YTsKKwlkZXYtPm51bV9mdW5jX2RhdGEgPSAzOworCWRldi0+ZnVuY19kYXRh
WzFdID0gJnNldHVwLT53aG87CisJZGV2LT5mdW5jX2RhdGFbMl0gPSBzZXR1cDsKKworCW5leHQo
MCwgZGV2KTsKKwlyZXQgPSB3YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9uKTsKKwor
IGVycm9yX3JldHVybjoKKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRldik7CisJcmV0dXJu
IHJldDsKK30KKworaW50IG9wYWxfcmV2ZXJ0KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0
cnVjdCBvcGFsX2tleSAqa2V5KQoreworCWNvbnN0IG9wYWxfc3RlcCByZXZlcnRfZnVuY3NbXSA9
IHsKKwkJb3BhbF9kaXNjb3ZlcnkwLAorCQlzdGFydF9TSURBU1Bfb3BhbF9zZXNzaW9uLAorCQly
ZXZlcnRfdHBlciwgLyogY29udHJvbGxlciB3aWxsIHRlcm1pbmF0ZSBzZXNzaW9uICovCisJCU5V
TEwsCisJfTsKKworCXJldHVybiBvcGFsX3JlZ2lzdGVyKGJkZXYsIGtleSwgcmV2ZXJ0X2Z1bmNz
KTsKK30KKworaW50IGFjdGl2YXRlX3VzZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3Ry
dWN0IG9wYWxfYWN0aXZhdGVfdXNlciAqYWN0KQoreworCWNvbnN0IG9wYWxfc3RlcCBhY3RfZnVu
Y3NbXSA9IHsKKwkJb3BhbF9kaXNjb3ZlcnkwLAorCQlzdGFydF9hZG1pbjFMU1Bfb3BhbF9zZXNz
aW9uLAorCQlpbnRlcm5hbF9hY3RpdmF0ZV91c2VyLAorCQllbmRfb3BhbF9zZXNzaW9uLAorCQlO
VUxMCisJfTsKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKKwlzdHJ1Y3Qgb3BhbF9jb21wbGV0aW9u
ICpjb21wbGV0aW9uOworCXZvaWQgKmRhdGFbM10gPSB7IE5VTEwgfTsKKwlpbnQgcmV0OworCisJ
ZGV2ID0gZ2V0X29yX2NyZWF0ZV9vcGFsX2RldihiZGV2LCBhY3QtPmtleS5sciwgdHJ1ZSk7CisJ
aWYgKCFkZXYpCisJCXJldHVybiAtRU5PTUVNOworCisJY29tcGxldGlvbiA9IHNldHVwX29wYWxf
ZGV2KGJkZXYsIGRldiwgYWN0X2Z1bmNzLCAmYWN0LT5rZXkpOworCWlmIChJU19FUlIoY29tcGxl
dGlvbikpIHsKKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKKwkJZ290byBlcnJvcl9yZXR1
cm47CisJfQorCisJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKKwlkZXYtPmZ1bmNfZGF0YSA9IGRh
dGE7CisJZGV2LT5mdW5jX2RhdGFbMV0gPSBhY3Q7CisJZGV2LT5mdW5jX2RhdGFbMl0gPSBhY3Q7
CisKKwluZXh0KDAsIGRldik7CisJcmV0ID0gd2FpdF9mb3JfY21kX2NvbXBsZXRpb24oY29tcGxl
dGlvbik7CisKKyBlcnJvcl9yZXR1cm46CisJcmVtb3ZlX2FuZF9jbGVhbl9vcGFsX2RldihkZXYp
OworCXJldHVybiByZXQ7Cit9CisKK2ludCBvcGFsX3NldF9wdyhzdHJ1Y3QgYmxvY2tfZGV2aWNl
ICpiZGV2LCBzdHJ1Y3Qgb3BhbF9uZXdfcHcgKnB3KQorCit7CisJY29uc3Qgb3BhbF9zdGVwIHB3
X2Z1bmNzW10gPSB7CisJCW9wYWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRfYXV0aF9vcGFsX3Nlc3Np
b24sCisJCXNldF9uZXdfcHcsCisJCWVuZF9vcGFsX3Nlc3Npb24sCisJCU5VTEwKKwl9OworCXN0
cnVjdCBvcGFsX2RldiAqZGV2OworCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247
CisJdm9pZCAqZGF0YVszXSA9IHsgTlVMTCB9OworCWludCByZXQ7CisKKwlkZXYgPSBnZXRfb3Jf
Y3JlYXRlX29wYWxfZGV2KGJkZXYsIHB3LT5jdXJyZW50X3Bpbi5sciwgdHJ1ZSk7CisJaWYgKCFk
ZXYpCisJCXJldHVybiAtRU5PTUVNOworCisJY29tcGxldGlvbiA9IHNldHVwX29wYWxfZGV2KGJk
ZXYsIGRldiwgcHdfZnVuY3MsICZwdy0+Y3VycmVudF9waW4pOworCWlmIChJU19FUlIoY29tcGxl
dGlvbikpIHsKKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKKwkJZ290byBlcnJvcl9yZXR1
cm47CisJfQorCisJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKKwlkZXYtPmZ1bmNfZGF0YSA9IGRh
dGE7CisJZGV2LT5mdW5jX2RhdGFbMV0gPSAodm9pZCAqKSAmcHctPndobzsKKwlkZXYtPmZ1bmNf
ZGF0YVsyXSA9ICh2b2lkICopIHB3OworCisJbmV4dCgwLCBkZXYpOworCXJldCA9IHdhaXRfZm9y
X2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24pOworCisgZXJyb3JfcmV0dXJuOgorCXJlbW92ZV9h
bmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0OworfQorCitpbnQgb3BhbF9hY3Rf
bHNwX2ludChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgb3BhbF9rZXkgKmtleSwK
KwkJICAgICBjb25zdCBvcGFsX3N0ZXAgKmZ1bmNzKQoreworCXN0cnVjdCBvcGFsX2RldiAqZGV2
OworCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247CisJaW50IHJldDsKKworCWRl
diA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwga2V5LT5sciwgdHJ1ZSk7CisJaWYgKCFk
ZXYpCisJCXJldHVybiAtRU5PTUVNOworCWNvbXBsZXRpb24gPSBzZXR1cF9vcGFsX2RldihiZGV2
LCBkZXYsIGZ1bmNzLCBrZXkpOworCWlmIChJU19FUlIoY29tcGxldGlvbikpIHsKKwkJcmV0ID0g
UFRSX0VSUihjb21wbGV0aW9uKTsKKwkJZ290byBlcnJvcl9yZXR1cm47CisJfQorCisJbmV4dCgw
LCBkZXYpOworCXJldCA9IHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24pOworCisg
ZXJyb3JfcmV0dXJuOgorCXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4g
cmV0OworfQorCisKK3N0YXRpYyBpbnQgb3BhbF9zYXZlX2ludGVybmFsKHN0cnVjdCBibG9ja19k
ZXZpY2UgKmJkZXYsCisJCQkgICAgICBzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayAqbGspCit7CisJ
dm9pZCAqZnVuY19kYXRhWzNdID0geyBOVUxMIH07CisJc3RydWN0IG9wYWxfZGV2ICpkZXY7CisJ
c3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKKwljb25zdCBvcGFsX3N0ZXAgX2F1
dGhfZnVuY3NbXSA9IHsKKwkJb3BhbF9kaXNjb3ZlcnkwLAorCQlzdGFydF9hdXRoX29wYWxfc2Vz
c2lvbiwKKwkJcXVlcnlfbG9ja2luZ19yYW5nZSwKKwkJZW5kX29wYWxfc2Vzc2lvbiwKKwkJb3Bh
bF9yZWdpc3Rlcl9jb250LAorCQlOVUxMCisJfTsKKwlpbnQgcmV0OworCisJZGV2ID0gZ2V0X29y
X2NyZWF0ZV9vcGFsX2RldihiZGV2LCBsay0+a2V5LmxyLCBmYWxzZSk7CisJaWYgKCFkZXYpCisJ
CXJldHVybiAtRU5PTUVNOworCWNvbXBsZXRpb24gPSBzZXR1cF9vcGFsX2RldihiZGV2LCBkZXYs
IF9hdXRoX2Z1bmNzLCAmbGstPmtleSk7CisJaWYgKElTX0VSUihjb21wbGV0aW9uKSkgeworCQly
ZXQgPSBQVFJfRVJSKGNvbXBsZXRpb24pOworCQlnb3RvIGVycm9yX3JldHVybjsKKwl9CisKKwlk
ZXYtPm51bV9mdW5jX2RhdGEgPSAzOworCWRldi0+ZnVuY19kYXRhID0gZnVuY19kYXRhOworCWRl
di0+ZnVuY19kYXRhWzFdID0gJmxrLT5hdXRob3JpdHk7CisJZGV2LT5sa3VsID0gKmxrOworCisJ
bmV4dCgwLCBkZXYpOworCXJldCA9IHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24p
OworCisgZXJyb3JfcmV0dXJuOgorCXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwly
ZXR1cm4gcmV0OworfQorCitzdGF0aWMgaW50IGFkZF91c2VyX2xyX2ludGVybmFsKHN0cnVjdCBi
bG9ja19kZXZpY2UgKmJkZXYsCisJCQkJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrKQorewor
CXZvaWQgKmZ1bmNfZGF0YVszXSA9IHsgTlVMTCB9OworCXN0cnVjdCBvcGFsX2RldiAqZGV2Owor
CXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247CisJY29uc3Qgb3BhbF9zdGVwIGZ1
bmNzW10gPSB7CisJCW9wYWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRfYWRtaW4xTFNQX29wYWxfc2Vz
c2lvbiwKKwkJYWRkX3VzZXJfdG9fbHIsCisJCWVuZF9vcGFsX3Nlc3Npb24sCisJCU5VTEwKKwl9
OworCWludCByZXQ7CisKKwlkZXYgPSBnZXRfb3JfY3JlYXRlX29wYWxfZGV2KGJkZXYsIGxrLT5r
ZXkubHIsIHRydWUpOworCWlmICghZGV2KQorCQlyZXR1cm4gLUVOT01FTTsKKwljb21wbGV0aW9u
ID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBmdW5jcywgJmxrLT5rZXkpOworCWlmIChJU19F
UlIoY29tcGxldGlvbikpIHsKKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKKwkJZ290byBl
cnJvcl9yZXR1cm47CisJfQorCisJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKKwlkZXYtPmZ1bmNf
ZGF0YSA9IGZ1bmNfZGF0YTsKKwlkZXYtPmZ1bmNfZGF0YVsyXSA9IGxrOworCisJbmV4dCgwLCBk
ZXYpOworCXJldCA9IHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24pOworCisgZXJy
b3JfcmV0dXJuOgorCXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0
OworfQorCisvKiBUaGVzZSBhcmUgZ2xvYmFsJ2QgYmVjYXVzZSBib3RoIGxvY2tfdW5sb2NrX2lu
dGVybmFsCisgKiBhbmQgb3BhbF91bmxvY2tfZnJvbV9zdXNwZW5kIG5lZWQgdGhlbS4KKyAqLwor
Y29uc3Qgb3BhbF9zdGVwIHVsa19mdW5jc19TVU1bXSA9IHsKKwlvcGFsX2Rpc2NvdmVyeTAsCisJ
c3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCisJbG9ja191bmxvY2tfbG9ja2luZ19yYW5nZV9TVU0s
CisJZW5kX29wYWxfc2Vzc2lvbiwKKwlOVUxMCit9OworY29uc3Qgb3BhbF9zdGVwIF91bmxvY2tf
ZnVuY3NbXSA9IHsKKwlvcGFsX2Rpc2NvdmVyeTAsCisJc3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24s
CisJbG9ja191bmxvY2tfbG9ja2luZ19yYW5nZSwKKwllbmRfb3BhbF9zZXNzaW9uLAorCU5VTEwK
K307CitzdGF0aWMgaW50IGxvY2tfdW5sb2NrX2ludGVybmFsKHN0cnVjdCBibG9ja19kZXZpY2Ug
KmJkZXYsCisJCQkJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrKQoreworCXZvaWQgKmZ1bmNf
ZGF0YVszXSA9IHsgTlVMTCB9OworCXN0cnVjdCBvcGFsX2RldiAqZGV2OworCXN0cnVjdCBvcGFs
X2NvbXBsZXRpb24gKmNvbXBsZXRpb247CisKKwlpbnQgcmV0OworCisJZGV2ID0gZ2V0X29yX2Ny
ZWF0ZV9vcGFsX2RldihiZGV2LCBsay0+a2V5LmxyLCB0cnVlKTsKKwlpZiAoIWRldikKKwkJcmV0
dXJuIC1FTk9NRU07CisKKwlpZiAobGstPmF1dGhvcml0eS5TVU0pCisJCWNvbXBsZXRpb24gPSBz
ZXR1cF9vcGFsX2RldihiZGV2LCBkZXYsIHVsa19mdW5jc19TVU0sICZsay0+a2V5KTsKKwllbHNl
CisJCWNvbXBsZXRpb24gPSBzZXR1cF9vcGFsX2RldihiZGV2LCBkZXYsIF91bmxvY2tfZnVuY3Ms
ICZsay0+a2V5KTsKKworCWlmIChJU19FUlIoY29tcGxldGlvbikpIHsKKwkJcmV0ID0gUFRSX0VS
Uihjb21wbGV0aW9uKTsKKwkJZ290byBlcnJvcl9yZXR1cm47CisJfQorCisJZGV2LT5udW1fZnVu
Y19kYXRhID0gMzsKKwlkZXYtPmZ1bmNfZGF0YSA9IGZ1bmNfZGF0YTsKKwlkZXYtPmZ1bmNfZGF0
YVsxXSA9ICZsay0+YXV0aG9yaXR5OworCWRldi0+ZnVuY19kYXRhWzJdID0gbGs7CisKKwluZXh0
KDAsIGRldik7CisJcmV0ID0gd2FpdF9mb3JfY21kX2NvbXBsZXRpb24oY29tcGxldGlvbik7CisK
KyBlcnJvcl9yZXR1cm46CisJcmVtb3ZlX2FuZF9jbGVhbl9vcGFsX2RldihkZXYpOworCXJldHVy
biByZXQ7Cit9CisKK2ludCBvcGFsX2VyYXNlX2xvY2tpbmdfcmFuZ2Uoc3RydWN0IGJsb2NrX2Rl
dmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRl
djsKKwlzdHJ1Y3Qgb3BhbF9jb21wbGV0aW9uICpjb21wbGV0aW9uOworCXN0cnVjdCBvcGFsX2tl
eSBrOworCWludCByZXQ7CisJY29uc3Qgb3BhbF9zdGVwIGVyYXNlX2Z1bmNzW10gPSB7CisJCW9w
YWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRfYWRtaW4xTFNQX29wYWxfc2Vzc2lvbiwKKwkJZXJhc2Vf
bG9ja2luZ19yYW5nZSwKKwkJZW5kX29wYWxfc2Vzc2lvbiwKKwkJTlVMTCwKKwl9OworCisJaWYg
KCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrKSB7CisJCXByX2VycigiQ2FuJ3Qgc2F2ZSBwYXNzd29y
ZCBmb3IgTlVMTCBibG9jayBkZXZpY2UuXG4iKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJ
aWYgKGNvcHlfZnJvbV91c2VyKCZrLCBrZXktPm9wYWwsIHNpemVvZigqa2V5LT5vcGFsKSkpCisJ
CXJldHVybiAtRUZBVUxUOworCisJZGV2ID0gZ2V0X29yX2NyZWF0ZV9vcGFsX2RldihiZGV2LCBr
LmxyLCB0cnVlKTsKKwlpZiAoIWRldikKKwkJcmV0dXJuIC1FTk9NRU07CisKKwljb21wbGV0aW9u
ID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBlcmFzZV9mdW5jcywgJmspOworCWlmIChJU19F
UlIoY29tcGxldGlvbikpIHsKKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKKwkJZ290byBl
cnJvcl9yZXR1cm47CisJfQorCisJbmV4dCgwLCBkZXYpOworCXJldCA9IHdhaXRfZm9yX2NtZF9j
b21wbGV0aW9uKGNvbXBsZXRpb24pOworCisgZXJyb3JfcmV0dXJuOgorCXJlbW92ZV9hbmRfY2xl
YW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0OworfQorRVhQT1JUX1NZTUJPTChvcGFsX2Vy
YXNlX2xvY2tpbmdfcmFuZ2UpOworCitpbnQgb3BhbF9lbmFibGVfZGlzYWJsZV9zaGFkb3dfbWJy
KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJCQkJICAgc3RydWN0IHNlZF9rZXkgKmtleSkK
K3sKKwl2b2lkICpmdW5jX2RhdGFbNl0gPSB7IE5VTEwgfTsKKwlzdHJ1Y3Qgb3BhbF9tYnJfZGF0
YSBtYnI7CisJc3RydWN0IG9wYWxfZGV2ICpkZXY7CisJc3RydWN0IG9wYWxfY29tcGxldGlvbiAq
Y29tcGxldGlvbjsKKwljb25zdCBvcGFsX3N0ZXAgbWJyX2Z1bmNzW10gPSB7CisJCW9wYWxfZGlz
Y292ZXJ5MCwKKwkJc3RhcnRfYWRtaW4xTFNQX29wYWxfc2Vzc2lvbiwKKwkJc2V0X21icl9kb25l
LAorCQllbmRfb3BhbF9zZXNzaW9uLAorCQlzdGFydF9hZG1pbjFMU1Bfb3BhbF9zZXNzaW9uLAor
CQlzZXRfbWJyX2VuYWJsZV9kaXNhYmxlLAorCQllbmRfb3BhbF9zZXNzaW9uLAorCQlOVUxMLAor
CX07CisJaW50IHJldDsKKworCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzaykgeworCQlwcl9l
cnIoIkNhbid0IHNhdmUgcGFzc3dvcmQgZm9yIE5VTEwgYmxvY2sgZGV2aWNlLlxuIik7CisJCXJl
dHVybiAtRUlOVkFMOworCX0KKworCWlmIChjb3B5X2Zyb21fdXNlcigmbWJyLCBrZXktPm9wYWxf
bWJyLCBzaXplb2YoKmtleS0+b3BhbF9tYnIpKSkKKwkJcmV0dXJuIC1FRkFVTFQ7CisKKwlpZiAo
bWJyLmVuYWJsZV9kaXNhYmxlICE9IE9QQUxfTUJSX0VOQUJMRSAmJgorCSAgICBtYnIuZW5hYmxl
X2Rpc2FibGUgIT0gT1BBTF9NQlJfRElTQUJMRSkKKwkJcmV0dXJuIC1FSU5WQUw7CisKKwlkZXYg
PSBnZXRfb3JfY3JlYXRlX29wYWxfZGV2KGJkZXYsIG1ici5rZXkubHIsIHRydWUpOworCWlmICgh
ZGV2KQorCQlyZXR1cm4gLUVOT01FTTsKKworCWNvbXBsZXRpb24gPSBzZXR1cF9vcGFsX2Rldihi
ZGV2LCBkZXYsIG1icl9mdW5jcywgJm1ici5rZXkpOworCWlmIChJU19FUlIoY29tcGxldGlvbikp
IHsKKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKKwkJZ290byBlcnJvcl9yZXR1cm47CisJ
fQorCisJZGV2LT5udW1fZnVuY19kYXRhID0gNjsKKwlkZXYtPmZ1bmNfZGF0YSA9IGZ1bmNfZGF0
YTsKKwlkZXYtPmZ1bmNfZGF0YVsyXSA9ICZtYnIuZW5hYmxlX2Rpc2FibGU7CisJZGV2LT5mdW5j
X2RhdGFbNV0gPSAmbWJyLmVuYWJsZV9kaXNhYmxlOworCisJbmV4dCgwLCBkZXYpOworCXJldCA9
IHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24pOworCisgZXJyb3JfcmV0dXJuOgor
CXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0OworCit9CitFWFBP
UlRfU1lNQk9MKG9wYWxfZW5hYmxlX2Rpc2FibGVfc2hhZG93X21icik7CisKK2ludCBvcGFsX3Nh
dmUoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKwlz
dHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayBsa3VsOworCisJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9k
aXNrKSB7CisJCXByX2VycigiQ2FuJ3Qgc2F2ZSBwYXNzd29yZCBmb3IgTlVMTCBibG9jayBkZXZp
Y2UuXG4iKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJaWYgKGNvcHlfZnJvbV91c2VyKCZs
a3VsLCBrZXktPm9wYWxfbGtfdW5saywgc2l6ZW9mKCprZXktPm9wYWwpKSkKKwkJcmV0dXJuIC1F
RkFVTFQ7CisKKwlyZXR1cm4gb3BhbF9zYXZlX2ludGVybmFsKGJkZXYsICZsa3VsKTsKK30KK0VY
UE9SVF9TWU1CT0wob3BhbF9zYXZlKTsKKworaW50IG9wYWxfYWRkX3VzZXJfdG9fbHIoc3RydWN0
IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKwlzdHJ1Y3Qgb3Bh
bF9sb2NrX3VubG9jayBsa3VsOworCisJaWYgKGNvcHlfZnJvbV91c2VyKCZsa3VsLCBrZXktPm9w
YWxfbGtfdW5saywgc2l6ZW9mKGxrdWwpKSkKKwkJcmV0dXJuIC1FRkFVTFQ7CisKKwlpZiAoIWJk
ZXYgfHwgIWJkZXYtPmJkX2Rpc2spIHsKKwkJcHJfZXJyKCJDYW4ndCBhc3NpZ24gdXNlciB0byBM
UiB3aXRob3V0IGJhY2tpbmcgZGlza1xuIik7CisJCXJldHVybiAtRUZBVUxUOworCX0KKwlpZiAo
bGt1bC5sX3N0YXRlICE9IE9QQUxfUk8gJiYgbGt1bC5sX3N0YXRlICE9IE9QQUxfUlcpIHsKKwkJ
cHJfZXJyKCJMb2NraW5nIHN0YXRlIHdhcyBub3QgUk8gb3IgUldcbiIpOworCQlyZXR1cm4gLUVJ
TlZBTDsKKwl9CisJaWYgKGxrdWwuYXV0aG9yaXR5LndobyA8IE9QQUxfVVNFUjEgJiYKKwkgICAg
bGt1bC5hdXRob3JpdHkud2hvID4gT1BBTF9VU0VSOSkgeworCQlwcl9lcnIoIkF1dGhvcml0eSB3
YXMgbm90IHdpdGhpbiB0aGUgcmFuZ2Ugb2YgdXNlcnM6ICVkXG4iLAorCQkgICAgICAgbGt1bC5h
dXRob3JpdHkud2hvKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCWlmIChsa3VsLmF1dGhvcml0
eS5TVU0pIHsKKwkJcHJfZXJyKCIlcyBub3Qgc3VwcG9ydGVkIGluIFNVTS4gVXNlIHNldHVwIGxv
Y2tpbmcgcmFuZ2VcbiIsCisJCSAgICAgICBfX2Z1bmNfXyk7CisJCXJldHVybiAtRUlOVkFMOwor
CX0KKworCXJldHVybiBhZGRfdXNlcl9scl9pbnRlcm5hbChiZGV2LCAmbGt1bCk7Cit9CitFWFBP
UlRfU1lNQk9MKG9wYWxfYWRkX3VzZXJfdG9fbHIpOworCitpbnQgb3BhbF9yZXZlcnR0cGVyKHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisJc3RydWN0
IG9wYWxfa2V5IGs7CisKKwlpZiAoY29weV9mcm9tX3VzZXIoJmssIGtleS0+b3BhbCwgc2l6ZW9m
KCprZXktPm9wYWwpKSkKKwkJcmV0dXJuIC1FRkFVTFQ7CisKKwlyZXR1cm4gb3BhbF9yZXZlcnQo
YmRldiwgJmspOworfQorRVhQT1JUX1NZTUJPTChvcGFsX3JldmVydHRwZXIpOworCitpbnQgb3Bh
bF9sb2NrX3VubG9jayhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAq
a2V5KQoreworCXN0cnVjdCBvcGFsX2xvY2tfdW5sb2NrIGs7CisKKwlpZiAoY29weV9mcm9tX3Vz
ZXIoJmssIGtleS0+b3BhbF9sa191bmxrLCBzaXplb2YoKmtleS0+b3BhbF9sa191bmxrKSkpCisJ
CXJldHVybiAtRUZBVUxUOworCisJaWYgKGsuYXV0aG9yaXR5LndobyA8IE9QQUxfQURNSU4xIHx8
IGsuYXV0aG9yaXR5LndobyA+IE9QQUxfVVNFUjkpCisJCXJldHVybiAtRUlOVkFMOworCisJcmV0
dXJuIGxvY2tfdW5sb2NrX2ludGVybmFsKGJkZXYsICZrKTsKK30KK0VYUE9SVF9TWU1CT0wob3Bh
bF9sb2NrX3VubG9jayk7CisKK2ludCBvcGFsX3Rha2Vfb3duZXJzaGlwKHN0cnVjdCBibG9ja19k
ZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisJc3RydWN0IG9wYWxfa2V5IGs7
CisJY29uc3Qgb3BhbF9zdGVwIG93bmVyX2Z1bmNzW10gPSB7CisJCW9wYWxfZGlzY292ZXJ5MCwK
KwkJc3RhcnRfYW55Ym9keUFTUF9vcGFsX3Nlc3Npb24sCisJCWdldF9tc2lkX2NwaW5fcGluLAor
CQllbmRfb3BhbF9zZXNzaW9uLAorCQlzdGFydF9TSURBU1Bfb3BhbF9zZXNzaW9uLAorCQlzZXRf
c2lkX2NwaW5fcGluLAorCQllbmRfb3BhbF9zZXNzaW9uLAorCQlOVUxMCisJfTsKKworCWlmICgh
YmRldiB8fCAhYmRldi0+YmRfZGlzaykgeworCQlwcl9lcnIoIkNhbid0IHNhdmUgcGFzc3dvcmQg
Zm9yIE5VTEwgYmxvY2sgZGV2aWNlLlxuIik7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCWlm
IChjb3B5X2Zyb21fdXNlcigmaywga2V5LT5vcGFsLCBzaXplb2YoKmtleS0+b3BhbCkpKQorCQly
ZXR1cm4gLUVGQVVMVDsKKworCXJldHVybiBvcGFsX3JlZ2lzdGVyKGJkZXYsICZrLCBvd25lcl9m
dW5jcyk7Cit9CitFWFBPUlRfU1lNQk9MKG9wYWxfdGFrZV9vd25lcnNoaXApOworCitpbnQgb3Bh
bF9hY3RpdmF0ZV9sc3Aoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkg
KmtleSkKK3sKKwlzdHJ1Y3Qgb3BhbF9rZXkgazsKKwljb25zdCBvcGFsX3N0ZXAgYWN0aXZlX2Z1
bmNzW10gPSB7CisJCW9wYWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRfU0lEQVNQX29wYWxfc2Vzc2lv
biwgLyogT3BlbiBzZXNzaW9uIGFzIFNJRCBhdXRoICovCisJCWdldF9sc3BfbGlmZWN5Y2xlLAor
CQlhY3RpdmF0ZV9sc3AsCisJCWVuZF9vcGFsX3Nlc3Npb24sCisJCU5VTEwKKwl9OworCisJaWYg
KCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrKSB7CisJCXByX2VycigiQ2FuJ3Qgc2F2ZSBwYXNzd29y
ZCBmb3IgTlVMTCBibG9jayBkZXZpY2UuXG4iKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJ
aWYgKGNvcHlfZnJvbV91c2VyKCZrLCBrZXktPm9wYWwsIHNpemVvZigqa2V5LT5vcGFsKSkpCisJ
CXJldHVybiAtRUZBVUxUOworCisJcmV0dXJuIG9wYWxfYWN0X2xzcF9pbnQoYmRldiwgJmssIGFj
dGl2ZV9mdW5jcyk7Cit9CitFWFBPUlRfU1lNQk9MKG9wYWxfYWN0aXZhdGVfbHNwKTsKKworaW50
IG9wYWxfc2V0dXBfbG9ja2luZ19yYW5nZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1
Y3Qgc2VkX2tleSAqcHcpCit7CisJc3RydWN0IG9wYWxfdXNlcl9scl9zZXR1cCBrOworCisJaWYg
KCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrKSB7CisJCXByX2VycigiQ2FuJ3Qgc2F2ZSBwYXNzd29y
ZCBmb3IgTlVMTCBibG9jayBkZXZpY2UuXG4iKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJ
aWYgKGNvcHlfZnJvbV91c2VyKCZrLCBwdy0+b3BhbF9scnMsIHNpemVvZigqcHctPm9wYWxfbHJz
KSkpCisJCXJldHVybiAtRUZBVUxUOworCisJcmV0dXJuIGludGVybmFsX3NldHVwX2xyKGJkZXYs
ICZrKTsKK30KKworaW50IG9wYWxfc2V0X25ld19wdyhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2
LCBzdHJ1Y3Qgc2VkX2tleSAqcHcpCit7CisJc3RydWN0IG9wYWxfbmV3X3B3IGs7CisKKwlpZiAo
cHctPnNlZF90eXBlICE9IE9QQUxfUFcpCisJCXJldHVybiAtRUlOVkFMOworCisJaWYgKGNvcHlf
ZnJvbV91c2VyKCZrLCBwdy0+b3BhbF9wdywgc2l6ZW9mKCpwdy0+b3BhbF9wdykpKQorCQlyZXR1
cm4gLUVGQVVMVDsKKworCWlmIChrLndoby53aG8gPCBPUEFMX0FETUlOMSB8fCBrLndoby53aG8g
PiBPUEFMX1VTRVI5KQorCQlyZXR1cm4gLUVJTlZBTDsKKworCXJldHVybiBvcGFsX3NldF9wdyhi
ZGV2LCAmayk7Cit9CitFWFBPUlRfU1lNQk9MKG9wYWxfc2V0X25ld19wdyk7CisKK2ludCBvcGFs
X2FjdGl2YXRlX3VzZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkg
KnB3KQoreworCXN0cnVjdCBvcGFsX2FjdGl2YXRlX3VzZXIgazsKKworCWlmIChwdy0+c2VkX3R5
cGUgIT0gT1BBTF9BQ1RfVVNSKSB7CisJCXByX2VycigiU2VkIHR5cGUgd2FzIG5vdCBhY3QgdXNl
clxuIik7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCWlmIChjb3B5X2Zyb21fdXNlcigmaywg
cHctPm9wYWxfYWN0LCBzaXplb2YoKnB3LT5vcGFsX2FjdCkpKSB7CisJCXByX2VycigiY29weSBm
cm9tIHVzZXIgZXJyb3JcbiIpOworCQlyZXR1cm4gLUVGQVVMVDsKKwl9CisKKwkvKiBXZSBjYW4n
dCBhY3RpdmF0ZSBBZG1pbjEgaXQncyBhY3RpdmUgYXMgbWFudWZhY3R1cmVkICovCisJaWYgKGsu
d2hvLndobyA8IE9QQUxfVVNFUjEgJiYgay53aG8ud2hvID4gT1BBTF9VU0VSOSkgeworCQlwcl9l
cnIoIldobyB3YXMgbm90IGEgdmFsaWQgdXNlcjogJWQgXG4iLCBrLndoby53aG8pOworCQlyZXR1
cm4gLUVJTlZBTDsKKwl9CisKKwlyZXR1cm4gYWN0aXZhdGVfdXNlcihiZGV2LCAmayk7CisKK30K
K0VYUE9SVF9TWU1CT0wob3BhbF9hY3RpdmF0ZV91c2VyKTsKKworaW50IG9wYWxfdW5sb2NrX2Zy
b21fc3VzcGVuZChzdHJ1Y3Qgb3BhbF9zdXNwZW5kX3VubGsgKmRhdGEpCit7CisJY29uc3QgY2hh
ciAqZGlza25hbWUgPSBkYXRhLT5uYW1lOworCXN0cnVjdCBvcGFsX2RldiAqaXRlciwgKmRldiA9
IE5VTEw7CisJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKKwl2b2lkICpmdW5j
X2RhdGFbM10gPSB7IE5VTEwgfTsKKworCXNwaW5fbG9jaygmbGlzdF9zcGlubG9jayk7CisJbGlz
dF9mb3JfZWFjaF9lbnRyeShpdGVyLCAmb3BhbF9saXN0LCBub2RlKSB7CisJCWlmIChzdHJuY21w
KGl0ZXItPmRpc2tfbmFtZSwgZGlza25hbWUsIERJU0tfTkFNRV9MRU4pKSB7CisJCQlwcl9lcnIo
Iml0ZXJkaXNrIHdhcyAlcyBhbmQgZGlza25hbWUgaXMgJXNcbiIsCisJCQkgICAgICAgaXRlci0+
ZGlza19uYW1lLCBkaXNrbmFtZSk7CisJCQljb250aW51ZTsKKwkJfQorCQlpZiAoYXRvbWljX2Fk
ZF91bmxlc3MoJml0ZXItPmluX3VzZSwgMSwgMSkpIHsKKwkJCWRldiA9IGl0ZXI7CisJCQlkZXYt
PmZ1bmNfZGF0YSA9IGZ1bmNfZGF0YTsKKwkJCWRldi0+cmVzdW1lX2Zyb21fc3VzcGVuZCA9IHRy
dWU7CisJCQlkZXYtPnJlc3VtZV9kYXRhID0gZGF0YTsKKwkJCWRldi0+ZmluYWxfY2IgPSB1bmxv
Y2tfc3VzcGVuZF9maW5hbDsKKwkJCWRldi0+ZmluYWxfY2JfZGF0YSA9IGRldjsKKwkJCWRldi0+
ZXJyb3JfY2IgPSBlbmRfb3BhbF9zZXNzaW9uX2Vycm9yOworCQkJZGV2LT5lcnJvcl9jYl9kYXRh
ID0gZGV2OworCQkJZGV2LT5zdGF0ZSA9IDA7CisJCQlpZiAoZGV2LT5sa3VsLmF1dGhvcml0eS5T
VU0pCisJCQkJZGV2LT5mdW5jcyA9IHVsa19mdW5jc19TVU07CisJCQllbHNlCisJCQkJZGV2LT5m
dW5jcyA9IF91bmxvY2tfZnVuY3M7CisJCQlkZXYtPlRTTiA9IDA7CisJCQlkZXYtPkhTTiA9IDA7
CisJCQlkZXYtPmZ1bmNfZGF0YVsyXSA9ICZkZXYtPmxrdWw7CisJCQlkZXYtPmZ1bmNfZGF0YVsx
XSA9ICZkZXYtPmxrdWwuYXV0aG9yaXR5OworCQkJY29tcGxldGlvbiA9IGRldi0+Y29tcGxldGlv
bjsKKwkJCW5leHQoMCwgZGV2KTsKKwkJCXdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRp
b24pOworCQl9CisJfQorCXNwaW5fdW5sb2NrKCZsaXN0X3NwaW5sb2NrKTsKKworCWlmICghZGV2
KQorCQlyZXR1cm4gLUVOT0RFVjsKKwlyZXR1cm4gMDsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF91
bmxvY2tfZnJvbV9zdXNwZW5kKTsKZGlmZiAtLWdpdCBhL2xpYi9zZWQtb3BhbF9pbnRlcm5hbC5o
IGIvbGliL3NlZC1vcGFsX2ludGVybmFsLmgKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAw
MDAwMC4uNTQwNDFjYgotLS0gL2Rldi9udWxsCisrKyBiL2xpYi9zZWQtb3BhbF9pbnRlcm5hbC5o
CkBAIC0wLDAgKzEsNTg3IEBACisvKgorICogQ29weXJpZ2h0IMKpIDIwMTYgSW50ZWwgQ29ycG9y
YXRpb24KKyAqCisgKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJn
ZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYQorICogY29weSBvZiB0aGlzIHNvZnR3YXJlIGFu
ZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwKKyAqIHRv
IGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRo
b3V0IGxpbWl0YXRpb24KKyAqIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdl
LCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLAorICogYW5kL29yIHNlbGwgY29waWVz
IG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlCisgKiBT
b2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBj
b25kaXRpb25zOgorICoKKyAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBl
cm1pc3Npb24gbm90aWNlIChpbmNsdWRpbmcgdGhlIG5leHQKKyAqIHBhcmFncmFwaCkgc2hhbGwg
YmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUK
KyAqIFNvZnR3YXJlLgorICoKKyAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBX
SVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SCisgKiBJTVBMSUVELCBJTkNM
VURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElU
WSwKKyAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1F
TlQuICBJTiBOTyBFVkVOVCBTSEFMTAorICogVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERF
UlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKKyAqIExJQUJJTElU
WSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBB
UklTSU5HCisgKiBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FS
RSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTCisgKiBJTiBUSEUgU09GVFdBUkUuCisgKgor
ICogQXV0aG9yOgorICogICAgUmFmYWVsIEFudG9nbm9sbGkgPHJhZmFlbC5hbnRvZ25vbGxpQGlu
dGVsLmNvbT4KKyAqICAgIFNjb3R0ICBCYXVlciAgICAgIDxzY290dC5iYXVlckBpbnRlbC5jb20+
CisgKi8KKworI2lmbmRlZiBfTlZNRV9PUEFMX0lOVEVSTkFMX0gKKyNkZWZpbmUgX05WTUVfT1BB
TF9JTlRFUk5BTF9ICisKKyNpbmNsdWRlIDxsaW51eC9rZXktdHlwZS5oPgorI2luY2x1ZGUgPGtl
eXMvdXNlci10eXBlLmg+CisKKyNkZWZpbmUgRFRBRVJST1JfTk9fTUVUSE9EX1NUQVRVUyAweDg5
CisjZGVmaW5lIEdFTkVSSUNfSE9TVF9TRVNTSU9OX05VTSAweDQxCisKK3N0YXRpYyBjb25zdCBj
aGFyICpvcGFsX2Vycm9yc1tdID0geworCSJTdWNjZXNzIiwKKwkiTm90IEF1dGhvcml6ZWQiLAor
CSJVbmtub3duIEVycm9yIiwKKwkiU1AgQnVzeSIsCisJIlNQIEZhaWxlZCIsCisJIlNQIERpc2Fi
bGVkIiwKKwkiU1AgRnJvemVuIiwKKwkiTm8gU2Vzc2lvbnMgQXZhaWxhYmxlIiwKKwkiVW5pcXVl
bmVzcyBDb25mbGljdCIsCisJIkluc3VmZmljaWVudCBTcGFjZSIsCisJIkluc3VmZmljaWVudCBS
b3dzIiwKKwkiSW52YWxpZCBGdW5jdGlvbiIsCisJIkludmFsaWQgUGFyYW1ldGVyIiwKKwkiSW52
YWxpZCBSZWZlcmVuY2UiLAorCSJVbmtub3duIEVycm9yIiwKKwkiVFBFUiBNYWxmdW5jdGlvbiIs
CisJIlRyYW5zYWN0aW9uIEZhaWx1cmUiLAorCSJSZXNwb25zZSBPdmVyZmxvdyIsCisJIkF1dGhv
cml0eSBMb2NrZWQgT3V0IiwKK307CisKK3N0YXRpYyBjb25zdCBjaGFyICpvcGFsX2Vycm9yX3Rv
X2h1bWFuKGludCBlcnJvcikKK3sKKwlpZiAoZXJyb3IgPT0gMHgzZikKKwkJcmV0dXJuICJGYWls
ZWQiOworCisJaWYgKGVycm9yID49IEFSUkFZX1NJWkUob3BhbF9lcnJvcnMpIHx8IGVycm9yIDwg
MCkKKwkJcmV0dXJuICJVbmtub3duIEVycm9yIjsKKworCXJldHVybiBvcGFsX2Vycm9yc1tlcnJv
cl07Cit9CisKKy8qIFVzZXIgSURzIHVzZWQgaW4gdGhlIFRDRyBzdG9yYWdlIFNTQ3MgKi8KK3N0
YXRpYyBjb25zdCB1OCBPUEFMVUlEW11bOF0gPSB7CisJLyogdXNlcnMgKi8KKworCS8qIHNlc3Np
b24gbWFuYWdlbWVudCAgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAs
IDB4MDAsIDB4ZmZ9LAorCS8qIHNwZWNpYWwgInRoaXNTUCIgc3ludGF4ICovCisJeyAweDAwLCAw
eDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAxIH0sCisJLyogQWRtaW5pc3Ry
YXRpdmUgU1AgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDIsIDB4MDUsIDB4MDAsIDB4MDAsIDB4MDAs
IDB4MDEgfSwKKwkvKiBMb2NraW5nIFNQICovCisJeyAweDAwLCAweDAwLCAweDAyLCAweDA1LCAw
eDAwLCAweDAwLCAweDAwLCAweDAyIH0sCisJLyogRU5URVJQUklTRSBMb2NraW5nIFNQICAqLwor
CXsgMHgwMCwgMHgwMCwgMHgwMiwgMHgwNSwgMHgwMCwgMHgwMSwgMHgwMCwgMHgwMSB9LAorCS8q
IGFueWJvZHkgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDksIDB4MDAsIDB4MDAsIDB4MDAs
IDB4MDEgfSwKKwkvKiBTSUQgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDksIDB4MDAsIDB4
MDAsIDB4MDAsIDB4MDYgfSwKKwkvKiBBRE1JTjEgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4
MDksIDB4MDAsIDB4MDEsIDB4MDAsIDB4MDEgfSwKKwkvKiBVU0VSMSAqLworCXsgMHgwMCwgMHgw
MCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMywgMHgwMCwgMHgwMSB9LAorCS8qIFVTRVIyICovCisJ
eyAweDAwLCAweDAwLCAweDAwLCAweDA5LCAweDAwLCAweDAzLCAweDAwLCAweDAyIH0sCisJLyog
UFNJRCB1c2VyICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA5LCAweDAwLCAweDAxLCAweGZm
LCAweDAxIH0sCisJLyogQmFuZE1hc3RlciAwICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA5
LCAweDAwLCAweDAwLCAweDgwLCAweDAxIH0sCisJIC8qIEVyYXNlTWFzdGVyICovCisJeyAweDAw
LCAweDAwLCAweDAwLCAweDA5LCAweDAwLCAweDAwLCAweDg0LCAweDAxIH0sCisKKwkvKiB0YWJs
ZXMgKi8KKworCS8qIExvY2tpbmdfR2xvYmFsUmFuZ2UgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDgs
IDB4MDIsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDEgfSwKKwkvKiBBQ0VfTG9ja2luZ19SYW5nZV9T
ZXRfUmRMb2NrZWQgVUlEICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA4LCAweDAwLCAweDAz
LCAweEUwLCAweDAxIH0sCisJLyogQUNFX0xvY2tpbmdfUmFuZ2VfU2V0X1dyTG9ja2VkIFVJRCAq
LworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOCwgMHgwMCwgMHgwMywgMHhFOCwgMHgwMSB9LAor
CS8qIE1CUiBDb250cm9sICovCisJeyAweDAwLCAweDAwLCAweDA4LCAweDAzLCAweDAwLCAweDAw
LCAweDAwLCAweDAxIH0sCisJLyogU2hhZG93IE1CUiAqLworCXsgMHgwMCwgMHgwMCwgMHgwOCwg
MHgwNCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCB9LAorCS8qIEFVVEhPUklUWV9UQUJMRSAqLwor
CXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMH0sCisJLyog
Q19QSU5fVEFCTEUgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MEIsIDB4MDAsIDB4MDAsIDB4
MDAsIDB4MDB9LAorCS8qIE9QQUwgTG9ja2luZyBJbmZvICovCisJeyAweDAwLCAweDAwLCAweDA4
LCAweDAxLCAweDAwLCAweDAwLCAweDAwLCAweDAxIH0sCisJLyogRW50ZXJwcmlzZSBMb2NraW5n
IEluZm8gKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDgsIDB4MDEsIDB4MDAsIDB4MDAsIDB4MDAsIDB4
MDAgfSwKKworCS8qIENfUElOX1RBQkxFIG9iamVjdCBJRCdzICovCisKKwkvKiBDX1BJTl9NU0lE
ICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDBCLCAweDAwLCAweDAwLCAweDg0LCAweDAyfSwK
KwkvKiBDX1BJTl9TSUQgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MEIsIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDF9LAorCSAvKiBDX1BJTl9BRE1JTjEgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAs
IDB4MEIsIDB4MDAsIDB4MDEsIDB4MDAsIDB4MDF9LAorCisJLyogaGFsZiBVSUQncyAob25seSBm
aXJzdCA0IGJ5dGVzIHVzZWQpICovCisKKwkvKiBIYWxmLVVJRCDigJMgQXV0aG9yaXR5X29iamVj
dF9yZWYgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MEMsIDB4MDUsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4
ZmYgfSwKKwkvKiBIYWxmLVVJRCDigJMgQm9vbGVhbiBBQ0UgKi8KKwl7IDB4MDAsIDB4MDAsIDB4
MDQsIDB4MEUsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYgfSwKKworCS8qIHNwZWNpYWwgdmFsdWUg
Zm9yIG9taXR0ZWQgb3B0aW9uYWwgcGFyYW1ldGVyICovCisKKwkvKiBIRVhGRiBmb3Igb21pdHRl
ZCAqLworCXsgMHhmZiwgMHhmZiwgMHhmZiwgMHhmZiwgMHhmZiwgMHhmZiwgMHhmZiwgMHhmZn0s
Cit9Oworc3RhdGljIGNvbnN0IHNpemVfdCBPUEFMX1VJRF9MRU5HVEggPSA4Oworc3RhdGljIGNv
bnN0IHNpemVfdCBPUEFMX01TSURfS0VZTEVOID0gMTU7CitzdGF0aWMgY29uc3Qgc2l6ZV90IE9Q
QUxfVUlEX0xFTkdUSF9IQUxGID0gNDsKKworCisvKiBFbnVtIHRvIGluZGV4IE9QQUxVSUQgYXJy
YXkgKi8KK2VudW0gT1BBTF9VSUQgeworCS8qIHVzZXJzICovCisJT1BBTF9TTVVJRF9VSUQsCisJ
T1BBTF9USElTU1BfVUlELAorCU9QQUxfQURNSU5TUF9VSUQsCisJT1BBTF9MT0NLSU5HU1BfVUlE
LAorCU9QQUxfRU5URVJQUklTRV9MT0NLSU5HU1BfVUlELAorCU9QQUxfQU5ZQk9EWV9VSUQsCisJ
T1BBTF9TSURfVUlELAorCU9QQUxfQURNSU4xX1VJRCwKKwlPUEFMX1VTRVIxX1VJRCwKKwlPUEFM
X1VTRVIyX1VJRCwKKwlPUEFMX1BTSURfVUlELAorCU9QQUxfRU5URVJQUklTRV9CQU5ETUFTVEVS
MF9VSUQsCisJT1BBTF9FTlRFUlBSSVNFX0VSQVNFTUFTVEVSX1VJRCwKKwkvKiB0YWJsZXMgKi8K
KwlPUEFMX0xPQ0tJTkdSQU5HRV9HTE9CQUwsCisJT1BBTF9MT0NLSU5HUkFOR0VfQUNFX1JETE9D
S0VELAorCU9QQUxfTE9DS0lOR1JBTkdFX0FDRV9XUkxPQ0tFRCwKKwlPUEFMX01CUkNPTlRST0ws
CisJT1BBTF9NQlIsCisJT1BBTF9BVVRIT1JJVFlfVEFCTEUsCisJT1BBTF9DX1BJTl9UQUJMRSwK
KwlPUEFMX0xPQ0tJTkdfSU5GT19UQUJMRSwKKwlPUEFMX0VOVEVSUFJJU0VfTE9DS0lOR19JTkZP
X1RBQkxFLAorCS8qIENfUElOX1RBQkxFIG9iamVjdCBJRCdzICovCisJT1BBTF9DX1BJTl9NU0lE
LAorCU9QQUxfQ19QSU5fU0lELAorCU9QQUxfQ19QSU5fQURNSU4xLAorCS8qIGhhbGYgVUlEJ3Mg
KG9ubHkgZmlyc3QgNCBieXRlcyB1c2VkKSAqLworCU9QQUxfSEFMRl9VSURfQVVUSE9SSVRZX09C
Sl9SRUYsCisJT1BBTF9IQUxGX1VJRF9CT09MRUFOX0FDRSwKKwkvKiBvbWl0dGVkIG9wdGlvbmFs
IHBhcmFtZXRlciAqLworCU9QQUxfVUlEX0hFWEZGLAorfTsKKworLyoKKyAqIFRDRyBTdG9yYWdl
IFNTQyBNZXRob2RzLgorICovCitzdGF0aWMgY29uc3QgdTggT1BBTE1FVEhPRFtdWzhdID0gewor
CS8qIFByb3BlcnRpZXMgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAs
IDB4ZmYsIDB4MDEgfSwKKwkvKiBTVEFSVFNFU1NJT04gKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDAsIDB4MDAsIDB4ZmYsIDB4MDIgfSwKKwkvKiBSZXZlcnQgKi8KKwl7IDB4MDAs
IDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDIsIDB4MDIgfSwKKwkvKiBBY3RpdmF0
ZSAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMiwgMHgwMyB9
LAorCS8qIEVudGVycHJpc2UgR2V0ICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAw
LCAweDAwLCAweDAwLCAweDA2IH0sCisJLyogRW50ZXJwcmlzZSBTZXQgKi8KKwl7IDB4MDAsIDB4
MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDcgfSwKKwkvKiBORVhUICovCisJ
eyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDA4IH0sCisJLyog
RW50ZXJwcmlzZSBBdXRoZW50aWNhdGUgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4
MDAsIDB4MDAsIDB4MDAsIDB4MGMgfSwKKwkvKiBHZXRBQ0wgKi8KKwl7IDB4MDAsIDB4MDAsIDB4
MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MGQgfSwKKwkvKiBHZW5LZXkgKi8KKwl7IDB4
MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MTAgfSwKKwkvKiByZXZl
cnRTUCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgx
MSB9LAorCS8qIEdldCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwg
MHgwMCwgMHgxNiB9LAorCS8qIFNldCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgw
MCwgMHgwMCwgMHgwMCwgMHgxNyB9LAorCS8qIEF1dGhlbnRpY2F0ZSAqLworCXsgMHgwMCwgMHgw
MCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgxYyB9LAorCS8qIFJhbmRvbSAqLwor
CXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMSB9LAorCS8q
IEVyYXNlICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDA4LCAw
eDAzIH0sCit9Oworc3RhdGljIGNvbnN0IHNpemVfdCBPUEFMX01FVEhPRF9MRU5HVEggPSA4Owor
CisvKiBFbnVtIGZvciBpbmRleGluZyB0aGUgT1BBTE1FVEhPRCBhcnJheSAqLworZW51bSBPUEFM
X01FVEhPRCB7CisJT1BBTF9QUk9QRVJUSUVTLAorCU9QQUxfU1RBUlRTRVNTSU9OLAorCU9QQUxf
UkVWRVJULAorCU9QQUxfQUNUSVZBVEUsCisJT1BBTF9FR0VULAorCU9QQUxfRVNFVCwKKwlPUEFM
X05FWFQsCisJT1BBTF9FQVVUSEVOVElDQVRFLAorCU9QQUxfR0VUQUNMLAorCU9QQUxfR0VOS0VZ
LAorCU9QQUxfUkVWRVJUU1AsCisJT1BBTF9HRVQsCisJT1BBTF9TRVQsCisJT1BBTF9BVVRIRU5U
SUNBVEUsCisJT1BBTF9SQU5ET00sCisJT1BBTF9FUkFTRSwKK307CisKK2VudW0gT1BBTF9SRVNQ
T05TRV9UT0tFTiB7CisJT1BBTF9EVEFfVE9LRU5JRF9CWVRFU1RSSU5HID0gMHhlMCwKKwlPUEFM
X0RUQV9UT0tFTklEX1NJTlQgPSAweGUxLAorCU9QQUxfRFRBX1RPS0VOSURfVUlOVCA9IDB4ZTIs
CisJT1BBTF9EVEFfVE9LRU5JRF9UT0tFTiA9IDB4ZTMsIC8qIGFjdHVhbCB0b2tlbiBpcyByZXR1
cm5lZCAqLworCU9QQUxfRFRBX1RPS0VOSURfSU5WQUxJRCA9IDBYMAorfTsKKworZW51bSBPUEFM
X1RPS0VOIHsKKwkvKiBCb29sZWFuICovCisJT1BBTF9UUlVFID0gMHgwMSwKKwlPUEFMX0ZBTFNF
ID0gMHgwMCwKKwlPUEFMX0JPT0xFQU5fRVhQUiA9IDB4MDMsCisJLyogY2VsbGJsb2NrcyAqLwor
CU9QQUxfVEFCTEUgPSAweDAwLAorCU9QQUxfU1RBUlRST1cgPSAweDAxLAorCU9QQUxfRU5EUk9X
ID0gMHgwMiwKKwlPUEFMX1NUQVJUQ09MVU1OID0gMHgwMywKKwlPUEFMX0VORENPTFVNTiA9IDB4
MDQsCisJT1BBTF9WQUxVRVMgPSAweDAxLAorCS8qIGF1dGhvcml0eSB0YWJsZSAqLworCU9QQUxf
UElOID0gMHgwMywKKwkvKiBsb2NraW5nIHRva2VucyAqLworCU9QQUxfUkFOR0VTVEFSVCA9IDB4
MDMsCisJT1BBTF9SQU5HRUxFTkdUSCA9IDB4MDQsCisJT1BBTF9SRUFETE9DS0VOQUJMRUQgPSAw
eDA1LAorCU9QQUxfV1JJVEVMT0NLRU5BQkxFRCA9IDB4MDYsCisJT1BBTF9SRUFETE9DS0VEID0g
MHgwNywKKwlPUEFMX1dSSVRFTE9DS0VEID0gMHgwOCwKKwlPUEFMX0FDVElWRUtFWSA9IDB4MEEs
CisJLyogbG9ja2luZyBpbmZvIHRhYmxlICovCisJT1BBTF9NQVhSQU5HRVMgPSAweDA0LAorCSAv
KiBtYnIgY29udHJvbCAqLworCU9QQUxfTUJSRU5BQkxFID0gMHgwMSwKKwlPUEFMX01CUkRPTkUg
PSAweDAyLAorCS8qIHByb3BlcnRpZXMgKi8KKwlPUEFMX0hPU1RQUk9QRVJUSUVTID0gMHgwMCwK
KwkvKiBhdG9tcyAqLworCU9QQUxfU1RBUlRMSVNUID0gMHhmMCwKKwlPUEFMX0VORExJU1QgPSAw
eGYxLAorCU9QQUxfU1RBUlROQU1FID0gMHhmMiwKKwlPUEFMX0VORE5BTUUgPSAweGYzLAorCU9Q
QUxfQ0FMTCA9IDB4ZjgsCisJT1BBTF9FTkRPRkRBVEEgPSAweGY5LAorCU9QQUxfRU5ET0ZTRVNT
SU9OID0gMHhmYSwKKwlPUEFMX1NUQVJUVFJBTlNBQ1RPTiA9IDB4ZmIsCisJT1BBTF9FTkRUUkFO
U0FDVE9OID0gMHhmQywKKwlPUEFMX0VNUFRZQVRPTSA9IDB4ZmYsCisJT1BBTF9XSEVSRSA9IDB4
MDAsCit9OworCisvKiBVc2VmdWwgdGlueSBhdG9tcy4KKyAqIFVzZWZ1bCBmb3IgdGFibGUgY29s
dW1ucyBldGMKKyAqLworZW51bSBPUEFMX1RJTllfQVRPTSB7CisJT1BBTF9USU5ZX1VJTlRfMDAg
PSAweDAwLAorCU9QQUxfVElOWV9VSU5UXzAxID0gMHgwMSwKKwlPUEFMX1RJTllfVUlOVF8wMiA9
IDB4MDIsCisJT1BBTF9USU5ZX1VJTlRfMDMgPSAweDAzLAorCU9QQUxfVElOWV9VSU5UXzA0ID0g
MHgwNCwKKwlPUEFMX1RJTllfVUlOVF8wNSA9IDB4MDUsCisJT1BBTF9USU5ZX1VJTlRfMDYgPSAw
eDA2LAorCU9QQUxfVElOWV9VSU5UXzA3ID0gMHgwNywKKwlPUEFMX1RJTllfVUlOVF8wOCA9IDB4
MDgsCisJT1BBTF9USU5ZX1VJTlRfMDkgPSAweDA5LAorCU9QQUxfVElOWV9VSU5UXzEwID0gMHgw
YSwKKwlPUEFMX1RJTllfVUlOVF8xMSA9IDB4MGIsCisJT1BBTF9USU5ZX1VJTlRfMTIgPSAweDBj
LAorCU9QQUxfVElOWV9VSU5UXzEzID0gMHgwZCwKKwlPUEFMX1RJTllfVUlOVF8xNCA9IDB4MGUs
CisJT1BBTF9USU5ZX1VJTlRfMTUgPSAweDBmLAorfTsKKworZW51bSBPUEFMX0FUT01fV0lEVEgg
eworCU9QQUxfV0lEVEhfVElOWSwKKwlPUEFMX1dJRFRIX1NIT1JULAorCU9QQUxfV0lEVEhfTUVE
SVVNLAorCU9QQUxfV0lEVEhfTE9ORywKKwlPUEFMX1dJRFRIX1RPS0VOCit9OworCisvKiBMb2Nr
aW5nIHN0YXRlIGZvciBhIGxvY2tpbmcgcmFuZ2UgKi8KK2VudW0gT1BBTF9MT0NLSU5HU1RBVEUg
eworCU9QQUxfTE9DS0lOR19SRUFEV1JJVEUgPSAweDAxLAorCU9QQUxfTE9DS0lOR19SRUFET05M
WSA9IDB4MDIsCisJT1BBTF9MT0NLSU5HX0xPQ0tFRCA9IDB4MDMsCit9OworCisvKgorICogU3Ry
dWN0dXJlcyB0byBidWlsZCBhbmQgZGVjb2RlIHRoZSBPcGFsIFNTQyBtZXNzYWdlcworICogZmll
bGRzIHRoYXQgYXJlIE5PVCByZWFsbHkgbnVtZXJpYyBhcmUgZGVmaW5lZCBhcyB1OFtdIHRvCisg
KiBoZWxwIHJlZHVjZSB0aGUgZW5kaWFubmVzcyBpc3N1ZXMKKyAqLworCisvKiBDb21tIFBhY2tl
dCAoaGVhZGVyKSBmb3IgdHJhbnNtaXNzaW9ucy4gKi8KK3N0cnVjdCBvcGFsX2NvbXBhY2tldCB7
CisJdTMyIHJlc2VydmVkMDsKKwl1OCBleHRlbmRlZENvbUlEWzRdOworCXUzMiBvdXRzdGFuZGlu
Z0RhdGE7CisJdTMyIG1pblRyYW5zZmVyOworCXUzMiBsZW5ndGg7Cit9OworCisvKiBQYWNrZXQg
c3RydWN0dXJlLiAqLworc3RydWN0IG9wYWxfcGFja2V0IHsKKwl1MzIgVFNOOworCXUzMiBIU047
CisJdTMyIHNlcV9udW1iZXI7CisJdTE2IHJlc2VydmVkMDsKKwl1MTYgYWNrX3R5cGU7CisJdTMy
IGFja25vd2xlZGdtZW50OworCXUzMiBsZW5ndGg7Cit9OworCisvKiBEYXRhIHN1YiBwYWNrZXQg
aGVhZGVyICovCitzdHJ1Y3Qgb3BhbF9kYXRhX3N1YnBhY2tldCB7CisJdTggcmVzZXJ2ZWQwWzZd
OworCXUxNiBraW5kOworCXUzMiBsZW5ndGg7Cit9OworCisvKiBoZWFkZXIgb2YgYSByZXNwb25z
ZSAqLworc3RydWN0IG9wYWxfaGVhZGVyIHsKKwlzdHJ1Y3Qgb3BhbF9jb21wYWNrZXQgY3A7CisJ
c3RydWN0IG9wYWxfcGFja2V0IHBrdDsKKwlzdHJ1Y3Qgb3BhbF9kYXRhX3N1YnBhY2tldCBzdWJw
a3Q7Cit9OworCisjZGVmaW5lIEZDX1RQRVIgICAgICAgMHgwMDAxCisjZGVmaW5lIEZDX0xPQ0tJ
TkcgICAgMHgwMDAyCisjZGVmaW5lIEZDX0dFT01FVFJZICAgMHgwMDAzCisjZGVmaW5lIEZDX0VO
VEVSUFJJU0UgMHgwMTAwCisjZGVmaW5lIEZDX0RBVEFTVE9SRSAgMHgwMjAyCisjZGVmaW5lIEZD
X1NJTkdMRVVTRVIgMHgwMjAxCisjZGVmaW5lIEZDX09QQUxWMTAwICAgMHgwMjAwCisjZGVmaW5l
IEZDX09QQUxWMjAwICAgMHgwMjAzCisKKy8qCisgKiBUaGUgRGlzY292ZXJ5IDAgSGVhZGVyLiBB
cyBkZWZpbmVkIGluCisgKiBPcGFsIFNTQyBEb2N1bWVudGF0aW9uCisgKi8KK3N0cnVjdCBkMF9o
ZWFkZXIgeworCXUzMiBsZW5ndGg7IC8qIHRoZSBsZW5ndGggb2YgdGhlIGhlYWRlciA0OCBpbiAy
LjAwLjEwMCAqLworCXUzMiByZXZpc2lvbjsgLyoqPCByZXZpc2lvbiBvZiB0aGUgaGVhZGVyIDEg
aW4gMi4wMC4xMDAgKi8KKwl1MzIgcmVzZXJ2ZWQwMTsKKwl1MzIgcmVzZXJ2ZWQwMjsKKwkvKgor
CSAqIHRoZSByZW1haW5kZXIgb2YgdGhlIHN0cnVjdHVyZSBpcyB2ZW5kb3Igc3BlY2lmaWMgYW5k
IHdpbGwgbm90IGJlCisJICogYWRkcmVzc2VkIG5vdworCSAqLworCXU4IGlnbm9yZWRbMzJdOwor
fTsKKworLyoKKyAqIFRQZXIgRmVhdHVyZSBEZXNjcmlwdG9yLiBDb250YWlucyBmbGFncyBpbmRp
Y2F0aW5nIHN1cHBvcnQgZm9yIHRoZQorICogVFBlciBmZWF0dXJlcyBkZXNjcmliZWQgaW4gdGhl
IE9QQUwgc3BlY2lmaWNhdGlvbi4gVGhlIG5hbWVzIG1hdGNoIHRoZQorICogT1BBTCB0ZXJtaW5v
bG9neQorICoKKyAqIGNvZGUgPT0gMHgwMDEgaW4gMi4wMC4xMDAKKyAqLworc3RydWN0IGQwX3Rw
ZXJfZmVhdHVyZXMgeworCS8qCisJICogc3VwcG9ydGVkX2ZlYXR1cmVzIGJpdHM6CisJICogYml0
IDc6IHJlc2VydmVkCisJICogYml0IDY6IGNvbSBJRCBtYW5hZ2VtZW50CisJICogYml0IDU6IHJl
c2VydmVkCisJICogYml0IDQ6IHN0cmVhbWluZyBzdXBwb3J0CisJICogYml0IDM6IGJ1ZmZlciBt
YW5hZ2VtZW50CisJICogYml0IDI6IEFDSy9OQUNLCisJICogYml0IDE6IGFzeW5jCisJICogYml0
IDA6IHN5bmMKKwkgKi8KKwl1OCBzdXBwb3J0ZWRfZmVhdHVyZXM7CisJLyoKKwkgKiBieXRlcyA1
IHRocm91Z2ggMTUgYXJlIHJlc2VydmVkLCBidXQgd2UgcmVwcmVzZW50IHRoZSBmaXJzdCAzIGFz
CisJICogdTggdG8ga2VlcCB0aGUgb3RoZXIgdHdvIDMyYml0cyBpbnRlZ2VycyBhbGlnbmVkLgor
CSAqLworCXU4IHJlc2VydmVkMDFbM107CisJdTMyIHJlc2VydmVkMDI7CisJdTMyIHJlc2VydmVk
MDM7Cit9OworCisvKgorICogTG9ja2luZyBGZWF0dXJlIERlc2NyaXB0b3IuIENvbnRhaW5zIGZs
YWdzIGluZGljYXRpbmcgc3VwcG9ydCBmb3IgdGhlCisgKiBsb2NraW5nIGZlYXR1cmVzIGRlc2Ny
aWJlZCBpbiB0aGUgT1BBTCBzcGVjaWZpY2F0aW9uLiBUaGUgbmFtZXMgbWF0Y2ggdGhlCisgKiBP
UEFMIHRlcm1pbm9sb2d5CisgKgorICogY29kZSA9PSAweDAwMDIgaW4gMi4wMC4xMDAKKyAqLwor
c3RydWN0IGQwX2xvY2tpbmdfZmVhdHVyZXMgeworCS8qCisJICogc3VwcG9ydGVkX2ZlYXR1cmVz
IGJpdHM6CisJICogYml0cyA2LTc6IHJlc2VydmVkCisJICogYml0IDU6IE1CUiBkb25lCisJICog
Yml0IDQ6IE1CUiBlbmFibGVkCisJICogYml0IDM6IG1lZGlhIGVuY3J5cHRpb24KKwkgKiBiaXQg
MjogbG9ja2VkCisJICogYml0IDE6IGxvY2tpbmcgZW5hYmxlZAorCSAqIGJpdCAwOiBsb2NraW5n
IHN1cHBvcnRlZAorCSAqLworCXU4IHN1cHBvcnRlZF9mZWF0dXJlczsKKwkvKgorCSAqIGJ5dGVz
IDUgdGhyb3VnaCAxNSBhcmUgcmVzZXJ2ZWQsIGJ1dCB3ZSByZXByZXNlbnQgdGhlIGZpcnN0IDMg
YXMKKwkgKiB1OCB0byBrZWVwIHRoZSBvdGhlciB0d28gMzJiaXRzIGludGVnZXJzIGFsaWduZWQu
CisJICovCisJdTggcmVzZXJ2ZWQwMVszXTsKKwl1MzIgcmVzZXJ2ZWQwMjsKKwl1MzIgcmVzZXJ2
ZWQwMzsKK307CisKKy8qCisgKiBHZW9tZXRyeSBGZWF0dXJlIERlc2NyaXB0b3IuIENvbnRhaW5z
IGZsYWdzIGluZGljYXRpbmcgc3VwcG9ydCBmb3IgdGhlCisgKiBnZW9tZXRyeSBmZWF0dXJlcyBk
ZXNjcmliZWQgaW4gdGhlIE9QQUwgc3BlY2lmaWNhdGlvbi4gVGhlIG5hbWVzIG1hdGNoIHRoZQor
ICogT1BBTCB0ZXJtaW5vbG9neQorICoKKyAqIGNvZGUgPT0gMHgwMDAzIGluIDIuMDAuMTAwCisg
Ki8KK3N0cnVjdCBkMF9nZW9tZXRyeV9mZWF0dXJlcyB7CisJLyoKKwkgKiBza2lwIDMyIGJpdHMg
ZnJvbSBoZWFkZXIsIG5lZWRlZCB0byBhbGlnbiB0aGUgc3RydWN0IHRvIDY0IGJpdHMuCisJICov
CisJdTggaGVhZGVyWzRdOworCS8qCisJICogcmVzZXJ2ZWQwMToKKwkgKiBiaXRzIDEtNjogcmVz
ZXJ2ZWQKKwkgKiBiaXQgMDogYWxpZ24KKwkgKi8KKwl1OCByZXNlcnZlZDAxOworCXU4IHJlc2Vy
dmVkMDJbN107CisJdTMyIGxvZ2ljYWxfYmxvY2tfc2l6ZTsKKwl1NjQgYWxpZ25tZW50X2dyYW51
bGFyaXR5OworCXU2NCBsb3dlc3RfYWxpZ25lZF9sYmE7Cit9OworCisvKgorICogRW50ZXJwcmlz
ZSBTU0MgRmVhdHVyZQorICoKKyAqIGNvZGUgPT0gMHgwMTAwCisgKi8KK3N0cnVjdCBkMF9lbnRl
cnByaXNlX3NzYyB7CisJdTE2IGJhc2VDb21JRDsKKwl1MTYgbnVtQ29tSURzOworCS8qIHJhbmdl
X2Nyb3NzaW5nOgorCSAqIGJpdHMgMS02OiByZXNlcnZlZAorCSAqIGJpdCAwOiByYW5nZSBjcm9z
c2luZworCSAqLworCXU4IHJhbmdlX2Nyb3NzaW5nOworCXU4IHJlc2VydmVkMDE7CisJdTE2IHJl
c2VydmVkMDI7CisJdTMyIHJlc2VydmVkMDM7CisJdTMyIHJlc2VydmVkMDQ7Cit9OworCisvKgor
ICogT3BhbCBWMSBmZWF0dXJlCisgKgorICogY29kZSA9PSAweDAyMDAKKyAqLworc3RydWN0IGQw
X29wYWxfdjEwMCB7CisJdTE2IGJhc2VDb21JRDsKKwl1MTYgbnVtQ29tSURzOworfTsKKworLyoK
KyAqIFNpbmdsZSBVc2VyIE1vZGUgZmVhdHVyZQorICoKKyAqIGNvZGUgPT0gMHgwMjAxCisgKi8K
K3N0cnVjdCBkMF9zaW5nbGVfdXNlcl9tb2RlIHsKKwl1MzIgbnVtX2xvY2tpbmdfb2JqZWN0czsK
KwkvKiByZXNlcnZlZDAxOgorCSAqIGJpdCAwOiBhbnkKKwkgKiBiaXQgMTogYWxsCisJICogYml0
IDI6IHBvbGljeQorCSAqIGJpdHMgMy03OiByZXNlcnZlZAorCSAqLworCXU4IHJlc2VydmVkMDE7
CisJdTggcmVzZXJ2ZWQwMjsKKwl1MTYgcmVzZXJ2ZWQwMzsKKwl1MzIgcmVzZXJ2ZWQwNDsKK307
CisKKy8qCisgKiBBZGRpdG9uYWwgRGF0YXN0b3JlcyBmZWF0dXJlCisgKgorICogY29kZSA9PSAw
eDAyMDIKKyAqLworc3RydWN0IGQwX2RhdGFzdG9yZV90YWJsZSB7CisJdTE2IHJlc2VydmVkMDE7
CisJdTE2IG1heF90YWJsZXM7CisJdTMyIG1heF9zaXplX3RhYmxlczsKKwl1MzIgdGFibGVfc2l6
ZV9hbGlnbm1lbnQ7Cit9OworCisvKgorICogT1BBTCAyLjAgZmVhdHVyZQorICoKKyAqIGNvZGUg
PT0gMHgwMjAzCisgKi8KK3N0cnVjdCBkMF9vcGFsX3YyMDAgeworCXUxNiBiYXNlQ29tSUQ7CisJ
dTE2IG51bUNvbUlEczsKKwkvKiByYW5nZV9jcm9zc2luZzoKKwkgKiBiaXRzIDEtNjogcmVzZXJ2
ZWQKKwkgKiBiaXQgMDogcmFuZ2UgY3Jvc3NpbmcKKwkgKi8KKwl1OCByYW5nZV9jcm9zc2luZzsK
KwkvKiBudW1fbG9ja2luZ19hZG1pbl9hdXRoOgorCSAqIG5vdCBhbGlnbmVkIHRvIDE2IGJpdHMs
IHNvIHVzZSB0d28gdTguCisJICogc3RvcmVkIGluIGJpZyBlbmRpYW46CisJICogMDogTVNCCisJ
ICogMTogTFNCCisJICovCisJdTggbnVtX2xvY2tpbmdfYWRtaW5fYXV0aFsyXTsKKwkvKiBudW1f
bG9ja2luZ191c2VyX2F1dGg6CisJICogbm90IGFsaWduZWQgdG8gMTYgYml0cywgc28gdXNlIHR3
byB1OC4KKwkgKiBzdG9yZWQgaW4gYmlnIGVuZGlhbjoKKwkgKiAwOiBNU0IKKwkgKiAxOiBMU0IK
KwkgKi8KKwl1OCBudW1fbG9ja2luZ191c2VyX2F1dGhbMl07CisJdTggaW5pdGlhbFBJTjsKKwl1
OCByZXZlcnRlZFBJTjsKKwl1OCByZXNlcnZlZDAxOworCXUzMiByZXNlcnZlZDAyOworfTsKKwor
LyogVW5pb24gb2YgZmVhdHVyZXMgdXNlZCB0byBwYXJzZSB0aGUgZGlzY292ZXJ5IDAgcmVzcG9u
c2UgKi8KK3N0cnVjdCBkMF9mZWF0dXJlcyB7CisJdTE2IGNvZGU7CisJLyoKKwkgKiByX3ZlcnNp
b24gYml0czoKKwkgKiBiaXRzIDQtNzogdmVyc2lvbgorCSAqIGJpdHMgMC0zOiByZXNlcnZlZAor
CSAqLworCXU4IHJfdmVyc2lvbjsKKwl1OCBsZW5ndGg7CisJdTggZmVhdHVyZXNbXTsKK307CisK
K3N0cnVjdCBrZXkgKnJlcXVlc3RfdXNlcl9rZXkoY29uc3QgY2hhciAqbWFzdGVyX2Rlc2MsIGNv
bnN0IHU4ICoqbWFzdGVyX2tleSwKKwkJCSAgICAgc2l6ZV90ICptYXN0ZXJfa2V5bGVuKTsKKwor
I2VuZGlmIC8qIF9OVk1FX09QQUxfSU5URVJOQUxfSCAqLwpkaWZmIC0tZ2l0IGEvbGliL3NlZC1v
cGFsX2tleS5jIGIvbGliL3NlZC1vcGFsX2tleS5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4
IDAwMDAwMDAuLjBiNGRlMDEKLS0tIC9kZXYvbnVsbAorKysgYi9saWIvc2VkLW9wYWxfa2V5LmMK
QEAgLTAsMCArMSw0NiBAQAorLyoKKyAqIENvcHlyaWdodCDCqSAyMDE2IEludGVsIENvcnBvcmF0
aW9uCisgKgorICogUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2Us
IHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEKKyAqIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQg
YXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksCisgKiB0byBk
ZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91
dCBsaW1pdGF0aW9uCisgKiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwg
cHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwKKyAqIGFuZC9vciBzZWxsIGNvcGllcyBv
ZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZQorICogU29m
dHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29u
ZGl0aW9uczoKKyAqCisgKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJt
aXNzaW9uIG5vdGljZSAoaW5jbHVkaW5nIHRoZSBuZXh0CisgKiBwYXJhZ3JhcGgpIHNoYWxsIGJl
IGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlCisg
KiBTb2Z0d2FyZS4KKyAqCisgKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lU
SE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgorICogSU1QTElFRCwgSU5DTFVE
SU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFks
CisgKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5U
LiAgSU4gTk8gRVZFTlQgU0hBTEwKKyAqIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJT
IEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSCisgKiBMSUFCSUxJVFks
IFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJ
U0lORworICogRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUg
T1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUworICogSU4gVEhFIFNPRlRXQVJFLgorICoKKyAq
IEF1dGhvcjoKKyAqICAgIFJhZmFlbCBBbnRvZ25vbGxpIDxyYWZhZWwuYW50b2dub2xsaUBpbnRl
bC5jb20+CisgKi8KKworI2luY2x1ZGUgPGxpbnV4L2tleS5oPgorI2luY2x1ZGUgInNlZC1vcGFs
X2ludGVybmFsLmgiCisKK3N0cnVjdCBrZXkgKnJlcXVlc3RfdXNlcl9rZXkoY29uc3QgY2hhciAq
bWFzdGVyX2Rlc2MsIGNvbnN0IHU4ICoqbWFzdGVyX2tleSwKKwkJCSAgICAgc2l6ZV90ICptYXN0
ZXJfa2V5bGVuKQoreworCWNvbnN0IHN0cnVjdCB1c2VyX2tleV9wYXlsb2FkICp1cGF5bG9hZDsK
KwlzdHJ1Y3Qga2V5ICp1a2V5OworCisJdWtleSA9IHJlcXVlc3Rfa2V5KCZrZXlfdHlwZV91c2Vy
LCBtYXN0ZXJfZGVzYywgTlVMTCk7CisJaWYgKElTX0VSUih1a2V5KSkKKwkJZ290byBlcnJvcjsK
KworCWRvd25fcmVhZCgmdWtleS0+c2VtKTsKKwl1cGF5bG9hZCA9IHVzZXJfa2V5X3BheWxvYWQo
dWtleSk7CisJKm1hc3Rlcl9rZXkgPSB1cGF5bG9hZC0+ZGF0YTsKKwkqbWFzdGVyX2tleWxlbiA9
IHVwYXlsb2FkLT5kYXRhbGVuOworZXJyb3I6CisJcmV0dXJuIHVrZXk7Cit9CmRpZmYgLS1naXQg
YS9saWIvc2VkLmMgYi9saWIvc2VkLmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAw
MC4uNzhmOGJhMwotLS0gL2Rldi9udWxsCisrKyBiL2xpYi9zZWQuYwpAQCAtMCwwICsxLDI1MCBA
QAorI2luY2x1ZGUgPGxpbnV4L2Jsa2Rldi5oPgorI2luY2x1ZGUgPGxpbnV4L3NlZC5oPgorI2lu
Y2x1ZGUgPGxpbnV4L3NlZC1vcGFsLmg+CisKKyNpZm5kZWYgQ09ORklHX1NFRF9PUEFMCitzdGF0
aWMgaW50IHNlZF9vcGFsX3NhdmUoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNl
ZF9rZXkgKnNlZCkKKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQorc3RhdGljIGludCBzZWRfb3Bh
bF9sb2NrX3VubG9jayhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAq
a2V5KQorCXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9CitzdGF0aWMgaW50IHNlZF9vcGFsX3Rha2Vf
b3duZXJzaGlwKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkp
CisJeyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KK3N0YXRpYyBpbnQgc2VkX29wYWxfYWN0aXZhdGVf
bHNwKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCisJeyBy
ZXR1cm4gLUVPUE5PVFNVUFA7IH0KK3N0YXRpYyBpbnQgc2VkX29wYWxfc2V0X3B3KHN0cnVjdCBi
bG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCisJeyByZXR1cm4gLUVPUE5P
VFNVUFA7IH0KK3N0YXRpYyBpbnQgc2VkX29wYWxfYWN0aXZhdGVfdXNlcihzdHJ1Y3QgYmxvY2tf
ZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQorCXsgcmV0dXJuIC1FT1BOT1RTVVBQ
OyB9CitzdGF0aWMgaW50IHNlZF9vcGFsX3JldmVydHRwZXIoc3RydWN0IGJsb2NrX2RldmljZSAq
YmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQorc3Rh
dGljIGludCBzZWRfb3BhbF9zZXR1cF9sb2NraW5nX3JhbmdlKHN0cnVjdCBibG9ja19kZXZpY2Ug
KmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCisJeyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KK3N0
YXRpYyBpbnQgc2VkX29wYWxfYWRkdXNlcl90b19scihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2
LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQorCXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9CitzdGF0aWMg
aW50IHNlZF9vcGFsX2RvX21icihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2Vk
X2tleSAqa2V5KQorCXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9CitzdGF0aWMgaW50IHNlZF9vcGFs
X2VyYXNlX2xyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkp
CisJeyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KKworI2Vsc2UKKworc3RhdGljIGlubGluZSBpbnQg
YmRldl9zZWNfY2FwYWJsZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2KQoreworCXJldHVybiAh
KCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8CisJCSAh
YmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcyk7CisKK30KKworc3RhdGljIGludCBzZWRfb3Bh
bF9zYXZlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7
CisJaWYgKGJkZXZfc2VjX2NhcGFibGUoYmRldikpCisJICAgIHJldHVybiBvcGFsX3NhdmUoYmRl
diwga2V5KTsKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisKK3N0YXRpYyBpbnQgc2VkX29wYWxf
bG9ja191bmxvY2soc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtl
eSkKK3sKKworCWlmIChiZGV2X3NlY19jYXBhYmxlKGJkZXYpKQorCQlyZXR1cm4gb3BhbF9sb2Nr
X3VubG9jayhiZGV2LCBrZXkpOworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworc3RhdGljIGlu
dCBzZWRfb3BhbF90YWtlX293bmVyc2hpcChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LAorCQkJ
CSAgIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlpZiAoYmRldl9zZWNfY2FwYWJsZShiZGV2
KSkKKwkJcmV0dXJuIG9wYWxfdGFrZV9vd25lcnNoaXAoYmRldiwga2V5KTsKKwlyZXR1cm4gLUVP
UE5PVFNVUFA7Cit9CisKK3N0YXRpYyBpbnQgc2VkX29wYWxfYWN0aXZhdGVfbHNwKHN0cnVjdCBi
bG9ja19kZXZpY2UgKmJkZXYsCisJCQkJIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlpZiAo
YmRldl9zZWNfY2FwYWJsZShiZGV2KSkKKwkJcmV0dXJuIG9wYWxfYWN0aXZhdGVfbHNwKGJkZXYs
IGtleSk7CisJcmV0dXJuIC1FT1BOT1RTVVBQOworfQorCitzdGF0aWMgaW50IHNlZF9vcGFsX3Nl
dF9wdyhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LAorCQkJICAgc3RydWN0IHNlZF9rZXkgKmtl
eSkKK3sKKwlpZiAoYmRldl9zZWNfY2FwYWJsZShiZGV2KSkKKwkJcmV0dXJuIG9wYWxfc2V0X25l
d19wdyhiZGV2LCBrZXkpOworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworc3RhdGljIGludCBz
ZWRfb3BhbF9hY3RpdmF0ZV91c2VyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJCQkJICBz
dHJ1Y3Qgc2VkX2tleSAqa2V5KQoreworCWlmIChiZGV2X3NlY19jYXBhYmxlKGJkZXYpKQorCQly
ZXR1cm4gb3BhbF9hY3RpdmF0ZV91c2VyKGJkZXYsIGtleSk7CisJcmV0dXJuIC1FT1BOT1RTVVBQ
OworfQorCitzdGF0aWMgaW50IHNlZF9vcGFsX3JldmVydHRwZXIoc3RydWN0IGJsb2NrX2Rldmlj
ZSAqYmRldiwKKwkJCSAgICAgICBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQoreworCWlmIChiZGV2X3Nl
Y19jYXBhYmxlKGJkZXYpKQorCQlyZXR1cm4gb3BhbF9yZXZlcnR0cGVyKGJkZXYsIGtleSk7CisJ
cmV0dXJuIC1FT1BOT1RTVVBQOworfQorCitzdGF0aWMgaW50IHNlZF9vcGFsX3NldHVwX2xyKHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJCQkgICAgIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7
CisKKwlpZiAoYmRldl9zZWNfY2FwYWJsZShiZGV2KSkKKwkJcmV0dXJuIG9wYWxfc2V0dXBfbG9j
a2luZ19yYW5nZShiZGV2LCBrZXkpOworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworc3RhdGlj
IGludCBzZWRfb3BhbF9hZGR1c2VyX3RvX2xyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJ
CQkgICAgIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlpZiAoYmRldl9zZWNfY2FwYWJsZShi
ZGV2KSkKKwkJcmV0dXJuIG9wYWxfYWRkX3VzZXJfdG9fbHIoYmRldiwga2V5KTsKKwlyZXR1cm4g
LUVPUE5PVFNVUFA7Cit9CisKK3N0YXRpYyBpbnQgc2VkX29wYWxfZG9fbWJyKHN0cnVjdCBibG9j
a19kZXZpY2UgKmJkZXYsCisJCQkgICBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQoreworCisJaWYgKGJk
ZXZfc2VjX2NhcGFibGUoYmRldikpCisJCXJldHVybiBvcGFsX2VuYWJsZV9kaXNhYmxlX3NoYWRv
d19tYnIoYmRldiwga2V5KTsKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisKK3N0YXRpYyBpbnQg
c2VkX29wYWxfZXJhc2VfbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKKwkJCSAgICAgc3Ry
dWN0IHNlZF9rZXkgKmtleSkKK3sKKwlpZiAoYmRldl9zZWNfY2FwYWJsZShiZGV2KSkKKwkJcmV0
dXJuIG9wYWxfZXJhc2VfbG9ja2luZ19yYW5nZShiZGV2LCBrZXkpOworCXJldHVybiAtRU9QTk9U
U1VQUDsKK30KKyNlbmRpZgorCitpbnQgc2VkX3NhdmUoc3RydWN0IGJsb2NrX2RldmljZSAqYmRl
diwgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKworCXN3aXRjaCAoa2V5LT5zZWRfdHlwZSkgewor
CWNhc2UgT1BBTF9MT0NLX1VOTE9DSzoKKwkJcmV0dXJuIHNlZF9vcGFsX3NhdmUoYmRldiwga2V5
KTsKKwl9CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisKK2ludCBzZWRfbG9ja191bmxvY2so
c3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKworCXN3
aXRjaCAoa2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BBTF9MT0NLX1VOTE9DSzoKKwkJcmV0dXJu
IHNlZF9vcGFsX2xvY2tfdW5sb2NrKGJkZXYsIGtleSk7CisJfQorCisJcmV0dXJuIC1FT1BOT1RT
VVBQOworfQorCitpbnQgc2VkX3Rha2Vfb3duZXJzaGlwKHN0cnVjdCBibG9ja19kZXZpY2UgKmJk
ZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsK
KwljYXNlIE9QQUw6CisJCXJldHVybiBzZWRfb3BhbF90YWtlX293bmVyc2hpcChiZGV2LCBrZXkp
OworCX0KKworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworaW50IHNlZF9hY3RpdmF0ZV9sc3Ao
c3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKworCXN3
aXRjaCAoa2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BBTDoKKwkJcmV0dXJuIHNlZF9vcGFsX2Fj
dGl2YXRlX2xzcChiZGV2LCBrZXkpOworCX0KKworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKwor
aW50IHNlZF9zZXRfcHcoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkg
KmtleSkKK3sKKworCXN3aXRjaCAoa2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BBTF9QVzoKKwkJ
cmV0dXJuIHNlZF9vcGFsX3NldF9wdyhiZGV2LCBrZXkpOworCX0KKworCXJldHVybiAtRU9QTk9U
U1VQUDsKK30KKworaW50IHNlZF9hY3RpdmF0ZV91c2VyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJk
ZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsK
KwljYXNlIE9QQUxfQUNUX1VTUjoKKwkJcmV0dXJuIHNlZF9vcGFsX2FjdGl2YXRlX3VzZXIoYmRl
diwga2V5KTsKKwl9CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisKK2ludCBzZWRfcmV2ZXJ0
dHBlcihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQorewor
CisJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7CisJY2FzZSBPUEFMOgorCQlyZXR1cm4gc2VkX29w
YWxfcmV2ZXJ0dHBlcihiZGV2LCBrZXkpOworCX0KKworCXJldHVybiAtRU9QTk9UU1VQUDsKK30K
KworaW50IHNlZF9zZXR1cF9sb2NraW5nX3JhbmdlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYs
IHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsKKwlj
YXNlIE9QQUxfTFJfU0VUVVA6CisJCXJldHVybiBzZWRfb3BhbF9zZXR1cF9scihiZGV2LCBrZXkp
OworCX0KKworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworaW50IHNlZF9hZGR1c2VyX3RvX2xy
KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlz
d2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsKKwljYXNlIE9QQUxfTE9DS19VTkxPQ0s6CisJCXJldHVy
biBzZWRfb3BhbF9hZGR1c2VyX3RvX2xyKGJkZXYsIGtleSk7CisJfQorCisJcmV0dXJuIC1FT1BO
T1RTVVBQOworfQorCitpbnQgc2VkX2RvX21icihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBz
dHJ1Y3Qgc2VkX2tleSAqa2V5KQoreworCisJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7CisJY2Fz
ZSBPUEFMX01CUl9EQVRBOgorCQlyZXR1cm4gc2VkX29wYWxfZG9fbWJyKGJkZXYsIGtleSk7CisJ
fQorCisJcmV0dXJuIC1FT1BOT1RTVVBQOworfQorCitpbnQgc2VkX2VyYXNlX2xyKHN0cnVjdCBi
bG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlzd2l0Y2ggKGtl
eS0+c2VkX3R5cGUpIHsKKwljYXNlIE9QQUw6CisJCXJldHVybiBzZWRfb3BhbF9lcmFzZV9scihi
ZGV2LCBrZXkpOworCX0KKworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KLS0gCjIuNy40CgoKX19f
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KTGludXgtbnZtZSBt
YWlsaW5nIGxpc3QKTGludXgtbnZtZUBsaXN0cy5pbmZyYWRlYWQub3JnCmh0dHA6Ly9saXN0cy5p
bmZyYWRlYWQub3JnL21haWxtYW4vbGlzdGluZm8vbGludXgtbnZtZQo=

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 2/7] lib: Add Sed-opal library
@ 2016-11-16 23:17   ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)


This patch implements the necessary logic to bring an Opal
enabled drive out of a factory-enabled into a working
Opal state.

This patch set also enables logic to save a password to
be replayed during a resume from suspend. The key can be
saved in the driver or in the Kernel's Key managment.

Signed-off-by: Scott Bauer <scott.bauer at intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli at intel.com>
---
 lib/sed-opal.c          | 3338 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/sed-opal_internal.h |  587 +++++++++
 lib/sed-opal_key.c      |   46 +
 lib/sed.c               |  250 ++++
 4 files changed, 4221 insertions(+)
 create mode 100644 lib/sed-opal.c
 create mode 100644 lib/sed-opal_internal.h
 create mode 100644 lib/sed-opal_key.c
 create mode 100644 lib/sed.c

diff --git a/lib/sed-opal.c b/lib/sed-opal.c
new file mode 100644
index 0000000..3ce1126
--- /dev/null
+++ b/lib/sed-opal.c
@@ -0,0 +1,3338 @@
+/*
+ * Copyright ? 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rafael Antognolli <rafael.antognolli at intel.com>
+ *    Scott  Bauer      <scott.bauer at intel.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/sed-opal.h>
+#include <linux/sed.h>
+#include <linux/sed-opal.h>
+#include <linux/string.h>
+
+#include "sed-opal_internal.h"
+
+#define IO_BUFFER_LENGTH 2048
+
+#define MAX_TOKS 64
+
+struct opal_cmd {
+	struct block_device *bdev;
+	sec_cb *cb;
+	void *cb_data;
+
+	size_t pos;
+	u8 cmd_buf[IO_BUFFER_LENGTH * 2];
+	u8 resp_buf[IO_BUFFER_LENGTH * 2];
+	u8 *cmd;
+	u8 *resp;
+};
+
+/*
+ * On the parsed response, we don't store again the toks that are already
+ * stored in the response buffer. Instead, for each token, we just store a
+ * pointer to the position in the buffer where the token starts, and the size
+ * of the token in bytes.
+ */
+struct opal_resp_tok {
+	const u8 *pos;
+	size_t len;
+	enum OPAL_RESPONSE_TOKEN type;
+	enum OPAL_ATOM_WIDTH width;
+	union {
+		u64 u;
+		s64 s;
+	} stored;
+};
+
+/*
+ * From the response header it's not possible to know how many tokens there are
+ * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
+ * if we start dealing with messages that have more than that, we can increase
+ * this number. This is done to avoid having to make two passes through the
+ * response, the first one counting how many tokens we have and the second one
+ * actually storing the positions.
+ */
+struct parsed_resp {
+	int num;
+	struct opal_resp_tok toks[MAX_TOKS];
+};
+
+struct opal_dev;
+
+typedef void (*opal_cb)(int error, struct opal_dev *dev);
+
+typedef int (*opal_step)(struct opal_dev *dev);
+
+struct opal_completion {
+	struct completion cmd_completion;
+	int completion_status;
+};
+
+struct opal_dev {
+	struct block_device *bdev;
+	struct opal_completion *completion;
+	struct opal_lock_unlock lkul;
+	const opal_step *funcs;
+	struct work_struct opal_send_work;
+	struct work_struct opal_recv_work;
+	void **func_data;
+	bool resume_from_suspend;
+	struct opal_suspend_unlk *resume_data;
+	size_t num_func_data;
+	atomic_t in_use;
+	sector_t start;
+	sector_t length;
+	u8 lr;
+	u8 key_type;
+	u8 key_name[OPAL_KEY_MAX];
+	size_t key_name_len;
+	u8 key[OPAL_KEY_MAX];
+	size_t key_len;
+	u16 comID;
+	u32 HSN;
+	u32 TSN;
+	u64 align;
+	u64 lowest_lba;
+	struct list_head node;
+	char disk_name[DISK_NAME_LEN];
+	int state;
+
+	struct opal_cmd cmd;
+	struct parsed_resp parsed;
+
+	size_t prev_d_len;
+	void *prev_data;
+
+	sec_cb *final_cb;
+	void *final_cb_data;
+	opal_step error_cb;
+	void *error_cb_data;
+	opal_cb oper_cb;
+};
+
+LIST_HEAD(opal_list);
+DEFINE_SPINLOCK(list_spinlock);
+
+static void print_buffer(const u8 *ptr, u32 length)
+{
+#ifdef DEBUG
+	print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
+	pr_debug("\n");
+#endif
+}
+
+#define TPER_SYNC_SUPPORTED BIT(0)
+
+static bool check_tper(const void *data)
+{
+	const struct d0_tper_features *tper = data;
+	u8 flags = tper->supported_features;
+
+	if (!(flags & TPER_SYNC_SUPPORTED)) {
+		pr_err("TPer sync not supported. flags = %d\n",
+		       tper->supported_features);
+		return false;
+	}
+
+	return true;
+}
+
+static bool check_SUM(const void *data)
+{
+	const struct d0_single_user_mode *sum = data;
+	u32 nlo = be32_to_cpu(sum->num_locking_objects);
+
+	if (nlo == 0) {
+		pr_err("Need at least one locking object.\n");
+		return false;
+	}
+
+	pr_debug("Number of locking objects: %d\n", nlo);
+
+	return true;
+}
+
+static u16 get_comID_v100(const void *data)
+{
+	const struct d0_opal_v100 *v100 = data;
+
+	return be16_to_cpu(v100->baseComID);
+}
+
+static u16 get_comID_v200(const void *data)
+{
+	const struct d0_opal_v200 *v200 = data;
+
+	return be16_to_cpu(v200->baseComID);
+}
+
+static void opal_send_cb_cont(int error, void *data)
+{
+	struct opal_dev *dev = data;
+	size_t buflen = IO_BUFFER_LENGTH;
+	void *buffer = dev->cmd.resp;
+	struct opal_header *hdr = buffer;
+
+	pr_debug("%s: Sent OPAL command: error=%d, outstanding=%d, minTransfer=%d\n",
+	       dev->disk_name, error, hdr->cp.outstandingData,
+	       hdr->cp.minTransfer);
+
+	if (error || hdr->cp.outstandingData == 0 ||
+	    hdr->cp.minTransfer != 0) {
+		if (dev->cmd.cb)
+			dev->cmd.cb(error, dev->cmd.cb_data);
+		return;
+	}
+
+	memset(buffer, 0, buflen);
+	schedule_work(&dev->opal_recv_work);
+}
+
+static void opal_send_cb(int error, void *data)
+{
+	struct opal_dev *dev = data;
+	size_t buflen = IO_BUFFER_LENGTH;
+	void *buffer = dev->cmd.resp;
+
+	if (error) {
+		if (dev->cmd.cb)
+			dev->cmd.cb(error, dev->cmd.cb_data);
+		return;
+	}
+
+	memset(buffer, 0, buflen);
+	schedule_work(&dev->opal_recv_work);
+}
+
+static inline void get_data_ops(struct opal_dev *dev, const struct sec_ops **ops,
+				void **data)
+{
+	if (dev->resume_from_suspend) {
+		*ops = &dev->resume_data->ops;
+		*data = dev->resume_data->data;
+	} else {
+		*ops = dev->bdev->bd_disk->fops->sec_ops;
+		*data = dev->bdev->bd_disk->private_data;
+	}
+}
+
+static void _opal_send_cmd(struct work_struct *send_work)
+{
+	struct opal_dev *dev = container_of(send_work, struct opal_dev,
+					    opal_send_work);
+	const struct sec_ops *ops = NULL;
+	void *data = NULL;
+
+	get_data_ops(dev, &ops, &data);
+	ops->send(data, dev->comID, TCG_SECP_01, dev->cmd.cmd,
+		  IO_BUFFER_LENGTH, opal_send_cb, dev);
+
+}
+
+static void _opal_recv_cmd(struct work_struct *recv_work)
+{
+	struct opal_dev *dev = container_of(recv_work, struct opal_dev,
+					    opal_recv_work);
+	const struct sec_ops *ops;
+	void *data;
+
+	get_data_ops(dev, &ops, &data);
+	ops->recv(data, dev->comID, TCG_SECP_01, dev->cmd.resp,
+		  IO_BUFFER_LENGTH, opal_send_cb_cont, dev);
+}
+
+static void opal_send_recv(struct opal_dev *dev, sec_cb *cb, void *cb_data)
+{
+	dev->cmd.cb = cb;
+	dev->cmd.cb_data = cb_data;
+	schedule_work(&dev->opal_send_work);
+}
+
+static void check_geometry(struct opal_dev *dev, const void *data)
+{
+	const struct d0_geometry_features *geo = data;
+
+	dev->align = geo->alignment_granularity;
+	dev->lowest_lba = geo->lowest_aligned_lba;
+}
+
+static void opal_discovery0_end(int error, void *data)
+{
+	bool foundComID = false, supported = true, single_user = false;
+	struct opal_dev *dev = data;
+	const struct d0_header *hdr;
+	const u8 *epos, *cpos;
+	u16 comID = 0;
+
+	if (error) {
+		pr_err("%s: Sending discovery0 failed\n", dev->disk_name);
+		goto err_callback;
+	}
+
+	epos = dev->cmd.resp;
+	cpos = dev->cmd.resp;
+	hdr = (struct d0_header *)dev->cmd.resp;
+
+	print_buffer(dev->cmd.resp, be32_to_cpu(hdr->length));
+
+	epos += be32_to_cpu(hdr->length); /* end of buffer */
+	cpos += sizeof(*hdr); /* current position on buffer */
+
+	while (cpos < epos && supported) {
+		const struct d0_features *body =
+			(const struct d0_features *)cpos;
+
+		switch (be16_to_cpu(body->code)) {
+		case FC_TPER:
+			supported = check_tper(body->features);
+			break;
+		case FC_SINGLEUSER:
+			single_user = check_SUM(body->features);
+			break;
+		case FC_GEOMETRY:
+			check_geometry(dev, body);
+			break;
+		case FC_LOCKING:
+		case FC_ENTERPRISE:
+		case FC_DATASTORE:
+			/* some ignored properties */
+			pr_debug("%s: Found OPAL feature description: %d\n",
+				 dev->disk_name, be16_to_cpu(body->code));
+			break;
+		case FC_OPALV100:
+			comID = get_comID_v100(body->features);
+			foundComID = true;
+			break;
+		case FC_OPALV200:
+			comID = get_comID_v200(body->features);
+			foundComID = true;
+			break;
+		case 0xbfff ... 0xffff:
+			/* vendor specific, just ignore */
+			break;
+		default:
+			pr_warn("%s: OPAL Unknown feature: %d\n",
+				dev->disk_name, be16_to_cpu(body->code));
+
+		}
+		cpos += body->length + 4;
+	}
+
+	if (!supported) {
+		pr_err("%s: Device not supported\n", dev->disk_name);
+		goto err_callback;
+	}
+
+	if (!single_user)
+		pr_warn("%s: Device doesn't support single user mode\n",
+			dev->disk_name);
+
+	if (!foundComID) {
+		pr_warn("%s: Could not find OPAL comID for device. OPAL kernel unlocking will be disabled\n",
+			dev->disk_name);
+		goto err_callback;
+	}
+
+	dev->comID = comID;
+
+err_callback:
+	if (dev->oper_cb)
+		dev->oper_cb(error, dev);
+}
+
+static int opal_discovery0(struct opal_dev *dev)
+{
+	const struct sec_ops *ops;
+	void *data;
+
+	get_data_ops(dev, &ops, &data);
+	memset(dev->cmd.resp, 0, IO_BUFFER_LENGTH);
+	return ops->recv(data, 0x0001, TCG_SECP_01, dev->cmd.resp,
+			 IO_BUFFER_LENGTH, opal_discovery0_end, dev);
+}
+
+static void add_token_u8(struct opal_cmd *cmd, u8 tok)
+{
+	cmd->cmd[cmd->pos++] = tok;
+}
+
+static ssize_t test_and_add_token_u8(struct opal_cmd *cmd, u8 tok)
+{
+	BUILD_BUG_ON(IO_BUFFER_LENGTH >= SIZE_MAX);
+
+	if (cmd->pos >= IO_BUFFER_LENGTH - 1) {
+		pr_err("Error adding u8: end of buffer.\n");
+		return -ERANGE;
+	}
+
+	add_token_u8(cmd, tok);
+
+	return 1;
+}
+
+#define TINY_ATOM_DATA_MASK GENMASK(5, 0)
+#define TINY_ATOM_SIGNED BIT(6)
+
+#define SHORT_ATOM_ID BIT(7)
+#define SHORT_ATOM_BYTESTRING BIT(5)
+#define SHORT_ATOM_SIGNED BIT(4)
+#define SHORT_ATOM_LEN_MASK GENMASK(3, 0)
+
+static void add_short_atom_header(struct opal_cmd *cmd, bool bytestring,
+				  bool has_sign, int len)
+{
+	u8 atom;
+
+	atom = SHORT_ATOM_ID;
+	atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
+	atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
+	atom |= len & SHORT_ATOM_LEN_MASK;
+
+	add_token_u8(cmd, atom);
+}
+
+#define MEDIUM_ATOM_ID (BIT(7) | BIT(6))
+#define MEDIUM_ATOM_BYTESTRING BIT(4)
+#define MEDIUM_ATOM_SIGNED BIT(3)
+#define MEDIUM_ATOM_LEN_MASK GENMASK(2, 0)
+
+static void add_medium_atom_header(struct opal_cmd *cmd, bool bytestring,
+				   bool has_sign, int len)
+{
+	u8 header0;
+
+	header0 = MEDIUM_ATOM_ID;
+	header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
+	header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
+	header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
+	cmd->cmd[cmd->pos++] = header0;
+	cmd->cmd[cmd->pos++] = len;
+}
+
+static void add_token_u64(struct opal_cmd *cmd, u64 number, size_t len)
+{
+	add_short_atom_header(cmd, false, false, len);
+
+	while (len--) {
+		u8 n = number >> (len * 8);
+
+		add_token_u8(cmd, n);
+	}
+}
+
+static ssize_t test_and_add_token_u64(struct opal_cmd *cmd, u64 number)
+{
+	int len;
+	int msb;
+
+	if (!(number & ~TINY_ATOM_DATA_MASK))
+		return test_and_add_token_u8(cmd, number);
+
+	msb = fls(number);
+	len = DIV_ROUND_UP(msb, 4);
+
+	if (cmd->pos >= IO_BUFFER_LENGTH - len - 1) {
+		pr_err("Error adding u64: end of buffer.\n");
+		return -ERANGE;
+	}
+
+	add_token_u64(cmd, number, len);
+
+	/* return length of token plus atom */
+	return len + 1;
+}
+
+static void add_token_bytestring(struct opal_cmd *cmd,
+				 const u8 *bytestring, size_t len)
+{
+	memcpy(&cmd->cmd[cmd->pos], bytestring, len);
+	cmd->pos += len;
+}
+
+static ssize_t test_and_add_token_bytestring(struct opal_cmd *cmd,
+					     const u8 *bytestring, size_t len)
+{
+	size_t header_len = 1;
+	bool is_short_atom = true;
+
+	if (len & ~SHORT_ATOM_LEN_MASK) {
+		header_len = 2;
+		is_short_atom = false;
+	}
+
+	if (cmd->pos >= IO_BUFFER_LENGTH - len - header_len) {
+		pr_err("Error adding bytestring: end of buffer.\n");
+		return -ERANGE;
+	}
+
+	if (is_short_atom)
+		add_short_atom_header(cmd, true, false, len);
+	else
+		add_medium_atom_header(cmd, true, false, len);
+
+	add_token_bytestring(cmd, bytestring, len);
+
+	return header_len + len;
+}
+
+#define LOCKING_RANGE_NON_GLOBAL 0x03
+
+static int build_locking_range(u8 *buffer, size_t length, u8 lr)
+{
+	if (length < OPAL_UID_LENGTH)
+		return -ERANGE;
+
+	memcpy(buffer, OPALUID[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
+
+	if (lr == 0)
+		return 0;
+	buffer[5] = LOCKING_RANGE_NON_GLOBAL;
+	buffer[7] = lr;
+
+	return 0;
+}
+
+static int build_locking_user(u8 *buffer, size_t length, u8 lr)
+{
+	if (length < OPAL_UID_LENGTH)
+		return -ERANGE;
+
+	memcpy(buffer, OPALUID[OPAL_USER1_UID], OPAL_UID_LENGTH);
+
+	buffer[7] = lr + 1;
+
+	return 0;
+}
+
+/*
+ * N = number of format specifiers (1-999) to be replicated
+ * c = u8
+ * u = u64
+ * s = bytestring, length
+ *
+ * ret = test_and_add_token_va(cmd, "c",
+ *			       u8_val1);
+ *
+ * ret = test_and_add_token_va(cmd, "2c2u",
+ *			       u8_val1, u8_val2, u64_val1, u64_val2);
+ *
+ * ret = test_and_add_token_va(cmd, "3s",
+ *			       bytestring1, length1,
+ *			       bytestring2, length2,
+ *			       bytestring3, length3);
+ */
+static int test_and_add_token_va(struct opal_cmd *cmd,
+				 const char *fmt, ...)
+{
+	const u8 *it = fmt, *tmp;
+	int ret, num = 1, sum = 0;
+	va_list ap;
+
+	va_start(ap, fmt);
+
+	while (*it != '\0') {
+		u64 tok64 = 0;
+		u8 tok, *bstr;
+		size_t len;
+
+		ret = 0;
+
+		switch (*it) {
+		case '1' ... '9':
+			tmp = it;
+			num = 0;
+			while (*tmp >= '0' && *tmp <= '9')
+				num = num * 10 + (*tmp++ - '0');
+			it = tmp;
+			continue;
+		case 'c':
+			while (num--) {
+				tok = va_arg(ap, unsigned int);
+				ret = test_and_add_token_u8(cmd, tok);
+				if (ret < 0)
+					goto err;
+			}
+			num = 1;
+			break;
+		case 'u':
+			while (num--) {
+				tok64 = va_arg(ap, u64);
+				ret = test_and_add_token_u64(cmd, tok64);
+				if (ret < 0)
+					goto err;
+			}
+			num = 1;
+			break;
+		case 's':
+			while (num--) {
+				bstr = va_arg(ap, u8 *);
+				len = va_arg(ap, size_t);
+				ret = test_and_add_token_bytestring(cmd, bstr,
+								    len);
+				if (ret < 0)
+					goto err;
+			}
+			num = 1;
+			break;
+		case ' ':
+		case '\t':
+			/* ignored */
+			break;
+		default:
+			pr_warn("Unrecognized type.\n");
+		}
+
+		it++;
+		sum += ret;
+	}
+
+	va_end(ap);
+
+	return sum;
+
+ err:
+	pr_err("Token failed to be added.\n");
+	return ret;
+}
+
+static void set_comID(struct opal_cmd *cmd, u16 comID)
+{
+	struct opal_header *hdr = (struct opal_header *)cmd->cmd;
+
+	hdr->cp.extendedComID[0] = comID >> 8;
+	hdr->cp.extendedComID[1] = comID;
+	hdr->cp.extendedComID[2] = 0;
+	hdr->cp.extendedComID[3] = 0;
+}
+
+static int cmd_finalize(struct opal_cmd *cmd, u32 hsn, u32 tsn)
+{
+	struct opal_header *hdr;
+	int ret;
+
+	ret = test_and_add_token_va(cmd, "6c",
+				    OPAL_ENDOFDATA, OPAL_STARTLIST,
+				    0, 0, 0, OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("Error finalizing command.\n");
+		return -EFAULT;
+	}
+
+	hdr = (struct opal_header *) cmd->cmd;
+
+	hdr->pkt.TSN = cpu_to_be32(tsn);
+	hdr->pkt.HSN = cpu_to_be32(hsn);
+
+	hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
+	while (cmd->pos % 4) {
+		if (cmd->pos >= IO_BUFFER_LENGTH) {
+			pr_err("Error: Buffer overrun\n");
+			return -ERANGE;
+		}
+		cmd->cmd[cmd->pos++] = 0;
+	}
+	hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
+				      sizeof(hdr->pkt));
+	hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
+
+	return 0;
+}
+
+static enum OPAL_RESPONSE_TOKEN token_type(const struct parsed_resp *resp,
+					   int n)
+{
+	const struct opal_resp_tok *tok;
+
+	if (n >= resp->num) {
+		pr_err("Token number doesn't exist: %d, resp: %d\n",
+		       n, resp->num);
+		return OPAL_DTA_TOKENID_INVALID;
+	}
+
+	tok = &resp->toks[n];
+	if (tok->len == 0) {
+		pr_err("Token length must be non-zero\n");
+		return OPAL_DTA_TOKENID_INVALID;
+	}
+
+	return tok->type;
+}
+
+/*
+ * This function returns 0 in case of invalid token. One should call
+ * token_type() first to find out if the token is valid or not.
+ */
+static enum OPAL_TOKEN response_get_token(const struct parsed_resp *resp,
+					  int n)
+{
+	const struct opal_resp_tok *tok;
+
+	if (n >= resp->num) {
+		pr_err("Token number doesn't exist: %d, resp: %d\n",
+		       n, resp->num);
+		return 0;
+	}
+
+	tok = &resp->toks[n];
+	if (tok->len == 0) {
+		pr_err("Token length must be non-zero\n");
+		return 0;
+	}
+
+	return tok->pos[0];
+}
+
+static size_t response_parse_tiny(struct opal_resp_tok *tok,
+				  const u8 *pos)
+{
+	tok->pos = pos;
+	tok->len = 1;
+	tok->width = OPAL_WIDTH_TINY;
+
+	if (pos[0] & TINY_ATOM_SIGNED) {
+		tok->type = OPAL_DTA_TOKENID_SINT;
+	} else {
+		tok->type = OPAL_DTA_TOKENID_UINT;
+		tok->stored.u = pos[0] & 0x3f;
+	}
+
+	return tok->len;
+}
+
+static size_t response_parse_short(struct opal_resp_tok *tok,
+				   const u8 *pos)
+{
+	tok->pos = pos;
+	tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
+	tok->width = OPAL_WIDTH_SHORT;
+
+	if (pos[0] & SHORT_ATOM_BYTESTRING) {
+		tok->type = OPAL_DTA_TOKENID_BYTESTRING;
+	} else if (pos[0] & SHORT_ATOM_SIGNED) {
+		tok->type = OPAL_DTA_TOKENID_SINT;
+	} else {
+		u64 u_integer = 0;
+		int i, b = 0;
+
+		tok->type = OPAL_DTA_TOKENID_UINT;
+		if (tok->len > 9) {
+			pr_warn("uint64 with more than 8 bytes\n");
+			return -EINVAL;
+		}
+		for (i = tok->len - 1; i > 0; i--) {
+			u_integer |= ((u64)pos[i] << (8 * b));
+			b++;
+		}
+		tok->stored.u = u_integer;
+	}
+
+	return tok->len;
+}
+
+static size_t response_parse_medium(struct opal_resp_tok *tok,
+				    const u8 *pos)
+{
+	tok->pos = pos;
+	tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
+	tok->width = OPAL_WIDTH_MEDIUM;
+
+	if (pos[0] & MEDIUM_ATOM_BYTESTRING)
+		tok->type = OPAL_DTA_TOKENID_BYTESTRING;
+	else if (pos[0] & MEDIUM_ATOM_SIGNED)
+		tok->type = OPAL_DTA_TOKENID_SINT;
+	else
+		tok->type = OPAL_DTA_TOKENID_UINT;
+
+	return tok->len;
+}
+
+#define LONG_ATOM_ID (BIT(7) | BIT(6) | BIT(5))
+#define LONG_ATOM_BYTESTRING BIT(1)
+#define LONG_ATOM_SIGNED BIT(0)
+static size_t response_parse_long(struct opal_resp_tok *tok,
+				  const u8 *pos)
+{
+	tok->pos = pos;
+	tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
+	tok->width = OPAL_WIDTH_LONG;
+
+	if (pos[0] & LONG_ATOM_BYTESTRING)
+		tok->type = OPAL_DTA_TOKENID_BYTESTRING;
+	else if (pos[0] & LONG_ATOM_SIGNED)
+		tok->type = OPAL_DTA_TOKENID_SINT;
+	else
+		tok->type = OPAL_DTA_TOKENID_UINT;
+
+	return tok->len;
+}
+
+static size_t response_parse_token(struct opal_resp_tok *tok,
+				   const u8 *pos)
+{
+	tok->pos = pos;
+	tok->len = 1;
+	tok->type = OPAL_DTA_TOKENID_TOKEN;
+	tok->width = OPAL_WIDTH_TOKEN;
+
+	return tok->len;
+}
+
+static int response_parse(const u8 *buf, size_t length,
+			  struct parsed_resp *resp)
+{
+	const struct opal_header *hdr;
+	struct opal_resp_tok *iter;
+	int ret, num_entries = 0;
+	u32 cpos = 0, total;
+	size_t token_length;
+	const u8 *pos;
+
+	if (!buf)
+		return -EFAULT;
+
+	if (!resp)
+		return -EFAULT;
+
+	hdr = (struct opal_header *)buf;
+	pos = buf;
+	pos += sizeof(*hdr);
+
+	pr_debug("Response size: cp: %d, pkt: %d, subpkt: %d\n",
+		 be32_to_cpu(hdr->cp.length),
+		 be32_to_cpu(hdr->pkt.length),
+		 be32_to_cpu(hdr->subpkt.length));
+
+	if ((hdr->cp.length == 0)
+	    || (hdr->pkt.length == 0)
+	    || (hdr->subpkt.length == 0)) {
+		pr_err("Bad header length. cp: %d, pkt: %d, subpkt: %d\n",
+		       be32_to_cpu(hdr->cp.length),
+		       be32_to_cpu(hdr->pkt.length),
+		       be32_to_cpu(hdr->subpkt.length));
+		print_buffer(pos, sizeof(*hdr));
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (pos > buf + length) {
+		ret = -EFAULT;
+		goto err;
+	}
+
+	iter = resp->toks;
+	total = be32_to_cpu(hdr->subpkt.length);
+	print_buffer(pos, total);
+	while (cpos < total) {
+		if (!(pos[0] & 0x80)) /* tiny atom */
+			token_length = response_parse_tiny(iter, pos);
+		else if (!(pos[0] & 0x40)) /* short atom */
+			token_length = response_parse_short(iter, pos);
+		else if (!(pos[0] & 0x20)) /* medium atom */
+			token_length = response_parse_medium(iter, pos);
+		else if (!(pos[0] & 0x10)) /* long atom */
+			token_length = response_parse_long(iter, pos);
+		else /* TOKEN */
+			token_length = response_parse_token(iter, pos);
+
+		if (token_length == -EINVAL) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		pos += token_length;
+		cpos += token_length;
+		iter++;
+		num_entries++;
+	}
+
+	if (num_entries == 0) {
+		pr_err("Couldn't parse response.\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	resp->num = num_entries;
+
+	return 0;
+err:
+	return ret;
+}
+
+static size_t response_get_string(const struct parsed_resp *resp, int n,
+				  const char **store)
+{
+	*store = NULL;
+	if (!resp) {
+		pr_err("Response is NULL\n");
+		return 0;
+	}
+
+	if (n > resp->num) {
+		pr_err("Response has %d tokens. Can't access %d\n",
+		       resp->num, n);
+		return 0;
+	}
+
+	if (resp->toks[n].type != OPAL_DTA_TOKENID_BYTESTRING) {
+		pr_err("Token is not a byte string!\n");
+		return 0;
+	}
+
+	*store = resp->toks[n].pos + 1;
+	return resp->toks[n].len - 1;
+}
+
+static u64 response_get_u64(const struct parsed_resp *resp, int n)
+{
+	if (!resp) {
+		pr_err("Response is NULL\n");
+		return 0;
+	}
+
+	if (n > resp->num) {
+		pr_err("Response has %d tokens. Can't access %d\n",
+		       resp->num, n);
+		return 0;
+	}
+
+	if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) {
+		pr_err("Token is not unsigned it: %d\n",
+		       resp->toks[n].type);
+		return 0;
+	}
+
+	if (!((resp->toks[n].width == OPAL_WIDTH_TINY) ||
+	      (resp->toks[n].width == OPAL_WIDTH_SHORT))) {
+		pr_err("Atom is not short or tiny: %d\n",
+		       resp->toks[n].width);
+		return 0;
+	}
+
+	return resp->toks[n].stored.u;
+}
+
+static u8 response_status(const struct parsed_resp *resp)
+{
+	if ((token_type(resp, 0) == OPAL_DTA_TOKENID_TOKEN)
+	    && (response_get_token(resp, 0) == OPAL_ENDOFSESSION)) {
+		return 0;
+	}
+
+	if (resp->num < 5)
+		return DTAERROR_NO_METHOD_STATUS;
+
+	if ((token_type(resp, resp->num - 1) != OPAL_DTA_TOKENID_TOKEN) ||
+	    (token_type(resp, resp->num - 5) != OPAL_DTA_TOKENID_TOKEN) ||
+	    (response_get_token(resp, resp->num - 1) != OPAL_ENDLIST) ||
+	    (response_get_token(resp, resp->num - 5) != OPAL_STARTLIST))
+		return DTAERROR_NO_METHOD_STATUS;
+
+	return response_get_u64(resp, resp->num - 4);
+}
+
+/* Parses and checks for errors */
+static int parse_and_check_status(struct opal_dev *dev)
+{
+	struct opal_cmd *cmd;
+	int error;
+
+	cmd = &dev->cmd;
+	print_buffer(cmd->cmd, cmd->pos);
+
+	error = response_parse(cmd->resp, IO_BUFFER_LENGTH, &dev->parsed);
+	if (error) {
+		pr_err("%s: Couldn't parse response.\n", dev->disk_name);
+		goto err_return;
+	}
+
+	error = response_status(&dev->parsed);
+	if (error)
+		pr_err("%s: Response Status: %d\n", dev->disk_name,
+		       error);
+
+ err_return:
+	return error;
+}
+
+static void clear_opal_cmd(struct opal_cmd *cmd)
+{
+	cmd->pos = sizeof(struct opal_header);
+	memset(cmd->cmd, 0, IO_BUFFER_LENGTH);
+	cmd->cb = NULL;
+	cmd->cb_data = NULL;
+}
+
+static void start_opal_session_cont(int error, void *data)
+{
+	struct opal_dev *dev = data;
+	u32 HSN, TSN;
+
+	if (error)
+		goto err_return;
+
+	error = parse_and_check_status(dev);
+	if (error)
+		goto err_return;
+
+	HSN = response_get_u64(&dev->parsed, 4);
+	TSN = response_get_u64(&dev->parsed, 5);
+
+	if (HSN == 0 && TSN == 0) {
+		pr_err("%s: Couldn't authenticate session\n", dev->disk_name);
+		error = -EPERM;
+		goto err_return;
+	}
+
+	dev->HSN = HSN;
+	dev->TSN = TSN;
+
+err_return:
+	if (dev->oper_cb)
+		dev->oper_cb(error, dev);
+}
+
+static int get_opal_key(struct opal_dev *dev)
+{
+	struct key *ukey = NULL;
+	const u8 *tmpkey = NULL;
+	size_t tmplen;
+	int ret = 0;
+
+	if (dev->key_type == OPAL_KEY_PLAIN) {
+		tmpkey = dev->key_name;
+		tmplen = dev->key_name_len;
+	} else if (dev->key_type == OPAL_KEY_KEYRING) {
+		ukey = request_user_key(dev->key_name, &tmpkey, &tmplen);
+		if (IS_ERR(ukey)) {
+			pr_err("%s: Can't retrieve key: %ld\n", dev->disk_name,
+			       PTR_ERR(ukey));
+			return PTR_ERR(ukey);
+		}
+	} else {
+		pr_err("Requested invalid key type: %d\n", dev->key_type);
+		return -EINVAL;
+	}
+
+	if (tmplen > OPAL_KEY_MAX) {
+		pr_err("Requested key with invalid size: %zd\n", tmplen);
+		ret = -EINVAL;
+		goto err_exit;
+	}
+
+	dev->key_len = tmplen;
+	if (!memcpy(dev->key, tmpkey, tmplen)) {
+		pr_err("Error when copying key");
+		ret = -EFAULT;
+		goto err_exit;
+	}
+
+err_exit:
+	key_put(ukey);
+
+	return 0;
+}
+
+static void clean_opal_key(struct opal_dev *dev)
+{
+	memset(dev->key, 0, OPAL_KEY_MAX);
+	dev->key_len = 0;
+}
+
+static inline void clean_function_data(struct opal_dev *dev)
+{
+		dev->func_data = NULL;
+		dev->num_func_data = 0;
+}
+
+/* This is a generic continue fn.
+ * We use this when we don't care about the response data
+ * and simply want to check the status and continue.
+ */
+static void generic_cont(int error, void *data)
+{
+	struct opal_dev *dev = data;
+
+	if (error)
+		goto err_return;
+
+	error = parse_and_check_status(dev);
+
+ err_return:
+	if (dev->oper_cb)
+		dev->oper_cb(error, dev);
+}
+
+static void end_session_cont(int error, void *data)
+{
+	struct opal_dev *dev = data;
+
+	dev->HSN = 0;
+	dev->TSN = 0;
+	generic_cont(error, data);
+}
+
+static int finalize_and_send(struct opal_dev *dev, struct opal_cmd *cmd,
+			     sec_cb cont)
+{
+	int ret;
+
+	ret = cmd_finalize(cmd, dev->HSN, dev->TSN);
+	if (ret) {
+		pr_err("%s: Error finalizing command buffer: %d\n",
+		       dev->disk_name, ret);
+		return ret;
+	}
+
+	print_buffer(cmd->cmd, cmd->pos);
+
+	opal_send_recv(dev, cont, dev);
+	return ret;
+}
+
+static int wait_for_cmd_completion(struct opal_completion *completion)
+{
+	wait_for_completion_interruptible(&completion->cmd_completion);
+	return completion->completion_status;
+}
+
+static int gen_key(struct opal_dev *dev)
+{
+	const u8 *method;
+	u8 uid[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	int ret;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
+	method = OPALMETHOD[OPAL_GENKEY];
+	kfree(dev->prev_data);
+	dev->prev_data = NULL;
+
+	ret = test_and_add_token_va(cmd, "c2s 2c",
+				    OPAL_CALL,
+				    uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_ENDLIST);
+	if (ret < 0) {
+		pr_err("%s: Error building gen key command\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static void get_active_key_cont(int error, void *data)
+{
+	struct opal_dev *dev = data;
+	const char *activekey;
+	size_t keylen;
+
+	if (error)
+		goto err_return;
+
+	error = parse_and_check_status(dev);
+	if (error)
+		goto err_return;
+	keylen = response_get_string(&dev->parsed, 4, &activekey);
+	if (!activekey) {
+		pr_err("%s: Couldn't extract the Activekey from the response\n",
+		       __func__);
+		error = 0x0A;
+		goto err_return;
+	}
+	dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
+
+	if (!dev->prev_data)
+		error = -ENOMEM;
+
+	dev->prev_d_len = keylen;
+
+err_return:
+	if (dev->oper_cb)
+		dev->oper_cb(error, dev);
+}
+
+static int get_active_key(struct opal_dev *dev)
+{
+	const u8 *method;
+	u8 uid[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	int ret;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	method = OPALMETHOD[OPAL_GET];
+
+	ret = build_locking_range(uid, sizeof(uid), dev->lr);
+	if (ret < 0) {
+		pr_err("%s: Can't build locking range\n", dev->disk_name);
+		return -EINVAL;
+	}
+
+	ret = test_and_add_token_va(cmd, "c2s 6c 4c 2c",
+				    OPAL_CALL,
+				    uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_03, /* startCloumn */
+				    OPAL_TINY_UINT_10, /* ActiveKey */
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_04, /* endColumn */
+				    OPAL_TINY_UINT_10, /* ActiveKey */
+				    OPAL_ENDNAME,
+
+				    OPAL_ENDLIST,
+				    OPAL_ENDLIST);
+	if (ret < 0) {
+		pr_err("%s: Error building get active key command\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, get_active_key_cont);
+}
+
+static inline int enable_global_lr(struct opal_cmd *cmd, u8 *uid,
+				   struct opal_user_lr_setup *setup)
+{
+	const u8 *method;
+	method = OPALMETHOD[OPAL_SET];
+	return test_and_add_token_va(cmd, "c2s 4c 2cuc 2cu 4c",
+				     OPAL_CALL,
+				     uid, OPAL_UID_LENGTH,
+				     method, OPAL_METHOD_LENGTH,
+
+				     OPAL_STARTLIST,
+				     OPAL_STARTNAME,
+				     OPAL_VALUES,
+				     OPAL_STARTLIST,
+
+				     OPAL_STARTNAME,
+				     OPAL_TINY_UINT_05, /* ReadLockEnabled */
+				     !!setup->RLE,
+				     OPAL_ENDNAME,
+
+				     OPAL_STARTNAME,
+				     OPAL_TINY_UINT_06, /* WriteLockEnabled */
+				     !!setup->WLE,
+
+				     OPAL_ENDNAME,
+				     OPAL_ENDLIST,
+				     OPAL_ENDNAME,
+				     OPAL_ENDLIST);
+}
+
+static int setup_locking_range(struct opal_dev *dev)
+{
+	const u8 *method;
+	u8 uid[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	struct opal_user_lr_setup *setup;
+	int ret;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	method = OPALMETHOD[OPAL_SET];
+	ret = build_locking_range(uid, sizeof(uid), dev->lr);
+	if (ret < 0) {
+		pr_err("%s: Can't build locking range\n", dev->disk_name);
+		return -EINVAL;
+	}
+	setup = dev->func_data[dev->state - 1];
+	if (dev->lr == 0)
+		ret = enable_global_lr(cmd, uid, setup);
+	else
+		ret = test_and_add_token_va(cmd, "c2s  4c 2cuc 2cuc 2cuc 2cu 4c",
+				    OPAL_CALL,
+				    uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_VALUES,
+				    OPAL_STARTLIST,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_03, /* Range Start */
+				    setup->range_start,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_04, /* Range Length */
+				    setup->range_length,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_05, /* ReadLockEnabled */
+				    !!setup->RLE,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_06, /* WriteLockEnabled */
+				    !!setup->WLE,
+
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST,
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+	if (ret < 0) {
+		pr_err("%s: Error building Setup Locking range command.\n",
+		       dev->disk_name);
+		return ret;
+
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static int start_adminsp_opal_session(struct opal_dev *dev,
+				      enum OPAL_UID auth,
+				      const char *key,
+				      u8 key_len)
+{
+	const u8 *method, *smuid, *admin_sp, *hsa;
+	struct opal_cmd *cmd;
+	u32 HSN;
+	int ret;
+
+	if (key == NULL && auth != OPAL_ANYBODY_UID) {
+		pr_err("%s: Attempted to open ADMIN_SP Session without a Host" \
+		       "Challenge, and not as the Anybody UID\n", __func__);
+		return 1;
+	}
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+
+	set_comID(cmd, dev->comID);
+	HSN = GENERIC_HOST_SESSION_NUM;
+
+	smuid = OPALUID[OPAL_SMUID_UID];
+	method = OPALMETHOD[OPAL_STARTSESSION];
+	admin_sp = OPALUID[OPAL_ADMINSP_UID];
+
+	ret = test_and_add_token_va(cmd, "c2s cusc",
+				    OPAL_CALL,
+				    smuid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+				    OPAL_STARTLIST,
+				    HSN,
+				    admin_sp, OPAL_UID_LENGTH,
+				    OPAL_TINY_UINT_01);
+	if (ret < 0) {
+		pr_err("%s: Error building start adminsp session command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	switch (auth) {
+	case OPAL_ANYBODY_UID:
+		/* nothing left to do for anybody, just end and finalize */
+		ret = test_and_add_token_va(cmd, "c",
+					    OPAL_ENDLIST);
+		break;
+	case OPAL_SID_UID:
+		hsa = OPALUID[OPAL_SID_UID];
+		ret = test_and_add_token_va(cmd, "2c s 3c s 2c",
+					    OPAL_STARTNAME,
+					    OPAL_TINY_UINT_00, /* HostChallenge */
+					    key, key_len,
+					    OPAL_ENDNAME,
+					    OPAL_STARTNAME,
+					    OPAL_TINY_UINT_03, /* HostSignAuth */
+					    hsa, OPAL_UID_LENGTH,
+					    OPAL_ENDNAME,
+					    OPAL_ENDLIST);
+		break;
+	default:
+		pr_err("Cannot start Admin SP session with auth %d\n", auth);
+		return 1;
+	}
+
+	if (ret < 0) {
+		pr_err("%s: Error building start adminsp session command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, start_opal_session_cont);
+}
+
+static int start_anybodyASP_opal_session(struct opal_dev *dev)
+{
+	return start_adminsp_opal_session(dev, OPAL_ANYBODY_UID, NULL, 0);
+}
+
+static int start_SIDASP_opal_session(struct opal_dev *dev)
+{
+	int ret;
+	const u8 *key = dev->prev_data;
+
+	if (!key)
+		ret = start_adminsp_opal_session(dev, OPAL_SID_UID, dev->key,
+						 dev->key_len);
+	else {
+		ret = start_adminsp_opal_session(dev, OPAL_SID_UID, key,
+						 dev->prev_d_len);
+		kfree(key);
+		dev->prev_data = NULL;
+	}
+	return ret;
+}
+
+static int start_lockingsp_opal_session(struct opal_dev *dev,
+					enum OPAL_UID auth, const u8 *key,
+					u8 key_len)
+{
+
+	const u8 *method, *smuid, *locking_sp, *hsa;
+	struct opal_cmd *cmd;
+	size_t klen = key_len;
+	u32 HSN;
+	int ret;
+
+	if (key == NULL) {
+		pr_err("Cannot start Locking SP session without a key\n");
+		return -EINVAL;
+	}
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+
+	set_comID(cmd, dev->comID);
+	HSN = GENERIC_HOST_SESSION_NUM;
+
+	smuid = OPALUID[OPAL_SMUID_UID];
+	method = OPALMETHOD[OPAL_STARTSESSION];
+	locking_sp = OPALUID[OPAL_LOCKINGSP_UID];
+	hsa = OPALUID[auth];
+
+	ret = test_and_add_token_va(cmd, "c2s cusc 2csc 2csc c",
+				    OPAL_CALL,
+				    smuid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    HSN,
+				    locking_sp, OPAL_UID_LENGTH,
+				    OPAL_TINY_UINT_01,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_00, /* HostChallenge */
+				    key, klen,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_03, /* Host Sign Authority */
+				    hsa, OPAL_UID_LENGTH,
+				    OPAL_ENDNAME,
+
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building start adminsp session command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+	return finalize_and_send(dev, cmd, start_opal_session_cont);
+}
+
+static inline int start_admin1LSP_opal_session(struct opal_dev *dev)
+{
+	return start_lockingsp_opal_session(dev, OPAL_ADMIN1_UID,
+					    dev->key, dev->key_len);
+}
+
+static int start_auth_opal_session(struct opal_dev *dev)
+{
+	const u8 *method, *smuid, *locking_sp;
+	u8 lk_ul_user[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	u32 HSN;
+	int ret;
+	struct opal_user_info *uinfo;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+
+	set_comID(cmd, dev->comID);
+
+	HSN = GENERIC_HOST_SESSION_NUM;
+
+	uinfo = dev->func_data[dev->state - 1];
+
+	smuid = OPALUID[OPAL_SMUID_UID];
+	method = OPALMETHOD[OPAL_STARTSESSION];
+	locking_sp = OPALUID[OPAL_LOCKINGSP_UID];
+
+	if (uinfo->SUM) {
+		ret = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
+					 dev->lr);
+		if (ret < 0) {
+			pr_err("%s: Can't build locking user\n",
+			       dev->disk_name);
+			return ret;
+		}
+	} else if (uinfo->who != OPAL_ADMIN1 && !uinfo->SUM) {
+		ret = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
+					 uinfo->who - 1);
+		if (ret < 0) {
+			pr_err("%s: Can't build locking user\n",
+			       dev->disk_name);
+			return ret;
+		}
+	} else
+		memcpy(lk_ul_user, OPALUID[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
+
+
+	ret = test_and_add_token_va(cmd, "c2s cus3cs3c s 2c",
+				    OPAL_CALL,
+				    smuid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    HSN,
+				    locking_sp, OPAL_UID_LENGTH,
+				    OPAL_TINY_UINT_01,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_00,
+				    dev->key, dev->key_len,
+				    OPAL_ENDNAME,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_03,
+
+				    lk_ul_user, OPAL_UID_LENGTH,
+
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building STARTSESSION command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, start_opal_session_cont);
+}
+
+static int revert_tper(struct opal_dev *dev)
+{
+	const u8 *method, *smuid;
+	struct opal_cmd *cmd;
+	int ret;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+
+	set_comID(cmd, dev->comID);
+
+	smuid = OPALUID[OPAL_ADMINSP_UID];
+	method = OPALMETHOD[OPAL_REVERT];
+
+	ret = test_and_add_token_va(cmd, "c2s 2c",
+				    OPAL_CALL,
+				    smuid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+				    OPAL_STARTLIST,
+				    OPAL_ENDLIST);
+	if (ret < 0) {
+		pr_err("%s: Error building REVERT TPER command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static int internal_activate_user(struct opal_dev *dev)
+{
+	const u8 *method;
+	u8 uid[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	int ret;
+	struct opal_activate_user *act;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	act = dev->func_data[dev->state - 1];
+
+	memcpy(uid, OPALUID[OPAL_USER1_UID], OPAL_UID_LENGTH);
+	uid[7] = act->who.who;
+
+	method = OPALMETHOD[OPAL_SET];
+
+	ret = test_and_add_token_va(cmd, "c2s 3c c 4c 3c",
+				    OPAL_CALL,
+				    uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_01, /* Values */
+
+				    OPAL_STARTLIST,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_05, /* Enabled */
+				    OPAL_TINY_UINT_01, /* True */
+				    OPAL_ENDNAME,
+
+				    OPAL_ENDLIST,
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building Activate UserN command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static int erase_locking_range(struct opal_dev *dev)
+{
+	const u8 *method;
+	u8 uid[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	int ret;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	method = OPALMETHOD[OPAL_ERASE];
+
+	if (build_locking_range(uid, sizeof(uid), dev->lr) < 0) {
+		pr_err("%s: Can't build locking range\n", dev->disk_name);
+		return -EINVAL;
+	}
+
+	ret = test_and_add_token_va(cmd, "c2s 2c",
+				    OPAL_CALL,
+				    uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building Erase Locking Range Cmmand.\n",
+		       dev->disk_name);
+		return ret;
+	}
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static int set_mbr_done(struct opal_dev *dev)
+{
+	const u8 *method, *uid;
+	struct opal_cmd *cmd;
+	int ret;
+
+	u8 mbr_done_tf = *(u8 *)dev->func_data[dev->state - 1];
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	method = OPALMETHOD[OPAL_SET];
+	uid = OPALUID[OPAL_MBRCONTROL];
+
+	ret = test_and_add_token_va(cmd, "c2s 3c 6c 2c",
+				    OPAL_CALL,
+				    uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_VALUES,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_02, /* Done */
+				    mbr_done_tf,       /* Done T or F */
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST,
+
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+	if (ret < 0) {
+		pr_err("%s: Error Building set MBR Done command\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static int set_mbr_enable_disable(struct opal_dev *dev)
+{
+	const u8 *method, *uid;
+	struct opal_cmd *cmd;
+	int ret;
+
+	u8 mbr_en_dis = *(u8 *)dev->func_data[dev->state - 1];
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	method = OPALMETHOD[OPAL_SET];
+	uid = OPALUID[OPAL_MBRCONTROL];
+
+	ret = test_and_add_token_va(cmd, "c2s 3c 6c 2c",
+				    OPAL_CALL,
+				    uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_VALUES,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_01, /* Enable */
+				    mbr_en_dis,        /* Enable or Disable */
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST,
+
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+	if (ret < 0) {
+		pr_err("%s: Error Building set MBR done command\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static int set_new_pw(struct opal_dev *dev)
+{
+	const u8 *method;
+	u8 cpin_uid[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	int ret;
+	struct opal_new_pw *pw;
+	size_t key_len;
+	u8 *key;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	pw = dev->func_data[dev->state - 1];
+	key = pw->new_pin.key;
+	key_len = pw->new_pin.key_len;
+	memcpy(cpin_uid, OPALUID[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
+
+	if (pw->user_for_pw != OPAL_ADMIN1) {
+		cpin_uid[5] = 0x03;
+		if (pw->who.SUM)
+			cpin_uid[7] = pw->new_pin.lr + 1;
+		else
+			cpin_uid[7] = pw->user_for_pw;
+	}
+
+	method = OPALMETHOD[OPAL_SET];
+
+	ret = test_and_add_token_va(cmd, "c2s 3c 3cs2c 2c",
+				    OPAL_CALL,
+				    cpin_uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_01, /* Values */
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_03, /* PIN */
+				    key, key_len,
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST,
+
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building SET AMIN1 PIN command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static int set_sid_cpin_pin(struct opal_dev *dev)
+{
+	const u8 *method, *cpin_uid;
+	struct opal_cmd *cmd;
+	int ret;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	cpin_uid = OPALUID[OPAL_C_PIN_SID];
+	method = OPALMETHOD[OPAL_SET];
+
+	ret = test_and_add_token_va(cmd, "c2s 2c 4cs2c 2c",
+				    OPAL_CALL,
+				    cpin_uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+
+				    OPAL_TINY_UINT_01, /* Values */
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_03, /* PIN */
+				    dev->key, dev->key_len,
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST,
+
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building SET CPIN PIN command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static void query_locking_range_cont(int error, void *data)
+{
+	struct opal_dev *dev = data;
+
+	if (error)
+		goto err_return;
+
+	error = parse_and_check_status(dev);
+	if (error)
+		goto err_return;
+
+	dev->start = response_get_u64(&dev->parsed, 4);
+	dev->length = response_get_u64(&dev->parsed, 8);
+
+err_return:
+	if (dev->oper_cb)
+		dev->oper_cb(error, dev);
+}
+
+static int query_locking_range(struct opal_dev *dev)
+{
+	u8 lr_buffer[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	const u8 *method;
+	int ret;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+
+	method = OPALMETHOD[OPAL_GET];
+
+	if (build_locking_range(lr_buffer, sizeof(lr_buffer), dev->lr) < 0) {
+		pr_err("%s: Can't build locking range\n", dev->disk_name);
+		return -EINVAL;
+	}
+
+	set_comID(cmd, dev->comID);
+
+	ret = test_and_add_token_va(cmd, "c2s 12c",
+				    OPAL_CALL,
+				    lr_buffer, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_STARTCOLUMN,
+				    OPAL_RANGESTART,
+				    OPAL_ENDNAME,
+				    OPAL_STARTNAME,
+				    OPAL_ENDCOLUMN,
+				    OPAL_RANGELENGTH,
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST,
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building GET Locking Range command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, query_locking_range_cont);
+}
+
+static int add_user_to_lr(struct opal_dev *dev)
+{
+	u8 lr_buffer[OPAL_UID_LENGTH];
+	u8 user_uid[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	const u8 *method;
+	struct opal_lock_unlock *lkul;
+	int ret;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	method = OPALMETHOD[OPAL_SET];
+
+	lkul = dev->func_data[dev->state - 1];
+
+	memcpy(lr_buffer, OPALUID[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
+	       OPAL_UID_LENGTH);
+
+	if (lkul->l_state == OPAL_RW)
+		memcpy(lr_buffer, OPALUID[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
+		       OPAL_UID_LENGTH);
+
+	lr_buffer[7] = dev->lr;
+
+	memcpy(user_uid, OPALUID[OPAL_USER1_UID], OPAL_UID_LENGTH);
+	user_uid[7] = lkul->authority.who;
+
+	ret = test_and_add_token_va(cmd, "c2s 3c 3c 2c 2sc c2sc cs2c 5c",
+				    OPAL_CALL,
+				    lr_buffer, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_01, /* Values */
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_03, /* BooleanExpr */
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+
+				    OPALUID[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
+				    OPAL_UID_LENGTH_HALF,
+				    user_uid, OPAL_UID_LENGTH,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPALUID[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
+				    OPAL_UID_LENGTH_HALF,
+				    user_uid, OPAL_UID_LENGTH,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPALUID[OPAL_HALF_UID_BOOLEAN_ACE],
+				    OPAL_UID_LENGTH_HALF,
+				    OPAL_TINY_UINT_01,
+				    OPAL_ENDNAME,
+
+				    OPAL_ENDLIST,
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST,
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+	if (ret < 0) {
+		pr_err("%s: Error building add user to locking range command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static int lock_unlock_locking_range(struct opal_dev *dev)
+{
+	u8 lr_buffer[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	const u8 *method;
+	struct opal_lock_unlock *lkul;
+	int ret;
+	u8 read_locked = 1, write_locked = 1;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	method = OPALMETHOD[OPAL_SET];
+	lkul = dev->func_data[dev->state - 1];
+	if (build_locking_range(lr_buffer, sizeof(lr_buffer), dev->lr) < 0) {
+		pr_err("%s: Can't build locking range\n", dev->disk_name);
+		return -EINVAL;
+	}
+
+	switch (lkul->l_state) {
+	case OPAL_RO:
+		read_locked = 0;
+		write_locked = 1;
+		break;
+	case OPAL_RW:
+		read_locked = 0;
+		write_locked = 0;
+		break;
+	case OPAL_LK:
+		/* vars are initalized to locked */
+		break;
+	default:
+		pr_err("Tried to set an invalid locking state... returning to uland\n");
+		return 1;
+	}
+
+	ret = test_and_add_token_va(cmd, "c2sc 3c 4c 4c 3c",
+				    OPAL_CALL,
+				    lr_buffer, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+				    OPAL_STARTLIST,
+
+				    OPAL_STARTNAME,
+				    OPAL_VALUES,
+				    OPAL_STARTLIST,
+
+				    OPAL_STARTNAME,
+				    OPAL_READLOCKED,
+				    read_locked,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_WRITELOCKED,
+				    write_locked,
+				    OPAL_ENDNAME,
+
+				    OPAL_ENDLIST,
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building SET command.\n", dev->disk_name);
+		return ret;
+	}
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+
+static int lock_unlock_locking_range_SUM(struct opal_dev *dev)
+{
+	u8 lr_buffer[OPAL_UID_LENGTH];
+	struct opal_cmd *cmd;
+	const u8 *method;
+	struct opal_lock_unlock *lkul;
+	int ret;
+	u8 read_locked = 1, write_locked = 1;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	method = OPALMETHOD[OPAL_SET];
+	lkul = dev->func_data[dev->state - 1];
+	if (build_locking_range(lr_buffer, sizeof(lr_buffer), dev->lr) < 0) {
+		pr_err("%s: Can't build locking range\n", dev->disk_name);
+		return -EINVAL;
+	}
+
+	switch (lkul->l_state) {
+	case OPAL_RO:
+		read_locked = 0;
+		write_locked = 1;
+		break;
+	case OPAL_RW:
+		read_locked = 0;
+		write_locked = 0;
+		break;
+	case OPAL_LK:
+		/* vars are initalized to locked */
+		break;
+	default:
+		pr_err("Tried to set an invalid locking state.\n");
+		return 1;
+	}
+
+	ret = test_and_add_token_va(cmd, "c2sc 3c 4c 4c 4c 4c 3c",
+				    OPAL_CALL,
+				    lr_buffer, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+				    OPAL_STARTLIST,
+
+				    OPAL_STARTNAME,
+				    OPAL_VALUES,
+				    OPAL_STARTLIST,
+
+				    OPAL_STARTNAME,
+				    OPAL_READLOCKENABLED,
+				    OPAL_TRUE,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_WRITELOCKENABLED,
+				    OPAL_TRUE,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_READLOCKED,
+				    read_locked,
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_WRITELOCKED,
+				    write_locked,
+				    OPAL_ENDNAME,
+
+				    OPAL_ENDLIST,
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST);
+	if (ret < 0) {
+		pr_err("%s: Error building SET command.\n", dev->disk_name);
+		return ret;
+	}
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+int activate_lsp(struct opal_dev *dev)
+{
+	u8 user_lr[OPAL_UID_LENGTH];
+	const u8 *method, *uid;
+	struct opal_cmd *cmd;
+	int ret;
+	size_t uint_3 = 0x83;
+
+	cmd = &dev->cmd;
+
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	uid = OPALUID[OPAL_LOCKINGSP_UID];
+	method = OPALMETHOD[OPAL_ACTIVATE];
+
+	ret = test_and_add_token_va(cmd, "c2s",
+				    OPAL_CALL,
+				    uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH);
+	if (ret < 0) {
+		pr_err("%s: Error building Activate LockingSP command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+	/* Activating as SUM */
+	if (dev->lr > 0) {
+		ret = build_locking_range(user_lr, sizeof(user_lr), dev->lr);
+		if (ret < 0) {
+			pr_err("%s: Can't build locking user\n",
+			       dev->disk_name);
+			return ret;
+		}
+		test_and_add_token_va(cmd, "2c 4c csc 2c",
+				      OPAL_STARTLIST,
+				      OPAL_STARTNAME,
+
+				      uint_3,
+				      OPAL_TINY_UINT_06,
+				      OPAL_TINY_UINT_00,
+				      OPAL_TINY_UINT_00,
+
+				      OPAL_STARTLIST,
+				      user_lr, OPAL_UID_LENGTH,
+				      OPAL_ENDLIST,
+
+				      OPAL_ENDNAME,
+				      OPAL_ENDLIST);
+	} else /* Actiave Normal Mode */
+		ret = test_and_add_token_va(cmd, "2c",
+					    OPAL_STARTLIST,
+					    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building Activate LockingSP command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, generic_cont);
+}
+
+static void get_lsp_lifecycle_cont(int error, void *data)
+{
+
+	struct opal_dev *dev = data;
+	u8 lc_status;
+
+	if (error)
+		goto err_return;
+
+	error = parse_and_check_status(dev);
+	if (error)
+		goto err_return;
+
+	lc_status = response_get_u64(&dev->parsed, 4);
+	/* 0x08 is Manufacured Inactive */
+	/* 0x09 is Manufactured */
+	if (lc_status != 0x08) {
+		pr_err("%s: Couldn't determine the status of the Lifcycle state\n",
+		       dev->disk_name);
+		error = -ENODEV;
+	}
+
+err_return:
+	if (dev->oper_cb)
+		dev->oper_cb(error, dev);
+}
+
+/* Determine if we're in the Manufactured Inactive or Active state */
+int get_lsp_lifecycle(struct opal_dev *dev)
+{
+	struct opal_cmd *cmd;
+	const u8 *method, *uid;
+	int ret;
+
+	cmd = &dev->cmd;
+
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	uid = OPALUID[OPAL_LOCKINGSP_UID];
+	method = OPALMETHOD[OPAL_GET];
+
+	ret = test_and_add_token_va(cmd, "c2s 2c 4c 4c 2c",
+				    OPAL_CALL,
+				    uid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTLIST,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_03, /* Start Column */
+				    OPAL_TINY_UINT_06, /* Lifcycle Column */
+				    OPAL_ENDNAME,
+
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_04, /* End Column */
+				    OPAL_TINY_UINT_06, /* Lifecycle Column */
+				    OPAL_ENDNAME,
+
+				    OPAL_ENDLIST,
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error Building GET Lifecycle Status command\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, get_lsp_lifecycle_cont);
+}
+
+static void get_msid_cpin_pin_cont(int error, void *data)
+{
+	const char *msid_pin;
+	struct opal_dev *dev = data;
+	size_t strlen;
+
+	if (error)
+		goto err_return;
+
+	error = parse_and_check_status(dev);
+	if (error)
+		goto err_return;
+
+	strlen = response_get_string(&dev->parsed, 4, &msid_pin);
+	if (!msid_pin) {
+		pr_err("%s: Couldn't extract PIN from response\n", __func__);
+		error = 1;
+		goto err_return;
+	}
+
+	dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
+	if (!dev->prev_data)
+		error = -ENOMEM;
+
+	dev->prev_d_len = strlen;
+
+ err_return:
+	if (dev->oper_cb)
+		dev->oper_cb(error, dev);
+}
+
+static int get_msid_cpin_pin(struct opal_dev *dev)
+{
+	const u8 *method, *smuid;
+	int ret;
+	struct opal_cmd *cmd;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+	set_comID(cmd, dev->comID);
+
+	smuid = OPALUID[OPAL_C_PIN_MSID];
+	method = OPALMETHOD[OPAL_GET];
+
+	ret = test_and_add_token_va(cmd, "c 2s 12c",
+				    OPAL_CALL,
+
+				    smuid, OPAL_UID_LENGTH,
+				    method, OPAL_METHOD_LENGTH,
+
+				    OPAL_STARTLIST,
+				    OPAL_STARTLIST,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_03, /* Sart Column */
+				    OPAL_TINY_UINT_03, /* PIN */
+				    OPAL_ENDNAME,
+				    OPAL_STARTNAME,
+				    OPAL_TINY_UINT_04, /* End Column */
+				    OPAL_TINY_UINT_03, /* PIN */
+				    OPAL_ENDNAME,
+				    OPAL_ENDLIST,
+				    OPAL_ENDLIST);
+
+	if (ret < 0) {
+		pr_err("%s: Error building Get MSID CPIN PIN command.\n",
+		       dev->disk_name);
+		return ret;
+	}
+
+	return finalize_and_send(dev, cmd, get_msid_cpin_pin_cont);
+}
+
+static void unlock_suspend_final(int error, void *data)
+{
+	struct opal_dev *dev = data;
+
+	dev->resume_from_suspend = false;
+	dev->resume_data = NULL;
+	dev->func_data = NULL;
+	dev->bdev = NULL;
+}
+
+static int build_end_opal_session(struct opal_dev *dev)
+{
+	struct opal_cmd *cmd;
+
+	cmd = &dev->cmd;
+	clear_opal_cmd(cmd);
+
+	set_comID(cmd, dev->comID);
+	return test_and_add_token_u8(cmd, OPAL_ENDOFSESSION);
+}
+
+static int end_opal_session(struct opal_dev *dev)
+{
+	int ret = build_end_opal_session(dev);
+	if (ret < 0)
+		return ret;
+	return finalize_and_send(dev, &dev->cmd, end_session_cont);
+}
+
+static struct opal_dev *find_opal_dev(struct block_device *bdev, u8 lr)
+{
+	struct opal_dev *iter, *opal_dev = NULL;
+
+	list_for_each_entry(iter, &opal_list, node) {
+		if (strncmp(iter->disk_name, bdev->bd_disk->disk_name,
+			    DISK_NAME_LEN))
+			continue;
+		if (iter->lr == lr) {
+			opal_dev = iter;
+			break;
+		}
+	}
+
+	return opal_dev;
+}
+
+static int update_opal_dev(struct opal_dev *old_dev, struct opal_dev *new_dev)
+{
+	if (!atomic_add_unless(&old_dev->in_use, 1, 1)) {
+		pr_err("%s: dev was in use\n", __func__);
+		return -EBUSY;
+	}
+
+	old_dev->key_name_len = new_dev->key_name_len;
+	if (!memcpy(old_dev->key_name, new_dev->key_name, old_dev->key_name_len)) {
+		pr_err("%s: Error updating device:\n", old_dev->disk_name);
+		return -EFAULT;
+	}
+
+	if (!strncpy(old_dev->disk_name, new_dev->disk_name, DISK_NAME_LEN)) {
+		pr_err("%s: Error registering device: copying disk name\n",
+		       old_dev->disk_name);
+		return -EFAULT;
+	}
+
+	old_dev->comID = new_dev->comID;
+	old_dev->start = new_dev->start;
+	old_dev->length = new_dev->length;
+	old_dev->align = new_dev->align;
+	old_dev->lowest_lba = new_dev->lowest_lba;
+	old_dev->bdev = NULL;
+	old_dev->final_cb = new_dev->final_cb;
+	old_dev->final_cb_data = new_dev->final_cb_data;
+	old_dev->oper_cb = new_dev->oper_cb;
+	old_dev->state = new_dev->state;
+	old_dev->funcs = new_dev->funcs;
+
+	kfree(old_dev->completion);
+	clean_function_data(old_dev);
+
+	old_dev->completion = new_dev->completion;
+
+	/*
+	 * Won't be able to auto unlock this locking range based on block
+	 * requestes.
+	 */
+	if (old_dev->length == 0)
+		pr_warn("%s: Missing block information for locking range %d\n",
+			old_dev->disk_name, old_dev->lr);
+
+	return 0;
+}
+
+int opal_register_cont(struct opal_dev *new_dev)
+{
+	struct opal_dev *old_dev;
+	unsigned long flags;
+	int error = 0;
+
+	spin_lock_irqsave(&list_spinlock, flags);
+
+	old_dev = find_opal_dev(new_dev->bdev, new_dev->lr);
+	if (!old_dev) {
+		list_add_tail(&new_dev->node, &opal_list);
+		old_dev = new_dev;
+	} else {
+		if (old_dev == new_dev)
+			error = 0;
+		else {
+			error = update_opal_dev(old_dev, new_dev);
+			clean_opal_key(new_dev);
+			kfree(new_dev);
+		}
+	}
+
+	if (error)
+		list_del(&old_dev->node);
+
+	spin_unlock_irqrestore(&list_spinlock, flags);
+
+	if (!error)
+		pr_info("%s: Registered key for locking range: %d\n",
+			old_dev->disk_name, old_dev->lr);
+
+	if (old_dev->oper_cb)
+		old_dev->oper_cb(error, old_dev);
+
+	return 0;
+}
+
+static void next(int error, struct opal_dev *dev)
+{
+	opal_step func = dev->funcs[dev->state];
+	void *cb_data = dev->final_cb_data;
+	sec_cb *cb = dev->final_cb;
+	bool done = false;
+
+
+	if (error || !func) {
+		done = true;
+		goto next_exit;
+	}
+	dev->state++;
+	dev->oper_cb = next;
+	error = func(dev);
+ next_exit:
+	if (error) {
+		pr_err("%s: Error on step function: %d with error %d: %s\n",
+		       dev->disk_name, dev->state, error,
+		       opal_error_to_human(error));
+
+
+		atomic_dec(&dev->in_use);
+		if (dev->error_cb) {
+			dev->error_cb(dev->error_cb_data);
+			return;
+		}
+		if (cb)
+			cb(error, cb_data);
+
+		dev->completion->completion_status = error;
+		complete(&dev->completion->cmd_completion);
+	} else if (!error && done) {
+		atomic_dec(&dev->in_use);
+		if (cb)
+			cb(error, cb_data);
+		dev->completion->completion_status = error;
+		complete(&dev->completion->cmd_completion);
+	}
+}
+
+const opal_step error_end_session[] = {
+	end_opal_session,
+	NULL,
+};
+static int end_opal_session_error(struct opal_dev *dev)
+{
+
+	dev->funcs = error_end_session;
+	dev->state = 0;
+	dev->error_cb = NULL;
+	next(0, dev);
+	return 0;
+}
+
+static struct opal_dev *alloc_opal_dev(struct block_device *bdev, u8 lr)
+{
+	struct opal_dev *opal_dev;
+	struct request_queue *q;
+	unsigned long dma_align;
+	const char *disk_name;
+	struct opal_cmd *cmd;
+	int ret;
+
+	opal_dev = kzalloc(sizeof(*opal_dev), GFP_KERNEL);
+	if (!opal_dev)
+		return ERR_PTR(-ENOMEM);
+
+	opal_dev->bdev = bdev;
+	opal_dev->lr = lr;
+	cmd = &opal_dev->cmd;
+	cmd->cmd = cmd->cmd_buf;
+	cmd->resp = cmd->resp_buf;
+
+	disk_name = bdev->bd_disk->disk_name;
+	if (!strncpy(opal_dev->disk_name, disk_name, DISK_NAME_LEN)) {
+		pr_err("%s: Error registering device: copying disk name\n",
+		       disk_name);
+		ret = -EFAULT;
+		goto err_free_dev;
+	}
+
+	q = bdev->bd_queue;
+	dma_align = (queue_dma_alignment(q) | q->dma_pad_mask) + 1;
+	cmd->cmd = (u8 *)round_up((uintptr_t)cmd->cmd, dma_align);
+	cmd->resp = (u8 *)round_up((uintptr_t)cmd->resp, dma_align);
+
+	INIT_LIST_HEAD(&opal_dev->node);
+	atomic_set(&opal_dev->in_use, 1);
+
+	opal_dev->completion = kzalloc(sizeof(*opal_dev->completion),
+				       GFP_KERNEL);
+
+	if (!opal_dev->completion)
+		goto err_free_dev;
+
+	init_completion(&opal_dev->completion->cmd_completion);
+	opal_dev->completion->completion_status = 0;
+	opal_dev->state = 0;
+	INIT_WORK(&opal_dev->opal_send_work, _opal_send_cmd);
+	INIT_WORK(&opal_dev->opal_recv_work, _opal_recv_cmd);
+
+
+	return opal_dev;
+
+err_free_dev:
+	kfree(opal_dev);
+	return ERR_PTR(ret);
+}
+
+int opal_register(struct block_device *bdev, struct opal_key *key_cmd,
+		  const opal_step *funcs)
+{
+	struct opal_dev *new_dev = NULL;
+	u8 key_len = key_cmd->key_len;
+	u8 lr = key_cmd->lr;
+	struct opal_completion *completion;
+	int ret;
+
+	new_dev = alloc_opal_dev(bdev, lr);
+	if (IS_ERR(new_dev)) {
+		pr_err("%s: Error registering device: allocation\n",
+		       bdev->bd_disk->disk_name);
+		return PTR_ERR(new_dev);
+	}
+
+	if (!memcpy(new_dev->key_name, key_cmd->key, key_len)) {
+		pr_err("%s: Error registering key: couldn't copy key\n",
+		       new_dev->disk_name);
+		return -EFAULT;
+	}
+
+	new_dev->key_name_len = key_len;
+	new_dev->key_type = key_cmd->key_type;
+	ret = get_opal_key(new_dev);
+	if (ret) {
+		pr_err("%s: Couldn't get key: %d\n", new_dev->disk_name, ret);
+		return ret;
+	}
+
+	new_dev->funcs = funcs;
+
+	new_dev->state = 0;
+	completion = new_dev->completion;
+	next(0, new_dev);
+
+	return wait_for_cmd_completion(completion);
+}
+
+static struct opal_dev *get_registered_opal_dev(struct block_device *bdev,
+						u8 lr)
+{
+	const char *diskname = bdev->bd_disk->disk_name;
+	struct opal_dev *iter, *dev = NULL;
+	unsigned long flags;
+	bool in_use = false;
+
+	spin_lock_irqsave(&list_spinlock, flags);
+	list_for_each_entry(iter, &opal_list, node) {
+		if (strncmp(iter->disk_name, diskname, DISK_NAME_LEN))
+			continue;
+		if (iter->lr == lr) {
+			dev = iter;
+			if (!atomic_add_unless(&iter->in_use, 1, 1)) {
+				dev = NULL;
+				in_use = true;
+			}
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&list_spinlock, flags);
+
+	if (!dev)
+		return NULL;
+
+	dev->bdev = bdev;
+	return dev;
+}
+
+/* Free up the Opal dev and its keys during two scenarios:
+ *
+ * 1) When a command is complete that no longer requires
+ *    the opal dev to be around.
+ * 2) When a command, including Opal Save fails we clean
+ *    and free the opal dev.
+ *
+ *    If we find the opal dev structure in the list of
+ *    saved passwords we will *not* remove it.
+ */
+static void remove_and_clean_opal_dev(struct opal_dev *dev)
+{
+	struct opal_dev *iter;
+	bool found = false;
+
+	spin_lock(&list_spinlock);
+	list_for_each_entry(iter, &opal_list, node) {
+		if (iter == dev) {
+			found = true;
+			break;
+		}
+	}
+
+	spin_unlock(&list_spinlock);
+	if (!found) {
+		clean_opal_key(dev);
+		clean_function_data(dev);
+		kfree(dev);
+	}
+}
+
+static struct opal_dev *get_or_create_opal_dev(struct block_device *bdev,
+					       u8 lr, bool use_new)
+{
+	struct opal_dev *dev = NULL;
+
+	if (!use_new)
+		dev = get_registered_opal_dev(bdev, lr);
+
+	if (!dev)
+		dev = alloc_opal_dev(bdev, lr);
+
+	return dev;
+}
+
+static struct opal_completion *setup_opal_dev(struct block_device *bdev,
+					      struct opal_dev *dev,
+					      const opal_step *funcs,
+					      struct opal_key *key)
+{
+	int ret;
+
+	dev->bdev = bdev;
+	dev->state = 0;
+	dev->funcs = funcs;
+	dev->TSN = 0;
+	dev->HSN = 0;
+	dev->final_cb = NULL;
+	dev->final_cb_data = NULL;
+	dev->lr = key->lr;
+	dev->error_cb = end_opal_session_error;
+	dev->error_cb_data = dev;
+
+	if (key) {
+		memcpy(dev->key_name, key->key, key->key_len);
+		dev->key_name_len = key->key_len;
+		dev->key_type = key->key_type;
+
+		ret = get_opal_key(dev);
+		if (ret) {
+			kfree(dev->completion);
+			pr_err("%s: Couldn't get key: %d\n",
+			       dev->disk_name, ret);
+			return ERR_PTR(ret);
+		}
+	}
+	dev->func_data = NULL;
+	dev->completion->completion_status = 0;
+	return dev->completion;
+}
+
+static int internal_setup_lr(struct block_device *bdev,
+			     struct opal_user_lr_setup *setup)
+{
+	struct opal_dev *dev;
+	struct opal_completion *completion;
+	void *data[3] = { NULL };
+	const opal_step lr_funcs[] = {
+		opal_discovery0,
+		start_auth_opal_session,
+		setup_locking_range,
+		get_active_key,
+		gen_key,
+		end_opal_session,
+		NULL,
+	};
+	int ret;
+
+	dev = get_or_create_opal_dev(bdev, setup->key.lr, true);
+	if (!dev)
+		return -ENOMEM;
+
+	completion = setup_opal_dev(bdev, dev, lr_funcs, &setup->key);
+	if (IS_ERR(completion)) {
+		ret = PTR_ERR(completion);
+		goto error_return;
+	}
+
+	dev->func_data = data;
+	dev->num_func_data = 3;
+	dev->func_data[1] = &setup->who;
+	dev->func_data[2] = setup;
+
+	next(0, dev);
+	ret = wait_for_cmd_completion(completion);
+
+ error_return:
+	remove_and_clean_opal_dev(dev);
+	return ret;
+}
+
+int opal_revert(struct block_device *bdev, struct opal_key *key)
+{
+	const opal_step revert_funcs[] = {
+		opal_discovery0,
+		start_SIDASP_opal_session,
+		revert_tper, /* controller will terminate session */
+		NULL,
+	};
+
+	return opal_register(bdev, key, revert_funcs);
+}
+
+int activate_user(struct block_device *bdev, struct opal_activate_user *act)
+{
+	const opal_step act_funcs[] = {
+		opal_discovery0,
+		start_admin1LSP_opal_session,
+		internal_activate_user,
+		end_opal_session,
+		NULL
+	};
+	struct opal_dev *dev;
+	struct opal_completion *completion;
+	void *data[3] = { NULL };
+	int ret;
+
+	dev = get_or_create_opal_dev(bdev, act->key.lr, true);
+	if (!dev)
+		return -ENOMEM;
+
+	completion = setup_opal_dev(bdev, dev, act_funcs, &act->key);
+	if (IS_ERR(completion)) {
+		ret = PTR_ERR(completion);
+		goto error_return;
+	}
+
+	dev->num_func_data = 3;
+	dev->func_data = data;
+	dev->func_data[1] = act;
+	dev->func_data[2] = act;
+
+	next(0, dev);
+	ret = wait_for_cmd_completion(completion);
+
+ error_return:
+	remove_and_clean_opal_dev(dev);
+	return ret;
+}
+
+int opal_set_pw(struct block_device *bdev, struct opal_new_pw *pw)
+
+{
+	const opal_step pw_funcs[] = {
+		opal_discovery0,
+		start_auth_opal_session,
+		set_new_pw,
+		end_opal_session,
+		NULL
+	};
+	struct opal_dev *dev;
+	struct opal_completion *completion;
+	void *data[3] = { NULL };
+	int ret;
+
+	dev = get_or_create_opal_dev(bdev, pw->current_pin.lr, true);
+	if (!dev)
+		return -ENOMEM;
+
+	completion = setup_opal_dev(bdev, dev, pw_funcs, &pw->current_pin);
+	if (IS_ERR(completion)) {
+		ret = PTR_ERR(completion);
+		goto error_return;
+	}
+
+	dev->num_func_data = 3;
+	dev->func_data = data;
+	dev->func_data[1] = (void *) &pw->who;
+	dev->func_data[2] = (void *) pw;
+
+	next(0, dev);
+	ret = wait_for_cmd_completion(completion);
+
+ error_return:
+	remove_and_clean_opal_dev(dev);
+	return ret;
+}
+
+int opal_act_lsp_int(struct block_device *bdev, struct opal_key *key,
+		     const opal_step *funcs)
+{
+	struct opal_dev *dev;
+	struct opal_completion *completion;
+	int ret;
+
+	dev = get_or_create_opal_dev(bdev, key->lr, true);
+	if (!dev)
+		return -ENOMEM;
+	completion = setup_opal_dev(bdev, dev, funcs, key);
+	if (IS_ERR(completion)) {
+		ret = PTR_ERR(completion);
+		goto error_return;
+	}
+
+	next(0, dev);
+	ret = wait_for_cmd_completion(completion);
+
+ error_return:
+	remove_and_clean_opal_dev(dev);
+	return ret;
+}
+
+
+static int opal_save_internal(struct block_device *bdev,
+			      struct opal_lock_unlock *lk)
+{
+	void *func_data[3] = { NULL };
+	struct opal_dev *dev;
+	struct opal_completion *completion;
+	const opal_step _auth_funcs[] = {
+		opal_discovery0,
+		start_auth_opal_session,
+		query_locking_range,
+		end_opal_session,
+		opal_register_cont,
+		NULL
+	};
+	int ret;
+
+	dev = get_or_create_opal_dev(bdev, lk->key.lr, false);
+	if (!dev)
+		return -ENOMEM;
+	completion = setup_opal_dev(bdev, dev, _auth_funcs, &lk->key);
+	if (IS_ERR(completion)) {
+		ret = PTR_ERR(completion);
+		goto error_return;
+	}
+
+	dev->num_func_data = 3;
+	dev->func_data = func_data;
+	dev->func_data[1] = &lk->authority;
+	dev->lkul = *lk;
+
+	next(0, dev);
+	ret = wait_for_cmd_completion(completion);
+
+ error_return:
+	remove_and_clean_opal_dev(dev);
+	return ret;
+}
+
+static int add_user_lr_internal(struct block_device *bdev,
+				struct opal_lock_unlock *lk)
+{
+	void *func_data[3] = { NULL };
+	struct opal_dev *dev;
+	struct opal_completion *completion;
+	const opal_step funcs[] = {
+		opal_discovery0,
+		start_admin1LSP_opal_session,
+		add_user_to_lr,
+		end_opal_session,
+		NULL
+	};
+	int ret;
+
+	dev = get_or_create_opal_dev(bdev, lk->key.lr, true);
+	if (!dev)
+		return -ENOMEM;
+	completion = setup_opal_dev(bdev, dev, funcs, &lk->key);
+	if (IS_ERR(completion)) {
+		ret = PTR_ERR(completion);
+		goto error_return;
+	}
+
+	dev->num_func_data = 3;
+	dev->func_data = func_data;
+	dev->func_data[2] = lk;
+
+	next(0, dev);
+	ret = wait_for_cmd_completion(completion);
+
+ error_return:
+	remove_and_clean_opal_dev(dev);
+	return ret;
+}
+
+/* These are global'd because both lock_unlock_internal
+ * and opal_unlock_from_suspend need them.
+ */
+const opal_step ulk_funcs_SUM[] = {
+	opal_discovery0,
+	start_auth_opal_session,
+	lock_unlock_locking_range_SUM,
+	end_opal_session,
+	NULL
+};
+const opal_step _unlock_funcs[] = {
+	opal_discovery0,
+	start_auth_opal_session,
+	lock_unlock_locking_range,
+	end_opal_session,
+	NULL
+};
+static int lock_unlock_internal(struct block_device *bdev,
+				struct opal_lock_unlock *lk)
+{
+	void *func_data[3] = { NULL };
+	struct opal_dev *dev;
+	struct opal_completion *completion;
+
+	int ret;
+
+	dev = get_or_create_opal_dev(bdev, lk->key.lr, true);
+	if (!dev)
+		return -ENOMEM;
+
+	if (lk->authority.SUM)
+		completion = setup_opal_dev(bdev, dev, ulk_funcs_SUM, &lk->key);
+	else
+		completion = setup_opal_dev(bdev, dev, _unlock_funcs, &lk->key);
+
+	if (IS_ERR(completion)) {
+		ret = PTR_ERR(completion);
+		goto error_return;
+	}
+
+	dev->num_func_data = 3;
+	dev->func_data = func_data;
+	dev->func_data[1] = &lk->authority;
+	dev->func_data[2] = lk;
+
+	next(0, dev);
+	ret = wait_for_cmd_completion(completion);
+
+ error_return:
+	remove_and_clean_opal_dev(dev);
+	return ret;
+}
+
+int opal_erase_locking_range(struct block_device *bdev, struct sed_key *key)
+{
+	struct opal_dev *dev;
+	struct opal_completion *completion;
+	struct opal_key k;
+	int ret;
+	const opal_step erase_funcs[] = {
+		opal_discovery0,
+		start_admin1LSP_opal_session,
+		erase_locking_range,
+		end_opal_session,
+		NULL,
+	};
+
+	if (!bdev || !bdev->bd_disk) {
+		pr_err("Can't save password for NULL block device.\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&k, key->opal, sizeof(*key->opal)))
+		return -EFAULT;
+
+	dev = get_or_create_opal_dev(bdev, k.lr, true);
+	if (!dev)
+		return -ENOMEM;
+
+	completion = setup_opal_dev(bdev, dev, erase_funcs, &k);
+	if (IS_ERR(completion)) {
+		ret = PTR_ERR(completion);
+		goto error_return;
+	}
+
+	next(0, dev);
+	ret = wait_for_cmd_completion(completion);
+
+ error_return:
+	remove_and_clean_opal_dev(dev);
+	return ret;
+}
+EXPORT_SYMBOL(opal_erase_locking_range);
+
+int opal_enable_disable_shadow_mbr(struct block_device *bdev,
+				   struct sed_key *key)
+{
+	void *func_data[6] = { NULL };
+	struct opal_mbr_data mbr;
+	struct opal_dev *dev;
+	struct opal_completion *completion;
+	const opal_step mbr_funcs[] = {
+		opal_discovery0,
+		start_admin1LSP_opal_session,
+		set_mbr_done,
+		end_opal_session,
+		start_admin1LSP_opal_session,
+		set_mbr_enable_disable,
+		end_opal_session,
+		NULL,
+	};
+	int ret;
+
+	if (!bdev || !bdev->bd_disk) {
+		pr_err("Can't save password for NULL block device.\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&mbr, key->opal_mbr, sizeof(*key->opal_mbr)))
+		return -EFAULT;
+
+	if (mbr.enable_disable != OPAL_MBR_ENABLE &&
+	    mbr.enable_disable != OPAL_MBR_DISABLE)
+		return -EINVAL;
+
+	dev = get_or_create_opal_dev(bdev, mbr.key.lr, true);
+	if (!dev)
+		return -ENOMEM;
+
+	completion = setup_opal_dev(bdev, dev, mbr_funcs, &mbr.key);
+	if (IS_ERR(completion)) {
+		ret = PTR_ERR(completion);
+		goto error_return;
+	}
+
+	dev->num_func_data = 6;
+	dev->func_data = func_data;
+	dev->func_data[2] = &mbr.enable_disable;
+	dev->func_data[5] = &mbr.enable_disable;
+
+	next(0, dev);
+	ret = wait_for_cmd_completion(completion);
+
+ error_return:
+	remove_and_clean_opal_dev(dev);
+	return ret;
+
+}
+EXPORT_SYMBOL(opal_enable_disable_shadow_mbr);
+
+int opal_save(struct block_device *bdev, struct sed_key *key)
+{
+	struct opal_lock_unlock lkul;
+
+	if (!bdev || !bdev->bd_disk) {
+		pr_err("Can't save password for NULL block device.\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&lkul, key->opal_lk_unlk, sizeof(*key->opal)))
+		return -EFAULT;
+
+	return opal_save_internal(bdev, &lkul);
+}
+EXPORT_SYMBOL(opal_save);
+
+int opal_add_user_to_lr(struct block_device *bdev, struct sed_key *key)
+{
+	struct opal_lock_unlock lkul;
+
+	if (copy_from_user(&lkul, key->opal_lk_unlk, sizeof(lkul)))
+		return -EFAULT;
+
+	if (!bdev || !bdev->bd_disk) {
+		pr_err("Can't assign user to LR without backing disk\n");
+		return -EFAULT;
+	}
+	if (lkul.l_state != OPAL_RO && lkul.l_state != OPAL_RW) {
+		pr_err("Locking state was not RO or RW\n");
+		return -EINVAL;
+	}
+	if (lkul.authority.who < OPAL_USER1 &&
+	    lkul.authority.who > OPAL_USER9) {
+		pr_err("Authority was not within the range of users: %d\n",
+		       lkul.authority.who);
+		return -EINVAL;
+	}
+	if (lkul.authority.SUM) {
+		pr_err("%s not supported in SUM. Use setup locking range\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	return add_user_lr_internal(bdev, &lkul);
+}
+EXPORT_SYMBOL(opal_add_user_to_lr);
+
+int opal_reverttper(struct block_device *bdev, struct sed_key *key)
+{
+	struct opal_key k;
+
+	if (copy_from_user(&k, key->opal, sizeof(*key->opal)))
+		return -EFAULT;
+
+	return opal_revert(bdev, &k);
+}
+EXPORT_SYMBOL(opal_reverttper);
+
+int opal_lock_unlock(struct block_device *bdev, struct sed_key *key)
+{
+	struct opal_lock_unlock k;
+
+	if (copy_from_user(&k, key->opal_lk_unlk, sizeof(*key->opal_lk_unlk)))
+		return -EFAULT;
+
+	if (k.authority.who < OPAL_ADMIN1 || k.authority.who > OPAL_USER9)
+		return -EINVAL;
+
+	return lock_unlock_internal(bdev, &k);
+}
+EXPORT_SYMBOL(opal_lock_unlock);
+
+int opal_take_ownership(struct block_device *bdev, struct sed_key *key)
+{
+	struct opal_key k;
+	const opal_step owner_funcs[] = {
+		opal_discovery0,
+		start_anybodyASP_opal_session,
+		get_msid_cpin_pin,
+		end_opal_session,
+		start_SIDASP_opal_session,
+		set_sid_cpin_pin,
+		end_opal_session,
+		NULL
+	};
+
+	if (!bdev || !bdev->bd_disk) {
+		pr_err("Can't save password for NULL block device.\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&k, key->opal, sizeof(*key->opal)))
+		return -EFAULT;
+
+	return opal_register(bdev, &k, owner_funcs);
+}
+EXPORT_SYMBOL(opal_take_ownership);
+
+int opal_activate_lsp(struct block_device *bdev, struct sed_key *key)
+{
+	struct opal_key k;
+	const opal_step active_funcs[] = {
+		opal_discovery0,
+		start_SIDASP_opal_session, /* Open session as SID auth */
+		get_lsp_lifecycle,
+		activate_lsp,
+		end_opal_session,
+		NULL
+	};
+
+	if (!bdev || !bdev->bd_disk) {
+		pr_err("Can't save password for NULL block device.\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&k, key->opal, sizeof(*key->opal)))
+		return -EFAULT;
+
+	return opal_act_lsp_int(bdev, &k, active_funcs);
+}
+EXPORT_SYMBOL(opal_activate_lsp);
+
+int opal_setup_locking_range(struct block_device *bdev, struct sed_key *pw)
+{
+	struct opal_user_lr_setup k;
+
+	if (!bdev || !bdev->bd_disk) {
+		pr_err("Can't save password for NULL block device.\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&k, pw->opal_lrs, sizeof(*pw->opal_lrs)))
+		return -EFAULT;
+
+	return internal_setup_lr(bdev, &k);
+}
+
+int opal_set_new_pw(struct block_device *bdev, struct sed_key *pw)
+{
+	struct opal_new_pw k;
+
+	if (pw->sed_type != OPAL_PW)
+		return -EINVAL;
+
+	if (copy_from_user(&k, pw->opal_pw, sizeof(*pw->opal_pw)))
+		return -EFAULT;
+
+	if (k.who.who < OPAL_ADMIN1 || k.who.who > OPAL_USER9)
+		return -EINVAL;
+
+	return opal_set_pw(bdev, &k);
+}
+EXPORT_SYMBOL(opal_set_new_pw);
+
+int opal_activate_user(struct block_device *bdev, struct sed_key *pw)
+{
+	struct opal_activate_user k;
+
+	if (pw->sed_type != OPAL_ACT_USR) {
+		pr_err("Sed type was not act user\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&k, pw->opal_act, sizeof(*pw->opal_act))) {
+		pr_err("copy from user error\n");
+		return -EFAULT;
+	}
+
+	/* We can't activate Admin1 it's active as manufactured */
+	if (k.who.who < OPAL_USER1 && k.who.who > OPAL_USER9) {
+		pr_err("Who was not a valid user: %d \n", k.who.who);
+		return -EINVAL;
+	}
+
+	return activate_user(bdev, &k);
+
+}
+EXPORT_SYMBOL(opal_activate_user);
+
+int opal_unlock_from_suspend(struct opal_suspend_unlk *data)
+{
+	const char *diskname = data->name;
+	struct opal_dev *iter, *dev = NULL;
+	struct opal_completion *completion;
+	void *func_data[3] = { NULL };
+
+	spin_lock(&list_spinlock);
+	list_for_each_entry(iter, &opal_list, node) {
+		if (strncmp(iter->disk_name, diskname, DISK_NAME_LEN)) {
+			pr_err("iterdisk was %s and diskname is %s\n",
+			       iter->disk_name, diskname);
+			continue;
+		}
+		if (atomic_add_unless(&iter->in_use, 1, 1)) {
+			dev = iter;
+			dev->func_data = func_data;
+			dev->resume_from_suspend = true;
+			dev->resume_data = data;
+			dev->final_cb = unlock_suspend_final;
+			dev->final_cb_data = dev;
+			dev->error_cb = end_opal_session_error;
+			dev->error_cb_data = dev;
+			dev->state = 0;
+			if (dev->lkul.authority.SUM)
+				dev->funcs = ulk_funcs_SUM;
+			else
+				dev->funcs = _unlock_funcs;
+			dev->TSN = 0;
+			dev->HSN = 0;
+			dev->func_data[2] = &dev->lkul;
+			dev->func_data[1] = &dev->lkul.authority;
+			completion = dev->completion;
+			next(0, dev);
+			wait_for_cmd_completion(completion);
+		}
+	}
+	spin_unlock(&list_spinlock);
+
+	if (!dev)
+		return -ENODEV;
+	return 0;
+}
+EXPORT_SYMBOL(opal_unlock_from_suspend);
diff --git a/lib/sed-opal_internal.h b/lib/sed-opal_internal.h
new file mode 100644
index 0000000..54041cb
--- /dev/null
+++ b/lib/sed-opal_internal.h
@@ -0,0 +1,587 @@
+/*
+ * Copyright ? 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Author:
+ *    Rafael Antognolli <rafael.antognolli at intel.com>
+ *    Scott  Bauer      <scott.bauer at intel.com>
+ */
+
+#ifndef _NVME_OPAL_INTERNAL_H
+#define _NVME_OPAL_INTERNAL_H
+
+#include <linux/key-type.h>
+#include <keys/user-type.h>
+
+#define DTAERROR_NO_METHOD_STATUS 0x89
+#define GENERIC_HOST_SESSION_NUM 0x41
+
+static const char *opal_errors[] = {
+	"Success",
+	"Not Authorized",
+	"Unknown Error",
+	"SP Busy",
+	"SP Failed",
+	"SP Disabled",
+	"SP Frozen",
+	"No Sessions Available",
+	"Uniqueness Conflict",
+	"Insufficient Space",
+	"Insufficient Rows",
+	"Invalid Function",
+	"Invalid Parameter",
+	"Invalid Reference",
+	"Unknown Error",
+	"TPER Malfunction",
+	"Transaction Failure",
+	"Response Overflow",
+	"Authority Locked Out",
+};
+
+static const char *opal_error_to_human(int error)
+{
+	if (error == 0x3f)
+		return "Failed";
+
+	if (error >= ARRAY_SIZE(opal_errors) || error < 0)
+		return "Unknown Error";
+
+	return opal_errors[error];
+}
+
+/* User IDs used in the TCG storage SSCs */
+static const u8 OPALUID[][8] = {
+	/* users */
+
+	/* session management  */
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
+	/* special "thisSP" syntax */
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+	/* Administrative SP */
+	{ 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
+	/* Locking SP */
+	{ 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
+	/* ENTERPRISE Locking SP  */
+	{ 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
+	/* anybody */
+	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
+	/* SID */
+	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
+	/* ADMIN1 */
+	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
+	/* USER1 */
+	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
+	/* USER2 */
+	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
+	/* PSID user */
+	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
+	/* BandMaster 0 */
+	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
+	 /* EraseMaster */
+	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
+
+	/* tables */
+
+	/* Locking_GlobalRange */
+	{ 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
+	/* ACE_Locking_Range_Set_RdLocked UID */
+	{ 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
+	/* ACE_Locking_Range_Set_WrLocked UID */
+	{ 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
+	/* MBR Control */
+	{ 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
+	/* Shadow MBR */
+	{ 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
+	/* AUTHORITY_TABLE */
+	{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
+	/* C_PIN_TABLE */
+	{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
+	/* OPAL Locking Info */
+	{ 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
+	/* Enterprise Locking Info */
+	{ 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
+
+	/* C_PIN_TABLE object ID's */
+
+	/* C_PIN_MSID */
+	{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
+	/* C_PIN_SID */
+	{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
+	 /* C_PIN_ADMIN1 */
+	{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
+
+	/* half UID's (only first 4 bytes used) */
+
+	/* Half-UID ? Authority_object_ref */
+	{ 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
+	/* Half-UID ? Boolean ACE */
+	{ 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
+
+	/* special value for omitted optional parameter */
+
+	/* HEXFF for omitted */
+	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+static const size_t OPAL_UID_LENGTH = 8;
+static const size_t OPAL_MSID_KEYLEN = 15;
+static const size_t OPAL_UID_LENGTH_HALF = 4;
+
+
+/* Enum to index OPALUID array */
+enum OPAL_UID {
+	/* users */
+	OPAL_SMUID_UID,
+	OPAL_THISSP_UID,
+	OPAL_ADMINSP_UID,
+	OPAL_LOCKINGSP_UID,
+	OPAL_ENTERPRISE_LOCKINGSP_UID,
+	OPAL_ANYBODY_UID,
+	OPAL_SID_UID,
+	OPAL_ADMIN1_UID,
+	OPAL_USER1_UID,
+	OPAL_USER2_UID,
+	OPAL_PSID_UID,
+	OPAL_ENTERPRISE_BANDMASTER0_UID,
+	OPAL_ENTERPRISE_ERASEMASTER_UID,
+	/* tables */
+	OPAL_LOCKINGRANGE_GLOBAL,
+	OPAL_LOCKINGRANGE_ACE_RDLOCKED,
+	OPAL_LOCKINGRANGE_ACE_WRLOCKED,
+	OPAL_MBRCONTROL,
+	OPAL_MBR,
+	OPAL_AUTHORITY_TABLE,
+	OPAL_C_PIN_TABLE,
+	OPAL_LOCKING_INFO_TABLE,
+	OPAL_ENTERPRISE_LOCKING_INFO_TABLE,
+	/* C_PIN_TABLE object ID's */
+	OPAL_C_PIN_MSID,
+	OPAL_C_PIN_SID,
+	OPAL_C_PIN_ADMIN1,
+	/* half UID's (only first 4 bytes used) */
+	OPAL_HALF_UID_AUTHORITY_OBJ_REF,
+	OPAL_HALF_UID_BOOLEAN_ACE,
+	/* omitted optional parameter */
+	OPAL_UID_HEXFF,
+};
+
+/*
+ * TCG Storage SSC Methods.
+ */
+static const u8 OPALMETHOD[][8] = {
+	/* Properties */
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
+	/* STARTSESSION */
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
+	/* Revert */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
+	/* Activate */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
+	/* Enterprise Get */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
+	/* Enterprise Set */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
+	/* NEXT */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
+	/* Enterprise Authenticate */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
+	/* GetACL */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
+	/* GenKey */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
+	/* revertSP */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
+	/* Get */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
+	/* Set */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
+	/* Authenticate */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
+	/* Random */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
+	/* Erase */
+	{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
+};
+static const size_t OPAL_METHOD_LENGTH = 8;
+
+/* Enum for indexing the OPALMETHOD array */
+enum OPAL_METHOD {
+	OPAL_PROPERTIES,
+	OPAL_STARTSESSION,
+	OPAL_REVERT,
+	OPAL_ACTIVATE,
+	OPAL_EGET,
+	OPAL_ESET,
+	OPAL_NEXT,
+	OPAL_EAUTHENTICATE,
+	OPAL_GETACL,
+	OPAL_GENKEY,
+	OPAL_REVERTSP,
+	OPAL_GET,
+	OPAL_SET,
+	OPAL_AUTHENTICATE,
+	OPAL_RANDOM,
+	OPAL_ERASE,
+};
+
+enum OPAL_RESPONSE_TOKEN {
+	OPAL_DTA_TOKENID_BYTESTRING = 0xe0,
+	OPAL_DTA_TOKENID_SINT = 0xe1,
+	OPAL_DTA_TOKENID_UINT = 0xe2,
+	OPAL_DTA_TOKENID_TOKEN = 0xe3, /* actual token is returned */
+	OPAL_DTA_TOKENID_INVALID = 0X0
+};
+
+enum OPAL_TOKEN {
+	/* Boolean */
+	OPAL_TRUE = 0x01,
+	OPAL_FALSE = 0x00,
+	OPAL_BOOLEAN_EXPR = 0x03,
+	/* cellblocks */
+	OPAL_TABLE = 0x00,
+	OPAL_STARTROW = 0x01,
+	OPAL_ENDROW = 0x02,
+	OPAL_STARTCOLUMN = 0x03,
+	OPAL_ENDCOLUMN = 0x04,
+	OPAL_VALUES = 0x01,
+	/* authority table */
+	OPAL_PIN = 0x03,
+	/* locking tokens */
+	OPAL_RANGESTART = 0x03,
+	OPAL_RANGELENGTH = 0x04,
+	OPAL_READLOCKENABLED = 0x05,
+	OPAL_WRITELOCKENABLED = 0x06,
+	OPAL_READLOCKED = 0x07,
+	OPAL_WRITELOCKED = 0x08,
+	OPAL_ACTIVEKEY = 0x0A,
+	/* locking info table */
+	OPAL_MAXRANGES = 0x04,
+	 /* mbr control */
+	OPAL_MBRENABLE = 0x01,
+	OPAL_MBRDONE = 0x02,
+	/* properties */
+	OPAL_HOSTPROPERTIES = 0x00,
+	/* atoms */
+	OPAL_STARTLIST = 0xf0,
+	OPAL_ENDLIST = 0xf1,
+	OPAL_STARTNAME = 0xf2,
+	OPAL_ENDNAME = 0xf3,
+	OPAL_CALL = 0xf8,
+	OPAL_ENDOFDATA = 0xf9,
+	OPAL_ENDOFSESSION = 0xfa,
+	OPAL_STARTTRANSACTON = 0xfb,
+	OPAL_ENDTRANSACTON = 0xfC,
+	OPAL_EMPTYATOM = 0xff,
+	OPAL_WHERE = 0x00,
+};
+
+/* Useful tiny atoms.
+ * Useful for table columns etc
+ */
+enum OPAL_TINY_ATOM {
+	OPAL_TINY_UINT_00 = 0x00,
+	OPAL_TINY_UINT_01 = 0x01,
+	OPAL_TINY_UINT_02 = 0x02,
+	OPAL_TINY_UINT_03 = 0x03,
+	OPAL_TINY_UINT_04 = 0x04,
+	OPAL_TINY_UINT_05 = 0x05,
+	OPAL_TINY_UINT_06 = 0x06,
+	OPAL_TINY_UINT_07 = 0x07,
+	OPAL_TINY_UINT_08 = 0x08,
+	OPAL_TINY_UINT_09 = 0x09,
+	OPAL_TINY_UINT_10 = 0x0a,
+	OPAL_TINY_UINT_11 = 0x0b,
+	OPAL_TINY_UINT_12 = 0x0c,
+	OPAL_TINY_UINT_13 = 0x0d,
+	OPAL_TINY_UINT_14 = 0x0e,
+	OPAL_TINY_UINT_15 = 0x0f,
+};
+
+enum OPAL_ATOM_WIDTH {
+	OPAL_WIDTH_TINY,
+	OPAL_WIDTH_SHORT,
+	OPAL_WIDTH_MEDIUM,
+	OPAL_WIDTH_LONG,
+	OPAL_WIDTH_TOKEN
+};
+
+/* Locking state for a locking range */
+enum OPAL_LOCKINGSTATE {
+	OPAL_LOCKING_READWRITE = 0x01,
+	OPAL_LOCKING_READONLY = 0x02,
+	OPAL_LOCKING_LOCKED = 0x03,
+};
+
+/*
+ * Structures to build and decode the Opal SSC messages
+ * fields that are NOT really numeric are defined as u8[] to
+ * help reduce the endianness issues
+ */
+
+/* Comm Packet (header) for transmissions. */
+struct opal_compacket {
+	u32 reserved0;
+	u8 extendedComID[4];
+	u32 outstandingData;
+	u32 minTransfer;
+	u32 length;
+};
+
+/* Packet structure. */
+struct opal_packet {
+	u32 TSN;
+	u32 HSN;
+	u32 seq_number;
+	u16 reserved0;
+	u16 ack_type;
+	u32 acknowledgment;
+	u32 length;
+};
+
+/* Data sub packet header */
+struct opal_data_subpacket {
+	u8 reserved0[6];
+	u16 kind;
+	u32 length;
+};
+
+/* header of a response */
+struct opal_header {
+	struct opal_compacket cp;
+	struct opal_packet pkt;
+	struct opal_data_subpacket subpkt;
+};
+
+#define FC_TPER       0x0001
+#define FC_LOCKING    0x0002
+#define FC_GEOMETRY   0x0003
+#define FC_ENTERPRISE 0x0100
+#define FC_DATASTORE  0x0202
+#define FC_SINGLEUSER 0x0201
+#define FC_OPALV100   0x0200
+#define FC_OPALV200   0x0203
+
+/*
+ * The Discovery 0 Header. As defined in
+ * Opal SSC Documentation
+ */
+struct d0_header {
+	u32 length; /* the length of the header 48 in 2.00.100 */
+	u32 revision; /**< revision of the header 1 in 2.00.100 */
+	u32 reserved01;
+	u32 reserved02;
+	/*
+	 * the remainder of the structure is vendor specific and will not be
+	 * addressed now
+	 */
+	u8 ignored[32];
+};
+
+/*
+ * TPer Feature Descriptor. Contains flags indicating support for the
+ * TPer features described in the OPAL specification. The names match the
+ * OPAL terminology
+ *
+ * code == 0x001 in 2.00.100
+ */
+struct d0_tper_features {
+	/*
+	 * supported_features bits:
+	 * bit 7: reserved
+	 * bit 6: com ID management
+	 * bit 5: reserved
+	 * bit 4: streaming support
+	 * bit 3: buffer management
+	 * bit 2: ACK/NACK
+	 * bit 1: async
+	 * bit 0: sync
+	 */
+	u8 supported_features;
+	/*
+	 * bytes 5 through 15 are reserved, but we represent the first 3 as
+	 * u8 to keep the other two 32bits integers aligned.
+	 */
+	u8 reserved01[3];
+	u32 reserved02;
+	u32 reserved03;
+};
+
+/*
+ * Locking Feature Descriptor. Contains flags indicating support for the
+ * locking features described in the OPAL specification. The names match the
+ * OPAL terminology
+ *
+ * code == 0x0002 in 2.00.100
+ */
+struct d0_locking_features {
+	/*
+	 * supported_features bits:
+	 * bits 6-7: reserved
+	 * bit 5: MBR done
+	 * bit 4: MBR enabled
+	 * bit 3: media encryption
+	 * bit 2: locked
+	 * bit 1: locking enabled
+	 * bit 0: locking supported
+	 */
+	u8 supported_features;
+	/*
+	 * bytes 5 through 15 are reserved, but we represent the first 3 as
+	 * u8 to keep the other two 32bits integers aligned.
+	 */
+	u8 reserved01[3];
+	u32 reserved02;
+	u32 reserved03;
+};
+
+/*
+ * Geometry Feature Descriptor. Contains flags indicating support for the
+ * geometry features described in the OPAL specification. The names match the
+ * OPAL terminology
+ *
+ * code == 0x0003 in 2.00.100
+ */
+struct d0_geometry_features {
+	/*
+	 * skip 32 bits from header, needed to align the struct to 64 bits.
+	 */
+	u8 header[4];
+	/*
+	 * reserved01:
+	 * bits 1-6: reserved
+	 * bit 0: align
+	 */
+	u8 reserved01;
+	u8 reserved02[7];
+	u32 logical_block_size;
+	u64 alignment_granularity;
+	u64 lowest_aligned_lba;
+};
+
+/*
+ * Enterprise SSC Feature
+ *
+ * code == 0x0100
+ */
+struct d0_enterprise_ssc {
+	u16 baseComID;
+	u16 numComIDs;
+	/* range_crossing:
+	 * bits 1-6: reserved
+	 * bit 0: range crossing
+	 */
+	u8 range_crossing;
+	u8 reserved01;
+	u16 reserved02;
+	u32 reserved03;
+	u32 reserved04;
+};
+
+/*
+ * Opal V1 feature
+ *
+ * code == 0x0200
+ */
+struct d0_opal_v100 {
+	u16 baseComID;
+	u16 numComIDs;
+};
+
+/*
+ * Single User Mode feature
+ *
+ * code == 0x0201
+ */
+struct d0_single_user_mode {
+	u32 num_locking_objects;
+	/* reserved01:
+	 * bit 0: any
+	 * bit 1: all
+	 * bit 2: policy
+	 * bits 3-7: reserved
+	 */
+	u8 reserved01;
+	u8 reserved02;
+	u16 reserved03;
+	u32 reserved04;
+};
+
+/*
+ * Additonal Datastores feature
+ *
+ * code == 0x0202
+ */
+struct d0_datastore_table {
+	u16 reserved01;
+	u16 max_tables;
+	u32 max_size_tables;
+	u32 table_size_alignment;
+};
+
+/*
+ * OPAL 2.0 feature
+ *
+ * code == 0x0203
+ */
+struct d0_opal_v200 {
+	u16 baseComID;
+	u16 numComIDs;
+	/* range_crossing:
+	 * bits 1-6: reserved
+	 * bit 0: range crossing
+	 */
+	u8 range_crossing;
+	/* num_locking_admin_auth:
+	 * not aligned to 16 bits, so use two u8.
+	 * stored in big endian:
+	 * 0: MSB
+	 * 1: LSB
+	 */
+	u8 num_locking_admin_auth[2];
+	/* num_locking_user_auth:
+	 * not aligned to 16 bits, so use two u8.
+	 * stored in big endian:
+	 * 0: MSB
+	 * 1: LSB
+	 */
+	u8 num_locking_user_auth[2];
+	u8 initialPIN;
+	u8 revertedPIN;
+	u8 reserved01;
+	u32 reserved02;
+};
+
+/* Union of features used to parse the discovery 0 response */
+struct d0_features {
+	u16 code;
+	/*
+	 * r_version bits:
+	 * bits 4-7: version
+	 * bits 0-3: reserved
+	 */
+	u8 r_version;
+	u8 length;
+	u8 features[];
+};
+
+struct key *request_user_key(const char *master_desc, const u8 **master_key,
+			     size_t *master_keylen);
+
+#endif /* _NVME_OPAL_INTERNAL_H */
diff --git a/lib/sed-opal_key.c b/lib/sed-opal_key.c
new file mode 100644
index 0000000..0b4de01
--- /dev/null
+++ b/lib/sed-opal_key.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright ? 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Author:
+ *    Rafael Antognolli <rafael.antognolli at intel.com>
+ */
+
+#include <linux/key.h>
+#include "sed-opal_internal.h"
+
+struct key *request_user_key(const char *master_desc, const u8 **master_key,
+			     size_t *master_keylen)
+{
+	const struct user_key_payload *upayload;
+	struct key *ukey;
+
+	ukey = request_key(&key_type_user, master_desc, NULL);
+	if (IS_ERR(ukey))
+		goto error;
+
+	down_read(&ukey->sem);
+	upayload = user_key_payload(ukey);
+	*master_key = upayload->data;
+	*master_keylen = upayload->datalen;
+error:
+	return ukey;
+}
diff --git a/lib/sed.c b/lib/sed.c
new file mode 100644
index 0000000..78f8ba3
--- /dev/null
+++ b/lib/sed.c
@@ -0,0 +1,250 @@
+#include <linux/blkdev.h>
+#include <linux/sed.h>
+#include <linux/sed-opal.h>
+
+#ifndef CONFIG_SED_OPAL
+static int sed_opal_save(struct block_device *bdev, struct sed_key *sed)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_lock_unlock(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_take_ownership(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_activate_lsp(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_set_pw(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_activate_user(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_reverttper(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_setup_locking_range(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_adduser_to_lr(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_do_mbr(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+static int sed_opal_erase_lr(struct block_device *bdev, struct sed_key *key)
+	{ return -EOPNOTSUPP; }
+
+#else
+
+static inline int bdev_sec_capable(struct block_device *bdev)
+{
+	return !(!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+		 !bdev->bd_disk->fops->sec_ops);
+
+}
+
+static int sed_opal_save(struct block_device *bdev, struct sed_key *key)
+{
+	if (bdev_sec_capable(bdev))
+	    return opal_save(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_lock_unlock(struct block_device *bdev, struct sed_key *key)
+{
+
+	if (bdev_sec_capable(bdev))
+		return opal_lock_unlock(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_take_ownership(struct block_device *bdev,
+				   struct sed_key *key)
+{
+
+	if (bdev_sec_capable(bdev))
+		return opal_take_ownership(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_activate_lsp(struct block_device *bdev,
+				 struct sed_key *key)
+{
+
+	if (bdev_sec_capable(bdev))
+		return opal_activate_lsp(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_set_pw(struct block_device *bdev,
+			   struct sed_key *key)
+{
+	if (bdev_sec_capable(bdev))
+		return opal_set_new_pw(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_activate_user(struct block_device *bdev,
+				  struct sed_key *key)
+{
+	if (bdev_sec_capable(bdev))
+		return opal_activate_user(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_reverttper(struct block_device *bdev,
+			       struct sed_key *key)
+{
+	if (bdev_sec_capable(bdev))
+		return opal_reverttper(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_setup_lr(struct block_device *bdev,
+			     struct sed_key *key)
+{
+
+	if (bdev_sec_capable(bdev))
+		return opal_setup_locking_range(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_adduser_to_lr(struct block_device *bdev,
+			     struct sed_key *key)
+{
+
+	if (bdev_sec_capable(bdev))
+		return opal_add_user_to_lr(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_do_mbr(struct block_device *bdev,
+			   struct sed_key *key)
+{
+
+	if (bdev_sec_capable(bdev))
+		return opal_enable_disable_shadow_mbr(bdev, key);
+	return -EOPNOTSUPP;
+}
+
+static int sed_opal_erase_lr(struct block_device *bdev,
+			     struct sed_key *key)
+{
+	if (bdev_sec_capable(bdev))
+		return opal_erase_locking_range(bdev, key);
+	return -EOPNOTSUPP;
+}
+#endif
+
+int sed_save(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL_LOCK_UNLOCK:
+		return sed_opal_save(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_lock_unlock(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL_LOCK_UNLOCK:
+		return sed_opal_lock_unlock(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_take_ownership(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL:
+		return sed_opal_take_ownership(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_activate_lsp(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL:
+		return sed_opal_activate_lsp(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_set_pw(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL_PW:
+		return sed_opal_set_pw(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_activate_user(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL_ACT_USR:
+		return sed_opal_activate_user(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_reverttper(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL:
+		return sed_opal_reverttper(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_setup_locking_range(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL_LR_SETUP:
+		return sed_opal_setup_lr(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_adduser_to_lr(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL_LOCK_UNLOCK:
+		return sed_opal_adduser_to_lr(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_do_mbr(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL_MBR_DATA:
+		return sed_opal_do_mbr(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+int sed_erase_lr(struct block_device *bdev, struct sed_key *key)
+{
+
+	switch (key->sed_type) {
+	case OPAL:
+		return sed_opal_erase_lr(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 3/7] lib: Add Sed to Kconfig and Makefile
  2016-11-16 23:17 ` Scott Bauer
@ 2016-11-16 23:17   ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, sagi, Scott Bauer

Signed-off-by: Scott Bauer <scott.bauer@intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli@intel.com>
---
 lib/Kconfig  | 12 ++++++++++++
 lib/Makefile |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/lib/Kconfig b/lib/Kconfig
index 260a80e..47c39ac 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -547,6 +547,18 @@ config STACKDEPOT
 	bool
 	select STACKTRACE
 
+config SED
+	bool "Self-Encrypting Drive library"
+	help
+	  Provides self-encrypting drive helpers
+
+config SED_OPAL
+	bool "Self-Encrypting Drive library - Opal implementation"
+	depends on SED
+	help
+	  Provides self-encrypting drive helpers for drives that implement the
+	  Opal spec.
+
 config SBITMAP
 	bool
 
diff --git a/lib/Makefile b/lib/Makefile
index 50144a3..976da7a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -229,4 +229,11 @@ obj-$(CONFIG_UBSAN) += ubsan.o
 
 UBSAN_SANITIZE_ubsan.o := n
 
+
+obj-$(CONFIG_SED) += sed.o
+
+obj-$(CONFIG_SED_OPAL) += sed-opal.o
+obj-$(CONFIG_SED_OPAL) += sed-opal_key.o
+
 obj-$(CONFIG_SBITMAP) += sbitmap.o
+
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 3/7] lib: Add Sed to Kconfig and Makefile
@ 2016-11-16 23:17   ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)


Signed-off-by: Scott Bauer <scott.bauer at intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli at intel.com>
---
 lib/Kconfig  | 12 ++++++++++++
 lib/Makefile |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/lib/Kconfig b/lib/Kconfig
index 260a80e..47c39ac 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -547,6 +547,18 @@ config STACKDEPOT
 	bool
 	select STACKTRACE
 
+config SED
+	bool "Self-Encrypting Drive library"
+	help
+	  Provides self-encrypting drive helpers
+
+config SED_OPAL
+	bool "Self-Encrypting Drive library - Opal implementation"
+	depends on SED
+	help
+	  Provides self-encrypting drive helpers for drives that implement the
+	  Opal spec.
+
 config SBITMAP
 	bool
 
diff --git a/lib/Makefile b/lib/Makefile
index 50144a3..976da7a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -229,4 +229,11 @@ obj-$(CONFIG_UBSAN) += ubsan.o
 
 UBSAN_SANITIZE_ubsan.o := n
 
+
+obj-$(CONFIG_SED) += sed.o
+
+obj-$(CONFIG_SED_OPAL) += sed-opal.o
+obj-$(CONFIG_SED_OPAL) += sed-opal_key.o
+
 obj-$(CONFIG_SBITMAP) += sbitmap.o
+
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 4/7] include: Add sec_ops to block device operations
  2016-11-16 23:17 ` Scott Bauer
@ 2016-11-16 23:17   ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, sagi, Scott Bauer

Signed-off-by: Scott Bauer <scott.bauer@intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli@intel.com>
---
 include/linux/blkdev.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index c47c358..6fceff1 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1690,6 +1690,7 @@ struct block_device_operations {
 	void (*swap_slot_free_notify) (struct block_device *, unsigned long);
 	struct module *owner;
 	const struct pr_ops *pr_ops;
+	struct sec_ops *sec_ops;
 };
 
 extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 4/7] include: Add sec_ops to block device operations
@ 2016-11-16 23:17   ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)


Signed-off-by: Scott Bauer <scott.bauer at intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli at intel.com>
---
 include/linux/blkdev.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index c47c358..6fceff1 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1690,6 +1690,7 @@ struct block_device_operations {
 	void (*swap_slot_free_notify) (struct block_device *, unsigned long);
 	struct module *owner;
 	const struct pr_ops *pr_ops;
+	struct sec_ops *sec_ops;
 };
 
 extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int,
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 5/7] nvme: Implement SED Security Operations
  2016-11-16 23:17 ` Scott Bauer
@ 2016-11-16 23:17   ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, sagi, Scott Bauer

This patch implements the sec_ops functions for sending OPAL
packets to the controller.

Signed-off-by: Scott Bauer <scott.bauer@intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli@intel.com>
---
 drivers/nvme/host/core.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/nvme/host/nvme.h |  3 +-
 2 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 79e679d..e8b6804 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -28,6 +28,8 @@
 #include <linux/t10-pi.h>
 #include <scsi/sg.h>
 #include <asm/unaligned.h>
+#include <linux/sed.h>
+#include <linux/sed-opal.h>
 
 #include "nvme.h"
 #include "fabrics.h"
@@ -1067,6 +1069,97 @@ static const struct pr_ops nvme_pr_ops = {
 	.pr_clear	= nvme_pr_clear,
 };
 
+struct sed_cb_data {
+	sec_cb	*cb;
+	void	*cb_data;
+	struct nvme_command cmd;
+};
+
+static void sec_submit_endio(struct request *req, int error)
+{
+	struct sed_cb_data *sed_data = req->end_io_data;
+
+	if (sed_data->cb)
+		sed_data->cb(error, sed_data->cb_data);
+
+	kfree(sed_data);
+	blk_mq_free_request(req);
+}
+
+static int nvme_sec_submit(void *data, u8 opcode, u16 SPSP,
+			   u8 SECP, void *buffer, size_t len,
+			   sec_cb *cb, void *cb_data)
+{
+	struct request_queue *q;
+	struct request *req;
+	struct sed_cb_data *sed_data;
+	struct nvme_ns *ns;
+	struct nvme_command *cmd;
+	int ret;
+
+	ns = data;
+
+	sed_data = kzalloc(sizeof(*sed_data), GFP_NOWAIT);
+	if (!sed_data)
+		return -ENOMEM;
+	sed_data->cb = cb;
+	sed_data->cb_data = cb_data;
+	cmd = &sed_data->cmd;
+
+	cmd->common.opcode = opcode;
+	cmd->common.nsid = ns->ns_id;
+	cmd->common.cdw10[0] = SECP << 24 | SPSP << 8;
+	cmd->common.cdw10[1] = len;
+
+	q = ns->ctrl->admin_q;
+
+	req = nvme_alloc_request(q, cmd, 0, NVME_QID_ANY);
+	if (IS_ERR(req)) {
+		ret = PTR_ERR(req);
+		goto err_free;
+	}
+
+	req->timeout = ADMIN_TIMEOUT;
+	req->special = NULL;
+
+	if (buffer && len) {
+		ret = blk_rq_map_kern(q, req, buffer, len, GFP_NOWAIT);
+		if (ret) {
+			blk_mq_free_request(req);
+			goto err_free;
+		}
+	}
+
+	req->end_io_data = sed_data;
+
+	blk_execute_rq_nowait(q, ns->disk, req, 1, sec_submit_endio);
+	return 0;
+
+err_free:
+	kfree(sed_data);
+}
+
+static int nvme_sec_recv(void *data, u16 SPSP, u8 SECP,
+			 void *buffer, size_t len,
+			 sec_cb *cb, void *cb_data)
+{
+	return nvme_sec_submit(data, nvme_admin_security_recv, SPSP, SECP,
+			       buffer, len, cb, cb_data);
+}
+
+static int nvme_sec_send(void *data, u16 SPSP, u8 SECP,
+			 void *buffer, size_t len,
+			 sec_cb *cb, void *cb_data)
+{
+	return nvme_sec_submit(data, nvme_admin_security_send, SPSP, SECP,
+			       buffer, len, cb, cb_data);
+}
+
+static struct sec_ops nvme_sec_ops = {
+	.send	= nvme_sec_send,
+	.recv	= nvme_sec_recv,
+};
+
 static const struct block_device_operations nvme_fops = {
 	.owner		= THIS_MODULE,
 	.ioctl		= nvme_ioctl,
@@ -1076,6 +1169,7 @@ static const struct block_device_operations nvme_fops = {
 	.getgeo		= nvme_getgeo,
 	.revalidate_disk= nvme_revalidate_disk,
 	.pr_ops		= &nvme_pr_ops,
+	.sec_ops	= &nvme_sec_ops,
 };
 
 static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled)
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index d47f5a5..977c631 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -240,7 +240,8 @@ static inline int nvme_error_status(u16 status)
 
 static inline bool nvme_req_needs_retry(struct request *req, u16 status)
 {
-	return !(status & NVME_SC_DNR || blk_noretry_request(req)) &&
+	return !(status & NVME_SC_DNR || status & NVME_SC_ACCESS_DENIED ||
+		 blk_noretry_request(req)) &&
 		(jiffies - req->start_time) < req->timeout &&
 		req->retries < nvme_max_retries;
 }
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 5/7] nvme: Implement SED Security Operations
@ 2016-11-16 23:17   ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)


This patch implements the sec_ops functions for sending OPAL
packets to the controller.

Signed-off-by: Scott Bauer <scott.bauer at intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli at intel.com>
---
 drivers/nvme/host/core.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/nvme/host/nvme.h |  3 +-
 2 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 79e679d..e8b6804 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -28,6 +28,8 @@
 #include <linux/t10-pi.h>
 #include <scsi/sg.h>
 #include <asm/unaligned.h>
+#include <linux/sed.h>
+#include <linux/sed-opal.h>
 
 #include "nvme.h"
 #include "fabrics.h"
@@ -1067,6 +1069,97 @@ static const struct pr_ops nvme_pr_ops = {
 	.pr_clear	= nvme_pr_clear,
 };
 
+struct sed_cb_data {
+	sec_cb	*cb;
+	void	*cb_data;
+	struct nvme_command cmd;
+};
+
+static void sec_submit_endio(struct request *req, int error)
+{
+	struct sed_cb_data *sed_data = req->end_io_data;
+
+	if (sed_data->cb)
+		sed_data->cb(error, sed_data->cb_data);
+
+	kfree(sed_data);
+	blk_mq_free_request(req);
+}
+
+static int nvme_sec_submit(void *data, u8 opcode, u16 SPSP,
+			   u8 SECP, void *buffer, size_t len,
+			   sec_cb *cb, void *cb_data)
+{
+	struct request_queue *q;
+	struct request *req;
+	struct sed_cb_data *sed_data;
+	struct nvme_ns *ns;
+	struct nvme_command *cmd;
+	int ret;
+
+	ns = data;
+
+	sed_data = kzalloc(sizeof(*sed_data), GFP_NOWAIT);
+	if (!sed_data)
+		return -ENOMEM;
+	sed_data->cb = cb;
+	sed_data->cb_data = cb_data;
+	cmd = &sed_data->cmd;
+
+	cmd->common.opcode = opcode;
+	cmd->common.nsid = ns->ns_id;
+	cmd->common.cdw10[0] = SECP << 24 | SPSP << 8;
+	cmd->common.cdw10[1] = len;
+
+	q = ns->ctrl->admin_q;
+
+	req = nvme_alloc_request(q, cmd, 0, NVME_QID_ANY);
+	if (IS_ERR(req)) {
+		ret = PTR_ERR(req);
+		goto err_free;
+	}
+
+	req->timeout = ADMIN_TIMEOUT;
+	req->special = NULL;
+
+	if (buffer && len) {
+		ret = blk_rq_map_kern(q, req, buffer, len, GFP_NOWAIT);
+		if (ret) {
+			blk_mq_free_request(req);
+			goto err_free;
+		}
+	}
+
+	req->end_io_data = sed_data;
+
+	blk_execute_rq_nowait(q, ns->disk, req, 1, sec_submit_endio);
+	return 0;
+
+err_free:
+	kfree(sed_data);
+}
+
+static int nvme_sec_recv(void *data, u16 SPSP, u8 SECP,
+			 void *buffer, size_t len,
+			 sec_cb *cb, void *cb_data)
+{
+	return nvme_sec_submit(data, nvme_admin_security_recv, SPSP, SECP,
+			       buffer, len, cb, cb_data);
+}
+
+static int nvme_sec_send(void *data, u16 SPSP, u8 SECP,
+			 void *buffer, size_t len,
+			 sec_cb *cb, void *cb_data)
+{
+	return nvme_sec_submit(data, nvme_admin_security_send, SPSP, SECP,
+			       buffer, len, cb, cb_data);
+}
+
+static struct sec_ops nvme_sec_ops = {
+	.send	= nvme_sec_send,
+	.recv	= nvme_sec_recv,
+};
+
 static const struct block_device_operations nvme_fops = {
 	.owner		= THIS_MODULE,
 	.ioctl		= nvme_ioctl,
@@ -1076,6 +1169,7 @@ static const struct block_device_operations nvme_fops = {
 	.getgeo		= nvme_getgeo,
 	.revalidate_disk= nvme_revalidate_disk,
 	.pr_ops		= &nvme_pr_ops,
+	.sec_ops	= &nvme_sec_ops,
 };
 
 static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled)
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index d47f5a5..977c631 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -240,7 +240,8 @@ static inline int nvme_error_status(u16 status)
 
 static inline bool nvme_req_needs_retry(struct request *req, u16 status)
 {
-	return !(status & NVME_SC_DNR || blk_noretry_request(req)) &&
+	return !(status & NVME_SC_DNR || status & NVME_SC_ACCESS_DENIED ||
+		 blk_noretry_request(req)) &&
 		(jiffies - req->start_time) < req->timeout &&
 		req->retries < nvme_max_retries;
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 6/7] nvme: Implement SED Unlock from suspend
  2016-11-16 23:17 ` Scott Bauer
@ 2016-11-16 23:17   ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, sagi, Scott Bauer

This patch implements the necessary logic to unlock a drive after a
suspend-to-RAM.

Signed-off-by: Scott Bauer <scott.bauer@intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli@intel.com>
---
 drivers/nvme/host/core.c | 24 ++++++++++++++++++++++++
 drivers/nvme/host/nvme.h |  1 +
 drivers/nvme/host/pci.c  |  7 ++++++-
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index e8b6804..0a2b866 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1155,6 +1155,30 @@ static int nvme_sec_send(void *data, u16 SPSP, u8 SECP,
 			       buffer, len, cb, cb_data);
 }
 
+void nvme_unlock_from_suspend(struct nvme_ctrl *ctrl)
+{
+	struct opal_suspend_unlk ulk = { 0 };
+	struct nvme_ns *ns;
+	char diskname[DISK_NAME_LEN];
+	mutex_lock(&ctrl->namespaces_mutex);
+	if (list_empty(&ctrl->namespaces))
+		goto out_no_namespace;
+	ulk.data = ns =list_first_entry(&ctrl->namespaces, struct nvme_ns, list);
+	mutex_unlock(&ctrl->namespaces_mutex);
+	snprintf(diskname, sizeof(diskname), "%sn%d",
+		 dev_name(ctrl->device), ns->instance);
+	ulk.name = diskname;
+
+	ulk.ops.send = nvme_sec_send;
+	ulk.ops.recv = nvme_sec_recv;
+	opal_unlock_from_suspend(&ulk);
+
+	return;
+ out_no_namespace:
+	mutex_unlock(&ctrl->namespaces_mutex);
+}
+EXPORT_SYMBOL_GPL(nvme_unlock_from_suspend);
+
 static struct sec_ops nvme_sec_ops = {
 	.send	= nvme_sec_send,
 	.recv	= nvme_sec_recv,
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 977c631..ac7e5b1 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -260,6 +260,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl);
 
 void nvme_queue_scan(struct nvme_ctrl *ctrl);
 void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
+void nvme_unlock_from_suspend(struct nvme_ctrl *ctrl);
 
 #define NVME_NR_AERS	1
 void nvme_complete_async_event(struct nvme_ctrl *ctrl,
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 0248d0e..3c29f75 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -43,6 +43,7 @@
 #include <linux/types.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <asm/unaligned.h>
+#include <linux/sed-opal.h>
 
 #include "nvme.h"
 
@@ -1758,10 +1759,11 @@ static void nvme_reset_work(struct work_struct *work)
 {
 	struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
 	int result = -ENODEV;
-
+	bool was_suspend = false;
 	if (WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING))
 		goto out;
 
+	was_suspend = !!(dev->ctrl.ctrl_config & NVME_CC_SHN_NORMAL);
 	/*
 	 * If we're called to reset a live controller first shut it down before
 	 * moving on.
@@ -1789,6 +1791,9 @@ static void nvme_reset_work(struct work_struct *work)
 	if (result)
 		goto out;
 
+	if (was_suspend)
+		nvme_unlock_from_suspend(&dev->ctrl);
+
 	result = nvme_setup_io_queues(dev);
 	if (result)
 		goto out;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 6/7] nvme: Implement SED Unlock from suspend
@ 2016-11-16 23:17   ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)


This patch implements the necessary logic to unlock a drive after a
suspend-to-RAM.

Signed-off-by: Scott Bauer <scott.bauer at intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli at intel.com>
---
 drivers/nvme/host/core.c | 24 ++++++++++++++++++++++++
 drivers/nvme/host/nvme.h |  1 +
 drivers/nvme/host/pci.c  |  7 ++++++-
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index e8b6804..0a2b866 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1155,6 +1155,30 @@ static int nvme_sec_send(void *data, u16 SPSP, u8 SECP,
 			       buffer, len, cb, cb_data);
 }
 
+void nvme_unlock_from_suspend(struct nvme_ctrl *ctrl)
+{
+	struct opal_suspend_unlk ulk = { 0 };
+	struct nvme_ns *ns;
+	char diskname[DISK_NAME_LEN];
+	mutex_lock(&ctrl->namespaces_mutex);
+	if (list_empty(&ctrl->namespaces))
+		goto out_no_namespace;
+	ulk.data = ns =list_first_entry(&ctrl->namespaces, struct nvme_ns, list);
+	mutex_unlock(&ctrl->namespaces_mutex);
+	snprintf(diskname, sizeof(diskname), "%sn%d",
+		 dev_name(ctrl->device), ns->instance);
+	ulk.name = diskname;
+
+	ulk.ops.send = nvme_sec_send;
+	ulk.ops.recv = nvme_sec_recv;
+	opal_unlock_from_suspend(&ulk);
+
+	return;
+ out_no_namespace:
+	mutex_unlock(&ctrl->namespaces_mutex);
+}
+EXPORT_SYMBOL_GPL(nvme_unlock_from_suspend);
+
 static struct sec_ops nvme_sec_ops = {
 	.send	= nvme_sec_send,
 	.recv	= nvme_sec_recv,
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 977c631..ac7e5b1 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -260,6 +260,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl);
 
 void nvme_queue_scan(struct nvme_ctrl *ctrl);
 void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
+void nvme_unlock_from_suspend(struct nvme_ctrl *ctrl);
 
 #define NVME_NR_AERS	1
 void nvme_complete_async_event(struct nvme_ctrl *ctrl,
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 0248d0e..3c29f75 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -43,6 +43,7 @@
 #include <linux/types.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <asm/unaligned.h>
+#include <linux/sed-opal.h>
 
 #include "nvme.h"
 
@@ -1758,10 +1759,11 @@ static void nvme_reset_work(struct work_struct *work)
 {
 	struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
 	int result = -ENODEV;
-
+	bool was_suspend = false;
 	if (WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING))
 		goto out;
 
+	was_suspend = !!(dev->ctrl.ctrl_config & NVME_CC_SHN_NORMAL);
 	/*
 	 * If we're called to reset a live controller first shut it down before
 	 * moving on.
@@ -1789,6 +1791,9 @@ static void nvme_reset_work(struct work_struct *work)
 	if (result)
 		goto out;
 
+	if (was_suspend)
+		nvme_unlock_from_suspend(&dev->ctrl);
+
 	result = nvme_setup_io_queues(dev);
 	if (result)
 		goto out;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 7/7] block: ioctl: Wire up Sed to block ioctls
  2016-11-16 23:17 ` Scott Bauer
@ 2016-11-16 23:17   ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, sagi, Scott Bauer

Signed-off-by: Scott Bauer <scott.bauer@intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli@intel.com>
---
 block/compat_ioctl.c |  14 ++++
 block/ioctl.c        | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 213 insertions(+), 1 deletion(-)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 556826a..2b83019 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -10,6 +10,7 @@
 #include <linux/syscalls.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
+#include <linux/sed.h>
 
 static int compat_put_ushort(unsigned long arg, unsigned short val)
 {
@@ -746,6 +747,19 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 	case BLKTRACETEARDOWN: /* compatible */
 		ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
 		return ret;
+	case IOC_SED_SAVE:
+	case IOC_SED_LOCK_UNLOCK:
+	case IOC_SED_TAKE_OWNERSHIP:
+	case IOC_SED_ACTIVATE_LSP:
+	case IOC_SED_SET_PW:
+	case IOC_SED_ACTIVATE_USR:
+	case IOC_SED_REVERT_TPR:
+	case IOC_SED_LR_SETUP:
+	case IOC_SED_ADD_USR_TO_LR:
+	case IOC_SED_ENABLE_DISABLE_MBR:
+	case IOC_SED_ERASE_LR:
+		return blkdev_ioctl(bdev, mode, cmd,
+				(unsigned long)compat_ptr(arg));
 	default:
 		if (disk->fops->compat_ioctl)
 			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
diff --git a/block/ioctl.c b/block/ioctl.c
index 755119c..f5c971b 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -8,6 +8,7 @@
 #include <linux/fs.h>
 #include <linux/blktrace_api.h>
 #include <linux/pr.h>
+#include <linux/sed.h>
 #include <asm/uaccess.h>
 
 static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
@@ -392,6 +393,181 @@ static int blkdev_pr_clear(struct block_device *bdev,
 	return ops->pr_clear(bdev, c.key);
 }
 
+static int blkdev_sed_save(struct block_device *bdev,
+		struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_save(bdev, &k);
+}
+
+static int blkdev_sed_lock_unlock(struct block_device *bdev,
+		struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_lock_unlock(bdev, &k);
+}
+
+static int blkdev_sed_take_ownership(struct block_device *bdev,
+		struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_take_ownership(bdev, &k);
+}
+
+static int blkdev_sed_activate_lsp(struct block_device *bdev,
+		struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_activate_lsp(bdev, &k);
+}
+
+static int blkdev_sed_set_pw(struct block_device *bdev,
+			     struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_set_pw(bdev, &k);
+}
+
+static int blkdev_sed_activate_user(struct block_device *bdev,
+				    struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+	return sed_activate_user(bdev, &k);
+}
+
+static int blkdev_sed_reverttper(struct block_device *bdev,
+				 struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_reverttper(bdev, &k);
+}
+
+static int blkdev_sed_setuplr(struct block_device *bdev,
+			      struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_setup_locking_range(bdev, &k);
+}
+
+static int blkdev_sed_add_usr_to_lr(struct block_device *bdev,
+				    struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_adduser_to_lr(bdev, &k);
+}
+
+static int blkdev_sed_do_mbr(struct block_device *bdev,
+			     struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_do_mbr(bdev, &k);
+}
+
+static int blkdev_sed_erase_lr(struct block_device *bdev,
+			     struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_erase_lr(bdev, &k);
+}
+
 /*
  * Is it an unrecognized ioctl? The correct returns are either
  * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a
@@ -551,7 +727,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 		return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev)));
 	case BLKRASET:
 	case BLKFRASET:
-		if(!capable(CAP_SYS_ADMIN))
+		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
 		bdi = blk_get_backing_dev_info(bdev);
 		bdi->ra_pages = (arg * 512) / PAGE_SIZE;
@@ -586,6 +762,28 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 		return blkdev_pr_preempt(bdev, argp, true);
 	case IOC_PR_CLEAR:
 		return blkdev_pr_clear(bdev, argp);
+	case IOC_SED_SAVE:
+		return blkdev_sed_save(bdev, argp);
+	case IOC_SED_LOCK_UNLOCK:
+		return blkdev_sed_lock_unlock(bdev, argp);
+	case IOC_SED_TAKE_OWNERSHIP:
+		return blkdev_sed_take_ownership(bdev, argp);
+	case IOC_SED_ACTIVATE_LSP:
+		return blkdev_sed_activate_lsp(bdev, argp);
+	case IOC_SED_SET_PW:
+		return blkdev_sed_set_pw(bdev, argp);
+	case IOC_SED_ACTIVATE_USR:
+		return blkdev_sed_activate_user(bdev, argp);
+	case IOC_SED_REVERT_TPR:
+		return blkdev_sed_reverttper(bdev, argp);
+	case IOC_SED_LR_SETUP:
+		return blkdev_sed_setuplr(bdev, argp);
+	case IOC_SED_ADD_USR_TO_LR:
+		return blkdev_sed_add_usr_to_lr(bdev, argp);
+	case IOC_SED_ENABLE_DISABLE_MBR:
+		return blkdev_sed_do_mbr(bdev, argp);
+	case IOC_SED_ERASE_LR:
+		return blkdev_sed_erase_lr(bdev, argp);
 	default:
 		return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
 	}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v1 7/7] block: ioctl: Wire up Sed to block ioctls
@ 2016-11-16 23:17   ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-16 23:17 UTC (permalink / raw)


Signed-off-by: Scott Bauer <scott.bauer at intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli at intel.com>
---
 block/compat_ioctl.c |  14 ++++
 block/ioctl.c        | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 213 insertions(+), 1 deletion(-)

diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 556826a..2b83019 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -10,6 +10,7 @@
 #include <linux/syscalls.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
+#include <linux/sed.h>
 
 static int compat_put_ushort(unsigned long arg, unsigned short val)
 {
@@ -746,6 +747,19 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 	case BLKTRACETEARDOWN: /* compatible */
 		ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
 		return ret;
+	case IOC_SED_SAVE:
+	case IOC_SED_LOCK_UNLOCK:
+	case IOC_SED_TAKE_OWNERSHIP:
+	case IOC_SED_ACTIVATE_LSP:
+	case IOC_SED_SET_PW:
+	case IOC_SED_ACTIVATE_USR:
+	case IOC_SED_REVERT_TPR:
+	case IOC_SED_LR_SETUP:
+	case IOC_SED_ADD_USR_TO_LR:
+	case IOC_SED_ENABLE_DISABLE_MBR:
+	case IOC_SED_ERASE_LR:
+		return blkdev_ioctl(bdev, mode, cmd,
+				(unsigned long)compat_ptr(arg));
 	default:
 		if (disk->fops->compat_ioctl)
 			ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
diff --git a/block/ioctl.c b/block/ioctl.c
index 755119c..f5c971b 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -8,6 +8,7 @@
 #include <linux/fs.h>
 #include <linux/blktrace_api.h>
 #include <linux/pr.h>
+#include <linux/sed.h>
 #include <asm/uaccess.h>
 
 static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
@@ -392,6 +393,181 @@ static int blkdev_pr_clear(struct block_device *bdev,
 	return ops->pr_clear(bdev, c.key);
 }
 
+static int blkdev_sed_save(struct block_device *bdev,
+		struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_save(bdev, &k);
+}
+
+static int blkdev_sed_lock_unlock(struct block_device *bdev,
+		struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_lock_unlock(bdev, &k);
+}
+
+static int blkdev_sed_take_ownership(struct block_device *bdev,
+		struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_take_ownership(bdev, &k);
+}
+
+static int blkdev_sed_activate_lsp(struct block_device *bdev,
+		struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_activate_lsp(bdev, &k);
+}
+
+static int blkdev_sed_set_pw(struct block_device *bdev,
+			     struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_set_pw(bdev, &k);
+}
+
+static int blkdev_sed_activate_user(struct block_device *bdev,
+				    struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+	return sed_activate_user(bdev, &k);
+}
+
+static int blkdev_sed_reverttper(struct block_device *bdev,
+				 struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_reverttper(bdev, &k);
+}
+
+static int blkdev_sed_setuplr(struct block_device *bdev,
+			      struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_setup_locking_range(bdev, &k);
+}
+
+static int blkdev_sed_add_usr_to_lr(struct block_device *bdev,
+				    struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_adduser_to_lr(bdev, &k);
+}
+
+static int blkdev_sed_do_mbr(struct block_device *bdev,
+			     struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_do_mbr(bdev, &k);
+}
+
+static int blkdev_sed_erase_lr(struct block_device *bdev,
+			     struct sed_key __user *arg)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+	struct sed_key k;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!ops || !ops->send || !ops->recv)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&k, arg, sizeof(k)))
+		return -EFAULT;
+
+	return sed_erase_lr(bdev, &k);
+}
+
 /*
  * Is it an unrecognized ioctl? The correct returns are either
  * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a
@@ -551,7 +727,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 		return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev)));
 	case BLKRASET:
 	case BLKFRASET:
-		if(!capable(CAP_SYS_ADMIN))
+		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
 		bdi = blk_get_backing_dev_info(bdev);
 		bdi->ra_pages = (arg * 512) / PAGE_SIZE;
@@ -586,6 +762,28 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
 		return blkdev_pr_preempt(bdev, argp, true);
 	case IOC_PR_CLEAR:
 		return blkdev_pr_clear(bdev, argp);
+	case IOC_SED_SAVE:
+		return blkdev_sed_save(bdev, argp);
+	case IOC_SED_LOCK_UNLOCK:
+		return blkdev_sed_lock_unlock(bdev, argp);
+	case IOC_SED_TAKE_OWNERSHIP:
+		return blkdev_sed_take_ownership(bdev, argp);
+	case IOC_SED_ACTIVATE_LSP:
+		return blkdev_sed_activate_lsp(bdev, argp);
+	case IOC_SED_SET_PW:
+		return blkdev_sed_set_pw(bdev, argp);
+	case IOC_SED_ACTIVATE_USR:
+		return blkdev_sed_activate_user(bdev, argp);
+	case IOC_SED_REVERT_TPR:
+		return blkdev_sed_reverttper(bdev, argp);
+	case IOC_SED_LR_SETUP:
+		return blkdev_sed_setuplr(bdev, argp);
+	case IOC_SED_ADD_USR_TO_LR:
+		return blkdev_sed_add_usr_to_lr(bdev, argp);
+	case IOC_SED_ENABLE_DISABLE_MBR:
+		return blkdev_sed_do_mbr(bdev, argp);
+	case IOC_SED_ERASE_LR:
+		return blkdev_sed_erase_lr(bdev, argp);
 	default:
 		return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
 	}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 5/7] nvme: Implement SED Security Operations
  2016-11-16 23:17   ` Scott Bauer
@ 2016-11-17  0:09     ` Keith Busch
  -1 siblings, 0 replies; 38+ messages in thread
From: Keith Busch @ 2016-11-17  0:09 UTC (permalink / raw)
  To: Scott Bauer
  Cc: linux-nvme, Rafael.Antognolli, axboe, jonathan.derrick,
	j.naumann, hch, linux-block, sagi

On Wed, Nov 16, 2016 at 04:17:30PM -0700, Scott Bauer wrote:
> +static int nvme_sec_submit(void *data, u8 opcode, u16 SPSP,
> +			   u8 SECP, void *buffer, size_t len,
> +			   sec_cb *cb, void *cb_data)
> +{
> +	struct request_queue *q;
> +	struct request *req;
> +	struct sed_cb_data *sed_data;
> +	struct nvme_ns *ns;
> +	struct nvme_command *cmd;
> +	int ret;
> +
> +	ns = data;
> +
> +	sed_data = kzalloc(sizeof(*sed_data), GFP_NOWAIT);
> +	if (!sed_data)
> +		return -ENOMEM;
> +	sed_data->cb = cb;
> +	sed_data->cb_data = cb_data;
> +	cmd = &sed_data->cmd;
> +
> +	cmd->common.opcode = opcode;
> +	cmd->common.nsid = ns->ns_id;
> +	cmd->common.cdw10[0] = SECP << 24 | SPSP << 8;
> +	cmd->common.cdw10[1] = len;

Need to use the write cpu_to_le* conversions.

> +	q = ns->ctrl->admin_q;
> +
> +	req = nvme_alloc_request(q, cmd, 0, NVME_QID_ANY);
> +	if (IS_ERR(req)) {
> +		ret = PTR_ERR(req);
> +		goto err_free;
> +	}
> +
> +	req->timeout = ADMIN_TIMEOUT;
> +	req->special = NULL;
> +
> +	if (buffer && len) {
> +		ret = blk_rq_map_kern(q, req, buffer, len, GFP_NOWAIT);
> +		if (ret) {
> +			blk_mq_free_request(req);
> +			goto err_free;
> +		}
> +	}
> +
> +	req->end_io_data = sed_data;
> +
> +	blk_execute_rq_nowait(q, ns->disk, req, 1, sec_submit_endio);
> +	return 0;
> +
> +err_free:
> +	kfree(sed_data);

Missing 'return ret;', here.

> +}

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 5/7] nvme: Implement SED Security Operations
@ 2016-11-17  0:09     ` Keith Busch
  0 siblings, 0 replies; 38+ messages in thread
From: Keith Busch @ 2016-11-17  0:09 UTC (permalink / raw)


On Wed, Nov 16, 2016@04:17:30PM -0700, Scott Bauer wrote:
> +static int nvme_sec_submit(void *data, u8 opcode, u16 SPSP,
> +			   u8 SECP, void *buffer, size_t len,
> +			   sec_cb *cb, void *cb_data)
> +{
> +	struct request_queue *q;
> +	struct request *req;
> +	struct sed_cb_data *sed_data;
> +	struct nvme_ns *ns;
> +	struct nvme_command *cmd;
> +	int ret;
> +
> +	ns = data;
> +
> +	sed_data = kzalloc(sizeof(*sed_data), GFP_NOWAIT);
> +	if (!sed_data)
> +		return -ENOMEM;
> +	sed_data->cb = cb;
> +	sed_data->cb_data = cb_data;
> +	cmd = &sed_data->cmd;
> +
> +	cmd->common.opcode = opcode;
> +	cmd->common.nsid = ns->ns_id;
> +	cmd->common.cdw10[0] = SECP << 24 | SPSP << 8;
> +	cmd->common.cdw10[1] = len;

Need to use the write cpu_to_le* conversions.

> +	q = ns->ctrl->admin_q;
> +
> +	req = nvme_alloc_request(q, cmd, 0, NVME_QID_ANY);
> +	if (IS_ERR(req)) {
> +		ret = PTR_ERR(req);
> +		goto err_free;
> +	}
> +
> +	req->timeout = ADMIN_TIMEOUT;
> +	req->special = NULL;
> +
> +	if (buffer && len) {
> +		ret = blk_rq_map_kern(q, req, buffer, len, GFP_NOWAIT);
> +		if (ret) {
> +			blk_mq_free_request(req);
> +			goto err_free;
> +		}
> +	}
> +
> +	req->end_io_data = sed_data;
> +
> +	blk_execute_rq_nowait(q, ns->disk, req, 1, sec_submit_endio);
> +	return 0;
> +
> +err_free:
> +	kfree(sed_data);

Missing 'return ret;', here.

> +}

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 2/7] lib: Add Sed-opal library
  2016-11-16 23:17   ` Scott Bauer
@ 2016-11-17  0:35     ` Keith Busch
  -1 siblings, 0 replies; 38+ messages in thread
From: Keith Busch @ 2016-11-17  0:35 UTC (permalink / raw)
  To: Scott Bauer
  Cc: linux-nvme, Rafael.Antognolli, axboe, jonathan.derrick,
	j.naumann, hch, linux-block, sagi

On Wed, Nov 16, 2016 at 04:17:27PM -0700, Scott Bauer wrote:
> +int opal_unlock_from_suspend(struct opal_suspend_unlk *data)
> +{
> +	const char *diskname = data->name;
> +	struct opal_dev *iter, *dev = NULL;
> +	struct opal_completion *completion;
> +	void *func_data[3] = { NULL };
> +
> +	spin_lock(&list_spinlock);
> +	list_for_each_entry(iter, &opal_list, node) {
> +		if (strncmp(iter->disk_name, diskname, DISK_NAME_LEN)) {
> +			pr_err("iterdisk was %s and diskname is %s\n",
> +			       iter->disk_name, diskname);
> +			continue;
> +		}
> +		if (atomic_add_unless(&iter->in_use, 1, 1)) {
> +			dev = iter;
> +			dev->func_data = func_data;
> +			dev->resume_from_suspend = true;
> +			dev->resume_data = data;
> +			dev->final_cb = unlock_suspend_final;
> +			dev->final_cb_data = dev;
> +			dev->error_cb = end_opal_session_error;
> +			dev->error_cb_data = dev;
> +			dev->state = 0;
> +			if (dev->lkul.authority.SUM)
> +				dev->funcs = ulk_funcs_SUM;
> +			else
> +				dev->funcs = _unlock_funcs;
> +			dev->TSN = 0;
> +			dev->HSN = 0;
> +			dev->func_data[2] = &dev->lkul;
> +			dev->func_data[1] = &dev->lkul.authority;
> +			completion = dev->completion;
> +			next(0, dev);
> +			wait_for_cmd_completion(completion);

Waiting while holding a spinlock will get a scheduling error.

> +		}
> +	}
> +	spin_unlock(&list_spinlock);

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 2/7] lib: Add Sed-opal library
@ 2016-11-17  0:35     ` Keith Busch
  0 siblings, 0 replies; 38+ messages in thread
From: Keith Busch @ 2016-11-17  0:35 UTC (permalink / raw)


On Wed, Nov 16, 2016@04:17:27PM -0700, Scott Bauer wrote:
> +int opal_unlock_from_suspend(struct opal_suspend_unlk *data)
> +{
> +	const char *diskname = data->name;
> +	struct opal_dev *iter, *dev = NULL;
> +	struct opal_completion *completion;
> +	void *func_data[3] = { NULL };
> +
> +	spin_lock(&list_spinlock);
> +	list_for_each_entry(iter, &opal_list, node) {
> +		if (strncmp(iter->disk_name, diskname, DISK_NAME_LEN)) {
> +			pr_err("iterdisk was %s and diskname is %s\n",
> +			       iter->disk_name, diskname);
> +			continue;
> +		}
> +		if (atomic_add_unless(&iter->in_use, 1, 1)) {
> +			dev = iter;
> +			dev->func_data = func_data;
> +			dev->resume_from_suspend = true;
> +			dev->resume_data = data;
> +			dev->final_cb = unlock_suspend_final;
> +			dev->final_cb_data = dev;
> +			dev->error_cb = end_opal_session_error;
> +			dev->error_cb_data = dev;
> +			dev->state = 0;
> +			if (dev->lkul.authority.SUM)
> +				dev->funcs = ulk_funcs_SUM;
> +			else
> +				dev->funcs = _unlock_funcs;
> +			dev->TSN = 0;
> +			dev->HSN = 0;
> +			dev->func_data[2] = &dev->lkul;
> +			dev->func_data[1] = &dev->lkul.authority;
> +			completion = dev->completion;
> +			next(0, dev);
> +			wait_for_cmd_completion(completion);

Waiting while holding a spinlock will get a scheduling error.

> +		}
> +	}
> +	spin_unlock(&list_spinlock);

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 0/7] SED OPAL Library
  2016-11-16 23:17 ` Scott Bauer
@ 2016-11-17 13:12   ` Christoph Hellwig
  -1 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 13:12 UTC (permalink / raw)
  To: Scott Bauer
  Cc: hch, sagi, axboe, linux-nvme, keith.busch, Rafael.Antognolli,
	linux-block, jonathan.derrick, j.naumann

Hi Scott,

I took a look at the code and here are some very high level comments:

 - we only call into block_device_operations.sec_ops from the ioctl
   handlers.  So instead of adding it to the block layer I'd rather
   structure the code so that the driver itself calls a new common
   blkdev_sed_ioctl handler implemented in lib/sed.c, which then gets
   callbacks passed directly from the calling, similar to how
   opal_unlock_from_suspend works.  And the callbacks might actually
   be condensed to one I think, given that all potential
   implementations would basically just dispatch to two
   different opcode but otherwise use the same implementation.
 - talking about lib/sed*.c - I'd move it to block/
 - there are a lot of levels of indirection in the code, I think
   we can condense them down a bit to basically just having the
   main blkdev_sed_ioctl entry point, which should check
   bdev_sec_capable first, and then dispatch to the security
   types, probably through a little method table.
 - what's so special about request_user_key that it can't be inline
   into the only caller but needs a separate file?
 - please don't use pointer indirections in your userspace ABI,
   struct sed_key will be a pain to handle for 32-bit userspace
   on 64-bit kernels.  I don't fully understand what the key_type
   is for anyway - it seems like exactly one type is supported
   per call anyway.

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 0/7] SED OPAL Library
@ 2016-11-17 13:12   ` Christoph Hellwig
  0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 13:12 UTC (permalink / raw)


Hi Scott,

I took a look at the code and here are some very high level comments:

 - we only call into block_device_operations.sec_ops from the ioctl
   handlers.  So instead of adding it to the block layer I'd rather
   structure the code so that the driver itself calls a new common
   blkdev_sed_ioctl handler implemented in lib/sed.c, which then gets
   callbacks passed directly from the calling, similar to how
   opal_unlock_from_suspend works.  And the callbacks might actually
   be condensed to one I think, given that all potential
   implementations would basically just dispatch to two
   different opcode but otherwise use the same implementation.
 - talking about lib/sed*.c - I'd move it to block/
 - there are a lot of levels of indirection in the code, I think
   we can condense them down a bit to basically just having the
   main blkdev_sed_ioctl entry point, which should check
   bdev_sec_capable first, and then dispatch to the security
   types, probably through a little method table.
 - what's so special about request_user_key that it can't be inline
   into the only caller but needs a separate file?
 - please don't use pointer indirections in your userspace ABI,
   struct sed_key will be a pain to handle for 32-bit userspace
   on 64-bit kernels.  I don't fully understand what the key_type
   is for anyway - it seems like exactly one type is supported
   per call anyway.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 6/7] nvme: Implement SED Unlock from suspend
  2016-11-16 23:17   ` Scott Bauer
@ 2016-11-17 13:16     ` Christoph Hellwig
  -1 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 13:16 UTC (permalink / raw)
  To: Scott Bauer
  Cc: hch, sagi, axboe, linux-nvme, keith.busch, Rafael.Antognolli,
	linux-block, jonathan.derrick, j.naumann

> +{
> +	struct opal_suspend_unlk ulk = { 0 };
> +	struct nvme_ns *ns;
> +	char diskname[DISK_NAME_LEN];
> +	mutex_lock(&ctrl->namespaces_mutex);
> +	if (list_empty(&ctrl->namespaces))
> +		goto out_no_namespace;
> +	ulk.data = ns =list_first_entry(&ctrl->namespaces, struct nvme_ns, list);

Simply grabbing a namespace without locking is broken.  That being
said..

> +	mutex_unlock(&ctrl->namespaces_mutex);
> +	snprintf(diskname, sizeof(diskname), "%sn%d",
> +		 dev_name(ctrl->device), ns->instance);
> +	ulk.name = diskname;
> +
> +	ulk.ops.send = nvme_sec_send;
> +	ulk.ops.recv = nvme_sec_recv;
> +	opal_unlock_from_suspend(&ulk);

passing a device _name_ to a lower level interface is even more
broken.  The Security Send/Receive commands operate on the NVMe
admin queue, and for SCSI and ATA that'd operate on the device.
So what we need to do here is to pass an object that identifies
the device - either the request queue if the opal code wants
to use it directly, or an opaqueue object that allows us to find
the nvme_ctrl.

Looking a bit at the actual low-level OPAL code it seems
like the driver should allocate the opal_dev structure when
setting up the device, and we should always pass it in.  But
maybe I need to understand that code a bit better first.

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 6/7] nvme: Implement SED Unlock from suspend
@ 2016-11-17 13:16     ` Christoph Hellwig
  0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 13:16 UTC (permalink / raw)


> +{
> +	struct opal_suspend_unlk ulk = { 0 };
> +	struct nvme_ns *ns;
> +	char diskname[DISK_NAME_LEN];
> +	mutex_lock(&ctrl->namespaces_mutex);
> +	if (list_empty(&ctrl->namespaces))
> +		goto out_no_namespace;
> +	ulk.data = ns =list_first_entry(&ctrl->namespaces, struct nvme_ns, list);

Simply grabbing a namespace without locking is broken.  That being
said..

> +	mutex_unlock(&ctrl->namespaces_mutex);
> +	snprintf(diskname, sizeof(diskname), "%sn%d",
> +		 dev_name(ctrl->device), ns->instance);
> +	ulk.name = diskname;
> +
> +	ulk.ops.send = nvme_sec_send;
> +	ulk.ops.recv = nvme_sec_recv;
> +	opal_unlock_from_suspend(&ulk);

passing a device _name_ to a lower level interface is even more
broken.  The Security Send/Receive commands operate on the NVMe
admin queue, and for SCSI and ATA that'd operate on the device.
So what we need to do here is to pass an object that identifies
the device - either the request queue if the opal code wants
to use it directly, or an opaqueue object that allows us to find
the nvme_ctrl.

Looking a bit at the actual low-level OPAL code it seems
like the driver should allocate the opal_dev structure when
setting up the device, and we should always pass it in.  But
maybe I need to understand that code a bit better first.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 1/7] Include: Add definitions for sed
  2016-11-16 23:17   ` Scott Bauer
@ 2016-11-17 15:22     ` Christoph Hellwig
  -1 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 15:22 UTC (permalink / raw)
  To: Scott Bauer
  Cc: hch, sagi, axboe, linux-nvme, keith.busch, Rafael.Antognolli,
	linux-block, jonathan.derrick, j.naumann

> @@ -0,0 +1,58 @@
> +/*
> + * Copyright =A9 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining=
 a
> + * copy of this software and associated documentation files (the "Softwa=
re"),
> + * to deal in the Software without restriction, including without limita=
tion
> + * the rights to use, copy, modify, merge, publish, distribute, sublicen=
se,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the =
next
> + * paragraph) shall be included in all copies or substantial portions of=
 the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRE=
SS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILI=
TY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SH=
ALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR =
OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISI=
NG
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER D=
EALINGS

Can we get a proper GPLv2/GPLv2 license for this from the Intel
layers?  While the license grant looks fine from a quick look I'd really
prefer to have an official statement that this should be compatible
with the kernel licensing.

> +#define LINUX_OPAL_H
> +
> +#include <linux/sed.h>
> +#include <linux/kernel.h>
> +
> +enum {
> +	TCG_SECP_00 =3D 0,
> +	TCG_SECP_01,
> +};

These are the SPC4 security protocol defintions, aren't they?
Can you please add a separate include/scsi/sec_protocol.h header that
defines just these and documents where they come from?

Similarly for all the other constants it would be nice to refer to
the spec they are from in the header.

> +struct sec_ops {
> +	int (*send)(void *data, __u16 SPSP, __u8 SECP,
> +			void *buffer, size_t len,
> +			sec_cb *cb, void *cb_data);
> +	int (*recv)(void *data, __u16 SPSP, __u8 SECP,
> +			void *buffer, size_t len,
> +			sec_cb *cb, void *cb_data);

please use lower case names for all arguments and variables.

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 1/7] Include: Add definitions for sed
@ 2016-11-17 15:22     ` Christoph Hellwig
  0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 15:22 UTC (permalink / raw)


> @@ -0,0 +1,58 @@
> +/*
> + * Copyright ? 2016 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS

Can we get a proper GPLv2/GPLv2 license for this from the Intel
layers?  While the license grant looks fine from a quick look I'd really
prefer to have an official statement that this should be compatible
with the kernel licensing.

> +#define LINUX_OPAL_H
> +
> +#include <linux/sed.h>
> +#include <linux/kernel.h>
> +
> +enum {
> +	TCG_SECP_00 = 0,
> +	TCG_SECP_01,
> +};

These are the SPC4 security protocol defintions, aren't they?
Can you please add a separate include/scsi/sec_protocol.h header that
defines just these and documents where they come from?

Similarly for all the other constants it would be nice to refer to
the spec they are from in the header.

> +struct sec_ops {
> +	int (*send)(void *data, __u16 SPSP, __u8 SECP,
> +			void *buffer, size_t len,
> +			sec_cb *cb, void *cb_data);
> +	int (*recv)(void *data, __u16 SPSP, __u8 SECP,
> +			void *buffer, size_t len,
> +			sec_cb *cb, void *cb_data);

please use lower case names for all arguments and variables.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 2/7] lib: Add Sed-opal library
  2016-11-16 23:17   ` Scott Bauer
@ 2016-11-17 15:38     ` Christoph Hellwig
  -1 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 15:38 UTC (permalink / raw)
  To: Scott Bauer
  Cc: hch, sagi, axboe, linux-nvme, keith.busch, Rafael.Antognolli,
	linux-block, jonathan.derrick, j.naumann

I'm trying to understand the logic for how the OPAL state machine
and how it interacts with the Security Send / Receive commands.

It seems like it's implemented as an asynchronous state machine,
but all the callers and up waiting synchronously for the result.

How about making ->send and ->recv (or the merged method if you
follow my earlier suggestion) synchronous, e.g. for nvme just
switch from blk_execute_rq_nowait to blk_execute_rq for the
execution and stop passing the cb and cb_data arguments which
would not be needed with this scheme.

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 2/7] lib: Add Sed-opal library
@ 2016-11-17 15:38     ` Christoph Hellwig
  0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 15:38 UTC (permalink / raw)


I'm trying to understand the logic for how the OPAL state machine
and how it interacts with the Security Send / Receive commands.

It seems like it's implemented as an asynchronous state machine,
but all the callers and up waiting synchronously for the result.

How about making ->send and ->recv (or the merged method if you
follow my earlier suggestion) synchronous, e.g. for nvme just
switch from blk_execute_rq_nowait to blk_execute_rq for the
execution and stop passing the cb and cb_data arguments which
would not be needed with this scheme.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 1/7] Include: Add definitions for sed
  2016-11-17 15:22     ` Christoph Hellwig
@ 2016-11-17 16:10       ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-17 16:10 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-block, sagi, Rafael.Antognolli, axboe, linux-nvme,
	keith.busch, jonathan.derrick, j.naumann

On Thu, Nov 17, 2016 at 07:22:15AM -0800, Christoph Hellwig wrote:
> > @@ -0,0 +1,58 @@
> > +/*
> > + * Copyright =A9 2016 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person obtaini=
ng a
> > + * copy of this software and associated documentation files (the "Soft=
ware"),
> > + * to deal in the Software without restriction, including without limi=
tation
> > + * the rights to use, copy, modify, merge, publish, distribute, sublic=
ense,
> > + * and/or sell copies of the Software, and to permit persons to whom t=
he
> > + * Software is furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice (including th=
e next
> > + * paragraph) shall be included in all copies or substantial portions =
of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXP=
RESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABI=
LITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT =
SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES O=
R OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARI=
SING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER=
 DEALINGS
> =

> Can we get a proper GPLv2/GPLv2 license for this from the Intel
> layers?  While the license grant looks fine from a quick look I'd really
> prefer to have an official statement that this should be compatible
> with the kernel licensing.
> =

Sure, I will send them some mail to see if we can change them to something =
else.


> > +#define LINUX_OPAL_H
> > +
> > +#include <linux/sed.h>
> > +#include <linux/kernel.h>
> > +
> > +enum {
> > +	TCG_SECP_00 =3D 0,
> > +	TCG_SECP_01,
> > +};
> =

> These are the SPC4 security protocol defintions, aren't they?
> Can you please add a separate include/scsi/sec_protocol.h header that
> defines just these and documents where they come from?
> =

> Similarly for all the other constants it would be nice to refer to
> the spec they are from in the header.
 =

Sure I can specify what spec/location they're pulled from.

> > +struct sec_ops {
> > +	int (*send)(void *data, __u16 SPSP, __u8 SECP,
> > +			void *buffer, size_t len,
> > +			sec_cb *cb, void *cb_data);
> > +	int (*recv)(void *data, __u16 SPSP, __u8 SECP,
> > +			void *buffer, size_t len,
> > +			sec_cb *cb, void *cb_data);
> =

> please use lower case names for all arguments and variables.
I think we chose the uppercase because that's how it was in the specificati=
on,
none the less we'll swap them up.


_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 1/7] Include: Add definitions for sed
@ 2016-11-17 16:10       ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-17 16:10 UTC (permalink / raw)


On Thu, Nov 17, 2016@07:22:15AM -0800, Christoph Hellwig wrote:
> > @@ -0,0 +1,58 @@
> > +/*
> > + * Copyright ? 2016 Intel Corporation
> > + *
> > + * Permission is hereby granted, free of charge, to any person obtaining a
> > + * copy of this software and associated documentation files (the "Software"),
> > + * to deal in the Software without restriction, including without limitation
> > + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> > + * and/or sell copies of the Software, and to permit persons to whom the
> > + * Software is furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice (including the next
> > + * paragraph) shall be included in all copies or substantial portions of the
> > + * Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> 
> Can we get a proper GPLv2/GPLv2 license for this from the Intel
> layers?  While the license grant looks fine from a quick look I'd really
> prefer to have an official statement that this should be compatible
> with the kernel licensing.
> 
Sure, I will send them some mail to see if we can change them to something else.


> > +#define LINUX_OPAL_H
> > +
> > +#include <linux/sed.h>
> > +#include <linux/kernel.h>
> > +
> > +enum {
> > +	TCG_SECP_00 = 0,
> > +	TCG_SECP_01,
> > +};
> 
> These are the SPC4 security protocol defintions, aren't they?
> Can you please add a separate include/scsi/sec_protocol.h header that
> defines just these and documents where they come from?
> 
> Similarly for all the other constants it would be nice to refer to
> the spec they are from in the header.
 
Sure I can specify what spec/location they're pulled from.

> > +struct sec_ops {
> > +	int (*send)(void *data, __u16 SPSP, __u8 SECP,
> > +			void *buffer, size_t len,
> > +			sec_cb *cb, void *cb_data);
> > +	int (*recv)(void *data, __u16 SPSP, __u8 SECP,
> > +			void *buffer, size_t len,
> > +			sec_cb *cb, void *cb_data);
> 
> please use lower case names for all arguments and variables.
I think we chose the uppercase because that's how it was in the specification,
none the less we'll swap them up.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 0/7] SED OPAL Library
  2016-11-17 13:12   ` Christoph Hellwig
@ 2016-11-17 17:36     ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-17 17:36 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-block, sagi, Rafael.Antognolli, axboe, linux-nvme,
	keith.busch, jonathan.derrick, j.naumann

On Thu, Nov 17, 2016 at 05:12:51AM -0800, Christoph Hellwig wrote:
> Hi Scott,
> 
> I took a look at the code and here are some very high level comments:
> 
>  - we only call into block_device_operations.sec_ops from the ioctl
>    handlers.  So instead of adding it to the block layer I'd rather
>    structure the code so that the driver itself calls a new common
>    blkdev_sed_ioctl handler implemented in lib/sed.c, which then gets
>    callbacks passed directly from the calling, similar to how
>    opal_unlock_from_suspend works.

I want some further clarification, if you don't mind. We call sec_ops
inside the actual logic for the opal code. Which is only accessible via the
ioctls, is that what you were meaning?  When you say "the driver calls"
do you mean that the nvme/sata/et al drivers would implement some generic
block sed function that would be called via ioctl?
So the call chain would be:

Userland
 block/ioctl  ops->blkdev_sed()

  nvme/et al (implements blkdev_sed()) which calls:

   sed.c blkdev_sed_ioctl(with passed in combined fn to get data to controller)?

Is this what you were thinking, if so I agree it will alleviate a bunch of clutter
in block/ioctl.c. If this isn't what you were thinking please let me know.




>  - talking about lib/sed*.c - I'd move it to block/

I don't have any reservations about this but from a learning standpoint, why
 block/ instead of lib/ ?

>  - there are a lot of levels of indirection in the code, I think
>    we can condense them down a bit to basically just having the
>    main blkdev_sed_ioctl entry point, which should check
>    bdev_sec_capable first, and then dispatch to the security
>    types, probably through a little method table.

If we go with what I described above I'm not sure if we'll even need
blkdev_sec_capable. If the driver(nvme/etc) implements blkdev_sed then we know it's
capable?

>  - what's so special about request_user_key that it can't be inline
>    into the only caller but needs a separate file?

Probably nothing I'll check with Rafael and see if there was a reason.
We do have another patch set which once all this new code lands lives in that file.
It can probably go elsewhere though.

>  - please don't use pointer indirections in your userspace ABI,
>    struct sed_key will be a pain to handle for 32-bit userspace
>    on 64-bit kernels.  I don't fully understand what the key_type
>    is for anyway - it seems like exactly one type is supported
>    per call anyway.

Sure good call... Now that you say this I see we didnt even implement the compat
ioctl properly for the indirect pointers.
We'll inline as much as we can.



_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 0/7] SED OPAL Library
@ 2016-11-17 17:36     ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-17 17:36 UTC (permalink / raw)


On Thu, Nov 17, 2016@05:12:51AM -0800, Christoph Hellwig wrote:
> Hi Scott,
> 
> I took a look at the code and here are some very high level comments:
> 
>  - we only call into block_device_operations.sec_ops from the ioctl
>    handlers.  So instead of adding it to the block layer I'd rather
>    structure the code so that the driver itself calls a new common
>    blkdev_sed_ioctl handler implemented in lib/sed.c, which then gets
>    callbacks passed directly from the calling, similar to how
>    opal_unlock_from_suspend works.

I want some further clarification, if you don't mind. We call sec_ops
inside the actual logic for the opal code. Which is only accessible via the
ioctls, is that what you were meaning?  When you say "the driver calls"
do you mean that the nvme/sata/et al drivers would implement some generic
block sed function that would be called via ioctl?
So the call chain would be:

Userland
 block/ioctl  ops->blkdev_sed()

  nvme/et al (implements blkdev_sed()) which calls:

   sed.c blkdev_sed_ioctl(with passed in combined fn to get data to controller)?

Is this what you were thinking, if so I agree it will alleviate a bunch of clutter
in block/ioctl.c. If this isn't what you were thinking please let me know.




>  - talking about lib/sed*.c - I'd move it to block/

I don't have any reservations about this but from a learning standpoint, why
 block/ instead of lib/ ?

>  - there are a lot of levels of indirection in the code, I think
>    we can condense them down a bit to basically just having the
>    main blkdev_sed_ioctl entry point, which should check
>    bdev_sec_capable first, and then dispatch to the security
>    types, probably through a little method table.

If we go with what I described above I'm not sure if we'll even need
blkdev_sec_capable. If the driver(nvme/etc) implements blkdev_sed then we know it's
capable?

>  - what's so special about request_user_key that it can't be inline
>    into the only caller but needs a separate file?

Probably nothing I'll check with Rafael and see if there was a reason.
We do have another patch set which once all this new code lands lives in that file.
It can probably go elsewhere though.

>  - please don't use pointer indirections in your userspace ABI,
>    struct sed_key will be a pain to handle for 32-bit userspace
>    on 64-bit kernels.  I don't fully understand what the key_type
>    is for anyway - it seems like exactly one type is supported
>    per call anyway.

Sure good call... Now that you say this I see we didnt even implement the compat
ioctl properly for the indirect pointers.
We'll inline as much as we can.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 0/7] SED OPAL Library
  2016-11-17 17:36     ` Scott Bauer
@ 2016-11-17 18:21       ` Rafael Antognolli
  -1 siblings, 0 replies; 38+ messages in thread
From: Rafael Antognolli @ 2016-11-17 18:21 UTC (permalink / raw)
  To: Scott Bauer
  Cc: Christoph Hellwig, linux-nvme, keith.busch, sagi, axboe,
	linux-block, jonathan.derrick, j.naumann

On Thu, Nov 17, 2016 at 10:36:14AM -0700, Scott Bauer wrote:
> On Thu, Nov 17, 2016 at 05:12:51AM -0800, Christoph Hellwig wrote:
> > Hi Scott,
> > 
> > I took a look at the code and here are some very high level comments:
> > 
> >  - we only call into block_device_operations.sec_ops from the ioctl
> >    handlers.  So instead of adding it to the block layer I'd rather
> >    structure the code so that the driver itself calls a new common
> >    blkdev_sed_ioctl handler implemented in lib/sed.c, which then gets
> >    callbacks passed directly from the calling, similar to how
> >    opal_unlock_from_suspend works.
> 
> I want some further clarification, if you don't mind. We call sec_ops
> inside the actual logic for the opal code. Which is only accessible via the
> ioctls, is that what you were meaning?  When you say "the driver calls"
> do you mean that the nvme/sata/et al drivers would implement some generic
> block sed function that would be called via ioctl?
> So the call chain would be:
> 
> Userland
>  block/ioctl  ops->blkdev_sed()
> 
>   nvme/et al (implements blkdev_sed()) which calls:
> 
>    sed.c blkdev_sed_ioctl(with passed in combined fn to get data to controller)?
> 
> Is this what you were thinking, if so I agree it will alleviate a bunch of clutter
> in block/ioctl.c. If this isn't what you were thinking please let me know.
> 
> 
> 
> 
> >  - talking about lib/sed*.c - I'd move it to block/
> 
> I don't have any reservations about this but from a learning standpoint, why
>  block/ instead of lib/ ?
> 
> >  - there are a lot of levels of indirection in the code, I think
> >    we can condense them down a bit to basically just having the
> >    main blkdev_sed_ioctl entry point, which should check
> >    bdev_sec_capable first, and then dispatch to the security
> >    types, probably through a little method table.
> 
> If we go with what I described above I'm not sure if we'll even need
> blkdev_sec_capable. If the driver(nvme/etc) implements blkdev_sed then we know it's
> capable?
> 
> >  - what's so special about request_user_key that it can't be inline
> >    into the only caller but needs a separate file?
> 
> Probably nothing I'll check with Rafael and see if there was a reason.
> We do have another patch set which once all this new code lands lives in that file.
> It can probably go elsewhere though.

It's nothing special, but I just wanted to avoid polluting the sed
implementation with keyring-only code. In the future, in theory, we
could implement support for other types of keyring keys (right now only
user keys are supported). So that code could go into this file too.

But feel free to put it whetever you want and, if we happen to add other
keys later, we could split it into its own file (if it makes sense).

> >  - please don't use pointer indirections in your userspace ABI,
> >    struct sed_key will be a pain to handle for 32-bit userspace
> >    on 64-bit kernels.  I don't fully understand what the key_type
> >    is for anyway - it seems like exactly one type is supported
> >    per call anyway.
> 
> Sure good call... Now that you say this I see we didnt even implement the compat
> ioctl properly for the indirect pointers.
> We'll inline as much as we can.
> 
> 

Regards,
Rafael

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 0/7] SED OPAL Library
@ 2016-11-17 18:21       ` Rafael Antognolli
  0 siblings, 0 replies; 38+ messages in thread
From: Rafael Antognolli @ 2016-11-17 18:21 UTC (permalink / raw)


On Thu, Nov 17, 2016@10:36:14AM -0700, Scott Bauer wrote:
> On Thu, Nov 17, 2016@05:12:51AM -0800, Christoph Hellwig wrote:
> > Hi Scott,
> > 
> > I took a look at the code and here are some very high level comments:
> > 
> >  - we only call into block_device_operations.sec_ops from the ioctl
> >    handlers.  So instead of adding it to the block layer I'd rather
> >    structure the code so that the driver itself calls a new common
> >    blkdev_sed_ioctl handler implemented in lib/sed.c, which then gets
> >    callbacks passed directly from the calling, similar to how
> >    opal_unlock_from_suspend works.
> 
> I want some further clarification, if you don't mind. We call sec_ops
> inside the actual logic for the opal code. Which is only accessible via the
> ioctls, is that what you were meaning?  When you say "the driver calls"
> do you mean that the nvme/sata/et al drivers would implement some generic
> block sed function that would be called via ioctl?
> So the call chain would be:
> 
> Userland
>  block/ioctl  ops->blkdev_sed()
> 
>   nvme/et al (implements blkdev_sed()) which calls:
> 
>    sed.c blkdev_sed_ioctl(with passed in combined fn to get data to controller)?
> 
> Is this what you were thinking, if so I agree it will alleviate a bunch of clutter
> in block/ioctl.c. If this isn't what you were thinking please let me know.
> 
> 
> 
> 
> >  - talking about lib/sed*.c - I'd move it to block/
> 
> I don't have any reservations about this but from a learning standpoint, why
>  block/ instead of lib/ ?
> 
> >  - there are a lot of levels of indirection in the code, I think
> >    we can condense them down a bit to basically just having the
> >    main blkdev_sed_ioctl entry point, which should check
> >    bdev_sec_capable first, and then dispatch to the security
> >    types, probably through a little method table.
> 
> If we go with what I described above I'm not sure if we'll even need
> blkdev_sec_capable. If the driver(nvme/etc) implements blkdev_sed then we know it's
> capable?
> 
> >  - what's so special about request_user_key that it can't be inline
> >    into the only caller but needs a separate file?
> 
> Probably nothing I'll check with Rafael and see if there was a reason.
> We do have another patch set which once all this new code lands lives in that file.
> It can probably go elsewhere though.

It's nothing special, but I just wanted to avoid polluting the sed
implementation with keyring-only code. In the future, in theory, we
could implement support for other types of keyring keys (right now only
user keys are supported). So that code could go into this file too.

But feel free to put it whetever you want and, if we happen to add other
keys later, we could split it into its own file (if it makes sense).

> >  - please don't use pointer indirections in your userspace ABI,
> >    struct sed_key will be a pain to handle for 32-bit userspace
> >    on 64-bit kernels.  I don't fully understand what the key_type
> >    is for anyway - it seems like exactly one type is supported
> >    per call anyway.
> 
> Sure good call... Now that you say this I see we didnt even implement the compat
> ioctl properly for the indirect pointers.
> We'll inline as much as we can.
> 
> 

Regards,
Rafael

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 0/7] SED OPAL Library
  2016-11-17 17:36     ` Scott Bauer
@ 2016-11-17 19:28       ` Christoph Hellwig
  -1 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 19:28 UTC (permalink / raw)
  To: Scott Bauer
  Cc: Christoph Hellwig, linux-block, sagi, Rafael.Antognolli, axboe,
	linux-nvme, keith.busch, jonathan.derrick, j.naumann

On Thu, Nov 17, 2016 at 10:36:14AM -0700, Scott Bauer wrote:
> 
> I want some further clarification, if you don't mind. We call sec_ops
> inside the actual logic for the opal code. Which is only accessible via the
> ioctls, is that what you were meaning?  When you say "the driver calls"
> do you mean that the nvme/sata/et al drivers would implement some generic
> block sed function that would be called via ioctl?
> So the call chain would be:
> 
> Userland
>  block/ioctl  ops->blkdev_sed()
> 
>   nvme/et al (implements blkdev_sed()) which calls:
> 
>    sed.c blkdev_sed_ioctl(with passed in combined fn to get data to controller)?
> 
> Is this what you were thinking, if so I agree it will alleviate a bunch of clutter
> in block/ioctl.c. If this isn't what you were thinking please let me know.

Similar, but not quite the same.  We already have an ioctl method in
struct block_device_operations, so in that we'd do something like
this for nvme:

	case IOC_SED_FOO:
	...
	case IOC_SED_BAR:
		return blkdev_sed_ioctl(bdev, mode, cmd, arg,
				ctrl, nvme_sec_submit);

Or maybe even shortcut the list of ioctl with something like this
before the main switch statement:

	if (is_sed_ioctl(cmd)) {
		return blkdev_sed_ioctl(bdev, mode, cmd, arg,
			ctrl, nvme_sec_submit);
	}

> >  - talking about lib/sed*.c - I'd move it to block/
> 
> I don't have any reservations about this but from a learning standpoint, why
>  block/ instead of lib/ ?

Because it's code related to block devices, and it looks like it's
tied pretty deeply into block device semantics.

> If we go with what I described above I'm not sure if we'll even need
> blkdev_sec_capable. If the driver(nvme/etc) implements blkdev_sed then we know it's
> capable?

Indeed, even better.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 0/7] SED OPAL Library
@ 2016-11-17 19:28       ` Christoph Hellwig
  0 siblings, 0 replies; 38+ messages in thread
From: Christoph Hellwig @ 2016-11-17 19:28 UTC (permalink / raw)


On Thu, Nov 17, 2016@10:36:14AM -0700, Scott Bauer wrote:
> 
> I want some further clarification, if you don't mind. We call sec_ops
> inside the actual logic for the opal code. Which is only accessible via the
> ioctls, is that what you were meaning?  When you say "the driver calls"
> do you mean that the nvme/sata/et al drivers would implement some generic
> block sed function that would be called via ioctl?
> So the call chain would be:
> 
> Userland
>  block/ioctl  ops->blkdev_sed()
> 
>   nvme/et al (implements blkdev_sed()) which calls:
> 
>    sed.c blkdev_sed_ioctl(with passed in combined fn to get data to controller)?
> 
> Is this what you were thinking, if so I agree it will alleviate a bunch of clutter
> in block/ioctl.c. If this isn't what you were thinking please let me know.

Similar, but not quite the same.  We already have an ioctl method in
struct block_device_operations, so in that we'd do something like
this for nvme:

	case IOC_SED_FOO:
	...
	case IOC_SED_BAR:
		return blkdev_sed_ioctl(bdev, mode, cmd, arg,
				ctrl, nvme_sec_submit);

Or maybe even shortcut the list of ioctl with something like this
before the main switch statement:

	if (is_sed_ioctl(cmd)) {
		return blkdev_sed_ioctl(bdev, mode, cmd, arg,
			ctrl, nvme_sec_submit);
	}

> >  - talking about lib/sed*.c - I'd move it to block/
> 
> I don't have any reservations about this but from a learning standpoint, why
>  block/ instead of lib/ ?

Because it's code related to block devices, and it looks like it's
tied pretty deeply into block device semantics.

> If we go with what I described above I'm not sure if we'll even need
> blkdev_sec_capable. If the driver(nvme/etc) implements blkdev_sed then we know it's
> capable?

Indeed, even better.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v1 0/7] SED OPAL Library
  2016-11-17 19:28       ` Christoph Hellwig
@ 2016-11-17 19:33         ` Scott Bauer
  -1 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-17 19:33 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-block, sagi, Rafael.Antognolli, axboe, linux-nvme,
	keith.busch, jonathan.derrick, j.naumann

On Thu, Nov 17, 2016 at 11:28:07AM -0800, Christoph Hellwig wrote:
> On Thu, Nov 17, 2016 at 10:36:14AM -0700, Scott Bauer wrote:
> > 
> > I want some further clarification, if you don't mind. We call sec_ops
> > inside the actual logic for the opal code. Which is only accessible via the
> > ioctls, is that what you were meaning?  When you say "the driver calls"
> > do you mean that the nvme/sata/et al drivers would implement some generic
> > block sed function that would be called via ioctl?
> > So the call chain would be:
> > 
> > Userland
> >  block/ioctl  ops->blkdev_sed()
> > 
> >   nvme/et al (implements blkdev_sed()) which calls:
> > 
> >    sed.c blkdev_sed_ioctl(with passed in combined fn to get data to controller)?
> > 
> > Is this what you were thinking, if so I agree it will alleviate a bunch of clutter
> > in block/ioctl.c. If this isn't what you were thinking please let me know.
> 
> Similar, but not quite the same.  We already have an ioctl method in
> struct block_device_operations, so in that we'd do something like
> this for nvme:

Ah okay this was the piece I was missing. I was mixed up on how we would
agnostically get it into the nvme drive and allow sata etc to do the same.

Thanks for your help i'll get working.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v1 0/7] SED OPAL Library
@ 2016-11-17 19:33         ` Scott Bauer
  0 siblings, 0 replies; 38+ messages in thread
From: Scott Bauer @ 2016-11-17 19:33 UTC (permalink / raw)


On Thu, Nov 17, 2016@11:28:07AM -0800, Christoph Hellwig wrote:
> On Thu, Nov 17, 2016@10:36:14AM -0700, Scott Bauer wrote:
> > 
> > I want some further clarification, if you don't mind. We call sec_ops
> > inside the actual logic for the opal code. Which is only accessible via the
> > ioctls, is that what you were meaning?  When you say "the driver calls"
> > do you mean that the nvme/sata/et al drivers would implement some generic
> > block sed function that would be called via ioctl?
> > So the call chain would be:
> > 
> > Userland
> >  block/ioctl  ops->blkdev_sed()
> > 
> >   nvme/et al (implements blkdev_sed()) which calls:
> > 
> >    sed.c blkdev_sed_ioctl(with passed in combined fn to get data to controller)?
> > 
> > Is this what you were thinking, if so I agree it will alleviate a bunch of clutter
> > in block/ioctl.c. If this isn't what you were thinking please let me know.
> 
> Similar, but not quite the same.  We already have an ioctl method in
> struct block_device_operations, so in that we'd do something like
> this for nvme:

Ah okay this was the piece I was missing. I was mixed up on how we would
agnostically get it into the nvme drive and allow sata etc to do the same.

Thanks for your help i'll get working.

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2016-11-17 19:39 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-16 23:17 [PATCH v1 0/7] SED OPAL Library Scott Bauer
2016-11-16 23:17 ` Scott Bauer
2016-11-16 23:17 ` [PATCH v1 1/7] Include: Add definitions for sed Scott Bauer
2016-11-16 23:17   ` Scott Bauer
2016-11-17 15:22   ` Christoph Hellwig
2016-11-17 15:22     ` Christoph Hellwig
2016-11-17 16:10     ` Scott Bauer
2016-11-17 16:10       ` Scott Bauer
2016-11-16 23:17 ` [PATCH v1 2/7] lib: Add Sed-opal library Scott Bauer
2016-11-16 23:17   ` Scott Bauer
2016-11-17  0:35   ` Keith Busch
2016-11-17  0:35     ` Keith Busch
2016-11-17 15:38   ` Christoph Hellwig
2016-11-17 15:38     ` Christoph Hellwig
2016-11-16 23:17 ` [PATCH v1 3/7] lib: Add Sed to Kconfig and Makefile Scott Bauer
2016-11-16 23:17   ` Scott Bauer
2016-11-16 23:17 ` [PATCH v1 4/7] include: Add sec_ops to block device operations Scott Bauer
2016-11-16 23:17   ` Scott Bauer
2016-11-16 23:17 ` [PATCH v1 5/7] nvme: Implement SED Security Operations Scott Bauer
2016-11-16 23:17   ` Scott Bauer
2016-11-17  0:09   ` Keith Busch
2016-11-17  0:09     ` Keith Busch
2016-11-16 23:17 ` [PATCH v1 6/7] nvme: Implement SED Unlock from suspend Scott Bauer
2016-11-16 23:17   ` Scott Bauer
2016-11-17 13:16   ` Christoph Hellwig
2016-11-17 13:16     ` Christoph Hellwig
2016-11-16 23:17 ` [PATCH v1 7/7] block: ioctl: Wire up Sed to block ioctls Scott Bauer
2016-11-16 23:17   ` Scott Bauer
2016-11-17 13:12 ` [PATCH v1 0/7] SED OPAL Library Christoph Hellwig
2016-11-17 13:12   ` Christoph Hellwig
2016-11-17 17:36   ` Scott Bauer
2016-11-17 17:36     ` Scott Bauer
2016-11-17 18:21     ` Rafael Antognolli
2016-11-17 18:21       ` Rafael Antognolli
2016-11-17 19:28     ` Christoph Hellwig
2016-11-17 19:28       ` Christoph Hellwig
2016-11-17 19:33       ` Scott Bauer
2016-11-17 19:33         ` Scott Bauer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.