All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/6] Sed Opal
@ 2016-10-31 21:58 ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block

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


At a high level the code works by declaring a set of opal_step functions,
which we save in our opal_dev structure. The opal_step functions declare
the functions which are necessary to do the opal command. We start
dispatching the commands to the device, which return immediately. The
thread from userland calls into wait_for_cmd_completion to wait until
all the commands have finished. Each new command is issued in an interrupt
that signaled the completion of the previous command.

If a command requires information to complete we pass that information in
the opal_dev structure in the func_data. If a command needs to save data
to give to a future command it is saved in the prev_data.



On a side note, since these files are new I assume we will need to add
a new entry into MAINTAINERS for this code base, can anyone confirm that?






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

* [RFC PATCH 0/6] Sed Opal
@ 2016-10-31 21:58 ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 UTC (permalink / raw)


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


At a high level the code works by declaring a set of opal_step functions,
which we save in our opal_dev structure. The opal_step functions declare
the functions which are necessary to do the opal command. We start
dispatching the commands to the device, which return immediately. The
thread from userland calls into wait_for_cmd_completion to wait until
all the commands have finished. Each new command is issued in an interrupt
that signaled the completion of the previous command.

If a command requires information to complete we pass that information in
the opal_dev structure in the func_data. If a command needs to save data
to give to a future command it is saved in the prev_data.



On a side note, since these files are new I assume we will need to add
a new entry into MAINTAINERS for this code base, can anyone confirm that?

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

* [RFC PATCH 1/6] Include: Add definitions for sed
  2016-10-31 21:58 ` Scott Bauer
@ 2016-10-31 21:58   ` Scott Bauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, 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] 32+ messages in thread

* [RFC PATCH 1/6] Include: Add definitions for sed
@ 2016-10-31 21:58   ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 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] 32+ messages in thread

* [RFC PATCH 2/6] lib: Add Sed-opal library
  2016-10-31 21:58 ` Scott Bauer
@ 2016-10-31 21:58   ` Scott Bauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 UTC (permalink / raw)
  To: linux-nvme
  Cc: keith.busch, hch, Rafael.Antognolli, axboe, linux-block,
	Scott Bauer, jonathan.derrick, j.naumann

VGhpcyBwYXRjaCBpbXBsZW1lbnRzIHRoZSBuZWNlc3NhcnkgbG9naWMgdG8gYnJpbmcgYW4gT3Bh
bAplbmFibGVkIGRyaXZlIG91dCBvZiBhIGZhY3RvcnktZW5hYmxlZCBpbnRvIGEgd29ya2luZwpP
cGFsIHN0YXRlLgoKVGhpcyBwYXRjaCBzZXQgYWxzbyBlbmFibGVzIGxvZ2ljIHRvIHNhdmUgYSBw
YXNzd29yZCB0bwpiZSByZXBsYXllZCBkdXJpbmcgYSByZXN1bWUgZnJvbSBzdXNwZW5kLiBUaGUg
a2V5IGNhbiBiZQpzYXZlZCBpbiB0aGUgZHJpdmVyIG9yIGluIHRoZSBLZXJuZWwncyBLZXkgbWFu
YWdtZW50LgoKU2lnbmVkLW9mZi1ieTogU2NvdHQgQmF1ZXIgPHNjb3R0LmJhdWVyQGludGVsLmNv
bT4KU2lnbmVkLW9mZi1ieTogUmFmYWVsIEFudG9nbm9sbGkgPFJhZmFlbC5BbnRvZ25vbGxpQGlu
dGVsLmNvbT4KLS0tCiBsaWIvc2VkLW9wYWwuYyAgICAgICAgICB8IDMzMzcgKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIGxpYi9zZWQtb3BhbF9pbnRlcm5h
bC5oIHwgIDU4NiArKysrKysrKysKIGxpYi9zZWQtb3BhbF9rZXkuYyAgICAgIHwgICA0NiArCiBs
aWIvc2VkLmMgICAgICAgICAgICAgICB8ICAzMDMgKysrKysKIDQgZmlsZXMgY2hhbmdlZCwgNDI3
MiBpbnNlcnRpb25zKCspCiBjcmVhdGUgbW9kZSAxMDA2NDQgbGliL3NlZC1vcGFsLmMKIGNyZWF0
ZSBtb2RlIDEwMDY0NCBsaWIvc2VkLW9wYWxfaW50ZXJuYWwuaAogY3JlYXRlIG1vZGUgMTAwNjQ0
IGxpYi9zZWQtb3BhbF9rZXkuYwogY3JlYXRlIG1vZGUgMTAwNjQ0IGxpYi9zZWQuYwoKZGlmZiAt
LWdpdCBhL2xpYi9zZWQtb3BhbC5jIGIvbGliL3NlZC1vcGFsLmMKbmV3IGZpbGUgbW9kZSAxMDA2
NDQKaW5kZXggMDAwMDAwMC4uMTBiMzM0OAotLS0gL2Rldi9udWxsCisrKyBiL2xpYi9zZWQtb3Bh
bC5jCkBAIC0wLDAgKzEsMzMzNyBAQAorLyoKKyAqIENvcHlyaWdodCDCqSAyMDE2IEludGVsIENv
cnBvcmF0aW9uCisgKgorICogUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBj
aGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEKKyAqIGNvcHkgb2YgdGhpcyBzb2Z0d2Fy
ZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksCisg
KiB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcg
d2l0aG91dCBsaW1pdGF0aW9uCisgKiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBt
ZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwKKyAqIGFuZC9vciBzZWxsIGNv
cGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZQor
ICogU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dp
bmcgY29uZGl0aW9uczoKKyAqCisgKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhp
cyBwZXJtaXNzaW9uIG5vdGljZSAoaW5jbHVkaW5nIHRoZSBuZXh0CisgKiBwYXJhZ3JhcGgpIHNo
YWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2Yg
dGhlCisgKiBTb2Z0d2FyZS4KKyAqCisgKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElT
IiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgorICogSU1QTElFRCwg
SU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFC
SUxJVFksCisgKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklO
R0VNRU5ULiAgSU4gTk8gRVZFTlQgU0hBTEwKKyAqIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBI
T0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSCisgKiBMSUFC
SUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lT
RSwgQVJJU0lORworICogRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09G
VFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUworICogSU4gVEhFIFNPRlRXQVJFLgor
ICoKKyAqIEF1dGhvcnM6CisgKiAgICBSYWZhZWwgQW50b2dub2xsaSA8cmFmYWVsLmFudG9nbm9s
bGlAaW50ZWwuY29tPgorICogICAgU2NvdHQgIEJhdWVyICAgICAgPHNjb3R0LmJhdWVyQGludGVs
LmNvbT4KKyAqLworCisjZGVmaW5lIHByX2ZtdChmbXQpIEtCVUlMRF9NT0ROQU1FICI6T1BBTDog
IiBmbXQKKworI2luY2x1ZGUgPGxpbnV4L2RlbGF5Lmg+CisjaW5jbHVkZSA8bGludXgvZGV2aWNl
Lmg+CisjaW5jbHVkZSA8bGludXgva2VybmVsLmg+CisjaW5jbHVkZSA8bGludXgvbGlzdC5oPgor
I2luY2x1ZGUgPGxpbnV4L2dlbmhkLmg+CisjaW5jbHVkZSA8bGludXgvc2xhYi5oPgorI2luY2x1
ZGUgPGxpbnV4L3VhY2Nlc3MuaD4KKyNpbmNsdWRlIDx1YXBpL2xpbnV4L3NlZC1vcGFsLmg+Cisj
aW5jbHVkZSA8bGludXgvc2VkLmg+CisjaW5jbHVkZSA8bGludXgvc2VkLW9wYWwuaD4KKyNpbmNs
dWRlIDxsaW51eC9zdHJpbmcuaD4KKworI2luY2x1ZGUgInNlZC1vcGFsX2ludGVybmFsLmgiCisK
KyNkZWZpbmUgSU9fQlVGRkVSX0xFTkdUSCAyMDQ4CisKKyNkZWZpbmUgTUFYX1RPS1MgNjQKKwor
c3RydWN0IG9wYWxfY21kIHsKKwlzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2OworCXNlY19jYiAq
Y2I7CisJdm9pZCAqY2JfZGF0YTsKKworCXNpemVfdCBwb3M7CisJdTggY21kX2J1ZltJT19CVUZG
RVJfTEVOR1RIICogMl07CisJdTggcmVzcF9idWZbSU9fQlVGRkVSX0xFTkdUSCAqIDJdOworCXU4
ICpjbWQ7CisJdTggKnJlc3A7Cit9OworCisvKgorICogT24gdGhlIHBhcnNlZCByZXNwb25zZSwg
d2UgZG9uJ3Qgc3RvcmUgYWdhaW4gdGhlIHRva3MgdGhhdCBhcmUgYWxyZWFkeQorICogc3RvcmVk
IGluIHRoZSByZXNwb25zZSBidWZmZXIuIEluc3RlYWQsIGZvciBlYWNoIHRva2VuLCB3ZSBqdXN0
IHN0b3JlIGEKKyAqIHBvaW50ZXIgdG8gdGhlIHBvc2l0aW9uIGluIHRoZSBidWZmZXIgd2hlcmUg
dGhlIHRva2VuIHN0YXJ0cywgYW5kIHRoZSBzaXplCisgKiBvZiB0aGUgdG9rZW4gaW4gYnl0ZXMu
CisgKi8KK3N0cnVjdCBvcGFsX3Jlc3BfdG9rIHsKKwljb25zdCB1OCAqcG9zOworCXNpemVfdCBs
ZW47CisJZW51bSBPUEFMX1JFU1BPTlNFX1RPS0VOIHR5cGU7CisJZW51bSBPUEFMX0FUT01fV0lE
VEggd2lkdGg7CisJdW5pb24geworCQl1NjQgdTsKKwkJczY0IHM7CisJfSBzdG9yZWQ7Cit9Owor
CisvKgorICogRnJvbSB0aGUgcmVzcG9uc2UgaGVhZGVyIGl0J3Mgbm90IHBvc3NpYmxlIHRvIGtu
b3cgaG93IG1hbnkgdG9rZW5zIHRoZXJlIGFyZQorICogb24gdGhlIHBheWxvYWQuIFNvIHdlIGhh
cmRjb2RlIHRoYXQgdGhlIG1heGltdW0gd2lsbCBiZSBNQVhfVE9LUywgYW5kIGxhdGVyCisgKiBp
ZiB3ZSBzdGFydCBkZWFsaW5nIHdpdGggbWVzc2FnZXMgdGhhdCBoYXZlIG1vcmUgdGhhbiB0aGF0
LCB3ZSBjYW4gaW5jcmVhc2UKKyAqIHRoaXMgbnVtYmVyLiBUaGlzIGlzIGRvbmUgdG8gYXZvaWQg
aGF2aW5nIHRvIG1ha2UgdHdvIHBhc3NlcyB0aHJvdWdoIHRoZQorICogcmVzcG9uc2UsIHRoZSBm
aXJzdCBvbmUgY291bnRpbmcgaG93IG1hbnkgdG9rZW5zIHdlIGhhdmUgYW5kIHRoZSBzZWNvbmQg
b25lCisgKiBhY3R1YWxseSBzdG9yaW5nIHRoZSBwb3NpdGlvbnMuCisgKi8KK3N0cnVjdCBwYXJz
ZWRfcmVzcCB7CisJaW50IG51bTsKKwlzdHJ1Y3Qgb3BhbF9yZXNwX3RvayB0b2tzW01BWF9UT0tT
XTsKK307CisKK3N0cnVjdCBvcGFsX2RldjsKKwordHlwZWRlZiB2b2lkICgqb3BhbF9jYikoaW50
IGVycm9yLCBzdHJ1Y3Qgb3BhbF9kZXYgKmRldik7CisKK3R5cGVkZWYgaW50ICgqb3BhbF9zdGVw
KShzdHJ1Y3Qgb3BhbF9kZXYgKmRldik7CisKK3N0cnVjdCBvcGFsX2NvbXBsZXRpb24geworCXN0
cnVjdCBjb21wbGV0aW9uIGNtZF9jb21wbGV0aW9uOworCWludCBjb21wbGV0aW9uX3N0YXR1czsK
K307CisKK3N0cnVjdCBvcGFsX2RldiB7CisJc3RydWN0IGJsb2NrX2RldmljZSAqYmRldjsKKwlz
dHJ1Y3Qgb3BhbF9jb21wbGV0aW9uICpjb21wbGV0aW9uOworCXN0cnVjdCBvcGFsX2xvY2tfdW5s
b2NrIGxrdWw7CisJY29uc3Qgb3BhbF9zdGVwICpmdW5jczsKKwl2b2lkICoqZnVuY19kYXRhOwor
CWJvb2wgcmVzdW1lX2Zyb21fc3VzcGVuZDsKKwlzdHJ1Y3Qgb3BhbF9zdXNwZW5kX3VubGsgKnJl
c3VtZV9kYXRhOworCXNpemVfdCBudW1fZnVuY19kYXRhOworCWF0b21pY190IGluX3VzZTsKKwlz
ZWN0b3JfdCBzdGFydDsKKwlzZWN0b3JfdCBsZW5ndGg7CisJdTggbHI7CisJdTgga2V5X3R5cGU7
CisJdTgga2V5X25hbWVbT1BBTF9LRVlfTUFYXTsKKwlzaXplX3Qga2V5X25hbWVfbGVuOworCXU4
IGtleVtPUEFMX0tFWV9NQVhdOworCXNpemVfdCBrZXlfbGVuOworCXUxNiBjb21JRDsKKwl1MzIg
SFNOOworCXUzMiBUU047CisJdTY0IGFsaWduOworCXU2NCBsb3dlc3RfbGJhOworCXN0cnVjdCBs
aXN0X2hlYWQgbm9kZTsKKwljaGFyIGRpc2tfbmFtZVtESVNLX05BTUVfTEVOXTsKKwlpbnQgc3Rh
dGU7CisKKwlzdHJ1Y3Qgb3BhbF9jbWQgY21kOworCXN0cnVjdCBwYXJzZWRfcmVzcCBwYXJzZWQ7
CisKKwlzaXplX3QgcHJldl9kX2xlbjsKKwl2b2lkICpwcmV2X2RhdGE7CisKKwlzZWNfY2IgKmZp
bmFsX2NiOworCXZvaWQgKmZpbmFsX2NiX2RhdGE7CisJb3BhbF9zdGVwIGVycm9yX2NiOworCXZv
aWQgKmVycm9yX2NiX2RhdGE7CisJb3BhbF9jYiBvcGVyX2NiOworfTsKKworTElTVF9IRUFEKG9w
YWxfbGlzdCk7CitERUZJTkVfU1BJTkxPQ0sobGlzdF9zcGlubG9jayk7CisKK3N0YXRpYyB2b2lk
IHByaW50X2J1ZmZlcihjb25zdCB1OCAqcHRyLCB1MzIgbGVuZ3RoKQoreworI2lmZGVmIERFQlVH
CisJcHJpbnRfaGV4X2R1bXBfYnl0ZXMoIk9QQUw6ICIsIERVTVBfUFJFRklYX09GRlNFVCwgcHRy
LCBsZW5ndGgpOworCXByX2RlYnVnKCJcbiIpOworI2VuZGlmCit9CisKKyNkZWZpbmUgVFBFUl9T
WU5DX1NVUFBPUlRFRCBCSVQoMCkKKworc3RhdGljIGJvb2wgY2hlY2tfdHBlcihjb25zdCB2b2lk
ICpkYXRhKQoreworCWNvbnN0IHN0cnVjdCBkMF90cGVyX2ZlYXR1cmVzICp0cGVyID0gZGF0YTsK
Kwl1OCBmbGFncyA9IHRwZXItPnN1cHBvcnRlZF9mZWF0dXJlczsKKworCWlmICghKGZsYWdzICYg
VFBFUl9TWU5DX1NVUFBPUlRFRCkpIHsKKwkJcHJfZXJyKCJUUGVyIHN5bmMgbm90IHN1cHBvcnRl
ZC4gZmxhZ3MgPSAlZFxuIiwKKwkJICAgICAgIHRwZXItPnN1cHBvcnRlZF9mZWF0dXJlcyk7CisJ
CXJldHVybiBmYWxzZTsKKwl9CisKKwlyZXR1cm4gdHJ1ZTsKK30KKworc3RhdGljIGJvb2wgY2hl
Y2tfU1VNKGNvbnN0IHZvaWQgKmRhdGEpCit7CisJY29uc3Qgc3RydWN0IGQwX3NpbmdsZV91c2Vy
X21vZGUgKnN1bSA9IGRhdGE7CisJdTMyIG5sbyA9IGJlMzJfdG9fY3B1KHN1bS0+bnVtX2xvY2tp
bmdfb2JqZWN0cyk7CisKKwlpZiAobmxvID09IDApIHsKKwkJcHJfZXJyKCJOZWVkIGF0IGxlYXN0
IG9uZSBsb2NraW5nIG9iamVjdC5cbiIpOworCQlyZXR1cm4gZmFsc2U7CisJfQorCisJcHJfZGVi
dWcoIk51bWJlciBvZiBsb2NraW5nIG9iamVjdHM6ICVkXG4iLCBubG8pOworCisJcmV0dXJuIHRy
dWU7Cit9CisKK3N0YXRpYyB1MTYgZ2V0X2NvbUlEX3YxMDAoY29uc3Qgdm9pZCAqZGF0YSkKK3sK
Kwljb25zdCBzdHJ1Y3QgZDBfb3BhbF92MTAwICp2MTAwID0gZGF0YTsKKworCXJldHVybiBiZTE2
X3RvX2NwdSh2MTAwLT5iYXNlQ29tSUQpOworfQorCitzdGF0aWMgdTE2IGdldF9jb21JRF92MjAw
KGNvbnN0IHZvaWQgKmRhdGEpCit7CisJY29uc3Qgc3RydWN0IGQwX29wYWxfdjIwMCAqdjIwMCA9
IGRhdGE7CisKKwlyZXR1cm4gYmUxNl90b19jcHUodjIwMC0+YmFzZUNvbUlEKTsKK30KKworc3Rh
dGljIGludCBfX29wYWxfc2VuZF9jbWQoc3RydWN0IG9wYWxfc3VzcGVuZF91bmxrICpkYXRhLCB1
MTYgY29tSUQsCisJCQkgICB2b2lkICpidWZmZXIsIHNpemVfdCBidWZsZW4sIHNlY19jYiAqY2Is
CisJCQkgICB2b2lkICpjYl9kYXRhKQoreworCXJldHVybiBkYXRhLT5vcHMuc2VuZChkYXRhLT5k
YXRhLCBjb21JRCwgVENHX1NFQ1BfMDEsIGJ1ZmZlciwgYnVmbGVuLAorCQkJICAgICBjYiwgY2Jf
ZGF0YSk7Cit9CitzdGF0aWMgaW50IF9vcGFsX3NlbmRfY21kKHN0cnVjdCBibG9ja19kZXZpY2Ug
KmJkZXYsIHUxNiBjb21JRCwKKwkJCSAgdm9pZCAqYnVmZmVyLCBzaXplX3QgYnVmbGVuLAorCQkJ
ICBzZWNfY2IgKmNiLCB2b2lkICpjYl9kYXRhKQoreworCWNvbnN0IHN0cnVjdCBzZWNfb3BzICpv
cHMgPSBiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzOworCisJcmV0dXJuIG9wcy0+c2VuZChi
ZGV2LT5iZF9kaXNrLT5wcml2YXRlX2RhdGEsIGNvbUlELAorCQkJIFRDR19TRUNQXzAxLCBidWZm
ZXIsIGJ1ZmxlbiwKKwkJCSBjYiwgY2JfZGF0YSk7Cit9CisKK3N0YXRpYyBpbnQgX19vcGFsX3Jl
Y3ZfY21kKHN0cnVjdCBvcGFsX3N1c3BlbmRfdW5sayAqZGF0YSwgdTE2IGNvbUlELAorCQkJICAg
dm9pZCAqYnVmZmVyLCBzaXplX3QgYnVmbGVuLCBzZWNfY2IgKmNiLAorCQkJICAgdm9pZCAqY2Jf
ZGF0YSkKK3sKKwlyZXR1cm4gZGF0YS0+b3BzLnJlY3YoZGF0YS0+ZGF0YSwgY29tSUQsIFRDR19T
RUNQXzAxLCBidWZmZXIsIGJ1ZmxlbiwKKwkJCSAgICAgY2IsIGNiX2RhdGEpOworfQorCitzdGF0
aWMgaW50IF9vcGFsX3JlY3ZfY21kKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHUxNiBjb21J
RCwKKwkJCSAgdm9pZCAqYnVmZmVyLCBzaXplX3QgYnVmbGVuLAorCQkJICBzZWNfY2IgKmNiLCB2
b2lkICpjYl9kYXRhKQoreworCWNvbnN0IHN0cnVjdCBzZWNfb3BzICpvcHMgPSBiZGV2LT5iZF9k
aXNrLT5mb3BzLT5zZWNfb3BzOworCisJcmV0dXJuIG9wcy0+cmVjdihiZGV2LT5iZF9kaXNrLT5w
cml2YXRlX2RhdGEsIGNvbUlELAorCQkJIFRDR19TRUNQXzAxLCBidWZmZXIsIGJ1ZmxlbiwKKwkJ
CSBjYiwgY2JfZGF0YSk7Cit9CisKK3N0YXRpYyB2b2lkIG9wYWxfc2VuZF9jYl9jb250KGludCBl
cnJvciwgdm9pZCAqZGF0YSkKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisJc2l6
ZV90IGJ1ZmxlbiA9IElPX0JVRkZFUl9MRU5HVEg7CisJdm9pZCAqYnVmZmVyID0gZGV2LT5jbWQu
cmVzcDsKKwlzdHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkciA9IGJ1ZmZlcjsKKworCXByX2RlYnVnKCIl
czogU2VudCBPUEFMIGNvbW1hbmQ6IGVycm9yPSVkLCBvdXRzdGFuZGluZz0lZCwgbWluVHJhbnNm
ZXI9JWRcbiIsCisJICAgICAgIGRldi0+ZGlza19uYW1lLCBlcnJvciwgaGRyLT5jcC5vdXRzdGFu
ZGluZ0RhdGEsCisJICAgICAgIGhkci0+Y3AubWluVHJhbnNmZXIpOworCisJaWYgKGVycm9yIHx8
IGhkci0+Y3Aub3V0c3RhbmRpbmdEYXRhID09IDAgfHwKKwkgICAgaGRyLT5jcC5taW5UcmFuc2Zl
ciAhPSAwKSB7CisJCWlmIChkZXYtPmNtZC5jYikKKwkJCWRldi0+Y21kLmNiKGVycm9yLCBkZXYt
PmNtZC5jYl9kYXRhKTsKKwkJcmV0dXJuOworCX0KKworCW1lbXNldChidWZmZXIsIDAsIGJ1Zmxl
bik7CisJaWYgKGRldi0+cmVzdW1lX2Zyb21fc3VzcGVuZCkKKwkJX19vcGFsX3JlY3ZfY21kKGRl
di0+cmVzdW1lX2RhdGEsIGRldi0+Y29tSUQsCisJCQkJYnVmZmVyLCBidWZsZW4sIG9wYWxfc2Vu
ZF9jYl9jb250LCBkZXYpOworCWVsc2UKKwkJX29wYWxfcmVjdl9jbWQoZGV2LT5iZGV2LCBkZXYt
PmNvbUlELCBidWZmZXIsIGJ1ZmxlbiwKKwkJCSAgICAgICBvcGFsX3NlbmRfY2JfY29udCwgZGV2
KTsKK30KKworc3RhdGljIHZvaWQgb3BhbF9zZW5kX2NiKGludCBlcnJvciwgdm9pZCAqZGF0YSkK
K3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisJc2l6ZV90IGJ1ZmxlbiA9IElPX0JV
RkZFUl9MRU5HVEg7CisJdm9pZCAqYnVmZmVyID0gZGV2LT5jbWQucmVzcDsKKworCWlmIChlcnJv
cikgeworCQlpZiAoZGV2LT5jbWQuY2IpCisJCQlkZXYtPmNtZC5jYihlcnJvciwgZGV2LT5jbWQu
Y2JfZGF0YSk7CisJCXJldHVybjsKKwl9CisKKwltZW1zZXQoYnVmZmVyLCAwLCBidWZsZW4pOwor
CWlmIChkZXYtPnJlc3VtZV9mcm9tX3N1c3BlbmQpCisJCV9fb3BhbF9yZWN2X2NtZChkZXYtPnJl
c3VtZV9kYXRhLCBkZXYtPmNvbUlELAorCQkJCWJ1ZmZlciwgYnVmbGVuLCBvcGFsX3NlbmRfY2Jf
Y29udCwgZGV2KTsKKwllbHNlCisJCV9vcGFsX3JlY3ZfY21kKGRldi0+YmRldiwgZGV2LT5jb21J
RCwgYnVmZmVyLCBidWZsZW4sCisJCQkgICAgICAgb3BhbF9zZW5kX2NiX2NvbnQsIGRldik7Cit9
CisKK3N0YXRpYyBpbnQgb3BhbF9zZW5kX3JlY3Yoc3RydWN0IG9wYWxfZGV2ICpkZXYsIHNlY19j
YiAqY2IsIHZvaWQgKmNiX2RhdGEpCit7CisJc2l6ZV90IGJ1ZmxlbiA9IElPX0JVRkZFUl9MRU5H
VEg7CisJdm9pZCAqYnVmZmVyID0gZGV2LT5jbWQuY21kOworCWludCByZXQ7CisKKwlkZXYtPmNt
ZC5jYiA9IGNiOworCWRldi0+Y21kLmNiX2RhdGEgPSBjYl9kYXRhOworCWlmIChkZXYtPnJlc3Vt
ZV9mcm9tX3N1c3BlbmQpCisJCXJldCA9IF9fb3BhbF9zZW5kX2NtZChkZXYtPnJlc3VtZV9kYXRh
LCBkZXYtPmNvbUlELCBidWZmZXIsCisJCQkJICAgICAgYnVmbGVuLCBvcGFsX3NlbmRfY2IsIGRl
dik7CisJZWxzZQorCQlyZXQgPSBfb3BhbF9zZW5kX2NtZChkZXYtPmJkZXYsIGRldi0+Y29tSUQs
IGJ1ZmZlciwgYnVmbGVuLAorCQkJCSAgICAgb3BhbF9zZW5kX2NiLCBkZXYpOworCisJcmV0dXJu
IHJldDsKK30KKworc3RhdGljIHZvaWQgY2hlY2tfZ2VvbWV0cnkoc3RydWN0IG9wYWxfZGV2ICpk
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
KwkJCWJyZWFrOworCQlkZWZhdWx0OgorCQkJaWYgKGJlMTZfdG9fY3B1KGJvZHktPmNvZGUpID4g
MHhiZmZmKSB7CisJCQkJLyogdmVuZG9yIHNwZWNpZmljLCBqdXN0IGlnbm9yZSAqLworCQkJfSBl
bHNlIHsKKwkJCQlwcl93YXJuKCIlczogT1BBTCBVbmtub3duIGZlYXR1cmU6ICVkXG4iLAorCQkJ
CQlkZXYtPmRpc2tfbmFtZSwgYmUxNl90b19jcHUoYm9keS0+Y29kZSkpOworCQkJfQorCQl9CisJ
CWNwb3MgKz0gYm9keS0+bGVuZ3RoICsgNDsKKwl9CisKKwlpZiAoIXN1cHBvcnRlZCkgeworCQlw
cl9lcnIoIiVzOiBEZXZpY2Ugbm90IHN1cHBvcnRlZFxuIiwgZGV2LT5kaXNrX25hbWUpOworCQln
b3RvIGVycl9jYWxsYmFjazsKKwl9CisKKwlpZiAoIXNpbmdsZV91c2VyKQorCQlwcl93YXJuKCIl
czogRGV2aWNlIGRvZXNuJ3Qgc3VwcG9ydCBzaW5nbGUgdXNlciBtb2RlXG4iLAorCQkJZGV2LT5k
aXNrX25hbWUpOworCisJaWYgKCFmb3VuZENvbUlEKSB7CisJCXByX3dhcm4oIiVzOiBDb3VsZCBu
b3QgZmluZCBPUEFMIGNvbUlEIGZvciBkZXZpY2UuIE9QQUwga2VybmVsIHVubG9ja2luZyB3aWxs
IGJlIGRpc2FibGVkXG4iLAorCQkJZGV2LT5kaXNrX25hbWUpOworCQlnb3RvIGVycl9jYWxsYmFj
azsKKwl9CisKKwlkZXYtPmNvbUlEID0gY29tSUQ7CisKK2Vycl9jYWxsYmFjazoKKwlpZiAoZGV2
LT5vcGVyX2NiKQorCQlkZXYtPm9wZXJfY2IoZXJyb3IsIGRldik7Cit9CisKK3N0YXRpYyBpbnQg
b3BhbF9kaXNjb3ZlcnkwKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCW1lbXNldChkZXYtPmNt
ZC5yZXNwLCAwLCBJT19CVUZGRVJfTEVOR1RIKTsKKworCWlmIChkZXYtPnJlc3VtZV9mcm9tX3N1
c3BlbmQpCisJCXJldHVybiBfX29wYWxfcmVjdl9jbWQoZGV2LT5yZXN1bWVfZGF0YSwgMHgwMDAx
LAorCQkJCSAgICAgICBkZXYtPmNtZC5yZXNwLCBJT19CVUZGRVJfTEVOR1RILAorCQkJCSAgICAg
ICBvcGFsX2Rpc2NvdmVyeTBfZW5kLCBkZXYpOworCisJcmV0dXJuIF9vcGFsX3JlY3ZfY21kKGRl
di0+YmRldiwgMHgwMDAxLCBkZXYtPmNtZC5yZXNwLAorCQkJICAgICAgSU9fQlVGRkVSX0xFTkdU
SCwgb3BhbF9kaXNjb3ZlcnkwX2VuZCwKKwkJCSAgICAgIGRldik7Cit9CisKK3N0YXRpYyB2b2lk
IGFkZF90b2tlbl91OChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTggdG9rKQoreworCWNtZC0+Y21k
W2NtZC0+cG9zKytdID0gdG9rOworfQorCitzdGF0aWMgc3NpemVfdCB0ZXN0X2FuZF9hZGRfdG9r
ZW5fdTgoc3RydWN0IG9wYWxfY21kICpjbWQsIHU4IHRvaykKK3sKKwlCVUlMRF9CVUdfT04oSU9f
QlVGRkVSX0xFTkdUSCA+PSBTSVpFX01BWCk7CisKKwlpZiAoY21kLT5wb3MgPj0gSU9fQlVGRkVS
X0xFTkdUSCAtIDEpIHsKKwkJcHJfZXJyKCJFcnJvciBhZGRpbmcgdTg6IGVuZCBvZiBidWZmZXIu
XG4iKTsKKwkJcmV0dXJuIC1FUkFOR0U7CisJfQorCisJYWRkX3Rva2VuX3U4KGNtZCwgdG9rKTsK
KworCXJldHVybiAxOworfQorCisjZGVmaW5lIFRJTllfQVRPTV9EQVRBX01BU0sgR0VOTUFTSyg1
LCAwKQorI2RlZmluZSBUSU5ZX0FUT01fU0lHTkVEIEJJVCg2KQorCisjZGVmaW5lIFNIT1JUX0FU
T01fSUQgQklUKDcpCisjZGVmaW5lIFNIT1JUX0FUT01fQllURVNUUklORyBCSVQoNSkKKyNkZWZp
bmUgU0hPUlRfQVRPTV9TSUdORUQgQklUKDQpCisjZGVmaW5lIFNIT1JUX0FUT01fTEVOX01BU0sg
R0VOTUFTSygzLCAwKQorCitzdGF0aWMgdm9pZCBhZGRfc2hvcnRfYXRvbV9oZWFkZXIoc3RydWN0
IG9wYWxfY21kICpjbWQsIGJvb2wgYnl0ZXN0cmluZywKKwkJCQkgIGJvb2wgaGFzX3NpZ24sIGlu
dCBsZW4pCit7CisJdTggYXRvbTsKKworCWF0b20gPSBTSE9SVF9BVE9NX0lEOworCWF0b20gfD0g
Ynl0ZXN0cmluZyA/IFNIT1JUX0FUT01fQllURVNUUklORyA6IDA7CisJYXRvbSB8PSBoYXNfc2ln
biA/IFNIT1JUX0FUT01fU0lHTkVEIDogMDsKKwlhdG9tIHw9IGxlbiAmIFNIT1JUX0FUT01fTEVO
X01BU0s7CisKKwlhZGRfdG9rZW5fdTgoY21kLCBhdG9tKTsKK30KKworI2RlZmluZSBNRURJVU1f
QVRPTV9JRCAoQklUKDcpIHwgQklUKDYpKQorI2RlZmluZSBNRURJVU1fQVRPTV9CWVRFU1RSSU5H
IEJJVCg0KQorI2RlZmluZSBNRURJVU1fQVRPTV9TSUdORUQgQklUKDMpCisjZGVmaW5lIE1FRElV
TV9BVE9NX0xFTl9NQVNLIEdFTk1BU0soMiwgMCkKKworc3RhdGljIHZvaWQgYWRkX21lZGl1bV9h
dG9tX2hlYWRlcihzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgYm9vbCBieXRlc3RyaW5nLAorCQkJCSAg
IGJvb2wgaGFzX3NpZ24sIGludCBsZW4pCit7CisJdTggaGVhZGVyMDsKKworCWhlYWRlcjAgPSBN
RURJVU1fQVRPTV9JRDsKKwloZWFkZXIwIHw9IGJ5dGVzdHJpbmcgPyBNRURJVU1fQVRPTV9CWVRF
U1RSSU5HIDogMDsKKwloZWFkZXIwIHw9IGhhc19zaWduID8gTUVESVVNX0FUT01fU0lHTkVEIDog
MDsKKwloZWFkZXIwIHw9IChsZW4gPj4gOCkgJiBNRURJVU1fQVRPTV9MRU5fTUFTSzsKKwljbWQt
PmNtZFtjbWQtPnBvcysrXSA9IGhlYWRlcjA7CisJY21kLT5jbWRbY21kLT5wb3MrK10gPSBsZW47
Cit9CisKK3N0YXRpYyB2b2lkIGFkZF90b2tlbl91NjQoc3RydWN0IG9wYWxfY21kICpjbWQsIHU2
NCBudW1iZXIsIHNpemVfdCBsZW4pCit7CisJYWRkX3Nob3J0X2F0b21faGVhZGVyKGNtZCwgZmFs
c2UsIGZhbHNlLCBsZW4pOworCisJd2hpbGUgKGxlbi0tKSB7CisJCXU4IG4gPSBudW1iZXIgPj4g
KGxlbiAqIDgpOworCisJCWFkZF90b2tlbl91OChjbWQsIG4pOworCX0KK30KKworc3RhdGljIHNz
aXplX3QgdGVzdF9hbmRfYWRkX3Rva2VuX3U2NChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTY0IG51
bWJlcikKK3sKKwlpbnQgbGVuOworCWludCBtc2I7CisKKwlpZiAoIShudW1iZXIgJiB+VElOWV9B
VE9NX0RBVEFfTUFTSykpCisJCXJldHVybiB0ZXN0X2FuZF9hZGRfdG9rZW5fdTgoY21kLCBudW1i
ZXIpOworCisJbXNiID0gZmxzKG51bWJlcik7CisJbGVuID0gRElWX1JPVU5EX1VQKG1zYiwgNCk7
CisKKwlpZiAoY21kLT5wb3MgPj0gSU9fQlVGRkVSX0xFTkdUSCAtIGxlbiAtIDEpIHsKKwkJcHJf
ZXJyKCJFcnJvciBhZGRpbmcgdTY0OiBlbmQgb2YgYnVmZmVyLlxuIik7CisJCXJldHVybiAtRVJB
TkdFOworCX0KKworCWFkZF90b2tlbl91NjQoY21kLCBudW1iZXIsIGxlbik7CisKKwkvKiByZXR1
cm4gbGVuZ3RoIG9mIHRva2VuIHBsdXMgYXRvbSAqLworCXJldHVybiBsZW4gKyAxOworfQorCitz
dGF0aWMgdm9pZCBhZGRfdG9rZW5fYnl0ZXN0cmluZyhzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwKKwkJ
CQkgY29uc3QgdTggKmJ5dGVzdHJpbmcsIHNpemVfdCBsZW4pCit7CisJbWVtY3B5KCZjbWQtPmNt
ZFtjbWQtPnBvc10sIGJ5dGVzdHJpbmcsIGxlbik7CisJY21kLT5wb3MgKz0gbGVuOworfQorCitz
dGF0aWMgc3NpemVfdCB0ZXN0X2FuZF9hZGRfdG9rZW5fYnl0ZXN0cmluZyhzdHJ1Y3Qgb3BhbF9j
bWQgKmNtZCwKKwkJCQkJICAgICBjb25zdCB1OCAqYnl0ZXN0cmluZywgc2l6ZV90IGxlbikKK3sK
KwlzaXplX3QgaGVhZGVyX2xlbiA9IDE7CisJYm9vbCBpc19zaG9ydF9hdG9tID0gdHJ1ZTsKKwor
CWlmIChsZW4gJiB+U0hPUlRfQVRPTV9MRU5fTUFTSykgeworCQloZWFkZXJfbGVuID0gMjsKKwkJ
aXNfc2hvcnRfYXRvbSA9IGZhbHNlOworCX0KKworCWlmIChjbWQtPnBvcyA+PSBJT19CVUZGRVJf
TEVOR1RIIC0gbGVuIC0gaGVhZGVyX2xlbikgeworCQlwcl9lcnIoIkVycm9yIGFkZGluZyBieXRl
c3RyaW5nOiBlbmQgb2YgYnVmZmVyLlxuIik7CisJCXJldHVybiAtRVJBTkdFOworCX0KKworCWlm
IChpc19zaG9ydF9hdG9tKQorCQlhZGRfc2hvcnRfYXRvbV9oZWFkZXIoY21kLCB0cnVlLCBmYWxz
ZSwgbGVuKTsKKwllbHNlCisJCWFkZF9tZWRpdW1fYXRvbV9oZWFkZXIoY21kLCB0cnVlLCBmYWxz
ZSwgbGVuKTsKKworCWFkZF90b2tlbl9ieXRlc3RyaW5nKGNtZCwgYnl0ZXN0cmluZywgbGVuKTsK
KworCXJldHVybiBoZWFkZXJfbGVuICsgbGVuOworfQorCisjZGVmaW5lIExPQ0tJTkdfUkFOR0Vf
Tk9OX0dMT0JBTCAweDAzCisKK3N0YXRpYyBpbnQgYnVpbGRfbG9ja2luZ19yYW5nZSh1OCAqYnVm
ZmVyLCBzaXplX3QgbGVuZ3RoLCB1OCBscikKK3sKKwlpZiAobGVuZ3RoIDwgT1BBTF9VSURfTEVO
R1RIKQorCQlyZXR1cm4gLUVSQU5HRTsKKworCW1lbWNweShidWZmZXIsIE9QQUxVSURbT1BBTF9M
T0NLSU5HUkFOR0VfR0xPQkFMXSwgT1BBTF9VSURfTEVOR1RIKTsKKworCWlmIChsciA9PSAwKQor
CQlyZXR1cm4gMDsKKwlidWZmZXJbNV0gPSBMT0NLSU5HX1JBTkdFX05PTl9HTE9CQUw7CisJYnVm
ZmVyWzddID0gbHI7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBidWlsZF9sb2NraW5n
X3VzZXIodTggKmJ1ZmZlciwgc2l6ZV90IGxlbmd0aCwgdTggbHIpCit7CisJaWYgKGxlbmd0aCA8
IE9QQUxfVUlEX0xFTkdUSCkKKwkJcmV0dXJuIC1FUkFOR0U7CisKKwltZW1jcHkoYnVmZmVyLCBP
UEFMVUlEW09QQUxfVVNFUjFfVUlEXSwgT1BBTF9VSURfTEVOR1RIKTsKKworCWJ1ZmZlcls3XSA9
IGxyICsgMTsKKworCXJldHVybiAwOworfQorCisvKgorICogTiA9IG51bWJlciBvZiBmb3JtYXQg
c3BlY2lmaWVycyAoMS05OTkpIHRvIGJlIHJlcGxpY2F0ZWQKKyAqIGMgPSB1OAorICogdSA9IHU2
NAorICogcyA9IGJ5dGVzdHJpbmcsIGxlbmd0aAorICoKKyAqIHJldCA9IHRlc3RfYW5kX2FkZF90
b2tlbl92YShjbWQsICJjIiwKKyAqCQkJICAgICAgIHU4X3ZhbDEpOworICoKKyAqIHJldCA9IHRl
c3RfYW5kX2FkZF90b2tlbl92YShjbWQsICIyYzJ1IiwKKyAqCQkJICAgICAgIHU4X3ZhbDEsIHU4
X3ZhbDIsIHU2NF92YWwxLCB1NjRfdmFsMik7CisgKgorICogcmV0ID0gdGVzdF9hbmRfYWRkX3Rv
a2VuX3ZhKGNtZCwgIjNzIiwKKyAqCQkJICAgICAgIGJ5dGVzdHJpbmcxLCBsZW5ndGgxLAorICoJ
CQkgICAgICAgYnl0ZXN0cmluZzIsIGxlbmd0aDIsCisgKgkJCSAgICAgICBieXRlc3RyaW5nMywg
bGVuZ3RoMyk7CisgKi8KK3N0YXRpYyBpbnQgdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKHN0cnVjdCBv
cGFsX2NtZCAqY21kLAorCQkJCSBjb25zdCBjaGFyICpmbXQsIC4uLikKK3sKKwljb25zdCB1OCAq
aXQgPSBmbXQsICp0bXA7CisJaW50IHJldCwgbnVtID0gMSwgc3VtID0gMDsKKwl2YV9saXN0IGFw
OworCisJdmFfc3RhcnQoYXAsIGZtdCk7CisKKwl3aGlsZSAoKml0ICE9ICdcMCcpIHsKKwkJdTY0
IHRvazY0ID0gMDsKKwkJdTggdG9rLCAqYnN0cjsKKwkJc2l6ZV90IGxlbjsKKworCQlyZXQgPSAw
OworCisJCXN3aXRjaCAoKml0KSB7CisJCWNhc2UgJzEnIC4uLiAnOSc6CisJCQl0bXAgPSBpdDsK
KwkJCW51bSA9IDA7CisJCQl3aGlsZSAoKnRtcCA+PSAnMCcgJiYgKnRtcCA8PSAnOScpCisJCQkJ
bnVtID0gbnVtICogMTAgKyAoKnRtcCsrIC0gJzAnKTsKKwkJCWl0ID0gdG1wOworCQkJY29udGlu
dWU7CisJCWNhc2UgJ2MnOgorCQkJd2hpbGUgKG51bS0tKSB7CisJCQkJdG9rID0gdmFfYXJnKGFw
LCB1bnNpZ25lZCBpbnQpOworCQkJCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl91OChjbWQsIHRv
ayk7CisJCQkJaWYgKHJldCA8IDApCisJCQkJCWdvdG8gZXJyOworCQkJfQorCQkJbnVtID0gMTsK
KwkJCWJyZWFrOworCQljYXNlICd1JzoKKwkJCXdoaWxlIChudW0tLSkgeworCQkJCXRvazY0ID0g
dmFfYXJnKGFwLCB1NjQpOworCQkJCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl91NjQoY21kLCB0
b2s2NCk7CisJCQkJaWYgKHJldCA8IDApCisJCQkJCWdvdG8gZXJyOworCQkJfQorCQkJbnVtID0g
MTsKKwkJCWJyZWFrOworCQljYXNlICdzJzoKKwkJCXdoaWxlIChudW0tLSkgeworCQkJCWJzdHIg
PSB2YV9hcmcoYXAsIHU4ICopOworCQkJCWxlbiA9IHZhX2FyZyhhcCwgc2l6ZV90KTsKKwkJCQly
ZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fYnl0ZXN0cmluZyhjbWQsIGJzdHIsCisJCQkJCQkJCSAg
ICBsZW4pOworCQkJCWlmIChyZXQgPCAwKQorCQkJCQlnb3RvIGVycjsKKwkJCX0KKwkJCW51bSA9
IDE7CisJCQlicmVhazsKKwkJY2FzZSAnICc6CisJCWNhc2UgJ1x0JzoKKwkJCS8qIGlnbm9yZWQg
Ki8KKwkJCWJyZWFrOworCQlkZWZhdWx0OgorCQkJcHJfd2FybigiVW5yZWNvZ25pemVkIHR5cGUu
XG4iKTsKKwkJfQorCisJCWl0Kys7CisJCXN1bSArPSByZXQ7CisJfQorCisJdmFfZW5kKGFwKTsK
KworCXJldHVybiBzdW07CisKKyBlcnI6CisJcHJfZXJyKCJUb2tlbiBmYWlsZWQgdG8gYmUgYWRk
ZWQuXG4iKTsKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgdm9pZCBzZXRfY29tSUQoc3RydWN0
IG9wYWxfY21kICpjbWQsIHUxNiBjb21JRCkKK3sKKwlzdHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkciA9
IChzdHJ1Y3Qgb3BhbF9oZWFkZXIgKiljbWQtPmNtZDsKKworCWhkci0+Y3AuZXh0ZW5kZWRDb21J
RFswXSA9IGNvbUlEID4+IDg7CisJaGRyLT5jcC5leHRlbmRlZENvbUlEWzFdID0gY29tSUQ7CisJ
aGRyLT5jcC5leHRlbmRlZENvbUlEWzJdID0gMDsKKwloZHItPmNwLmV4dGVuZGVkQ29tSURbM10g
PSAwOworfQorCitzdGF0aWMgaW50IGNtZF9maW5hbGl6ZShzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwg
dTMyIGhzbiwgdTMyIHRzbikKK3sKKwlzdHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkcjsKKwlpbnQgcmV0
OworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgIjZjIiwKKwkJCQkgICAgT1BB
TF9FTkRPRkRBVEEsIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICAwLCAwLCAwLCBPUEFMX0VORExJ
U1QpOworCisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCJFcnJvciBmaW5hbGl6aW5nIGNvbW1h
bmQuXG4iKTsKKwkJcmV0dXJuIC1FRkFVTFQ7CisJfQorCisJaGRyID0gKHN0cnVjdCBvcGFsX2hl
YWRlciAqKSBjbWQtPmNtZDsKKworCWhkci0+cGt0LlRTTiA9IGNwdV90b19iZTMyKHRzbik7CisJ
aGRyLT5wa3QuSFNOID0gY3B1X3RvX2JlMzIoaHNuKTsKKworCWhkci0+c3VicGt0Lmxlbmd0aCA9
IGNwdV90b19iZTMyKGNtZC0+cG9zIC0gc2l6ZW9mKCpoZHIpKTsKKwl3aGlsZSAoY21kLT5wb3Mg
JSA0KSB7CisJCWlmIChjbWQtPnBvcyA+PSBJT19CVUZGRVJfTEVOR1RIKSB7CisJCQlwcl9lcnIo
IkVycm9yOiBCdWZmZXIgb3ZlcnJ1blxuIik7CisJCQlyZXR1cm4gLUVSQU5HRTsKKwkJfQorCQlj
bWQtPmNtZFtjbWQtPnBvcysrXSA9IDA7CisJfQorCWhkci0+cGt0Lmxlbmd0aCA9IGNwdV90b19i
ZTMyKGNtZC0+cG9zIC0gc2l6ZW9mKGhkci0+Y3ApIC0KKwkJCQkgICAgICBzaXplb2YoaGRyLT5w
a3QpKTsKKwloZHItPmNwLmxlbmd0aCA9IGNwdV90b19iZTMyKGNtZC0+cG9zIC0gc2l6ZW9mKGhk
ci0+Y3ApKTsKKworCXJldHVybiAwOworfQorCitzdGF0aWMgZW51bSBPUEFMX1JFU1BPTlNFX1RP
S0VOIHRva2VuX3R5cGUoY29uc3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNwLAorCQkJCQkgICBp
bnQgbikKK3sKKwljb25zdCBzdHJ1Y3Qgb3BhbF9yZXNwX3RvayAqdG9rOworCisJaWYgKG4gPj0g
cmVzcC0+bnVtKSB7CisJCXByX2VycigiVG9rZW4gbnVtYmVyIGRvZXNuJ3QgZXhpc3Q6ICVkLCBy
ZXNwOiAlZFxuIiwKKwkJICAgICAgIG4sIHJlc3AtPm51bSk7CisJCXJldHVybiBPUEFMX0RUQV9U
T0tFTklEX0lOVkFMSUQ7CisJfQorCisJdG9rID0gJnJlc3AtPnRva3Nbbl07CisJaWYgKHRvay0+
bGVuID09IDApIHsKKwkJcHJfZXJyKCJUb2tlbiBsZW5ndGggbXVzdCBiZSBub24temVyb1xuIik7
CisJCXJldHVybiBPUEFMX0RUQV9UT0tFTklEX0lOVkFMSUQ7CisJfQorCisJcmV0dXJuIHRvay0+
dHlwZTsKK30KKworLyoKKyAqIFRoaXMgZnVuY3Rpb24gcmV0dXJucyAwIGluIGNhc2Ugb2YgaW52
YWxpZCB0b2tlbi4gT25lIHNob3VsZCBjYWxsCisgKiB0b2tlbl90eXBlKCkgZmlyc3QgdG8gZmlu
ZCBvdXQgaWYgdGhlIHRva2VuIGlzIHZhbGlkIG9yIG5vdC4KKyAqLworc3RhdGljIGVudW0gT1BB
TF9UT0tFTiByZXNwb25zZV9nZXRfdG9rZW4oY29uc3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNw
LAorCQkJCQkgIGludCBuKQoreworCWNvbnN0IHN0cnVjdCBvcGFsX3Jlc3BfdG9rICp0b2s7CisK
KwlpZiAobiA+PSByZXNwLT5udW0pIHsKKwkJcHJfZXJyKCJUb2tlbiBudW1iZXIgZG9lc24ndCBl
eGlzdDogJWQsIHJlc3A6ICVkXG4iLAorCQkgICAgICAgbiwgcmVzcC0+bnVtKTsKKwkJcmV0dXJu
IDA7CisJfQorCisJdG9rID0gJnJlc3AtPnRva3Nbbl07CisJaWYgKHRvay0+bGVuID09IDApIHsK
KwkJcHJfZXJyKCJUb2tlbiBsZW5ndGggbXVzdCBiZSBub24temVyb1xuIik7CisJCXJldHVybiAw
OworCX0KKworCXJldHVybiB0b2stPnBvc1swXTsKK30KKworc3RhdGljIHNpemVfdCByZXNwb25z
ZV9wYXJzZV90aW55KHN0cnVjdCBvcGFsX3Jlc3BfdG9rICp0b2ssCisJCQkJICBjb25zdCB1OCAq
cG9zKQoreworCXRvay0+cG9zID0gcG9zOworCXRvay0+bGVuID0gMTsKKwl0b2stPndpZHRoID0g
T1BBTF9XSURUSF9USU5ZOworCisJaWYgKHBvc1swXSAmIFRJTllfQVRPTV9TSUdORUQpIHsKKwkJ
dG9rLT50eXBlID0gT1BBTF9EVEFfVE9LRU5JRF9TSU5UOworCX0gZWxzZSB7CisJCXRvay0+dHlw
ZSA9IE9QQUxfRFRBX1RPS0VOSURfVUlOVDsKKwkJdG9rLT5zdG9yZWQudSA9IHBvc1swXSAmIDB4
M2Y7CisJfQorCisJcmV0dXJuIHRvay0+bGVuOworfQorCitzdGF0aWMgc2l6ZV90IHJlc3BvbnNl
X3BhcnNlX3Nob3J0KHN0cnVjdCBvcGFsX3Jlc3BfdG9rICp0b2ssCisJCQkJICAgY29uc3QgdTgg
KnBvcykKK3sKKwl0b2stPnBvcyA9IHBvczsKKwl0b2stPmxlbiA9IChwb3NbMF0gJiBTSE9SVF9B
VE9NX0xFTl9NQVNLKSArIDE7CisJdG9rLT53aWR0aCA9IE9QQUxfV0lEVEhfU0hPUlQ7CisKKwlp
ZiAocG9zWzBdICYgU0hPUlRfQVRPTV9CWVRFU1RSSU5HKSB7CisJCXRvay0+dHlwZSA9IE9QQUxf
RFRBX1RPS0VOSURfQllURVNUUklORzsKKwl9IGVsc2UgaWYgKHBvc1swXSAmIFNIT1JUX0FUT01f
U0lHTkVEKSB7CisJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfU0lOVDsKKwl9IGVsc2Ug
eworCQl1NjQgdV9pbnRlZ2VyID0gMDsKKwkJaW50IGksIGIgPSAwOworCisJCXRvay0+dHlwZSA9
IE9QQUxfRFRBX1RPS0VOSURfVUlOVDsKKwkJaWYgKHRvay0+bGVuID4gOSkKKwkJCXByX3dhcm4o
InVpbnQ2NCB3aXRoIG1vcmUgdGhhbiA4IGJ5dGVzXG4iKTsKKwkJZm9yIChpID0gdG9rLT5sZW4g
LSAxOyBpID4gMDsgaS0tKSB7CisJCQl1X2ludGVnZXIgfD0gKCh1NjQpcG9zW2ldIDw8ICg4ICog
YikpOworCQkJYisrOworCQl9CisJCXRvay0+c3RvcmVkLnUgPSB1X2ludGVnZXI7CisJfQorCisJ
cmV0dXJuIHRvay0+bGVuOworfQorCitzdGF0aWMgc2l6ZV90IHJlc3BvbnNlX3BhcnNlX21lZGl1
bShzdHJ1Y3Qgb3BhbF9yZXNwX3RvayAqdG9rLAorCQkJCSAgICBjb25zdCB1OCAqcG9zKQorewor
CXRvay0+cG9zID0gcG9zOworCXRvay0+bGVuID0gKCgocG9zWzBdICYgTUVESVVNX0FUT01fTEVO
X01BU0spIDw8IDgpIHwgcG9zWzFdKSArIDI7CisJdG9rLT53aWR0aCA9IE9QQUxfV0lEVEhfTUVE
SVVNOworCisJaWYgKHBvc1swXSAmIE1FRElVTV9BVE9NX0JZVEVTVFJJTkcpCisJCXRvay0+dHlw
ZSA9IE9QQUxfRFRBX1RPS0VOSURfQllURVNUUklORzsKKwllbHNlIGlmIChwb3NbMF0gJiBNRURJ
VU1fQVRPTV9TSUdORUQpCisJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfU0lOVDsKKwll
bHNlCisJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfVUlOVDsKKworCXJldHVybiB0b2st
PmxlbjsKK30KKworI2RlZmluZSBMT05HX0FUT01fSUQgKEJJVCg3KSB8IEJJVCg2KSB8IEJJVCg1
KSkKKyNkZWZpbmUgTE9OR19BVE9NX0JZVEVTVFJJTkcgQklUKDEpCisjZGVmaW5lIExPTkdfQVRP
TV9TSUdORUQgQklUKDApCitzdGF0aWMgc2l6ZV90IHJlc3BvbnNlX3BhcnNlX2xvbmcoc3RydWN0
IG9wYWxfcmVzcF90b2sgKnRvaywKKwkJCQkgIGNvbnN0IHU4ICpwb3MpCit7CisJdG9rLT5wb3Mg
PSBwb3M7CisJdG9rLT5sZW4gPSAoKHBvc1sxXSA8PCAxNikgfCAocG9zWzJdIDw8IDgpIHwgcG9z
WzNdKSArIDQ7CisJdG9rLT53aWR0aCA9IE9QQUxfV0lEVEhfTE9ORzsKKworCWlmIChwb3NbMF0g
JiBMT05HX0FUT01fQllURVNUUklORykKKwkJdG9rLT50eXBlID0gT1BBTF9EVEFfVE9LRU5JRF9C
WVRFU1RSSU5HOworCWVsc2UgaWYgKHBvc1swXSAmIExPTkdfQVRPTV9TSUdORUQpCisJCXRvay0+
dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfU0lOVDsKKwllbHNlCisJCXRvay0+dHlwZSA9IE9QQUxf
RFRBX1RPS0VOSURfVUlOVDsKKworCXJldHVybiB0b2stPmxlbjsKK30KKworc3RhdGljIHNpemVf
dCByZXNwb25zZV9wYXJzZV90b2tlbihzdHJ1Y3Qgb3BhbF9yZXNwX3RvayAqdG9rLAorCQkJCSAg
IGNvbnN0IHU4ICpwb3MpCit7CisJdG9rLT5wb3MgPSBwb3M7CisJdG9rLT5sZW4gPSAxOworCXRv
ay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfVE9LRU47CisJdG9rLT53aWR0aCA9IE9QQUxfV0lE
VEhfVE9LRU47CisKKwlyZXR1cm4gdG9rLT5sZW47Cit9CisKK3N0YXRpYyBpbnQgcmVzcG9uc2Vf
cGFyc2UoY29uc3QgdTggKmJ1Ziwgc2l6ZV90IGxlbmd0aCwKKwkJCSAgc3RydWN0IHBhcnNlZF9y
ZXNwICpyZXNwKQoreworCWNvbnN0IHN0cnVjdCBvcGFsX2hlYWRlciAqaGRyOworCXN0cnVjdCBv
cGFsX3Jlc3BfdG9rICppdGVyOworCWludCByZXQsIG51bV9lbnRyaWVzID0gMDsKKwl1MzIgY3Bv
cyA9IDAsIHRvdGFsOworCXNpemVfdCB0b2tlbl9sZW5ndGg7CisJY29uc3QgdTggKnBvczsKKwor
CWlmICghYnVmKQorCQlyZXR1cm4gLUVGQVVMVDsKKworCWlmICghcmVzcCkKKwkJcmV0dXJuIC1F
RkFVTFQ7CisKKwloZHIgPSAoc3RydWN0IG9wYWxfaGVhZGVyICopYnVmOworCXBvcyA9IGJ1ZjsK
Kwlwb3MgKz0gc2l6ZW9mKCpoZHIpOworCisJcHJfZGVidWcoIlJlc3BvbnNlIHNpemU6IGNwOiAl
ZCwgcGt0OiAlZCwgc3VicGt0OiAlZFxuIiwKKwkJIGJlMzJfdG9fY3B1KGhkci0+Y3AubGVuZ3Ro
KSwKKwkJIGJlMzJfdG9fY3B1KGhkci0+cGt0Lmxlbmd0aCksCisJCSBiZTMyX3RvX2NwdShoZHIt
PnN1YnBrdC5sZW5ndGgpKTsKKworCWlmICgoaGRyLT5jcC5sZW5ndGggPT0gMCkKKwkgICAgfHwg
KGhkci0+cGt0Lmxlbmd0aCA9PSAwKQorCSAgICB8fCAoaGRyLT5zdWJwa3QubGVuZ3RoID09IDAp
KSB7CisJCXByX2VycigiQmFkIGhlYWRlciBsZW5ndGguIGNwOiAlZCwgcGt0OiAlZCwgc3VicGt0
OiAlZFxuIiwKKwkJICAgICAgIGJlMzJfdG9fY3B1KGhkci0+Y3AubGVuZ3RoKSwKKwkJICAgICAg
IGJlMzJfdG9fY3B1KGhkci0+cGt0Lmxlbmd0aCksCisJCSAgICAgICBiZTMyX3RvX2NwdShoZHIt
PnN1YnBrdC5sZW5ndGgpKTsKKwkJcHJpbnRfYnVmZmVyKHBvcywgc2l6ZW9mKCpoZHIpKTsKKwkJ
cmV0ID0gLUVJTlZBTDsKKwkJZ290byBlcnI7CisJfQorCisJaWYgKHBvcyA+IGJ1ZiArIGxlbmd0
aCkgeworCQlyZXQgPSAtRUZBVUxUOworCQlnb3RvIGVycjsKKwl9CisKKwlpdGVyID0gcmVzcC0+
dG9rczsKKwl0b3RhbCA9IGJlMzJfdG9fY3B1KGhkci0+c3VicGt0Lmxlbmd0aCk7CisJcHJpbnRf
YnVmZmVyKHBvcywgdG90YWwpOworCXdoaWxlIChjcG9zIDwgdG90YWwpIHsKKwkJaWYgKCEocG9z
WzBdICYgMHg4MCkpIC8qIHRpbnkgYXRvbSAqLworCQkJdG9rZW5fbGVuZ3RoID0gcmVzcG9uc2Vf
cGFyc2VfdGlueShpdGVyLCBwb3MpOworCQllbHNlIGlmICghKHBvc1swXSAmIDB4NDApKSAvKiBz
aG9ydCBhdG9tICovCisJCQl0b2tlbl9sZW5ndGggPSByZXNwb25zZV9wYXJzZV9zaG9ydChpdGVy
LCBwb3MpOworCQllbHNlIGlmICghKHBvc1swXSAmIDB4MjApKSAvKiBtZWRpdW0gYXRvbSAqLwor
CQkJdG9rZW5fbGVuZ3RoID0gcmVzcG9uc2VfcGFyc2VfbWVkaXVtKGl0ZXIsIHBvcyk7CisJCWVs
c2UgaWYgKCEocG9zWzBdICYgMHgxMCkpIC8qIGxvbmcgYXRvbSAqLworCQkJdG9rZW5fbGVuZ3Ro
ID0gcmVzcG9uc2VfcGFyc2VfbG9uZyhpdGVyLCBwb3MpOworCQllbHNlIC8qIFRPS0VOICovCisJ
CQl0b2tlbl9sZW5ndGggPSByZXNwb25zZV9wYXJzZV90b2tlbihpdGVyLCBwb3MpOworCisJCXBv
cyArPSB0b2tlbl9sZW5ndGg7CisJCWNwb3MgKz0gdG9rZW5fbGVuZ3RoOworCQlpdGVyKys7CisJ
CW51bV9lbnRyaWVzKys7CisJfQorCisJaWYgKG51bV9lbnRyaWVzID09IDApIHsKKwkJcHJfZXJy
KCJDb3VsZG4ndCBwYXJzZSByZXNwb25zZS5cbiIpOworCQlyZXQgPSAtRUlOVkFMOworCQlnb3Rv
IGVycjsKKwl9CisJcmVzcC0+bnVtID0gbnVtX2VudHJpZXM7CisKKwlyZXR1cm4gMDsKK2VycjoK
KwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgc2l6ZV90IHJlc3BvbnNlX2dldF9zdHJpbmcoY29u
c3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNwLCBpbnQgbiwKKwkJCQkgIGNvbnN0IGNoYXIgKipz
dG9yZSkKK3sKKwkqc3RvcmUgPSBOVUxMOworCWlmICghcmVzcCkgeworCQlwcl9lcnIoIlJlc3Bv
bnNlIGlzIE5VTExcbiIpOworCQlyZXR1cm4gMDsKKwl9CisKKwlpZiAobiA+IHJlc3AtPm51bSkg
eworCQlwcl9lcnIoIlJlc3BvbnNlIGhhcyAlZCB0b2tlbnMuIENhbid0IGFjY2VzcyAlZFxuIiwK
KwkJICAgICAgIHJlc3AtPm51bSwgbik7CisJCXJldHVybiAwOworCX0KKworCWlmIChyZXNwLT50
b2tzW25dLnR5cGUgIT0gT1BBTF9EVEFfVE9LRU5JRF9CWVRFU1RSSU5HKSB7CisJCXByX2Vycigi
VG9rZW4gaXMgbm90IGEgYnl0ZSBzdHJpbmchXG4iKTsKKwkJcmV0dXJuIDA7CisJfQorCisJKnN0
b3JlID0gcmVzcC0+dG9rc1tuXS5wb3MgKyAxOworCXJldHVybiByZXNwLT50b2tzW25dLmxlbiAt
IDE7Cit9CisKK3N0YXRpYyB1NjQgcmVzcG9uc2VfZ2V0X3U2NChjb25zdCBzdHJ1Y3QgcGFyc2Vk
X3Jlc3AgKnJlc3AsIGludCBuKQoreworCWlmICghcmVzcCkgeworCQlwcl9lcnIoIlJlc3BvbnNl
IGlzIE5VTExcbiIpOworCQlyZXR1cm4gMDsKKwl9CisKKwlpZiAobiA+IHJlc3AtPm51bSkgewor
CQlwcl9lcnIoIlJlc3BvbnNlIGhhcyAlZCB0b2tlbnMuIENhbid0IGFjY2VzcyAlZFxuIiwKKwkJ
ICAgICAgIHJlc3AtPm51bSwgbik7CisJCXJldHVybiAwOworCX0KKworCWlmIChyZXNwLT50b2tz
W25dLnR5cGUgIT0gT1BBTF9EVEFfVE9LRU5JRF9VSU5UKSB7CisJCXByX2VycigiVG9rZW4gaXMg
bm90IHVuc2lnbmVkIGl0OiAlZFxuIiwKKwkJICAgICAgIHJlc3AtPnRva3Nbbl0udHlwZSk7CisJ
CXJldHVybiAwOworCX0KKworCWlmICghKChyZXNwLT50b2tzW25dLndpZHRoID09IE9QQUxfV0lE
VEhfVElOWSkgfHwKKwkgICAgICAocmVzcC0+dG9rc1tuXS53aWR0aCA9PSBPUEFMX1dJRFRIX1NI
T1JUKSkpIHsKKwkJcHJfZXJyKCJBdG9tIGlzIG5vdCBzaG9ydCBvciB0aW55OiAlZFxuIiwKKwkJ
ICAgICAgIHJlc3AtPnRva3Nbbl0ud2lkdGgpOworCQlyZXR1cm4gMDsKKwl9CisKKwlyZXR1cm4g
cmVzcC0+dG9rc1tuXS5zdG9yZWQudTsKK30KKworc3RhdGljIHU4IHJlc3BvbnNlX3N0YXR1cyhj
b25zdCBzdHJ1Y3QgcGFyc2VkX3Jlc3AgKnJlc3ApCit7CisJaWYgKCh0b2tlbl90eXBlKHJlc3As
IDApID09IE9QQUxfRFRBX1RPS0VOSURfVE9LRU4pCisJICAgICYmIChyZXNwb25zZV9nZXRfdG9r
ZW4ocmVzcCwgMCkgPT0gT1BBTF9FTkRPRlNFU1NJT04pKSB7CisJCXJldHVybiAwOworCX0KKwor
CWlmIChyZXNwLT5udW0gPCA1KQorCQlyZXR1cm4gRFRBRVJST1JfTk9fTUVUSE9EX1NUQVRVUzsK
KworCWlmICgodG9rZW5fdHlwZShyZXNwLCByZXNwLT5udW0gLSAxKSAhPSBPUEFMX0RUQV9UT0tF
TklEX1RPS0VOKSB8fAorCSAgICAodG9rZW5fdHlwZShyZXNwLCByZXNwLT5udW0gLSA1KSAhPSBP
UEFMX0RUQV9UT0tFTklEX1RPS0VOKSB8fAorCSAgICAocmVzcG9uc2VfZ2V0X3Rva2VuKHJlc3As
IHJlc3AtPm51bSAtIDEpICE9IE9QQUxfRU5ETElTVCkgfHwKKwkgICAgKHJlc3BvbnNlX2dldF90
b2tlbihyZXNwLCByZXNwLT5udW0gLSA1KSAhPSBPUEFMX1NUQVJUTElTVCkpCisJCXJldHVybiBE
VEFFUlJPUl9OT19NRVRIT0RfU1RBVFVTOworCisJcmV0dXJuIHJlc3BvbnNlX2dldF91NjQocmVz
cCwgcmVzcC0+bnVtIC0gNCk7Cit9CisKKy8qIFBhcnNlcyBhbmQgY2hlY2tzIGZvciBlcnJvcnMg
Ki8KK3N0YXRpYyBpbnQgcGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhzdHJ1Y3Qgb3BhbF9kZXYgKmRl
dikKK3sKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlpbnQgZXJyb3I7CisKKwljbWQgPSAmZGV2
LT5jbWQ7CisJcHJpbnRfYnVmZmVyKGNtZC0+Y21kLCBjbWQtPnBvcyk7CisKKwllcnJvciA9IHJl
c3BvbnNlX3BhcnNlKGNtZC0+cmVzcCwgSU9fQlVGRkVSX0xFTkdUSCwgJmRldi0+cGFyc2VkKTsK
KwlpZiAoZXJyb3IpIHsKKwkJcHJfZXJyKCIlczogQ291bGRuJ3QgcGFyc2UgcmVzcG9uc2UuXG4i
LCBkZXYtPmRpc2tfbmFtZSk7CisJCWdvdG8gZXJyX3JldHVybjsKKwl9CisKKwllcnJvciA9IHJl
c3BvbnNlX3N0YXR1cygmZGV2LT5wYXJzZWQpOworCWlmIChlcnJvcikKKwkJcHJfZXJyKCIlczog
UmVzcG9uc2UgU3RhdHVzOiAlZFxuIiwgZGV2LT5kaXNrX25hbWUsCisJCSAgICAgICBlcnJvcik7
CisKKyBlcnJfcmV0dXJuOgorCXJldHVybiBlcnJvcjsKK30KKworc3RhdGljIHZvaWQgY2xlYXJf
b3BhbF9jbWQoc3RydWN0IG9wYWxfY21kICpjbWQpCit7CisJY21kLT5wb3MgPSBzaXplb2Yoc3Ry
dWN0IG9wYWxfaGVhZGVyKTsKKwltZW1zZXQoY21kLT5jbWQsIDAsIElPX0JVRkZFUl9MRU5HVEgp
OworCWNtZC0+Y2IgPSBOVUxMOworCWNtZC0+Y2JfZGF0YSA9IE5VTEw7Cit9CisKK3N0YXRpYyB2
b2lkIHN0YXJ0X29wYWxfc2Vzc2lvbl9jb250KGludCBlcnJvciwgdm9pZCAqZGF0YSkKK3sKKwlz
dHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisJdTMyIEhTTiwgVFNOOworCisJaWYgKGVycm9y
KQorCQlnb3RvIGVycl9yZXR1cm47CisKKwllcnJvciA9IHBhcnNlX2FuZF9jaGVja19zdGF0dXMo
ZGV2KTsKKwlpZiAoZXJyb3IpCisJCWdvdG8gZXJyX3JldHVybjsKKworCUhTTiA9IHJlc3BvbnNl
X2dldF91NjQoJmRldi0+cGFyc2VkLCA0KTsKKwlUU04gPSByZXNwb25zZV9nZXRfdTY0KCZkZXYt
PnBhcnNlZCwgNSk7CisKKwlpZiAoSFNOID09IDAgJiYgVFNOID09IDApIHsKKwkJcHJfZXJyKCIl
czogQ291bGRuJ3QgYXV0aGVudGljYXRlIHNlc3Npb25cbiIsIGRldi0+ZGlza19uYW1lKTsKKwkJ
ZXJyb3IgPSAtRVBFUk07CisJCWdvdG8gZXJyX3JldHVybjsKKwl9CisKKwlkZXYtPkhTTiA9IEhT
TjsKKwlkZXYtPlRTTiA9IFRTTjsKKworZXJyX3JldHVybjoKKwlpZiAoZGV2LT5vcGVyX2NiKQor
CQlkZXYtPm9wZXJfY2IoZXJyb3IsIGRldik7Cit9CisKK3N0YXRpYyBpbnQgZ2V0X29wYWxfa2V5
KHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXN0cnVjdCBrZXkgKnVrZXkgPSBOVUxMOworCWNv
bnN0IHU4ICp0bXBrZXkgPSBOVUxMOworCXNpemVfdCB0bXBsZW47CisJaW50IHJldCA9IDA7CisK
KwlpZiAoZGV2LT5rZXlfdHlwZSA9PSBPUEFMX0tFWV9QTEFJTikgeworCQl0bXBrZXkgPSBkZXYt
PmtleV9uYW1lOworCQl0bXBsZW4gPSBkZXYtPmtleV9uYW1lX2xlbjsKKwl9IGVsc2UgaWYgKGRl
di0+a2V5X3R5cGUgPT0gT1BBTF9LRVlfS0VZUklORykgeworCQl1a2V5ID0gcmVxdWVzdF91c2Vy
X2tleShkZXYtPmtleV9uYW1lLCAmdG1wa2V5LCAmdG1wbGVuKTsKKwkJaWYgKElTX0VSUih1a2V5
KSkgeworCQkJcHJfZXJyKCIlczogQ2FuJ3QgcmV0cmlldmUga2V5OiAlbGRcbiIsIGRldi0+ZGlz
a19uYW1lLAorCQkJICAgICAgIFBUUl9FUlIodWtleSkpOworCQkJcmV0dXJuIFBUUl9FUlIodWtl
eSk7CisJCX0KKwl9IGVsc2UgeworCQlwcl9lcnIoIlJlcXVlc3RlZCBpbnZhbGlkIGtleSB0eXBl
OiAlZFxuIiwgZGV2LT5rZXlfdHlwZSk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCWlmICh0
bXBsZW4gPiBPUEFMX0tFWV9NQVgpIHsKKwkJcHJfZXJyKCJSZXF1ZXN0ZWQga2V5IHdpdGggaW52
YWxpZCBzaXplOiAlemRcbiIsIHRtcGxlbik7CisJCXJldCA9IC1FSU5WQUw7CisJCWdvdG8gZXJy
X2V4aXQ7CisJfQorCisJZGV2LT5rZXlfbGVuID0gdG1wbGVuOworCWlmICghbWVtY3B5KGRldi0+
a2V5LCB0bXBrZXksIHRtcGxlbikpIHsKKwkJcHJfZXJyKCJFcnJvciB3aGVuIGNvcHlpbmcga2V5
Iik7CisJCXJldCA9IC1FRkFVTFQ7CisJCWdvdG8gZXJyX2V4aXQ7CisJfQorCitlcnJfZXhpdDoK
KwlrZXlfcHV0KHVrZXkpOworCisJcmV0dXJuIDA7Cit9CisKK3N0YXRpYyB2b2lkIGNsZWFuX29w
YWxfa2V5KHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCW1lbXNldChkZXYtPmtleSwgMCwgT1BB
TF9LRVlfTUFYKTsKKwlkZXYtPmtleV9sZW4gPSAwOworfQorCitzdGF0aWMgaW5saW5lIHZvaWQg
Y2xlYW5fZnVuY3Rpb25fZGF0YShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwkJZGV2LT5mdW5j
X2RhdGEgPSBOVUxMOworCQlkZXYtPm51bV9mdW5jX2RhdGEgPSAwOworfQorCisvKiBUaGlzIGlz
IGEgZ2VuZXJpYyBjb250aW51ZSBmbi4KKyAqIFdlIHVzZSB0aGlzIHdoZW4gd2UgZG9uJ3QgY2Fy
ZSBhYm91dCB0aGUgcmVzcG9uc2UgZGF0YQorICogYW5kIHNpbXBseSB3YW50IHRvIGNoZWNrIHRo
ZSBzdGF0dXMgYW5kIGNvbnRpbnVlLgorICovCitzdGF0aWMgdm9pZCBnZW5lcmljX2NvbnQoaW50
IGVycm9yLCB2b2lkICpkYXRhKQoreworCXN0cnVjdCBvcGFsX2RldiAqZGV2ID0gZGF0YTsKKwor
CWlmIChlcnJvcikKKwkJZ290byBlcnJfcmV0dXJuOworCisJZXJyb3IgPSBwYXJzZV9hbmRfY2hl
Y2tfc3RhdHVzKGRldik7CisKKyBlcnJfcmV0dXJuOgorCWlmIChkZXYtPm9wZXJfY2IpCisJCWRl
di0+b3Blcl9jYihlcnJvciwgZGV2KTsKK30KKworc3RhdGljIHZvaWQgZW5kX3Nlc3Npb25fY29u
dChpbnQgZXJyb3IsIHZvaWQgKmRhdGEpCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRh
OworCisJZGV2LT5IU04gPSAwOworCWRldi0+VFNOID0gMDsKKwlnZW5lcmljX2NvbnQoZXJyb3Is
IGRhdGEpOworfQorCitzdGF0aWMgaW50IGZpbmFsaXplX2FuZF9zZW5kKHN0cnVjdCBvcGFsX2Rl
diAqZGV2LCBzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwKKwkJCSAgICAgc2VjX2NiIGNvbnQpCit7CisJ
aW50IHJldDsKKworCXJldCA9IGNtZF9maW5hbGl6ZShjbWQsIGRldi0+SFNOLCBkZXYtPlRTTik7
CisJaWYgKHJldCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBmaW5hbGl6aW5nIGNvbW1hbmQgYnVm
ZmVyOiAlZFxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lLCByZXQpOworCQlyZXR1cm4gcmV0
OworCX0KKworCXByaW50X2J1ZmZlcihjbWQtPmNtZCwgY21kLT5wb3MpOworCisJcmV0ID0gb3Bh
bF9zZW5kX3JlY3YoZGV2LCBjb250LCBkZXYpOworCWlmIChyZXQpCisJCXByX2VycigiJXM6IEVy
cm9yIHJ1bm5pbmcgY29tbWFuZDogJWRcbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSwgcmV0
KTsKKworCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBpbnQgd2FpdF9mb3JfY21kX2NvbXBsZXRp
b24oc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbikKK3sKKwl3YWl0X2Zvcl9jb21w
bGV0aW9uX2ludGVycnVwdGlibGUoJmNvbXBsZXRpb24tPmNtZF9jb21wbGV0aW9uKTsKKwlyZXR1
cm4gY29tcGxldGlvbi0+Y29tcGxldGlvbl9zdGF0dXM7Cit9CisKK3N0YXRpYyBpbnQgZ2VuX2tl
eShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwljb25zdCB1OCAqbWV0aG9kOworCXU4IHVpZFtP
UEFMX1VJRF9MRU5HVEhdOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisKKwlj
bWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBk
ZXYtPmNvbUlEKTsKKworCW1lbWNweSh1aWQsIGRldi0+cHJldl9kYXRhLCBtaW4oc2l6ZW9mKHVp
ZCksIGRldi0+cHJldl9kX2xlbikpOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9HRU5LRVld
OworCWtmcmVlKGRldi0+cHJldl9kYXRhKTsKKwlkZXYtPnByZXZfZGF0YSA9IE5VTEw7CisKKwly
ZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDJjIiwKKwkJCQkgICAgT1BBTF9D
QUxMLAorCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFM
X01FVEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxf
RU5ETElTVCk7CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcg
Z2VuIGtleSBjb21tYW5kXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4g
cmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19j
b250KTsKK30KKworc3RhdGljIHZvaWQgZ2V0X2FjdGl2ZV9rZXlfY29udChpbnQgZXJyb3IsIHZv
aWQgKmRhdGEpCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOworCWNvbnN0IGNoYXIg
KmFjdGl2ZWtleTsKKwlzaXplX3Qga2V5bGVuOworCisJaWYgKGVycm9yKQorCQlnb3RvIGVycl9y
ZXR1cm47CisKKwllcnJvciA9IHBhcnNlX2FuZF9jaGVja19zdGF0dXMoZGV2KTsKKwlpZiAoZXJy
b3IpCisJCWdvdG8gZXJyX3JldHVybjsKKwlrZXlsZW4gPSByZXNwb25zZV9nZXRfc3RyaW5nKCZk
ZXYtPnBhcnNlZCwgNCwgJmFjdGl2ZWtleSk7CisJaWYgKCFhY3RpdmVrZXkpIHsKKwkJcHJfZXJy
KCIlczogQ291bGRuJ3QgZXh0cmFjdCB0aGUgQWN0aXZla2V5IGZyb20gdGhlIHJlc3BvbnNlXG4i
LAorCQkgICAgICAgX19mdW5jX18pOworCQllcnJvciA9IDB4MEE7CisJCWdvdG8gZXJyX3JldHVy
bjsKKwl9CisJZGV2LT5wcmV2X2RhdGEgPSBrbWVtZHVwKGFjdGl2ZWtleSwga2V5bGVuLCBHRlBf
S0VSTkVMKTsKKworCWlmICghZGV2LT5wcmV2X2RhdGEpCisJCWVycm9yID0gLUVOT01FTTsKKwor
CWRldi0+cHJldl9kX2xlbiA9IGtleWxlbjsKKworZXJyX3JldHVybjoKKwlpZiAoZGV2LT5vcGVy
X2NiKQorCQlkZXYtPm9wZXJfY2IoZXJyb3IsIGRldik7Cit9CisKK3N0YXRpYyBpbnQgZ2V0X2Fj
dGl2ZV9rZXkoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJY29uc3QgdTggKm1ldGhvZDsKKwl1
OCB1aWRbT1BBTF9VSURfTEVOR1RIXTsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlpbnQgcmV0
OworCisJY21kID0gJmRldi0+Y21kOworCWNsZWFyX29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlE
KGNtZCwgZGV2LT5jb21JRCk7CisKKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfR0VUXTsKKwor
CXJldCA9IGJ1aWxkX2xvY2tpbmdfcmFuZ2UodWlkLCBzaXplb2YodWlkKSwgZGV2LT5scik7CisJ
aWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogQ2FuJ3QgYnVpbGQgbG9ja2luZyByYW5nZVxu
IiwgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlyZXQgPSB0ZXN0
X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDZjIDRjIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxM
LAorCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01F
VEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RB
UlRMSVNULAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRf
MDMsIC8qIHN0YXJ0Q2xvdW1uICovCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzEwLCAvKiBBY3Rp
dmVLZXkgKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1F
LAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wNCwgLyogZW5kQ29sdW1uICovCisJCQkJICAgIE9Q
QUxfVElOWV9VSU5UXzEwLCAvKiBBY3RpdmVLZXkgKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAor
CisJCQkJICAgIE9QQUxfRU5ETElTVCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKwlpZiAocmV0
IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBnZXQgYWN0aXZlIGtleSBjb21t
YW5kXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKwor
CXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2V0X2FjdGl2ZV9rZXlfY29udCk7
Cit9CisKK3N0YXRpYyBpbnQgc2V0dXBfbG9ja2luZ19yYW5nZShzdHJ1Y3Qgb3BhbF9kZXYgKmRl
dikKK3sKKwljb25zdCB1OCAqbWV0aG9kOworCXU4IHVpZFtPUEFMX1VJRF9MRU5HVEhdOworCXN0
cnVjdCBvcGFsX2NtZCAqY21kOworCXN0cnVjdCBvcGFsX3VzZXJfbHJfc2V0dXAgKnNldHVwOwor
CWludCByZXQ7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlz
ZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsKKworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9T
RVRdOworCXJldCA9IGJ1aWxkX2xvY2tpbmdfcmFuZ2UodWlkLCBzaXplb2YodWlkKSwgZGV2LT5s
cik7CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogQ2FuJ3QgYnVpbGQgbG9ja2luZyBy
YW5nZVxuIiwgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisJc2V0dXAg
PSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0YXRlIC0gMV07CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRf
dG9rZW5fdmEoY21kLCAiYzJzICA0YyAyY3VjIDJjdWMgMmN1YyAyY3UgNGMiLAorCQkJCSAgICBP
UEFMX0NBTEwsCisJCQkJICAgIHVpZCwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICBtZXRob2Qs
IE9QQUxfTUVUSE9EX0xFTkdUSCwKKworCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkgICAg
T1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVkFMVUVTLAorCQkJCSAgICBPUEFMX1NUQVJU
TElTVCwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRf
MDMsIC8qIFJhbmdlIFN0YXJ0ICovCisJCQkJICAgIHNldHVwLT5yYW5nZV9zdGFydCwKKwkJCQkg
ICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFM
X1RJTllfVUlOVF8wNCwgLyogUmFuZ2UgTGVuZ3RoICovCisJCQkJICAgIHNldHVwLT5yYW5nZV9s
ZW5ndGgsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwK
KwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDUsIC8qIFJlYWRMb2NrRW5hYmxlZCAqLworCQkJCSAg
ICAhIXNldHVwLT5STEUsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKworCQkJCSAgICBPUEFMX1NU
QVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIFdyaXRlTG9ja0VuYWJsZWQg
Ki8KKwkJCQkgICAgISFzZXR1cC0+V0xFLAorCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkg
ICAgT1BBTF9FTkRMSVNULAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5E
TElTVCk7CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgU2V0
dXAgTG9ja2luZyByYW5nZSBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsK
KwkJcmV0dXJuIHJldDsKKworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNt
ZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBzdGFydF9hZG1pbnNwX29wYWxfc2Vz
c2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldiwKKwkJCQkgICAgICBlbnVtIE9QQUxfVUlEIGF1dGgs
CisJCQkJICAgICAgY29uc3QgY2hhciAqa2V5LAorCQkJCSAgICAgIHU4IGtleV9sZW4pCit7CisJ
Y29uc3QgdTggKm1ldGhvZCwgKnNtdWlkLCAqYWRtaW5fc3AsICpoc2E7CisJc3RydWN0IG9wYWxf
Y21kICpjbWQ7CisJdTMyIEhTTjsKKwlpbnQgcmV0OworCisJaWYgKGtleSA9PSBOVUxMICYmIGF1
dGggIT0gT1BBTF9BTllCT0RZX1VJRCkgeworCQlwcl9lcnIoIiVzOiBBdHRlbXB0ZWQgdG8gb3Bl
biBBRE1JTl9TUCBTZXNzaW9uIHdpdGhvdXQgYSBIb3N0IiBcCisJCSAgICAgICAiQ2hhbGxlbmdl
LCBhbmQgbm90IGFzIHRoZSBBbnlib2R5IFVJRFxuIiwgX19mdW5jX18pOworCQlyZXR1cm4gMTsK
Kwl9CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKworCXNldF9j
b21JRChjbWQsIGRldi0+Y29tSUQpOworCUhTTiA9IDB4NDE7CisKKwlzbXVpZCA9IE9QQUxVSURb
T1BBTF9TTVVJRF9VSURdOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9TVEFSVFNFU1NJT05d
OworCWFkbWluX3NwID0gT1BBTFVJRFtPUEFMX0FETUlOU1BfVUlEXTsKKworCXJldCA9IHRlc3Rf
YW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgY3VzYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJ
CQkgICAgc211aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhP
RF9MRU5HVEgsCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBIU04sCisJCQkJICAg
IGFkbWluX3NwLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxKTsK
KwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBzdGFydCBhZG1p
bnNwIHNlc3Npb24gY29tbWFuZC5cbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJl
dHVybiByZXQ7CisJfQorCisJc3dpdGNoIChhdXRoKSB7CisJY2FzZSBPUEFMX0FOWUJPRFlfVUlE
OgorCQkvKiBub3RoaW5nIGxlZnQgdG8gZG8gZm9yIGFueWJvZHksIGp1c3QgZW5kIGFuZCBmaW5h
bGl6ZSAqLworCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYyIsCisJCQkJCSAg
ICBPUEFMX0VORExJU1QpOworCQlicmVhazsKKwljYXNlIE9QQUxfU0lEX1VJRDoKKwkJaHNhID0g
T1BBTFVJRFtPUEFMX1NJRF9VSURdOworCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21k
LCAiMmMgcyAzYyBzIDJjIiwKKwkJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCQkgICAgT1BB
TF9USU5ZX1VJTlRfMDAsIC8qIEhvc3RDaGFsbGVuZ2UgKi8KKwkJCQkJICAgIGtleSwga2V5X2xl
biwKKwkJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJ
CQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIEhvc3RTaWduQXV0aCAqLworCQkJCQkgICAgaHNh
LCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJCSAgICBPUEFM
X0VORExJU1QpOworCQlicmVhazsKKwlkZWZhdWx0OgorCQlwcl9lcnIoIkNhbm5vdCBzdGFydCBB
ZG1pbiBTUCBzZXNzaW9uIHdpdGggYXV0aCAlZFxuIiwgYXV0aCk7CisJCXJldHVybiAxOworCX0K
KworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIHN0YXJ0IGFk
bWluc3Agc2Vzc2lvbiBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJ
cmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIHN0
YXJ0X29wYWxfc2Vzc2lvbl9jb250KTsKK30KKworc3RhdGljIGludCBzdGFydF9hbnlib2R5QVNQ
X29wYWxfc2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlyZXR1cm4gc3RhcnRfYWRt
aW5zcF9vcGFsX3Nlc3Npb24oZGV2LCBPUEFMX0FOWUJPRFlfVUlELCBOVUxMLCAwKTsKK30KKwor
c3RhdGljIGludCBzdGFydF9TSURBU1Bfb3BhbF9zZXNzaW9uKHN0cnVjdCBvcGFsX2RldiAqZGV2
KQoreworCWludCByZXQ7CisJY29uc3QgdTggKmtleSA9IGRldi0+cHJldl9kYXRhOworCisJaWYg
KCFrZXkpCisJCXJldCA9IHN0YXJ0X2FkbWluc3Bfb3BhbF9zZXNzaW9uKGRldiwgT1BBTF9TSURf
VUlELCBkZXYtPmtleSwKKwkJCQkJCSBkZXYtPmtleV9sZW4pOworCWVsc2UgeworCQlyZXQgPSBz
dGFydF9hZG1pbnNwX29wYWxfc2Vzc2lvbihkZXYsIE9QQUxfU0lEX1VJRCwga2V5LAorCQkJCQkJ
IGRldi0+cHJldl9kX2xlbik7CisJCWtmcmVlKGtleSk7CisJCWRldi0+cHJldl9kYXRhID0gTlVM
TDsKKwl9CisJcmV0dXJuIHJldDsKK30KKworc3RhdGljIGludCBzdGFydF9sb2NraW5nc3Bfb3Bh
bF9zZXNzaW9uKHN0cnVjdCBvcGFsX2RldiAqZGV2LAorCQkJCQllbnVtIE9QQUxfVUlEIGF1dGgs
IGNvbnN0IHU4ICprZXksCisJCQkJCXU4IGtleV9sZW4pCit7CisKKwljb25zdCB1OCAqbWV0aG9k
LCAqc211aWQsICpsb2NraW5nX3NwLCAqaHNhOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCXNp
emVfdCBrbGVuID0ga2V5X2xlbjsKKwl1MzIgSFNOOworCWludCByZXQ7CisKKwlpZiAoa2V5ID09
IE5VTEwpIHsKKwkJcHJfZXJyKCJDYW5ub3Qgc3RhcnQgTG9ja2luZyBTUCBzZXNzaW9uIHdpdGhv
dXQgYSBrZXlcbiIpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwljbWQgPSAmZGV2LT5jbWQ7
CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwor
CUhTTiA9IDB4NDE7CisKKwlzbXVpZCA9IE9QQUxVSURbT1BBTF9TTVVJRF9VSURdOworCW1ldGhv
ZCA9IE9QQUxNRVRIT0RbT1BBTF9TVEFSVFNFU1NJT05dOworCWxvY2tpbmdfc3AgPSBPUEFMVUlE
W09QQUxfTE9DS0lOR1NQX1VJRF07CisJaHNhID0gT1BBTFVJRFthdXRoXTsKKworCXJldCA9IHRl
c3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgY3VzYyAyY3NjIDJjc2MgYyIsCisJCQkJICAg
IE9QQUxfQ0FMTCwKKwkJCQkgICAgc211aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0
aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJ
ICAgIEhTTiwKKwkJCQkgICAgbG9ja2luZ19zcCwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICBP
UEFMX1RJTllfVUlOVF8wMSwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BB
TF9USU5ZX1VJTlRfMDAsIC8qIEhvc3RDaGFsbGVuZ2UgKi8KKwkJCQkgICAga2V5LCBrbGVuLAor
CQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAg
IE9QQUxfVElOWV9VSU5UXzAzLCAvKiBIb3N0IFNpZ24gQXV0aG9yaXR5ICovCisJCQkJICAgIGhz
YSwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BB
TF9FTkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxk
aW5nIHN0YXJ0IGFkbWluc3Agc2Vzc2lvbiBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlz
a19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9CisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRl
diwgY21kLCBzdGFydF9vcGFsX3Nlc3Npb25fY29udCk7Cit9CisKK3N0YXRpYyBpbmxpbmUgaW50
IHN0YXJ0X2FkbWluMUxTUF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJ
cmV0dXJuIHN0YXJ0X2xvY2tpbmdzcF9vcGFsX3Nlc3Npb24oZGV2LCBPUEFMX0FETUlOMV9VSUQs
CisJCQkJCSAgICBkZXYtPmtleSwgZGV2LT5rZXlfbGVuKTsKK30KKworc3RhdGljIGludCBzdGFy
dF9hdXRoX29wYWxfc2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwljb25zdCB1OCAq
bWV0aG9kLCAqc211aWQsICpsb2NraW5nX3NwOworCXU4IGxrX3VsX3VzZXJbT1BBTF9VSURfTEVO
R1RIXTsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwl1MzIgSFNOOworCWludCByZXQ7CisJc3Ry
dWN0IG9wYWxfdXNlcl9pbmZvICp1aW5mbzsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9v
cGFsX2NtZChjbWQpOworCisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwlIU04gPSAw
eDQxOworCisJdWluZm8gPSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0YXRlIC0gMV07CisKKwlzbXVp
ZCA9IE9QQUxVSURbT1BBTF9TTVVJRF9VSURdOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9T
VEFSVFNFU1NJT05dOworCWxvY2tpbmdfc3AgPSBPUEFMVUlEW09QQUxfTE9DS0lOR1NQX1VJRF07
CisKKwlpZiAodWluZm8tPlNVTSkgeworCQlyZXQgPSBidWlsZF9sb2NraW5nX3VzZXIobGtfdWxf
dXNlciwgc2l6ZW9mKGxrX3VsX3VzZXIpLAorCQkJCQkgZGV2LT5scik7CisJCWlmIChyZXQgPCAw
KSB7CisJCQlwcl9lcnIoIiVzOiBDYW4ndCBidWlsZCBsb2NraW5nIHVzZXJcbiIsCisJCQkgICAg
ICAgZGV2LT5kaXNrX25hbWUpOworCQkJcmV0dXJuIHJldDsKKwkJfQorCX0gZWxzZSBpZiAodWlu
Zm8tPndobyAhPSBPUEFMX0FETUlOMSAmJiAhdWluZm8tPlNVTSkgeworCQlyZXQgPSBidWlsZF9s
b2NraW5nX3VzZXIobGtfdWxfdXNlciwgc2l6ZW9mKGxrX3VsX3VzZXIpLAorCQkJCQkgdWluZm8t
PndobyAtIDEpOworCQlpZiAocmV0IDwgMCkgeworCQkJcHJfZXJyKCIlczogQ2FuJ3QgYnVpbGQg
bG9ja2luZyB1c2VyXG4iLAorCQkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJCXJldHVybiBy
ZXQ7CisJCX0KKwl9IGVsc2UKKwkJbWVtY3B5KGxrX3VsX3VzZXIsIE9QQUxVSURbT1BBTF9BRE1J
TjFfVUlEXSwgT1BBTF9VSURfTEVOR1RIKTsKKworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2Vu
X3ZhKGNtZCwgImMycyBjdXMzY3MzYyBzIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAg
ICBzbXVpZCwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xF
TkdUSCwKKworCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkgICAgSFNOLAorCQkJCSAgICBs
b2NraW5nX3NwLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxLAor
CQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDAsCisJCQkJ
ICAgIGRldi0+a2V5LCBkZXYtPmtleV9sZW4sCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkg
ICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLAorCisJCQkJICAg
IGxrX3VsX3VzZXIsIE9QQUxfVUlEX0xFTkdUSCwKKworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJ
CQkJICAgIE9QQUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBF
cnJvciBidWlsZGluZyBTVEFSVFNFU1NJT04gY29tbWFuZC5cbiIsCisJCSAgICAgICBkZXYtPmRp
c2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5k
KGRldiwgY21kLCBzdGFydF9vcGFsX3Nlc3Npb25fY29udCk7Cit9CisKK3N0YXRpYyBpbnQgcmV2
ZXJ0X3RwZXIoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJY29uc3QgdTggKm1ldGhvZCwgKnNt
dWlkOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisKKwljbWQgPSAmZGV2LT5j
bWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQp
OworCisJc211aWQgPSBPUEFMVUlEW09QQUxfQURNSU5TUF9VSURdOworCW1ldGhvZCA9IE9QQUxN
RVRIT0RbT1BBTF9SRVZFUlRdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwg
ImMycyAyYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgc211aWQsIE9QQUxfVUlEX0xF
TkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisJCQkJICAgIE9QQUxf
U1RBUlRMSVNULAorCQkJCSAgICBPUEFMX0VORExJU1QpOworCWlmIChyZXQgPCAwKSB7CisJCXBy
X2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIFJFVkVSVCBUUEVSIGNvbW1hbmQuXG4iLAorCQkgICAg
ICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6
ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBpbnRl
cm5hbF9hY3RpdmF0ZV91c2VyKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCWNvbnN0IHU4ICpt
ZXRob2Q7CisJdTggdWlkW09QQUxfVUlEX0xFTkdUSF07CisJc3RydWN0IG9wYWxfY21kICpjbWQ7
CisJaW50IHJldDsKKwlzdHJ1Y3Qgb3BhbF9hY3RpdmF0ZV91c2VyICphY3Q7CisKKwljbWQgPSAm
ZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNv
bUlEKTsKKworCWFjdCA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKworCW1lbWNw
eSh1aWQsIE9QQUxVSURbT1BBTF9VU0VSMV9VSURdLCBPUEFMX1VJRF9MRU5HVEgpOworCXVpZFs3
XSA9IGFjdC0+d2hvLndobzsKKworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9TRVRdOworCisJ
cmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAzYyBjIDRjIDNjIiwKKwkJCQkg
ICAgT1BBTF9DQUxMLAorCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0
aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJ
ICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMSwgLyogVmFsdWVz
ICovCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUs
CisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzA1LCAvKiBFbmFibGVkICovCisJCQkJICAgIE9QQUxf
VElOWV9VSU5UXzAxLCAvKiBUcnVlICovCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKworCQkJCSAg
ICBPUEFMX0VORExJU1QsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9FTkRM
SVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIEFj
dGl2YXRlIFVzZXJOIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQly
ZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2Vu
ZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBlcmFzZV9sb2NraW5nX3JhbmdlKHN0cnVjdCBv
cGFsX2RldiAqZGV2KQoreworCWNvbnN0IHU4ICptZXRob2Q7CisJdTggdWlkW09QQUxfVUlEX0xF
TkdUSF07CisJc3RydWN0IG9wYWxfY21kICpjbWQ7CisJaW50IHJldDsKKworCWNtZCA9ICZkZXYt
PmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQp
OworCisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX0VSQVNFXTsKKworCWlmIChidWlsZF9sb2Nr
aW5nX3JhbmdlKHVpZCwgc2l6ZW9mKHVpZCksIGRldi0+bHIpIDwgMCkgeworCQlwcl9lcnIoIiVz
OiBDYW4ndCBidWlsZCBsb2NraW5nIHJhbmdlXG4iLCBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVy
biAtRUlOVkFMOworCX0KKworCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMg
MmMiLAorCQkJCSAgICBPUEFMX0NBTEwsCisJCQkJICAgIHVpZCwgT1BBTF9VSURfTEVOR1RILAor
CQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKworCQkJCSAgICBPUEFMX1NUQVJU
TElTVCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2Vy
cigiJXM6IEVycm9yIGJ1aWxkaW5nIEVyYXNlIExvY2tpbmcgUmFuZ2UgQ21tYW5kLlxuIiwKKwkJ
ICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9CisJcmV0dXJuIGZpbmFs
aXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOworfQorCitzdGF0aWMgaW50IHNl
dF9tYnJfZG9uZShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwljb25zdCB1OCAqbWV0aG9kLCAq
dWlkOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisKKwl1OCBtYnJfZG9uZV90
ZiA9ICoodTggKilkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0YXRlIC0gMV07CisKKwljbWQgPSAmZGV2
LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlE
KTsKKworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9TRVRdOworCXVpZCA9IE9QQUxVSURbT1BB
TF9NQlJDT05UUk9MXTsKKworCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMg
M2MgNmMgMmMiLAorCQkJCSAgICBPUEFMX0NBTEwsCisJCQkJICAgIHVpZCwgT1BBTF9VSURfTEVO
R1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKworCQkJCSAgICBPUEFM
X1NUQVJUTElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVkFMVUVT
LAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJ
CQkgICAgT1BBTF9USU5ZX1VJTlRfMDIsIC8qIERvbmUgKi8KKwkJCQkgICAgbWJyX2RvbmVfdGYs
ICAgICAgIC8qIERvbmUgVCBvciBGICovCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAg
T1BBTF9FTkRMSVNULAorCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9FTkRM
SVNUKTsKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBCdWlsZGluZyBzZXQg
TUJSIERvbnQvTm90IGRvbmUgY29tbWFuZFxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsK
KwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQs
IGdlbmVyaWNfY29udCk7Cit9CisKK3N0YXRpYyBpbnQgc2V0X21icl9lbmFibGVfZGlzYWJsZShz
dHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwljb25zdCB1OCAqbWV0aG9kLCAqdWlkOworCXN0cnVj
dCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisKKwl1OCBtYnJfZW5fZGlzID0gKih1OCAqKWRl
di0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVh
cl9vcGFsX2NtZChjbWQpOworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOworCisJbWV0aG9k
ID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07CisJdWlkID0gT1BBTFVJRFtPUEFMX01CUkNPTlRST0xd
OworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAzYyA2YyAyYyIsCisJ
CQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAg
IG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAor
CQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9WQUxVRVMsCisKKwkJCQkgICAg
T1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJ
TllfVUlOVF8wMSwgLyogRW5hYmxlICovCisJCQkJICAgIG1icl9lbl9kaXMsICAgICAgICAvKiBF
bmFibGUgb3IgRGlzYWJsZSAqLworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxf
RU5ETElTVCwKKworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElTVCk7
CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3IgQnVpbGRpbmcgc2V0IE1CUiBE
b250L05vdCBkb25lIGNvbW1hbmRcbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJl
dHVybiByZXQ7CisJfQorCisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5l
cmljX2NvbnQpOworfQorCitzdGF0aWMgaW50IHNldF9uZXdfcHcoc3RydWN0IG9wYWxfZGV2ICpk
ZXYpCit7CisJY29uc3QgdTggKm1ldGhvZDsKKwl1OCBjcGluX3VpZFtPUEFMX1VJRF9MRU5HVEhd
OworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisJc3RydWN0IG9wYWxfbmV3X3B3
ICpwdzsKKwlzaXplX3Qga2V5X2xlbjsKKwl1OCAqa2V5OworCisJY21kID0gJmRldi0+Y21kOwor
CWNsZWFyX29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwlw
dyA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKwlrZXkgPSBwdy0+bmV3X3Bpbi5r
ZXk7CisJa2V5X2xlbiA9IHB3LT5uZXdfcGluLmtleV9sZW47CisJbWVtY3B5KGNwaW5fdWlkLCBP
UEFMVUlEW09QQUxfQ19QSU5fQURNSU4xXSwgT1BBTF9VSURfTEVOR1RIKTsKKworCWlmIChwdy0+
dXNlcl9mb3JfcHcgIT0gT1BBTF9BRE1JTjEpIHsKKwkJY3Bpbl91aWRbNV0gPSAweDAzOworCQlp
ZiAocHctPndoby5TVU0pCisJCQljcGluX3VpZFs3XSA9IHB3LT5uZXdfcGluLmxyICsgMTsKKwkJ
ZWxzZQorCQkJY3Bpbl91aWRbN10gPSBwdy0+dXNlcl9mb3JfcHc7CisJfQorCisJbWV0aG9kID0g
T1BBTE1FVEhPRFtPUEFMX1NFVF07CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21k
LCAiYzJzIDNjIDNjczJjIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICBjcGluX3Vp
ZCwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwK
KworCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJ
ICAgIE9QQUxfVElOWV9VSU5UXzAxLCAvKiBWYWx1ZXMgKi8KKworCQkJCSAgICBPUEFMX1NUQVJU
TElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAz
LCAvKiBQSU4gKi8KKwkJCQkgICAga2V5LCBrZXlfbGVuLAorCQkJCSAgICBPUEFMX0VORE5BTUUs
CisJCQkJICAgIE9QQUxfRU5ETElTVCwKKworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAg
IE9QQUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBi
dWlsZGluZyBTRVQgQU1JTjEgUElOIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25h
bWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYs
IGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBzZXRfc2lkX2NwaW5fcGluKHN0
cnVjdCBvcGFsX2RldiAqZGV2KQoreworCWNvbnN0IHU4ICptZXRob2QsICpjcGluX3VpZDsKKwlz
dHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlpbnQgcmV0OworCisJY21kID0gJmRldi0+Y21kOworCWNs
ZWFyX29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwljcGlu
X3VpZCA9IE9QQUxVSURbT1BBTF9DX1BJTl9TSURdOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BB
TF9TRVRdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAyYyA0Y3My
YyAyYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgY3Bpbl91aWQsIE9QQUxfVUlEX0xF
TkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BB
TF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCisJCQkJICAgIE9QQUxfVElO
WV9VSU5UXzAxLCAvKiBWYWx1ZXMgKi8KKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAg
IE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogUElOICovCisJ
CQkJICAgIGRldi0+a2V5LCBkZXYtPmtleV9sZW4sCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJ
CQkgICAgT1BBTF9FTkRMSVNULAorCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BB
TF9FTkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxk
aW5nIFNFVCBDUElOIFBJTiBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsK
KwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQs
IGdlbmVyaWNfY29udCk7Cit9CisKK3N0YXRpYyB2b2lkIHF1ZXJ5X2xvY2tpbmdfcmFuZ2VfY29u
dChpbnQgZXJyb3IsIHZvaWQgKmRhdGEpCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRh
OworCisJaWYgKGVycm9yKQorCQlnb3RvIGVycl9yZXR1cm47CisKKwllcnJvciA9IHBhcnNlX2Fu
ZF9jaGVja19zdGF0dXMoZGV2KTsKKwlpZiAoZXJyb3IpCisJCWdvdG8gZXJyX3JldHVybjsKKwor
CWRldi0+c3RhcnQgPSByZXNwb25zZV9nZXRfdTY0KCZkZXYtPnBhcnNlZCwgNCk7CisJZGV2LT5s
ZW5ndGggPSByZXNwb25zZV9nZXRfdTY0KCZkZXYtPnBhcnNlZCwgOCk7CisKK2Vycl9yZXR1cm46
CisJaWYgKGRldi0+b3Blcl9jYikKKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBkZXYpOworfQorCitz
dGF0aWMgaW50IHF1ZXJ5X2xvY2tpbmdfcmFuZ2Uoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJ
dTggbHJfYnVmZmVyW09QQUxfVUlEX0xFTkdUSF07CisJc3RydWN0IG9wYWxfY21kICpjbWQ7CisJ
Y29uc3QgdTggKm1ldGhvZDsKKwlpbnQgcmV0OworCisJY21kID0gJmRldi0+Y21kOworCWNsZWFy
X29wYWxfY21kKGNtZCk7CisKKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfR0VUXTsKKworCWlm
IChidWlsZF9sb2NraW5nX3JhbmdlKGxyX2J1ZmZlciwgc2l6ZW9mKGxyX2J1ZmZlciksIGRldi0+
bHIpIDwgMCkgeworCQlwcl9lcnIoIiVzOiBDYW4ndCBidWlsZCBsb2NraW5nIHJhbmdlXG4iLCBk
ZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCXNldF9jb21JRChjbWQs
IGRldi0+Y29tSUQpOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAx
MmMiLAorCQkJCSAgICBPUEFMX0NBTEwsCisJCQkJICAgIGxyX2J1ZmZlciwgT1BBTF9VSURfTEVO
R1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKworCQkJCSAgICBPUEFM
X1NUQVJUTElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlRO
QU1FLAorCQkJCSAgICBPUEFMX1NUQVJUQ09MVU1OLAorCQkJCSAgICBPUEFMX1JBTkdFU1RBUlQs
CisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAg
IE9QQUxfRU5EQ09MVU1OLAorCQkJCSAgICBPUEFMX1JBTkdFTEVOR1RILAorCQkJCSAgICBPUEFM
X0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElTVCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsK
KworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIEdFVCBMb2Nr
aW5nIFJhbmdlIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1
cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgcXVlcnlf
bG9ja2luZ19yYW5nZV9jb250KTsKK30KKworc3RhdGljIGludCBhZGRfdXNlcl90b19scihzdHJ1
Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwl1OCBscl9idWZmZXJbT1BBTF9VSURfTEVOR1RIXTsKKwl1
OCB1c2VyX3VpZFtPUEFMX1VJRF9MRU5HVEhdOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWNv
bnN0IHU4ICptZXRob2Q7CisJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrdWw7CisJaW50IHJl
dDsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9jb21J
RChjbWQsIGRldi0+Y29tSUQpOworCisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07CisK
Kwlsa3VsID0gZGV2LT5mdW5jX2RhdGFbZGV2LT5zdGF0ZSAtIDFdOworCisJbWVtY3B5KGxyX2J1
ZmZlciwgT1BBTFVJRFtPUEFMX0xPQ0tJTkdSQU5HRV9BQ0VfUkRMT0NLRURdLAorCSAgICAgICBP
UEFMX1VJRF9MRU5HVEgpOworCisJaWYgKGxrdWwtPmxfc3RhdGUgPT0gT1BBTF9SVykKKwkJbWVt
Y3B5KGxyX2J1ZmZlciwgT1BBTFVJRFtPUEFMX0xPQ0tJTkdSQU5HRV9BQ0VfV1JMT0NLRURdLAor
CQkgICAgICAgT1BBTF9VSURfTEVOR1RIKTsKKworCWxyX2J1ZmZlcls3XSA9IGRldi0+bHI7CisK
KwltZW1jcHkodXNlcl91aWQsIE9QQUxVSURbT1BBTF9VU0VSMV9VSURdLCBPUEFMX1VJRF9MRU5H
VEgpOworCXVzZXJfdWlkWzddID0gbGt1bC0+YXV0aG9yaXR5LndobzsKKworCXJldCA9IHRlc3Rf
YW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgM2MgM2MgMmMgMnNjIGMyc2MgY3MyYyA1YyIsCisJ
CQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgbHJfYnVmZmVyLCBPUEFMX1VJRF9MRU5HVEgsCisJ
CQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRM
SVNULAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDEs
IC8qIFZhbHVlcyAqLworCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBPUEFMX1NU
QVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIEJvb2xlYW5FeHByICovCisK
KwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCisJCQkJ
ICAgIE9QQUxVSURbT1BBTF9IQUxGX1VJRF9BVVRIT1JJVFlfT0JKX1JFRl0sCisJCQkJICAgIE9Q
QUxfVUlEX0xFTkdUSF9IQUxGLAorCQkJCSAgICB1c2VyX3VpZCwgT1BBTF9VSURfTEVOR1RILAor
CQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAg
IE9QQUxVSURbT1BBTF9IQUxGX1VJRF9BVVRIT1JJVFlfT0JKX1JFRl0sCisJCQkJICAgIE9QQUxf
VUlEX0xFTkdUSF9IQUxGLAorCQkJCSAgICB1c2VyX3VpZCwgT1BBTF9VSURfTEVOR1RILAorCQkJ
CSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9Q
QUxVSURbT1BBTF9IQUxGX1VJRF9CT09MRUFOX0FDRV0sCisJCQkJICAgIE9QQUxfVUlEX0xFTkdU
SF9IQUxGLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMSwKKwkJCQkgICAgT1BBTF9FTkROQU1F
LAorCisJCQkJICAgIE9QQUxfRU5ETElTVCwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCQkJCSAg
ICBPUEFMX0VORExJU1QsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9FTkRM
SVNUKTsKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBhZGQg
dXNlciB0byBsb2NraW5nIHJhbmdlIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25h
bWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYs
IGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBsb2NrX3VubG9ja19sb2NraW5n
X3JhbmdlKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXU4IGxyX2J1ZmZlcltPUEFMX1VJRF9M
RU5HVEhdOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWNvbnN0IHU4ICptZXRob2Q7CisJc3Ry
dWN0IG9wYWxfbG9ja191bmxvY2sgKmxrdWw7CisJaW50IHJldDsKKwl1OCByZWFkX2xvY2tlZCA9
IDEsIHdyaXRlX2xvY2tlZCA9IDE7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9j
bWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsKKworCW1ldGhvZCA9IE9QQUxN
RVRIT0RbT1BBTF9TRVRdOworCWxrdWwgPSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0YXRlIC0gMV07
CisJaWYgKGJ1aWxkX2xvY2tpbmdfcmFuZ2UobHJfYnVmZmVyLCBzaXplb2YobHJfYnVmZmVyKSwg
ZGV2LT5scikgPCAwKSB7CisJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2Vc
biIsIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJc3dpdGNoIChs
a3VsLT5sX3N0YXRlKSB7CisJY2FzZSBPUEFMX1JPOgorCQlyZWFkX2xvY2tlZCA9IDA7CisJCXdy
aXRlX2xvY2tlZCA9IDE7CisJCWJyZWFrOworCWNhc2UgT1BBTF9SVzoKKwkJcmVhZF9sb2NrZWQg
PSAwOworCQl3cml0ZV9sb2NrZWQgPSAwOworCQlicmVhazsKKwljYXNlIE9QQUxfTEs6CisJCS8q
IHZhcnMgYXJlIGluaXRhbGl6ZWQgdG8gbG9ja2VkICovCisJCWJyZWFrOworCWRlZmF1bHQ6CisJ
CXByX2VycigiVHJpZWQgdG8gc2V0IGFuIGludmFsaWQgbG9ja2luZyBzdGF0ZS4uLiByZXR1cm5p
bmcgdG8gdWxhbmRcbiIpOworCQlyZXR1cm4gMTsKKwl9CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRf
dG9rZW5fdmEoY21kLCAiYzJzYyAzYyA0YyA0YyAzYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJ
CQkgICAgbHJfYnVmZmVyLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1ldGhvZCwgT1BBTF9N
RVRIT0RfTEVOR1RILAorCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKworCQkJCSAgICBPUEFMX1NU
QVJUTkFNRSwKKwkJCQkgICAgT1BBTF9WQUxVRVMsCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAor
CisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1JFQURMT0NLRUQsCisJCQkJ
ICAgIHJlYWRfbG9ja2VkLAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9T
VEFSVE5BTUUsCisJCQkJICAgIE9QQUxfV1JJVEVMT0NLRUQsCisJCQkJICAgIHdyaXRlX2xvY2tl
ZCwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfRU5ETElTVCwKKwkJCQkg
ICAgT1BBTF9FTkROQU1FLAorCQkJCSAgICBPUEFMX0VORExJU1QpOworCisJaWYgKHJldCA8IDAp
IHsKKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgU0VUIGNvbW1hbmQuXG4iLCBkZXYtPmRp
c2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChk
ZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworCitzdGF0aWMgaW50IGxvY2tfdW5sb2NrX2xv
Y2tpbmdfcmFuZ2VfU1VNKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXU4IGxyX2J1ZmZlcltP
UEFMX1VJRF9MRU5HVEhdOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWNvbnN0IHU4ICptZXRo
b2Q7CisJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrdWw7CisJaW50IHJldDsKKwl1OCByZWFk
X2xvY2tlZCA9IDEsIHdyaXRlX2xvY2tlZCA9IDE7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xl
YXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsKKworCW1ldGhv
ZCA9IE9QQUxNRVRIT0RbT1BBTF9TRVRdOworCWxrdWwgPSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0
YXRlIC0gMV07CisJaWYgKGJ1aWxkX2xvY2tpbmdfcmFuZ2UobHJfYnVmZmVyLCBzaXplb2YobHJf
YnVmZmVyKSwgZGV2LT5scikgPCAwKSB7CisJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tp
bmcgcmFuZ2VcbiIsIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJ
c3dpdGNoIChsa3VsLT5sX3N0YXRlKSB7CisJY2FzZSBPUEFMX1JPOgorCQlyZWFkX2xvY2tlZCA9
IDA7CisJCXdyaXRlX2xvY2tlZCA9IDE7CisJCWJyZWFrOworCWNhc2UgT1BBTF9SVzoKKwkJcmVh
ZF9sb2NrZWQgPSAwOworCQl3cml0ZV9sb2NrZWQgPSAwOworCQlicmVhazsKKwljYXNlIE9QQUxf
TEs6CisJCS8qIHZhcnMgYXJlIGluaXRhbGl6ZWQgdG8gbG9ja2VkICovCisJCWJyZWFrOworCWRl
ZmF1bHQ6CisJCXByX2VycigiVHJpZWQgdG8gc2V0IGFuIGludmFsaWQgbG9ja2luZyBzdGF0ZS5c
biIpOworCQlyZXR1cm4gMTsKKwl9CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21k
LCAiYzJzYyAzYyA0YyA0YyA0YyA0YyAzYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAg
bHJfYnVmZmVyLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0Rf
TEVOR1RILAorCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFN
RSwKKwkJCQkgICAgT1BBTF9WQUxVRVMsCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCisJCQkJ
ICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1JFQURMT0NLRU5BQkxFRCwKKwkJCQkg
ICAgT1BBTF9UUlVFLAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFS
VE5BTUUsCisJCQkJICAgIE9QQUxfV1JJVEVMT0NLRU5BQkxFRCwKKwkJCQkgICAgT1BBTF9UUlVF
LAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJ
ICAgIE9QQUxfUkVBRExPQ0tFRCwKKwkJCQkgICAgcmVhZF9sb2NrZWQsCisJCQkJICAgIE9QQUxf
RU5ETkFNRSwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9XUklURUxP
Q0tFRCwKKwkJCQkgICAgd3JpdGVfbG9ja2VkLAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJ
CQkgICAgT1BBTF9FTkRMSVNULAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxf
RU5ETElTVCk7CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcg
U0VUIGNvbW1hbmQuXG4iLCBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCXJl
dHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworaW50
IGFjdGl2YXRlX2xzcChzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwl1OCB1c2VyX2xyW09QQUxf
VUlEX0xFTkdUSF07CisJY29uc3QgdTggKm1ldGhvZCwgKnVpZDsKKwlzdHJ1Y3Qgb3BhbF9jbWQg
KmNtZDsKKwlpbnQgcmV0OworCXNpemVfdCB1aW50XzMgPSAweDgzOworCisJY21kID0gJmRldi0+
Y21kOworCisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlE
KTsKKworCXVpZCA9IE9QQUxVSURbT1BBTF9MT0NLSU5HU1BfVUlEXTsKKwltZXRob2QgPSBPUEFM
TUVUSE9EW09QQUxfQUNUSVZBVEVdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNt
ZCwgImMycyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJRF9MRU5H
VEgsCisJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RIKTsKKwlpZiAocmV0IDwgMCkg
eworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBBY3RpdmF0ZSBMb2NraW5nU1AgY29tbWFu
ZC5cbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCS8q
IEFjdGl2YXRpbmcgYXMgU1VNICovCisJaWYgKGRldi0+bHIgPiAwKSB7CisJCXJldCA9IGJ1aWxk
X2xvY2tpbmdfcmFuZ2UodXNlcl9sciwgc2l6ZW9mKHVzZXJfbHIpLCBkZXYtPmxyKTsKKwkJaWYg
KHJldCA8IDApIHsKKwkJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgdXNlclxuIiwK
KwkJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCQlyZXR1cm4gcmV0OworCQl9CisJCXRlc3Rf
YW5kX2FkZF90b2tlbl92YShjbWQsICIyYyA0YyBjc2MgMmMiLAorCQkJCSAgICAgIE9QQUxfU1RB
UlRMSVNULAorCQkJCSAgICAgIE9QQUxfU1RBUlROQU1FLAorCisJCQkJICAgICAgdWludF8zLAor
CQkJCSAgICAgIE9QQUxfVElOWV9VSU5UXzA2LAorCQkJCSAgICAgIE9QQUxfVElOWV9VSU5UXzAw
LAorCQkJCSAgICAgIE9QQUxfVElOWV9VSU5UXzAwLAorCisJCQkJICAgICAgT1BBTF9TVEFSVExJ
U1QsCisJCQkJICAgICAgdXNlcl9sciwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICAgIE9QQUxf
RU5ETElTVCwKKworCQkJCSAgICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgICBPUEFMX0VORExJ
U1QpOworCX0gZWxzZSAvKiBBY3RpYXZlIE5vcm1hbCBNb2RlICovCisJCXJldCA9IHRlc3RfYW5k
X2FkZF90b2tlbl92YShjbWQsICIyYyIsCisJCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkJ
ICAgIE9QQUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJv
ciBidWlsZGluZyBBY3RpdmF0ZSBMb2NraW5nU1AgY29tbWFuZC5cbiIsCisJCSAgICAgICBkZXYt
PmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIGZpbmFsaXplX2FuZF9z
ZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOworfQorCitzdGF0aWMgdm9pZCBnZXRfbHNwX2xp
ZmVjeWNsZV9jb250KGludCBlcnJvciwgdm9pZCAqZGF0YSkKK3sKKworCXN0cnVjdCBvcGFsX2Rl
diAqZGV2ID0gZGF0YTsKKwl1OCBsY19zdGF0dXM7CisKKwlpZiAoZXJyb3IpCisJCWdvdG8gZXJy
X3JldHVybjsKKworCWVycm9yID0gcGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhkZXYpOworCWlmIChl
cnJvcikKKwkJZ290byBlcnJfcmV0dXJuOworCisJbGNfc3RhdHVzID0gcmVzcG9uc2VfZ2V0X3U2
NCgmZGV2LT5wYXJzZWQsIDQpOworCS8qIDB4MDggaXMgTWFudWZhY3VyZWQgSW5hY3RpdmUgKi8K
KwkvKiAweDA5IGlzIE1hbnVmYWN0dXJlZCAqLworCWlmIChsY19zdGF0dXMgIT0gMHgwOCkgewor
CQlwcl9lcnIoIiVzOiBDb3VsZG4ndCBkZXRlcm1pbmUgdGhlIHN0YXR1cyBvZiB0aGUgTGlmY3lj
bGUgc3RhdGVcbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCWVycm9yID0gLUVOT0RF
VjsKKwl9CisKK2Vycl9yZXR1cm46CisJaWYgKGRldi0+b3Blcl9jYikKKwkJZGV2LT5vcGVyX2Ni
KGVycm9yLCBkZXYpOworfQorCisvKiBEZXRlcm1pbmUgaWYgd2UncmUgaW4gdGhlIE1hbnVmYWN0
dXJlZCBJbmFjdGl2ZSBvciBBY3RpdmUgc3RhdGUgKi8KK2ludCBnZXRfbHNwX2xpZmVjeWNsZShz
dHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwljb25zdCB1
OCAqbWV0aG9kLCAqdWlkOworCWludCByZXQ7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisKKwljbGVh
cl9vcGFsX2NtZChjbWQpOworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOworCisJdWlkID0g
T1BBTFVJRFtPUEFMX0xPQ0tJTkdTUF9VSURdOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9H
RVRdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAyYyA0YyA0YyAy
YyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJ
CQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRM
SVNULAorCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwK
KwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIFN0YXJ0IENvbHVtbiAqLworCQkJCSAgICBP
UEFMX1RJTllfVUlOVF8wNiwgLyogTGlmY3ljbGUgQ29sdW1uICovCisJCQkJICAgIE9QQUxfRU5E
TkFNRSwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRf
MDQsIC8qIEVuZCBDb2x1bW4gKi8KKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIExpZmVj
eWNsZSBDb2x1bW4gKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfRU5E
TElTVCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2Vy
cigiJXM6IEVycm9yIEJ1aWxkaW5nIEdFVCBMaWZlY3ljbGUgU3RhdHVzIGNvbW1hbmRcbiIsCisJ
CSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIGZp
bmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZXRfbHNwX2xpZmVjeWNsZV9jb250KTsKK30KKwor
c3RhdGljIHZvaWQgZ2V0X21zaWRfY3Bpbl9waW5fY29udChpbnQgZXJyb3IsIHZvaWQgKmRhdGEp
Cit7CisJY29uc3QgY2hhciAqbXNpZF9waW47CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRh
OworCXNpemVfdCBzdHJsZW47CisKKwlpZiAoZXJyb3IpCisJCWdvdG8gZXJyX3JldHVybjsKKwor
CWVycm9yID0gcGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhkZXYpOworCWlmIChlcnJvcikKKwkJZ290
byBlcnJfcmV0dXJuOworCisJc3RybGVuID0gcmVzcG9uc2VfZ2V0X3N0cmluZygmZGV2LT5wYXJz
ZWQsIDQsICZtc2lkX3Bpbik7CisJaWYgKCFtc2lkX3BpbikgeworCQlwcl9lcnIoIiVzOiBDb3Vs
ZG4ndCBleHRyYWN0IFBJTiBmcm9tIHJlc3BvbnNlXG4iLCBfX2Z1bmNfXyk7CisJCWVycm9yID0g
MTsKKwkJZ290byBlcnJfcmV0dXJuOworCX0KKworCWRldi0+cHJldl9kYXRhID0ga21lbWR1cCht
c2lkX3Bpbiwgc3RybGVuLCBHRlBfS0VSTkVMKTsKKwlpZiAoIWRldi0+cHJldl9kYXRhKQorCQll
cnJvciA9IC1FTk9NRU07CisKKwlkZXYtPnByZXZfZF9sZW4gPSBzdHJsZW47CisKKyBlcnJfcmV0
dXJuOgorCWlmIChkZXYtPm9wZXJfY2IpCisJCWRldi0+b3Blcl9jYihlcnJvciwgZGV2KTsKK30K
Kworc3RhdGljIGludCBnZXRfbXNpZF9jcGluX3BpbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sK
Kwljb25zdCB1OCAqbWV0aG9kLCAqc211aWQ7CisJaW50IHJldDsKKwlzdHJ1Y3Qgb3BhbF9jbWQg
KmNtZDsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9j
b21JRChjbWQsIGRldi0+Y29tSUQpOworCisJc211aWQgPSBPUEFMVUlEW09QQUxfQ19QSU5fTVNJ
RF07CisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX0dFVF07CisKKwlyZXQgPSB0ZXN0X2FuZF9h
ZGRfdG9rZW5fdmEoY21kLCAiYyAycyAxMmMiLAorCQkJCSAgICBPUEFMX0NBTEwsCisKKwkJCQkg
ICAgc211aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9M
RU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlRMSVNU
LAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8q
IFNhcnQgQ29sdW1uICovCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLCAvKiBQSU4gKi8KKwkJ
CQkgICAgT1BBTF9FTkROQU1FLAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BB
TF9USU5ZX1VJTlRfMDQsIC8qIEVuZCBDb2x1bW4gKi8KKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRf
MDMsIC8qIFBJTiAqLworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElT
VCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2Vycigi
JXM6IEVycm9yIGJ1aWxkaW5nIEdldCBNU0lEIENQSU4gUElOIGNvbW1hbmQuXG4iLAorCQkgICAg
ICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6
ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2V0X21zaWRfY3Bpbl9waW5fY29udCk7Cit9CisKK3N0YXRp
YyB2b2lkIHVubG9ja19zdXNwZW5kX2ZpbmFsKGludCBlcnJvciwgdm9pZCAqZGF0YSkKK3sKKwlz
dHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisKKwlkZXYtPnJlc3VtZV9mcm9tX3N1c3BlbmQg
PSBmYWxzZTsKKwlkZXYtPnJlc3VtZV9kYXRhID0gTlVMTDsKKwlkZXYtPmZ1bmNfZGF0YSA9IE5V
TEw7CisJZGV2LT5iZGV2ID0gTlVMTDsKK30KKworc3RhdGljIGludCBidWlsZF9lbmRfb3BhbF9z
ZXNzaW9uKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXN0cnVjdCBvcGFsX2NtZCAqY21kOwor
CisJY21kID0gJmRldi0+Y21kOworCWNsZWFyX29wYWxfY21kKGNtZCk7CisKKwlzZXRfY29tSUQo
Y21kLCBkZXYtPmNvbUlEKTsKKwlyZXR1cm4gdGVzdF9hbmRfYWRkX3Rva2VuX3U4KGNtZCwgT1BB
TF9FTkRPRlNFU1NJT04pOworfQorCitzdGF0aWMgaW50IGVuZF9vcGFsX3Nlc3Npb24oc3RydWN0
IG9wYWxfZGV2ICpkZXYpCit7CisJaWYgKGJ1aWxkX2VuZF9vcGFsX3Nlc3Npb24oZGV2KSA8IDAp
CisJCXJldHVybiAtMTsKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCAmZGV2LT5jbWQs
IGVuZF9zZXNzaW9uX2NvbnQpOworfQorCitzdGF0aWMgc3RydWN0IG9wYWxfZGV2ICpmaW5kX29w
YWxfZGV2KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHU4IGxyKQoreworCXN0cnVjdCBvcGFs
X2RldiAqaXRlciwgKm9wYWxfZGV2ID0gTlVMTDsKKworCWxpc3RfZm9yX2VhY2hfZW50cnkoaXRl
ciwgJm9wYWxfbGlzdCwgbm9kZSkgeworCQlpZiAoc3RybmNtcChpdGVyLT5kaXNrX25hbWUsIGJk
ZXYtPmJkX2Rpc2stPmRpc2tfbmFtZSwKKwkJCSAgICBESVNLX05BTUVfTEVOKSkKKwkJCWNvbnRp
bnVlOworCQlpZiAoaXRlci0+bHIgPT0gbHIpIHsKKwkJCW9wYWxfZGV2ID0gaXRlcjsKKwkJCWJy
ZWFrOworCQl9CisJfQorCisJcmV0dXJuIG9wYWxfZGV2OworfQorCitzdGF0aWMgaW50IHVwZGF0
ZV9vcGFsX2RldihzdHJ1Y3Qgb3BhbF9kZXYgKm9sZF9kZXYsIHN0cnVjdCBvcGFsX2RldiAqbmV3
X2RldikKK3sKKwlpZiAoIWF0b21pY19hZGRfdW5sZXNzKCZvbGRfZGV2LT5pbl91c2UsIDEsIDEp
KSB7CisJCXByX2VycigiJXM6IGRldiB3YXMgaW4gdXNlXG4iLCBfX2Z1bmNfXyk7CisJCXJldHVy
biAtRUJVU1k7CisJfQorCisJb2xkX2Rldi0+a2V5X25hbWVfbGVuID0gbmV3X2Rldi0+a2V5X25h
bWVfbGVuOworCWlmICghbWVtY3B5KG9sZF9kZXYtPmtleV9uYW1lLCBuZXdfZGV2LT5rZXlfbmFt
ZSwgb2xkX2Rldi0+a2V5X25hbWVfbGVuKSkgeworCQlwcl9lcnIoIiVzOiBFcnJvciB1cGRhdGlu
ZyBkZXZpY2U6XG4iLCBvbGRfZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gLUVGQVVMVDsKKwl9
CisKKwlpZiAoIXN0cm5jcHkob2xkX2Rldi0+ZGlza19uYW1lLCBuZXdfZGV2LT5kaXNrX25hbWUs
IERJU0tfTkFNRV9MRU4pKSB7CisJCXByX2VycigiJXM6IEVycm9yIHJlZ2lzdGVyaW5nIGRldmlj
ZTogY29weWluZyBkaXNrIG5hbWVcbiIsCisJCSAgICAgICBvbGRfZGV2LT5kaXNrX25hbWUpOwor
CQlyZXR1cm4gLUVGQVVMVDsKKwl9CisKKwlvbGRfZGV2LT5jb21JRCA9IG5ld19kZXYtPmNvbUlE
OworCW9sZF9kZXYtPnN0YXJ0ID0gbmV3X2Rldi0+c3RhcnQ7CisJb2xkX2Rldi0+bGVuZ3RoID0g
bmV3X2Rldi0+bGVuZ3RoOworCW9sZF9kZXYtPmFsaWduID0gbmV3X2Rldi0+YWxpZ247CisJb2xk
X2Rldi0+bG93ZXN0X2xiYSA9IG5ld19kZXYtPmxvd2VzdF9sYmE7CisJb2xkX2Rldi0+YmRldiA9
IE5VTEw7CisJb2xkX2Rldi0+ZmluYWxfY2IgPSBuZXdfZGV2LT5maW5hbF9jYjsKKwlvbGRfZGV2
LT5maW5hbF9jYl9kYXRhID0gbmV3X2Rldi0+ZmluYWxfY2JfZGF0YTsKKwlvbGRfZGV2LT5vcGVy
X2NiID0gbmV3X2Rldi0+b3Blcl9jYjsKKwlvbGRfZGV2LT5zdGF0ZSA9IG5ld19kZXYtPnN0YXRl
OworCW9sZF9kZXYtPmZ1bmNzID0gbmV3X2Rldi0+ZnVuY3M7CisKKwlrZnJlZShvbGRfZGV2LT5j
b21wbGV0aW9uKTsKKwljbGVhbl9mdW5jdGlvbl9kYXRhKG9sZF9kZXYpOworCisJb2xkX2Rldi0+
Y29tcGxldGlvbiA9IG5ld19kZXYtPmNvbXBsZXRpb247CisKKwkvKgorCSAqIFdvbid0IGJlIGFi
bGUgdG8gYXV0byB1bmxvY2sgdGhpcyBsb2NraW5nIHJhbmdlIGJhc2VkIG9uIGJsb2NrCisJICog
cmVxdWVzdGVzLgorCSAqLworCWlmIChvbGRfZGV2LT5sZW5ndGggPT0gMCkKKwkJcHJfd2Fybigi
JXM6IE1pc3NpbmcgYmxvY2sgaW5mb3JtYXRpb24gZm9yIGxvY2tpbmcgcmFuZ2UgJWRcbiIsCisJ
CQlvbGRfZGV2LT5kaXNrX25hbWUsIG9sZF9kZXYtPmxyKTsKKworCXJldHVybiAwOworfQorCitp
bnQgb3BhbF9yZWdpc3Rlcl9jb250KHN0cnVjdCBvcGFsX2RldiAqbmV3X2RldikKK3sKKwlzdHJ1
Y3Qgb3BhbF9kZXYgKm9sZF9kZXY7CisJdW5zaWduZWQgbG9uZyBmbGFnczsKKwlpbnQgZXJyb3Ig
PSAwOworCisJc3Bpbl9sb2NrX2lycXNhdmUoJmxpc3Rfc3BpbmxvY2ssIGZsYWdzKTsKKworCW9s
ZF9kZXYgPSBmaW5kX29wYWxfZGV2KG5ld19kZXYtPmJkZXYsIG5ld19kZXYtPmxyKTsKKwlpZiAo
IW9sZF9kZXYpIHsKKwkJbGlzdF9hZGRfdGFpbCgmbmV3X2Rldi0+bm9kZSwgJm9wYWxfbGlzdCk7
CisJCW9sZF9kZXYgPSBuZXdfZGV2OworCX0gZWxzZSB7CisJCWlmIChvbGRfZGV2ID09IG5ld19k
ZXYpCisJCQllcnJvciA9IDA7CisJCWVsc2UgeworCQkJZXJyb3IgPSB1cGRhdGVfb3BhbF9kZXYo
b2xkX2RldiwgbmV3X2Rldik7CisJCQljbGVhbl9vcGFsX2tleShuZXdfZGV2KTsKKwkJCWtmcmVl
KG5ld19kZXYpOworCQl9CisJfQorCisJaWYgKGVycm9yKQorCQlsaXN0X2RlbCgmb2xkX2Rldi0+
bm9kZSk7CisKKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZsaXN0X3NwaW5sb2NrLCBmbGFncyk7
CisKKwlpZiAoIWVycm9yKQorCQlwcl9pbmZvKCIlczogUmVnaXN0ZXJlZCBrZXkgZm9yIGxvY2tp
bmcgcmFuZ2U6ICVkXG4iLAorCQkJb2xkX2Rldi0+ZGlza19uYW1lLCBvbGRfZGV2LT5scik7CisK
KwlpZiAob2xkX2Rldi0+b3Blcl9jYikKKwkJb2xkX2Rldi0+b3Blcl9jYihlcnJvciwgb2xkX2Rl
dik7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHZvaWQgbmV4dChpbnQgZXJyb3IsIHN0cnVj
dCBvcGFsX2RldiAqZGV2KQoreworCW9wYWxfc3RlcCBmdW5jID0gZGV2LT5mdW5jc1tkZXYtPnN0
YXRlXTsKKwl2b2lkICpjYl9kYXRhID0gZGV2LT5maW5hbF9jYl9kYXRhOworCXNlY19jYiAqY2Ig
PSBkZXYtPmZpbmFsX2NiOworCWJvb2wgZG9uZSA9IGZhbHNlOworCisKKwlpZiAoZXJyb3IgfHwg
IWZ1bmMpIHsKKwkJZG9uZSA9IHRydWU7CisJCWdvdG8gbmV4dF9leGl0OworCX0KKwlkZXYtPnN0
YXRlKys7CisJZGV2LT5vcGVyX2NiID0gbmV4dDsKKwllcnJvciA9IGZ1bmMoZGV2KTsKKyBuZXh0
X2V4aXQ6CisJaWYgKGVycm9yKSB7CisJCXByX2VycigiJXM6IEVycm9yIG9uIHN0ZXAgZnVuY3Rp
b246ICVkIHdpdGggZXJyb3IgJWQ6ICVzXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUsIGRl
di0+c3RhdGUsIGVycm9yLAorCQkgICAgICAgb3BhbF9lcnJvcl90b19odW1hbihlcnJvcikpOwor
CisKKwkJYXRvbWljX2RlYygmZGV2LT5pbl91c2UpOworCQlpZiAoZGV2LT5lcnJvcl9jYikgewor
CQkJZGV2LT5lcnJvcl9jYihkZXYtPmVycm9yX2NiX2RhdGEpOworCQkJcmV0dXJuOworCQl9CisJ
CWlmIChjYikKKwkJCWNiKGVycm9yLCBjYl9kYXRhKTsKKworCQlkZXYtPmNvbXBsZXRpb24tPmNv
bXBsZXRpb25fc3RhdHVzID0gZXJyb3I7CisJCWNvbXBsZXRlKCZkZXYtPmNvbXBsZXRpb24tPmNt
ZF9jb21wbGV0aW9uKTsKKwl9IGVsc2UgaWYgKCFlcnJvciAmJiBkb25lKSB7CisJCWF0b21pY19k
ZWMoJmRldi0+aW5fdXNlKTsKKwkJaWYgKGNiKQorCQkJY2IoZXJyb3IsIGNiX2RhdGEpOworCQlk
ZXYtPmNvbXBsZXRpb24tPmNvbXBsZXRpb25fc3RhdHVzID0gZXJyb3I7CisJCWNvbXBsZXRlKCZk
ZXYtPmNvbXBsZXRpb24tPmNtZF9jb21wbGV0aW9uKTsKKwl9Cit9CisKK2NvbnN0IG9wYWxfc3Rl
cCBlcnJvcl9lbmRfc2Vzc2lvbltdID0geworCWVuZF9vcGFsX3Nlc3Npb24sCisJTlVMTCwKK307
CitzdGF0aWMgaW50IGVuZF9vcGFsX3Nlc3Npb25fZXJyb3Ioc3RydWN0IG9wYWxfZGV2ICpkZXYp
Cit7CisKKwlkZXYtPmZ1bmNzID0gZXJyb3JfZW5kX3Nlc3Npb247CisJZGV2LT5zdGF0ZSA9IDA7
CisJZGV2LT5lcnJvcl9jYiA9IE5VTEw7CisJbmV4dCgwLCBkZXYpOworCXJldHVybiAwOworfQor
CitzdGF0aWMgc3RydWN0IG9wYWxfZGV2ICphbGxvY19vcGFsX2RldihzdHJ1Y3QgYmxvY2tfZGV2
aWNlICpiZGV2LCB1OCBscikKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKm9wYWxfZGV2OworCXN0cnVj
dCByZXF1ZXN0X3F1ZXVlICpxOworCXVuc2lnbmVkIGxvbmcgZG1hX2FsaWduOworCWNvbnN0IGNo
YXIgKmRpc2tfbmFtZTsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlpbnQgcmV0OworCisJb3Bh
bF9kZXYgPSBremFsbG9jKHNpemVvZigqb3BhbF9kZXYpLCBHRlBfS0VSTkVMKTsKKwlpZiAoIW9w
YWxfZGV2KQorCQlyZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsKKworCW9wYWxfZGV2LT5iZGV2ID0g
YmRldjsKKwlvcGFsX2Rldi0+bHIgPSBscjsKKwljbWQgPSAmb3BhbF9kZXYtPmNtZDsKKwljbWQt
PmNtZCA9IGNtZC0+Y21kX2J1ZjsKKwljbWQtPnJlc3AgPSBjbWQtPnJlc3BfYnVmOworCisJZGlz
a19uYW1lID0gYmRldi0+YmRfZGlzay0+ZGlza19uYW1lOworCWlmICghc3RybmNweShvcGFsX2Rl
di0+ZGlza19uYW1lLCBkaXNrX25hbWUsIERJU0tfTkFNRV9MRU4pKSB7CisJCXByX2VycigiJXM6
IEVycm9yIHJlZ2lzdGVyaW5nIGRldmljZTogY29weWluZyBkaXNrIG5hbWVcbiIsCisJCSAgICAg
ICBkaXNrX25hbWUpOworCQlyZXQgPSAtRUZBVUxUOworCQlnb3RvIGVycl9mcmVlX2RldjsKKwl9
CisKKwlxID0gYmRldi0+YmRfcXVldWU7CisJZG1hX2FsaWduID0gKHF1ZXVlX2RtYV9hbGlnbm1l
bnQocSkgfCBxLT5kbWFfcGFkX21hc2spICsgMTsKKwljbWQtPmNtZCA9ICh1OCAqKXJvdW5kX3Vw
KCh1aW50cHRyX3QpY21kLT5jbWQsIGRtYV9hbGlnbik7CisJY21kLT5yZXNwID0gKHU4ICopcm91
bmRfdXAoKHVpbnRwdHJfdCljbWQtPnJlc3AsIGRtYV9hbGlnbik7CisKKwlJTklUX0xJU1RfSEVB
RCgmb3BhbF9kZXYtPm5vZGUpOworCWF0b21pY19zZXQoJm9wYWxfZGV2LT5pbl91c2UsIDEpOwor
CisJb3BhbF9kZXYtPmNvbXBsZXRpb24gPSBremFsbG9jKHNpemVvZigqb3BhbF9kZXYtPmNvbXBs
ZXRpb24pLAorCQkJCSAgICAgICBHRlBfS0VSTkVMKTsKKworCWlmICghb3BhbF9kZXYtPmNvbXBs
ZXRpb24pCisJCWdvdG8gZXJyX2ZyZWVfZGV2OworCisJaW5pdF9jb21wbGV0aW9uKCZvcGFsX2Rl
di0+Y29tcGxldGlvbi0+Y21kX2NvbXBsZXRpb24pOworCW9wYWxfZGV2LT5jb21wbGV0aW9uLT5j
b21wbGV0aW9uX3N0YXR1cyA9IDA7CisJb3BhbF9kZXYtPnN0YXRlID0gMDsKKworCXJldHVybiBv
cGFsX2RldjsKKworZXJyX2ZyZWVfZGV2OgorCWtmcmVlKG9wYWxfZGV2KTsKKwlyZXR1cm4gRVJS
X1BUUihyZXQpOworfQorCitpbnQgb3BhbF9yZWdpc3RlcihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpi
ZGV2LCBzdHJ1Y3Qgb3BhbF9rZXkgKmtleV9jbWQsCisJCSAgY29uc3Qgb3BhbF9zdGVwICpmdW5j
cykKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKm5ld19kZXYgPSBOVUxMOworCXU4IGtleV9sZW4gPSBr
ZXlfY21kLT5rZXlfbGVuOworCXU4IGxyID0ga2V5X2NtZC0+bHI7CisJc3RydWN0IG9wYWxfY29t
cGxldGlvbiAqY29tcGxldGlvbjsKKwlpbnQgcmV0OworCisJbmV3X2RldiA9IGFsbG9jX29wYWxf
ZGV2KGJkZXYsIGxyKTsKKwlpZiAoSVNfRVJSKG5ld19kZXYpKSB7CisJCXByX2VycigiJXM6IEVy
cm9yIHJlZ2lzdGVyaW5nIGRldmljZTogYWxsb2NhdGlvblxuIiwKKwkJICAgICAgIGJkZXYtPmJk
X2Rpc2stPmRpc2tfbmFtZSk7CisJCXJldHVybiBQVFJfRVJSKG5ld19kZXYpOworCX0KKworCWlm
ICghbWVtY3B5KG5ld19kZXYtPmtleV9uYW1lLCBrZXlfY21kLT5rZXksIGtleV9sZW4pKSB7CisJ
CXByX2VycigiJXM6IEVycm9yIHJlZ2lzdGVyaW5nIGtleTogY291bGRuJ3QgY29weSBrZXlcbiIs
CisJCSAgICAgICBuZXdfZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gLUVGQVVMVDsKKwl9CisK
KwluZXdfZGV2LT5rZXlfbmFtZV9sZW4gPSBrZXlfbGVuOworCW5ld19kZXYtPmtleV90eXBlID0g
a2V5X2NtZC0+a2V5X3R5cGU7CisJcmV0ID0gZ2V0X29wYWxfa2V5KG5ld19kZXYpOworCWlmIChy
ZXQpIHsKKwkJcHJfZXJyKCIlczogQ291bGRuJ3QgZ2V0IGtleTogJWRcbiIsIG5ld19kZXYtPmRp
c2tfbmFtZSwgcmV0KTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwluZXdfZGV2LT5mdW5jcyA9IGZ1
bmNzOworCisJbmV3X2Rldi0+c3RhdGUgPSAwOworCWNvbXBsZXRpb24gPSBuZXdfZGV2LT5jb21w
bGV0aW9uOworCW5leHQoMCwgbmV3X2Rldik7CisKKwlyZXR1cm4gd2FpdF9mb3JfY21kX2NvbXBs
ZXRpb24oY29tcGxldGlvbik7Cit9CisKK3N0YXRpYyBzdHJ1Y3Qgb3BhbF9kZXYgKmdldF9yZWdp
c3RlcmVkX29wYWxfZGV2KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJCQkJCQl1OCBscikK
K3sKKwljb25zdCBjaGFyICpkaXNrbmFtZSA9IGJkZXYtPmJkX2Rpc2stPmRpc2tfbmFtZTsKKwlz
dHJ1Y3Qgb3BhbF9kZXYgKml0ZXIsICpkZXYgPSBOVUxMOworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7
CisJYm9vbCBpbl91c2UgPSBmYWxzZTsKKworCXNwaW5fbG9ja19pcnFzYXZlKCZsaXN0X3NwaW5s
b2NrLCBmbGFncyk7CisJbGlzdF9mb3JfZWFjaF9lbnRyeShpdGVyLCAmb3BhbF9saXN0LCBub2Rl
KSB7CisJCWlmIChzdHJuY21wKGl0ZXItPmRpc2tfbmFtZSwgZGlza25hbWUsIERJU0tfTkFNRV9M
RU4pKQorCQkJY29udGludWU7CisJCWlmIChpdGVyLT5sciA9PSBscikgeworCQkJZGV2ID0gaXRl
cjsKKwkJCWlmICghYXRvbWljX2FkZF91bmxlc3MoJml0ZXItPmluX3VzZSwgMSwgMSkpIHsKKwkJ
CQlkZXYgPSBOVUxMOworCQkJCWluX3VzZSA9IHRydWU7CisJCQl9CisJCQlicmVhazsKKwkJfQor
CX0KKworCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJmxpc3Rfc3BpbmxvY2ssIGZsYWdzKTsKKwor
CWlmICghZGV2KQorCQlyZXR1cm4gTlVMTDsKKworCWRldi0+YmRldiA9IGJkZXY7CisJcmV0dXJu
IGRldjsKK30KKworLyogRnJlZSB1cCB0aGUgT3BhbCBkZXYgYW5kIGl0cyBrZXlzIGR1cmluZyB0
d28gc2NlbmFyaW9zOgorICoKKyAqIDEpIFdoZW4gYSBjb21tYW5kIGlzIGNvbXBsZXRlIHRoYXQg
bm8gbG9uZ2VyIHJlcXVpcmVzCisgKiAgICB0aGUgb3BhbCBkZXYgdG8gYmUgYXJvdW5kLgorICog
MikgV2hlbiBhIGNvbW1hbmQsIGluY2x1ZGluZyBPcGFsIFNhdmUgZmFpbHMgd2UgY2xlYW4KKyAq
ICAgIGFuZCBmcmVlIHRoZSBvcGFsIGRldi4KKyAqCisgKiAgICBJZiB3ZSBmaW5kIHRoZSBvcGFs
IGRldiBzdHJ1Y3R1cmUgaW4gdGhlIGxpc3Qgb2YKKyAqICAgIHNhdmVkIHBhc3N3b3JkcyB3ZSB3
aWxsICpub3QqIHJlbW92ZSBpdC4KKyAqLworc3RhdGljIHZvaWQgcmVtb3ZlX2FuZF9jbGVhbl9v
cGFsX2RldihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKml0ZXI7
CisJYm9vbCBmb3VuZCA9IGZhbHNlOworCisJc3Bpbl9sb2NrKCZsaXN0X3NwaW5sb2NrKTsKKwls
aXN0X2Zvcl9lYWNoX2VudHJ5KGl0ZXIsICZvcGFsX2xpc3QsIG5vZGUpIHsKKwkJaWYgKGl0ZXIg
PT0gZGV2KSB7CisJCQlmb3VuZCA9IHRydWU7CisJCQlicmVhazsKKwkJfQorCX0KKworCXNwaW5f
dW5sb2NrKCZsaXN0X3NwaW5sb2NrKTsKKwlpZiAoIWZvdW5kKSB7CisJCWNsZWFuX29wYWxfa2V5
KGRldik7CisJCWNsZWFuX2Z1bmN0aW9uX2RhdGEoZGV2KTsKKwkJa2ZyZWUoZGV2KTsKKwl9Cit9
CisKK3N0YXRpYyBzdHJ1Y3Qgb3BhbF9kZXYgKmdldF9vcl9jcmVhdGVfb3BhbF9kZXYoc3RydWN0
IGJsb2NrX2RldmljZSAqYmRldiwKKwkJCQkJICAgICAgIHU4IGxyLCBib29sIHVzZV9uZXcpCit7
CisJc3RydWN0IG9wYWxfZGV2ICpkZXY7CisKKwlpZiAodXNlX25ldykKKwkJcmV0dXJuIGFsbG9j
X29wYWxfZGV2KGJkZXYsIGxyKTsKKworCWRldiA9IGdldF9yZWdpc3RlcmVkX29wYWxfZGV2KGJk
ZXYsIGxyKTsKKwlpZiAoIWRldikgeworCQlkZXYgPSBhbGxvY19vcGFsX2RldihiZGV2LCBscik7
CisJCWlmICghZGV2KQorCQkJcmV0dXJuIE5VTEw7CisJfQorCXJldHVybiBkZXY7Cit9CisKK3N0
YXRpYyBzdHJ1Y3Qgb3BhbF9jb21wbGV0aW9uICpzZXR1cF9vcGFsX2RldihzdHJ1Y3QgYmxvY2tf
ZGV2aWNlICpiZGV2LAorCQkJCQkgICAgICBzdHJ1Y3Qgb3BhbF9kZXYgKmRldiwKKwkJCQkJICAg
ICAgY29uc3Qgb3BhbF9zdGVwICpmdW5jcywKKwkJCQkJICAgICAgc3RydWN0IG9wYWxfa2V5ICpr
ZXkpCit7CisJaW50IHJldDsKKworCWRldi0+YmRldiA9IGJkZXY7CisJZGV2LT5zdGF0ZSA9IDA7
CisJZGV2LT5mdW5jcyA9IGZ1bmNzOworCWRldi0+VFNOID0gMDsKKwlkZXYtPkhTTiA9IDA7CisJ
ZGV2LT5maW5hbF9jYiA9IE5VTEw7CisJZGV2LT5maW5hbF9jYl9kYXRhID0gTlVMTDsKKwlkZXYt
PmxyID0ga2V5LT5scjsKKwlkZXYtPmVycm9yX2NiID0gZW5kX29wYWxfc2Vzc2lvbl9lcnJvcjsK
KwlkZXYtPmVycm9yX2NiX2RhdGEgPSBkZXY7CisKKwlpZiAoa2V5KSB7CisJCW1lbWNweShkZXYt
PmtleV9uYW1lLCBrZXktPmtleSwga2V5LT5rZXlfbGVuKTsKKwkJZGV2LT5rZXlfbmFtZV9sZW4g
PSBrZXktPmtleV9sZW47CisJCWRldi0+a2V5X3R5cGUgPSBrZXktPmtleV90eXBlOworCisJCXJl
dCA9IGdldF9vcGFsX2tleShkZXYpOworCQlpZiAocmV0KSB7CisJCQlrZnJlZShkZXYtPmNvbXBs
ZXRpb24pOworCQkJcHJfZXJyKCIlczogQ291bGRuJ3QgZ2V0IGtleTogJWRcbiIsCisJCQkgICAg
ICAgZGV2LT5kaXNrX25hbWUsIHJldCk7CisJCQlyZXR1cm4gRVJSX1BUUihyZXQpOworCQl9CisJ
fQorCWRldi0+ZnVuY19kYXRhID0gTlVMTDsKKwlkZXYtPmNvbXBsZXRpb24tPmNvbXBsZXRpb25f
c3RhdHVzID0gMDsKKworCXJldHVybiBkZXYtPmNvbXBsZXRpb247Cit9CisKK3N0YXRpYyBpbnQg
aW50ZXJuYWxfc2V0dXBfbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKKwkJCSAgICAgc3Ry
dWN0IG9wYWxfdXNlcl9scl9zZXR1cCAqc2V0dXApCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXY7
CisJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKKwl2b2lkICpkYXRhWzNdID0g
eyBOVUxMIH07CisJY29uc3Qgb3BhbF9zdGVwIGxyX2Z1bmNzW10gPSB7CisJCW9wYWxfZGlzY292
ZXJ5MCwKKwkJc3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCisJCXNldHVwX2xvY2tpbmdfcmFuZ2Us
CisJCWdldF9hY3RpdmVfa2V5LAorCQlnZW5fa2V5LAorCQllbmRfb3BhbF9zZXNzaW9uLAorCQlO
VUxMLAorCX07CisJaW50IHJldDsKKworCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRl
diwgc2V0dXAtPmtleS5sciwgdHJ1ZSk7CisJaWYgKCFkZXYpCisJCXJldHVybiAtRU5PTUVNOwor
CisJY29tcGxldGlvbiA9IHNldHVwX29wYWxfZGV2KGJkZXYsIGRldiwgbHJfZnVuY3MsICZzZXR1
cC0+a2V5KTsKKwlpZiAoSVNfRVJSKGNvbXBsZXRpb24pKSB7CisJCXJldCA9IFBUUl9FUlIoY29t
cGxldGlvbik7CisJCWdvdG8gZXJyb3JfcmV0dXJuOworCX0KKworCWRldi0+ZnVuY19kYXRhID0g
ZGF0YTsKKwlkZXYtPm51bV9mdW5jX2RhdGEgPSAzOworCWRldi0+ZnVuY19kYXRhWzFdID0gJnNl
dHVwLT53aG87CisJZGV2LT5mdW5jX2RhdGFbMl0gPSBzZXR1cDsKKworCW5leHQoMCwgZGV2KTsK
KwlyZXQgPSB3YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9uKTsKKworIGVycm9yX3Jl
dHVybjoKKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRldik7CisJcmV0dXJuIHJldDsKK30K
KworaW50IG9wYWxfcmV2ZXJ0KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBvcGFs
X2tleSAqa2V5KQoreworCWNvbnN0IG9wYWxfc3RlcCByZXZlcnRfZnVuY3NbXSA9IHsKKwkJb3Bh
bF9kaXNjb3ZlcnkwLAorCQlzdGFydF9TSURBU1Bfb3BhbF9zZXNzaW9uLAorCQlyZXZlcnRfdHBl
ciwgLyogY29udHJvbGxlciB3aWxsIHRlcm1pbmF0ZSBzZXNzaW9uICovCisJCU5VTEwsCisJfTsK
KworCXJldHVybiBvcGFsX3JlZ2lzdGVyKGJkZXYsIGtleSwgcmV2ZXJ0X2Z1bmNzKTsKK30KKwor
aW50IGFjdGl2YXRlX3VzZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IG9wYWxf
YWN0aXZhdGVfdXNlciAqYWN0KQoreworCWNvbnN0IG9wYWxfc3RlcCBhY3RfZnVuY3NbXSA9IHsK
KwkJb3BhbF9kaXNjb3ZlcnkwLAorCQlzdGFydF9hZG1pbjFMU1Bfb3BhbF9zZXNzaW9uLAorCQlp
bnRlcm5hbF9hY3RpdmF0ZV91c2VyLAorCQllbmRfb3BhbF9zZXNzaW9uLAorCQlOVUxMCisJfTsK
KwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKKwlzdHJ1Y3Qgb3BhbF9jb21wbGV0aW9uICpjb21wbGV0
aW9uOworCXZvaWQgKmRhdGFbM10gPSB7IE5VTEwgfTsKKwlpbnQgcmV0OworCisJZGV2ID0gZ2V0
X29yX2NyZWF0ZV9vcGFsX2RldihiZGV2LCBhY3QtPmtleS5sciwgdHJ1ZSk7CisJaWYgKCFkZXYp
CisJCXJldHVybiAtRU5PTUVNOworCisJY29tcGxldGlvbiA9IHNldHVwX29wYWxfZGV2KGJkZXYs
IGRldiwgYWN0X2Z1bmNzLCAmYWN0LT5rZXkpOworCWlmIChJU19FUlIoY29tcGxldGlvbikpIHsK
KwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKKwkJZ290byBlcnJvcl9yZXR1cm47CisJfQor
CisJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKKwlkZXYtPmZ1bmNfZGF0YSA9IGRhdGE7CisJZGV2
LT5mdW5jX2RhdGFbMV0gPSBhY3Q7CisJZGV2LT5mdW5jX2RhdGFbMl0gPSBhY3Q7CisKKwluZXh0
KDAsIGRldik7CisJcmV0ID0gd2FpdF9mb3JfY21kX2NvbXBsZXRpb24oY29tcGxldGlvbik7CisK
KyBlcnJvcl9yZXR1cm46CisJcmVtb3ZlX2FuZF9jbGVhbl9vcGFsX2RldihkZXYpOworCXJldHVy
biByZXQ7Cit9CisKK2ludCBvcGFsX3NldF9wdyhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBz
dHJ1Y3Qgb3BhbF9uZXdfcHcgKnB3KQorCit7CisJY29uc3Qgb3BhbF9zdGVwIHB3X2Z1bmNzW10g
PSB7CisJCW9wYWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCisJCXNl
dF9uZXdfcHcsCisJCWVuZF9vcGFsX3Nlc3Npb24sCisJCU5VTEwKKwl9OworCXN0cnVjdCBvcGFs
X2RldiAqZGV2OworCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247CisJdm9pZCAq
ZGF0YVszXSA9IHsgTlVMTCB9OworCWludCByZXQ7CisKKwlkZXYgPSBnZXRfb3JfY3JlYXRlX29w
YWxfZGV2KGJkZXYsIHB3LT5jdXJyZW50X3Bpbi5sciwgdHJ1ZSk7CisJaWYgKCFkZXYpCisJCXJl
dHVybiAtRU5PTUVNOworCisJY29tcGxldGlvbiA9IHNldHVwX29wYWxfZGV2KGJkZXYsIGRldiwg
cHdfZnVuY3MsICZwdy0+Y3VycmVudF9waW4pOworCWlmIChJU19FUlIoY29tcGxldGlvbikpIHsK
KwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKKwkJZ290byBlcnJvcl9yZXR1cm47CisJfQor
CisJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKKwlkZXYtPmZ1bmNfZGF0YSA9IGRhdGE7CisJZGV2
LT5mdW5jX2RhdGFbMV0gPSAodm9pZCAqKSAmcHctPndobzsKKwlkZXYtPmZ1bmNfZGF0YVsyXSA9
ICh2b2lkICopIHB3OworCisJbmV4dCgwLCBkZXYpOworCXJldCA9IHdhaXRfZm9yX2NtZF9jb21w
bGV0aW9uKGNvbXBsZXRpb24pOworCisgZXJyb3JfcmV0dXJuOgorCXJlbW92ZV9hbmRfY2xlYW5f
b3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0OworfQorCitpbnQgb3BhbF9hY3RfbHNwX2ludChz
dHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgb3BhbF9rZXkgKmtleSwKKwkJICAgICBj
b25zdCBvcGFsX3N0ZXAgKmZ1bmNzKQoreworCXN0cnVjdCBvcGFsX2RldiAqZGV2OworCXN0cnVj
dCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247CisJaW50IHJldDsKKworCWRldiA9IGdldF9v
cl9jcmVhdGVfb3BhbF9kZXYoYmRldiwga2V5LT5sciwgdHJ1ZSk7CisJaWYgKCFkZXYpCisJCXJl
dHVybiAtRU5PTUVNOworCWNvbXBsZXRpb24gPSBzZXR1cF9vcGFsX2RldihiZGV2LCBkZXYsIGZ1
bmNzLCBrZXkpOworCWlmIChJU19FUlIoY29tcGxldGlvbikpIHsKKwkJcmV0ID0gUFRSX0VSUihj
b21wbGV0aW9uKTsKKwkJZ290byBlcnJvcl9yZXR1cm47CisJfQorCisJbmV4dCgwLCBkZXYpOwor
CXJldCA9IHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24pOworCisgZXJyb3JfcmV0
dXJuOgorCXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0OworfQor
CisKK3N0YXRpYyBpbnQgb3BhbF9zYXZlX2ludGVybmFsKHN0cnVjdCBibG9ja19kZXZpY2UgKmJk
ZXYsCisJCQkgICAgICBzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayAqbGspCit7CisJdm9pZCAqZnVu
Y19kYXRhWzNdID0geyBOVUxMIH07CisJc3RydWN0IG9wYWxfZGV2ICpkZXY7CisJc3RydWN0IG9w
YWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKKwljb25zdCBvcGFsX3N0ZXAgX2F1dGhfZnVuY3Nb
XSA9IHsKKwkJb3BhbF9kaXNjb3ZlcnkwLAorCQlzdGFydF9hdXRoX29wYWxfc2Vzc2lvbiwKKwkJ
cXVlcnlfbG9ja2luZ19yYW5nZSwKKwkJZW5kX29wYWxfc2Vzc2lvbiwKKwkJb3BhbF9yZWdpc3Rl
cl9jb250LAorCQlOVUxMCisJfTsKKwlpbnQgcmV0OworCisJZGV2ID0gZ2V0X29yX2NyZWF0ZV9v
cGFsX2RldihiZGV2LCBsay0+a2V5LmxyLCBmYWxzZSk7CisJaWYgKCFkZXYpCisJCXJldHVybiAt
RU5PTUVNOworCWNvbXBsZXRpb24gPSBzZXR1cF9vcGFsX2RldihiZGV2LCBkZXYsIF9hdXRoX2Z1
bmNzLCAmbGstPmtleSk7CisJaWYgKElTX0VSUihjb21wbGV0aW9uKSkgeworCQlyZXQgPSBQVFJf
RVJSKGNvbXBsZXRpb24pOworCQlnb3RvIGVycm9yX3JldHVybjsKKwl9CisKKwlkZXYtPm51bV9m
dW5jX2RhdGEgPSAzOworCWRldi0+ZnVuY19kYXRhID0gZnVuY19kYXRhOworCWRldi0+ZnVuY19k
YXRhWzFdID0gJmxrLT5hdXRob3JpdHk7CisJZGV2LT5sa3VsID0gKmxrOworCisJbmV4dCgwLCBk
ZXYpOworCXJldCA9IHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24pOworCisgZXJy
b3JfcmV0dXJuOgorCXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0
OworfQorCitzdGF0aWMgaW50IGFkZF91c2VyX2xyX2ludGVybmFsKHN0cnVjdCBibG9ja19kZXZp
Y2UgKmJkZXYsCisJCQkJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrKQoreworCXZvaWQgKmZ1
bmNfZGF0YVszXSA9IHsgTlVMTCB9OworCXN0cnVjdCBvcGFsX2RldiAqZGV2OworCXN0cnVjdCBv
cGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247CisJY29uc3Qgb3BhbF9zdGVwIGZ1bmNzW10gPSB7
CisJCW9wYWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRfYWRtaW4xTFNQX29wYWxfc2Vzc2lvbiwKKwkJ
YWRkX3VzZXJfdG9fbHIsCisJCWVuZF9vcGFsX3Nlc3Npb24sCisJCU5VTEwKKwl9OworCWludCBy
ZXQ7CisKKwlkZXYgPSBnZXRfb3JfY3JlYXRlX29wYWxfZGV2KGJkZXYsIGxrLT5rZXkubHIsIHRy
dWUpOworCWlmICghZGV2KQorCQlyZXR1cm4gLUVOT01FTTsKKwljb21wbGV0aW9uID0gc2V0dXBf
b3BhbF9kZXYoYmRldiwgZGV2LCBmdW5jcywgJmxrLT5rZXkpOworCWlmIChJU19FUlIoY29tcGxl
dGlvbikpIHsKKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKKwkJZ290byBlcnJvcl9yZXR1
cm47CisJfQorCisJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKKwlkZXYtPmZ1bmNfZGF0YSA9IGZ1
bmNfZGF0YTsKKwlkZXYtPmZ1bmNfZGF0YVsyXSA9IGxrOworCisJbmV4dCgwLCBkZXYpOworCXJl
dCA9IHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24pOworCisgZXJyb3JfcmV0dXJu
OgorCXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0OworfQorCitz
dGF0aWMgaW50IGxvY2tfdW5sb2NrX2ludGVybmFsKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYs
CisJCQkJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrKQoreworCXZvaWQgKmZ1bmNfZGF0YVsz
XSA9IHsgTlVMTCB9OworCXN0cnVjdCBvcGFsX2RldiAqZGV2OworCXN0cnVjdCBvcGFsX2NvbXBs
ZXRpb24gKmNvbXBsZXRpb247CisKKwljb25zdCBvcGFsX3N0ZXAgdWxrX2Z1bmNzX1NVTVtdID0g
eworCQlvcGFsX2Rpc2NvdmVyeTAsCisJCXN0YXJ0X2F1dGhfb3BhbF9zZXNzaW9uLAorCQlsb2Nr
X3VubG9ja19sb2NraW5nX3JhbmdlX1NVTSwKKwkJZW5kX29wYWxfc2Vzc2lvbiwKKwkJTlVMTAor
CX07CisJY29uc3Qgb3BhbF9zdGVwIF91bmxvY2tfZnVuY3NbXSA9IHsKKwkJb3BhbF9kaXNjb3Zl
cnkwLAorCQlzdGFydF9hdXRoX29wYWxfc2Vzc2lvbiwKKwkJbG9ja191bmxvY2tfbG9ja2luZ19y
YW5nZSwKKwkJZW5kX29wYWxfc2Vzc2lvbiwKKwkJTlVMTAorCX07CisJaW50IHJldDsKKworCWRl
diA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgbGstPmtleS5sciwgdHJ1ZSk7CisJaWYg
KCFkZXYpCisJCXJldHVybiAtRU5PTUVNOworCisJaWYgKGxrLT5hdXRob3JpdHkuU1VNKQorCQlj
b21wbGV0aW9uID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCB1bGtfZnVuY3NfU1VNLCAmbGst
PmtleSk7CisJZWxzZQorCQljb21wbGV0aW9uID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBf
dW5sb2NrX2Z1bmNzLCAmbGstPmtleSk7CisKKwlpZiAoSVNfRVJSKGNvbXBsZXRpb24pKSB7CisJ
CXJldCA9IFBUUl9FUlIoY29tcGxldGlvbik7CisJCWdvdG8gZXJyb3JfcmV0dXJuOworCX0KKwor
CWRldi0+bnVtX2Z1bmNfZGF0YSA9IDM7CisJZGV2LT5mdW5jX2RhdGEgPSBmdW5jX2RhdGE7CisJ
ZGV2LT5mdW5jX2RhdGFbMV0gPSAmbGstPmF1dGhvcml0eTsKKwlkZXYtPmZ1bmNfZGF0YVsyXSA9
IGxrOworCisJbmV4dCgwLCBkZXYpOworCXJldCA9IHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNv
bXBsZXRpb24pOworCisgZXJyb3JfcmV0dXJuOgorCXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYo
ZGV2KTsKKwlyZXR1cm4gcmV0OworfQorCitpbnQgb3BhbF9lcmFzZV9sb2NraW5nX3JhbmdlKHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisJc3RydWN0
IG9wYWxfZGV2ICpkZXY7CisJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKKwlz
dHJ1Y3Qgb3BhbF9rZXkgazsKKwlpbnQgcmV0OworCWNvbnN0IG9wYWxfc3RlcCBlcmFzZV9mdW5j
c1tdID0geworCQlvcGFsX2Rpc2NvdmVyeTAsCisJCXN0YXJ0X2FkbWluMUxTUF9vcGFsX3Nlc3Np
b24sCisJCWVyYXNlX2xvY2tpbmdfcmFuZ2UsCisJCWVuZF9vcGFsX3Nlc3Npb24sCisJCU5VTEws
CisJfTsKKworCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzaykgeworCQlwcl9lcnIoIkNhbid0
IHNhdmUgcGFzc3dvcmQgZm9yIE5VTEwgYmxvY2sgZGV2aWNlLlxuIik7CisJCXJldHVybiAtRUlO
VkFMOworCX0KKworCWlmIChjb3B5X2Zyb21fdXNlcigmaywga2V5LT5vcGFsLCBzaXplb2YoKmtl
eS0+b3BhbCkpKQorCQlyZXR1cm4gLUVGQVVMVDsKKworCWRldiA9IGdldF9vcl9jcmVhdGVfb3Bh
bF9kZXYoYmRldiwgay5sciwgdHJ1ZSk7CisJaWYgKCFkZXYpCisJCXJldHVybiAtRU5PTUVNOwor
CisJY29tcGxldGlvbiA9IHNldHVwX29wYWxfZGV2KGJkZXYsIGRldiwgZXJhc2VfZnVuY3MsICZr
KTsKKwlpZiAoSVNfRVJSKGNvbXBsZXRpb24pKSB7CisJCXJldCA9IFBUUl9FUlIoY29tcGxldGlv
bik7CisJCWdvdG8gZXJyb3JfcmV0dXJuOworCX0KKworCW5leHQoMCwgZGV2KTsKKwlyZXQgPSB3
YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9uKTsKKworIGVycm9yX3JldHVybjoKKwly
ZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRldik7CisJcmV0dXJuIHJldDsKK30KK0VYUE9SVF9T
WU1CT0wob3BhbF9lcmFzZV9sb2NraW5nX3JhbmdlKTsKKworaW50IG9wYWxfZW5hYmxlX2Rpc2Fi
bGVfc2hhZG93X21icihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LAorCQkJCSAgIHN0cnVjdCBz
ZWRfa2V5ICprZXkpCit7CisJdm9pZCAqZnVuY19kYXRhWzZdID0geyBOVUxMIH07CisJc3RydWN0
IG9wYWxfbWJyX2RhdGEgbWJyOworCXN0cnVjdCBvcGFsX2RldiAqZGV2OworCXN0cnVjdCBvcGFs
X2NvbXBsZXRpb24gKmNvbXBsZXRpb247CisJY29uc3Qgb3BhbF9zdGVwIG1icl9mdW5jc1tdID0g
eworCQlvcGFsX2Rpc2NvdmVyeTAsCisJCXN0YXJ0X2FkbWluMUxTUF9vcGFsX3Nlc3Npb24sCisJ
CXNldF9tYnJfZG9uZSwKKwkJZW5kX29wYWxfc2Vzc2lvbiwKKwkJc3RhcnRfYWRtaW4xTFNQX29w
YWxfc2Vzc2lvbiwKKwkJc2V0X21icl9lbmFibGVfZGlzYWJsZSwKKwkJZW5kX29wYWxfc2Vzc2lv
biwKKwkJTlVMTCwKKwl9OworCWludCByZXQ7CisKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rp
c2spIHsKKwkJcHJfZXJyKCJDYW4ndCBzYXZlIHBhc3N3b3JkIGZvciBOVUxMIGJsb2NrIGRldmlj
ZS5cbiIpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlpZiAoY29weV9mcm9tX3VzZXIoJm1i
ciwga2V5LT5vcGFsX21iciwgc2l6ZW9mKCprZXktPm9wYWxfbWJyKSkpCisJCXJldHVybiAtRUZB
VUxUOworCisJaWYgKG1ici5lbmFibGVfZGlzYWJsZSAhPSBPUEFMX01CUl9FTkFCTEUgJiYKKwkg
ICAgbWJyLmVuYWJsZV9kaXNhYmxlICE9IE9QQUxfTUJSX0RJU0FCTEUpCisJCXJldHVybiAtRUlO
VkFMOworCisJZGV2ID0gZ2V0X29yX2NyZWF0ZV9vcGFsX2RldihiZGV2LCBtYnIua2V5LmxyLCB0
cnVlKTsKKwlpZiAoIWRldikKKwkJcmV0dXJuIC1FTk9NRU07CisKKwljb21wbGV0aW9uID0gc2V0
dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBtYnJfZnVuY3MsICZtYnIua2V5KTsKKwlpZiAoSVNfRVJS
KGNvbXBsZXRpb24pKSB7CisJCXJldCA9IFBUUl9FUlIoY29tcGxldGlvbik7CisJCWdvdG8gZXJy
b3JfcmV0dXJuOworCX0KKworCWRldi0+bnVtX2Z1bmNfZGF0YSA9IDY7CisJZGV2LT5mdW5jX2Rh
dGEgPSBmdW5jX2RhdGE7CisJZGV2LT5mdW5jX2RhdGFbMl0gPSAmbWJyLmVuYWJsZV9kaXNhYmxl
OworCWRldi0+ZnVuY19kYXRhWzVdID0gJm1ici5lbmFibGVfZGlzYWJsZTsKKworCW5leHQoMCwg
ZGV2KTsKKwlyZXQgPSB3YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9uKTsKKworIGVy
cm9yX3JldHVybjoKKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRldik7CisJcmV0dXJuIHJl
dDsKKworfQorRVhQT1JUX1NZTUJPTChvcGFsX2VuYWJsZV9kaXNhYmxlX3NoYWRvd19tYnIpOwor
CitpbnQgb3BhbF9zYXZlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5
ICprZXkpCit7CisJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgbGt1bDsKKworCWlmICghYmRldiB8
fCAhYmRldi0+YmRfZGlzaykgeworCQlwcl9lcnIoIkNhbid0IHNhdmUgcGFzc3dvcmQgZm9yIE5V
TEwgYmxvY2sgZGV2aWNlLlxuIik7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCWlmIChjb3B5
X2Zyb21fdXNlcigmbGt1bCwga2V5LT5vcGFsX2xrX3VubGssIHNpemVvZigqa2V5LT5vcGFsKSkp
CisJCXJldHVybiAtRUZBVUxUOworCisJcmV0dXJuIG9wYWxfc2F2ZV9pbnRlcm5hbChiZGV2LCAm
bGt1bCk7Cit9CitFWFBPUlRfU1lNQk9MKG9wYWxfc2F2ZSk7CisKK2ludCBvcGFsX2FkZF91c2Vy
X3RvX2xyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7
CisJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgbGt1bDsKKworCWlmIChjb3B5X2Zyb21fdXNlcigm
bGt1bCwga2V5LT5vcGFsX2xrX3VubGssIHNpemVvZihsa3VsKSkpCisJCXJldHVybiAtRUZBVUxU
OworCisJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrKSB7CisJCXByX2VycigiQ2FuJ3QgYXNz
aWduIHVzZXIgdG8gTFIgd2l0aG91dCBiYWNraW5nIGRpc2tcbiIpOworCQlyZXR1cm4gLUVGQVVM
VDsKKwl9CisJaWYgKGxrdWwubF9zdGF0ZSAhPSBPUEFMX1JPICYmIGxrdWwubF9zdGF0ZSAhPSBP
UEFMX1JXKSB7CisJCXByX2VycigiTG9ja2luZyBzdGF0ZSB3YXMgbm90IFJPIG9yIFJXXG4iKTsK
KwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCWlmIChsa3VsLmF1dGhvcml0eS53aG8gPCBPUEFMX1VT
RVIxICYmCisJICAgIGxrdWwuYXV0aG9yaXR5LndobyA+IE9QQUxfVVNFUjkpIHsKKwkJcHJfZXJy
KCJBdXRob3JpdHkgd2FzIG5vdCB3aXRoaW4gdGhlIHJhbmdlIG9mIHVzZXJzOiAlZFxuIiwKKwkJ
ICAgICAgIGxrdWwuYXV0aG9yaXR5Lndobyk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKwlpZiAo
bGt1bC5hdXRob3JpdHkuU1VNKSB7CisJCXByX2VycigiJXMgbm90IHN1cHBvcnRlZCBpbiBTVU0u
IFVzZSBzZXR1cCBsb2NraW5nIHJhbmdlXG4iLAorCQkgICAgICAgX19mdW5jX18pOworCQlyZXR1
cm4gLUVJTlZBTDsKKwl9CisKKwlyZXR1cm4gYWRkX3VzZXJfbHJfaW50ZXJuYWwoYmRldiwgJmxr
dWwpOworfQorRVhQT1JUX1NZTUJPTChvcGFsX2FkZF91c2VyX3RvX2xyKTsKKworaW50IG9wYWxf
cmV2ZXJ0dHBlcihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5
KQoreworCXN0cnVjdCBvcGFsX2tleSBrOworCisJaWYgKGNvcHlfZnJvbV91c2VyKCZrLCBrZXkt
Pm9wYWwsIHNpemVvZigqa2V5LT5vcGFsKSkpCisJCXJldHVybiAtRUZBVUxUOworCisJcmV0dXJu
IG9wYWxfcmV2ZXJ0KGJkZXYsICZrKTsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF9yZXZlcnR0cGVy
KTsKKworaW50IG9wYWxfbG9ja191bmxvY2soc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3Ry
dWN0IHNlZF9rZXkgKmtleSkKK3sKKwlzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayBrOworCisJaWYg
KGNvcHlfZnJvbV91c2VyKCZrLCBrZXktPm9wYWxfbGtfdW5saywgc2l6ZW9mKCprZXktPm9wYWxf
bGtfdW5saykpKQorCQlyZXR1cm4gLUVGQVVMVDsKKworCWlmIChrLmF1dGhvcml0eS53aG8gPCBP
UEFMX0FETUlOMSB8fCBrLmF1dGhvcml0eS53aG8gPj0gT1BBTF9VU0VSOSkKKwkJcmV0dXJuIC1F
SU5WQUw7CisKKwlyZXR1cm4gbG9ja191bmxvY2tfaW50ZXJuYWwoYmRldiwgJmspOworfQorRVhQ
T1JUX1NZTUJPTChvcGFsX2xvY2tfdW5sb2NrKTsKKworaW50IG9wYWxfdGFrZV9vd25lcnNoaXAo
c3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKwlzdHJ1
Y3Qgb3BhbF9rZXkgazsKKwljb25zdCBvcGFsX3N0ZXAgb3duZXJfZnVuY3NbXSA9IHsKKwkJb3Bh
bF9kaXNjb3ZlcnkwLAorCQlzdGFydF9hbnlib2R5QVNQX29wYWxfc2Vzc2lvbiwKKwkJZ2V0X21z
aWRfY3Bpbl9waW4sCisJCWVuZF9vcGFsX3Nlc3Npb24sCisJCXN0YXJ0X1NJREFTUF9vcGFsX3Nl
c3Npb24sCisJCXNldF9zaWRfY3Bpbl9waW4sCisJCWVuZF9vcGFsX3Nlc3Npb24sCisJCU5VTEwK
Kwl9OworCisJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrKSB7CisJCXByX2VycigiQ2FuJ3Qg
c2F2ZSBwYXNzd29yZCBmb3IgTlVMTCBibG9jayBkZXZpY2UuXG4iKTsKKwkJcmV0dXJuIC1FSU5W
QUw7CisJfQorCisJaWYgKGNvcHlfZnJvbV91c2VyKCZrLCBrZXktPm9wYWwsIHNpemVvZigqa2V5
LT5vcGFsKSkpCisJCXJldHVybiAtRUZBVUxUOworCisJcmV0dXJuIG9wYWxfcmVnaXN0ZXIoYmRl
diwgJmssIG93bmVyX2Z1bmNzKTsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF90YWtlX293bmVyc2hp
cCk7CisKK2ludCBvcGFsX2FjdGl2YXRlX2xzcChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBz
dHJ1Y3Qgc2VkX2tleSAqa2V5KQoreworCXN0cnVjdCBvcGFsX2tleSBrOworCWNvbnN0IG9wYWxf
c3RlcCBhY3RpdmVfZnVuY3NbXSA9IHsKKwkJb3BhbF9kaXNjb3ZlcnkwLAorCQlzdGFydF9TSURB
U1Bfb3BhbF9zZXNzaW9uLCAvKiBPcGVuIHNlc3Npb24gYXMgU0lEIGF1dGggKi8KKwkJZ2V0X2xz
cF9saWZlY3ljbGUsCisJCWFjdGl2YXRlX2xzcCwKKwkJZW5kX29wYWxfc2Vzc2lvbiwKKwkJTlVM
TAorCX07CisKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2spIHsKKwkJcHJfZXJyKCJDYW4n
dCBzYXZlIHBhc3N3b3JkIGZvciBOVUxMIGJsb2NrIGRldmljZS5cbiIpOworCQlyZXR1cm4gLUVJ
TlZBTDsKKwl9CisKKwlpZiAoY29weV9mcm9tX3VzZXIoJmssIGtleS0+b3BhbCwgc2l6ZW9mKCpr
ZXktPm9wYWwpKSkKKwkJcmV0dXJuIC1FRkFVTFQ7CisKKwlyZXR1cm4gb3BhbF9hY3RfbHNwX2lu
dChiZGV2LCAmaywgYWN0aXZlX2Z1bmNzKTsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF9hY3RpdmF0
ZV9sc3ApOworCitpbnQgb3BhbF9zZXR1cF9sb2NraW5nX3JhbmdlKHN0cnVjdCBibG9ja19kZXZp
Y2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICpwdykKK3sKKwlzdHJ1Y3Qgb3BhbF91c2VyX2xyX3Nl
dHVwIGs7CisKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2spIHsKKwkJcHJfZXJyKCJDYW4n
dCBzYXZlIHBhc3N3b3JkIGZvciBOVUxMIGJsb2NrIGRldmljZS5cbiIpOworCQlyZXR1cm4gLUVJ
TlZBTDsKKwl9CisKKwlpZiAoY29weV9mcm9tX3VzZXIoJmssIHB3LT5vcGFsX2xycywgc2l6ZW9m
KCpwdy0+b3BhbF9scnMpKSkKKwkJcmV0dXJuIC1FRkFVTFQ7CisKKwlyZXR1cm4gaW50ZXJuYWxf
c2V0dXBfbHIoYmRldiwgJmspOworfQorCitpbnQgb3BhbF9zZXRfbmV3X3B3KHN0cnVjdCBibG9j
a19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICpwdykKK3sKKwlzdHJ1Y3Qgb3BhbF9uZXdf
cHcgazsKKworCWlmIChwdy0+c2VkX3R5cGUgIT0gT1BBTF9QVykKKwkJcmV0dXJuIC1FSU5WQUw7
CisKKwlpZiAoY29weV9mcm9tX3VzZXIoJmssIHB3LT5vcGFsX3B3LCBzaXplb2YoKnB3LT5vcGFs
X3B3KSkpCisJCXJldHVybiAtRUZBVUxUOworCisJaWYgKGsud2hvLndobyA8IE9QQUxfQURNSU4x
IHx8IGsud2hvLndobyA+IE9QQUxfVVNFUjkpCisJCXJldHVybiAtRUlOVkFMOworCisJcmV0dXJu
IG9wYWxfc2V0X3B3KGJkZXYsICZrKTsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF9zZXRfbmV3X3B3
KTsKKworaW50IG9wYWxfYWN0aXZhdGVfdXNlcihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBz
dHJ1Y3Qgc2VkX2tleSAqcHcpCit7CisJc3RydWN0IG9wYWxfYWN0aXZhdGVfdXNlciBrOworCisJ
aWYgKHB3LT5zZWRfdHlwZSAhPSBPUEFMX0FDVF9VU1IpIHsKKwkJcHJfZXJyKCJTZWQgdHlwZSB3
YXMgbm90IGFjdCB1c2VyXG4iKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJaWYgKGNvcHlf
ZnJvbV91c2VyKCZrLCBwdy0+b3BhbF9hY3QsIHNpemVvZigqcHctPm9wYWxfYWN0KSkpIHsKKwkJ
cHJfZXJyKCJjb3B5IGZyb20gdXNlciBlcnJvclxuIik7CisJCXJldHVybiAtRUZBVUxUOworCX0K
KworCS8qIFdlIGNhbid0IGFjdGl2YXRlIEFkbWluMSBpdCdzIGFjdGl2ZSBhcyBtYW51ZmFjdHVy
ZWQgKi8KKwlpZiAoay53aG8ud2hvIDwgT1BBTF9VU0VSMSAmJiBrLndoby53aG8gPiBPUEFMX1VT
RVI5KSB7CisJCXByX2VycigiV2hvIHdhcyBub3QgYSB2YWxpZCB1c2VyOiAlZCBcbiIsIGsud2hv
Lndobyk7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCXJldHVybiBhY3RpdmF0ZV91c2VyKGJk
ZXYsICZrKTsKKworfQorRVhQT1JUX1NZTUJPTChvcGFsX2FjdGl2YXRlX3VzZXIpOworCitpbnQg
b3BhbF91bmxvY2tfZnJvbV9zdXNwZW5kKHN0cnVjdCBvcGFsX3N1c3BlbmRfdW5sayAqZGF0YSkK
K3sKKwljb25zdCBjaGFyICpkaXNrbmFtZSA9IGRhdGEtPm5hbWU7CisJc3RydWN0IG9wYWxfZGV2
ICppdGVyLCAqZGV2ID0gTlVMTDsKKwlzdHJ1Y3Qgb3BhbF9jb21wbGV0aW9uICpjb21wbGV0aW9u
OworCXZvaWQgKmZ1bmNfZGF0YVszXSA9IHsgTlVMTCB9OworCWNvbnN0IG9wYWxfc3RlcCBfdW5s
b2NrX2Z1bmNzX1NVTVtdID0geworCQlvcGFsX2Rpc2NvdmVyeTAsCisJCXN0YXJ0X2F1dGhfb3Bh
bF9zZXNzaW9uLAorCQlsb2NrX3VubG9ja19sb2NraW5nX3JhbmdlLAorCQllbmRfb3BhbF9zZXNz
aW9uLAorCQlOVUxMCisJfTsKKwljb25zdCBvcGFsX3N0ZXAgX3VubG9ja19mdW5jc1tdID0gewor
CQlvcGFsX2Rpc2NvdmVyeTAsCisJCXN0YXJ0X2F1dGhfb3BhbF9zZXNzaW9uLAorCQlsb2NrX3Vu
bG9ja19sb2NraW5nX3JhbmdlLAorCQllbmRfb3BhbF9zZXNzaW9uLAorCQlOVUxMCisJfTsKKwor
CisJc3Bpbl9sb2NrKCZsaXN0X3NwaW5sb2NrKTsKKwlsaXN0X2Zvcl9lYWNoX2VudHJ5KGl0ZXIs
ICZvcGFsX2xpc3QsIG5vZGUpIHsKKwkJaWYgKHN0cm5jbXAoaXRlci0+ZGlza19uYW1lLCBkaXNr
bmFtZSwgRElTS19OQU1FX0xFTikpIHsKKwkJCXByX2VycigiaXRlcmRpc2sgd2FzICVzIGFuZCBk
aXNrbmFtZSBpcyAlc1xuIiwKKwkJCSAgICAgICBpdGVyLT5kaXNrX25hbWUsIGRpc2tuYW1lKTsK
KwkJCWNvbnRpbnVlOworCQl9CisJCWlmIChhdG9taWNfYWRkX3VubGVzcygmaXRlci0+aW5fdXNl
LCAxLCAxKSkgeworCQkJZGV2ID0gaXRlcjsKKwkJCWRldi0+ZnVuY19kYXRhID0gZnVuY19kYXRh
OworCQkJZGV2LT5yZXN1bWVfZnJvbV9zdXNwZW5kID0gdHJ1ZTsKKwkJCWRldi0+cmVzdW1lX2Rh
dGEgPSBkYXRhOworCQkJZGV2LT5maW5hbF9jYiA9IHVubG9ja19zdXNwZW5kX2ZpbmFsOworCQkJ
ZGV2LT5maW5hbF9jYl9kYXRhID0gZGV2OworCQkJZGV2LT5lcnJvcl9jYiA9IGVuZF9vcGFsX3Nl
c3Npb25fZXJyb3I7CisJCQlkZXYtPmVycm9yX2NiX2RhdGEgPSBkZXY7CisJCQlkZXYtPnN0YXRl
ID0gMDsKKwkJCWlmIChkZXYtPmxrdWwuYXV0aG9yaXR5LlNVTSkKKwkJCQlkZXYtPmZ1bmNzID0g
X3VubG9ja19mdW5jc19TVU07CisJCQllbHNlCisJCQkJZGV2LT5mdW5jcyA9IF91bmxvY2tfZnVu
Y3M7CisJCQlkZXYtPlRTTiA9IDA7CisJCQlkZXYtPkhTTiA9IDA7CisJCQlkZXYtPmZ1bmNfZGF0
YVsyXSA9ICZkZXYtPmxrdWw7CisJCQlkZXYtPmZ1bmNfZGF0YVsxXSA9ICZkZXYtPmxrdWwuYXV0
aG9yaXR5OworCQkJY29tcGxldGlvbiA9IGRldi0+Y29tcGxldGlvbjsKKwkJCW5leHQoMCwgZGV2
KTsKKwkJCXdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24pOworCQl9CisJfQorCXNw
aW5fdW5sb2NrKCZsaXN0X3NwaW5sb2NrKTsKKworCWlmICghZGV2KQorCQlyZXR1cm4gLUVOT0RF
VjsKKwlyZXR1cm4gMDsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF91bmxvY2tfZnJvbV9zdXNwZW5k
KTsKZGlmZiAtLWdpdCBhL2xpYi9zZWQtb3BhbF9pbnRlcm5hbC5oIGIvbGliL3NlZC1vcGFsX2lu
dGVybmFsLmgKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uYzlkMzg4MwotLS0g
L2Rldi9udWxsCisrKyBiL2xpYi9zZWQtb3BhbF9pbnRlcm5hbC5oCkBAIC0wLDAgKzEsNTg2IEBA
CisvKgorICogQ29weXJpZ2h0IMKpIDIwMTYgSW50ZWwgQ29ycG9yYXRpb24KKyAqCisgKiBQZXJt
aXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBv
YnRhaW5pbmcgYQorICogY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3Vt
ZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwKKyAqIHRvIGRlYWwgaW4gdGhlIFNvZnR3
YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24KKyAq
IHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmli
dXRlLCBzdWJsaWNlbnNlLAorICogYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwg
YW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlCisgKiBTb2Z0d2FyZSBpcyBmdXJuaXNo
ZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgorICoKKyAq
IFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIChp
bmNsdWRpbmcgdGhlIG5leHQKKyAqIHBhcmFncmFwaCkgc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxs
IGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUKKyAqIFNvZnR3YXJlLgorICoK
KyAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9G
IEFOWSBLSU5ELCBFWFBSRVNTIE9SCisgKiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1J
VEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKKyAqIEZJVE5FU1MgRk9S
IEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuICBJTiBOTyBFVkVOVCBT
SEFMTAorICogVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBB
TlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKKyAqIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBB
Q1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HCisgKiBGUk9NLCBP
VVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9U
SEVSIERFQUxJTkdTCisgKiBJTiBUSEUgU09GVFdBUkUuCisgKgorICogQXV0aG9yOgorICogICAg
UmFmYWVsIEFudG9nbm9sbGkgPHJhZmFlbC5hbnRvZ25vbGxpQGludGVsLmNvbT4KKyAqICAgIFNj
b3R0ICBCYXVlciAgICAgIDxzY290dC5iYXVlckBpbnRlbC5jb20+CisgKi8KKworI2lmbmRlZiBf
TlZNRV9PUEFMX0lOVEVSTkFMX0gKKyNkZWZpbmUgX05WTUVfT1BBTF9JTlRFUk5BTF9ICisKKyNp
bmNsdWRlIDxsaW51eC9rZXktdHlwZS5oPgorI2luY2x1ZGUgPGtleXMvdXNlci10eXBlLmg+CisK
KyNkZWZpbmUgRFRBRVJST1JfTk9fTUVUSE9EX1NUQVRVUyAweDg5CisKK3N0YXRpYyBjb25zdCBj
aGFyICpvcGFsX2Vycm9yc1sxOV0gPSB7CisJIlN1Y2Nlc3MiLAorCSJOb3QgQXV0aG9yaXplZCIs
CisJIlVua25vd24gRXJyb3IiLAorCSJTUCBCdXN5IiwKKwkiU1AgRmFpbGVkIiwKKwkiU1AgRGlz
YWJsZWQiLAorCSJTUCBGcm96ZW4iLAorCSJObyBTZXNzaW9ucyBBdmFpbGFibGUiLAorCSJVbmlx
dWVuZXNzIENvbmZsaWN0IiwKKwkiSW5zdWZmaWNpZW50IFNwYWNlIiwKKwkiSW5zdWZmaWNpZW50
IFJvd3MiLAorCSJJbnZhbGlkIEZ1bmN0aW9uIiwKKwkiSW52YWxpZCBQYXJhbWV0ZXIiLAorCSJJ
bnZhbGlkIFJlZmVyZW5jZSIsCisJIlVua25vd24gRXJyb3IiLAorCSJUUEVSIE1hbGZ1bmN0aW9u
IiwKKwkiVHJhbnNhY3Rpb24gRmFpbHVyZSIsCisJIlJlc3BvbnNlIE92ZXJmbG93IiwKKwkiQXV0
aG9yaXR5IExvY2tlZCBPdXQiLAorfTsKKworc3RhdGljIGNvbnN0IGNoYXIgKm9wYWxfZXJyb3Jf
dG9faHVtYW4oaW50IGVycm9yKQoreworCWlmIChlcnJvciA9PSAweDNmKQorCQlyZXR1cm4gIkZh
aWxlZCI7CisKKwlpZiAoZXJyb3IgPj0gc2l6ZW9mKG9wYWxfZXJyb3JzKSB8fCBlcnJvciA8IDAp
CisJCXJldHVybiAiVW5rbm93biBFcnJvciI7CisKKwlyZXR1cm4gb3BhbF9lcnJvcnNbZXJyb3Jd
OworfQorCisvKiBVc2VyIElEcyB1c2VkIGluIHRoZSBUQ0cgc3RvcmFnZSBTU0NzICovCitzdGF0
aWMgY29uc3QgdTggT1BBTFVJRFtdWzhdID0geworCS8qIHVzZXJzICovCisKKwkvKiBzZXNzaW9u
IG1hbmFnZW1lbnQgICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAw
eDAwLCAweGZmfSwKKwkvKiBzcGVjaWFsICJ0aGlzU1AiIHN5bnRheCAqLworCXsgMHgwMCwgMHgw
MCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMSB9LAorCS8qIEFkbWluaXN0cmF0
aXZlIFNQICovCisJeyAweDAwLCAweDAwLCAweDAyLCAweDA1LCAweDAwLCAweDAwLCAweDAwLCAw
eDAxIH0sCisJLyogTG9ja2luZyBTUCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMiwgMHgwNSwgMHgw
MCwgMHgwMCwgMHgwMCwgMHgwMiB9LAorCS8qIEVOVEVSUFJJU0UgTG9ja2luZyBTUCAgKi8KKwl7
IDB4MDAsIDB4MDAsIDB4MDIsIDB4MDUsIDB4MDAsIDB4MDEsIDB4MDAsIDB4MDEgfSwKKwkvKiBh
bnlib2R5ICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA5LCAweDAwLCAweDAwLCAweDAwLCAw
eDAxIH0sCisJLyogU0lEICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA5LCAweDAwLCAweDAw
LCAweDAwLCAweDA2IH0sCisJLyogQURNSU4xICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA5
LCAweDAwLCAweDAxLCAweDAwLCAweDAxIH0sCisJLyogVVNFUjEgKi8KKwl7IDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDksIDB4MDAsIDB4MDMsIDB4MDAsIDB4MDEgfSwKKwkvKiBVU0VSMiAqLworCXsg
MHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMywgMHgwMCwgMHgwMiB9LAorCS8qIFBT
SUQgdXNlciAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMSwgMHhmZiwg
MHgwMSB9LAorCS8qIEJhbmRNYXN0ZXIgMCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwg
MHgwMCwgMHgwMCwgMHg4MCwgMHgwMSB9LAorCSAvKiBFcmFzZU1hc3RlciAqLworCXsgMHgwMCwg
MHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMCwgMHg4NCwgMHgwMSB9LAorCisJLyogdGFibGVz
ICovCisKKwkvKiBMb2NraW5nX0dsb2JhbFJhbmdlICovCisJeyAweDAwLCAweDAwLCAweDA4LCAw
eDAyLCAweDAwLCAweDAwLCAweDAwLCAweDAxIH0sCisJLyogQUNFX0xvY2tpbmdfUmFuZ2VfU2V0
X1JkTG9ja2VkIFVJRCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOCwgMHgwMCwgMHgwMywg
MHhFMCwgMHgwMSB9LAorCS8qIEFDRV9Mb2NraW5nX1JhbmdlX1NldF9XckxvY2tlZCBVSUQgKi8K
Kwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDgsIDB4MDAsIDB4MDMsIDB4RTgsIDB4MDEgfSwKKwkv
KiBNQlIgQ29udHJvbCAqLworCXsgMHgwMCwgMHgwMCwgMHgwOCwgMHgwMywgMHgwMCwgMHgwMCwg
MHgwMCwgMHgwMSB9LAorCS8qIFNoYWRvdyBNQlIgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDgsIDB4
MDQsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAgfSwKKwkvKiBBVVRIT1JJVFlfVEFCTEUgKi8KKwl7
IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDksIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDB9LAorCS8qIENf
UElOX1RBQkxFICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDBCLCAweDAwLCAweDAwLCAweDAw
LCAweDAwfSwKKwkvKiBPUEFMIExvY2tpbmcgSW5mbyAqLworCXsgMHgwMCwgMHgwMCwgMHgwOCwg
MHgwMSwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMSB9LAorCS8qIEVudGVycHJpc2UgTG9ja2luZyBJ
bmZvICovCisJeyAweDAwLCAweDAwLCAweDA4LCAweDAxLCAweDAwLCAweDAwLCAweDAwLCAweDAw
IH0sCisKKwkvKiBDX1BJTl9UQUJMRSBvYmplY3QgSUQncyAqLworCisJLyogQ19QSU5fTVNJRCAq
LworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwQiwgMHgwMCwgMHgwMCwgMHg4NCwgMHgwMn0sCisJ
LyogQ19QSU5fU0lEICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDBCLCAweDAwLCAweDAwLCAw
eDAwLCAweDAxfSwKKwkgLyogQ19QSU5fQURNSU4xICovCisJeyAweDAwLCAweDAwLCAweDAwLCAw
eDBCLCAweDAwLCAweDAxLCAweDAwLCAweDAxfSwKKworCS8qIGhhbGYgVUlEJ3MgKG9ubHkgZmly
c3QgNCBieXRlcyB1c2VkKSAqLworCisJLyogSGFsZi1VSUQg4oCTIEF1dGhvcml0eV9vYmplY3Rf
cmVmICovCisJeyAweDAwLCAweDAwLCAweDBDLCAweDA1LCAweGZmLCAweGZmLCAweGZmLCAweGZm
IH0sCisJLyogSGFsZi1VSUQg4oCTIEJvb2xlYW4gQUNFICovCisJeyAweDAwLCAweDAwLCAweDA0
LCAweDBFLCAweGZmLCAweGZmLCAweGZmLCAweGZmIH0sCisKKwkvKiBzcGVjaWFsIHZhbHVlIGZv
ciBvbWl0dGVkIG9wdGlvbmFsIHBhcmFtZXRlciAqLworCisJLyogSEVYRkYgZm9yIG9taXR0ZWQg
Ki8KKwl7IDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmZ9LAor
fTsKK3N0YXRpYyBjb25zdCBzaXplX3QgT1BBTF9VSURfTEVOR1RIID0gODsKK3N0YXRpYyBjb25z
dCBzaXplX3QgT1BBTF9NU0lEX0tFWUxFTiA9IDE1Oworc3RhdGljIGNvbnN0IHNpemVfdCBPUEFM
X1VJRF9MRU5HVEhfSEFMRiA9IDQ7CisKKworLyogRW51bSB0byBpbmRleCBPUEFMVUlEIGFycmF5
ICovCitlbnVtIE9QQUxfVUlEIHsKKwkvKiB1c2VycyAqLworCU9QQUxfU01VSURfVUlELAorCU9Q
QUxfVEhJU1NQX1VJRCwKKwlPUEFMX0FETUlOU1BfVUlELAorCU9QQUxfTE9DS0lOR1NQX1VJRCwK
KwlPUEFMX0VOVEVSUFJJU0VfTE9DS0lOR1NQX1VJRCwKKwlPUEFMX0FOWUJPRFlfVUlELAorCU9Q
QUxfU0lEX1VJRCwKKwlPUEFMX0FETUlOMV9VSUQsCisJT1BBTF9VU0VSMV9VSUQsCisJT1BBTF9V
U0VSMl9VSUQsCisJT1BBTF9QU0lEX1VJRCwKKwlPUEFMX0VOVEVSUFJJU0VfQkFORE1BU1RFUjBf
VUlELAorCU9QQUxfRU5URVJQUklTRV9FUkFTRU1BU1RFUl9VSUQsCisJLyogdGFibGVzICovCisJ
T1BBTF9MT0NLSU5HUkFOR0VfR0xPQkFMLAorCU9QQUxfTE9DS0lOR1JBTkdFX0FDRV9SRExPQ0tF
RCwKKwlPUEFMX0xPQ0tJTkdSQU5HRV9BQ0VfV1JMT0NLRUQsCisJT1BBTF9NQlJDT05UUk9MLAor
CU9QQUxfTUJSLAorCU9QQUxfQVVUSE9SSVRZX1RBQkxFLAorCU9QQUxfQ19QSU5fVEFCTEUsCisJ
T1BBTF9MT0NLSU5HX0lORk9fVEFCTEUsCisJT1BBTF9FTlRFUlBSSVNFX0xPQ0tJTkdfSU5GT19U
QUJMRSwKKwkvKiBDX1BJTl9UQUJMRSBvYmplY3QgSUQncyAqLworCU9QQUxfQ19QSU5fTVNJRCwK
KwlPUEFMX0NfUElOX1NJRCwKKwlPUEFMX0NfUElOX0FETUlOMSwKKwkvKiBoYWxmIFVJRCdzIChv
bmx5IGZpcnN0IDQgYnl0ZXMgdXNlZCkgKi8KKwlPUEFMX0hBTEZfVUlEX0FVVEhPUklUWV9PQkpf
UkVGLAorCU9QQUxfSEFMRl9VSURfQk9PTEVBTl9BQ0UsCisJLyogb21pdHRlZCBvcHRpb25hbCBw
YXJhbWV0ZXIgKi8KKwlPUEFMX1VJRF9IRVhGRiwKK307CisKKy8qCisgKiBUQ0cgU3RvcmFnZSBT
U0MgTWV0aG9kcy4KKyAqLworc3RhdGljIGNvbnN0IHU4IE9QQUxNRVRIT0RbXVs4XSA9IHsKKwkv
KiBQcm9wZXJ0aWVzICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAw
eGZmLCAweDAxIH0sCisJLyogU1RBUlRTRVNTSU9OICovCisJeyAweDAwLCAweDAwLCAweDAwLCAw
eDAwLCAweDAwLCAweDAwLCAweGZmLCAweDAyIH0sCisJLyogUmV2ZXJ0ICovCisJeyAweDAwLCAw
eDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAyLCAweDAyIH0sCisJLyogQWN0aXZhdGUg
Ki8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDIsIDB4MDMgfSwK
KwkvKiBFbnRlcnByaXNlIEdldCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwg
MHgwMCwgMHgwMCwgMHgwNiB9LAorCS8qIEVudGVycHJpc2UgU2V0ICovCisJeyAweDAwLCAweDAw
LCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDA3IH0sCisJLyogTkVYVCAqLworCXsg
MHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOCB9LAorCS8qIEVu
dGVycHJpc2UgQXV0aGVudGljYXRlICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAw
LCAweDAwLCAweDAwLCAweDBjIH0sCisJLyogR2V0QUNMICovCisJeyAweDAwLCAweDAwLCAweDAw
LCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDBkIH0sCisJLyogR2VuS2V5ICovCisJeyAweDAw
LCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDEwIH0sCisJLyogcmV2ZXJ0
U1AgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MTEg
fSwKKwkvKiBHZXQgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4
MDAsIDB4MTYgfSwKKwkvKiBTZXQgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAs
IDB4MDAsIDB4MDAsIDB4MTcgfSwKKwkvKiBBdXRoZW50aWNhdGUgKi8KKwl7IDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MWMgfSwKKwkvKiBSYW5kb20gKi8KKwl7
IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDEgfSwKKwkvKiBF
cmFzZSAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwOCwgMHgw
MyB9LAorfTsKK3N0YXRpYyBjb25zdCBzaXplX3QgT1BBTF9NRVRIT0RfTEVOR1RIID0gODsKKwor
LyogRW51bSBmb3IgaW5kZXhpbmcgdGhlIE9QQUxNRVRIT0QgYXJyYXkgKi8KK2VudW0gT1BBTF9N
RVRIT0QgeworCU9QQUxfUFJPUEVSVElFUywKKwlPUEFMX1NUQVJUU0VTU0lPTiwKKwlPUEFMX1JF
VkVSVCwKKwlPUEFMX0FDVElWQVRFLAorCU9QQUxfRUdFVCwKKwlPUEFMX0VTRVQsCisJT1BBTF9O
RVhULAorCU9QQUxfRUFVVEhFTlRJQ0FURSwKKwlPUEFMX0dFVEFDTCwKKwlPUEFMX0dFTktFWSwK
KwlPUEFMX1JFVkVSVFNQLAorCU9QQUxfR0VULAorCU9QQUxfU0VULAorCU9QQUxfQVVUSEVOVElD
QVRFLAorCU9QQUxfUkFORE9NLAorCU9QQUxfRVJBU0UsCit9OworCitlbnVtIE9QQUxfUkVTUE9O
U0VfVE9LRU4geworCU9QQUxfRFRBX1RPS0VOSURfQllURVNUUklORyA9IDB4ZTAsCisJT1BBTF9E
VEFfVE9LRU5JRF9TSU5UID0gMHhlMSwKKwlPUEFMX0RUQV9UT0tFTklEX1VJTlQgPSAweGUyLAor
CU9QQUxfRFRBX1RPS0VOSURfVE9LRU4gPSAweGUzLCAvKiBhY3R1YWwgdG9rZW4gaXMgcmV0dXJu
ZWQgKi8KKwlPUEFMX0RUQV9UT0tFTklEX0lOVkFMSUQgPSAwWDAKK307CisKK2VudW0gT1BBTF9U
T0tFTiB7CisJLyogQm9vbGVhbiAqLworCU9QQUxfVFJVRSA9IDB4MDEsCisJT1BBTF9GQUxTRSA9
IDB4MDAsCisJT1BBTF9CT09MRUFOX0VYUFIgPSAweDAzLAorCS8qIGNlbGxibG9ja3MgKi8KKwlP
UEFMX1RBQkxFID0gMHgwMCwKKwlPUEFMX1NUQVJUUk9XID0gMHgwMSwKKwlPUEFMX0VORFJPVyA9
IDB4MDIsCisJT1BBTF9TVEFSVENPTFVNTiA9IDB4MDMsCisJT1BBTF9FTkRDT0xVTU4gPSAweDA0
LAorCU9QQUxfVkFMVUVTID0gMHgwMSwKKwkvKiBhdXRob3JpdHkgdGFibGUgKi8KKwlPUEFMX1BJ
TiA9IDB4MDMsCisJLyogbG9ja2luZyB0b2tlbnMgKi8KKwlPUEFMX1JBTkdFU1RBUlQgPSAweDAz
LAorCU9QQUxfUkFOR0VMRU5HVEggPSAweDA0LAorCU9QQUxfUkVBRExPQ0tFTkFCTEVEID0gMHgw
NSwKKwlPUEFMX1dSSVRFTE9DS0VOQUJMRUQgPSAweDA2LAorCU9QQUxfUkVBRExPQ0tFRCA9IDB4
MDcsCisJT1BBTF9XUklURUxPQ0tFRCA9IDB4MDgsCisJT1BBTF9BQ1RJVkVLRVkgPSAweDBBLAor
CS8qIGxvY2tpbmcgaW5mbyB0YWJsZSAqLworCU9QQUxfTUFYUkFOR0VTID0gMHgwNCwKKwkgLyog
bWJyIGNvbnRyb2wgKi8KKwlPUEFMX01CUkVOQUJMRSA9IDB4MDEsCisJT1BBTF9NQlJET05FID0g
MHgwMiwKKwkvKiBwcm9wZXJ0aWVzICovCisJT1BBTF9IT1NUUFJPUEVSVElFUyA9IDB4MDAsCisJ
LyogYXRvbXMgKi8KKwlPUEFMX1NUQVJUTElTVCA9IDB4ZjAsCisJT1BBTF9FTkRMSVNUID0gMHhm
MSwKKwlPUEFMX1NUQVJUTkFNRSA9IDB4ZjIsCisJT1BBTF9FTkROQU1FID0gMHhmMywKKwlPUEFM
X0NBTEwgPSAweGY4LAorCU9QQUxfRU5ET0ZEQVRBID0gMHhmOSwKKwlPUEFMX0VORE9GU0VTU0lP
TiA9IDB4ZmEsCisJT1BBTF9TVEFSVFRSQU5TQUNUT04gPSAweGZiLAorCU9QQUxfRU5EVFJBTlNB
Q1RPTiA9IDB4ZkMsCisJT1BBTF9FTVBUWUFUT00gPSAweGZmLAorCU9QQUxfV0hFUkUgPSAweDAw
LAorfTsKKworLyogVXNlZnVsIHRpbnkgYXRvbXMuCisgKiBVc2VmdWwgZm9yIHRhYmxlIGNvbHVt
bnMgZXRjCisgKi8KK2VudW0gT1BBTF9USU5ZX0FUT00geworCU9QQUxfVElOWV9VSU5UXzAwID0g
MHgwMCwKKwlPUEFMX1RJTllfVUlOVF8wMSA9IDB4MDEsCisJT1BBTF9USU5ZX1VJTlRfMDIgPSAw
eDAyLAorCU9QQUxfVElOWV9VSU5UXzAzID0gMHgwMywKKwlPUEFMX1RJTllfVUlOVF8wNCA9IDB4
MDQsCisJT1BBTF9USU5ZX1VJTlRfMDUgPSAweDA1LAorCU9QQUxfVElOWV9VSU5UXzA2ID0gMHgw
NiwKKwlPUEFMX1RJTllfVUlOVF8wNyA9IDB4MDcsCisJT1BBTF9USU5ZX1VJTlRfMDggPSAweDA4
LAorCU9QQUxfVElOWV9VSU5UXzA5ID0gMHgwOSwKKwlPUEFMX1RJTllfVUlOVF8xMCA9IDB4MGEs
CisJT1BBTF9USU5ZX1VJTlRfMTEgPSAweDBiLAorCU9QQUxfVElOWV9VSU5UXzEyID0gMHgwYywK
KwlPUEFMX1RJTllfVUlOVF8xMyA9IDB4MGQsCisJT1BBTF9USU5ZX1VJTlRfMTQgPSAweDBlLAor
CU9QQUxfVElOWV9VSU5UXzE1ID0gMHgwZiwKK307CisKK2VudW0gT1BBTF9BVE9NX1dJRFRIIHsK
KwlPUEFMX1dJRFRIX1RJTlksCisJT1BBTF9XSURUSF9TSE9SVCwKKwlPUEFMX1dJRFRIX01FRElV
TSwKKwlPUEFMX1dJRFRIX0xPTkcsCisJT1BBTF9XSURUSF9UT0tFTgorfTsKKworLyogTG9ja2lu
ZyBzdGF0ZSBmb3IgYSBsb2NraW5nIHJhbmdlICovCitlbnVtIE9QQUxfTE9DS0lOR1NUQVRFIHsK
KwlPUEFMX0xPQ0tJTkdfUkVBRFdSSVRFID0gMHgwMSwKKwlPUEFMX0xPQ0tJTkdfUkVBRE9OTFkg
PSAweDAyLAorCU9QQUxfTE9DS0lOR19MT0NLRUQgPSAweDAzLAorfTsKKworLyoKKyAqIFN0cnVj
dHVyZXMgdG8gYnVpbGQgYW5kIGRlY29kZSB0aGUgT3BhbCBTU0MgbWVzc2FnZXMKKyAqIGZpZWxk
cyB0aGF0IGFyZSBOT1QgcmVhbGx5IG51bWVyaWMgYXJlIGRlZmluZWQgYXMgdThbXSB0bworICog
aGVscCByZWR1Y2UgdGhlIGVuZGlhbm5lc3MgaXNzdWVzCisgKi8KKworLyogQ29tbSBQYWNrZXQg
KGhlYWRlcikgZm9yIHRyYW5zbWlzc2lvbnMuICovCitzdHJ1Y3Qgb3BhbF9jb21wYWNrZXQgewor
CXUzMiByZXNlcnZlZDA7CisJdTggZXh0ZW5kZWRDb21JRFs0XTsKKwl1MzIgb3V0c3RhbmRpbmdE
YXRhOworCXUzMiBtaW5UcmFuc2ZlcjsKKwl1MzIgbGVuZ3RoOworfTsKKworLyogUGFja2V0IHN0
cnVjdHVyZS4gKi8KK3N0cnVjdCBvcGFsX3BhY2tldCB7CisJdTMyIFRTTjsKKwl1MzIgSFNOOwor
CXUzMiBzZXFfbnVtYmVyOworCXUxNiByZXNlcnZlZDA7CisJdTE2IGFja190eXBlOworCXUzMiBh
Y2tub3dsZWRnbWVudDsKKwl1MzIgbGVuZ3RoOworfTsKKworLyogRGF0YSBzdWIgcGFja2V0IGhl
YWRlciAqLworc3RydWN0IG9wYWxfZGF0YV9zdWJwYWNrZXQgeworCXU4IHJlc2VydmVkMFs2XTsK
Kwl1MTYga2luZDsKKwl1MzIgbGVuZ3RoOworfTsKKworLyogaGVhZGVyIG9mIGEgcmVzcG9uc2Ug
Ki8KK3N0cnVjdCBvcGFsX2hlYWRlciB7CisJc3RydWN0IG9wYWxfY29tcGFja2V0IGNwOworCXN0
cnVjdCBvcGFsX3BhY2tldCBwa3Q7CisJc3RydWN0IG9wYWxfZGF0YV9zdWJwYWNrZXQgc3VicGt0
OworfTsKKworI2RlZmluZSBGQ19UUEVSICAgICAgIDB4MDAwMQorI2RlZmluZSBGQ19MT0NLSU5H
ICAgIDB4MDAwMgorI2RlZmluZSBGQ19HRU9NRVRSWSAgIDB4MDAwMworI2RlZmluZSBGQ19FTlRF
UlBSSVNFIDB4MDEwMAorI2RlZmluZSBGQ19EQVRBU1RPUkUgIDB4MDIwMgorI2RlZmluZSBGQ19T
SU5HTEVVU0VSIDB4MDIwMQorI2RlZmluZSBGQ19PUEFMVjEwMCAgIDB4MDIwMAorI2RlZmluZSBG
Q19PUEFMVjIwMCAgIDB4MDIwMworCisvKgorICogVGhlIERpc2NvdmVyeSAwIEhlYWRlci4gQXMg
ZGVmaW5lZCBpbgorICogT3BhbCBTU0MgRG9jdW1lbnRhdGlvbgorICovCitzdHJ1Y3QgZDBfaGVh
ZGVyIHsKKwl1MzIgbGVuZ3RoOyAvKiB0aGUgbGVuZ3RoIG9mIHRoZSBoZWFkZXIgNDggaW4gMi4w
MC4xMDAgKi8KKwl1MzIgcmV2aXNpb247IC8qKjwgcmV2aXNpb24gb2YgdGhlIGhlYWRlciAxIGlu
IDIuMDAuMTAwICovCisJdTMyIHJlc2VydmVkMDE7CisJdTMyIHJlc2VydmVkMDI7CisJLyoKKwkg
KiB0aGUgcmVtYWluZGVyIG9mIHRoZSBzdHJ1Y3R1cmUgaXMgdmVuZG9yIHNwZWNpZmljIGFuZCB3
aWxsIG5vdCBiZQorCSAqIGFkZHJlc3NlZCBub3cKKwkgKi8KKwl1OCBpZ25vcmVkWzMyXTsKK307
CisKKy8qCisgKiBUUGVyIEZlYXR1cmUgRGVzY3JpcHRvci4gQ29udGFpbnMgZmxhZ3MgaW5kaWNh
dGluZyBzdXBwb3J0IGZvciB0aGUKKyAqIFRQZXIgZmVhdHVyZXMgZGVzY3JpYmVkIGluIHRoZSBP
UEFMIHNwZWNpZmljYXRpb24uIFRoZSBuYW1lcyBtYXRjaCB0aGUKKyAqIE9QQUwgdGVybWlub2xv
Z3kKKyAqCisgKiBjb2RlID09IDB4MDAxIGluIDIuMDAuMTAwCisgKi8KK3N0cnVjdCBkMF90cGVy
X2ZlYXR1cmVzIHsKKwkvKgorCSAqIHN1cHBvcnRlZF9mZWF0dXJlcyBiaXRzOgorCSAqIGJpdCA3
OiByZXNlcnZlZAorCSAqIGJpdCA2OiBjb20gSUQgbWFuYWdlbWVudAorCSAqIGJpdCA1OiByZXNl
cnZlZAorCSAqIGJpdCA0OiBzdHJlYW1pbmcgc3VwcG9ydAorCSAqIGJpdCAzOiBidWZmZXIgbWFu
YWdlbWVudAorCSAqIGJpdCAyOiBBQ0svTkFDSworCSAqIGJpdCAxOiBhc3luYworCSAqIGJpdCAw
OiBzeW5jCisJICovCisJdTggc3VwcG9ydGVkX2ZlYXR1cmVzOworCS8qCisJICogYnl0ZXMgNSB0
aHJvdWdoIDE1IGFyZSByZXNlcnZlZCwgYnV0IHdlIHJlcHJlc2VudCB0aGUgZmlyc3QgMyBhcwor
CSAqIHU4IHRvIGtlZXAgdGhlIG90aGVyIHR3byAzMmJpdHMgaW50ZWdlcnMgYWxpZ25lZC4KKwkg
Ki8KKwl1OCByZXNlcnZlZDAxWzNdOworCXUzMiByZXNlcnZlZDAyOworCXUzMiByZXNlcnZlZDAz
OworfTsKKworLyoKKyAqIExvY2tpbmcgRmVhdHVyZSBEZXNjcmlwdG9yLiBDb250YWlucyBmbGFn
cyBpbmRpY2F0aW5nIHN1cHBvcnQgZm9yIHRoZQorICogbG9ja2luZyBmZWF0dXJlcyBkZXNjcmli
ZWQgaW4gdGhlIE9QQUwgc3BlY2lmaWNhdGlvbi4gVGhlIG5hbWVzIG1hdGNoIHRoZQorICogT1BB
TCB0ZXJtaW5vbG9neQorICoKKyAqIGNvZGUgPT0gMHgwMDAyIGluIDIuMDAuMTAwCisgKi8KK3N0
cnVjdCBkMF9sb2NraW5nX2ZlYXR1cmVzIHsKKwkvKgorCSAqIHN1cHBvcnRlZF9mZWF0dXJlcyBi
aXRzOgorCSAqIGJpdHMgNi03OiByZXNlcnZlZAorCSAqIGJpdCA1OiBNQlIgZG9uZQorCSAqIGJp
dCA0OiBNQlIgZW5hYmxlZAorCSAqIGJpdCAzOiBtZWRpYSBlbmNyeXB0aW9uCisJICogYml0IDI6
IGxvY2tlZAorCSAqIGJpdCAxOiBsb2NraW5nIGVuYWJsZWQKKwkgKiBiaXQgMDogbG9ja2luZyBz
dXBwb3J0ZWQKKwkgKi8KKwl1OCBzdXBwb3J0ZWRfZmVhdHVyZXM7CisJLyoKKwkgKiBieXRlcyA1
IHRocm91Z2ggMTUgYXJlIHJlc2VydmVkLCBidXQgd2UgcmVwcmVzZW50IHRoZSBmaXJzdCAzIGFz
CisJICogdTggdG8ga2VlcCB0aGUgb3RoZXIgdHdvIDMyYml0cyBpbnRlZ2VycyBhbGlnbmVkLgor
CSAqLworCXU4IHJlc2VydmVkMDFbM107CisJdTMyIHJlc2VydmVkMDI7CisJdTMyIHJlc2VydmVk
MDM7Cit9OworCisvKgorICogR2VvbWV0cnkgRmVhdHVyZSBEZXNjcmlwdG9yLiBDb250YWlucyBm
bGFncyBpbmRpY2F0aW5nIHN1cHBvcnQgZm9yIHRoZQorICogZ2VvbWV0cnkgZmVhdHVyZXMgZGVz
Y3JpYmVkIGluIHRoZSBPUEFMIHNwZWNpZmljYXRpb24uIFRoZSBuYW1lcyBtYXRjaCB0aGUKKyAq
IE9QQUwgdGVybWlub2xvZ3kKKyAqCisgKiBjb2RlID09IDB4MDAwMyBpbiAyLjAwLjEwMAorICov
CitzdHJ1Y3QgZDBfZ2VvbWV0cnlfZmVhdHVyZXMgeworCS8qCisJICogc2tpcCAzMiBiaXRzIGZy
b20gaGVhZGVyLCBuZWVkZWQgdG8gYWxpZ24gdGhlIHN0cnVjdCB0byA2NCBiaXRzLgorCSAqLwor
CXU4IGhlYWRlcls0XTsKKwkvKgorCSAqIHJlc2VydmVkMDE6CisJICogYml0cyAxLTY6IHJlc2Vy
dmVkCisJICogYml0IDA6IGFsaWduCisJICovCisJdTggcmVzZXJ2ZWQwMTsKKwl1OCByZXNlcnZl
ZDAyWzddOworCXUzMiBsb2dpY2FsX2Jsb2NrX3NpemU7CisJdTY0IGFsaWdubWVudF9ncmFudWxh
cml0eTsKKwl1NjQgbG93ZXN0X2FsaWduZWRfbGJhOworfTsKKworLyoKKyAqIEVudGVycHJpc2Ug
U1NDIEZlYXR1cmUKKyAqCisgKiBjb2RlID09IDB4MDEwMAorICovCitzdHJ1Y3QgZDBfZW50ZXJw
cmlzZV9zc2MgeworCXUxNiBiYXNlQ29tSUQ7CisJdTE2IG51bUNvbUlEczsKKwkvKiByYW5nZV9j
cm9zc2luZzoKKwkgKiBiaXRzIDEtNjogcmVzZXJ2ZWQKKwkgKiBiaXQgMDogcmFuZ2UgY3Jvc3Np
bmcKKwkgKi8KKwl1OCByYW5nZV9jcm9zc2luZzsKKwl1OCByZXNlcnZlZDAxOworCXUxNiByZXNl
cnZlZDAyOworCXUzMiByZXNlcnZlZDAzOworCXUzMiByZXNlcnZlZDA0OworfTsKKworLyoKKyAq
IE9wYWwgVjEgZmVhdHVyZQorICoKKyAqIGNvZGUgPT0gMHgwMjAwCisgKi8KK3N0cnVjdCBkMF9v
cGFsX3YxMDAgeworCXUxNiBiYXNlQ29tSUQ7CisJdTE2IG51bUNvbUlEczsKK307CisKKy8qCisg
KiBTaW5nbGUgVXNlciBNb2RlIGZlYXR1cmUKKyAqCisgKiBjb2RlID09IDB4MDIwMQorICovCitz
dHJ1Y3QgZDBfc2luZ2xlX3VzZXJfbW9kZSB7CisJdTMyIG51bV9sb2NraW5nX29iamVjdHM7CisJ
LyogcmVzZXJ2ZWQwMToKKwkgKiBiaXQgMDogYW55CisJICogYml0IDE6IGFsbAorCSAqIGJpdCAy
OiBwb2xpY3kKKwkgKiBiaXRzIDMtNzogcmVzZXJ2ZWQKKwkgKi8KKwl1OCByZXNlcnZlZDAxOwor
CXU4IHJlc2VydmVkMDI7CisJdTE2IHJlc2VydmVkMDM7CisJdTMyIHJlc2VydmVkMDQ7Cit9Owor
CisvKgorICogQWRkaXRvbmFsIERhdGFzdG9yZXMgZmVhdHVyZQorICoKKyAqIGNvZGUgPT0gMHgw
MjAyCisgKi8KK3N0cnVjdCBkMF9kYXRhc3RvcmVfdGFibGUgeworCXUxNiByZXNlcnZlZDAxOwor
CXUxNiBtYXhfdGFibGVzOworCXUzMiBtYXhfc2l6ZV90YWJsZXM7CisJdTMyIHRhYmxlX3NpemVf
YWxpZ25tZW50OworfTsKKworLyoKKyAqIE9QQUwgMi4wIGZlYXR1cmUKKyAqCisgKiBjb2RlID09
IDB4MDIwMworICovCitzdHJ1Y3QgZDBfb3BhbF92MjAwIHsKKwl1MTYgYmFzZUNvbUlEOworCXUx
NiBudW1Db21JRHM7CisJLyogcmFuZ2VfY3Jvc3Npbmc6CisJICogYml0cyAxLTY6IHJlc2VydmVk
CisJICogYml0IDA6IHJhbmdlIGNyb3NzaW5nCisJICovCisJdTggcmFuZ2VfY3Jvc3Npbmc7CisJ
LyogbnVtX2xvY2tpbmdfYWRtaW5fYXV0aDoKKwkgKiBub3QgYWxpZ25lZCB0byAxNiBiaXRzLCBz
byB1c2UgdHdvIHU4LgorCSAqIHN0b3JlZCBpbiBiaWcgZW5kaWFuOgorCSAqIDA6IE1TQgorCSAq
IDE6IExTQgorCSAqLworCXU4IG51bV9sb2NraW5nX2FkbWluX2F1dGhbMl07CisJLyogbnVtX2xv
Y2tpbmdfdXNlcl9hdXRoOgorCSAqIG5vdCBhbGlnbmVkIHRvIDE2IGJpdHMsIHNvIHVzZSB0d28g
dTguCisJICogc3RvcmVkIGluIGJpZyBlbmRpYW46CisJICogMDogTVNCCisJICogMTogTFNCCisJ
ICovCisJdTggbnVtX2xvY2tpbmdfdXNlcl9hdXRoWzJdOworCXU4IGluaXRpYWxQSU47CisJdTgg
cmV2ZXJ0ZWRQSU47CisJdTggcmVzZXJ2ZWQwMTsKKwl1MzIgcmVzZXJ2ZWQwMjsKK307CisKKy8q
IFVuaW9uIG9mIGZlYXR1cmVzIHVzZWQgdG8gcGFyc2UgdGhlIGRpc2NvdmVyeSAwIHJlc3BvbnNl
ICovCitzdHJ1Y3QgZDBfZmVhdHVyZXMgeworCXUxNiBjb2RlOworCS8qCisJICogcl92ZXJzaW9u
IGJpdHM6CisJICogYml0cyA0LTc6IHZlcnNpb24KKwkgKiBiaXRzIDAtMzogcmVzZXJ2ZWQKKwkg
Ki8KKwl1OCByX3ZlcnNpb247CisJdTggbGVuZ3RoOworCXU4IGZlYXR1cmVzW107Cit9OworCitz
dHJ1Y3Qga2V5ICpyZXF1ZXN0X3VzZXJfa2V5KGNvbnN0IGNoYXIgKm1hc3Rlcl9kZXNjLCBjb25z
dCB1OCAqKm1hc3Rlcl9rZXksCisJCQkgICAgIHNpemVfdCAqbWFzdGVyX2tleWxlbik7CisKKyNl
bmRpZiAvKiBfTlZNRV9PUEFMX0lOVEVSTkFMX0ggKi8KZGlmZiAtLWdpdCBhL2xpYi9zZWQtb3Bh
bF9rZXkuYyBiL2xpYi9zZWQtb3BhbF9rZXkuYwpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAw
MDAwMDAwLi4wYjRkZTAxCi0tLSAvZGV2L251bGwKKysrIGIvbGliL3NlZC1vcGFsX2tleS5jCkBA
IC0wLDAgKzEsNDYgQEAKKy8qCisgKiBDb3B5cmlnaHQgwqkgMjAxNiBJbnRlbCBDb3Jwb3JhdGlv
bgorICoKKyAqIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0
byBhbnkgcGVyc29uIG9idGFpbmluZyBhCisgKiBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFz
c29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLAorICogdG8gZGVh
bCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQg
bGltaXRhdGlvbgorICogdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1
Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsCisgKiBhbmQvb3Igc2VsbCBjb3BpZXMgb2Yg
dGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUKKyAqIFNvZnR3
YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRp
dGlvbnM6CisgKgorICogVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlz
c2lvbiBub3RpY2UgKGluY2x1ZGluZyB0aGUgbmV4dAorICogcGFyYWdyYXBoKSBzaGFsbCBiZSBp
bmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZQorICog
U29mdHdhcmUuCisgKgorICogVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhP
VVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1IKKyAqIElNUExJRUQsIElOQ0xVRElO
RyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLAor
ICogRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4g
IElOIE5PIEVWRU5UIFNIQUxMCisgKiBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBC
RSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUgorICogTElBQklMSVRZLCBX
SEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJ
TkcKKyAqIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9S
IFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MKKyAqIElOIFRIRSBTT0ZUV0FSRS4KKyAqCisgKiBB
dXRob3I6CisgKiAgICBSYWZhZWwgQW50b2dub2xsaSA8cmFmYWVsLmFudG9nbm9sbGlAaW50ZWwu
Y29tPgorICovCisKKyNpbmNsdWRlIDxsaW51eC9rZXkuaD4KKyNpbmNsdWRlICJzZWQtb3BhbF9p
bnRlcm5hbC5oIgorCitzdHJ1Y3Qga2V5ICpyZXF1ZXN0X3VzZXJfa2V5KGNvbnN0IGNoYXIgKm1h
c3Rlcl9kZXNjLCBjb25zdCB1OCAqKm1hc3Rlcl9rZXksCisJCQkgICAgIHNpemVfdCAqbWFzdGVy
X2tleWxlbikKK3sKKwljb25zdCBzdHJ1Y3QgdXNlcl9rZXlfcGF5bG9hZCAqdXBheWxvYWQ7CisJ
c3RydWN0IGtleSAqdWtleTsKKworCXVrZXkgPSByZXF1ZXN0X2tleSgma2V5X3R5cGVfdXNlciwg
bWFzdGVyX2Rlc2MsIE5VTEwpOworCWlmIChJU19FUlIodWtleSkpCisJCWdvdG8gZXJyb3I7CisK
Kwlkb3duX3JlYWQoJnVrZXktPnNlbSk7CisJdXBheWxvYWQgPSB1c2VyX2tleV9wYXlsb2FkKHVr
ZXkpOworCSptYXN0ZXJfa2V5ID0gdXBheWxvYWQtPmRhdGE7CisJKm1hc3Rlcl9rZXlsZW4gPSB1
cGF5bG9hZC0+ZGF0YWxlbjsKK2Vycm9yOgorCXJldHVybiB1a2V5OworfQpkaWZmIC0tZ2l0IGEv
bGliL3NlZC5jIGIvbGliL3NlZC5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAu
LjA2Y2FjZDkKLS0tIC9kZXYvbnVsbAorKysgYi9saWIvc2VkLmMKQEAgLTAsMCArMSwzMDMgQEAK
KyNpbmNsdWRlIDxsaW51eC9ibGtkZXYuaD4KKyNpbmNsdWRlIDxsaW51eC9zZWQuaD4KKyNpbmNs
dWRlIDxsaW51eC9zZWQtb3BhbC5oPgorCisjaWZuZGVmIENPTkZJR19TRURfT1BBTAorc3RhdGlj
IGludCBzZWRfb3BhbF9zYXZlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRf
a2V5ICpzZWQpCisJeyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KK3N0YXRpYyBpbnQgc2VkX29wYWxf
bG9ja191bmxvY2soc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtl
eSkKKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQorc3RhdGljIGludCBzZWRfb3BhbF90YWtlX293
bmVyc2hpcChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQor
CXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9CitzdGF0aWMgaW50IHNlZF9vcGFsX2FjdGl2YXRlX2xz
cChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQorCXsgcmV0
dXJuIC1FT1BOT1RTVVBQOyB9CitzdGF0aWMgaW50IHNlZF9vcGFsX3NldF9wdyhzdHJ1Y3QgYmxv
Y2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQorCXsgcmV0dXJuIC1FT1BOT1RT
VVBQOyB9CitzdGF0aWMgaW50IHNlZF9vcGFsX2FjdGl2YXRlX3VzZXIoc3RydWN0IGJsb2NrX2Rl
dmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKKwl7IHJldHVybiAtRU9QTk9UU1VQUDsg
fQorc3RhdGljIGludCBzZWRfb3BhbF9yZXZlcnR0cGVyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJk
ZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCisJeyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KK3N0YXRp
YyBpbnQgc2VkX29wYWxfc2V0dXBfbG9ja2luZ19yYW5nZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpi
ZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQorCXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9CitzdGF0
aWMgaW50IHNlZF9vcGFsX2FkZHVzZXJfdG9fbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwg
c3RydWN0IHNlZF9rZXkgKmtleSkKKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQorc3RhdGljIGlu
dCBzZWRfb3BhbF9kb19tYnIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9r
ZXkgKmtleSkKKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQorc3RhdGljIGludCBzZWRfb3BhbF9l
cmFzZV9scihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQor
CXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9CisKKyNlbHNlCisKK3N0YXRpYyBpbnQgc2VkX29wYWxf
c2F2ZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQorewor
CisJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8
CisJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQorCQlyZXR1cm4gLUVPUE5PVFNV
UFA7CisKKwlyZXR1cm4gb3BhbF9zYXZlKGJkZXYsIGtleSk7Cit9CisKK3N0YXRpYyBpbnQgc2Vk
X29wYWxfbG9ja191bmxvY2soc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9r
ZXkgKmtleSkKK3sKKworCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRf
ZGlzay0+Zm9wcyB8fAorCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKKwkJcmV0
dXJuIC1FT1BOT1RTVVBQOworCisJcmV0dXJuIG9wYWxfbG9ja191bmxvY2soYmRldiwga2V5KTsK
K30KKworc3RhdGljIGludCBzZWRfb3BhbF90YWtlX293bmVyc2hpcChzdHJ1Y3QgYmxvY2tfZGV2
aWNlICpiZGV2LAorCQkJCSAgIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlpZiAoIWJkZXYg
fHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKKwkgICAgIWJkZXYt
PmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCisJCXJldHVybiAtRU9QTk9UU1VQUDsKKworCXJldHVy
biBvcGFsX3Rha2Vfb3duZXJzaGlwKGJkZXYsIGtleSk7Cit9CisKK3N0YXRpYyBpbnQgc2VkX29w
YWxfYWN0aXZhdGVfbHNwKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJCQkJIHN0cnVjdCBz
ZWRfa2V5ICprZXkpCit7CisKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYt
PmJkX2Rpc2stPmZvcHMgfHwKKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCisJ
CXJldHVybiAtRU9QTk9UU1VQUDsKKworCXJldHVybiBvcGFsX2FjdGl2YXRlX2xzcChiZGV2LCBr
ZXkpOworfQorCitzdGF0aWMgaW50IHNlZF9vcGFsX3NldF9wdyhzdHJ1Y3QgYmxvY2tfZGV2aWNl
ICpiZGV2LAorCQkJICAgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKworCWlmICghYmRldiB8fCAh
YmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlzay0+Zm9wcyB8fAorCSAgICAhYmRldi0+YmRf
ZGlzay0+Zm9wcy0+c2VjX29wcykKKwkJcmV0dXJuIC1FT1BOT1RTVVBQOworCisJcmV0dXJuIG9w
YWxfc2V0X25ld19wdyhiZGV2LCBrZXkpOworfQorCitzdGF0aWMgaW50IHNlZF9vcGFsX2FjdGl2
YXRlX3VzZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKKwkJCQkgIHN0cnVjdCBzZWRfa2V5
ICprZXkpCit7CisKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rp
c2stPmZvcHMgfHwKKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCisJCXJldHVy
biAtRU9QTk9UU1VQUDsKKworCXJldHVybiBvcGFsX2FjdGl2YXRlX3VzZXIoYmRldiwga2V5KTsK
K30KKworc3RhdGljIGludCBzZWRfb3BhbF9yZXZlcnR0cGVyKHN0cnVjdCBibG9ja19kZXZpY2Ug
KmJkZXYsCisJCQkgICAgICAgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKworCWlmICghYmRldiB8
fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlzay0+Zm9wcyB8fAorCSAgICAhYmRldi0+
YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKKwkJcmV0dXJuIC1FT1BOT1RTVVBQOworCisJcmV0dXJu
IG9wYWxfcmV2ZXJ0dHBlcihiZGV2LCBrZXkpOworfQorCitzdGF0aWMgaW50IHNlZF9vcGFsX3Nl
dHVwX2xyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJCQkgICAgIHN0cnVjdCBzZWRfa2V5
ICprZXkpCit7CisKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rp
c2stPmZvcHMgfHwKKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCisJCXJldHVy
biAtRU9QTk9UU1VQUDsKKworCXJldHVybiBvcGFsX3NldHVwX2xvY2tpbmdfcmFuZ2UoYmRldiwg
a2V5KTsKK30KKworc3RhdGljIGludCBzZWRfb3BhbF9hZGR1c2VyX3RvX2xyKHN0cnVjdCBibG9j
a19kZXZpY2UgKmJkZXYsCisJCQkgICAgIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisKKwlpZiAo
IWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKKwkgICAg
IWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCisJCXJldHVybiAtRU9QTk9UU1VQUDsKKwor
CXJldHVybiBvcGFsX2FkZF91c2VyX3RvX2xyKGJkZXYsIGtleSk7Cit9CisKK3N0YXRpYyBpbnQg
c2VkX29wYWxfZG9fbWJyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJCQkgICBzdHJ1Y3Qg
c2VkX2tleSAqa2V5KQoreworCisJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFiZGV2
LT5iZF9kaXNrLT5mb3BzIHx8CisJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQor
CQlyZXR1cm4gLUVPUE5PVFNVUFA7CisKKwlyZXR1cm4gb3BhbF9lbmFibGVfZGlzYWJsZV9zaGFk
b3dfbWJyKGJkZXYsIGtleSk7Cit9CisKK3N0YXRpYyBpbnQgc2VkX29wYWxfZXJhc2VfbHIoc3Ry
dWN0IGJsb2NrX2RldmljZSAqYmRldiwKKwkJCSAgICAgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sK
KworCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlzay0+Zm9wcyB8
fAorCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKKwkJcmV0dXJuIC1FT1BOT1RT
VVBQOworCisJcmV0dXJuIG9wYWxfZXJhc2VfbG9ja2luZ19yYW5nZShiZGV2LCBrZXkpOworfQor
I2VuZGlmCisKK2ludCBzZWRfc2F2ZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qg
c2VkX2tleSAqa2V5KQoreworCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+
YmRfZGlzay0+Zm9wcyB8fAorCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKKwkJ
cmV0dXJuIC1FT1BOT1RTVVBQOworCisJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7CisJY2FzZSBP
UEFMX0xPQ0tfVU5MT0NLOgorCQlyZXR1cm4gc2VkX29wYWxfc2F2ZShiZGV2LCBrZXkpOworCX0K
KworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworaW50IHNlZF9sb2NrX3VubG9jayhzdHJ1Y3Qg
YmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQoreworCWlmICghYmRldiB8
fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlzay0+Zm9wcyB8fAorCSAgICAhYmRldi0+
YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKKwkJcmV0dXJuIC1FT1BOT1RTVVBQOworCisJc3dpdGNo
IChrZXktPnNlZF90eXBlKSB7CisJY2FzZSBPUEFMX0xPQ0tfVU5MT0NLOgorCQlyZXR1cm4gc2Vk
X29wYWxfbG9ja191bmxvY2soYmRldiwga2V5KTsKKwl9CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7
Cit9CisKK2ludCBzZWRfdGFrZV9vd25lcnNoaXAoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwg
c3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwg
IWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19v
cHMpCisJCXJldHVybiAtRU9QTk9UU1VQUDsKKworCXN3aXRjaCAoa2V5LT5zZWRfdHlwZSkgewor
CWNhc2UgT1BBTDoKKwkJcmV0dXJuIHNlZF9vcGFsX3Rha2Vfb3duZXJzaGlwKGJkZXYsIGtleSk7
CisJfQorCisJcmV0dXJuIC1FT1BOT1RTVVBQOworfQorCitpbnQgc2VkX2FjdGl2YXRlX2xzcChz
dHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQoreworCWlmICgh
YmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlzay0+Zm9wcyB8fAorCSAgICAh
YmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKKwkJcmV0dXJuIC1FT1BOT1RTVVBQOworCisJ
c3dpdGNoIChrZXktPnNlZF90eXBlKSB7CisJY2FzZSBPUEFMOgorCQlyZXR1cm4gc2VkX29wYWxf
YWN0aXZhdGVfbHNwKGJkZXYsIGtleSk7CisJfQorCisJcmV0dXJuIC1FT1BOT1RTVVBQOworfQor
CitpbnQgc2VkX3NldF9wdyhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tl
eSAqa2V5KQoreworCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlz
ay0+Zm9wcyB8fAorCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKKwkJcmV0dXJu
IC1FT1BOT1RTVVBQOworCisJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7CisJY2FzZSBPUEFMX1BX
OgorCQlyZXR1cm4gc2VkX29wYWxfc2V0X3B3KGJkZXYsIGtleSk7CisJfQorCisJcmV0dXJuIC1F
T1BOT1RTVVBQOworfQorCitpbnQgc2VkX2FjdGl2YXRlX3VzZXIoc3RydWN0IGJsb2NrX2Rldmlj
ZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJk
X2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZv
cHMtPnNlY19vcHMpCisJCXJldHVybiAtRU9QTk9UU1VQUDsKKworCXN3aXRjaCAoa2V5LT5zZWRf
dHlwZSkgeworCWNhc2UgT1BBTF9BQ1RfVVNSOgorCQlyZXR1cm4gc2VkX29wYWxfYWN0aXZhdGVf
dXNlcihiZGV2LCBrZXkpOworCX0KKworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworaW50IHNl
ZF9yZXZlcnR0cGVyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICpr
ZXkpCit7CisJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFiZGV2LT5iZF9kaXNrLT5m
b3BzIHx8CisJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQorCQlyZXR1cm4gLUVP
UE5PVFNVUFA7CisKKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsKKwljYXNlIE9QQUw6CisJCXJl
dHVybiBzZWRfb3BhbF9yZXZlcnR0cGVyKGJkZXYsIGtleSk7CisJfQorCisJcmV0dXJuIC1FT1BO
T1RTVVBQOworfQorCitpbnQgc2VkX3NldHVwX2xvY2tpbmdfcmFuZ2Uoc3RydWN0IGJsb2NrX2Rl
dmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKK3sKKwlpZiAoIWJkZXYgfHwgIWJkZXYt
PmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKKwkgICAgIWJkZXYtPmJkX2Rpc2st
PmZvcHMtPnNlY19vcHMpCisJCXJldHVybiAtRU9QTk9UU1VQUDsKKworCXN3aXRjaCAoa2V5LT5z
ZWRfdHlwZSkgeworCWNhc2UgT1BBTF9MUl9TRVRVUDoKKwkJcmV0dXJuIHNlZF9vcGFsX3NldHVw
X2xyKGJkZXYsIGtleSk7CisJfQorCisJcmV0dXJuIC1FT1BOT1RTVVBQOworfQorCitpbnQgc2Vk
X2FkZHVzZXJfdG9fbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkg
KmtleSkKK3sKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2st
PmZvcHMgfHwKKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCisJCXJldHVybiAt
RU9QTk9UU1VQUDsKKworCXN3aXRjaCAoa2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BBTF9MT0NL
X1VOTE9DSzoKKwkJcmV0dXJuIHNlZF9vcGFsX2FkZHVzZXJfdG9fbHIoYmRldiwga2V5KTsKKwl9
CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisKK2ludCBzZWRfZG9fbWJyKHN0cnVjdCBibG9j
a19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCit7CisJaWYgKCFiZGV2IHx8ICFi
ZGV2LT5iZF9kaXNrIHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8CisJICAgICFiZGV2LT5iZF9k
aXNrLT5mb3BzLT5zZWNfb3BzKQorCQlyZXR1cm4gLUVPUE5PVFNVUFA7CisKKwlzd2l0Y2ggKGtl
eS0+c2VkX3R5cGUpIHsKKwljYXNlIE9QQUxfTUJSX0RBVEE6CisJCXJldHVybiBzZWRfb3BhbF9k
b19tYnIoYmRldiwga2V5KTsKKwl9CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisKK2ludCBz
ZWRfZXJhc2VfbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtl
eSkKK3sKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZv
cHMgfHwKKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCisJCXJldHVybiAtRU9Q
Tk9UU1VQUDsKKworCXN3aXRjaCAoa2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BBTDoKKwkJcmV0
dXJuIHNlZF9vcGFsX2VyYXNlX2xyKGJkZXYsIGtleSk7CisJfQorCisJcmV0dXJuIC1FT1BOT1RT
VVBQOworfQotLSAKMi43LjQKCgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fXwpMaW51eC1udm1lIG1haWxpbmcgbGlzdApMaW51eC1udm1lQGxpc3RzLmluZnJh
ZGVhZC5vcmcKaHR0cDovL2xpc3RzLmluZnJhZGVhZC5vcmcvbWFpbG1hbi9saXN0aW5mby9saW51
eC1udm1lCg==

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

* [RFC PATCH 2/6] lib: Add Sed-opal library
@ 2016-10-31 21:58   ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 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          | 3337 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/sed-opal_internal.h |  586 +++++++++
 lib/sed-opal_key.c      |   46 +
 lib/sed.c               |  303 +++++
 4 files changed, 4272 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..10b3348
--- /dev/null
+++ b/lib/sed-opal.c
@@ -0,0 +1,3337 @@
+/*
+ * 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;
+	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 int __opal_send_cmd(struct opal_suspend_unlk *data, u16 comID,
+			   void *buffer, size_t buflen, sec_cb *cb,
+			   void *cb_data)
+{
+	return data->ops.send(data->data, comID, TCG_SECP_01, buffer, buflen,
+			     cb, cb_data);
+}
+static int _opal_send_cmd(struct block_device *bdev, u16 comID,
+			  void *buffer, size_t buflen,
+			  sec_cb *cb, void *cb_data)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+
+	return ops->send(bdev->bd_disk->private_data, comID,
+			 TCG_SECP_01, buffer, buflen,
+			 cb, cb_data);
+}
+
+static int __opal_recv_cmd(struct opal_suspend_unlk *data, u16 comID,
+			   void *buffer, size_t buflen, sec_cb *cb,
+			   void *cb_data)
+{
+	return data->ops.recv(data->data, comID, TCG_SECP_01, buffer, buflen,
+			     cb, cb_data);
+}
+
+static int _opal_recv_cmd(struct block_device *bdev, u16 comID,
+			  void *buffer, size_t buflen,
+			  sec_cb *cb, void *cb_data)
+{
+	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
+
+	return ops->recv(bdev->bd_disk->private_data, comID,
+			 TCG_SECP_01, buffer, buflen,
+			 cb, cb_data);
+}
+
+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);
+	if (dev->resume_from_suspend)
+		__opal_recv_cmd(dev->resume_data, dev->comID,
+				buffer, buflen, opal_send_cb_cont, dev);
+	else
+		_opal_recv_cmd(dev->bdev, dev->comID, buffer, buflen,
+			       opal_send_cb_cont, dev);
+}
+
+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);
+	if (dev->resume_from_suspend)
+		__opal_recv_cmd(dev->resume_data, dev->comID,
+				buffer, buflen, opal_send_cb_cont, dev);
+	else
+		_opal_recv_cmd(dev->bdev, dev->comID, buffer, buflen,
+			       opal_send_cb_cont, dev);
+}
+
+static int opal_send_recv(struct opal_dev *dev, sec_cb *cb, void *cb_data)
+{
+	size_t buflen = IO_BUFFER_LENGTH;
+	void *buffer = dev->cmd.cmd;
+	int ret;
+
+	dev->cmd.cb = cb;
+	dev->cmd.cb_data = cb_data;
+	if (dev->resume_from_suspend)
+		ret = __opal_send_cmd(dev->resume_data, dev->comID, buffer,
+				      buflen, opal_send_cb, dev);
+	else
+		ret = _opal_send_cmd(dev->bdev, dev->comID, buffer, buflen,
+				     opal_send_cb, dev);
+
+	return ret;
+}
+
+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;
+		default:
+			if (be16_to_cpu(body->code) > 0xbfff) {
+				/* vendor specific, just ignore */
+			} else {
+				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)
+{
+	memset(dev->cmd.resp, 0, IO_BUFFER_LENGTH);
+
+	if (dev->resume_from_suspend)
+		return __opal_recv_cmd(dev->resume_data, 0x0001,
+				       dev->cmd.resp, IO_BUFFER_LENGTH,
+				       opal_discovery0_end, dev);
+
+	return _opal_recv_cmd(dev->bdev, 0x0001, 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");
+		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);
+
+		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);
+
+	ret = opal_send_recv(dev, cont, dev);
+	if (ret)
+		pr_err("%s: Error running command: %d\n",
+		       dev->disk_name, ret);
+
+	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 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];
+
+	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 = 0x41;
+
+	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 = 0x41;
+
+	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 = 0x41;
+
+	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 Dont/Not 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 Dont/Not 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)
+{
+	if (build_end_opal_session(dev) < 0)
+		return -1;
+	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;
+
+	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;
+
+	if (use_new)
+		return alloc_opal_dev(bdev, lr);
+
+	dev = get_registered_opal_dev(bdev, lr);
+	if (!dev) {
+		dev = alloc_opal_dev(bdev, lr);
+		if (!dev)
+			return NULL;
+	}
+	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;
+}
+
+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;
+
+	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
+	};
+	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 };
+	const opal_step _unlock_funcs_SUM[] = {
+		opal_discovery0,
+		start_auth_opal_session,
+		lock_unlock_locking_range,
+		end_opal_session,
+		NULL
+	};
+	const opal_step _unlock_funcs[] = {
+		opal_discovery0,
+		start_auth_opal_session,
+		lock_unlock_locking_range,
+		end_opal_session,
+		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 = _unlock_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..c9d3883
--- /dev/null
+++ b/lib/sed-opal_internal.h
@@ -0,0 +1,586 @@
+/*
+ * 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
+
+static const char *opal_errors[19] = {
+	"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 >= sizeof(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..06cacd9
--- /dev/null
+++ b/lib/sed.c
@@ -0,0 +1,303 @@
+#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 int sed_opal_save(struct block_device *bdev, struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_save(bdev, key);
+}
+
+static int sed_opal_lock_unlock(struct block_device *bdev, struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_lock_unlock(bdev, key);
+}
+
+static int sed_opal_take_ownership(struct block_device *bdev,
+				   struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_take_ownership(bdev, key);
+}
+
+static int sed_opal_activate_lsp(struct block_device *bdev,
+				 struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_activate_lsp(bdev, key);
+}
+
+static int sed_opal_set_pw(struct block_device *bdev,
+			   struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_set_new_pw(bdev, key);
+}
+
+static int sed_opal_activate_user(struct block_device *bdev,
+				  struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_activate_user(bdev, key);
+}
+
+static int sed_opal_reverttper(struct block_device *bdev,
+			       struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_reverttper(bdev, key);
+}
+
+static int sed_opal_setup_lr(struct block_device *bdev,
+			     struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_setup_locking_range(bdev, key);
+}
+
+static int sed_opal_adduser_to_lr(struct block_device *bdev,
+			     struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_add_user_to_lr(bdev, key);
+}
+
+static int sed_opal_do_mbr(struct block_device *bdev,
+			   struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_enable_disable_shadow_mbr(bdev, key);
+}
+
+static int sed_opal_erase_lr(struct block_device *bdev,
+			     struct sed_key *key)
+{
+
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	return opal_erase_locking_range(bdev, key);
+}
+#endif
+
+int sed_save(struct block_device *bdev, struct sed_key *key)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	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)
+{
+	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
+	    !bdev->bd_disk->fops->sec_ops)
+		return -EOPNOTSUPP;
+
+	switch (key->sed_type) {
+	case OPAL:
+		return sed_opal_erase_lr(bdev, key);
+	}
+
+	return -EOPNOTSUPP;
+}
-- 
2.7.4

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

* [RFC PATCH 3/6] lib: Add Sed to Kconfig and Makefile
  2016-10-31 21:58 ` Scott Bauer
@ 2016-10-31 21:58   ` Scott Bauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, 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] 32+ messages in thread

* [RFC PATCH 3/6] lib: Add Sed to Kconfig and Makefile
@ 2016-10-31 21:58   ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 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] 32+ messages in thread

* [RFC PATCH 4/6] include: Add sec_ops to block device operations
  2016-10-31 21:58 ` Scott Bauer
@ 2016-10-31 21:58   ` Scott Bauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, 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] 32+ messages in thread

* [RFC PATCH 4/6] include: Add sec_ops to block device operations
@ 2016-10-31 21:58   ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 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] 32+ messages in thread

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
  2016-10-31 21:58 ` Scott Bauer
@ 2016-10-31 21:58   ` Scott Bauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, Scott Bauer

This patch adds a new function unlock_from_suspend which is used
to call into the Opal code to attempt to unlock Locking Ranges,
after a suspend-to-RAM.

The patch also modifies nvme_req_needs_retry to *not* retry
a request that failed due to a NVME_SC_ACCESS_DENIED, which
gets returned if a request is attempting to much with a locked
range. The range won't magically unlock itself without user
interaction so we shouldn't retry the request -- it will fail
again.

Signed-off-by: Scott Bauer <scott.bauer@intel.com>
Signed-off-by: Rafael Antognolli <Rafael.Antognolli@intel.com>
---
 drivers/nvme/host/core.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/nvme/host/nvme.h |   4 +-
 drivers/nvme/host/pci.c  |  19 ++++---
 3 files changed, 149 insertions(+), 8 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 79e679d..1321331 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,137 @@ 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_insert_rq(struct request_queue *q, struct request *rq,
+			  int at_head, rq_end_io_fn *done)
+{
+	WARN_ON(rq->cmd_type == REQ_TYPE_FS);
+
+	rq->end_io = done;
+
+	if (!q->mq_ops)
+		return -EINVAL;
+
+	blk_mq_insert_request(rq, at_head, true, true);
+
+	return 0;
+}
+
+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;//bdev->bd_disk->private_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;
+	//req->rq_disk = bdev->bd_disk;
+
+	return nvme_insert_rq(q, req, 1, sec_submit_endio);
+
+err_free:
+	kfree(sed_data);
+	return ret;
+}
+
+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);
+}
+
+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,
+};
+
 static const struct block_device_operations nvme_fops = {
 	.owner		= THIS_MODULE,
 	.ioctl		= nvme_ioctl,
@@ -1076,6 +1209,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..ac7e5b1 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;
 }
@@ -259,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..18fd878 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"
 
@@ -582,6 +583,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 	struct nvme_command cmnd;
 	unsigned map_len;
 	int ret = BLK_MQ_RQ_QUEUE_OK;
+	unsigned long flags;
 
 	/*
 	 * If formated with metadata, require the block layer provide a buffer
@@ -614,18 +616,18 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 	cmnd.common.command_id = req->tag;
 	blk_mq_start_request(req);
 
-	spin_lock_irq(&nvmeq->q_lock);
+	spin_lock_irqsave(&nvmeq->q_lock, flags);
 	if (unlikely(nvmeq->cq_vector < 0)) {
 		if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
 			ret = BLK_MQ_RQ_QUEUE_BUSY;
 		else
 			ret = BLK_MQ_RQ_QUEUE_ERROR;
-		spin_unlock_irq(&nvmeq->q_lock);
+		spin_unlock_irqrestore(&nvmeq->q_lock, flags);
 		goto out;
 	}
 	__nvme_submit_cmd(nvmeq, &cmnd);
 	nvme_process_cq(nvmeq);
-	spin_unlock_irq(&nvmeq->q_lock);
+	spin_unlock_irqrestore(&nvmeq->q_lock, flags);
 	return BLK_MQ_RQ_QUEUE_OK;
 out:
 	nvme_free_iod(dev, req);
@@ -635,11 +637,11 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 static void nvme_complete_rq(struct request *req)
 {
 	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
-	struct nvme_dev *dev = iod->nvmeq->dev;
+	struct nvme_queue *nvmeq = iod->nvmeq;
+	struct nvme_dev *dev = nvmeq->dev;
 	int error = 0;
 
 	nvme_unmap_data(dev, req);
-
 	if (unlikely(req->errors)) {
 		if (nvme_req_needs_retry(req, req->errors)) {
 			req->retries++;
@@ -658,7 +660,6 @@ static void nvme_complete_rq(struct request *req)
 			"completing aborted command with status: %04x\n",
 			req->errors);
 	}
-
 	blk_mq_end_request(req, error);
 }
 
@@ -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] 32+ messages in thread

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
@ 2016-10-31 21:58   ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 UTC (permalink / raw)


This patch adds a new function unlock_from_suspend which is used
to call into the Opal code to attempt to unlock Locking Ranges,
after a suspend-to-RAM.

The patch also modifies nvme_req_needs_retry to *not* retry
a request that failed due to a NVME_SC_ACCESS_DENIED, which
gets returned if a request is attempting to much with a locked
range. The range won't magically unlock itself without user
interaction so we shouldn't retry the request -- it will fail
again.

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 | 134 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/nvme/host/nvme.h |   4 +-
 drivers/nvme/host/pci.c  |  19 ++++---
 3 files changed, 149 insertions(+), 8 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 79e679d..1321331 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,137 @@ 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_insert_rq(struct request_queue *q, struct request *rq,
+			  int at_head, rq_end_io_fn *done)
+{
+	WARN_ON(rq->cmd_type == REQ_TYPE_FS);
+
+	rq->end_io = done;
+
+	if (!q->mq_ops)
+		return -EINVAL;
+
+	blk_mq_insert_request(rq, at_head, true, true);
+
+	return 0;
+}
+
+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;//bdev->bd_disk->private_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;
+	//req->rq_disk = bdev->bd_disk;
+
+	return nvme_insert_rq(q, req, 1, sec_submit_endio);
+
+err_free:
+	kfree(sed_data);
+	return ret;
+}
+
+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);
+}
+
+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,
+};
+
 static const struct block_device_operations nvme_fops = {
 	.owner		= THIS_MODULE,
 	.ioctl		= nvme_ioctl,
@@ -1076,6 +1209,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..ac7e5b1 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;
 }
@@ -259,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..18fd878 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"
 
@@ -582,6 +583,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 	struct nvme_command cmnd;
 	unsigned map_len;
 	int ret = BLK_MQ_RQ_QUEUE_OK;
+	unsigned long flags;
 
 	/*
 	 * If formated with metadata, require the block layer provide a buffer
@@ -614,18 +616,18 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 	cmnd.common.command_id = req->tag;
 	blk_mq_start_request(req);
 
-	spin_lock_irq(&nvmeq->q_lock);
+	spin_lock_irqsave(&nvmeq->q_lock, flags);
 	if (unlikely(nvmeq->cq_vector < 0)) {
 		if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
 			ret = BLK_MQ_RQ_QUEUE_BUSY;
 		else
 			ret = BLK_MQ_RQ_QUEUE_ERROR;
-		spin_unlock_irq(&nvmeq->q_lock);
+		spin_unlock_irqrestore(&nvmeq->q_lock, flags);
 		goto out;
 	}
 	__nvme_submit_cmd(nvmeq, &cmnd);
 	nvme_process_cq(nvmeq);
-	spin_unlock_irq(&nvmeq->q_lock);
+	spin_unlock_irqrestore(&nvmeq->q_lock, flags);
 	return BLK_MQ_RQ_QUEUE_OK;
 out:
 	nvme_free_iod(dev, req);
@@ -635,11 +637,11 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
 static void nvme_complete_rq(struct request *req)
 {
 	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
-	struct nvme_dev *dev = iod->nvmeq->dev;
+	struct nvme_queue *nvmeq = iod->nvmeq;
+	struct nvme_dev *dev = nvmeq->dev;
 	int error = 0;
 
 	nvme_unmap_data(dev, req);
-
 	if (unlikely(req->errors)) {
 		if (nvme_req_needs_retry(req, req->errors)) {
 			req->retries++;
@@ -658,7 +660,6 @@ static void nvme_complete_rq(struct request *req)
 			"completing aborted command with status: %04x\n",
 			req->errors);
 	}
-
 	blk_mq_end_request(req, error);
 }
 
@@ -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] 32+ messages in thread

* [RFC PATCH 6/6] block: ioctl: Wire up Sed to block ioctls
  2016-10-31 21:58 ` Scott Bauer
@ 2016-10-31 21:58   ` Scott Bauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 UTC (permalink / raw)
  To: linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block, 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] 32+ messages in thread

* [RFC PATCH 6/6] block: ioctl: Wire up Sed to block ioctls
@ 2016-10-31 21:58   ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-10-31 21:58 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] 32+ messages in thread

* Re: [RFC PATCH 5/6] nvme: Add unlock_from_suspend
  2016-10-31 21:58   ` Scott Bauer
@ 2016-11-01  8:18     ` Sagi Grimberg
  -1 siblings, 0 replies; 32+ messages in thread
From: Sagi Grimberg @ 2016-11-01  8:18 UTC (permalink / raw)
  To: Scott Bauer, linux-nvme
  Cc: Rafael.Antognolli, axboe, keith.busch, jonathan.derrick,
	j.naumann, hch, linux-block


> +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_insert_rq(struct request_queue *q, struct request *rq,
> +			  int at_head, rq_end_io_fn *done)
> +{
> +	WARN_ON(rq->cmd_type == REQ_TYPE_FS);
> +
> +	rq->end_io = done;
> +
> +	if (!q->mq_ops)
> +		return -EINVAL;
> +
> +	blk_mq_insert_request(rq, at_head, true, true);
> +
> +	return 0;
> +}

No need for this function... you control the call site...

> +
> +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;//bdev->bd_disk->private_data;

??

you don't even have data anywhere in here...

> +
> +	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;
> +	//req->rq_disk = bdev->bd_disk;

??

> +
> +	return nvme_insert_rq(q, req, 1, sec_submit_endio);

No need to introduce nvme_insert_rq at all, just call
blk_mq_insert_request (other examples call blk_execute_rq_nowait
but its pretty much the same...)

> @@ -582,6 +583,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
>  	struct nvme_command cmnd;
>  	unsigned map_len;
>  	int ret = BLK_MQ_RQ_QUEUE_OK;
> +	unsigned long flags;
>
>  	/*
>  	 * If formated with metadata, require the block layer provide a buffer
> @@ -614,18 +616,18 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
>  	cmnd.common.command_id = req->tag;
>  	blk_mq_start_request(req);
>
> -	spin_lock_irq(&nvmeq->q_lock);
> +	spin_lock_irqsave(&nvmeq->q_lock, flags);
>  	if (unlikely(nvmeq->cq_vector < 0)) {
>  		if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
>  			ret = BLK_MQ_RQ_QUEUE_BUSY;
>  		else
>  			ret = BLK_MQ_RQ_QUEUE_ERROR;
> -		spin_unlock_irq(&nvmeq->q_lock);
> +		spin_unlock_irqrestore(&nvmeq->q_lock, flags);
>  		goto out;
>  	}
>  	__nvme_submit_cmd(nvmeq, &cmnd);
>  	nvme_process_cq(nvmeq);
> -	spin_unlock_irq(&nvmeq->q_lock);
> +	spin_unlock_irqrestore(&nvmeq->q_lock, flags);

No documentation why this is needed...

>  	return BLK_MQ_RQ_QUEUE_OK;
>  out:
>  	nvme_free_iod(dev, req);
> @@ -635,11 +637,11 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
>  static void nvme_complete_rq(struct request *req)
>  {
>  	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
> -	struct nvme_dev *dev = iod->nvmeq->dev;
> +	struct nvme_queue *nvmeq = iod->nvmeq;
> +	struct nvme_dev *dev = nvmeq->dev;

This is a cleanup that should go in a different patch...

>  	int error = 0;
>
>  	nvme_unmap_data(dev, req);
> -

Same here...

>  	if (unlikely(req->errors)) {
>  		if (nvme_req_needs_retry(req, req->errors)) {
>  			req->retries++;
> @@ -658,7 +660,6 @@ static void nvme_complete_rq(struct request *req)
>  			"completing aborted command with status: %04x\n",
>  			req->errors);
>  	}
> -

Here...

>  	blk_mq_end_request(req, error);
>  }
>
> @@ -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;
>

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

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
@ 2016-11-01  8:18     ` Sagi Grimberg
  0 siblings, 0 replies; 32+ messages in thread
From: Sagi Grimberg @ 2016-11-01  8:18 UTC (permalink / raw)



> +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_insert_rq(struct request_queue *q, struct request *rq,
> +			  int at_head, rq_end_io_fn *done)
> +{
> +	WARN_ON(rq->cmd_type == REQ_TYPE_FS);
> +
> +	rq->end_io = done;
> +
> +	if (!q->mq_ops)
> +		return -EINVAL;
> +
> +	blk_mq_insert_request(rq, at_head, true, true);
> +
> +	return 0;
> +}

No need for this function... you control the call site...

> +
> +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;//bdev->bd_disk->private_data;

??

you don't even have data anywhere in here...

> +
> +	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;
> +	//req->rq_disk = bdev->bd_disk;

??

> +
> +	return nvme_insert_rq(q, req, 1, sec_submit_endio);

No need to introduce nvme_insert_rq at all, just call
blk_mq_insert_request (other examples call blk_execute_rq_nowait
but its pretty much the same...)

> @@ -582,6 +583,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
>  	struct nvme_command cmnd;
>  	unsigned map_len;
>  	int ret = BLK_MQ_RQ_QUEUE_OK;
> +	unsigned long flags;
>
>  	/*
>  	 * If formated with metadata, require the block layer provide a buffer
> @@ -614,18 +616,18 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
>  	cmnd.common.command_id = req->tag;
>  	blk_mq_start_request(req);
>
> -	spin_lock_irq(&nvmeq->q_lock);
> +	spin_lock_irqsave(&nvmeq->q_lock, flags);
>  	if (unlikely(nvmeq->cq_vector < 0)) {
>  		if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
>  			ret = BLK_MQ_RQ_QUEUE_BUSY;
>  		else
>  			ret = BLK_MQ_RQ_QUEUE_ERROR;
> -		spin_unlock_irq(&nvmeq->q_lock);
> +		spin_unlock_irqrestore(&nvmeq->q_lock, flags);
>  		goto out;
>  	}
>  	__nvme_submit_cmd(nvmeq, &cmnd);
>  	nvme_process_cq(nvmeq);
> -	spin_unlock_irq(&nvmeq->q_lock);
> +	spin_unlock_irqrestore(&nvmeq->q_lock, flags);

No documentation why this is needed...

>  	return BLK_MQ_RQ_QUEUE_OK;
>  out:
>  	nvme_free_iod(dev, req);
> @@ -635,11 +637,11 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
>  static void nvme_complete_rq(struct request *req)
>  {
>  	struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
> -	struct nvme_dev *dev = iod->nvmeq->dev;
> +	struct nvme_queue *nvmeq = iod->nvmeq;
> +	struct nvme_dev *dev = nvmeq->dev;

This is a cleanup that should go in a different patch...

>  	int error = 0;
>
>  	nvme_unmap_data(dev, req);
> -

Same here...

>  	if (unlikely(req->errors)) {
>  		if (nvme_req_needs_retry(req, req->errors)) {
>  			req->retries++;
> @@ -658,7 +660,6 @@ static void nvme_complete_rq(struct request *req)
>  			"completing aborted command with status: %04x\n",
>  			req->errors);
>  	}
> -

Here...

>  	blk_mq_end_request(req, error);
>  }
>
> @@ -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;
>

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

* Re: [RFC PATCH 5/6] nvme: Add unlock_from_suspend
  2016-11-01  8:18     ` Sagi Grimberg
@ 2016-11-01 13:57       ` Christoph Hellwig
  -1 siblings, 0 replies; 32+ messages in thread
From: Christoph Hellwig @ 2016-11-01 13:57 UTC (permalink / raw)
  To: Sagi Grimberg
  Cc: Scott Bauer, linux-nvme, keith.busch, hch, Rafael.Antognolli,
	axboe, linux-block, jonathan.derrick, j.naumann

On Tue, Nov 01, 2016 at 10:18:13AM +0200, Sagi Grimberg wrote:
> > +
> > +	return nvme_insert_rq(q, req, 1, sec_submit_endio);
> 
> No need to introduce nvme_insert_rq at all, just call
> blk_mq_insert_request (other examples call blk_execute_rq_nowait
> but its pretty much the same...)

blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
even exported.

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

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
@ 2016-11-01 13:57       ` Christoph Hellwig
  0 siblings, 0 replies; 32+ messages in thread
From: Christoph Hellwig @ 2016-11-01 13:57 UTC (permalink / raw)


On Tue, Nov 01, 2016@10:18:13AM +0200, Sagi Grimberg wrote:
> > +
> > +	return nvme_insert_rq(q, req, 1, sec_submit_endio);
> 
> No need to introduce nvme_insert_rq at all, just call
> blk_mq_insert_request (other examples call blk_execute_rq_nowait
> but its pretty much the same...)

blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
even exported.

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

* Re: [RFC PATCH 5/6] nvme: Add unlock_from_suspend
  2016-11-01 13:57       ` Christoph Hellwig
@ 2016-11-01 14:40         ` Scott Bauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-11-01 14:40 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Sagi Grimberg, linux-nvme, keith.busch, Rafael.Antognolli, axboe,
	linux-block, jonathan.derrick, j.naumann

On Tue, Nov 01, 2016 at 06:57:05AM -0700, Christoph Hellwig wrote:
> On Tue, Nov 01, 2016 at 10:18:13AM +0200, Sagi Grimberg wrote:
> > > +
> > > +	return nvme_insert_rq(q, req, 1, sec_submit_endio);
> > 
> > No need to introduce nvme_insert_rq at all, just call
> > blk_mq_insert_request (other examples call blk_execute_rq_nowait
> > but its pretty much the same...)
> 
> blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
> even exported.

Thanks for the reviews. This patch needs to be separated into two 
patches. There is the addition of the nvme-suspend stuff and the
addition of sec_ops. Most of the clutter and weird stuff is coming
from the latter. I'll separate the patches, use the correct api and 
clean the clutter.

Thanks





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

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
@ 2016-11-01 14:40         ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-11-01 14:40 UTC (permalink / raw)


On Tue, Nov 01, 2016@06:57:05AM -0700, Christoph Hellwig wrote:
> On Tue, Nov 01, 2016@10:18:13AM +0200, Sagi Grimberg wrote:
> > > +
> > > +	return nvme_insert_rq(q, req, 1, sec_submit_endio);
> > 
> > No need to introduce nvme_insert_rq at all, just call
> > blk_mq_insert_request (other examples call blk_execute_rq_nowait
> > but its pretty much the same...)
> 
> blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
> even exported.

Thanks for the reviews. This patch needs to be separated into two 
patches. There is the addition of the nvme-suspend stuff and the
addition of sec_ops. Most of the clutter and weird stuff is coming
from the latter. I'll separate the patches, use the correct api and 
clean the clutter.

Thanks

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

* Re: [RFC PATCH 2/6] lib: Add Sed-opal library
  2016-10-31 21:58   ` Scott Bauer
@ 2016-11-01 18:56     ` Jon Derrick
  -1 siblings, 0 replies; 32+ messages in thread
From: Jon Derrick @ 2016-11-01 18:56 UTC (permalink / raw)
  To: Scott Bauer
  Cc: keith.busch, hch, Rafael.Antognolli, linux-nvme, axboe,
	linux-block, j.naumann

SGkgUmFmYWVsLCBTY290dCwKCgpGaXJzdCBvZmYsIGNvbmdyYXRzIG9uIHRoZSBzZXQhIEl0IGxv
b2tzIGdvb2Qgc28gZmFyLgoKSnVzdCBzb21lIHNtYWxsIG5pdHMgYmVsb3cgc2luY2UgeW91IGhh
dmUgdG8gcmVzcGluIGl0IGFueXdheXMgOikKCk9uIE1vbiwgT2N0IDMxLCAyMDE2IGF0IDAzOjU4
OjE1UE0gLTA2MDAsIFNjb3R0IEJhdWVyIHdyb3RlOgo+IFRoaXMgcGF0Y2ggaW1wbGVtZW50cyB0
aGUgbmVjZXNzYXJ5IGxvZ2ljIHRvIGJyaW5nIGFuIE9wYWwKPiBlbmFibGVkIGRyaXZlIG91dCBv
ZiBhIGZhY3RvcnktZW5hYmxlZCBpbnRvIGEgd29ya2luZwo+IE9wYWwgc3RhdGUuCj4gCj4gVGhp
cyBwYXRjaCBzZXQgYWxzbyBlbmFibGVzIGxvZ2ljIHRvIHNhdmUgYSBwYXNzd29yZCB0bwo+IGJl
IHJlcGxheWVkIGR1cmluZyBhIHJlc3VtZSBmcm9tIHN1c3BlbmQuIFRoZSBrZXkgY2FuIGJlCj4g
c2F2ZWQgaW4gdGhlIGRyaXZlciBvciBpbiB0aGUgS2VybmVsJ3MgS2V5IG1hbmFnbWVudC4KPiAK
PiBTaWduZWQtb2ZmLWJ5OiBTY290dCBCYXVlciA8c2NvdHQuYmF1ZXJAaW50ZWwuY29tPgo+IFNp
Z25lZC1vZmYtYnk6IFJhZmFlbCBBbnRvZ25vbGxpIDxSYWZhZWwuQW50b2dub2xsaUBpbnRlbC5j
b20+Cj4gLS0tCj4gIGxpYi9zZWQtb3BhbC5jICAgICAgICAgIHwgMzMzNyArKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwo+ICBsaWIvc2VkLW9wYWxfaW50ZXJu
YWwuaCB8ICA1ODYgKysrKysrKysrCj4gIGxpYi9zZWQtb3BhbF9rZXkuYyAgICAgIHwgICA0NiAr
Cj4gIGxpYi9zZWQuYyAgICAgICAgICAgICAgIHwgIDMwMyArKysrKwo+ICA0IGZpbGVzIGNoYW5n
ZWQsIDQyNzIgaW5zZXJ0aW9ucygrKQo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgbGliL3NlZC1vcGFs
LmMKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGxpYi9zZWQtb3BhbF9pbnRlcm5hbC5oCj4gIGNyZWF0
ZSBtb2RlIDEwMDY0NCBsaWIvc2VkLW9wYWxfa2V5LmMKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGxp
Yi9zZWQuYwo+IAo+IGRpZmYgLS1naXQgYS9saWIvc2VkLW9wYWwuYyBiL2xpYi9zZWQtb3BhbC5j
Cj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwLi4xMGIzMzQ4Cj4gLS0tIC9k
ZXYvbnVsbAo+ICsrKyBiL2xpYi9zZWQtb3BhbC5jCj4gQEAgLTAsMCArMSwzMzM3IEBACj4gKy8q
Cj4gKyAqIENvcHlyaWdodCDCqSAyMDE2IEludGVsIENvcnBvcmF0aW9uCj4gKyAqCj4gKyAqIFBl
cm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29u
IG9idGFpbmluZyBhCj4gKyAqIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBk
b2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksCj4gKyAqIHRvIGRlYWwgaW4gdGhl
IFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRp
b24KPiArICogdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gs
IGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsCj4gKyAqIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUg
U29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZQo+ICsgKiBTb2Z0d2Fy
ZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRp
b25zOgo+ICsgKgo+ICsgKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJt
aXNzaW9uIG5vdGljZSAoaW5jbHVkaW5nIHRoZSBuZXh0Cj4gKyAqIHBhcmFncmFwaCkgc2hhbGwg
YmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUK
PiArICogU29mdHdhcmUuCj4gKyAqCj4gKyAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMg
SVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SCj4gKyAqIElNUExJ
RUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hB
TlRBQklMSVRZLAo+ICsgKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9O
SU5GUklOR0VNRU5ULiAgSU4gTk8gRVZFTlQgU0hBTEwKPiArICogVEhFIEFVVEhPUlMgT1IgQ09Q
WVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIK
PiArICogTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBP
UiBPVEhFUldJU0UsIEFSSVNJTkcKPiArICogRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04g
V0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUwo+ICsgKiBJTiBU
SEUgU09GVFdBUkUuCj4gKyAqCj4gKyAqIEF1dGhvcnM6Cj4gKyAqICAgIFJhZmFlbCBBbnRvZ25v
bGxpIDxyYWZhZWwuYW50b2dub2xsaUBpbnRlbC5jb20+Cj4gKyAqICAgIFNjb3R0ICBCYXVlciAg
ICAgIDxzY290dC5iYXVlckBpbnRlbC5jb20+Cj4gKyAqLwo+ICsKPiArI2RlZmluZSBwcl9mbXQo
Zm10KSBLQlVJTERfTU9ETkFNRSAiOk9QQUw6ICIgZm10Cj4gKwo+ICsjaW5jbHVkZSA8bGludXgv
ZGVsYXkuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2RldmljZS5oPgo+ICsjaW5jbHVkZSA8bGludXgv
a2VybmVsLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9saXN0Lmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9n
ZW5oZC5oPgo+ICsjaW5jbHVkZSA8bGludXgvc2xhYi5oPgo+ICsjaW5jbHVkZSA8bGludXgvdWFj
Y2Vzcy5oPgo+ICsjaW5jbHVkZSA8dWFwaS9saW51eC9zZWQtb3BhbC5oPgo+ICsjaW5jbHVkZSA8
bGludXgvc2VkLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9zZWQtb3BhbC5oPgo+ICsjaW5jbHVkZSA8
bGludXgvc3RyaW5nLmg+Cj4gKwo+ICsjaW5jbHVkZSAic2VkLW9wYWxfaW50ZXJuYWwuaCIKPiAr
Cj4gKyNkZWZpbmUgSU9fQlVGRkVSX0xFTkdUSCAyMDQ4Cj4gKwo+ICsjZGVmaW5lIE1BWF9UT0tT
IDY0Cj4gKwo+ICtzdHJ1Y3Qgb3BhbF9jbWQgewo+ICsJc3RydWN0IGJsb2NrX2RldmljZSAqYmRl
djsKPiArCXNlY19jYiAqY2I7Cj4gKwl2b2lkICpjYl9kYXRhOwo+ICsKPiArCXNpemVfdCBwb3M7
Cj4gKwl1OCBjbWRfYnVmW0lPX0JVRkZFUl9MRU5HVEggKiAyXTsKPiArCXU4IHJlc3BfYnVmW0lP
X0JVRkZFUl9MRU5HVEggKiAyXTsKPiArCXU4ICpjbWQ7Cj4gKwl1OCAqcmVzcDsKPiArfTsKPiAr
Cj4gKy8qCj4gKyAqIE9uIHRoZSBwYXJzZWQgcmVzcG9uc2UsIHdlIGRvbid0IHN0b3JlIGFnYWlu
IHRoZSB0b2tzIHRoYXQgYXJlIGFscmVhZHkKPiArICogc3RvcmVkIGluIHRoZSByZXNwb25zZSBi
dWZmZXIuIEluc3RlYWQsIGZvciBlYWNoIHRva2VuLCB3ZSBqdXN0IHN0b3JlIGEKPiArICogcG9p
bnRlciB0byB0aGUgcG9zaXRpb24gaW4gdGhlIGJ1ZmZlciB3aGVyZSB0aGUgdG9rZW4gc3RhcnRz
LCBhbmQgdGhlIHNpemUKPiArICogb2YgdGhlIHRva2VuIGluIGJ5dGVzLgo+ICsgKi8KPiArc3Ry
dWN0IG9wYWxfcmVzcF90b2sgewo+ICsJY29uc3QgdTggKnBvczsKPiArCXNpemVfdCBsZW47Cj4g
KwllbnVtIE9QQUxfUkVTUE9OU0VfVE9LRU4gdHlwZTsKPiArCWVudW0gT1BBTF9BVE9NX1dJRFRI
IHdpZHRoOwo+ICsJdW5pb24gewo+ICsJCXU2NCB1Owo+ICsJCXM2NCBzOwo+ICsJfSBzdG9yZWQ7
Cj4gK307Cj4gKwo+ICsvKgo+ICsgKiBGcm9tIHRoZSByZXNwb25zZSBoZWFkZXIgaXQncyBub3Qg
cG9zc2libGUgdG8ga25vdyBob3cgbWFueSB0b2tlbnMgdGhlcmUgYXJlCj4gKyAqIG9uIHRoZSBw
YXlsb2FkLiBTbyB3ZSBoYXJkY29kZSB0aGF0IHRoZSBtYXhpbXVtIHdpbGwgYmUgTUFYX1RPS1Ms
IGFuZCBsYXRlcgo+ICsgKiBpZiB3ZSBzdGFydCBkZWFsaW5nIHdpdGggbWVzc2FnZXMgdGhhdCBo
YXZlIG1vcmUgdGhhbiB0aGF0LCB3ZSBjYW4gaW5jcmVhc2UKPiArICogdGhpcyBudW1iZXIuIFRo
aXMgaXMgZG9uZSB0byBhdm9pZCBoYXZpbmcgdG8gbWFrZSB0d28gcGFzc2VzIHRocm91Z2ggdGhl
Cj4gKyAqIHJlc3BvbnNlLCB0aGUgZmlyc3Qgb25lIGNvdW50aW5nIGhvdyBtYW55IHRva2VucyB3
ZSBoYXZlIGFuZCB0aGUgc2Vjb25kIG9uZQo+ICsgKiBhY3R1YWxseSBzdG9yaW5nIHRoZSBwb3Np
dGlvbnMuCj4gKyAqLwo+ICtzdHJ1Y3QgcGFyc2VkX3Jlc3Agewo+ICsJaW50IG51bTsKPiArCXN0
cnVjdCBvcGFsX3Jlc3BfdG9rIHRva3NbTUFYX1RPS1NdOwo+ICt9Owo+ICsKPiArc3RydWN0IG9w
YWxfZGV2Owo+ICsKPiArdHlwZWRlZiB2b2lkICgqb3BhbF9jYikoaW50IGVycm9yLCBzdHJ1Y3Qg
b3BhbF9kZXYgKmRldik7Cj4gKwo+ICt0eXBlZGVmIGludCAoKm9wYWxfc3RlcCkoc3RydWN0IG9w
YWxfZGV2ICpkZXYpOwo+ICsKPiArc3RydWN0IG9wYWxfY29tcGxldGlvbiB7Cj4gKwlzdHJ1Y3Qg
Y29tcGxldGlvbiBjbWRfY29tcGxldGlvbjsKPiArCWludCBjb21wbGV0aW9uX3N0YXR1czsKPiAr
fTsKPiArCj4gK3N0cnVjdCBvcGFsX2RldiB7Cj4gKwlzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2
Owo+ICsJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCXN0cnVjdCBvcGFs
X2xvY2tfdW5sb2NrIGxrdWw7Cj4gKwljb25zdCBvcGFsX3N0ZXAgKmZ1bmNzOwo+ICsJdm9pZCAq
KmZ1bmNfZGF0YTsKPiArCWJvb2wgcmVzdW1lX2Zyb21fc3VzcGVuZDsKPiArCXN0cnVjdCBvcGFs
X3N1c3BlbmRfdW5sayAqcmVzdW1lX2RhdGE7Cj4gKwlzaXplX3QgbnVtX2Z1bmNfZGF0YTsKPiAr
CWF0b21pY190IGluX3VzZTsKPiArCXNlY3Rvcl90IHN0YXJ0Owo+ICsJc2VjdG9yX3QgbGVuZ3Ro
Owo+ICsJdTggbHI7Cj4gKwl1OCBrZXlfdHlwZTsKPiArCXU4IGtleV9uYW1lW09QQUxfS0VZX01B
WF07Cj4gKwlzaXplX3Qga2V5X25hbWVfbGVuOwo+ICsJdTgga2V5W09QQUxfS0VZX01BWF07Cj4g
KwlzaXplX3Qga2V5X2xlbjsKPiArCXUxNiBjb21JRDsKPiArCXUzMiBIU047Cj4gKwl1MzIgVFNO
Owo+ICsJdTY0IGFsaWduOwo+ICsJdTY0IGxvd2VzdF9sYmE7Cj4gKwlzdHJ1Y3QgbGlzdF9oZWFk
IG5vZGU7Cj4gKwljaGFyIGRpc2tfbmFtZVtESVNLX05BTUVfTEVOXTsKPiArCWludCBzdGF0ZTsK
PiArCj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgY21kOwo+ICsJc3RydWN0IHBhcnNlZF9yZXNwIHBhcnNl
ZDsKPiArCj4gKwlzaXplX3QgcHJldl9kX2xlbjsKPiArCXZvaWQgKnByZXZfZGF0YTsKPiArCj4g
KwlzZWNfY2IgKmZpbmFsX2NiOwo+ICsJdm9pZCAqZmluYWxfY2JfZGF0YTsKPiArCW9wYWxfc3Rl
cCBlcnJvcl9jYjsKPiArCXZvaWQgKmVycm9yX2NiX2RhdGE7Cj4gKwlvcGFsX2NiIG9wZXJfY2I7
Cj4gK307Cj4gKwo+ICtMSVNUX0hFQUQob3BhbF9saXN0KTsKPiArREVGSU5FX1NQSU5MT0NLKGxp
c3Rfc3BpbmxvY2spOwo+ICsKPiArc3RhdGljIHZvaWQgcHJpbnRfYnVmZmVyKGNvbnN0IHU4ICpw
dHIsIHUzMiBsZW5ndGgpCj4gK3sKPiArI2lmZGVmIERFQlVHCj4gKwlwcmludF9oZXhfZHVtcF9i
eXRlcygiT1BBTDogIiwgRFVNUF9QUkVGSVhfT0ZGU0VULCBwdHIsIGxlbmd0aCk7Cj4gKwlwcl9k
ZWJ1ZygiXG4iKTsKPiArI2VuZGlmCj4gK30KPiArCj4gKyNkZWZpbmUgVFBFUl9TWU5DX1NVUFBP
UlRFRCBCSVQoMCkKPiArCj4gK3N0YXRpYyBib29sIGNoZWNrX3RwZXIoY29uc3Qgdm9pZCAqZGF0
YSkKPiArewo+ICsJY29uc3Qgc3RydWN0IGQwX3RwZXJfZmVhdHVyZXMgKnRwZXIgPSBkYXRhOwo+
ICsJdTggZmxhZ3MgPSB0cGVyLT5zdXBwb3J0ZWRfZmVhdHVyZXM7Cj4gKwo+ICsJaWYgKCEoZmxh
Z3MgJiBUUEVSX1NZTkNfU1VQUE9SVEVEKSkgewo+ICsJCXByX2VycigiVFBlciBzeW5jIG5vdCBz
dXBwb3J0ZWQuIGZsYWdzID0gJWRcbiIsCj4gKwkJICAgICAgIHRwZXItPnN1cHBvcnRlZF9mZWF0
dXJlcyk7Cj4gKwkJcmV0dXJuIGZhbHNlOwo+ICsJfQo+ICsKPiArCXJldHVybiB0cnVlOwo+ICt9
Cj4gKwo+ICtzdGF0aWMgYm9vbCBjaGVja19TVU0oY29uc3Qgdm9pZCAqZGF0YSkKPiArewo+ICsJ
Y29uc3Qgc3RydWN0IGQwX3NpbmdsZV91c2VyX21vZGUgKnN1bSA9IGRhdGE7Cj4gKwl1MzIgbmxv
ID0gYmUzMl90b19jcHUoc3VtLT5udW1fbG9ja2luZ19vYmplY3RzKTsKPiArCj4gKwlpZiAobmxv
ID09IDApIHsKPiArCQlwcl9lcnIoIk5lZWQgYXQgbGVhc3Qgb25lIGxvY2tpbmcgb2JqZWN0Llxu
Iik7Cj4gKwkJcmV0dXJuIGZhbHNlOwo+ICsJfQo+ICsKPiArCXByX2RlYnVnKCJOdW1iZXIgb2Yg
bG9ja2luZyBvYmplY3RzOiAlZFxuIiwgbmxvKTsKPiArCj4gKwlyZXR1cm4gdHJ1ZTsKPiArfQo+
ICsKPiArc3RhdGljIHUxNiBnZXRfY29tSURfdjEwMChjb25zdCB2b2lkICpkYXRhKQo+ICt7Cj4g
Kwljb25zdCBzdHJ1Y3QgZDBfb3BhbF92MTAwICp2MTAwID0gZGF0YTsKPiArCj4gKwlyZXR1cm4g
YmUxNl90b19jcHUodjEwMC0+YmFzZUNvbUlEKTsKPiArfQo+ICsKPiArc3RhdGljIHUxNiBnZXRf
Y29tSURfdjIwMChjb25zdCB2b2lkICpkYXRhKQo+ICt7Cj4gKwljb25zdCBzdHJ1Y3QgZDBfb3Bh
bF92MjAwICp2MjAwID0gZGF0YTsKPiArCj4gKwlyZXR1cm4gYmUxNl90b19jcHUodjIwMC0+YmFz
ZUNvbUlEKTsKPiArfQo+ICsKPiArc3RhdGljIGludCBfX29wYWxfc2VuZF9jbWQoc3RydWN0IG9w
YWxfc3VzcGVuZF91bmxrICpkYXRhLCB1MTYgY29tSUQsCj4gKwkJCSAgIHZvaWQgKmJ1ZmZlciwg
c2l6ZV90IGJ1Zmxlbiwgc2VjX2NiICpjYiwKPiArCQkJICAgdm9pZCAqY2JfZGF0YSkKPiArewo+
ICsJcmV0dXJuIGRhdGEtPm9wcy5zZW5kKGRhdGEtPmRhdGEsIGNvbUlELCBUQ0dfU0VDUF8wMSwg
YnVmZmVyLCBidWZsZW4sCj4gKwkJCSAgICAgY2IsIGNiX2RhdGEpOwo+ICt9Cj4gK3N0YXRpYyBp
bnQgX29wYWxfc2VuZF9jbWQoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgdTE2IGNvbUlELAo+
ICsJCQkgIHZvaWQgKmJ1ZmZlciwgc2l6ZV90IGJ1ZmxlbiwKPiArCQkJICBzZWNfY2IgKmNiLCB2
b2lkICpjYl9kYXRhKQo+ICt7Cj4gKwljb25zdCBzdHJ1Y3Qgc2VjX29wcyAqb3BzID0gYmRldi0+
YmRfZGlzay0+Zm9wcy0+c2VjX29wczsKPiArCj4gKwlyZXR1cm4gb3BzLT5zZW5kKGJkZXYtPmJk
X2Rpc2stPnByaXZhdGVfZGF0YSwgY29tSUQsCj4gKwkJCSBUQ0dfU0VDUF8wMSwgYnVmZmVyLCBi
dWZsZW4sCj4gKwkJCSBjYiwgY2JfZGF0YSk7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgX19vcGFs
X3JlY3ZfY21kKHN0cnVjdCBvcGFsX3N1c3BlbmRfdW5sayAqZGF0YSwgdTE2IGNvbUlELAo+ICsJ
CQkgICB2b2lkICpidWZmZXIsIHNpemVfdCBidWZsZW4sIHNlY19jYiAqY2IsCj4gKwkJCSAgIHZv
aWQgKmNiX2RhdGEpCj4gK3sKPiArCXJldHVybiBkYXRhLT5vcHMucmVjdihkYXRhLT5kYXRhLCBj
b21JRCwgVENHX1NFQ1BfMDEsIGJ1ZmZlciwgYnVmbGVuLAo+ICsJCQkgICAgIGNiLCBjYl9kYXRh
KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBfb3BhbF9yZWN2X2NtZChzdHJ1Y3QgYmxvY2tfZGV2
aWNlICpiZGV2LCB1MTYgY29tSUQsCj4gKwkJCSAgdm9pZCAqYnVmZmVyLCBzaXplX3QgYnVmbGVu
LAo+ICsJCQkgIHNlY19jYiAqY2IsIHZvaWQgKmNiX2RhdGEpCj4gK3sKPiArCWNvbnN0IHN0cnVj
dCBzZWNfb3BzICpvcHMgPSBiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzOwo+ICsKPiArCXJl
dHVybiBvcHMtPnJlY3YoYmRldi0+YmRfZGlzay0+cHJpdmF0ZV9kYXRhLCBjb21JRCwKPiArCQkJ
IFRDR19TRUNQXzAxLCBidWZmZXIsIGJ1ZmxlbiwKPiArCQkJIGNiLCBjYl9kYXRhKTsKPiArfQo+
ICsKPiArc3RhdGljIHZvaWQgb3BhbF9zZW5kX2NiX2NvbnQoaW50IGVycm9yLCB2b2lkICpkYXRh
KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7Cj4gKwlzaXplX3QgYnVmbGVu
ID0gSU9fQlVGRkVSX0xFTkdUSDsKPiArCXZvaWQgKmJ1ZmZlciA9IGRldi0+Y21kLnJlc3A7Cj4g
KwlzdHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkciA9IGJ1ZmZlcjsKPiArCj4gKwlwcl9kZWJ1ZygiJXM6
IFNlbnQgT1BBTCBjb21tYW5kOiBlcnJvcj0lZCwgb3V0c3RhbmRpbmc9JWQsIG1pblRyYW5zZmVy
PSVkXG4iLAo+ICsJICAgICAgIGRldi0+ZGlza19uYW1lLCBlcnJvciwgaGRyLT5jcC5vdXRzdGFu
ZGluZ0RhdGEsCj4gKwkgICAgICAgaGRyLT5jcC5taW5UcmFuc2Zlcik7Cj4gKwo+ICsJaWYgKGVy
cm9yIHx8IGhkci0+Y3Aub3V0c3RhbmRpbmdEYXRhID09IDAgfHwKPiArCSAgICBoZHItPmNwLm1p
blRyYW5zZmVyICE9IDApIHsKPiArCQlpZiAoZGV2LT5jbWQuY2IpCj4gKwkJCWRldi0+Y21kLmNi
KGVycm9yLCBkZXYtPmNtZC5jYl9kYXRhKTsKPiArCQlyZXR1cm47Cj4gKwl9Cj4gKwo+ICsJbWVt
c2V0KGJ1ZmZlciwgMCwgYnVmbGVuKTsKPiArCWlmIChkZXYtPnJlc3VtZV9mcm9tX3N1c3BlbmQp
Cj4gKwkJX19vcGFsX3JlY3ZfY21kKGRldi0+cmVzdW1lX2RhdGEsIGRldi0+Y29tSUQsCj4gKwkJ
CQlidWZmZXIsIGJ1Zmxlbiwgb3BhbF9zZW5kX2NiX2NvbnQsIGRldik7Cj4gKwllbHNlCj4gKwkJ
X29wYWxfcmVjdl9jbWQoZGV2LT5iZGV2LCBkZXYtPmNvbUlELCBidWZmZXIsIGJ1ZmxlbiwKPiAr
CQkJICAgICAgIG9wYWxfc2VuZF9jYl9jb250LCBkZXYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9p
ZCBvcGFsX3NlbmRfY2IoaW50IGVycm9yLCB2b2lkICpkYXRhKQo+ICt7Cj4gKwlzdHJ1Y3Qgb3Bh
bF9kZXYgKmRldiA9IGRhdGE7Cj4gKwlzaXplX3QgYnVmbGVuID0gSU9fQlVGRkVSX0xFTkdUSDsK
PiArCXZvaWQgKmJ1ZmZlciA9IGRldi0+Y21kLnJlc3A7Cj4gKwo+ICsJaWYgKGVycm9yKSB7Cj4g
KwkJaWYgKGRldi0+Y21kLmNiKQo+ICsJCQlkZXYtPmNtZC5jYihlcnJvciwgZGV2LT5jbWQuY2Jf
ZGF0YSk7Cj4gKwkJcmV0dXJuOwo+ICsJfQo+ICsKPiArCW1lbXNldChidWZmZXIsIDAsIGJ1Zmxl
bik7Cj4gKwlpZiAoZGV2LT5yZXN1bWVfZnJvbV9zdXNwZW5kKQo+ICsJCV9fb3BhbF9yZWN2X2Nt
ZChkZXYtPnJlc3VtZV9kYXRhLCBkZXYtPmNvbUlELAo+ICsJCQkJYnVmZmVyLCBidWZsZW4sIG9w
YWxfc2VuZF9jYl9jb250LCBkZXYpOwo+ICsJZWxzZQo+ICsJCV9vcGFsX3JlY3ZfY21kKGRldi0+
YmRldiwgZGV2LT5jb21JRCwgYnVmZmVyLCBidWZsZW4sCj4gKwkJCSAgICAgICBvcGFsX3NlbmRf
Y2JfY29udCwgZGV2KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBvcGFsX3NlbmRfcmVjdihzdHJ1
Y3Qgb3BhbF9kZXYgKmRldiwgc2VjX2NiICpjYiwgdm9pZCAqY2JfZGF0YSkKPiArewo+ICsJc2l6
ZV90IGJ1ZmxlbiA9IElPX0JVRkZFUl9MRU5HVEg7Cj4gKwl2b2lkICpidWZmZXIgPSBkZXYtPmNt
ZC5jbWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWRldi0+Y21kLmNiID0gY2I7Cj4gKwlkZXYtPmNt
ZC5jYl9kYXRhID0gY2JfZGF0YTsKPiArCWlmIChkZXYtPnJlc3VtZV9mcm9tX3N1c3BlbmQpCj4g
KwkJcmV0ID0gX19vcGFsX3NlbmRfY21kKGRldi0+cmVzdW1lX2RhdGEsIGRldi0+Y29tSUQsIGJ1
ZmZlciwKPiArCQkJCSAgICAgIGJ1Zmxlbiwgb3BhbF9zZW5kX2NiLCBkZXYpOwo+ICsJZWxzZQo+
ICsJCXJldCA9IF9vcGFsX3NlbmRfY21kKGRldi0+YmRldiwgZGV2LT5jb21JRCwgYnVmZmVyLCBi
dWZsZW4sCj4gKwkJCQkgICAgIG9wYWxfc2VuZF9jYiwgZGV2KTsKPiArCj4gKwlyZXR1cm4gcmV0
Owo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBjaGVja19nZW9tZXRyeShzdHJ1Y3Qgb3BhbF9kZXYg
KmRldiwgY29uc3Qgdm9pZCAqZGF0YSkKPiArewo+ICsJY29uc3Qgc3RydWN0IGQwX2dlb21ldHJ5
X2ZlYXR1cmVzICpnZW8gPSBkYXRhOwo+ICsKPiArCWRldi0+YWxpZ24gPSBnZW8tPmFsaWdubWVu
dF9ncmFudWxhcml0eTsKPiArCWRldi0+bG93ZXN0X2xiYSA9IGdlby0+bG93ZXN0X2FsaWduZWRf
bGJhOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBvcGFsX2Rpc2NvdmVyeTBfZW5kKGludCBlcnJv
ciwgdm9pZCAqZGF0YSkKPiArewo+ICsJYm9vbCBmb3VuZENvbUlEID0gZmFsc2UsIHN1cHBvcnRl
ZCA9IHRydWUsIHNpbmdsZV91c2VyID0gZmFsc2U7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9
IGRhdGE7Cj4gKwljb25zdCBzdHJ1Y3QgZDBfaGVhZGVyICpoZHI7Cj4gKwljb25zdCB1OCAqZXBv
cywgKmNwb3M7Cj4gKwl1MTYgY29tSUQgPSAwOwo+ICsKPiArCWlmIChlcnJvcikgewo+ICsJCXBy
X2VycigiJXM6IFNlbmRpbmcgZGlzY292ZXJ5MCBmYWlsZWRcbiIsIGRldi0+ZGlza19uYW1lKTsK
PiArCQlnb3RvIGVycl9jYWxsYmFjazsKPiArCX0KPiArCj4gKwllcG9zID0gZGV2LT5jbWQucmVz
cDsKPiArCWNwb3MgPSBkZXYtPmNtZC5yZXNwOwo+ICsJaGRyID0gKHN0cnVjdCBkMF9oZWFkZXIg
KilkZXYtPmNtZC5yZXNwOwo+ICsKPiArCXByaW50X2J1ZmZlcihkZXYtPmNtZC5yZXNwLCBiZTMy
X3RvX2NwdShoZHItPmxlbmd0aCkpOwo+ICsKPiArCWVwb3MgKz0gYmUzMl90b19jcHUoaGRyLT5s
ZW5ndGgpOyAvKiBlbmQgb2YgYnVmZmVyICovCj4gKwljcG9zICs9IHNpemVvZigqaGRyKTsgLyog
Y3VycmVudCBwb3NpdGlvbiBvbiBidWZmZXIgKi8KPiArCj4gKwl3aGlsZSAoY3BvcyA8IGVwb3Mg
JiYgc3VwcG9ydGVkKSB7Cj4gKwkJY29uc3Qgc3RydWN0IGQwX2ZlYXR1cmVzICpib2R5ID0KPiAr
CQkJKGNvbnN0IHN0cnVjdCBkMF9mZWF0dXJlcyAqKWNwb3M7Cj4gKwo+ICsJCXN3aXRjaCAoYmUx
Nl90b19jcHUoYm9keS0+Y29kZSkpIHsKPiArCQljYXNlIEZDX1RQRVI6Cj4gKwkJCXN1cHBvcnRl
ZCA9IGNoZWNrX3RwZXIoYm9keS0+ZmVhdHVyZXMpOwo+ICsJCQlicmVhazsKPiArCQljYXNlIEZD
X1NJTkdMRVVTRVI6Cj4gKwkJCXNpbmdsZV91c2VyID0gY2hlY2tfU1VNKGJvZHktPmZlYXR1cmVz
KTsKPiArCQkJYnJlYWs7Cj4gKwkJY2FzZSBGQ19HRU9NRVRSWToKPiArCQkJY2hlY2tfZ2VvbWV0
cnkoZGV2LCBib2R5KTsKPiArCQkJYnJlYWs7Cj4gKwkJY2FzZSBGQ19MT0NLSU5HOgo+ICsJCWNh
c2UgRkNfRU5URVJQUklTRToKPiArCQljYXNlIEZDX0RBVEFTVE9SRToKPiArCQkJLyogc29tZSBp
Z25vcmVkIHByb3BlcnRpZXMgKi8KPiArCQkJcHJfZGVidWcoIiVzOiBGb3VuZCBPUEFMIGZlYXR1
cmUgZGVzY3JpcHRpb246ICVkXG4iLAo+ICsJCQkJIGRldi0+ZGlza19uYW1lLCBiZTE2X3RvX2Nw
dShib2R5LT5jb2RlKSk7Cj4gKwkJCWJyZWFrOwo+ICsJCWNhc2UgRkNfT1BBTFYxMDA6Cj4gKwkJ
CWNvbUlEID0gZ2V0X2NvbUlEX3YxMDAoYm9keS0+ZmVhdHVyZXMpOwo+ICsJCQlmb3VuZENvbUlE
ID0gdHJ1ZTsKPiArCQkJYnJlYWs7Cj4gKwkJY2FzZSBGQ19PUEFMVjIwMDoKPiArCQkJY29tSUQg
PSBnZXRfY29tSURfdjIwMChib2R5LT5mZWF0dXJlcyk7Cj4gKwkJCWZvdW5kQ29tSUQgPSB0cnVl
Owo+ICsJCQlicmVhazsKPiArCQlkZWZhdWx0Ogo+ICsJCQlpZiAoYmUxNl90b19jcHUoYm9keS0+
Y29kZSkgPiAweGJmZmYpIHsKPiArCQkJCS8qIHZlbmRvciBzcGVjaWZpYywganVzdCBpZ25vcmUg
Ki8KPiArCQkJfSBlbHNlIHsKPiArCQkJCXByX3dhcm4oIiVzOiBPUEFMIFVua25vd24gZmVhdHVy
ZTogJWRcbiIsCj4gKwkJCQkJZGV2LT5kaXNrX25hbWUsIGJlMTZfdG9fY3B1KGJvZHktPmNvZGUp
KTsKPiArCQkJfQpTbWFsbCBuaXQsIGhvdyBhYm91dDoKCmNhc2UgMHhiZmZmIC4uLiAweGZmZmY6
CgkvKiB2ZW5kb3Igc3BlY2lmaWMsIGp1c3QgaWdub3JlICovCglicmVhazsKZGVmYXVsdDoKCXBy
X3dhcm4oLi4uCgoKCj4gKwkJfQo+ICsJCWNwb3MgKz0gYm9keS0+bGVuZ3RoICsgNDsKPiArCX0K
PiArCj4gKwlpZiAoIXN1cHBvcnRlZCkgewo+ICsJCXByX2VycigiJXM6IERldmljZSBub3Qgc3Vw
cG9ydGVkXG4iLCBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJZ290byBlcnJfY2FsbGJhY2s7Cj4gKwl9
Cj4gKwo+ICsJaWYgKCFzaW5nbGVfdXNlcikKPiArCQlwcl93YXJuKCIlczogRGV2aWNlIGRvZXNu
J3Qgc3VwcG9ydCBzaW5nbGUgdXNlciBtb2RlXG4iLAo+ICsJCQlkZXYtPmRpc2tfbmFtZSk7Cj4g
Kwo+ICsJaWYgKCFmb3VuZENvbUlEKSB7Cj4gKwkJcHJfd2FybigiJXM6IENvdWxkIG5vdCBmaW5k
IE9QQUwgY29tSUQgZm9yIGRldmljZS4gT1BBTCBrZXJuZWwgdW5sb2NraW5nIHdpbGwgYmUgZGlz
YWJsZWRcbiIsCj4gKwkJCWRldi0+ZGlza19uYW1lKTsKPiArCQlnb3RvIGVycl9jYWxsYmFjazsK
PiArCX0KPiArCj4gKwlkZXYtPmNvbUlEID0gY29tSUQ7Cj4gKwo+ICtlcnJfY2FsbGJhY2s6Cj4g
KwlpZiAoZGV2LT5vcGVyX2NiKQo+ICsJCWRldi0+b3Blcl9jYihlcnJvciwgZGV2KTsKPiArfQo+
ICsKPiArc3RhdGljIGludCBvcGFsX2Rpc2NvdmVyeTAoc3RydWN0IG9wYWxfZGV2ICpkZXYpCj4g
K3sKPiArCW1lbXNldChkZXYtPmNtZC5yZXNwLCAwLCBJT19CVUZGRVJfTEVOR1RIKTsKPiArCj4g
KwlpZiAoZGV2LT5yZXN1bWVfZnJvbV9zdXNwZW5kKQo+ICsJCXJldHVybiBfX29wYWxfcmVjdl9j
bWQoZGV2LT5yZXN1bWVfZGF0YSwgMHgwMDAxLAo+ICsJCQkJICAgICAgIGRldi0+Y21kLnJlc3As
IElPX0JVRkZFUl9MRU5HVEgsCj4gKwkJCQkgICAgICAgb3BhbF9kaXNjb3ZlcnkwX2VuZCwgZGV2
KTsKPiArCj4gKwlyZXR1cm4gX29wYWxfcmVjdl9jbWQoZGV2LT5iZGV2LCAweDAwMDEsIGRldi0+
Y21kLnJlc3AsCj4gKwkJCSAgICAgIElPX0JVRkZFUl9MRU5HVEgsIG9wYWxfZGlzY292ZXJ5MF9l
bmQsCj4gKwkJCSAgICAgIGRldik7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIGFkZF90b2tlbl91
OChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTggdG9rKQo+ICt7Cj4gKwljbWQtPmNtZFtjbWQtPnBv
cysrXSA9IHRvazsKPiArfQo+ICsKPiArc3RhdGljIHNzaXplX3QgdGVzdF9hbmRfYWRkX3Rva2Vu
X3U4KHN0cnVjdCBvcGFsX2NtZCAqY21kLCB1OCB0b2spCj4gK3sKPiArCUJVSUxEX0JVR19PTihJ
T19CVUZGRVJfTEVOR1RIID49IFNJWkVfTUFYKTsKPiArCj4gKwlpZiAoY21kLT5wb3MgPj0gSU9f
QlVGRkVSX0xFTkdUSCAtIDEpIHsKPiArCQlwcl9lcnIoIkVycm9yIGFkZGluZyB1ODogZW5kIG9m
IGJ1ZmZlci5cbiIpOwo+ICsJCXJldHVybiAtRVJBTkdFOwo+ICsJfQo+ICsKPiArCWFkZF90b2tl
bl91OChjbWQsIHRvayk7Cj4gKwo+ICsJcmV0dXJuIDE7Cj4gK30KPiArCj4gKyNkZWZpbmUgVElO
WV9BVE9NX0RBVEFfTUFTSyBHRU5NQVNLKDUsIDApCj4gKyNkZWZpbmUgVElOWV9BVE9NX1NJR05F
RCBCSVQoNikKPiArCj4gKyNkZWZpbmUgU0hPUlRfQVRPTV9JRCBCSVQoNykKPiArI2RlZmluZSBT
SE9SVF9BVE9NX0JZVEVTVFJJTkcgQklUKDUpCj4gKyNkZWZpbmUgU0hPUlRfQVRPTV9TSUdORUQg
QklUKDQpCj4gKyNkZWZpbmUgU0hPUlRfQVRPTV9MRU5fTUFTSyBHRU5NQVNLKDMsIDApCj4gKwo+
ICtzdGF0aWMgdm9pZCBhZGRfc2hvcnRfYXRvbV9oZWFkZXIoc3RydWN0IG9wYWxfY21kICpjbWQs
IGJvb2wgYnl0ZXN0cmluZywKPiArCQkJCSAgYm9vbCBoYXNfc2lnbiwgaW50IGxlbikKPiArewo+
ICsJdTggYXRvbTsKPiArCj4gKwlhdG9tID0gU0hPUlRfQVRPTV9JRDsKPiArCWF0b20gfD0gYnl0
ZXN0cmluZyA/IFNIT1JUX0FUT01fQllURVNUUklORyA6IDA7Cj4gKwlhdG9tIHw9IGhhc19zaWdu
ID8gU0hPUlRfQVRPTV9TSUdORUQgOiAwOwo+ICsJYXRvbSB8PSBsZW4gJiBTSE9SVF9BVE9NX0xF
Tl9NQVNLOwo+ICsKPiArCWFkZF90b2tlbl91OChjbWQsIGF0b20pOwo+ICt9Cj4gKwo+ICsjZGVm
aW5lIE1FRElVTV9BVE9NX0lEIChCSVQoNykgfCBCSVQoNikpCj4gKyNkZWZpbmUgTUVESVVNX0FU
T01fQllURVNUUklORyBCSVQoNCkKPiArI2RlZmluZSBNRURJVU1fQVRPTV9TSUdORUQgQklUKDMp
Cj4gKyNkZWZpbmUgTUVESVVNX0FUT01fTEVOX01BU0sgR0VOTUFTSygyLCAwKQo+ICsKPiArc3Rh
dGljIHZvaWQgYWRkX21lZGl1bV9hdG9tX2hlYWRlcihzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgYm9v
bCBieXRlc3RyaW5nLAo+ICsJCQkJICAgYm9vbCBoYXNfc2lnbiwgaW50IGxlbikKPiArewo+ICsJ
dTggaGVhZGVyMDsKPiArCj4gKwloZWFkZXIwID0gTUVESVVNX0FUT01fSUQ7Cj4gKwloZWFkZXIw
IHw9IGJ5dGVzdHJpbmcgPyBNRURJVU1fQVRPTV9CWVRFU1RSSU5HIDogMDsKPiArCWhlYWRlcjAg
fD0gaGFzX3NpZ24gPyBNRURJVU1fQVRPTV9TSUdORUQgOiAwOwo+ICsJaGVhZGVyMCB8PSAobGVu
ID4+IDgpICYgTUVESVVNX0FUT01fTEVOX01BU0s7Cj4gKwljbWQtPmNtZFtjbWQtPnBvcysrXSA9
IGhlYWRlcjA7Cj4gKwljbWQtPmNtZFtjbWQtPnBvcysrXSA9IGxlbjsKPiArfQo+ICsKPiArc3Rh
dGljIHZvaWQgYWRkX3Rva2VuX3U2NChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTY0IG51bWJlciwg
c2l6ZV90IGxlbikKPiArewo+ICsJYWRkX3Nob3J0X2F0b21faGVhZGVyKGNtZCwgZmFsc2UsIGZh
bHNlLCBsZW4pOwo+ICsKPiArCXdoaWxlIChsZW4tLSkgewo+ICsJCXU4IG4gPSBudW1iZXIgPj4g
KGxlbiAqIDgpOwo+ICsKPiArCQlhZGRfdG9rZW5fdTgoY21kLCBuKTsKPiArCX0KPiArfQo+ICsK
PiArc3RhdGljIHNzaXplX3QgdGVzdF9hbmRfYWRkX3Rva2VuX3U2NChzdHJ1Y3Qgb3BhbF9jbWQg
KmNtZCwgdTY0IG51bWJlcikKPiArewo+ICsJaW50IGxlbjsKPiArCWludCBtc2I7Cj4gKwo+ICsJ
aWYgKCEobnVtYmVyICYgflRJTllfQVRPTV9EQVRBX01BU0spKQo+ICsJCXJldHVybiB0ZXN0X2Fu
ZF9hZGRfdG9rZW5fdTgoY21kLCBudW1iZXIpOwo+ICsKPiArCW1zYiA9IGZscyhudW1iZXIpOwo+
ICsJbGVuID0gRElWX1JPVU5EX1VQKG1zYiwgNCk7Cj4gKwo+ICsJaWYgKGNtZC0+cG9zID49IElP
X0JVRkZFUl9MRU5HVEggLSBsZW4gLSAxKSB7Cj4gKwkJcHJfZXJyKCJFcnJvciBhZGRpbmcgdTY0
OiBlbmQgb2YgYnVmZmVyLlxuIik7Cj4gKwkJcmV0dXJuIC1FUkFOR0U7Cj4gKwl9Cj4gKwo+ICsJ
YWRkX3Rva2VuX3U2NChjbWQsIG51bWJlciwgbGVuKTsKPiArCj4gKwkvKiByZXR1cm4gbGVuZ3Ro
IG9mIHRva2VuIHBsdXMgYXRvbSAqLwo+ICsJcmV0dXJuIGxlbiArIDE7Cj4gK30KPiArCj4gK3N0
YXRpYyB2b2lkIGFkZF90b2tlbl9ieXRlc3RyaW5nKHN0cnVjdCBvcGFsX2NtZCAqY21kLAo+ICsJ
CQkJIGNvbnN0IHU4ICpieXRlc3RyaW5nLCBzaXplX3QgbGVuKQo+ICt7Cj4gKwltZW1jcHkoJmNt
ZC0+Y21kW2NtZC0+cG9zXSwgYnl0ZXN0cmluZywgbGVuKTsKPiArCWNtZC0+cG9zICs9IGxlbjsK
PiArfQo+ICsKPiArc3RhdGljIHNzaXplX3QgdGVzdF9hbmRfYWRkX3Rva2VuX2J5dGVzdHJpbmco
c3RydWN0IG9wYWxfY21kICpjbWQsCj4gKwkJCQkJICAgICBjb25zdCB1OCAqYnl0ZXN0cmluZywg
c2l6ZV90IGxlbikKPiArewo+ICsJc2l6ZV90IGhlYWRlcl9sZW4gPSAxOwo+ICsJYm9vbCBpc19z
aG9ydF9hdG9tID0gdHJ1ZTsKPiArCj4gKwlpZiAobGVuICYgflNIT1JUX0FUT01fTEVOX01BU0sp
IHsKPiArCQloZWFkZXJfbGVuID0gMjsKPiArCQlpc19zaG9ydF9hdG9tID0gZmFsc2U7Cj4gKwl9
Cj4gKwo+ICsJaWYgKGNtZC0+cG9zID49IElPX0JVRkZFUl9MRU5HVEggLSBsZW4gLSBoZWFkZXJf
bGVuKSB7Cj4gKwkJcHJfZXJyKCJFcnJvciBhZGRpbmcgYnl0ZXN0cmluZzogZW5kIG9mIGJ1ZmZl
ci5cbiIpOwo+ICsJCXJldHVybiAtRVJBTkdFOwo+ICsJfQo+ICsKPiArCWlmIChpc19zaG9ydF9h
dG9tKQo+ICsJCWFkZF9zaG9ydF9hdG9tX2hlYWRlcihjbWQsIHRydWUsIGZhbHNlLCBsZW4pOwo+
ICsJZWxzZQo+ICsJCWFkZF9tZWRpdW1fYXRvbV9oZWFkZXIoY21kLCB0cnVlLCBmYWxzZSwgbGVu
KTsKPiArCj4gKwlhZGRfdG9rZW5fYnl0ZXN0cmluZyhjbWQsIGJ5dGVzdHJpbmcsIGxlbik7Cj4g
Kwo+ICsJcmV0dXJuIGhlYWRlcl9sZW4gKyBsZW47Cj4gK30KPiArCj4gKyNkZWZpbmUgTE9DS0lO
R19SQU5HRV9OT05fR0xPQkFMIDB4MDMKPiArCj4gK3N0YXRpYyBpbnQgYnVpbGRfbG9ja2luZ19y
YW5nZSh1OCAqYnVmZmVyLCBzaXplX3QgbGVuZ3RoLCB1OCBscikKPiArewo+ICsJaWYgKGxlbmd0
aCA8IE9QQUxfVUlEX0xFTkdUSCkKPiArCQlyZXR1cm4gLUVSQU5HRTsKPiArCj4gKwltZW1jcHko
YnVmZmVyLCBPUEFMVUlEW09QQUxfTE9DS0lOR1JBTkdFX0dMT0JBTF0sIE9QQUxfVUlEX0xFTkdU
SCk7Cj4gKwo+ICsJaWYgKGxyID09IDApCj4gKwkJcmV0dXJuIDA7Cj4gKwlidWZmZXJbNV0gPSBM
T0NLSU5HX1JBTkdFX05PTl9HTE9CQUw7Cj4gKwlidWZmZXJbN10gPSBscjsKPiArCj4gKwlyZXR1
cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIGludCBidWlsZF9sb2NraW5nX3VzZXIodTggKmJ1ZmZl
ciwgc2l6ZV90IGxlbmd0aCwgdTggbHIpCj4gK3sKPiArCWlmIChsZW5ndGggPCBPUEFMX1VJRF9M
RU5HVEgpCj4gKwkJcmV0dXJuIC1FUkFOR0U7Cj4gKwo+ICsJbWVtY3B5KGJ1ZmZlciwgT1BBTFVJ
RFtPUEFMX1VTRVIxX1VJRF0sIE9QQUxfVUlEX0xFTkdUSCk7Cj4gKwo+ICsJYnVmZmVyWzddID0g
bHIgKyAxOwo+ICsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICsvKgo+ICsgKiBOID0gbnVtYmVy
IG9mIGZvcm1hdCBzcGVjaWZpZXJzICgxLTk5OSkgdG8gYmUgcmVwbGljYXRlZAo+ICsgKiBjID0g
dTgKPiArICogdSA9IHU2NAo+ICsgKiBzID0gYnl0ZXN0cmluZywgbGVuZ3RoCj4gKyAqCj4gKyAq
IHJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjIiwKPiArICoJCQkgICAgICAgdThf
dmFsMSk7Cj4gKyAqCj4gKyAqIHJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICIyYzJ1
IiwKPiArICoJCQkgICAgICAgdThfdmFsMSwgdThfdmFsMiwgdTY0X3ZhbDEsIHU2NF92YWwyKTsK
PiArICoKPiArICogcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgIjNzIiwKPiArICoJ
CQkgICAgICAgYnl0ZXN0cmluZzEsIGxlbmd0aDEsCj4gKyAqCQkJICAgICAgIGJ5dGVzdHJpbmcy
LCBsZW5ndGgyLAo+ICsgKgkJCSAgICAgICBieXRlc3RyaW5nMywgbGVuZ3RoMyk7Cj4gKyAqLwo+
ICtzdGF0aWMgaW50IHRlc3RfYW5kX2FkZF90b2tlbl92YShzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwK
PiArCQkJCSBjb25zdCBjaGFyICpmbXQsIC4uLikKPiArewo+ICsJY29uc3QgdTggKml0ID0gZm10
LCAqdG1wOwo+ICsJaW50IHJldCwgbnVtID0gMSwgc3VtID0gMDsKPiArCXZhX2xpc3QgYXA7Cj4g
Kwo+ICsJdmFfc3RhcnQoYXAsIGZtdCk7Cj4gKwo+ICsJd2hpbGUgKCppdCAhPSAnXDAnKSB7Cj4g
KwkJdTY0IHRvazY0ID0gMDsKPiArCQl1OCB0b2ssICpic3RyOwo+ICsJCXNpemVfdCBsZW47Cj4g
Kwo+ICsJCXJldCA9IDA7Cj4gKwo+ICsJCXN3aXRjaCAoKml0KSB7Cj4gKwkJY2FzZSAnMScgLi4u
ICc5JzoKPiArCQkJdG1wID0gaXQ7Cj4gKwkJCW51bSA9IDA7Cj4gKwkJCXdoaWxlICgqdG1wID49
ICcwJyAmJiAqdG1wIDw9ICc5JykKPiArCQkJCW51bSA9IG51bSAqIDEwICsgKCp0bXArKyAtICcw
Jyk7Cj4gKwkJCWl0ID0gdG1wOwo+ICsJCQljb250aW51ZTsKPiArCQljYXNlICdjJzoKPiArCQkJ
d2hpbGUgKG51bS0tKSB7Cj4gKwkJCQl0b2sgPSB2YV9hcmcoYXAsIHVuc2lnbmVkIGludCk7Cj4g
KwkJCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdTgoY21kLCB0b2spOwo+ICsJCQkJaWYgKHJl
dCA8IDApCj4gKwkJCQkJZ290byBlcnI7Cj4gKwkJCX0KPiArCQkJbnVtID0gMTsKPiArCQkJYnJl
YWs7Cj4gKwkJY2FzZSAndSc6Cj4gKwkJCXdoaWxlIChudW0tLSkgewo+ICsJCQkJdG9rNjQgPSB2
YV9hcmcoYXAsIHU2NCk7Cj4gKwkJCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdTY0KGNtZCwg
dG9rNjQpOwo+ICsJCQkJaWYgKHJldCA8IDApCj4gKwkJCQkJZ290byBlcnI7Cj4gKwkJCX0KPiAr
CQkJbnVtID0gMTsKPiArCQkJYnJlYWs7Cj4gKwkJY2FzZSAncyc6Cj4gKwkJCXdoaWxlIChudW0t
LSkgewo+ICsJCQkJYnN0ciA9IHZhX2FyZyhhcCwgdTggKik7Cj4gKwkJCQlsZW4gPSB2YV9hcmco
YXAsIHNpemVfdCk7Cj4gKwkJCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fYnl0ZXN0cmluZyhj
bWQsIGJzdHIsCj4gKwkJCQkJCQkJICAgIGxlbik7Cj4gKwkJCQlpZiAocmV0IDwgMCkKPiArCQkJ
CQlnb3RvIGVycjsKPiArCQkJfQo+ICsJCQludW0gPSAxOwo+ICsJCQlicmVhazsKPiArCQljYXNl
ICcgJzoKPiArCQljYXNlICdcdCc6Cj4gKwkJCS8qIGlnbm9yZWQgKi8KPiArCQkJYnJlYWs7Cj4g
KwkJZGVmYXVsdDoKPiArCQkJcHJfd2FybigiVW5yZWNvZ25pemVkIHR5cGUuXG4iKTsKPiArCQl9
Cj4gKwo+ICsJCWl0Kys7Cj4gKwkJc3VtICs9IHJldDsKPiArCX0KPiArCj4gKwl2YV9lbmQoYXAp
Owo+ICsKPiArCXJldHVybiBzdW07Cj4gKwo+ICsgZXJyOgo+ICsJcHJfZXJyKCJUb2tlbiBmYWls
ZWQgdG8gYmUgYWRkZWQuXG4iKTsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyB2
b2lkIHNldF9jb21JRChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTE2IGNvbUlEKQo+ICt7Cj4gKwlz
dHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkciA9IChzdHJ1Y3Qgb3BhbF9oZWFkZXIgKiljbWQtPmNtZDsK
PiArCj4gKwloZHItPmNwLmV4dGVuZGVkQ29tSURbMF0gPSBjb21JRCA+PiA4Owo+ICsJaGRyLT5j
cC5leHRlbmRlZENvbUlEWzFdID0gY29tSUQ7Cj4gKwloZHItPmNwLmV4dGVuZGVkQ29tSURbMl0g
PSAwOwo+ICsJaGRyLT5jcC5leHRlbmRlZENvbUlEWzNdID0gMDsKPiArfQo+ICsKPiArc3RhdGlj
IGludCBjbWRfZmluYWxpemUoc3RydWN0IG9wYWxfY21kICpjbWQsIHUzMiBoc24sIHUzMiB0c24p
Cj4gK3sKPiArCXN0cnVjdCBvcGFsX2hlYWRlciAqaGRyOwo+ICsJaW50IHJldDsKPiArCj4gKwly
ZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiNmMiLAo+ICsJCQkJICAgIE9QQUxfRU5E
T0ZEQVRBLCBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICAwLCAwLCAwLCBPUEFMX0VORExJU1Qp
Owo+ICsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCJFcnJvciBmaW5hbGl6aW5nIGNv
bW1hbmQuXG4iKTsKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCX0KPiArCj4gKwloZHIgPSAoc3Ry
dWN0IG9wYWxfaGVhZGVyICopIGNtZC0+Y21kOwo+ICsKPiArCWhkci0+cGt0LlRTTiA9IGNwdV90
b19iZTMyKHRzbik7Cj4gKwloZHItPnBrdC5IU04gPSBjcHVfdG9fYmUzMihoc24pOwo+ICsKPiAr
CWhkci0+c3VicGt0Lmxlbmd0aCA9IGNwdV90b19iZTMyKGNtZC0+cG9zIC0gc2l6ZW9mKCpoZHIp
KTsKPiArCXdoaWxlIChjbWQtPnBvcyAlIDQpIHsKPiArCQlpZiAoY21kLT5wb3MgPj0gSU9fQlVG
RkVSX0xFTkdUSCkgewo+ICsJCQlwcl9lcnIoIkVycm9yOiBCdWZmZXIgb3ZlcnJ1blxuIik7Cj4g
KwkJCXJldHVybiAtRVJBTkdFOwo+ICsJCX0KPiArCQljbWQtPmNtZFtjbWQtPnBvcysrXSA9IDA7
Cj4gKwl9Cj4gKwloZHItPnBrdC5sZW5ndGggPSBjcHVfdG9fYmUzMihjbWQtPnBvcyAtIHNpemVv
ZihoZHItPmNwKSAtCj4gKwkJCQkgICAgICBzaXplb2YoaGRyLT5wa3QpKTsKPiArCWhkci0+Y3Au
bGVuZ3RoID0gY3B1X3RvX2JlMzIoY21kLT5wb3MgLSBzaXplb2YoaGRyLT5jcCkpOwo+ICsKPiAr
CXJldHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0aWMgZW51bSBPUEFMX1JFU1BPTlNFX1RPS0VOIHRv
a2VuX3R5cGUoY29uc3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNwLAo+ICsJCQkJCSAgIGludCBu
KQo+ICt7Cj4gKwljb25zdCBzdHJ1Y3Qgb3BhbF9yZXNwX3RvayAqdG9rOwo+ICsKPiArCWlmIChu
ID49IHJlc3AtPm51bSkgewo+ICsJCXByX2VycigiVG9rZW4gbnVtYmVyIGRvZXNuJ3QgZXhpc3Q6
ICVkLCByZXNwOiAlZFxuIiwKPiArCQkgICAgICAgbiwgcmVzcC0+bnVtKTsKPiArCQlyZXR1cm4g
T1BBTF9EVEFfVE9LRU5JRF9JTlZBTElEOwo+ICsJfQo+ICsKPiArCXRvayA9ICZyZXNwLT50b2tz
W25dOwo+ICsJaWYgKHRvay0+bGVuID09IDApIHsKPiArCQlwcl9lcnIoIlRva2VuIGxlbmd0aCBt
dXN0IGJlIG5vbi16ZXJvXG4iKTsKPiArCQlyZXR1cm4gT1BBTF9EVEFfVE9LRU5JRF9JTlZBTElE
Owo+ICsJfQo+ICsKPiArCXJldHVybiB0b2stPnR5cGU7Cj4gK30KPiArCj4gKy8qCj4gKyAqIFRo
aXMgZnVuY3Rpb24gcmV0dXJucyAwIGluIGNhc2Ugb2YgaW52YWxpZCB0b2tlbi4gT25lIHNob3Vs
ZCBjYWxsCj4gKyAqIHRva2VuX3R5cGUoKSBmaXJzdCB0byBmaW5kIG91dCBpZiB0aGUgdG9rZW4g
aXMgdmFsaWQgb3Igbm90Lgo+ICsgKi8KPiArc3RhdGljIGVudW0gT1BBTF9UT0tFTiByZXNwb25z
ZV9nZXRfdG9rZW4oY29uc3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNwLAo+ICsJCQkJCSAgaW50
IG4pCj4gK3sKPiArCWNvbnN0IHN0cnVjdCBvcGFsX3Jlc3BfdG9rICp0b2s7Cj4gKwo+ICsJaWYg
KG4gPj0gcmVzcC0+bnVtKSB7Cj4gKwkJcHJfZXJyKCJUb2tlbiBudW1iZXIgZG9lc24ndCBleGlz
dDogJWQsIHJlc3A6ICVkXG4iLAo+ICsJCSAgICAgICBuLCByZXNwLT5udW0pOwo+ICsJCXJldHVy
biAwOwo+ICsJfQo+ICsKPiArCXRvayA9ICZyZXNwLT50b2tzW25dOwo+ICsJaWYgKHRvay0+bGVu
ID09IDApIHsKPiArCQlwcl9lcnIoIlRva2VuIGxlbmd0aCBtdXN0IGJlIG5vbi16ZXJvXG4iKTsK
PiArCQlyZXR1cm4gMDsKPiArCX0KPiArCj4gKwlyZXR1cm4gdG9rLT5wb3NbMF07Cj4gK30KPiAr
Cj4gK3N0YXRpYyBzaXplX3QgcmVzcG9uc2VfcGFyc2VfdGlueShzdHJ1Y3Qgb3BhbF9yZXNwX3Rv
ayAqdG9rLAo+ICsJCQkJICBjb25zdCB1OCAqcG9zKQo+ICt7Cj4gKwl0b2stPnBvcyA9IHBvczsK
PiArCXRvay0+bGVuID0gMTsKPiArCXRvay0+d2lkdGggPSBPUEFMX1dJRFRIX1RJTlk7Cj4gKwo+
ICsJaWYgKHBvc1swXSAmIFRJTllfQVRPTV9TSUdORUQpIHsKPiArCQl0b2stPnR5cGUgPSBPUEFM
X0RUQV9UT0tFTklEX1NJTlQ7Cj4gKwl9IGVsc2Ugewo+ICsJCXRvay0+dHlwZSA9IE9QQUxfRFRB
X1RPS0VOSURfVUlOVDsKPiArCQl0b2stPnN0b3JlZC51ID0gcG9zWzBdICYgMHgzZjsKPiArCX0K
PiArCj4gKwlyZXR1cm4gdG9rLT5sZW47Cj4gK30KPiArCj4gK3N0YXRpYyBzaXplX3QgcmVzcG9u
c2VfcGFyc2Vfc2hvcnQoc3RydWN0IG9wYWxfcmVzcF90b2sgKnRvaywKPiArCQkJCSAgIGNvbnN0
IHU4ICpwb3MpCj4gK3sKPiArCXRvay0+cG9zID0gcG9zOwo+ICsJdG9rLT5sZW4gPSAocG9zWzBd
ICYgU0hPUlRfQVRPTV9MRU5fTUFTSykgKyAxOwo+ICsJdG9rLT53aWR0aCA9IE9QQUxfV0lEVEhf
U0hPUlQ7Cj4gKwo+ICsJaWYgKHBvc1swXSAmIFNIT1JUX0FUT01fQllURVNUUklORykgewo+ICsJ
CXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfQllURVNUUklORzsKPiArCX0gZWxzZSBpZiAo
cG9zWzBdICYgU0hPUlRfQVRPTV9TSUdORUQpIHsKPiArCQl0b2stPnR5cGUgPSBPUEFMX0RUQV9U
T0tFTklEX1NJTlQ7Cj4gKwl9IGVsc2Ugewo+ICsJCXU2NCB1X2ludGVnZXIgPSAwOwo+ICsJCWlu
dCBpLCBiID0gMDsKPiArCj4gKwkJdG9rLT50eXBlID0gT1BBTF9EVEFfVE9LRU5JRF9VSU5UOwo+
ICsJCWlmICh0b2stPmxlbiA+IDkpClNob3VsZCB0aGlzIGJlIGxlbiA+IDggb3IgbGVuID49IDkg
PwoKPiArCQkJcHJfd2FybigidWludDY0IHdpdGggbW9yZSB0aGFuIDggYnl0ZXNcbiIpOwo+ICsJ
CWZvciAoaSA9IHRvay0+bGVuIC0gMTsgaSA+IDA7IGktLSkgewo+ICsJCQl1X2ludGVnZXIgfD0g
KCh1NjQpcG9zW2ldIDw8ICg4ICogYikpOwo+ICsJCQliKys7Cj4gKwkJfQpJdCBkb2Vzbid0IGxv
b2sgcGFydGljdWxhcmx5IHNhZmUgdG8ga2VlcCB1c2luZyB0aGlzIGRyaXZlciBvbiBhIGRyaXZl
CmlmIGl0IHJldHVybnMgYSBsZW4gPiA4LiBCdXQgdGhlIHNwZWNzIGRvIGFsbG93IDE2LWJ5dGUg
ZGF0YSBpbiBhIHNob3J0CmF0b20sIHNvIG1heWJlIHdlIHNob3VsZCBiYWlsIG9uIGFsbG93aW5n
IHRoZSBkcml2ZXIgdG8gbWFuYWdlIHRoZQpkcml2ZSwgb3IgY2hhbmdlIHRoZSB0eXBlcyB0byBz
b21lIDE2LWJ5dGUgdHlwZT8KCj4gKwkJdG9rLT5zdG9yZWQudSA9IHVfaW50ZWdlcjsKPiArCX0K
PiArCj4gKwlyZXR1cm4gdG9rLT5sZW47Cj4gK30KPiArCj4gK3N0YXRpYyBzaXplX3QgcmVzcG9u
c2VfcGFyc2VfbWVkaXVtKHN0cnVjdCBvcGFsX3Jlc3BfdG9rICp0b2ssCj4gKwkJCQkgICAgY29u
c3QgdTggKnBvcykKPiArewo+ICsJdG9rLT5wb3MgPSBwb3M7Cj4gKwl0b2stPmxlbiA9ICgoKHBv
c1swXSAmIE1FRElVTV9BVE9NX0xFTl9NQVNLKSA8PCA4KSB8IHBvc1sxXSkgKyAyOwo+ICsJdG9r
LT53aWR0aCA9IE9QQUxfV0lEVEhfTUVESVVNOwo+ICsKPiArCWlmIChwb3NbMF0gJiBNRURJVU1f
QVRPTV9CWVRFU1RSSU5HKQo+ICsJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfQllURVNU
UklORzsKPiArCWVsc2UgaWYgKHBvc1swXSAmIE1FRElVTV9BVE9NX1NJR05FRCkKPiArCQl0b2st
PnR5cGUgPSBPUEFMX0RUQV9UT0tFTklEX1NJTlQ7Cj4gKwllbHNlCj4gKwkJdG9rLT50eXBlID0g
T1BBTF9EVEFfVE9LRU5JRF9VSU5UOwo+ICsKPiArCXJldHVybiB0b2stPmxlbjsKPiArfQo+ICsK
PiArI2RlZmluZSBMT05HX0FUT01fSUQgKEJJVCg3KSB8IEJJVCg2KSB8IEJJVCg1KSkKPiArI2Rl
ZmluZSBMT05HX0FUT01fQllURVNUUklORyBCSVQoMSkKPiArI2RlZmluZSBMT05HX0FUT01fU0lH
TkVEIEJJVCgwKQo+ICtzdGF0aWMgc2l6ZV90IHJlc3BvbnNlX3BhcnNlX2xvbmcoc3RydWN0IG9w
YWxfcmVzcF90b2sgKnRvaywKPiArCQkJCSAgY29uc3QgdTggKnBvcykKPiArewo+ICsJdG9rLT5w
b3MgPSBwb3M7Cj4gKwl0b2stPmxlbiA9ICgocG9zWzFdIDw8IDE2KSB8IChwb3NbMl0gPDwgOCkg
fCBwb3NbM10pICsgNDsKPiArCXRvay0+d2lkdGggPSBPUEFMX1dJRFRIX0xPTkc7Cj4gKwo+ICsJ
aWYgKHBvc1swXSAmIExPTkdfQVRPTV9CWVRFU1RSSU5HKQo+ICsJCXRvay0+dHlwZSA9IE9QQUxf
RFRBX1RPS0VOSURfQllURVNUUklORzsKPiArCWVsc2UgaWYgKHBvc1swXSAmIExPTkdfQVRPTV9T
SUdORUQpCj4gKwkJdG9rLT50eXBlID0gT1BBTF9EVEFfVE9LRU5JRF9TSU5UOwo+ICsJZWxzZQo+
ICsJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfVUlOVDsKPiArCj4gKwlyZXR1cm4gdG9r
LT5sZW47Cj4gK30KPiArCj4gK3N0YXRpYyBzaXplX3QgcmVzcG9uc2VfcGFyc2VfdG9rZW4oc3Ry
dWN0IG9wYWxfcmVzcF90b2sgKnRvaywKPiArCQkJCSAgIGNvbnN0IHU4ICpwb3MpCj4gK3sKPiAr
CXRvay0+cG9zID0gcG9zOwo+ICsJdG9rLT5sZW4gPSAxOwo+ICsJdG9rLT50eXBlID0gT1BBTF9E
VEFfVE9LRU5JRF9UT0tFTjsKPiArCXRvay0+d2lkdGggPSBPUEFMX1dJRFRIX1RPS0VOOwo+ICsK
PiArCXJldHVybiB0b2stPmxlbjsKPiArfQo+ICsKPiArc3RhdGljIGludCByZXNwb25zZV9wYXJz
ZShjb25zdCB1OCAqYnVmLCBzaXplX3QgbGVuZ3RoLAo+ICsJCQkgIHN0cnVjdCBwYXJzZWRfcmVz
cCAqcmVzcCkKPiArewo+ICsJY29uc3Qgc3RydWN0IG9wYWxfaGVhZGVyICpoZHI7Cj4gKwlzdHJ1
Y3Qgb3BhbF9yZXNwX3RvayAqaXRlcjsKPiArCWludCByZXQsIG51bV9lbnRyaWVzID0gMDsKPiAr
CXUzMiBjcG9zID0gMCwgdG90YWw7Cj4gKwlzaXplX3QgdG9rZW5fbGVuZ3RoOwo+ICsJY29uc3Qg
dTggKnBvczsKPiArCj4gKwlpZiAoIWJ1ZikKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCj4gKwlp
ZiAoIXJlc3ApCj4gKwkJcmV0dXJuIC1FRkFVTFQ7Cj4gKwo+ICsJaGRyID0gKHN0cnVjdCBvcGFs
X2hlYWRlciAqKWJ1ZjsKPiArCXBvcyA9IGJ1ZjsKPiArCXBvcyArPSBzaXplb2YoKmhkcik7Cj4g
Kwo+ICsJcHJfZGVidWcoIlJlc3BvbnNlIHNpemU6IGNwOiAlZCwgcGt0OiAlZCwgc3VicGt0OiAl
ZFxuIiwKPiArCQkgYmUzMl90b19jcHUoaGRyLT5jcC5sZW5ndGgpLAo+ICsJCSBiZTMyX3RvX2Nw
dShoZHItPnBrdC5sZW5ndGgpLAo+ICsJCSBiZTMyX3RvX2NwdShoZHItPnN1YnBrdC5sZW5ndGgp
KTsKPiArCj4gKwlpZiAoKGhkci0+Y3AubGVuZ3RoID09IDApCj4gKwkgICAgfHwgKGhkci0+cGt0
Lmxlbmd0aCA9PSAwKQo+ICsJICAgIHx8IChoZHItPnN1YnBrdC5sZW5ndGggPT0gMCkpIHsKPiAr
CQlwcl9lcnIoIkJhZCBoZWFkZXIgbGVuZ3RoLiBjcDogJWQsIHBrdDogJWQsIHN1YnBrdDogJWRc
biIsCj4gKwkJICAgICAgIGJlMzJfdG9fY3B1KGhkci0+Y3AubGVuZ3RoKSwKPiArCQkgICAgICAg
YmUzMl90b19jcHUoaGRyLT5wa3QubGVuZ3RoKSwKPiArCQkgICAgICAgYmUzMl90b19jcHUoaGRy
LT5zdWJwa3QubGVuZ3RoKSk7Cj4gKwkJcHJpbnRfYnVmZmVyKHBvcywgc2l6ZW9mKCpoZHIpKTsK
PiArCQlyZXQgPSAtRUlOVkFMOwo+ICsJCWdvdG8gZXJyOwo+ICsJfQo+ICsKPiArCWlmIChwb3Mg
PiBidWYgKyBsZW5ndGgpIHsKPiArCQlyZXQgPSAtRUZBVUxUOwo+ICsJCWdvdG8gZXJyOwo+ICsJ
fQo+ICsKPiArCWl0ZXIgPSByZXNwLT50b2tzOwo+ICsJdG90YWwgPSBiZTMyX3RvX2NwdShoZHIt
PnN1YnBrdC5sZW5ndGgpOwo+ICsJcHJpbnRfYnVmZmVyKHBvcywgdG90YWwpOwo+ICsJd2hpbGUg
KGNwb3MgPCB0b3RhbCkgewo+ICsJCWlmICghKHBvc1swXSAmIDB4ODApKSAvKiB0aW55IGF0b20g
Ki8KPiArCQkJdG9rZW5fbGVuZ3RoID0gcmVzcG9uc2VfcGFyc2VfdGlueShpdGVyLCBwb3MpOwo+
ICsJCWVsc2UgaWYgKCEocG9zWzBdICYgMHg0MCkpIC8qIHNob3J0IGF0b20gKi8KPiArCQkJdG9r
ZW5fbGVuZ3RoID0gcmVzcG9uc2VfcGFyc2Vfc2hvcnQoaXRlciwgcG9zKTsKPiArCQllbHNlIGlm
ICghKHBvc1swXSAmIDB4MjApKSAvKiBtZWRpdW0gYXRvbSAqLwo+ICsJCQl0b2tlbl9sZW5ndGgg
PSByZXNwb25zZV9wYXJzZV9tZWRpdW0oaXRlciwgcG9zKTsKPiArCQllbHNlIGlmICghKHBvc1sw
XSAmIDB4MTApKSAvKiBsb25nIGF0b20gKi8KPiArCQkJdG9rZW5fbGVuZ3RoID0gcmVzcG9uc2Vf
cGFyc2VfbG9uZyhpdGVyLCBwb3MpOwo+ICsJCWVsc2UgLyogVE9LRU4gKi8KPiArCQkJdG9rZW5f
bGVuZ3RoID0gcmVzcG9uc2VfcGFyc2VfdG9rZW4oaXRlciwgcG9zKTsKPiArCj4gKwkJcG9zICs9
IHRva2VuX2xlbmd0aDsKPiArCQljcG9zICs9IHRva2VuX2xlbmd0aDsKPiArCQlpdGVyKys7Cj4g
KwkJbnVtX2VudHJpZXMrKzsKPiArCX0KPiArCj4gKwlpZiAobnVtX2VudHJpZXMgPT0gMCkgewo+
ICsJCXByX2VycigiQ291bGRuJ3QgcGFyc2UgcmVzcG9uc2UuXG4iKTsKPiArCQlyZXQgPSAtRUlO
VkFMOwo+ICsJCWdvdG8gZXJyOwo+ICsJfQo+ICsJcmVzcC0+bnVtID0gbnVtX2VudHJpZXM7Cj4g
Kwo+ICsJcmV0dXJuIDA7Cj4gK2VycjoKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRp
YyBzaXplX3QgcmVzcG9uc2VfZ2V0X3N0cmluZyhjb25zdCBzdHJ1Y3QgcGFyc2VkX3Jlc3AgKnJl
c3AsIGludCBuLAo+ICsJCQkJICBjb25zdCBjaGFyICoqc3RvcmUpCj4gK3sKPiArCSpzdG9yZSA9
IE5VTEw7Cj4gKwlpZiAoIXJlc3ApIHsKPiArCQlwcl9lcnIoIlJlc3BvbnNlIGlzIE5VTExcbiIp
Owo+ICsJCXJldHVybiAwOwo+ICsJfQo+ICsKPiArCWlmIChuID4gcmVzcC0+bnVtKSB7Cj4gKwkJ
cHJfZXJyKCJSZXNwb25zZSBoYXMgJWQgdG9rZW5zLiBDYW4ndCBhY2Nlc3MgJWRcbiIsCj4gKwkJ
ICAgICAgIHJlc3AtPm51bSwgbik7Cj4gKwkJcmV0dXJuIDA7Cj4gKwl9Cj4gKwo+ICsJaWYgKHJl
c3AtPnRva3Nbbl0udHlwZSAhPSBPUEFMX0RUQV9UT0tFTklEX0JZVEVTVFJJTkcpIHsKPiArCQlw
cl9lcnIoIlRva2VuIGlzIG5vdCBhIGJ5dGUgc3RyaW5nIVxuIik7Cj4gKwkJcmV0dXJuIDA7Cj4g
Kwl9Cj4gKwo+ICsJKnN0b3JlID0gcmVzcC0+dG9rc1tuXS5wb3MgKyAxOwo+ICsJcmV0dXJuIHJl
c3AtPnRva3Nbbl0ubGVuIC0gMTsKPiArfQo+ICsKPiArc3RhdGljIHU2NCByZXNwb25zZV9nZXRf
dTY0KGNvbnN0IHN0cnVjdCBwYXJzZWRfcmVzcCAqcmVzcCwgaW50IG4pCj4gK3sKPiArCWlmICgh
cmVzcCkgewo+ICsJCXByX2VycigiUmVzcG9uc2UgaXMgTlVMTFxuIik7Cj4gKwkJcmV0dXJuIDA7
Cj4gKwl9Cj4gKwo+ICsJaWYgKG4gPiByZXNwLT5udW0pIHsKPiArCQlwcl9lcnIoIlJlc3BvbnNl
IGhhcyAlZCB0b2tlbnMuIENhbid0IGFjY2VzcyAlZFxuIiwKPiArCQkgICAgICAgcmVzcC0+bnVt
LCBuKTsKPiArCQlyZXR1cm4gMDsKPiArCX0KPiArCj4gKwlpZiAocmVzcC0+dG9rc1tuXS50eXBl
ICE9IE9QQUxfRFRBX1RPS0VOSURfVUlOVCkgewo+ICsJCXByX2VycigiVG9rZW4gaXMgbm90IHVu
c2lnbmVkIGl0OiAlZFxuIiwKPiArCQkgICAgICAgcmVzcC0+dG9rc1tuXS50eXBlKTsKPiArCQly
ZXR1cm4gMDsKPiArCX0KPiArCj4gKwlpZiAoISgocmVzcC0+dG9rc1tuXS53aWR0aCA9PSBPUEFM
X1dJRFRIX1RJTlkpIHx8Cj4gKwkgICAgICAocmVzcC0+dG9rc1tuXS53aWR0aCA9PSBPUEFMX1dJ
RFRIX1NIT1JUKSkpIHsKPiArCQlwcl9lcnIoIkF0b20gaXMgbm90IHNob3J0IG9yIHRpbnk6ICVk
XG4iLAo+ICsJCSAgICAgICByZXNwLT50b2tzW25dLndpZHRoKTsKPiArCQlyZXR1cm4gMDsKPiAr
CX0KPiArCj4gKwlyZXR1cm4gcmVzcC0+dG9rc1tuXS5zdG9yZWQudTsKPiArfQo+ICsKPiArc3Rh
dGljIHU4IHJlc3BvbnNlX3N0YXR1cyhjb25zdCBzdHJ1Y3QgcGFyc2VkX3Jlc3AgKnJlc3ApCj4g
K3sKPiArCWlmICgodG9rZW5fdHlwZShyZXNwLCAwKSA9PSBPUEFMX0RUQV9UT0tFTklEX1RPS0VO
KQo+ICsJICAgICYmIChyZXNwb25zZV9nZXRfdG9rZW4ocmVzcCwgMCkgPT0gT1BBTF9FTkRPRlNF
U1NJT04pKSB7Cj4gKwkJcmV0dXJuIDA7Cj4gKwl9Cj4gKwo+ICsJaWYgKHJlc3AtPm51bSA8IDUp
Cj4gKwkJcmV0dXJuIERUQUVSUk9SX05PX01FVEhPRF9TVEFUVVM7Cj4gKwo+ICsJaWYgKCh0b2tl
bl90eXBlKHJlc3AsIHJlc3AtPm51bSAtIDEpICE9IE9QQUxfRFRBX1RPS0VOSURfVE9LRU4pIHx8
Cj4gKwkgICAgKHRva2VuX3R5cGUocmVzcCwgcmVzcC0+bnVtIC0gNSkgIT0gT1BBTF9EVEFfVE9L
RU5JRF9UT0tFTikgfHwKPiArCSAgICAocmVzcG9uc2VfZ2V0X3Rva2VuKHJlc3AsIHJlc3AtPm51
bSAtIDEpICE9IE9QQUxfRU5ETElTVCkgfHwKPiArCSAgICAocmVzcG9uc2VfZ2V0X3Rva2VuKHJl
c3AsIHJlc3AtPm51bSAtIDUpICE9IE9QQUxfU1RBUlRMSVNUKSkKPiArCQlyZXR1cm4gRFRBRVJS
T1JfTk9fTUVUSE9EX1NUQVRVUzsKPiArCj4gKwlyZXR1cm4gcmVzcG9uc2VfZ2V0X3U2NChyZXNw
LCByZXNwLT5udW0gLSA0KTsKPiArfQo+ICsKPiArLyogUGFyc2VzIGFuZCBjaGVja3MgZm9yIGVy
cm9ycyAqLwo+ICtzdGF0aWMgaW50IHBhcnNlX2FuZF9jaGVja19zdGF0dXMoc3RydWN0IG9wYWxf
ZGV2ICpkZXYpCj4gK3sKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJaW50IGVycm9yOwo+
ICsKPiArCWNtZCA9ICZkZXYtPmNtZDsKPiArCXByaW50X2J1ZmZlcihjbWQtPmNtZCwgY21kLT5w
b3MpOwo+ICsKPiArCWVycm9yID0gcmVzcG9uc2VfcGFyc2UoY21kLT5yZXNwLCBJT19CVUZGRVJf
TEVOR1RILCAmZGV2LT5wYXJzZWQpOwo+ICsJaWYgKGVycm9yKSB7Cj4gKwkJcHJfZXJyKCIlczog
Q291bGRuJ3QgcGFyc2UgcmVzcG9uc2UuXG4iLCBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJZ290byBl
cnJfcmV0dXJuOwo+ICsJfQo+ICsKPiArCWVycm9yID0gcmVzcG9uc2Vfc3RhdHVzKCZkZXYtPnBh
cnNlZCk7Cj4gKwlpZiAoZXJyb3IpCj4gKwkJcHJfZXJyKCIlczogUmVzcG9uc2UgU3RhdHVzOiAl
ZFxuIiwgZGV2LT5kaXNrX25hbWUsCj4gKwkJICAgICAgIGVycm9yKTsKPiArCj4gKyBlcnJfcmV0
dXJuOgo+ICsJcmV0dXJuIGVycm9yOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBjbGVhcl9vcGFs
X2NtZChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCkKPiArewo+ICsJY21kLT5wb3MgPSBzaXplb2Yoc3Ry
dWN0IG9wYWxfaGVhZGVyKTsKPiArCW1lbXNldChjbWQtPmNtZCwgMCwgSU9fQlVGRkVSX0xFTkdU
SCk7Cj4gKwljbWQtPmNiID0gTlVMTDsKPiArCWNtZC0+Y2JfZGF0YSA9IE5VTEw7Cj4gK30KPiAr
Cj4gK3N0YXRpYyB2b2lkIHN0YXJ0X29wYWxfc2Vzc2lvbl9jb250KGludCBlcnJvciwgdm9pZCAq
ZGF0YSkKPiArewo+ICsJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOwo+ICsJdTMyIEhTTiwg
VFNOOwo+ICsKPiArCWlmIChlcnJvcikKPiArCQlnb3RvIGVycl9yZXR1cm47Cj4gKwo+ICsJZXJy
b3IgPSBwYXJzZV9hbmRfY2hlY2tfc3RhdHVzKGRldik7Cj4gKwlpZiAoZXJyb3IpCj4gKwkJZ290
byBlcnJfcmV0dXJuOwo+ICsKPiArCUhTTiA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFyc2Vk
LCA0KTsKPiArCVRTTiA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFyc2VkLCA1KTsKPiArCj4g
KwlpZiAoSFNOID09IDAgJiYgVFNOID09IDApIHsKPiArCQlwcl9lcnIoIiVzOiBDb3VsZG4ndCBh
dXRoZW50aWNhdGUgc2Vzc2lvblxuIiwgZGV2LT5kaXNrX25hbWUpOwo+ICsJCWVycm9yID0gLUVQ
RVJNOwo+ICsJCWdvdG8gZXJyX3JldHVybjsKPiArCX0KPiArCj4gKwlkZXYtPkhTTiA9IEhTTjsK
PiArCWRldi0+VFNOID0gVFNOOwo+ICsKPiArZXJyX3JldHVybjoKPiArCWlmIChkZXYtPm9wZXJf
Y2IpCj4gKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBkZXYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50
IGdldF9vcGFsX2tleShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJc3RydWN0IGtleSAq
dWtleSA9IE5VTEw7Cj4gKwljb25zdCB1OCAqdG1wa2V5ID0gTlVMTDsKPiArCXNpemVfdCB0bXBs
ZW47Cj4gKwlpbnQgcmV0ID0gMDsKPiArCj4gKwlpZiAoZGV2LT5rZXlfdHlwZSA9PSBPUEFMX0tF
WV9QTEFJTikgewo+ICsJCXRtcGtleSA9IGRldi0+a2V5X25hbWU7Cj4gKwkJdG1wbGVuID0gZGV2
LT5rZXlfbmFtZV9sZW47Cj4gKwl9IGVsc2UgaWYgKGRldi0+a2V5X3R5cGUgPT0gT1BBTF9LRVlf
S0VZUklORykgewo+ICsJCXVrZXkgPSByZXF1ZXN0X3VzZXJfa2V5KGRldi0+a2V5X25hbWUsICZ0
bXBrZXksICZ0bXBsZW4pOwo+ICsJCWlmIChJU19FUlIodWtleSkpIHsKPiArCQkJcHJfZXJyKCIl
czogQ2FuJ3QgcmV0cmlldmUga2V5OiAlbGRcbiIsIGRldi0+ZGlza19uYW1lLAo+ICsJCQkgICAg
ICAgUFRSX0VSUih1a2V5KSk7Cj4gKwkJCXJldHVybiBQVFJfRVJSKHVrZXkpOwo+ICsJCX0KPiAr
CX0gZWxzZSB7Cj4gKwkJcHJfZXJyKCJSZXF1ZXN0ZWQgaW52YWxpZCBrZXkgdHlwZTogJWRcbiIs
IGRldi0+a2V5X3R5cGUpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCWlmICh0
bXBsZW4gPiBPUEFMX0tFWV9NQVgpIHsKPiArCQlwcl9lcnIoIlJlcXVlc3RlZCBrZXkgd2l0aCBp
bnZhbGlkIHNpemU6ICV6ZFxuIiwgdG1wbGVuKTsKPiArCQlyZXQgPSAtRUlOVkFMOwo+ICsJCWdv
dG8gZXJyX2V4aXQ7Cj4gKwl9Cj4gKwo+ICsJZGV2LT5rZXlfbGVuID0gdG1wbGVuOwo+ICsJaWYg
KCFtZW1jcHkoZGV2LT5rZXksIHRtcGtleSwgdG1wbGVuKSkgewo+ICsJCXByX2VycigiRXJyb3Ig
d2hlbiBjb3B5aW5nIGtleSIpOwo+ICsJCXJldCA9IC1FRkFVTFQ7Cj4gKwkJZ290byBlcnJfZXhp
dDsKPiArCX0KPiArCj4gK2Vycl9leGl0Ogo+ICsJa2V5X3B1dCh1a2V5KTsKPiArCj4gKwlyZXR1
cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgY2xlYW5fb3BhbF9rZXkoc3RydWN0IG9wYWxf
ZGV2ICpkZXYpCj4gK3sKPiArCW1lbXNldChkZXYtPmtleSwgMCwgT1BBTF9LRVlfTUFYKTsKPiAr
CWRldi0+a2V5X2xlbiA9IDA7Cj4gK30KPiArCj4gK3N0YXRpYyBpbmxpbmUgdm9pZCBjbGVhbl9m
dW5jdGlvbl9kYXRhKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwkJZGV2LT5mdW5jX2Rh
dGEgPSBOVUxMOwo+ICsJCWRldi0+bnVtX2Z1bmNfZGF0YSA9IDA7Cj4gK30KPiArCj4gKy8qIFRo
aXMgaXMgYSBnZW5lcmljIGNvbnRpbnVlIGZuLgo+ICsgKiBXZSB1c2UgdGhpcyB3aGVuIHdlIGRv
bid0IGNhcmUgYWJvdXQgdGhlIHJlc3BvbnNlIGRhdGEKPiArICogYW5kIHNpbXBseSB3YW50IHRv
IGNoZWNrIHRoZSBzdGF0dXMgYW5kIGNvbnRpbnVlLgo+ICsgKi8KPiArc3RhdGljIHZvaWQgZ2Vu
ZXJpY19jb250KGludCBlcnJvciwgdm9pZCAqZGF0YSkKPiArewo+ICsJc3RydWN0IG9wYWxfZGV2
ICpkZXYgPSBkYXRhOwo+ICsKPiArCWlmIChlcnJvcikKPiArCQlnb3RvIGVycl9yZXR1cm47Cj4g
Kwo+ICsJZXJyb3IgPSBwYXJzZV9hbmRfY2hlY2tfc3RhdHVzKGRldik7Cj4gKwo+ICsgZXJyX3Jl
dHVybjoKPiArCWlmIChkZXYtPm9wZXJfY2IpCj4gKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBkZXYp
Owo+ICt9CgpIb3cgYWJvdXQ6CgpzdGF0aWMgdm9pZCBnZW5lcmljX2NvbnQoaW50IGVycm9yLCB2
b2lkICpkYXRhKQp7CglzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CgoJaWYgKCFlcnJvcikK
CQllcnJvciA9IHBhcnNlX2FuZF9jaGVja19zdGF0dXMoZGV2KTsKCglpZiAoZGV2LT5vcGVyX2Ni
KQoJCWRldi0+b3Blcl9jYihlcnJvciwgZGV2KTsKfQoKPiArCj4gK3N0YXRpYyB2b2lkIGVuZF9z
ZXNzaW9uX2NvbnQoaW50IGVycm9yLCB2b2lkICpkYXRhKQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9k
ZXYgKmRldiA9IGRhdGE7Cj4gKwo+ICsJZGV2LT5IU04gPSAwOwo+ICsJZGV2LT5UU04gPSAwOwo+
ICsJZ2VuZXJpY19jb250KGVycm9yLCBkYXRhKTsKPiArfQo+ICsKPiArc3RhdGljIGludCBmaW5h
bGl6ZV9hbmRfc2VuZChzdHJ1Y3Qgb3BhbF9kZXYgKmRldiwgc3RydWN0IG9wYWxfY21kICpjbWQs
Cj4gKwkJCSAgICAgc2VjX2NiIGNvbnQpCj4gK3sKPiArCWludCByZXQ7Cj4gKwo+ICsJcmV0ID0g
Y21kX2ZpbmFsaXplKGNtZCwgZGV2LT5IU04sIGRldi0+VFNOKTsKPiArCWlmIChyZXQpIHsKPiAr
CQlwcl9lcnIoIiVzOiBFcnJvciBmaW5hbGl6aW5nIGNvbW1hbmQgYnVmZmVyOiAlZFxuIiwKPiAr
CQkgICAgICAgZGV2LT5kaXNrX25hbWUsIHJldCk7Cj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiAr
Cj4gKwlwcmludF9idWZmZXIoY21kLT5jbWQsIGNtZC0+cG9zKTsKPiArCj4gKwlyZXQgPSBvcGFs
X3NlbmRfcmVjdihkZXYsIGNvbnQsIGRldik7Cj4gKwlpZiAocmV0KQo+ICsJCXByX2VycigiJXM6
IEVycm9yIHJ1bm5pbmcgY29tbWFuZDogJWRcbiIsCj4gKwkJICAgICAgIGRldi0+ZGlza19uYW1l
LCByZXQpOwo+ICsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgd2FpdF9m
b3JfY21kX2NvbXBsZXRpb24oc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbikKPiAr
ewo+ICsJd2FpdF9mb3JfY29tcGxldGlvbl9pbnRlcnJ1cHRpYmxlKCZjb21wbGV0aW9uLT5jbWRf
Y29tcGxldGlvbik7Cj4gKwlyZXR1cm4gY29tcGxldGlvbi0+Y29tcGxldGlvbl9zdGF0dXM7Cj4g
K30KPiArCj4gK3N0YXRpYyBpbnQgZ2VuX2tleShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+
ICsJY29uc3QgdTggKm1ldGhvZDsKPiArCXU4IHVpZFtPUEFMX1VJRF9MRU5HVEhdOwo+ICsJc3Ry
dWN0IG9wYWxfY21kICpjbWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWNtZCA9ICZkZXYtPmNtZDsK
PiArCWNsZWFyX29wYWxfY21kKGNtZCk7Cj4gKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsK
PiArCj4gKwltZW1jcHkodWlkLCBkZXYtPnByZXZfZGF0YSwgbWluKHNpemVvZih1aWQpLCBkZXYt
PnByZXZfZF9sZW4pKTsKPiArCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9HRU5LRVldOwo+ICsJ
a2ZyZWUoZGV2LT5wcmV2X2RhdGEpOwo+ICsJZGV2LT5wcmV2X2RhdGEgPSBOVUxMOwo+ICsKPiAr
CXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgMmMiLAo+ICsJCQkJICAgIE9Q
QUxfQ0FMTCwKPiArCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAgICBtZXRo
b2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4g
KwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIl
czogRXJyb3IgYnVpbGRpbmcgZ2VuIGtleSBjb21tYW5kXG4iLAo+ICsJCSAgICAgICBkZXYtPmRp
c2tfbmFtZSk7Cj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiArCj4gKwlyZXR1cm4gZmluYWxpemVf
YW5kX3NlbmQoZGV2LCBjbWQsIGdlbmVyaWNfY29udCk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lk
IGdldF9hY3RpdmVfa2V5X2NvbnQoaW50IGVycm9yLCB2b2lkICpkYXRhKQo+ICt7Cj4gKwlzdHJ1
Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7Cj4gKwljb25zdCBjaGFyICphY3RpdmVrZXk7Cj4gKwlz
aXplX3Qga2V5bGVuOwo+ICsKPiArCWlmIChlcnJvcikKPiArCQlnb3RvIGVycl9yZXR1cm47Cj4g
Kwo+ICsJZXJyb3IgPSBwYXJzZV9hbmRfY2hlY2tfc3RhdHVzKGRldik7Cj4gKwlpZiAoZXJyb3Ip
Cj4gKwkJZ290byBlcnJfcmV0dXJuOwo+ICsJa2V5bGVuID0gcmVzcG9uc2VfZ2V0X3N0cmluZygm
ZGV2LT5wYXJzZWQsIDQsICZhY3RpdmVrZXkpOwo+ICsJaWYgKCFhY3RpdmVrZXkpIHsKPiArCQlw
cl9lcnIoIiVzOiBDb3VsZG4ndCBleHRyYWN0IHRoZSBBY3RpdmVrZXkgZnJvbSB0aGUgcmVzcG9u
c2VcbiIsCj4gKwkJICAgICAgIF9fZnVuY19fKTsKPiArCQllcnJvciA9IDB4MEE7Cj4gKwkJZ290
byBlcnJfcmV0dXJuOwo+ICsJfQo+ICsJZGV2LT5wcmV2X2RhdGEgPSBrbWVtZHVwKGFjdGl2ZWtl
eSwga2V5bGVuLCBHRlBfS0VSTkVMKTsKPiArCj4gKwlpZiAoIWRldi0+cHJldl9kYXRhKQo+ICsJ
CWVycm9yID0gLUVOT01FTTsKPiArCj4gKwlkZXYtPnByZXZfZF9sZW4gPSBrZXlsZW47Cj4gKwo+
ICtlcnJfcmV0dXJuOgo+ICsJaWYgKGRldi0+b3Blcl9jYikKPiArCQlkZXYtPm9wZXJfY2IoZXJy
b3IsIGRldik7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgZ2V0X2FjdGl2ZV9rZXkoc3RydWN0IG9w
YWxfZGV2ICpkZXYpCj4gK3sKPiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwl1OCB1aWRbT1BBTF9V
SURfTEVOR1RIXTsKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJaW50IHJldDsKPiArCj4g
KwljbWQgPSAmZGV2LT5jbWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+ICsJc2V0X2NvbUlE
KGNtZCwgZGV2LT5jb21JRCk7Cj4gKwo+ICsJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX0dFVF07
Cj4gKwo+ICsJcmV0ID0gYnVpbGRfbG9ja2luZ19yYW5nZSh1aWQsIHNpemVvZih1aWQpLCBkZXYt
PmxyKTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogQ2FuJ3QgYnVpbGQgbG9j
a2luZyByYW5nZVxuIiwgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJ
fQo+ICsKPiArCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgNmMgNGMgMmMi
LAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwK
PiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BB
TF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9T
VEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIHN0YXJ0Q2xvdW1uICov
Cj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMTAsIC8qIEFjdGl2ZUtleSAqLwo+ICsJCQkJICAg
IE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAg
T1BBTF9USU5ZX1VJTlRfMDQsIC8qIGVuZENvbHVtbiAqLwo+ICsJCQkJICAgIE9QQUxfVElOWV9V
SU5UXzEwLCAvKiBBY3RpdmVLZXkgKi8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJ
CQkJICAgIE9QQUxfRU5ETElTVCwKPiArCQkJCSAgICBPUEFMX0VORExJU1QpOwo+ICsJaWYgKHJl
dCA8IDApIHsKPiArCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBnZXQgYWN0aXZlIGtleSBj
b21tYW5kXG4iLAo+ICsJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJcmV0dXJuIHJldDsK
PiArCX0KPiArCj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdldF9hY3Rp
dmVfa2V5X2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNldHVwX2xvY2tpbmdfcmFuZ2Uo
c3RydWN0IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwl1OCB1
aWRbT1BBTF9VSURfTEVOR1RIXTsKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJc3RydWN0
IG9wYWxfdXNlcl9scl9zZXR1cCAqc2V0dXA7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWNtZCA9ICZk
ZXYtPmNtZDsKPiArCWNsZWFyX29wYWxfY21kKGNtZCk7Cj4gKwlzZXRfY29tSUQoY21kLCBkZXYt
PmNvbUlEKTsKPiArCj4gKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU0VUXTsKPiArCXJldCA9
IGJ1aWxkX2xvY2tpbmdfcmFuZ2UodWlkLCBzaXplb2YodWlkKSwgZGV2LT5scik7Cj4gKwlpZiAo
cmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2VcbiIs
IGRldi0+ZGlza19uYW1lKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0KPiArCXNldHVwID0g
ZGV2LT5mdW5jX2RhdGFbZGV2LT5zdGF0ZSAtIDFdOwo+ICsKPiArCXJldCA9IHRlc3RfYW5kX2Fk
ZF90b2tlbl92YShjbWQsICJjMnMgIDRjIDJjdWMgMmN1YyAyY3VjIDJjdSA0YyIsCj4gKwkJCQkg
ICAgT1BBTF9DQUxMLAo+ICsJCQkJICAgIHVpZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAg
IG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTElT
VCwKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1ZBTFVFUywKPiAr
CQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4g
KwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIFJhbmdlIFN0YXJ0ICovCj4gKwkJCQkgICAg
c2V0dXAtPnJhbmdlX3N0YXJ0LAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkg
ICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDQsIC8qIFJhbmdl
IExlbmd0aCAqLwo+ICsJCQkJICAgIHNldHVwLT5yYW5nZV9sZW5ndGgsCj4gKwkJCQkgICAgT1BB
TF9FTkROQU1FLAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFM
X1RJTllfVUlOVF8wNSwgLyogUmVhZExvY2tFbmFibGVkICovCj4gKwkJCQkgICAgISFzZXR1cC0+
UkxFLAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5B
TUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIFdyaXRlTG9ja0VuYWJsZWQgKi8K
PiArCQkJCSAgICAhIXNldHVwLT5XTEUsCj4gKwo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiAr
CQkJCSAgICBPUEFMX0VORExJU1QsCj4gKwkJCQkgICAgT1BBTF9FTkROQU1FLAo+ICsJCQkJICAg
IE9QQUxfRU5ETElTVCk7Cj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9y
IGJ1aWxkaW5nIFNldHVwIExvY2tpbmcgcmFuZ2UgY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRl
di0+ZGlza19uYW1lKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsKPiArCX0KPiArCj4gKwlyZXR1cm4g
ZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdlbmVyaWNfY29udCk7Cj4gK30KPiArCj4gK3N0
YXRpYyBpbnQgc3RhcnRfYWRtaW5zcF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYs
Cj4gKwkJCQkgICAgICBlbnVtIE9QQUxfVUlEIGF1dGgsCj4gKwkJCQkgICAgICBjb25zdCBjaGFy
ICprZXksCj4gKwkJCQkgICAgICB1OCBrZXlfbGVuKQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9k
LCAqc211aWQsICphZG1pbl9zcCwgKmhzYTsKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJ
dTMyIEhTTjsKPiArCWludCByZXQ7Cj4gKwo+ICsJaWYgKGtleSA9PSBOVUxMICYmIGF1dGggIT0g
T1BBTF9BTllCT0RZX1VJRCkgewo+ICsJCXByX2VycigiJXM6IEF0dGVtcHRlZCB0byBvcGVuIEFE
TUlOX1NQIFNlc3Npb24gd2l0aG91dCBhIEhvc3QiIFwKPiArCQkgICAgICAgIkNoYWxsZW5nZSwg
YW5kIG5vdCBhcyB0aGUgQW55Ym9keSBVSURcbiIsIF9fZnVuY19fKTsKPiArCQlyZXR1cm4gMTsK
PiArCX0KPiArCj4gKwljbWQgPSAmZGV2LT5jbWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+
ICsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsJSFNOID0gMHg0MTsKPiArCj4g
KwlzbXVpZCA9IE9QQUxVSURbT1BBTF9TTVVJRF9VSURdOwo+ICsJbWV0aG9kID0gT1BBTE1FVEhP
RFtPUEFMX1NUQVJUU0VTU0lPTl07Cj4gKwlhZG1pbl9zcCA9IE9QQUxVSURbT1BBTF9BRE1JTlNQ
X1VJRF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyBjdXNj
IiwKPiArCQkJCSAgICBPUEFMX0NBTEwsCj4gKwkJCQkgICAgc211aWQsIE9QQUxfVUlEX0xFTkdU
SCwKPiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCQkJCSAgICBPUEFM
X1NUQVJUTElTVCwKPiArCQkJCSAgICBIU04sCj4gKwkJCQkgICAgYWRtaW5fc3AsIE9QQUxfVUlE
X0xFTkdUSCwKPiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMSk7Cj4gKwlpZiAocmV0IDwgMCkg
ewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIHN0YXJ0IGFkbWluc3Agc2Vzc2lvbiBj
b21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7
Cj4gKwl9Cj4gKwo+ICsJc3dpdGNoIChhdXRoKSB7Cj4gKwljYXNlIE9QQUxfQU5ZQk9EWV9VSUQ6
Cj4gKwkJLyogbm90aGluZyBsZWZ0IHRvIGRvIGZvciBhbnlib2R5LCBqdXN0IGVuZCBhbmQgZmlu
YWxpemUgKi8KPiArCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYyIsCj4gKwkJ
CQkJICAgIE9QQUxfRU5ETElTVCk7Cj4gKwkJYnJlYWs7Cj4gKwljYXNlIE9QQUxfU0lEX1VJRDoK
PiArCQloc2EgPSBPUEFMVUlEW09QQUxfU0lEX1VJRF07Cj4gKwkJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgIjJjIHMgM2MgcyAyYyIsCj4gKwkJCQkJICAgIE9QQUxfU1RBUlROQU1F
LAo+ICsJCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMCwgLyogSG9zdENoYWxsZW5nZSAqLwo+ICsJ
CQkJCSAgICBrZXksIGtleV9sZW4sCj4gKwkJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCQkJCQkg
ICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLCAvKiBIb3N0
U2lnbkF1dGggKi8KPiArCQkJCQkgICAgaHNhLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwkJCQkJICAg
IE9QQUxfRU5ETkFNRSwKPiArCQkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCQlicmVhazsKPiAr
CWRlZmF1bHQ6Cj4gKwkJcHJfZXJyKCJDYW5ub3Qgc3RhcnQgQWRtaW4gU1Agc2Vzc2lvbiB3aXRo
IGF1dGggJWRcbiIsIGF1dGgpOwo+ICsJCXJldHVybiAxOwo+ICsJfQo+ICsKPiArCWlmIChyZXQg
PCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgc3RhcnQgYWRtaW5zcCBzZXNz
aW9uIGNvbW1hbmQuXG4iLAo+ICsJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJcmV0dXJu
IHJldDsKPiArCX0KPiArCj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIHN0
YXJ0X29wYWxfc2Vzc2lvbl9jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBzdGFydF9hbnli
b2R5QVNQX29wYWxfc2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJcmV0dXJu
IHN0YXJ0X2FkbWluc3Bfb3BhbF9zZXNzaW9uKGRldiwgT1BBTF9BTllCT0RZX1VJRCwgTlVMTCwg
MCk7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgc3RhcnRfU0lEQVNQX29wYWxfc2Vzc2lvbihzdHJ1
Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJaW50IHJldDsKPiArCWNvbnN0IHU4ICprZXkgPSBk
ZXYtPnByZXZfZGF0YTsKPiArCj4gKwlpZiAoIWtleSkKPiArCQlyZXQgPSBzdGFydF9hZG1pbnNw
X29wYWxfc2Vzc2lvbihkZXYsIE9QQUxfU0lEX1VJRCwgZGV2LT5rZXksCj4gKwkJCQkJCSBkZXYt
PmtleV9sZW4pOwo+ICsJZWxzZSB7Cj4gKwkJcmV0ID0gc3RhcnRfYWRtaW5zcF9vcGFsX3Nlc3Np
b24oZGV2LCBPUEFMX1NJRF9VSUQsIGtleSwKPiArCQkJCQkJIGRldi0+cHJldl9kX2xlbik7Cj4g
KwkJa2ZyZWUoa2V5KTsKPiArCQlkZXYtPnByZXZfZGF0YSA9IE5VTEw7Cj4gKwl9Cj4gKwlyZXR1
cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHN0YXJ0X2xvY2tpbmdzcF9vcGFsX3Nlc3Np
b24oc3RydWN0IG9wYWxfZGV2ICpkZXYsCj4gKwkJCQkJZW51bSBPUEFMX1VJRCBhdXRoLCBjb25z
dCB1OCAqa2V5LAo+ICsJCQkJCXU4IGtleV9sZW4pCj4gK3sKPiArCj4gKwljb25zdCB1OCAqbWV0
aG9kLCAqc211aWQsICpsb2NraW5nX3NwLCAqaHNhOwo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7
Cj4gKwlzaXplX3Qga2xlbiA9IGtleV9sZW47Cj4gKwl1MzIgSFNOOwo+ICsJaW50IHJldDsKPiAr
Cj4gKwlpZiAoa2V5ID09IE5VTEwpIHsKPiArCQlwcl9lcnIoIkNhbm5vdCBzdGFydCBMb2NraW5n
IFNQIHNlc3Npb24gd2l0aG91dCBhIGtleVxuIik7Cj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwl9
Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCj4g
KwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsKPiArCUhTTiA9IDB4NDE7Cj4gKwo+ICsJc211
aWQgPSBPUEFMVUlEW09QQUxfU01VSURfVUlEXTsKPiArCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BB
TF9TVEFSVFNFU1NJT05dOwo+ICsJbG9ja2luZ19zcCA9IE9QQUxVSURbT1BBTF9MT0NLSU5HU1Bf
VUlEXTsKPiArCWhzYSA9IE9QQUxVSURbYXV0aF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgImMycyBjdXNjIDJjc2MgMmNzYyBjIiwKPiArCQkJCSAgICBPUEFMX0NB
TEwsCj4gKwkJCQkgICAgc211aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAgICBtZXRob2Qs
IE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJ
CQkgICAgSFNOLAo+ICsJCQkJICAgIGxvY2tpbmdfc3AsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJ
CSAgICBPUEFMX1RJTllfVUlOVF8wMSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4g
KwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDAsIC8qIEhvc3RDaGFsbGVuZ2UgKi8KPiArCQkJCSAg
ICBrZXksIGtsZW4sCj4gKwkJCQkgICAgT1BBTF9FTkROQU1FLAo+ICsKPiArCQkJCSAgICBPUEFM
X1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogSG9zdCBTaWduIEF1
dGhvcml0eSAqLwo+ICsJCQkJICAgIGhzYSwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIE9Q
QUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCj4gKwlpZiAocmV0
IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIHN0YXJ0IGFkbWluc3Agc2Vz
c2lvbiBjb21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVy
biByZXQ7Cj4gKwl9Cj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIHN0YXJ0
X29wYWxfc2Vzc2lvbl9jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGlubGluZSBpbnQgc3RhcnRf
YWRtaW4xTFNQX29wYWxfc2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJcmV0
dXJuIHN0YXJ0X2xvY2tpbmdzcF9vcGFsX3Nlc3Npb24oZGV2LCBPUEFMX0FETUlOMV9VSUQsCj4g
KwkJCQkJICAgIGRldi0+a2V5LCBkZXYtPmtleV9sZW4pOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50
IHN0YXJ0X2F1dGhfb3BhbF9zZXNzaW9uKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwlj
b25zdCB1OCAqbWV0aG9kLCAqc211aWQsICpsb2NraW5nX3NwOwo+ICsJdTggbGtfdWxfdXNlcltP
UEFMX1VJRF9MRU5HVEhdOwo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwl1MzIgSFNOOwo+
ICsJaW50IHJldDsKPiArCXN0cnVjdCBvcGFsX3VzZXJfaW5mbyAqdWluZm87Cj4gKwo+ICsJY21k
ID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCj4gKwlzZXRfY29tSUQo
Y21kLCBkZXYtPmNvbUlEKTsKPiArCj4gKwlIU04gPSAweDQxOwpDYW4gd2UgI2RlZmluZSB0aGlz
OyBpdCdzIHVzZWQgYSBmZXcgb3RoZXIgcGxhY2VzIGFuZCBpcyBtYWdpY2t5Cgo+ICsKPiArCXVp
bmZvID0gZGV2LT5mdW5jX2RhdGFbZGV2LT5zdGF0ZSAtIDFdOwo+ICsKPiArCXNtdWlkID0gT1BB
TFVJRFtPUEFMX1NNVUlEX1VJRF07Cj4gKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU1RBUlRT
RVNTSU9OXTsKPiArCWxvY2tpbmdfc3AgPSBPUEFMVUlEW09QQUxfTE9DS0lOR1NQX1VJRF07Cj4g
Kwo+ICsJaWYgKHVpbmZvLT5TVU0pIHsKPiArCQlyZXQgPSBidWlsZF9sb2NraW5nX3VzZXIobGtf
dWxfdXNlciwgc2l6ZW9mKGxrX3VsX3VzZXIpLAo+ICsJCQkJCSBkZXYtPmxyKTsKPiArCQlpZiAo
cmV0IDwgMCkgewo+ICsJCQlwcl9lcnIoIiVzOiBDYW4ndCBidWlsZCBsb2NraW5nIHVzZXJcbiIs
Cj4gKwkJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJCXJldHVybiByZXQ7Cj4gKwkJfQo+
ICsJfSBlbHNlIGlmICh1aW5mby0+d2hvICE9IE9QQUxfQURNSU4xICYmICF1aW5mby0+U1VNKSB7
Cj4gKwkJcmV0ID0gYnVpbGRfbG9ja2luZ191c2VyKGxrX3VsX3VzZXIsIHNpemVvZihsa191bF91
c2VyKSwKPiArCQkJCQkgdWluZm8tPndobyAtIDEpOwo+ICsJCWlmIChyZXQgPCAwKSB7Cj4gKwkJ
CXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgdXNlclxuIiwKPiArCQkJICAgICAgIGRl
di0+ZGlza19uYW1lKTsKPiArCQkJcmV0dXJuIHJldDsKPiArCQl9Cj4gKwl9IGVsc2UKPiArCQlt
ZW1jcHkobGtfdWxfdXNlciwgT1BBTFVJRFtPUEFMX0FETUlOMV9VSURdLCBPUEFMX1VJRF9MRU5H
VEgpOwo+ICsKPiArCj4gKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIGN1
czNjczNjIHMgMmMiLAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICBzbXVpZCwgT1BB
TF9VSURfTEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsK
PiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICBIU04sCj4gKwkJCQkgICAgbG9j
a2luZ19zcCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxLAo+
ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAwLAo+
ICsJCQkJICAgIGRldi0+a2V5LCBkZXYtPmtleV9sZW4sCj4gKwkJCQkgICAgT1BBTF9FTkROQU1F
LAo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAz
LAo+ICsKPiArCQkJCSAgICBsa191bF91c2VyLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwo+ICsJCQkJ
ICAgIE9QQUxfRU5ETkFNRSwKPiArCQkJCSAgICBPUEFMX0VORExJU1QpOwo+ICsKPiArCWlmIChy
ZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgU1RBUlRTRVNTSU9OIGNv
bW1hbmQuXG4iLAo+ICsJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJcmV0dXJuIHJldDsK
PiArCX0KPiArCj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIHN0YXJ0X29w
YWxfc2Vzc2lvbl9jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCByZXZlcnRfdHBlcihzdHJ1
Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJY29uc3QgdTggKm1ldGhvZCwgKnNtdWlkOwo+ICsJ
c3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWNtZCA9ICZkZXYtPmNt
ZDsKPiArCWNsZWFyX29wYWxfY21kKGNtZCk7Cj4gKwo+ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5j
b21JRCk7Cj4gKwo+ICsJc211aWQgPSBPUEFMVUlEW09QQUxfQURNSU5TUF9VSURdOwo+ICsJbWV0
aG9kID0gT1BBTE1FVEhPRFtPUEFMX1JFVkVSVF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgImMycyAyYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAg
IHNtdWlkLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9M
RU5HVEgsCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNU
KTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgUkVW
RVJUIFRQRVIgY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKPiArCQly
ZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNt
ZCwgZ2VuZXJpY19jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBpbnRlcm5hbF9hY3RpdmF0
ZV91c2VyKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9kOwo+
ICsJdTggdWlkW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiAr
CWludCByZXQ7Cj4gKwlzdHJ1Y3Qgb3BhbF9hY3RpdmF0ZV91c2VyICphY3Q7Cj4gKwo+ICsJY21k
ID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21JRChjbWQs
IGRldi0+Y29tSUQpOwo+ICsKPiArCWFjdCA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAx
XTsKPiArCj4gKwltZW1jcHkodWlkLCBPUEFMVUlEW09QQUxfVVNFUjFfVUlEXSwgT1BBTF9VSURf
TEVOR1RIKTsKPiArCXVpZFs3XSA9IGFjdC0+d2hvLndobzsKPiArCj4gKwltZXRob2QgPSBPUEFM
TUVUSE9EW09QQUxfU0VUXTsKPiArCj4gKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21k
LCAiYzJzIDNjIGMgNGMgM2MiLAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICB1aWQs
IE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwK
PiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUs
Cj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDEsIC8qIFZhbHVlcyAqLwo+ICsKPiArCQkJCSAg
ICBPUEFMX1NUQVJUTElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkg
ICAgT1BBTF9USU5ZX1VJTlRfMDUsIC8qIEVuYWJsZWQgKi8KPiArCQkJCSAgICBPUEFMX1RJTllf
VUlOVF8wMSwgLyogVHJ1ZSAqLwo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkg
ICAgT1BBTF9FTkRMSVNULAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCQkJCSAgICBPUEFM
X0VORExJU1QpOwo+ICsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3Ig
YnVpbGRpbmcgQWN0aXZhdGUgVXNlck4gY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRldi0+ZGlz
a19uYW1lKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXJldHVybiBmaW5hbGl6ZV9h
bmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBl
cmFzZV9sb2NraW5nX3JhbmdlKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1
OCAqbWV0aG9kOwo+ICsJdTggdWlkW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qgb3BhbF9j
bWQgKmNtZDsKPiArCWludCByZXQ7Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJf
b3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCW1l
dGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9FUkFTRV07Cj4gKwo+ICsJaWYgKGJ1aWxkX2xvY2tpbmdf
cmFuZ2UodWlkLCBzaXplb2YodWlkKSwgZGV2LT5scikgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczog
Q2FuJ3QgYnVpbGQgbG9ja2luZyByYW5nZVxuIiwgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVy
biAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQs
ICJjMnMgMmMiLAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICB1aWQsIE9QQUxfVUlE
X0xFTkdUSCwKPiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJ
CQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCj4gKwlp
ZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIEVyYXNlIExvY2tp
bmcgUmFuZ2UgQ21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJl
dHVybiByZXQ7Cj4gKwl9Cj4gKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdl
bmVyaWNfY29udCk7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgc2V0X21icl9kb25lKHN0cnVjdCBv
cGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9kLCAqdWlkOwo+ICsJc3RydWN0
IG9wYWxfY21kICpjbWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCXU4IG1icl9kb25lX3RmID0gKih1
OCAqKWRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKPiArCj4gKwljbWQgPSAmZGV2LT5j
bWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21J
RCk7Cj4gKwo+ICsJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07Cj4gKwl1aWQgPSBPUEFM
VUlEW09QQUxfTUJSQ09OVFJPTF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3Zh
KGNtZCwgImMycyAzYyA2YyAyYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAgIHVp
ZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RI
LAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFN
RSwKPiArCQkJCSAgICBPUEFMX1ZBTFVFUywKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1Qs
Cj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDIs
IC8qIERvbmUgKi8KPiArCQkJCSAgICBtYnJfZG9uZV90ZiwgICAgICAgLyogRG9uZSBUIG9yIEYg
Ki8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsK
PiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCWlm
IChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgQnVpbGRpbmcgc2V0IE1CUiBEb250
L05vdCBkb25lIGNvbW1hbmRcbiIsCnMvRG9udC9Eb25lLyA/CgoKPiArCQkgICAgICAgZGV2LT5k
aXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIGZpbmFsaXpl
X2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50
IHNldF9tYnJfZW5hYmxlX2Rpc2FibGUoc3RydWN0IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCWNv
bnN0IHU4ICptZXRob2QsICp1aWQ7Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiArCWludCBy
ZXQ7Cj4gKwo+ICsJdTggbWJyX2VuX2RpcyA9ICoodTggKilkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0
YXRlIC0gMV07Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21k
KTsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCW1ldGhvZCA9IE9QQUxN
RVRIT0RbT1BBTF9TRVRdOwo+ICsJdWlkID0gT1BBTFVJRFtPUEFMX01CUkNPTlRST0xdOwo+ICsK
PiArCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgM2MgNmMgMmMiLAo+ICsJ
CQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJ
CSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFS
VExJU1QsCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9WQUxVRVMs
Cj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1F
LAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxLCAvKiBFbmFibGUgKi8KPiArCQkJCSAgICBt
YnJfZW5fZGlzLCAgICAgICAgLyogRW5hYmxlIG9yIERpc2FibGUgKi8KPiArCQkJCSAgICBPUEFM
X0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsKPiArCQkJCSAgICBPUEFMX0VO
RE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJ
cHJfZXJyKCIlczogRXJyb3IgQnVpbGRpbmcgc2V0IE1CUiBEb250L05vdCBkb25lIGNvbW1hbmRc
biIsCnMvRG9udC9Eb25lLyA/CgoKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJl
dHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21k
LCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNldF9uZXdfcHcoc3RydWN0
IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwl1OCBjcGluX3Vp
ZFtPUEFMX1VJRF9MRU5HVEhdOwo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwlpbnQgcmV0
Owo+ICsJc3RydWN0IG9wYWxfbmV3X3B3ICpwdzsKPiArCXNpemVfdCBrZXlfbGVuOwo+ICsJdTgg
KmtleTsKPiArCj4gKwljbWQgPSAmZGV2LT5jbWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+
ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7Cj4gKwo+ICsJcHcgPSBkZXYtPmZ1bmNfZGF0
YVtkZXYtPnN0YXRlIC0gMV07Cj4gKwlrZXkgPSBwdy0+bmV3X3Bpbi5rZXk7Cj4gKwlrZXlfbGVu
ID0gcHctPm5ld19waW4ua2V5X2xlbjsKPiArCW1lbWNweShjcGluX3VpZCwgT1BBTFVJRFtPUEFM
X0NfUElOX0FETUlOMV0sIE9QQUxfVUlEX0xFTkdUSCk7Cj4gKwo+ICsJaWYgKHB3LT51c2VyX2Zv
cl9wdyAhPSBPUEFMX0FETUlOMSkgewo+ICsJCWNwaW5fdWlkWzVdID0gMHgwMzsKPiArCQlpZiAo
cHctPndoby5TVU0pCj4gKwkJCWNwaW5fdWlkWzddID0gcHctPm5ld19waW4ubHIgKyAxOwo+ICsJ
CWVsc2UKPiArCQkJY3Bpbl91aWRbN10gPSBwdy0+dXNlcl9mb3JfcHc7Cj4gKwl9Cj4gKwo+ICsJ
bWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgImMycyAzYyAzY3MyYyAyYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+
ICsJCQkJICAgIGNwaW5fdWlkLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwkJCQkgICAgbWV0aG9kLCBP
UEFMX01FVEhPRF9MRU5HVEgsCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+ICsJCQkJ
ICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxLCAvKiBWYWx1
ZXMgKi8KPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCj4gKwkJCQkgICAgT1BBTF9TVEFS
VE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsIC8qIFBJTiAqLwo+ICsJCQkJICAg
IGtleSwga2V5X2xlbiwKPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9F
TkRMSVNULAo+ICsKPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRM
SVNUKTsKPiArCj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxk
aW5nIFNFVCBBTUlOMSBQSU4gY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRldi0+ZGlza19uYW1l
KTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXJldHVybiBmaW5hbGl6ZV9hbmRfc2Vu
ZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBzZXRfc2lk
X2NwaW5fcGluKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9k
LCAqY3Bpbl91aWQ7Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiArCWludCByZXQ7Cj4gKwo+
ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21J
RChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCWNwaW5fdWlkID0gT1BBTFVJRFtPUEFMX0NfUElO
X1NJRF07Cj4gKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU0VUXTsKPiArCj4gKwlyZXQgPSB0
ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDJjIDRjczJjIDJjIiwKPiArCQkJCSAgICBP
UEFMX0NBTEwsCj4gKwkJCQkgICAgY3Bpbl91aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAg
ICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVExJ
U1QsCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfVElOWV9V
SU5UXzAxLCAvKiBWYWx1ZXMgKi8KPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAg
ICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogUElOICov
Cj4gKwkJCQkgICAgZGV2LT5rZXksIGRldi0+a2V5X2xlbiwKPiArCQkJCSAgICBPUEFMX0VORE5B
TUUsCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsKPiArCQkJCSAgICBPUEFMX0VORE5BTUUs
Cj4gKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCXBy
X2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIFNFVCBDUElOIFBJTiBjb21tYW5kLlxuIiwKPiArCQkg
ICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0
dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+
ICtzdGF0aWMgdm9pZCBxdWVyeV9sb2NraW5nX3JhbmdlX2NvbnQoaW50IGVycm9yLCB2b2lkICpk
YXRhKQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7Cj4gKwo+ICsJaWYgKGVy
cm9yKQo+ICsJCWdvdG8gZXJyX3JldHVybjsKPiArCj4gKwllcnJvciA9IHBhcnNlX2FuZF9jaGVj
a19zdGF0dXMoZGV2KTsKPiArCWlmIChlcnJvcikKPiArCQlnb3RvIGVycl9yZXR1cm47Cj4gKwo+
ICsJZGV2LT5zdGFydCA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFyc2VkLCA0KTsKPiArCWRl
di0+bGVuZ3RoID0gcmVzcG9uc2VfZ2V0X3U2NCgmZGV2LT5wYXJzZWQsIDgpOwo+ICsKPiArZXJy
X3JldHVybjoKPiArCWlmIChkZXYtPm9wZXJfY2IpCj4gKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBk
ZXYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHF1ZXJ5X2xvY2tpbmdfcmFuZ2Uoc3RydWN0IG9w
YWxfZGV2ICpkZXYpCj4gK3sKPiArCXU4IGxyX2J1ZmZlcltPUEFMX1VJRF9MRU5HVEhdOwo+ICsJ
c3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwljb25zdCB1OCAqbWV0aG9kOwo+ICsJaW50IHJldDsK
PiArCj4gKwljbWQgPSAmZGV2LT5jbWQ7Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+ICsKPiAr
CW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9HRVRdOwo+ICsKPiArCWlmIChidWlsZF9sb2NraW5n
X3JhbmdlKGxyX2J1ZmZlciwgc2l6ZW9mKGxyX2J1ZmZlciksIGRldi0+bHIpIDwgMCkgewo+ICsJ
CXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2VcbiIsIGRldi0+ZGlza19uYW1l
KTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0KPiArCj4gKwlzZXRfY29tSUQoY21kLCBkZXYt
PmNvbUlEKTsKPiArCj4gKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDEy
YyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAgIGxyX2J1ZmZlciwgT1BBTF9VSURf
TEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsKPiArCQkJ
CSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAg
ICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1NUQVJUQ09MVU1OLAo+ICsJCQkJICAg
IE9QQUxfUkFOR0VTVEFSVCwKPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BB
TF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRDT0xVTU4sCj4gKwkJCQkgICAgT1BBTF9S
QU5HRUxFTkdUSCwKPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9FTkRM
SVNULAo+ICsJCQkJICAgIE9QQUxfRU5ETElTVCk7Cj4gKwo+ICsJaWYgKHJldCA8IDApIHsKPiAr
CQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBHRVQgTG9ja2luZyBSYW5nZSBjb21tYW5kLlxu
IiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4g
Kwo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBxdWVyeV9sb2NraW5nX3Jh
bmdlX2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGFkZF91c2VyX3RvX2xyKHN0cnVjdCBv
cGFsX2RldiAqZGV2KQo+ICt7Cj4gKwl1OCBscl9idWZmZXJbT1BBTF9VSURfTEVOR1RIXTsKPiAr
CXU4IHVzZXJfdWlkW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsK
PiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwlzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayAqbGt1bDsK
PiArCWludCByZXQ7Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQo
Y21kKTsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCW1ldGhvZCA9IE9Q
QUxNRVRIT0RbT1BBTF9TRVRdOwo+ICsKPiArCWxrdWwgPSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0
YXRlIC0gMV07Cj4gKwo+ICsJbWVtY3B5KGxyX2J1ZmZlciwgT1BBTFVJRFtPUEFMX0xPQ0tJTkdS
QU5HRV9BQ0VfUkRMT0NLRURdLAo+ICsJICAgICAgIE9QQUxfVUlEX0xFTkdUSCk7Cj4gKwo+ICsJ
aWYgKGxrdWwtPmxfc3RhdGUgPT0gT1BBTF9SVykKPiArCQltZW1jcHkobHJfYnVmZmVyLCBPUEFM
VUlEW09QQUxfTE9DS0lOR1JBTkdFX0FDRV9XUkxPQ0tFRF0sCj4gKwkJICAgICAgIE9QQUxfVUlE
X0xFTkdUSCk7Cj4gKwo+ICsJbHJfYnVmZmVyWzddID0gZGV2LT5scjsKPiArCj4gKwltZW1jcHko
dXNlcl91aWQsIE9QQUxVSURbT1BBTF9VU0VSMV9VSURdLCBPUEFMX1VJRF9MRU5HVEgpOwo+ICsJ
dXNlcl91aWRbN10gPSBsa3VsLT5hdXRob3JpdHkud2hvOwo+ICsKPiArCXJldCA9IHRlc3RfYW5k
X2FkZF90b2tlbl92YShjbWQsICJjMnMgM2MgM2MgMmMgMnNjIGMyc2MgY3MyYyA1YyIsCj4gKwkJ
CQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAgIGxyX2J1ZmZlciwgT1BBTF9VSURfTEVOR1RILAo+
ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsKPiArCQkJCSAgICBPUEFM
X1NUQVJUTElTVCwKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1RJ
TllfVUlOVF8wMSwgLyogVmFsdWVzICovCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+
ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLCAv
KiBCb29sZWFuRXhwciAqLwo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAg
ICBPUEFMX1NUQVJUTkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTFVJRFtPUEFMX0hBTEZfVUlEX0FV
VEhPUklUWV9PQkpfUkVGXSwKPiArCQkJCSAgICBPUEFMX1VJRF9MRU5HVEhfSEFMRiwKPiArCQkJ
CSAgICB1c2VyX3VpZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwK
PiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTFVJRFtPUEFMX0hB
TEZfVUlEX0FVVEhPUklUWV9PQkpfUkVGXSwKPiArCQkJCSAgICBPUEFMX1VJRF9MRU5HVEhfSEFM
RiwKPiArCQkJCSAgICB1c2VyX3VpZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxf
RU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTFVJ
RFtPUEFMX0hBTEZfVUlEX0JPT0xFQU5fQUNFXSwKPiArCQkJCSAgICBPUEFMX1VJRF9MRU5HVEhf
SEFMRiwKPiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMSwKPiArCQkJCSAgICBPUEFMX0VORE5B
TUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfRU5ETElTVCwKPiArCQkJCSAgICBPUEFMX0VORE5BTUUs
Cj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCQkJ
CSAgICBPUEFMX0VORExJU1QpOwo+ICsJaWYgKHJldCA8IDApIHsKPiArCQlwcl9lcnIoIiVzOiBF
cnJvciBidWlsZGluZyBhZGQgdXNlciB0byBsb2NraW5nIHJhbmdlIGNvbW1hbmQuXG4iLAo+ICsJ
CSAgICAgICBkZXYtPmRpc2tfbmFtZSk7Cj4gKwkJcmV0dXJuIHJldDsKPiArCX0KPiArCj4gKwly
ZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdlbmVyaWNfY29udCk7Cj4gK30KPiAr
Cj4gK3N0YXRpYyBpbnQgbG9ja191bmxvY2tfbG9ja2luZ19yYW5nZShzdHJ1Y3Qgb3BhbF9kZXYg
KmRldikKPiArewo+ICsJdTggbHJfYnVmZmVyW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qg
b3BhbF9jbWQgKmNtZDsKPiArCWNvbnN0IHU4ICptZXRob2Q7Cj4gKwlzdHJ1Y3Qgb3BhbF9sb2Nr
X3VubG9jayAqbGt1bDsKPiArCWludCByZXQ7Cj4gKwl1OCByZWFkX2xvY2tlZCA9IDEsIHdyaXRl
X2xvY2tlZCA9IDE7Cj4gKwo+ICsJY21kID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQo
Y21kKTsKPiArCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOwo+ICsKPiArCW1ldGhvZCA9IE9Q
QUxNRVRIT0RbT1BBTF9TRVRdOwo+ICsJbGt1bCA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUg
LSAxXTsKPiArCWlmIChidWlsZF9sb2NraW5nX3JhbmdlKGxyX2J1ZmZlciwgc2l6ZW9mKGxyX2J1
ZmZlciksIGRldi0+bHIpIDwgMCkgewo+ICsJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tp
bmcgcmFuZ2VcbiIsIGRldi0+ZGlza19uYW1lKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0K
PiArCj4gKwlzd2l0Y2ggKGxrdWwtPmxfc3RhdGUpIHsKPiArCWNhc2UgT1BBTF9STzoKPiArCQly
ZWFkX2xvY2tlZCA9IDA7Cj4gKwkJd3JpdGVfbG9ja2VkID0gMTsKPiArCQlicmVhazsKPiArCWNh
c2UgT1BBTF9SVzoKPiArCQlyZWFkX2xvY2tlZCA9IDA7Cj4gKwkJd3JpdGVfbG9ja2VkID0gMDsK
PiArCQlicmVhazsKPiArCWNhc2UgT1BBTF9MSzoKPiArCQkvKiB2YXJzIGFyZSBpbml0YWxpemVk
IHRvIGxvY2tlZCAqLwo+ICsJCWJyZWFrOwo+ICsJZGVmYXVsdDoKPiArCQlwcl9lcnIoIlRyaWVk
IHRvIHNldCBhbiBpbnZhbGlkIGxvY2tpbmcgc3RhdGUuLi4gcmV0dXJuaW5nIHRvIHVsYW5kXG4i
KTsKPiArCQlyZXR1cm4gMTsKPiArCX0KPiArCj4gKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5f
dmEoY21kLCAiYzJzYyAzYyA0YyA0YyAzYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJ
ICAgIGxyX2J1ZmZlciwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9N
RVRIT0RfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+ICsKPiArCQkJCSAgICBP
UEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1ZBTFVFUywKPiArCQkJCSAgICBPUEFMX1NU
QVJUTElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9S
RUFETE9DS0VELAo+ICsJCQkJICAgIHJlYWRfbG9ja2VkLAo+ICsJCQkJICAgIE9QQUxfRU5ETkFN
RSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9XUklURUxP
Q0tFRCwKPiArCQkJCSAgICB3cml0ZV9sb2NrZWQsCj4gKwkJCQkgICAgT1BBTF9FTkROQU1FLAo+
ICsKPiArCQkJCSAgICBPUEFMX0VORExJU1QsCj4gKwkJCQkgICAgT1BBTF9FTkROQU1FLAo+ICsJ
CQkJICAgIE9QQUxfRU5ETElTVCk7Cj4gKwo+ICsJaWYgKHJldCA8IDApIHsKPiArCQlwcl9lcnIo
IiVzOiBFcnJvciBidWlsZGluZyBTRVQgY29tbWFuZC5cbiIsIGRldi0+ZGlza19uYW1lKTsKPiAr
CQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21k
LCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICsKPiArc3RhdGljIGludCBsb2NrX3VubG9ja19s
b2NraW5nX3JhbmdlX1NVTShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKPiArewo+ICsJdTggbHJfYnVm
ZmVyW09QQUxfVUlEX0xFTkdUSF07Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiArCWNvbnN0
IHU4ICptZXRob2Q7Cj4gKwlzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayAqbGt1bDsKPiArCWludCBy
ZXQ7Cj4gKwl1OCByZWFkX2xvY2tlZCA9IDEsIHdyaXRlX2xvY2tlZCA9IDE7Cj4gKwo+ICsJY21k
ID0gJmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21JRChjbWQs
IGRldi0+Y29tSUQpOwo+ICsKPiArCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9TRVRdOwo+ICsJ
bGt1bCA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKPiArCWlmIChidWlsZF9sb2Nr
aW5nX3JhbmdlKGxyX2J1ZmZlciwgc2l6ZW9mKGxyX2J1ZmZlciksIGRldi0+bHIpIDwgMCkgewo+
ICsJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2VcbiIsIGRldi0+ZGlza19u
YW1lKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0KPiArCj4gKwlzd2l0Y2ggKGxrdWwtPmxf
c3RhdGUpIHsKPiArCWNhc2UgT1BBTF9STzoKPiArCQlyZWFkX2xvY2tlZCA9IDA7Cj4gKwkJd3Jp
dGVfbG9ja2VkID0gMTsKPiArCQlicmVhazsKPiArCWNhc2UgT1BBTF9SVzoKPiArCQlyZWFkX2xv
Y2tlZCA9IDA7Cj4gKwkJd3JpdGVfbG9ja2VkID0gMDsKPiArCQlicmVhazsKPiArCWNhc2UgT1BB
TF9MSzoKPiArCQkvKiB2YXJzIGFyZSBpbml0YWxpemVkIHRvIGxvY2tlZCAqLwo+ICsJCWJyZWFr
Owo+ICsJZGVmYXVsdDoKPiArCQlwcl9lcnIoIlRyaWVkIHRvIHNldCBhbiBpbnZhbGlkIGxvY2tp
bmcgc3RhdGUuXG4iKTsKPiArCQlyZXR1cm4gMTsKPiArCX0KPiArCj4gKwlyZXQgPSB0ZXN0X2Fu
ZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzYyAzYyA0YyA0YyA0YyA0YyAzYyIsCj4gKwkJCQkgICAg
T1BBTF9DQUxMLAo+ICsJCQkJICAgIGxyX2J1ZmZlciwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJ
ICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNU
LAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKPiArCQkJCSAgICBPUEFMX1ZBTFVFUywK
PiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUs
Cj4gKwkJCQkgICAgT1BBTF9SRUFETE9DS0VOQUJMRUQsCj4gKwkJCQkgICAgT1BBTF9UUlVFLAo+
ICsJCQkJICAgIE9QQUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4g
KwkJCQkgICAgT1BBTF9XUklURUxPQ0tFTkFCTEVELAo+ICsJCQkJICAgIE9QQUxfVFJVRSwKPiAr
CQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJ
CQkJICAgIE9QQUxfUkVBRExPQ0tFRCwKPiArCQkJCSAgICByZWFkX2xvY2tlZCwKPiArCQkJCSAg
ICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAg
IE9QQUxfV1JJVEVMT0NLRUQsCj4gKwkJCQkgICAgd3JpdGVfbG9ja2VkLAo+ICsJCQkJICAgIE9Q
QUxfRU5ETkFNRSwKPiArCj4gKwkJCQkgICAgT1BBTF9FTkRMSVNULAo+ICsJCQkJICAgIE9QQUxf
RU5ETkFNRSwKPiArCQkJCSAgICBPUEFMX0VORExJU1QpOwo+ICsJaWYgKHJldCA8IDApIHsKPiAr
CQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBTRVQgY29tbWFuZC5cbiIsIGRldi0+ZGlza19u
YW1lKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5k
KGRldiwgY21kLCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICtpbnQgYWN0aXZhdGVfbHNwKHN0
cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwl1OCB1c2VyX2xyW09QQUxfVUlEX0xFTkdUSF07
Cj4gKwljb25zdCB1OCAqbWV0aG9kLCAqdWlkOwo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7Cj4g
KwlpbnQgcmV0Owo+ICsJc2l6ZV90IHVpbnRfMyA9IDB4ODM7Cj4gKwo+ICsJY21kID0gJmRldi0+
Y21kOwo+ICsKPiArCWNsZWFyX29wYWxfY21kKGNtZCk7Cj4gKwlzZXRfY29tSUQoY21kLCBkZXYt
PmNvbUlEKTsKPiArCj4gKwl1aWQgPSBPUEFMVUlEW09QQUxfTE9DS0lOR1NQX1VJRF07Cj4gKwlt
ZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfQUNUSVZBVEVdOwo+ICsKPiArCXJldCA9IHRlc3RfYW5k
X2FkZF90b2tlbl92YShjbWQsICJjMnMiLAo+ICsJCQkJICAgIE9QQUxfQ0FMTCwKPiArCQkJCSAg
ICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKPiArCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xF
TkdUSCk7Cj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5n
IEFjdGl2YXRlIExvY2tpbmdTUCBjb21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25h
bWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4gKwkvKiBBY3RpdmF0aW5nIGFzIFNVTSAqLwo+
ICsJaWYgKGRldi0+bHIgPiAwKSB7Cj4gKwkJcmV0ID0gYnVpbGRfbG9ja2luZ19yYW5nZSh1c2Vy
X2xyLCBzaXplb2YodXNlcl9sciksIGRldi0+bHIpOwo+ICsJCWlmIChyZXQgPCAwKSB7Cj4gKwkJ
CXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgdXNlclxuIiwKPiArCQkJICAgICAgIGRl
di0+ZGlza19uYW1lKTsKPiArCQkJcmV0dXJuIHJldDsKPiArCQl9Cj4gKwkJdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgIjJjIDRjIGNzYyAyYyIsCj4gKwkJCQkgICAgICBPUEFMX1NUQVJUTElT
VCwKPiArCQkJCSAgICAgIE9QQUxfU1RBUlROQU1FLAo+ICsKPiArCQkJCSAgICAgIHVpbnRfMywK
PiArCQkJCSAgICAgIE9QQUxfVElOWV9VSU5UXzA2LAo+ICsJCQkJICAgICAgT1BBTF9USU5ZX1VJ
TlRfMDAsCj4gKwkJCQkgICAgICBPUEFMX1RJTllfVUlOVF8wMCwKPiArCj4gKwkJCQkgICAgICBP
UEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICAgIHVzZXJfbHIsIE9QQUxfVUlEX0xFTkdUSCwKPiAr
CQkJCSAgICAgIE9QQUxfRU5ETElTVCwKPiArCj4gKwkJCQkgICAgICBPUEFMX0VORE5BTUUsCj4g
KwkJCQkgICAgICBPUEFMX0VORExJU1QpOwo+ICsJfSBlbHNlIC8qIEFjdGlhdmUgTm9ybWFsIE1v
ZGUgKi8KPiArCQlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiMmMiLAo+ICsJCQkJ
CSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCQkgICAgT1BBTF9FTkRMSVNUKTsKPiArCj4gKwlp
ZiAocmV0IDwgMCkgewo+ICsJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIEFjdGl2YXRlIExv
Y2tpbmdTUCBjb21tYW5kLlxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJl
dHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21k
LCBnZW5lcmljX2NvbnQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBnZXRfbHNwX2xpZmVjeWNs
ZV9jb250KGludCBlcnJvciwgdm9pZCAqZGF0YSkKPiArewo+ICsKPiArCXN0cnVjdCBvcGFsX2Rl
diAqZGV2ID0gZGF0YTsKPiArCXU4IGxjX3N0YXR1czsKPiArCj4gKwlpZiAoZXJyb3IpCj4gKwkJ
Z290byBlcnJfcmV0dXJuOwo+ICsKPiArCWVycm9yID0gcGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhk
ZXYpOwo+ICsJaWYgKGVycm9yKQo+ICsJCWdvdG8gZXJyX3JldHVybjsKPiArCj4gKwlsY19zdGF0
dXMgPSByZXNwb25zZV9nZXRfdTY0KCZkZXYtPnBhcnNlZCwgNCk7Cj4gKwkvKiAweDA4IGlzIE1h
bnVmYWN1cmVkIEluYWN0aXZlICovCj4gKwkvKiAweDA5IGlzIE1hbnVmYWN0dXJlZCAqLwo+ICsJ
aWYgKGxjX3N0YXR1cyAhPSAweDA4KSB7Cj4gKwkJcHJfZXJyKCIlczogQ291bGRuJ3QgZGV0ZXJt
aW5lIHRoZSBzdGF0dXMgb2YgdGhlIExpZmN5Y2xlIHN0YXRlXG4iLAo+ICsJCSAgICAgICBkZXYt
PmRpc2tfbmFtZSk7Cj4gKwkJZXJyb3IgPSAtRU5PREVWOwo+ICsJfQo+ICsKPiArZXJyX3JldHVy
bjoKPiArCWlmIChkZXYtPm9wZXJfY2IpCj4gKwkJZGV2LT5vcGVyX2NiKGVycm9yLCBkZXYpOwo+
ICt9Cj4gKwo+ICsvKiBEZXRlcm1pbmUgaWYgd2UncmUgaW4gdGhlIE1hbnVmYWN0dXJlZCBJbmFj
dGl2ZSBvciBBY3RpdmUgc3RhdGUgKi8KPiAraW50IGdldF9sc3BfbGlmZWN5Y2xlKHN0cnVjdCBv
cGFsX2RldiAqZGV2KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKPiArCWNvbnN0IHU4
ICptZXRob2QsICp1aWQ7Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWNtZCA9ICZkZXYtPmNtZDsKPiAr
Cj4gKwljbGVhcl9vcGFsX2NtZChjbWQpOwo+ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7
Cj4gKwo+ICsJdWlkID0gT1BBTFVJRFtPUEFMX0xPQ0tJTkdTUF9VSURdOwo+ICsJbWV0aG9kID0g
T1BBTE1FVEhPRFtPUEFMX0dFVF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3Zh
KGNtZCwgImMycyAyYyA0YyA0YyAyYyIsCj4gKwkJCQkgICAgT1BBTF9DQUxMLAo+ICsJCQkJICAg
IHVpZCwgT1BBTF9VSURfTEVOR1RILAo+ICsJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVO
R1RILAo+ICsKPiArCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKPiArCQkJCSAgICBPUEFMX1NUQVJU
TElTVCwKPiArCj4gKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5Z
X1VJTlRfMDMsIC8qIFN0YXJ0IENvbHVtbiAqLwo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzA2
LCAvKiBMaWZjeWNsZSBDb2x1bW4gKi8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJ
CQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5UXzA0LCAvKiBF
bmQgQ29sdW1uICovCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIExpZmVjeWNsZSBD
b2x1bW4gKi8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwo+ICsJCQkJICAgIE9QQUxfRU5E
TElTVCwKPiArCQkJCSAgICBPUEFMX0VORExJU1QpOwo+ICsKPiArCWlmIChyZXQgPCAwKSB7Cj4g
KwkJcHJfZXJyKCIlczogRXJyb3IgQnVpbGRpbmcgR0VUIExpZmVjeWNsZSBTdGF0dXMgY29tbWFu
ZFxuIiwKPiArCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9
Cj4gKwo+ICsJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZXRfbHNwX2xpZmVj
eWNsZV9jb250KTsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgZ2V0X21zaWRfY3Bpbl9waW5fY29u
dChpbnQgZXJyb3IsIHZvaWQgKmRhdGEpCj4gK3sKPiArCWNvbnN0IGNoYXIgKm1zaWRfcGluOwo+
ICsJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOwo+ICsJc2l6ZV90IHN0cmxlbjsKPiArCj4g
KwlpZiAoZXJyb3IpCj4gKwkJZ290byBlcnJfcmV0dXJuOwo+ICsKPiArCWVycm9yID0gcGFyc2Vf
YW5kX2NoZWNrX3N0YXR1cyhkZXYpOwo+ICsJaWYgKGVycm9yKQo+ICsJCWdvdG8gZXJyX3JldHVy
bjsKPiArCj4gKwlzdHJsZW4gPSByZXNwb25zZV9nZXRfc3RyaW5nKCZkZXYtPnBhcnNlZCwgNCwg
Jm1zaWRfcGluKTsKPiArCWlmICghbXNpZF9waW4pIHsKPiArCQlwcl9lcnIoIiVzOiBDb3VsZG4n
dCBleHRyYWN0IFBJTiBmcm9tIHJlc3BvbnNlXG4iLCBfX2Z1bmNfXyk7Cj4gKwkJZXJyb3IgPSAx
Owo+ICsJCWdvdG8gZXJyX3JldHVybjsKPiArCX0KPiArCj4gKwlkZXYtPnByZXZfZGF0YSA9IGtt
ZW1kdXAobXNpZF9waW4sIHN0cmxlbiwgR0ZQX0tFUk5FTCk7Cj4gKwlpZiAoIWRldi0+cHJldl9k
YXRhKQo+ICsJCWVycm9yID0gLUVOT01FTTsKPiArCj4gKwlkZXYtPnByZXZfZF9sZW4gPSBzdHJs
ZW47Cj4gKwo+ICsgZXJyX3JldHVybjoKPiArCWlmIChkZXYtPm9wZXJfY2IpCj4gKwkJZGV2LT5v
cGVyX2NiKGVycm9yLCBkZXYpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGdldF9tc2lkX2NwaW5f
cGluKHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwljb25zdCB1OCAqbWV0aG9kLCAqc211
aWQ7Cj4gKwlpbnQgcmV0Owo+ICsJc3RydWN0IG9wYWxfY21kICpjbWQ7Cj4gKwo+ICsJY21kID0g
JmRldi0+Y21kOwo+ICsJY2xlYXJfb3BhbF9jbWQoY21kKTsKPiArCXNldF9jb21JRChjbWQsIGRl
di0+Y29tSUQpOwo+ICsKPiArCXNtdWlkID0gT1BBTFVJRFtPUEFMX0NfUElOX01TSURdOwo+ICsJ
bWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX0dFVF07Cj4gKwo+ICsJcmV0ID0gdGVzdF9hbmRfYWRk
X3Rva2VuX3ZhKGNtZCwgImMgMnMgMTJjIiwKPiArCQkJCSAgICBPUEFMX0NBTEwsCj4gKwo+ICsJ
CQkJICAgIHNtdWlkLCBPUEFMX1VJRF9MRU5HVEgsCj4gKwkJCQkgICAgbWV0aG9kLCBPUEFMX01F
VEhPRF9MRU5HVEgsCj4gKwo+ICsJCQkJICAgIE9QQUxfU1RBUlRMSVNULAo+ICsJCQkJICAgIE9Q
QUxfU1RBUlRMSVNULAo+ICsJCQkJICAgIE9QQUxfU1RBUlROQU1FLAo+ICsJCQkJICAgIE9QQUxf
VElOWV9VSU5UXzAzLCAvKiBTYXJ0IENvbHVtbiAqLwo+ICsJCQkJICAgIE9QQUxfVElOWV9VSU5U
XzAzLCAvKiBQSU4gKi8KPiArCQkJCSAgICBPUEFMX0VORE5BTUUsCj4gKwkJCQkgICAgT1BBTF9T
VEFSVE5BTUUsCj4gKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDQsIC8qIEVuZCBDb2x1bW4gKi8K
PiArCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogUElOICovCj4gKwkJCQkgICAgT1BBTF9F
TkROQU1FLAo+ICsJCQkJICAgIE9QQUxfRU5ETElTVCwKPiArCQkJCSAgICBPUEFMX0VORExJU1Qp
Owo+ICsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcg
R2V0IE1TSUQgQ1BJTiBQSU4gY29tbWFuZC5cbiIsCj4gKwkJICAgICAgIGRldi0+ZGlza19uYW1l
KTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXJldHVybiBmaW5hbGl6ZV9hbmRfc2Vu
ZChkZXYsIGNtZCwgZ2V0X21zaWRfY3Bpbl9waW5fY29udCk7Cj4gK30KPiArCj4gK3N0YXRpYyB2
b2lkIHVubG9ja19zdXNwZW5kX2ZpbmFsKGludCBlcnJvciwgdm9pZCAqZGF0YSkKPiArewo+ICsJ
c3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOwo+ICsKPiArCWRldi0+cmVzdW1lX2Zyb21fc3Vz
cGVuZCA9IGZhbHNlOwo+ICsJZGV2LT5yZXN1bWVfZGF0YSA9IE5VTEw7Cj4gKwlkZXYtPmZ1bmNf
ZGF0YSA9IE5VTEw7Cj4gKwlkZXYtPmJkZXYgPSBOVUxMOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50
IGJ1aWxkX2VuZF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCXN0
cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsKPiArCWNtZCA9ICZkZXYtPmNtZDsKPiArCWNsZWFyX29w
YWxfY21kKGNtZCk7Cj4gKwo+ICsJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7Cj4gKwlyZXR1
cm4gdGVzdF9hbmRfYWRkX3Rva2VuX3U4KGNtZCwgT1BBTF9FTkRPRlNFU1NJT04pOwo+ICt9Cj4g
Kwo+ICtzdGF0aWMgaW50IGVuZF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYpCj4g
K3sKPiArCWlmIChidWlsZF9lbmRfb3BhbF9zZXNzaW9uKGRldikgPCAwKQo+ICsJCXJldHVybiAt
MTsKPiArCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsICZkZXYtPmNtZCwgZW5kX3Nlc3Np
b25fY29udCk7Cj4gK30KQW55IHJlYXNvbiB3ZSBjYW50OgoKaW50IHJldCA9IGJ1aWxkXy4uLgpp
ZiAocmV0IDwgMCkKCXJldHVybiByZXQ7CgoKPiArCj4gK3N0YXRpYyBzdHJ1Y3Qgb3BhbF9kZXYg
KmZpbmRfb3BhbF9kZXYoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgdTggbHIpCj4gK3sKPiAr
CXN0cnVjdCBvcGFsX2RldiAqaXRlciwgKm9wYWxfZGV2ID0gTlVMTDsKPiArCj4gKwlsaXN0X2Zv
cl9lYWNoX2VudHJ5KGl0ZXIsICZvcGFsX2xpc3QsIG5vZGUpIHsKPiArCQlpZiAoc3RybmNtcChp
dGVyLT5kaXNrX25hbWUsIGJkZXYtPmJkX2Rpc2stPmRpc2tfbmFtZSwKPiArCQkJICAgIERJU0tf
TkFNRV9MRU4pKQo+ICsJCQljb250aW51ZTsKPiArCQlpZiAoaXRlci0+bHIgPT0gbHIpIHsKPiAr
CQkJb3BhbF9kZXYgPSBpdGVyOwo+ICsJCQlicmVhazsKPiArCQl9Cj4gKwl9Cj4gKwo+ICsJcmV0
dXJuIG9wYWxfZGV2Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHVwZGF0ZV9vcGFsX2RldihzdHJ1
Y3Qgb3BhbF9kZXYgKm9sZF9kZXYsIHN0cnVjdCBvcGFsX2RldiAqbmV3X2RldikKPiArewo+ICsJ
aWYgKCFhdG9taWNfYWRkX3VubGVzcygmb2xkX2Rldi0+aW5fdXNlLCAxLCAxKSkgewo+ICsJCXBy
X2VycigiJXM6IGRldiB3YXMgaW4gdXNlXG4iLCBfX2Z1bmNfXyk7Cj4gKwkJcmV0dXJuIC1FQlVT
WTsKPiArCX0KPiArCj4gKwlvbGRfZGV2LT5rZXlfbmFtZV9sZW4gPSBuZXdfZGV2LT5rZXlfbmFt
ZV9sZW47Cj4gKwlpZiAoIW1lbWNweShvbGRfZGV2LT5rZXlfbmFtZSwgbmV3X2Rldi0+a2V5X25h
bWUsIG9sZF9kZXYtPmtleV9uYW1lX2xlbikpIHsKPiArCQlwcl9lcnIoIiVzOiBFcnJvciB1cGRh
dGluZyBkZXZpY2U6XG4iLCBvbGRfZGV2LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiAtRUZBVUxU
Owo+ICsJfQo+ICsKPiArCWlmICghc3RybmNweShvbGRfZGV2LT5kaXNrX25hbWUsIG5ld19kZXYt
PmRpc2tfbmFtZSwgRElTS19OQU1FX0xFTikpIHsKPiArCQlwcl9lcnIoIiVzOiBFcnJvciByZWdp
c3RlcmluZyBkZXZpY2U6IGNvcHlpbmcgZGlzayBuYW1lXG4iLAo+ICsJCSAgICAgICBvbGRfZGV2
LT5kaXNrX25hbWUpOwo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsJfQo+ICsKPiArCW9sZF9kZXYt
PmNvbUlEID0gbmV3X2Rldi0+Y29tSUQ7Cj4gKwlvbGRfZGV2LT5zdGFydCA9IG5ld19kZXYtPnN0
YXJ0Owo+ICsJb2xkX2Rldi0+bGVuZ3RoID0gbmV3X2Rldi0+bGVuZ3RoOwo+ICsJb2xkX2Rldi0+
YWxpZ24gPSBuZXdfZGV2LT5hbGlnbjsKPiArCW9sZF9kZXYtPmxvd2VzdF9sYmEgPSBuZXdfZGV2
LT5sb3dlc3RfbGJhOwo+ICsJb2xkX2Rldi0+YmRldiA9IE5VTEw7Cj4gKwlvbGRfZGV2LT5maW5h
bF9jYiA9IG5ld19kZXYtPmZpbmFsX2NiOwo+ICsJb2xkX2Rldi0+ZmluYWxfY2JfZGF0YSA9IG5l
d19kZXYtPmZpbmFsX2NiX2RhdGE7Cj4gKwlvbGRfZGV2LT5vcGVyX2NiID0gbmV3X2Rldi0+b3Bl
cl9jYjsKPiArCW9sZF9kZXYtPnN0YXRlID0gbmV3X2Rldi0+c3RhdGU7Cj4gKwlvbGRfZGV2LT5m
dW5jcyA9IG5ld19kZXYtPmZ1bmNzOwo+ICsKPiArCWtmcmVlKG9sZF9kZXYtPmNvbXBsZXRpb24p
Owo+ICsJY2xlYW5fZnVuY3Rpb25fZGF0YShvbGRfZGV2KTsKPiArCj4gKwlvbGRfZGV2LT5jb21w
bGV0aW9uID0gbmV3X2Rldi0+Y29tcGxldGlvbjsKPiArCj4gKwkvKgo+ICsJICogV29uJ3QgYmUg
YWJsZSB0byBhdXRvIHVubG9jayB0aGlzIGxvY2tpbmcgcmFuZ2UgYmFzZWQgb24gYmxvY2sKPiAr
CSAqIHJlcXVlc3Rlcy4KPiArCSAqLwo+ICsJaWYgKG9sZF9kZXYtPmxlbmd0aCA9PSAwKQo+ICsJ
CXByX3dhcm4oIiVzOiBNaXNzaW5nIGJsb2NrIGluZm9ybWF0aW9uIGZvciBsb2NraW5nIHJhbmdl
ICVkXG4iLAo+ICsJCQlvbGRfZGV2LT5kaXNrX25hbWUsIG9sZF9kZXYtPmxyKTsKPiArCj4gKwly
ZXR1cm4gMDsKPiArfQo+ICsKPiAraW50IG9wYWxfcmVnaXN0ZXJfY29udChzdHJ1Y3Qgb3BhbF9k
ZXYgKm5ld19kZXYpCj4gK3sKPiArCXN0cnVjdCBvcGFsX2RldiAqb2xkX2RldjsKPiArCXVuc2ln
bmVkIGxvbmcgZmxhZ3M7Cj4gKwlpbnQgZXJyb3IgPSAwOwo+ICsKPiArCXNwaW5fbG9ja19pcnFz
YXZlKCZsaXN0X3NwaW5sb2NrLCBmbGFncyk7Cj4gKwo+ICsJb2xkX2RldiA9IGZpbmRfb3BhbF9k
ZXYobmV3X2Rldi0+YmRldiwgbmV3X2Rldi0+bHIpOwo+ICsJaWYgKCFvbGRfZGV2KSB7Cj4gKwkJ
bGlzdF9hZGRfdGFpbCgmbmV3X2Rldi0+bm9kZSwgJm9wYWxfbGlzdCk7Cj4gKwkJb2xkX2RldiA9
IG5ld19kZXY7Cj4gKwl9IGVsc2Ugewo+ICsJCWlmIChvbGRfZGV2ID09IG5ld19kZXYpCj4gKwkJ
CWVycm9yID0gMDsKPiArCQllbHNlIHsKPiArCQkJZXJyb3IgPSB1cGRhdGVfb3BhbF9kZXYob2xk
X2RldiwgbmV3X2Rldik7Cj4gKwkJCWNsZWFuX29wYWxfa2V5KG5ld19kZXYpOwo+ICsJCQlrZnJl
ZShuZXdfZGV2KTsKPiArCQl9Cj4gKwl9Cj4gKwo+ICsJaWYgKGVycm9yKQo+ICsJCWxpc3RfZGVs
KCZvbGRfZGV2LT5ub2RlKTsKPiArCj4gKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZsaXN0X3Nw
aW5sb2NrLCBmbGFncyk7Cj4gKwo+ICsJaWYgKCFlcnJvcikKPiArCQlwcl9pbmZvKCIlczogUmVn
aXN0ZXJlZCBrZXkgZm9yIGxvY2tpbmcgcmFuZ2U6ICVkXG4iLAo+ICsJCQlvbGRfZGV2LT5kaXNr
X25hbWUsIG9sZF9kZXYtPmxyKTsKPiArCj4gKwlpZiAob2xkX2Rldi0+b3Blcl9jYikKPiArCQlv
bGRfZGV2LT5vcGVyX2NiKGVycm9yLCBvbGRfZGV2KTsKPiArCj4gKwlyZXR1cm4gMDsKPiArfQo+
ICsKPiArc3RhdGljIHZvaWQgbmV4dChpbnQgZXJyb3IsIHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+
ICt7Cj4gKwlvcGFsX3N0ZXAgZnVuYyA9IGRldi0+ZnVuY3NbZGV2LT5zdGF0ZV07Cj4gKwl2b2lk
ICpjYl9kYXRhID0gZGV2LT5maW5hbF9jYl9kYXRhOwo+ICsJc2VjX2NiICpjYiA9IGRldi0+Zmlu
YWxfY2I7Cj4gKwlib29sIGRvbmUgPSBmYWxzZTsKPiArCj4gKwo+ICsJaWYgKGVycm9yIHx8ICFm
dW5jKSB7Cj4gKwkJZG9uZSA9IHRydWU7Cj4gKwkJZ290byBuZXh0X2V4aXQ7Cj4gKwl9Cj4gKwlk
ZXYtPnN0YXRlKys7Cj4gKwlkZXYtPm9wZXJfY2IgPSBuZXh0Owo+ICsJZXJyb3IgPSBmdW5jKGRl
dik7Cj4gKyBuZXh0X2V4aXQ6Cj4gKwlpZiAoZXJyb3IpIHsKPiArCQlwcl9lcnIoIiVzOiBFcnJv
ciBvbiBzdGVwIGZ1bmN0aW9uOiAlZCB3aXRoIGVycm9yICVkOiAlc1xuIiwKPiArCQkgICAgICAg
ZGV2LT5kaXNrX25hbWUsIGRldi0+c3RhdGUsIGVycm9yLAo+ICsJCSAgICAgICBvcGFsX2Vycm9y
X3RvX2h1bWFuKGVycm9yKSk7Cj4gKwo+ICsKPiArCQlhdG9taWNfZGVjKCZkZXYtPmluX3VzZSk7
Cj4gKwkJaWYgKGRldi0+ZXJyb3JfY2IpIHsKPiArCQkJZGV2LT5lcnJvcl9jYihkZXYtPmVycm9y
X2NiX2RhdGEpOwo+ICsJCQlyZXR1cm47Cj4gKwkJfQo+ICsJCWlmIChjYikKPiArCQkJY2IoZXJy
b3IsIGNiX2RhdGEpOwo+ICsKPiArCQlkZXYtPmNvbXBsZXRpb24tPmNvbXBsZXRpb25fc3RhdHVz
ID0gZXJyb3I7Cj4gKwkJY29tcGxldGUoJmRldi0+Y29tcGxldGlvbi0+Y21kX2NvbXBsZXRpb24p
Owo+ICsJfSBlbHNlIGlmICghZXJyb3IgJiYgZG9uZSkgewo+ICsJCWF0b21pY19kZWMoJmRldi0+
aW5fdXNlKTsKPiArCQlpZiAoY2IpCj4gKwkJCWNiKGVycm9yLCBjYl9kYXRhKTsKPiArCQlkZXYt
PmNvbXBsZXRpb24tPmNvbXBsZXRpb25fc3RhdHVzID0gZXJyb3I7Cj4gKwkJY29tcGxldGUoJmRl
di0+Y29tcGxldGlvbi0+Y21kX2NvbXBsZXRpb24pOwo+ICsJfQo+ICt9Cj4gKwo+ICtjb25zdCBv
cGFsX3N0ZXAgZXJyb3JfZW5kX3Nlc3Npb25bXSA9IHsKPiArCWVuZF9vcGFsX3Nlc3Npb24sCj4g
KwlOVUxMLAo+ICt9Owo+ICtzdGF0aWMgaW50IGVuZF9vcGFsX3Nlc3Npb25fZXJyb3Ioc3RydWN0
IG9wYWxfZGV2ICpkZXYpCj4gK3sKPiArCj4gKwlkZXYtPmZ1bmNzID0gZXJyb3JfZW5kX3Nlc3Np
b247Cj4gKwlkZXYtPnN0YXRlID0gMDsKPiArCWRldi0+ZXJyb3JfY2IgPSBOVUxMOwo+ICsJbmV4
dCgwLCBkZXYpOwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArCj4gK3N0YXRpYyBzdHJ1Y3Qgb3BhbF9k
ZXYgKmFsbG9jX29wYWxfZGV2KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHU4IGxyKQo+ICt7
Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKm9wYWxfZGV2Owo+ICsJc3RydWN0IHJlcXVlc3RfcXVldWUg
KnE7Cj4gKwl1bnNpZ25lZCBsb25nIGRtYV9hbGlnbjsKPiArCWNvbnN0IGNoYXIgKmRpc2tfbmFt
ZTsKPiArCXN0cnVjdCBvcGFsX2NtZCAqY21kOwo+ICsJaW50IHJldDsKPiArCj4gKwlvcGFsX2Rl
diA9IGt6YWxsb2Moc2l6ZW9mKCpvcGFsX2RldiksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFvcGFs
X2RldikKPiArCQlyZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsKPiArCj4gKwlvcGFsX2Rldi0+YmRl
diA9IGJkZXY7Cj4gKwlvcGFsX2Rldi0+bHIgPSBscjsKPiArCWNtZCA9ICZvcGFsX2Rldi0+Y21k
Owo+ICsJY21kLT5jbWQgPSBjbWQtPmNtZF9idWY7Cj4gKwljbWQtPnJlc3AgPSBjbWQtPnJlc3Bf
YnVmOwo+ICsKPiArCWRpc2tfbmFtZSA9IGJkZXYtPmJkX2Rpc2stPmRpc2tfbmFtZTsKPiArCWlm
ICghc3RybmNweShvcGFsX2Rldi0+ZGlza19uYW1lLCBkaXNrX25hbWUsIERJU0tfTkFNRV9MRU4p
KSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgcmVnaXN0ZXJpbmcgZGV2aWNlOiBjb3B5aW5nIGRp
c2sgbmFtZVxuIiwKPiArCQkgICAgICAgZGlza19uYW1lKTsKPiArCQlyZXQgPSAtRUZBVUxUOwo+
ICsJCWdvdG8gZXJyX2ZyZWVfZGV2Owo+ICsJfQo+ICsKPiArCXEgPSBiZGV2LT5iZF9xdWV1ZTsK
PiArCWRtYV9hbGlnbiA9IChxdWV1ZV9kbWFfYWxpZ25tZW50KHEpIHwgcS0+ZG1hX3BhZF9tYXNr
KSArIDE7Cj4gKwljbWQtPmNtZCA9ICh1OCAqKXJvdW5kX3VwKCh1aW50cHRyX3QpY21kLT5jbWQs
IGRtYV9hbGlnbik7Cj4gKwljbWQtPnJlc3AgPSAodTggKilyb3VuZF91cCgodWludHB0cl90KWNt
ZC0+cmVzcCwgZG1hX2FsaWduKTsKPiArCj4gKwlJTklUX0xJU1RfSEVBRCgmb3BhbF9kZXYtPm5v
ZGUpOwo+ICsJYXRvbWljX3NldCgmb3BhbF9kZXYtPmluX3VzZSwgMSk7Cj4gKwo+ICsJb3BhbF9k
ZXYtPmNvbXBsZXRpb24gPSBremFsbG9jKHNpemVvZigqb3BhbF9kZXYtPmNvbXBsZXRpb24pLAo+
ICsJCQkJICAgICAgIEdGUF9LRVJORUwpOwo+ICsKPiArCWlmICghb3BhbF9kZXYtPmNvbXBsZXRp
b24pCj4gKwkJZ290byBlcnJfZnJlZV9kZXY7Cj4gKwo+ICsJaW5pdF9jb21wbGV0aW9uKCZvcGFs
X2Rldi0+Y29tcGxldGlvbi0+Y21kX2NvbXBsZXRpb24pOwo+ICsJb3BhbF9kZXYtPmNvbXBsZXRp
b24tPmNvbXBsZXRpb25fc3RhdHVzID0gMDsKPiArCW9wYWxfZGV2LT5zdGF0ZSA9IDA7Cj4gKwo+
ICsJcmV0dXJuIG9wYWxfZGV2Owo+ICsKPiArZXJyX2ZyZWVfZGV2Ogo+ICsJa2ZyZWUob3BhbF9k
ZXYpOwo+ICsJcmV0dXJuIEVSUl9QVFIocmV0KTsKPiArfQo+ICsKPiAraW50IG9wYWxfcmVnaXN0
ZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IG9wYWxfa2V5ICprZXlfY21kLAo+
ICsJCSAgY29uc3Qgb3BhbF9zdGVwICpmdW5jcykKPiArewo+ICsJc3RydWN0IG9wYWxfZGV2ICpu
ZXdfZGV2ID0gTlVMTDsKPiArCXU4IGtleV9sZW4gPSBrZXlfY21kLT5rZXlfbGVuOwo+ICsJdTgg
bHIgPSBrZXlfY21kLT5scjsKPiArCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247
Cj4gKwlpbnQgcmV0Owo+ICsKPiArCW5ld19kZXYgPSBhbGxvY19vcGFsX2RldihiZGV2LCBscik7
Cj4gKwlpZiAoSVNfRVJSKG5ld19kZXYpKSB7Cj4gKwkJcHJfZXJyKCIlczogRXJyb3IgcmVnaXN0
ZXJpbmcgZGV2aWNlOiBhbGxvY2F0aW9uXG4iLAo+ICsJCSAgICAgICBiZGV2LT5iZF9kaXNrLT5k
aXNrX25hbWUpOwo+ICsJCXJldHVybiBQVFJfRVJSKG5ld19kZXYpOwo+ICsJfQo+ICsKPiArCWlm
ICghbWVtY3B5KG5ld19kZXYtPmtleV9uYW1lLCBrZXlfY21kLT5rZXksIGtleV9sZW4pKSB7Cj4g
KwkJcHJfZXJyKCIlczogRXJyb3IgcmVnaXN0ZXJpbmcga2V5OiBjb3VsZG4ndCBjb3B5IGtleVxu
IiwKPiArCQkgICAgICAgbmV3X2Rldi0+ZGlza19uYW1lKTsKPiArCQlyZXR1cm4gLUVGQVVMVDsK
PiArCX0KPiArCj4gKwluZXdfZGV2LT5rZXlfbmFtZV9sZW4gPSBrZXlfbGVuOwo+ICsJbmV3X2Rl
di0+a2V5X3R5cGUgPSBrZXlfY21kLT5rZXlfdHlwZTsKPiArCXJldCA9IGdldF9vcGFsX2tleShu
ZXdfZGV2KTsKPiArCWlmIChyZXQpIHsKPiArCQlwcl9lcnIoIiVzOiBDb3VsZG4ndCBnZXQga2V5
OiAlZFxuIiwgbmV3X2Rldi0+ZGlza19uYW1lLCByZXQpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9
Cj4gKwo+ICsJbmV3X2Rldi0+ZnVuY3MgPSBmdW5jczsKPiArCj4gKwluZXdfZGV2LT5zdGF0ZSA9
IDA7Cj4gKwljb21wbGV0aW9uID0gbmV3X2Rldi0+Y29tcGxldGlvbjsKPiArCW5leHQoMCwgbmV3
X2Rldik7Cj4gKwo+ICsJcmV0dXJuIHdhaXRfZm9yX2NtZF9jb21wbGV0aW9uKGNvbXBsZXRpb24p
Owo+ICt9Cj4gKwo+ICtzdGF0aWMgc3RydWN0IG9wYWxfZGV2ICpnZXRfcmVnaXN0ZXJlZF9vcGFs
X2RldihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LAo+ICsJCQkJCQl1OCBscikKPiArewo+ICsJ
Y29uc3QgY2hhciAqZGlza25hbWUgPSBiZGV2LT5iZF9kaXNrLT5kaXNrX25hbWU7Cj4gKwlzdHJ1
Y3Qgb3BhbF9kZXYgKml0ZXIsICpkZXYgPSBOVUxMOwo+ICsJdW5zaWduZWQgbG9uZyBmbGFnczsK
PiArCWJvb2wgaW5fdXNlID0gZmFsc2U7Cj4gKwo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJmxpc3Rf
c3BpbmxvY2ssIGZsYWdzKTsKPiArCWxpc3RfZm9yX2VhY2hfZW50cnkoaXRlciwgJm9wYWxfbGlz
dCwgbm9kZSkgewo+ICsJCWlmIChzdHJuY21wKGl0ZXItPmRpc2tfbmFtZSwgZGlza25hbWUsIERJ
U0tfTkFNRV9MRU4pKQo+ICsJCQljb250aW51ZTsKPiArCQlpZiAoaXRlci0+bHIgPT0gbHIpIHsK
PiArCQkJZGV2ID0gaXRlcjsKPiArCQkJaWYgKCFhdG9taWNfYWRkX3VubGVzcygmaXRlci0+aW5f
dXNlLCAxLCAxKSkgewo+ICsJCQkJZGV2ID0gTlVMTDsKPiArCQkJCWluX3VzZSA9IHRydWU7Cj4g
KwkJCX0KPiArCQkJYnJlYWs7Cj4gKwkJfQo+ICsJfQo+ICsKPiArCXNwaW5fdW5sb2NrX2lycXJl
c3RvcmUoJmxpc3Rfc3BpbmxvY2ssIGZsYWdzKTsKPiArCj4gKwlpZiAoIWRldikKPiArCQlyZXR1
cm4gTlVMTDsKPiArCj4gKwlkZXYtPmJkZXYgPSBiZGV2Owo+ICsJcmV0dXJuIGRldjsKPiArfQo+
ICsKPiArLyogRnJlZSB1cCB0aGUgT3BhbCBkZXYgYW5kIGl0cyBrZXlzIGR1cmluZyB0d28gc2Nl
bmFyaW9zOgo+ICsgKgo+ICsgKiAxKSBXaGVuIGEgY29tbWFuZCBpcyBjb21wbGV0ZSB0aGF0IG5v
IGxvbmdlciByZXF1aXJlcwo+ICsgKiAgICB0aGUgb3BhbCBkZXYgdG8gYmUgYXJvdW5kLgo+ICsg
KiAyKSBXaGVuIGEgY29tbWFuZCwgaW5jbHVkaW5nIE9wYWwgU2F2ZSBmYWlscyB3ZSBjbGVhbgo+
ICsgKiAgICBhbmQgZnJlZSB0aGUgb3BhbCBkZXYuCj4gKyAqCj4gKyAqICAgIElmIHdlIGZpbmQg
dGhlIG9wYWwgZGV2IHN0cnVjdHVyZSBpbiB0aGUgbGlzdCBvZgo+ICsgKiAgICBzYXZlZCBwYXNz
d29yZHMgd2Ugd2lsbCAqbm90KiByZW1vdmUgaXQuCj4gKyAqLwo+ICtzdGF0aWMgdm9pZCByZW1v
dmVfYW5kX2NsZWFuX29wYWxfZGV2KHN0cnVjdCBvcGFsX2RldiAqZGV2KQo+ICt7Cj4gKwlzdHJ1
Y3Qgb3BhbF9kZXYgKml0ZXI7Cj4gKwlib29sIGZvdW5kID0gZmFsc2U7Cj4gKwo+ICsJc3Bpbl9s
b2NrKCZsaXN0X3NwaW5sb2NrKTsKPiArCWxpc3RfZm9yX2VhY2hfZW50cnkoaXRlciwgJm9wYWxf
bGlzdCwgbm9kZSkgewo+ICsJCWlmIChpdGVyID09IGRldikgewo+ICsJCQlmb3VuZCA9IHRydWU7
Cj4gKwkJCWJyZWFrOwo+ICsJCX0KPiArCX0KPiArCj4gKwlzcGluX3VubG9jaygmbGlzdF9zcGlu
bG9jayk7Cj4gKwlpZiAoIWZvdW5kKSB7Cj4gKwkJY2xlYW5fb3BhbF9rZXkoZGV2KTsKPiArCQlj
bGVhbl9mdW5jdGlvbl9kYXRhKGRldik7Cj4gKwkJa2ZyZWUoZGV2KTsKPiArCX0KPiArfQo+ICsK
PiArc3RhdGljIHN0cnVjdCBvcGFsX2RldiAqZ2V0X29yX2NyZWF0ZV9vcGFsX2RldihzdHJ1Y3Qg
YmxvY2tfZGV2aWNlICpiZGV2LAo+ICsJCQkJCSAgICAgICB1OCBsciwgYm9vbCB1c2VfbmV3KQo+
ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKPiArCj4gKwlpZiAodXNlX25ldykKPiArCQly
ZXR1cm4gYWxsb2Nfb3BhbF9kZXYoYmRldiwgbHIpOwo+ICsKPiArCWRldiA9IGdldF9yZWdpc3Rl
cmVkX29wYWxfZGV2KGJkZXYsIGxyKTsKPiArCWlmICghZGV2KSB7Cj4gKwkJZGV2ID0gYWxsb2Nf
b3BhbF9kZXYoYmRldiwgbHIpOwo+ICsJCWlmICghZGV2KQo+ICsJCQlyZXR1cm4gTlVMTDsKTm8g
bmVlZCBmb3IgdGhpcyBjaGVjayB3aGVuIHlvdSBhbHJlYWR5IHJldHVybiBkZXYKCgo+ICsJfQo+
ICsJcmV0dXJuIGRldjsKPiArfQpJbnN0ZWFkLCBob3cgYWJvdXQ6CnN0YXRpYyBzdHJ1Y3Qgb3Bh
bF9kZXYgKmdldF9vcl9jcmVhdGVfb3BhbF9kZXYoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwK
CQkJCQkgICAgICAgdTggbHIsIGJvb2wgdXNlX25ldykKewoJc3RydWN0IG9wYWxfZGV2ICpkZXYg
PSBOVUxMOwoKCWlmICghdXNlX25ldykKCQlkZXYgPSBnZXRfcmVnaXN0ZXJlZF9vcGFsX2Rldihi
ZGV2LCBscik7CgoJaWYgKCFkZXYpCgkJZGV2ID0gYWxsb2Nfb3BhbF9kZXYoYmRldiwgbHIpOwoK
CXJldHVybiBkZXY7Cn0KCgo+ICsKPiArc3RhdGljIHN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKnNl
dHVwX29wYWxfZGV2KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQkJICAgICAgc3Ry
dWN0IG9wYWxfZGV2ICpkZXYsCj4gKwkJCQkJICAgICAgY29uc3Qgb3BhbF9zdGVwICpmdW5jcywK
PiArCQkJCQkgICAgICBzdHJ1Y3Qgb3BhbF9rZXkgKmtleSkKPiArewo+ICsJaW50IHJldDsKPiAr
Cj4gKwlkZXYtPmJkZXYgPSBiZGV2Owo+ICsJZGV2LT5zdGF0ZSA9IDA7Cj4gKwlkZXYtPmZ1bmNz
ID0gZnVuY3M7Cj4gKwlkZXYtPlRTTiA9IDA7Cj4gKwlkZXYtPkhTTiA9IDA7Cj4gKwlkZXYtPmZp
bmFsX2NiID0gTlVMTDsKPiArCWRldi0+ZmluYWxfY2JfZGF0YSA9IE5VTEw7Cj4gKwlkZXYtPmxy
ID0ga2V5LT5scjsKPiArCWRldi0+ZXJyb3JfY2IgPSBlbmRfb3BhbF9zZXNzaW9uX2Vycm9yOwo+
ICsJZGV2LT5lcnJvcl9jYl9kYXRhID0gZGV2Owo+ICsKPiArCWlmIChrZXkpIHsKPiArCQltZW1j
cHkoZGV2LT5rZXlfbmFtZSwga2V5LT5rZXksIGtleS0+a2V5X2xlbik7Cj4gKwkJZGV2LT5rZXlf
bmFtZV9sZW4gPSBrZXktPmtleV9sZW47Cj4gKwkJZGV2LT5rZXlfdHlwZSA9IGtleS0+a2V5X3R5
cGU7Cj4gKwo+ICsJCXJldCA9IGdldF9vcGFsX2tleShkZXYpOwo+ICsJCWlmIChyZXQpIHsKPiAr
CQkJa2ZyZWUoZGV2LT5jb21wbGV0aW9uKTsKPiArCQkJcHJfZXJyKCIlczogQ291bGRuJ3QgZ2V0
IGtleTogJWRcbiIsCj4gKwkJCSAgICAgICBkZXYtPmRpc2tfbmFtZSwgcmV0KTsKPiArCQkJcmV0
dXJuIEVSUl9QVFIocmV0KTsKPiArCQl9Cj4gKwl9Cj4gKwlkZXYtPmZ1bmNfZGF0YSA9IE5VTEw7
Cj4gKwlkZXYtPmNvbXBsZXRpb24tPmNvbXBsZXRpb25fc3RhdHVzID0gMDsKPiArCj4gKwlyZXR1
cm4gZGV2LT5jb21wbGV0aW9uOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGludGVybmFsX3NldHVw
X2xyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCSAgICAgc3RydWN0IG9wYWxfdXNl
cl9scl9zZXR1cCAqc2V0dXApCj4gK3sKPiArCXN0cnVjdCBvcGFsX2RldiAqZGV2Owo+ICsJc3Ry
dWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCXZvaWQgKmRhdGFbM10gPSB7IE5V
TEwgfTsKPiArCWNvbnN0IG9wYWxfc3RlcCBscl9mdW5jc1tdID0gewo+ICsJCW9wYWxfZGlzY292
ZXJ5MCwKPiArCQlzdGFydF9hdXRoX29wYWxfc2Vzc2lvbiwKPiArCQlzZXR1cF9sb2NraW5nX3Jh
bmdlLAo+ICsJCWdldF9hY3RpdmVfa2V5LAo+ICsJCWdlbl9rZXksCj4gKwkJZW5kX29wYWxfc2Vz
c2lvbiwKPiArCQlOVUxMLAo+ICsJfTsKPiArCWludCByZXQ7Cj4gKwo+ICsJZGV2ID0gZ2V0X29y
X2NyZWF0ZV9vcGFsX2RldihiZGV2LCBzZXR1cC0+a2V5LmxyLCB0cnVlKTsKPiArCWlmICghZGV2
KQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsKPiArCWNvbXBsZXRpb24gPSBzZXR1cF9vcGFsX2Rl
dihiZGV2LCBkZXYsIGxyX2Z1bmNzLCAmc2V0dXAtPmtleSk7Cj4gKwlpZiAoSVNfRVJSKGNvbXBs
ZXRpb24pKSB7Cj4gKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKPiArCQlnb3RvIGVycm9y
X3JldHVybjsKPiArCX0KPiArCj4gKwlkZXYtPmZ1bmNfZGF0YSA9IGRhdGE7Cj4gKwlkZXYtPm51
bV9mdW5jX2RhdGEgPSAzOwo+ICsJZGV2LT5mdW5jX2RhdGFbMV0gPSAmc2V0dXAtPndobzsKPiAr
CWRldi0+ZnVuY19kYXRhWzJdID0gc2V0dXA7Cj4gKwo+ICsJbmV4dCgwLCBkZXYpOwo+ICsJcmV0
ID0gd2FpdF9mb3JfY21kX2NvbXBsZXRpb24oY29tcGxldGlvbik7Cj4gKwo+ICsgZXJyb3JfcmV0
dXJuOgo+ICsJcmVtb3ZlX2FuZF9jbGVhbl9vcGFsX2RldihkZXYpOwo+ICsJcmV0dXJuIHJldDsK
PiArfQo+ICsKPiAraW50IG9wYWxfcmV2ZXJ0KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0
cnVjdCBvcGFsX2tleSAqa2V5KQo+ICt7Cj4gKwljb25zdCBvcGFsX3N0ZXAgcmV2ZXJ0X2Z1bmNz
W10gPSB7Cj4gKwkJb3BhbF9kaXNjb3ZlcnkwLAo+ICsJCXN0YXJ0X1NJREFTUF9vcGFsX3Nlc3Np
b24sCj4gKwkJcmV2ZXJ0X3RwZXIsIC8qIGNvbnRyb2xsZXIgd2lsbCB0ZXJtaW5hdGUgc2Vzc2lv
biAqLwo+ICsJCU5VTEwsCj4gKwl9Owo+ICsKPiArCXJldHVybiBvcGFsX3JlZ2lzdGVyKGJkZXYs
IGtleSwgcmV2ZXJ0X2Z1bmNzKTsKPiArfQo+ICsKPiAraW50IGFjdGl2YXRlX3VzZXIoc3RydWN0
IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IG9wYWxfYWN0aXZhdGVfdXNlciAqYWN0KQo+ICt7
Cj4gKwljb25zdCBvcGFsX3N0ZXAgYWN0X2Z1bmNzW10gPSB7Cj4gKwkJb3BhbF9kaXNjb3Zlcnkw
LAo+ICsJCXN0YXJ0X2FkbWluMUxTUF9vcGFsX3Nlc3Npb24sCj4gKwkJaW50ZXJuYWxfYWN0aXZh
dGVfdXNlciwKPiArCQllbmRfb3BhbF9zZXNzaW9uLAo+ICsJCU5VTEwKPiArCX07Cj4gKwlzdHJ1
Y3Qgb3BhbF9kZXYgKmRldjsKPiArCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247
Cj4gKwl2b2lkICpkYXRhWzNdID0geyBOVUxMIH07Cj4gKwlpbnQgcmV0Owo+ICsKPiArCWRldiA9
IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgYWN0LT5rZXkubHIsIHRydWUpOwo+ICsJaWYg
KCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsJY29tcGxldGlvbiA9IHNldHVwX29w
YWxfZGV2KGJkZXYsIGRldiwgYWN0X2Z1bmNzLCAmYWN0LT5rZXkpOwo+ICsJaWYgKElTX0VSUihj
b21wbGV0aW9uKSkgewo+ICsJCXJldCA9IFBUUl9FUlIoY29tcGxldGlvbik7Cj4gKwkJZ290byBl
cnJvcl9yZXR1cm47Cj4gKwl9Cj4gKwo+ICsJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKPiArCWRl
di0+ZnVuY19kYXRhID0gZGF0YTsKPiArCWRldi0+ZnVuY19kYXRhWzFdID0gYWN0Owo+ICsJZGV2
LT5mdW5jX2RhdGFbMl0gPSBhY3Q7Cj4gKwo+ICsJbmV4dCgwLCBkZXYpOwo+ICsJcmV0ID0gd2Fp
dF9mb3JfY21kX2NvbXBsZXRpb24oY29tcGxldGlvbik7Cj4gKwo+ICsgZXJyb3JfcmV0dXJuOgo+
ICsJcmVtb3ZlX2FuZF9jbGVhbl9vcGFsX2RldihkZXYpOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+
ICsKPiAraW50IG9wYWxfc2V0X3B3KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBv
cGFsX25ld19wdyAqcHcpCj4gKwo+ICt7Cj4gKwljb25zdCBvcGFsX3N0ZXAgcHdfZnVuY3NbXSA9
IHsKPiArCQlvcGFsX2Rpc2NvdmVyeTAsCj4gKwkJc3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCj4g
KwkJc2V0X25ld19wdywKPiArCQllbmRfb3BhbF9zZXNzaW9uLAo+ICsJCU5VTEwKPiArCX07Cj4g
KwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKPiArCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBs
ZXRpb247Cj4gKwl2b2lkICpkYXRhWzNdID0geyBOVUxMIH07Cj4gKwlpbnQgcmV0Owo+ICsKPiAr
CWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgcHctPmN1cnJlbnRfcGluLmxyLCB0
cnVlKTsKPiArCWlmICghZGV2KQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsKPiArCWNvbXBsZXRp
b24gPSBzZXR1cF9vcGFsX2RldihiZGV2LCBkZXYsIHB3X2Z1bmNzLCAmcHctPmN1cnJlbnRfcGlu
KTsKPiArCWlmIChJU19FUlIoY29tcGxldGlvbikpIHsKPiArCQlyZXQgPSBQVFJfRVJSKGNvbXBs
ZXRpb24pOwo+ICsJCWdvdG8gZXJyb3JfcmV0dXJuOwo+ICsJfQo+ICsKPiArCWRldi0+bnVtX2Z1
bmNfZGF0YSA9IDM7Cj4gKwlkZXYtPmZ1bmNfZGF0YSA9IGRhdGE7Cj4gKwlkZXYtPmZ1bmNfZGF0
YVsxXSA9ICh2b2lkICopICZwdy0+d2hvOwo+ICsJZGV2LT5mdW5jX2RhdGFbMl0gPSAodm9pZCAq
KSBwdzsKPiArCj4gKwluZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0X2Zvcl9jbWRfY29tcGxl
dGlvbihjb21wbGV0aW9uKTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4gKwlyZW1vdmVfYW5kX2Ns
ZWFuX29wYWxfZGV2KGRldik7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtpbnQgb3BhbF9h
Y3RfbHNwX2ludChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgb3BhbF9rZXkgKmtl
eSwKPiArCQkgICAgIGNvbnN0IG9wYWxfc3RlcCAqZnVuY3MpCj4gK3sKPiArCXN0cnVjdCBvcGFs
X2RldiAqZGV2Owo+ICsJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCWlu
dCByZXQ7Cj4gKwo+ICsJZGV2ID0gZ2V0X29yX2NyZWF0ZV9vcGFsX2RldihiZGV2LCBrZXktPmxy
LCB0cnVlKTsKPiArCWlmICghZGV2KQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsJY29tcGxldGlv
biA9IHNldHVwX29wYWxfZGV2KGJkZXYsIGRldiwgZnVuY3MsIGtleSk7Cj4gKwlpZiAoSVNfRVJS
KGNvbXBsZXRpb24pKSB7Cj4gKwkJcmV0ID0gUFRSX0VSUihjb21wbGV0aW9uKTsKPiArCQlnb3Rv
IGVycm9yX3JldHVybjsKPiArCX0KPiArCj4gKwluZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0
X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9uKTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4g
KwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRldik7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4g
Kwo+ICsKPiArc3RhdGljIGludCBvcGFsX3NhdmVfaW50ZXJuYWwoc3RydWN0IGJsb2NrX2Rldmlj
ZSAqYmRldiwKPiArCQkJICAgICAgc3RydWN0IG9wYWxfbG9ja191bmxvY2sgKmxrKQo+ICt7Cj4g
Kwl2b2lkICpmdW5jX2RhdGFbM10gPSB7IE5VTEwgfTsKPiArCXN0cnVjdCBvcGFsX2RldiAqZGV2
Owo+ICsJc3RydWN0IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCWNvbnN0IG9wYWxf
c3RlcCBfYXV0aF9mdW5jc1tdID0gewo+ICsJCW9wYWxfZGlzY292ZXJ5MCwKPiArCQlzdGFydF9h
dXRoX29wYWxfc2Vzc2lvbiwKPiArCQlxdWVyeV9sb2NraW5nX3JhbmdlLAo+ICsJCWVuZF9vcGFs
X3Nlc3Npb24sCj4gKwkJb3BhbF9yZWdpc3Rlcl9jb250LAo+ICsJCU5VTEwKPiArCX07Cj4gKwlp
bnQgcmV0Owo+ICsKPiArCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgbGstPmtl
eS5sciwgZmFsc2UpOwo+ICsJaWYgKCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwljb21w
bGV0aW9uID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBfYXV0aF9mdW5jcywgJmxrLT5rZXkp
Owo+ICsJaWYgKElTX0VSUihjb21wbGV0aW9uKSkgewo+ICsJCXJldCA9IFBUUl9FUlIoY29tcGxl
dGlvbik7Cj4gKwkJZ290byBlcnJvcl9yZXR1cm47Cj4gKwl9Cj4gKwo+ICsJZGV2LT5udW1fZnVu
Y19kYXRhID0gMzsKPiArCWRldi0+ZnVuY19kYXRhID0gZnVuY19kYXRhOwo+ICsJZGV2LT5mdW5j
X2RhdGFbMV0gPSAmbGstPmF1dGhvcml0eTsKPiArCWRldi0+bGt1bCA9ICpsazsKPiArCj4gKwlu
ZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9u
KTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4gKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRl
dik7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGFkZF91c2VyX2xyX2lu
dGVybmFsKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQlzdHJ1Y3Qgb3BhbF9sb2Nr
X3VubG9jayAqbGspCj4gK3sKPiArCXZvaWQgKmZ1bmNfZGF0YVszXSA9IHsgTlVMTCB9Owo+ICsJ
c3RydWN0IG9wYWxfZGV2ICpkZXY7Cj4gKwlzdHJ1Y3Qgb3BhbF9jb21wbGV0aW9uICpjb21wbGV0
aW9uOwo+ICsJY29uc3Qgb3BhbF9zdGVwIGZ1bmNzW10gPSB7Cj4gKwkJb3BhbF9kaXNjb3Zlcnkw
LAo+ICsJCXN0YXJ0X2FkbWluMUxTUF9vcGFsX3Nlc3Npb24sCj4gKwkJYWRkX3VzZXJfdG9fbHIs
Cj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiArCQlOVUxMCj4gKwl9Owo+ICsJaW50IHJldDsKPiAr
Cj4gKwlkZXYgPSBnZXRfb3JfY3JlYXRlX29wYWxfZGV2KGJkZXYsIGxrLT5rZXkubHIsIHRydWUp
Owo+ICsJaWYgKCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwljb21wbGV0aW9uID0gc2V0
dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBmdW5jcywgJmxrLT5rZXkpOwo+ICsJaWYgKElTX0VSUihj
b21wbGV0aW9uKSkgewo+ICsJCXJldCA9IFBUUl9FUlIoY29tcGxldGlvbik7Cj4gKwkJZ290byBl
cnJvcl9yZXR1cm47Cj4gKwl9Cj4gKwo+ICsJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKPiArCWRl
di0+ZnVuY19kYXRhID0gZnVuY19kYXRhOwo+ICsJZGV2LT5mdW5jX2RhdGFbMl0gPSBsazsKPiAr
Cj4gKwluZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21w
bGV0aW9uKTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4gKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxf
ZGV2KGRldik7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGxvY2tfdW5s
b2NrX2ludGVybmFsKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQlzdHJ1Y3Qgb3Bh
bF9sb2NrX3VubG9jayAqbGspCj4gK3sKPiArCXZvaWQgKmZ1bmNfZGF0YVszXSA9IHsgTlVMTCB9
Owo+ICsJc3RydWN0IG9wYWxfZGV2ICpkZXY7Cj4gKwlzdHJ1Y3Qgb3BhbF9jb21wbGV0aW9uICpj
b21wbGV0aW9uOwo+ICsKPiArCWNvbnN0IG9wYWxfc3RlcCB1bGtfZnVuY3NfU1VNW10gPSB7Cj4g
KwkJb3BhbF9kaXNjb3ZlcnkwLAo+ICsJCXN0YXJ0X2F1dGhfb3BhbF9zZXNzaW9uLAo+ICsJCWxv
Y2tfdW5sb2NrX2xvY2tpbmdfcmFuZ2VfU1VNLAo+ICsJCWVuZF9vcGFsX3Nlc3Npb24sCj4gKwkJ
TlVMTAo+ICsJfTsKPiArCWNvbnN0IG9wYWxfc3RlcCBfdW5sb2NrX2Z1bmNzW10gPSB7Cj4gKwkJ
b3BhbF9kaXNjb3ZlcnkwLAo+ICsJCXN0YXJ0X2F1dGhfb3BhbF9zZXNzaW9uLAo+ICsJCWxvY2tf
dW5sb2NrX2xvY2tpbmdfcmFuZ2UsCj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiArCQlOVUxMCj4g
Kwl9Owo+ICsJaW50IHJldDsKPiArCj4gKwlkZXYgPSBnZXRfb3JfY3JlYXRlX29wYWxfZGV2KGJk
ZXYsIGxrLT5rZXkubHIsIHRydWUpOwo+ICsJaWYgKCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9NRU07
Cj4gKwo+ICsJaWYgKGxrLT5hdXRob3JpdHkuU1VNKQo+ICsJCWNvbXBsZXRpb24gPSBzZXR1cF9v
cGFsX2RldihiZGV2LCBkZXYsIHVsa19mdW5jc19TVU0sICZsay0+a2V5KTsKPiArCWVsc2UKPiAr
CQljb21wbGV0aW9uID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBfdW5sb2NrX2Z1bmNzLCAm
bGstPmtleSk7Cj4gKwo+ICsJaWYgKElTX0VSUihjb21wbGV0aW9uKSkgewo+ICsJCXJldCA9IFBU
Ul9FUlIoY29tcGxldGlvbik7Cj4gKwkJZ290byBlcnJvcl9yZXR1cm47Cj4gKwl9Cj4gKwo+ICsJ
ZGV2LT5udW1fZnVuY19kYXRhID0gMzsKPiArCWRldi0+ZnVuY19kYXRhID0gZnVuY19kYXRhOwo+
ICsJZGV2LT5mdW5jX2RhdGFbMV0gPSAmbGstPmF1dGhvcml0eTsKPiArCWRldi0+ZnVuY19kYXRh
WzJdID0gbGs7Cj4gKwo+ICsJbmV4dCgwLCBkZXYpOwo+ICsJcmV0ID0gd2FpdF9mb3JfY21kX2Nv
bXBsZXRpb24oY29tcGxldGlvbik7Cj4gKwo+ICsgZXJyb3JfcmV0dXJuOgo+ICsJcmVtb3ZlX2Fu
ZF9jbGVhbl9vcGFsX2RldihkZXYpOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICsKPiAraW50IG9w
YWxfZXJhc2VfbG9ja2luZ19yYW5nZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qg
c2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKPiArCXN0cnVjdCBv
cGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247Cj4gKwlzdHJ1Y3Qgb3BhbF9rZXkgazsKPiArCWlu
dCByZXQ7Cj4gKwljb25zdCBvcGFsX3N0ZXAgZXJhc2VfZnVuY3NbXSA9IHsKPiArCQlvcGFsX2Rp
c2NvdmVyeTAsCj4gKwkJc3RhcnRfYWRtaW4xTFNQX29wYWxfc2Vzc2lvbiwKPiArCQllcmFzZV9s
b2NraW5nX3JhbmdlLAo+ICsJCWVuZF9vcGFsX3Nlc3Npb24sCj4gKwkJTlVMTCwKPiArCX07Cj4g
Kwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrKSB7Cj4gKwkJcHJfZXJyKCJDYW4ndCBz
YXZlIHBhc3N3b3JkIGZvciBOVUxMIGJsb2NrIGRldmljZS5cbiIpOwo+ICsJCXJldHVybiAtRUlO
VkFMOwo+ICsJfQo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNlcigmaywga2V5LT5vcGFsLCBzaXpl
b2YoKmtleS0+b3BhbCkpKQo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsKPiArCWRldiA9IGdldF9v
cl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgay5sciwgdHJ1ZSk7Cj4gKwlpZiAoIWRldikKPiArCQly
ZXR1cm4gLUVOT01FTTsKPiArCj4gKwljb21wbGV0aW9uID0gc2V0dXBfb3BhbF9kZXYoYmRldiwg
ZGV2LCBlcmFzZV9mdW5jcywgJmspOwo+ICsJaWYgKElTX0VSUihjb21wbGV0aW9uKSkgewo+ICsJ
CXJldCA9IFBUUl9FUlIoY29tcGxldGlvbik7Cj4gKwkJZ290byBlcnJvcl9yZXR1cm47Cj4gKwl9
Cj4gKwo+ICsJbmV4dCgwLCBkZXYpOwo+ICsJcmV0ID0gd2FpdF9mb3JfY21kX2NvbXBsZXRpb24o
Y29tcGxldGlvbik7Cj4gKwo+ICsgZXJyb3JfcmV0dXJuOgo+ICsJcmVtb3ZlX2FuZF9jbGVhbl9v
cGFsX2RldihkZXYpOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICtFWFBPUlRfU1lNQk9MKG9wYWxf
ZXJhc2VfbG9ja2luZ19yYW5nZSk7Cj4gKwo+ICtpbnQgb3BhbF9lbmFibGVfZGlzYWJsZV9zaGFk
b3dfbWJyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQkgICBzdHJ1Y3Qgc2VkX2tl
eSAqa2V5KQo+ICt7Cj4gKwl2b2lkICpmdW5jX2RhdGFbNl0gPSB7IE5VTEwgfTsKPiArCXN0cnVj
dCBvcGFsX21icl9kYXRhIG1icjsKPiArCXN0cnVjdCBvcGFsX2RldiAqZGV2Owo+ICsJc3RydWN0
IG9wYWxfY29tcGxldGlvbiAqY29tcGxldGlvbjsKPiArCWNvbnN0IG9wYWxfc3RlcCBtYnJfZnVu
Y3NbXSA9IHsKPiArCQlvcGFsX2Rpc2NvdmVyeTAsCj4gKwkJc3RhcnRfYWRtaW4xTFNQX29wYWxf
c2Vzc2lvbiwKPiArCQlzZXRfbWJyX2RvbmUsCj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiArCQlz
dGFydF9hZG1pbjFMU1Bfb3BhbF9zZXNzaW9uLAo+ICsJCXNldF9tYnJfZW5hYmxlX2Rpc2FibGUs
Cj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiArCQlOVUxMLAo+ICsJfTsKPiArCWludCByZXQ7Cj4g
Kwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrKSB7Cj4gKwkJcHJfZXJyKCJDYW4ndCBz
YXZlIHBhc3N3b3JkIGZvciBOVUxMIGJsb2NrIGRldmljZS5cbiIpOwo+ICsJCXJldHVybiAtRUlO
VkFMOwo+ICsJfQo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNlcigmbWJyLCBrZXktPm9wYWxfbWJy
LCBzaXplb2YoKmtleS0+b3BhbF9tYnIpKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCj4gKwlp
ZiAobWJyLmVuYWJsZV9kaXNhYmxlICE9IE9QQUxfTUJSX0VOQUJMRSAmJgo+ICsJICAgIG1ici5l
bmFibGVfZGlzYWJsZSAhPSBPUEFMX01CUl9ESVNBQkxFKQo+ICsJCXJldHVybiAtRUlOVkFMOwo+
ICsKPiArCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgbWJyLmtleS5sciwgdHJ1
ZSk7Cj4gKwlpZiAoIWRldikKPiArCQlyZXR1cm4gLUVOT01FTTsKPiArCj4gKwljb21wbGV0aW9u
ID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBtYnJfZnVuY3MsICZtYnIua2V5KTsKPiArCWlm
IChJU19FUlIoY29tcGxldGlvbikpIHsKPiArCQlyZXQgPSBQVFJfRVJSKGNvbXBsZXRpb24pOwo+
ICsJCWdvdG8gZXJyb3JfcmV0dXJuOwo+ICsJfQo+ICsKPiArCWRldi0+bnVtX2Z1bmNfZGF0YSA9
IDY7Cj4gKwlkZXYtPmZ1bmNfZGF0YSA9IGZ1bmNfZGF0YTsKPiArCWRldi0+ZnVuY19kYXRhWzJd
ID0gJm1ici5lbmFibGVfZGlzYWJsZTsKPiArCWRldi0+ZnVuY19kYXRhWzVdID0gJm1ici5lbmFi
bGVfZGlzYWJsZTsKPiArCj4gKwluZXh0KDAsIGRldik7Cj4gKwlyZXQgPSB3YWl0X2Zvcl9jbWRf
Y29tcGxldGlvbihjb21wbGV0aW9uKTsKPiArCj4gKyBlcnJvcl9yZXR1cm46Cj4gKwlyZW1vdmVf
YW5kX2NsZWFuX29wYWxfZGV2KGRldik7Cj4gKwlyZXR1cm4gcmV0Owo+ICsKPiArfQo+ICtFWFBP
UlRfU1lNQk9MKG9wYWxfZW5hYmxlX2Rpc2FibGVfc2hhZG93X21icik7Cj4gKwo+ICtpbnQgb3Bh
bF9zYXZlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4g
K3sKPiArCXN0cnVjdCBvcGFsX2xvY2tfdW5sb2NrIGxrdWw7Cj4gKwo+ICsJaWYgKCFiZGV2IHx8
ICFiZGV2LT5iZF9kaXNrKSB7Cj4gKwkJcHJfZXJyKCJDYW4ndCBzYXZlIHBhc3N3b3JkIGZvciBO
VUxMIGJsb2NrIGRldmljZS5cbiIpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiAr
CWlmIChjb3B5X2Zyb21fdXNlcigmbGt1bCwga2V5LT5vcGFsX2xrX3VubGssIHNpemVvZigqa2V5
LT5vcGFsKSkpCj4gKwkJcmV0dXJuIC1FRkFVTFQ7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfc2F2ZV9p
bnRlcm5hbChiZGV2LCAmbGt1bCk7Cj4gK30KPiArRVhQT1JUX1NZTUJPTChvcGFsX3NhdmUpOwo+
ICsKPiAraW50IG9wYWxfYWRkX3VzZXJfdG9fbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwg
c3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsJc3RydWN0IG9wYWxfbG9ja191bmxvY2sgbGt1
bDsKPiArCj4gKwlpZiAoY29weV9mcm9tX3VzZXIoJmxrdWwsIGtleS0+b3BhbF9sa191bmxrLCBz
aXplb2YobGt1bCkpKQo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsKPiArCWlmICghYmRldiB8fCAh
YmRldi0+YmRfZGlzaykgewo+ICsJCXByX2VycigiQ2FuJ3QgYXNzaWduIHVzZXIgdG8gTFIgd2l0
aG91dCBiYWNraW5nIGRpc2tcbiIpOwo+ICsJCXJldHVybiAtRUZBVUxUOwo+ICsJfQo+ICsJaWYg
KGxrdWwubF9zdGF0ZSAhPSBPUEFMX1JPICYmIGxrdWwubF9zdGF0ZSAhPSBPUEFMX1JXKSB7Cj4g
KwkJcHJfZXJyKCJMb2NraW5nIHN0YXRlIHdhcyBub3QgUk8gb3IgUldcbiIpOwo+ICsJCXJldHVy
biAtRUlOVkFMOwo+ICsJfQo+ICsJaWYgKGxrdWwuYXV0aG9yaXR5LndobyA8IE9QQUxfVVNFUjEg
JiYKPiArCSAgICBsa3VsLmF1dGhvcml0eS53aG8gPiBPUEFMX1VTRVI5KSB7Cj4gKwkJcHJfZXJy
KCJBdXRob3JpdHkgd2FzIG5vdCB3aXRoaW4gdGhlIHJhbmdlIG9mIHVzZXJzOiAlZFxuIiwKPiAr
CQkgICAgICAgbGt1bC5hdXRob3JpdHkud2hvKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCX0K
PiArCWlmIChsa3VsLmF1dGhvcml0eS5TVU0pIHsKPiArCQlwcl9lcnIoIiVzIG5vdCBzdXBwb3J0
ZWQgaW4gU1VNLiBVc2Ugc2V0dXAgbG9ja2luZyByYW5nZVxuIiwKPiArCQkgICAgICAgX19mdW5j
X18pOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCXJldHVybiBhZGRfdXNlcl9s
cl9pbnRlcm5hbChiZGV2LCAmbGt1bCk7Cj4gK30KPiArRVhQT1JUX1NZTUJPTChvcGFsX2FkZF91
c2VyX3RvX2xyKTsKPiArCj4gK2ludCBvcGFsX3JldmVydHRwZXIoc3RydWN0IGJsb2NrX2Rldmlj
ZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsJc3RydWN0IG9wYWxfa2V5IGs7
Cj4gKwo+ICsJaWYgKGNvcHlfZnJvbV91c2VyKCZrLCBrZXktPm9wYWwsIHNpemVvZigqa2V5LT5v
cGFsKSkpCj4gKwkJcmV0dXJuIC1FRkFVTFQ7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfcmV2ZXJ0KGJk
ZXYsICZrKTsKPiArfQo+ICtFWFBPUlRfU1lNQk9MKG9wYWxfcmV2ZXJ0dHBlcik7Cj4gKwo+ICtp
bnQgb3BhbF9sb2NrX3VubG9jayhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2Vk
X2tleSAqa2V5KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayBrOwo+ICsKPiArCWlm
IChjb3B5X2Zyb21fdXNlcigmaywga2V5LT5vcGFsX2xrX3VubGssIHNpemVvZigqa2V5LT5vcGFs
X2xrX3VubGspKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCj4gKwlpZiAoay5hdXRob3JpdHku
d2hvIDwgT1BBTF9BRE1JTjEgfHwgay5hdXRob3JpdHkud2hvID49IE9QQUxfVVNFUjkpClNob3Vs
ZCB0aGlzIGJlID4gT1BBTF9VU0VSOSA/CgoKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCj4gKwly
ZXR1cm4gbG9ja191bmxvY2tfaW50ZXJuYWwoYmRldiwgJmspOwo+ICt9Cj4gK0VYUE9SVF9TWU1C
T0wob3BhbF9sb2NrX3VubG9jayk7Cj4gKwo+ICtpbnQgb3BhbF90YWtlX293bmVyc2hpcChzdHJ1
Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlzdHJ1
Y3Qgb3BhbF9rZXkgazsKPiArCWNvbnN0IG9wYWxfc3RlcCBvd25lcl9mdW5jc1tdID0gewo+ICsJ
CW9wYWxfZGlzY292ZXJ5MCwKPiArCQlzdGFydF9hbnlib2R5QVNQX29wYWxfc2Vzc2lvbiwKPiAr
CQlnZXRfbXNpZF9jcGluX3BpbiwKPiArCQllbmRfb3BhbF9zZXNzaW9uLAo+ICsJCXN0YXJ0X1NJ
REFTUF9vcGFsX3Nlc3Npb24sCj4gKwkJc2V0X3NpZF9jcGluX3BpbiwKPiArCQllbmRfb3BhbF9z
ZXNzaW9uLAo+ICsJCU5VTEwKPiArCX07Cj4gKwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9k
aXNrKSB7Cj4gKwkJcHJfZXJyKCJDYW4ndCBzYXZlIHBhc3N3b3JkIGZvciBOVUxMIGJsb2NrIGRl
dmljZS5cbiIpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCWlmIChjb3B5X2Zy
b21fdXNlcigmaywga2V5LT5vcGFsLCBzaXplb2YoKmtleS0+b3BhbCkpKQo+ICsJCXJldHVybiAt
RUZBVUxUOwo+ICsKPiArCXJldHVybiBvcGFsX3JlZ2lzdGVyKGJkZXYsICZrLCBvd25lcl9mdW5j
cyk7Cj4gK30KPiArRVhQT1JUX1NZTUJPTChvcGFsX3Rha2Vfb3duZXJzaGlwKTsKPiArCj4gK2lu
dCBvcGFsX2FjdGl2YXRlX2xzcChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2Vk
X2tleSAqa2V5KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9rZXkgazsKPiArCWNvbnN0IG9wYWxfc3Rl
cCBhY3RpdmVfZnVuY3NbXSA9IHsKPiArCQlvcGFsX2Rpc2NvdmVyeTAsCj4gKwkJc3RhcnRfU0lE
QVNQX29wYWxfc2Vzc2lvbiwgLyogT3BlbiBzZXNzaW9uIGFzIFNJRCBhdXRoICovCj4gKwkJZ2V0
X2xzcF9saWZlY3ljbGUsCj4gKwkJYWN0aXZhdGVfbHNwLAo+ICsJCWVuZF9vcGFsX3Nlc3Npb24s
Cj4gKwkJTlVMTAo+ICsJfTsKPiArCj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2spIHsK
PiArCQlwcl9lcnIoIkNhbid0IHNhdmUgcGFzc3dvcmQgZm9yIE5VTEwgYmxvY2sgZGV2aWNlLlxu
Iik7Cj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwl9Cj4gKwo+ICsJaWYgKGNvcHlfZnJvbV91c2Vy
KCZrLCBrZXktPm9wYWwsIHNpemVvZigqa2V5LT5vcGFsKSkpCj4gKwkJcmV0dXJuIC1FRkFVTFQ7
Cj4gKwo+ICsJcmV0dXJuIG9wYWxfYWN0X2xzcF9pbnQoYmRldiwgJmssIGFjdGl2ZV9mdW5jcyk7
Cj4gK30KPiArRVhQT1JUX1NZTUJPTChvcGFsX2FjdGl2YXRlX2xzcCk7Cj4gKwo+ICtpbnQgb3Bh
bF9zZXR1cF9sb2NraW5nX3JhbmdlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBz
ZWRfa2V5ICpwdykKPiArewo+ICsJc3RydWN0IG9wYWxfdXNlcl9scl9zZXR1cCBrOwo+ICsKPiAr
CWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzaykgewo+ICsJCXByX2VycigiQ2FuJ3Qgc2F2ZSBw
YXNzd29yZCBmb3IgTlVMTCBibG9jayBkZXZpY2UuXG4iKTsKPiArCQlyZXR1cm4gLUVJTlZBTDsK
PiArCX0KPiArCj4gKwlpZiAoY29weV9mcm9tX3VzZXIoJmssIHB3LT5vcGFsX2xycywgc2l6ZW9m
KCpwdy0+b3BhbF9scnMpKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCj4gKwlyZXR1cm4gaW50
ZXJuYWxfc2V0dXBfbHIoYmRldiwgJmspOwo+ICt9Cj4gKwo+ICtpbnQgb3BhbF9zZXRfbmV3X3B3
KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICpwdykKPiArewo+ICsJ
c3RydWN0IG9wYWxfbmV3X3B3IGs7Cj4gKwo+ICsJaWYgKHB3LT5zZWRfdHlwZSAhPSBPUEFMX1BX
KQo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNlcigmaywgcHct
Pm9wYWxfcHcsIHNpemVvZigqcHctPm9wYWxfcHcpKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiAr
Cj4gKwlpZiAoay53aG8ud2hvIDwgT1BBTF9BRE1JTjEgfHwgay53aG8ud2hvID4gT1BBTF9VU0VS
OSkKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCj4gKwlyZXR1cm4gb3BhbF9zZXRfcHcoYmRldiwg
JmspOwo+ICt9Cj4gK0VYUE9SVF9TWU1CT0wob3BhbF9zZXRfbmV3X3B3KTsKPiArCj4gK2ludCBv
cGFsX2FjdGl2YXRlX3VzZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9r
ZXkgKnB3KQo+ICt7Cj4gKwlzdHJ1Y3Qgb3BhbF9hY3RpdmF0ZV91c2VyIGs7Cj4gKwo+ICsJaWYg
KHB3LT5zZWRfdHlwZSAhPSBPUEFMX0FDVF9VU1IpIHsKPiArCQlwcl9lcnIoIlNlZCB0eXBlIHdh
cyBub3QgYWN0IHVzZXJcbiIpOwo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsJfQo+ICsKPiArCWlm
IChjb3B5X2Zyb21fdXNlcigmaywgcHctPm9wYWxfYWN0LCBzaXplb2YoKnB3LT5vcGFsX2FjdCkp
KSB7Cj4gKwkJcHJfZXJyKCJjb3B5IGZyb20gdXNlciBlcnJvclxuIik7Cj4gKwkJcmV0dXJuIC1F
RkFVTFQ7Cj4gKwl9Cj4gKwo+ICsJLyogV2UgY2FuJ3QgYWN0aXZhdGUgQWRtaW4xIGl0J3MgYWN0
aXZlIGFzIG1hbnVmYWN0dXJlZCAqLwo+ICsJaWYgKGsud2hvLndobyA8IE9QQUxfVVNFUjEgJiYg
ay53aG8ud2hvID4gT1BBTF9VU0VSOSkgewo+ICsJCXByX2VycigiV2hvIHdhcyBub3QgYSB2YWxp
ZCB1c2VyOiAlZCBcbiIsIGsud2hvLndobyk7Cj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4gKwl9Cj4g
Kwo+ICsJcmV0dXJuIGFjdGl2YXRlX3VzZXIoYmRldiwgJmspOwo+ICsKPiArfQo+ICtFWFBPUlRf
U1lNQk9MKG9wYWxfYWN0aXZhdGVfdXNlcik7Cj4gKwo+ICtpbnQgb3BhbF91bmxvY2tfZnJvbV9z
dXNwZW5kKHN0cnVjdCBvcGFsX3N1c3BlbmRfdW5sayAqZGF0YSkKPiArewo+ICsJY29uc3QgY2hh
ciAqZGlza25hbWUgPSBkYXRhLT5uYW1lOwo+ICsJc3RydWN0IG9wYWxfZGV2ICppdGVyLCAqZGV2
ID0gTlVMTDsKPiArCXN0cnVjdCBvcGFsX2NvbXBsZXRpb24gKmNvbXBsZXRpb247Cj4gKwl2b2lk
ICpmdW5jX2RhdGFbM10gPSB7IE5VTEwgfTsKPiArCWNvbnN0IG9wYWxfc3RlcCBfdW5sb2NrX2Z1
bmNzX1NVTVtdID0gewo+ICsJCW9wYWxfZGlzY292ZXJ5MCwKPiArCQlzdGFydF9hdXRoX29wYWxf
c2Vzc2lvbiwKPiArCQlsb2NrX3VubG9ja19sb2NraW5nX3JhbmdlLApEaWQgeW91IG1lYW4gdG8g
dXNlIGxvY2tfdW5sb2NrX2xvY2tpbmdfcmFuZ2VfU1VNID8KQ2FuIHdlIHB1bGwgdGhlc2UgdHdv
IGFycmF5cyBvdXQgc2luY2UgdGhleSBhcmUgcmVxdWlyZWQgZm9yIGJvdGggdGhpcwpmdW5jdGlv
biBhbmQgbG9ja191bmxvY2tfaW50ZXJuYWwgPwoKCj4gKwkJZW5kX29wYWxfc2Vzc2lvbiwKPiAr
CQlOVUxMCj4gKwl9Owo+ICsJY29uc3Qgb3BhbF9zdGVwIF91bmxvY2tfZnVuY3NbXSA9IHsKPiAr
CQlvcGFsX2Rpc2NvdmVyeTAsCj4gKwkJc3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCj4gKwkJbG9j
a191bmxvY2tfbG9ja2luZ19yYW5nZSwKPiArCQllbmRfb3BhbF9zZXNzaW9uLAo+ICsJCU5VTEwK
PiArCX07Cj4gKwo+ICsKPiArCXNwaW5fbG9jaygmbGlzdF9zcGlubG9jayk7Cj4gKwlsaXN0X2Zv
cl9lYWNoX2VudHJ5KGl0ZXIsICZvcGFsX2xpc3QsIG5vZGUpIHsKPiArCQlpZiAoc3RybmNtcChp
dGVyLT5kaXNrX25hbWUsIGRpc2tuYW1lLCBESVNLX05BTUVfTEVOKSkgewo+ICsJCQlwcl9lcnIo
Iml0ZXJkaXNrIHdhcyAlcyBhbmQgZGlza25hbWUgaXMgJXNcbiIsCj4gKwkJCSAgICAgICBpdGVy
LT5kaXNrX25hbWUsIGRpc2tuYW1lKTsKPiArCQkJY29udGludWU7Cj4gKwkJfQo+ICsJCWlmIChh
dG9taWNfYWRkX3VubGVzcygmaXRlci0+aW5fdXNlLCAxLCAxKSkgewo+ICsJCQlkZXYgPSBpdGVy
Owo+ICsJCQlkZXYtPmZ1bmNfZGF0YSA9IGZ1bmNfZGF0YTsKPiArCQkJZGV2LT5yZXN1bWVfZnJv
bV9zdXNwZW5kID0gdHJ1ZTsKPiArCQkJZGV2LT5yZXN1bWVfZGF0YSA9IGRhdGE7Cj4gKwkJCWRl
di0+ZmluYWxfY2IgPSB1bmxvY2tfc3VzcGVuZF9maW5hbDsKPiArCQkJZGV2LT5maW5hbF9jYl9k
YXRhID0gZGV2Owo+ICsJCQlkZXYtPmVycm9yX2NiID0gZW5kX29wYWxfc2Vzc2lvbl9lcnJvcjsK
PiArCQkJZGV2LT5lcnJvcl9jYl9kYXRhID0gZGV2Owo+ICsJCQlkZXYtPnN0YXRlID0gMDsKPiAr
CQkJaWYgKGRldi0+bGt1bC5hdXRob3JpdHkuU1VNKQo+ICsJCQkJZGV2LT5mdW5jcyA9IF91bmxv
Y2tfZnVuY3NfU1VNOwo+ICsJCQllbHNlCj4gKwkJCQlkZXYtPmZ1bmNzID0gX3VubG9ja19mdW5j
czsKPiArCQkJZGV2LT5UU04gPSAwOwo+ICsJCQlkZXYtPkhTTiA9IDA7Cj4gKwkJCWRldi0+ZnVu
Y19kYXRhWzJdID0gJmRldi0+bGt1bDsKPiArCQkJZGV2LT5mdW5jX2RhdGFbMV0gPSAmZGV2LT5s
a3VsLmF1dGhvcml0eTsKPiArCQkJY29tcGxldGlvbiA9IGRldi0+Y29tcGxldGlvbjsKPiArCQkJ
bmV4dCgwLCBkZXYpOwo+ICsJCQl3YWl0X2Zvcl9jbWRfY29tcGxldGlvbihjb21wbGV0aW9uKTsK
PiArCQl9Cj4gKwl9Cj4gKwlzcGluX3VubG9jaygmbGlzdF9zcGlubG9jayk7Cj4gKwo+ICsJaWYg
KCFkZXYpCj4gKwkJcmV0dXJuIC1FTk9ERVY7Cj4gKwlyZXR1cm4gMDsKPiArfQo+ICtFWFBPUlRf
U1lNQk9MKG9wYWxfdW5sb2NrX2Zyb21fc3VzcGVuZCk7Cj4gZGlmZiAtLWdpdCBhL2xpYi9zZWQt
b3BhbF9pbnRlcm5hbC5oIGIvbGliL3NlZC1vcGFsX2ludGVybmFsLmgKPiBuZXcgZmlsZSBtb2Rl
IDEwMDY0NAo+IGluZGV4IDAwMDAwMDAuLmM5ZDM4ODMKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIv
bGliL3NlZC1vcGFsX2ludGVybmFsLmgKPiBAQCAtMCwwICsxLDU4NiBAQAo+ICsvKgo+ICsgKiBD
b3B5cmlnaHQgwqkgMjAxNiBJbnRlbCBDb3Jwb3JhdGlvbgo+ICsgKgo+ICsgKiBQZXJtaXNzaW9u
IGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5p
bmcgYQo+ICsgKiBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRh
dGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLAo+ICsgKiB0byBkZWFsIGluIHRoZSBTb2Z0d2Fy
ZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uCj4gKyAq
IHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmli
dXRlLCBzdWJsaWNlbnNlLAo+ICsgKiBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJl
LCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUKPiArICogU29mdHdhcmUgaXMgZnVy
bmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKPiAr
ICoKPiArICogVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBu
b3RpY2UgKGluY2x1ZGluZyB0aGUgbmV4dAo+ICsgKiBwYXJhZ3JhcGgpIHNoYWxsIGJlIGluY2x1
ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlCj4gKyAqIFNv
ZnR3YXJlLgo+ICsgKgo+ICsgKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lU
SE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgo+ICsgKiBJTVBMSUVELCBJTkNM
VURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElU
WSwKPiArICogRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdF
TUVOVC4gIElOIE5PIEVWRU5UIFNIQUxMCj4gKyAqIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBI
T0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSCj4gKyAqIExJ
QUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJX
SVNFLCBBUklTSU5HCj4gKyAqIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhF
IFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MKPiArICogSU4gVEhFIFNPRlRX
QVJFLgo+ICsgKgo+ICsgKiBBdXRob3I6Cj4gKyAqICAgIFJhZmFlbCBBbnRvZ25vbGxpIDxyYWZh
ZWwuYW50b2dub2xsaUBpbnRlbC5jb20+Cj4gKyAqICAgIFNjb3R0ICBCYXVlciAgICAgIDxzY290
dC5iYXVlckBpbnRlbC5jb20+Cj4gKyAqLwo+ICsKPiArI2lmbmRlZiBfTlZNRV9PUEFMX0lOVEVS
TkFMX0gKPiArI2RlZmluZSBfTlZNRV9PUEFMX0lOVEVSTkFMX0gKPiArCj4gKyNpbmNsdWRlIDxs
aW51eC9rZXktdHlwZS5oPgo+ICsjaW5jbHVkZSA8a2V5cy91c2VyLXR5cGUuaD4KPiArCj4gKyNk
ZWZpbmUgRFRBRVJST1JfTk9fTUVUSE9EX1NUQVRVUyAweDg5Cj4gKwo+ICtzdGF0aWMgY29uc3Qg
Y2hhciAqb3BhbF9lcnJvcnNbMTldID0gewpSZW1vdmUgdGhlIDE5IHNvIGl0J3MganVzdCBvcGFs
X2Vycm9yc1tdIChkb2VzbnQgc2lsZW50bHkgdHJ1bmNhdGUgYW55Cm5ldyBhZGRpdGlvbnMpCgoK
PiArCSJTdWNjZXNzIiwKPiArCSJOb3QgQXV0aG9yaXplZCIsCj4gKwkiVW5rbm93biBFcnJvciIs
Cj4gKwkiU1AgQnVzeSIsCj4gKwkiU1AgRmFpbGVkIiwKPiArCSJTUCBEaXNhYmxlZCIsCj4gKwki
U1AgRnJvemVuIiwKPiArCSJObyBTZXNzaW9ucyBBdmFpbGFibGUiLAo+ICsJIlVuaXF1ZW5lc3Mg
Q29uZmxpY3QiLAo+ICsJIkluc3VmZmljaWVudCBTcGFjZSIsCj4gKwkiSW5zdWZmaWNpZW50IFJv
d3MiLAo+ICsJIkludmFsaWQgRnVuY3Rpb24iLAo+ICsJIkludmFsaWQgUGFyYW1ldGVyIiwKPiAr
CSJJbnZhbGlkIFJlZmVyZW5jZSIsCj4gKwkiVW5rbm93biBFcnJvciIsCj4gKwkiVFBFUiBNYWxm
dW5jdGlvbiIsCj4gKwkiVHJhbnNhY3Rpb24gRmFpbHVyZSIsCj4gKwkiUmVzcG9uc2UgT3ZlcmZs
b3ciLAo+ICsJIkF1dGhvcml0eSBMb2NrZWQgT3V0IiwKPiArfTsKPiArCj4gK3N0YXRpYyBjb25z
dCBjaGFyICpvcGFsX2Vycm9yX3RvX2h1bWFuKGludCBlcnJvcikKPiArewo+ICsJaWYgKGVycm9y
ID09IDB4M2YpCj4gKwkJcmV0dXJuICJGYWlsZWQiOwo+ICsKPiArCWlmIChlcnJvciA+PSBzaXpl
b2Yob3BhbF9lcnJvcnMpIHx8IGVycm9yIDwgMCkKWW91IHdhbnQgc2l6ZW9mKG9wYWxfZXJyb3Jz
KS9zaXplb2YoKm9wYWxfZXJyb3JzKSBoZXJlLCBidXQgeW91IGNhbiBqdXN0CnVzZSB0aGUgQVJS
QVlfU0laRSBtYWNybyBpbnN0ZWFkCgoKPiArCQlyZXR1cm4gIlVua25vd24gRXJyb3IiOwo+ICsK
PiArCXJldHVybiBvcGFsX2Vycm9yc1tlcnJvcl07Cj4gK30KPiArCj4gKy8qIFVzZXIgSURzIHVz
ZWQgaW4gdGhlIFRDRyBzdG9yYWdlIFNTQ3MgKi8KPiArc3RhdGljIGNvbnN0IHU4IE9QQUxVSURb
XVs4XSA9IHsKPiArCS8qIHVzZXJzICovCj4gKwo+ICsJLyogc2Vzc2lvbiBtYW5hZ2VtZW50ICAq
Lwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweDAwLCAweGZmfSwK
PiArCS8qIHNwZWNpYWwgInRoaXNTUCIgc3ludGF4ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDEgfSwKPiArCS8qIEFkbWluaXN0cmF0aXZlIFNQ
ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDIsIDB4MDUsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDEg
fSwKPiArCS8qIExvY2tpbmcgU1AgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMiwgMHgwNSwgMHgw
MCwgMHgwMCwgMHgwMCwgMHgwMiB9LAo+ICsJLyogRU5URVJQUklTRSBMb2NraW5nIFNQICAqLwo+
ICsJeyAweDAwLCAweDAwLCAweDAyLCAweDA1LCAweDAwLCAweDAxLCAweDAwLCAweDAxIH0sCj4g
KwkvKiBhbnlib2R5ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDksIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDEgfSwKPiArCS8qIFNJRCAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA5
LCAweDAwLCAweDAwLCAweDAwLCAweDA2IH0sCj4gKwkvKiBBRE1JTjEgKi8KPiArCXsgMHgwMCwg
MHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMSwgMHgwMCwgMHgwMSB9LAo+ICsJLyogVVNFUjEg
Ki8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMywgMHgwMCwgMHgwMSB9
LAo+ICsJLyogVVNFUjIgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgw
MywgMHgwMCwgMHgwMiB9LAo+ICsJLyogUFNJRCB1c2VyICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4
MDAsIDB4MDksIDB4MDAsIDB4MDEsIDB4ZmYsIDB4MDEgfSwKPiArCS8qIEJhbmRNYXN0ZXIgMCAq
Lwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA5LCAweDAwLCAweDAwLCAweDgwLCAweDAxIH0s
Cj4gKwkgLyogRXJhc2VNYXN0ZXIgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgw
MCwgMHgwMCwgMHg4NCwgMHgwMSB9LAo+ICsKPiArCS8qIHRhYmxlcyAqLwo+ICsKPiArCS8qIExv
Y2tpbmdfR2xvYmFsUmFuZ2UgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwOCwgMHgwMiwgMHgwMCwg
MHgwMCwgMHgwMCwgMHgwMSB9LAo+ICsJLyogQUNFX0xvY2tpbmdfUmFuZ2VfU2V0X1JkTG9ja2Vk
IFVJRCAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA4LCAweDAwLCAweDAzLCAweEUwLCAw
eDAxIH0sCj4gKwkvKiBBQ0VfTG9ja2luZ19SYW5nZV9TZXRfV3JMb2NrZWQgVUlEICovCj4gKwl7
IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDgsIDB4MDAsIDB4MDMsIDB4RTgsIDB4MDEgfSwKPiArCS8q
IE1CUiBDb250cm9sICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDgsIDB4MDMsIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MDEgfSwKPiArCS8qIFNoYWRvdyBNQlIgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgw
OCwgMHgwNCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCB9LAo+ICsJLyogQVVUSE9SSVRZX1RBQkxF
ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDksIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDB9
LAo+ICsJLyogQ19QSU5fVEFCTEUgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwQiwgMHgw
MCwgMHgwMCwgMHgwMCwgMHgwMH0sCj4gKwkvKiBPUEFMIExvY2tpbmcgSW5mbyAqLwo+ICsJeyAw
eDAwLCAweDAwLCAweDA4LCAweDAxLCAweDAwLCAweDAwLCAweDAwLCAweDAxIH0sCj4gKwkvKiBF
bnRlcnByaXNlIExvY2tpbmcgSW5mbyAqLwo+ICsJeyAweDAwLCAweDAwLCAweDA4LCAweDAxLCAw
eDAwLCAweDAwLCAweDAwLCAweDAwIH0sCj4gKwo+ICsJLyogQ19QSU5fVEFCTEUgb2JqZWN0IElE
J3MgKi8KPiArCj4gKwkvKiBDX1BJTl9NU0lEICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4
MEIsIDB4MDAsIDB4MDAsIDB4ODQsIDB4MDJ9LAo+ICsJLyogQ19QSU5fU0lEICovCj4gKwl7IDB4
MDAsIDB4MDAsIDB4MDAsIDB4MEIsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDF9LAo+ICsJIC8qIENf
UElOX0FETUlOMSAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDBCLCAweDAwLCAweDAxLCAw
eDAwLCAweDAxfSwKPiArCj4gKwkvKiBoYWxmIFVJRCdzIChvbmx5IGZpcnN0IDQgYnl0ZXMgdXNl
ZCkgKi8KPiArCj4gKwkvKiBIYWxmLVVJRCDigJMgQXV0aG9yaXR5X29iamVjdF9yZWYgKi8KPiAr
CXsgMHgwMCwgMHgwMCwgMHgwQywgMHgwNSwgMHhmZiwgMHhmZiwgMHhmZiwgMHhmZiB9LAo+ICsJ
LyogSGFsZi1VSUQg4oCTIEJvb2xlYW4gQUNFICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDQsIDB4
MEUsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYgfSwKPiArCj4gKwkvKiBzcGVjaWFsIHZhbHVlIGZv
ciBvbWl0dGVkIG9wdGlvbmFsIHBhcmFtZXRlciAqLwo+ICsKPiArCS8qIEhFWEZGIGZvciBvbWl0
dGVkICovCj4gKwl7IDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4ZmYsIDB4
ZmZ9LAo+ICt9Owo+ICtzdGF0aWMgY29uc3Qgc2l6ZV90IE9QQUxfVUlEX0xFTkdUSCA9IDg7Cj4g
K3N0YXRpYyBjb25zdCBzaXplX3QgT1BBTF9NU0lEX0tFWUxFTiA9IDE1Owo+ICtzdGF0aWMgY29u
c3Qgc2l6ZV90IE9QQUxfVUlEX0xFTkdUSF9IQUxGID0gNDsKPiArCj4gKwo+ICsvKiBFbnVtIHRv
IGluZGV4IE9QQUxVSUQgYXJyYXkgKi8KPiArZW51bSBPUEFMX1VJRCB7Cj4gKwkvKiB1c2VycyAq
Lwo+ICsJT1BBTF9TTVVJRF9VSUQsCj4gKwlPUEFMX1RISVNTUF9VSUQsCj4gKwlPUEFMX0FETUlO
U1BfVUlELAo+ICsJT1BBTF9MT0NLSU5HU1BfVUlELAo+ICsJT1BBTF9FTlRFUlBSSVNFX0xPQ0tJ
TkdTUF9VSUQsCj4gKwlPUEFMX0FOWUJPRFlfVUlELAo+ICsJT1BBTF9TSURfVUlELAo+ICsJT1BB
TF9BRE1JTjFfVUlELAo+ICsJT1BBTF9VU0VSMV9VSUQsCj4gKwlPUEFMX1VTRVIyX1VJRCwKPiAr
CU9QQUxfUFNJRF9VSUQsCj4gKwlPUEFMX0VOVEVSUFJJU0VfQkFORE1BU1RFUjBfVUlELAo+ICsJ
T1BBTF9FTlRFUlBSSVNFX0VSQVNFTUFTVEVSX1VJRCwKPiArCS8qIHRhYmxlcyAqLwo+ICsJT1BB
TF9MT0NLSU5HUkFOR0VfR0xPQkFMLAo+ICsJT1BBTF9MT0NLSU5HUkFOR0VfQUNFX1JETE9DS0VE
LAo+ICsJT1BBTF9MT0NLSU5HUkFOR0VfQUNFX1dSTE9DS0VELAo+ICsJT1BBTF9NQlJDT05UUk9M
LAo+ICsJT1BBTF9NQlIsCj4gKwlPUEFMX0FVVEhPUklUWV9UQUJMRSwKPiArCU9QQUxfQ19QSU5f
VEFCTEUsCj4gKwlPUEFMX0xPQ0tJTkdfSU5GT19UQUJMRSwKPiArCU9QQUxfRU5URVJQUklTRV9M
T0NLSU5HX0lORk9fVEFCTEUsCj4gKwkvKiBDX1BJTl9UQUJMRSBvYmplY3QgSUQncyAqLwo+ICsJ
T1BBTF9DX1BJTl9NU0lELAo+ICsJT1BBTF9DX1BJTl9TSUQsCj4gKwlPUEFMX0NfUElOX0FETUlO
MSwKPiArCS8qIGhhbGYgVUlEJ3MgKG9ubHkgZmlyc3QgNCBieXRlcyB1c2VkKSAqLwo+ICsJT1BB
TF9IQUxGX1VJRF9BVVRIT1JJVFlfT0JKX1JFRiwKPiArCU9QQUxfSEFMRl9VSURfQk9PTEVBTl9B
Q0UsCj4gKwkvKiBvbWl0dGVkIG9wdGlvbmFsIHBhcmFtZXRlciAqLwo+ICsJT1BBTF9VSURfSEVY
RkYsCj4gK307Cj4gKwo+ICsvKgo+ICsgKiBUQ0cgU3RvcmFnZSBTU0MgTWV0aG9kcy4KPiArICov
Cj4gK3N0YXRpYyBjb25zdCB1OCBPUEFMTUVUSE9EW11bOF0gPSB7Cj4gKwkvKiBQcm9wZXJ0aWVz
ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4ZmYsIDB4MDEg
fSwKPiArCS8qIFNUQVJUU0VTU0lPTiAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDAwLCAw
eDAwLCAweDAwLCAweGZmLCAweDAyIH0sCj4gKwkvKiBSZXZlcnQgKi8KPiArCXsgMHgwMCwgMHgw
MCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMiwgMHgwMiB9LAo+ICsJLyogQWN0aXZhdGUg
Ki8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMiwgMHgwMyB9
LAo+ICsJLyogRW50ZXJwcmlzZSBHZXQgKi8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwg
MHgwMCwgMHgwMCwgMHgwMCwgMHgwNiB9LAo+ICsJLyogRW50ZXJwcmlzZSBTZXQgKi8KPiArCXsg
MHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNyB9LAo+ICsJLyog
TkVYVCAqLwo+ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAw
eDA4IH0sCj4gKwkvKiBFbnRlcnByaXNlIEF1dGhlbnRpY2F0ZSAqLwo+ICsJeyAweDAwLCAweDAw
LCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDBjIH0sCj4gKwkvKiBHZXRBQ0wgKi8K
PiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwZCB9LAo+
ICsJLyogR2VuS2V5ICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAs
IDB4MDAsIDB4MTAgfSwKPiArCS8qIHJldmVydFNQICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAs
IDB4MDYsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MTEgfSwKPiArCS8qIEdldCAqLwo+ICsJeyAweDAw
LCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDE2IH0sCj4gKwkvKiBTZXQg
Ki8KPiArCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgxNyB9
LAo+ICsJLyogQXV0aGVudGljYXRlICovCj4gKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4
MDAsIDB4MDAsIDB4MDAsIDB4MWMgfSwKPiArCS8qIFJhbmRvbSAqLwo+ICsJeyAweDAwLCAweDAw
LCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDA2LCAweDAxIH0sCj4gKwkvKiBFcmFzZSAqLwo+
ICsJeyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDA4LCAweDAzIH0sCj4g
K307Cj4gK3N0YXRpYyBjb25zdCBzaXplX3QgT1BBTF9NRVRIT0RfTEVOR1RIID0gODsKPiArCj4g
Ky8qIEVudW0gZm9yIGluZGV4aW5nIHRoZSBPUEFMTUVUSE9EIGFycmF5ICovCj4gK2VudW0gT1BB
TF9NRVRIT0Qgewo+ICsJT1BBTF9QUk9QRVJUSUVTLAo+ICsJT1BBTF9TVEFSVFNFU1NJT04sCj4g
KwlPUEFMX1JFVkVSVCwKPiArCU9QQUxfQUNUSVZBVEUsCj4gKwlPUEFMX0VHRVQsCj4gKwlPUEFM
X0VTRVQsCj4gKwlPUEFMX05FWFQsCj4gKwlPUEFMX0VBVVRIRU5USUNBVEUsCj4gKwlPUEFMX0dF
VEFDTCwKPiArCU9QQUxfR0VOS0VZLAo+ICsJT1BBTF9SRVZFUlRTUCwKPiArCU9QQUxfR0VULAo+
ICsJT1BBTF9TRVQsCj4gKwlPUEFMX0FVVEhFTlRJQ0FURSwKPiArCU9QQUxfUkFORE9NLAo+ICsJ
T1BBTF9FUkFTRSwKPiArfTsKPiArCj4gK2VudW0gT1BBTF9SRVNQT05TRV9UT0tFTiB7Cj4gKwlP
UEFMX0RUQV9UT0tFTklEX0JZVEVTVFJJTkcgPSAweGUwLAo+ICsJT1BBTF9EVEFfVE9LRU5JRF9T
SU5UID0gMHhlMSwKPiArCU9QQUxfRFRBX1RPS0VOSURfVUlOVCA9IDB4ZTIsCj4gKwlPUEFMX0RU
QV9UT0tFTklEX1RPS0VOID0gMHhlMywgLyogYWN0dWFsIHRva2VuIGlzIHJldHVybmVkICovCj4g
KwlPUEFMX0RUQV9UT0tFTklEX0lOVkFMSUQgPSAwWDAKPiArfTsKPiArCj4gK2VudW0gT1BBTF9U
T0tFTiB7Cj4gKwkvKiBCb29sZWFuICovCj4gKwlPUEFMX1RSVUUgPSAweDAxLAo+ICsJT1BBTF9G
QUxTRSA9IDB4MDAsCj4gKwlPUEFMX0JPT0xFQU5fRVhQUiA9IDB4MDMsCj4gKwkvKiBjZWxsYmxv
Y2tzICovCj4gKwlPUEFMX1RBQkxFID0gMHgwMCwKPiArCU9QQUxfU1RBUlRST1cgPSAweDAxLAo+
ICsJT1BBTF9FTkRST1cgPSAweDAyLAo+ICsJT1BBTF9TVEFSVENPTFVNTiA9IDB4MDMsCj4gKwlP
UEFMX0VORENPTFVNTiA9IDB4MDQsCj4gKwlPUEFMX1ZBTFVFUyA9IDB4MDEsCj4gKwkvKiBhdXRo
b3JpdHkgdGFibGUgKi8KPiArCU9QQUxfUElOID0gMHgwMywKPiArCS8qIGxvY2tpbmcgdG9rZW5z
ICovCj4gKwlPUEFMX1JBTkdFU1RBUlQgPSAweDAzLAo+ICsJT1BBTF9SQU5HRUxFTkdUSCA9IDB4
MDQsCj4gKwlPUEFMX1JFQURMT0NLRU5BQkxFRCA9IDB4MDUsCj4gKwlPUEFMX1dSSVRFTE9DS0VO
QUJMRUQgPSAweDA2LAo+ICsJT1BBTF9SRUFETE9DS0VEID0gMHgwNywKPiArCU9QQUxfV1JJVEVM
T0NLRUQgPSAweDA4LAo+ICsJT1BBTF9BQ1RJVkVLRVkgPSAweDBBLAo+ICsJLyogbG9ja2luZyBp
bmZvIHRhYmxlICovCj4gKwlPUEFMX01BWFJBTkdFUyA9IDB4MDQsCj4gKwkgLyogbWJyIGNvbnRy
b2wgKi8KPiArCU9QQUxfTUJSRU5BQkxFID0gMHgwMSwKPiArCU9QQUxfTUJSRE9ORSA9IDB4MDIs
Cj4gKwkvKiBwcm9wZXJ0aWVzICovCj4gKwlPUEFMX0hPU1RQUk9QRVJUSUVTID0gMHgwMCwKPiAr
CS8qIGF0b21zICovCj4gKwlPUEFMX1NUQVJUTElTVCA9IDB4ZjAsCj4gKwlPUEFMX0VORExJU1Qg
PSAweGYxLAo+ICsJT1BBTF9TVEFSVE5BTUUgPSAweGYyLAo+ICsJT1BBTF9FTkROQU1FID0gMHhm
MywKPiArCU9QQUxfQ0FMTCA9IDB4ZjgsCj4gKwlPUEFMX0VORE9GREFUQSA9IDB4ZjksCj4gKwlP
UEFMX0VORE9GU0VTU0lPTiA9IDB4ZmEsCj4gKwlPUEFMX1NUQVJUVFJBTlNBQ1RPTiA9IDB4ZmIs
Cj4gKwlPUEFMX0VORFRSQU5TQUNUT04gPSAweGZDLAo+ICsJT1BBTF9FTVBUWUFUT00gPSAweGZm
LAo+ICsJT1BBTF9XSEVSRSA9IDB4MDAsCj4gK307Cj4gKwo+ICsvKiBVc2VmdWwgdGlueSBhdG9t
cy4KPiArICogVXNlZnVsIGZvciB0YWJsZSBjb2x1bW5zIGV0Ywo+ICsgKi8KPiArZW51bSBPUEFM
X1RJTllfQVRPTSB7Cj4gKwlPUEFMX1RJTllfVUlOVF8wMCA9IDB4MDAsCj4gKwlPUEFMX1RJTllf
VUlOVF8wMSA9IDB4MDEsCj4gKwlPUEFMX1RJTllfVUlOVF8wMiA9IDB4MDIsCj4gKwlPUEFMX1RJ
TllfVUlOVF8wMyA9IDB4MDMsCj4gKwlPUEFMX1RJTllfVUlOVF8wNCA9IDB4MDQsCj4gKwlPUEFM
X1RJTllfVUlOVF8wNSA9IDB4MDUsCj4gKwlPUEFMX1RJTllfVUlOVF8wNiA9IDB4MDYsCj4gKwlP
UEFMX1RJTllfVUlOVF8wNyA9IDB4MDcsCj4gKwlPUEFMX1RJTllfVUlOVF8wOCA9IDB4MDgsCj4g
KwlPUEFMX1RJTllfVUlOVF8wOSA9IDB4MDksCj4gKwlPUEFMX1RJTllfVUlOVF8xMCA9IDB4MGEs
Cj4gKwlPUEFMX1RJTllfVUlOVF8xMSA9IDB4MGIsCj4gKwlPUEFMX1RJTllfVUlOVF8xMiA9IDB4
MGMsCj4gKwlPUEFMX1RJTllfVUlOVF8xMyA9IDB4MGQsCj4gKwlPUEFMX1RJTllfVUlOVF8xNCA9
IDB4MGUsCj4gKwlPUEFMX1RJTllfVUlOVF8xNSA9IDB4MGYsCj4gK307Cj4gKwo+ICtlbnVtIE9Q
QUxfQVRPTV9XSURUSCB7Cj4gKwlPUEFMX1dJRFRIX1RJTlksCj4gKwlPUEFMX1dJRFRIX1NIT1JU
LAo+ICsJT1BBTF9XSURUSF9NRURJVU0sCj4gKwlPUEFMX1dJRFRIX0xPTkcsCj4gKwlPUEFMX1dJ
RFRIX1RPS0VOCj4gK307Cj4gKwo+ICsvKiBMb2NraW5nIHN0YXRlIGZvciBhIGxvY2tpbmcgcmFu
Z2UgKi8KPiArZW51bSBPUEFMX0xPQ0tJTkdTVEFURSB7Cj4gKwlPUEFMX0xPQ0tJTkdfUkVBRFdS
SVRFID0gMHgwMSwKPiArCU9QQUxfTE9DS0lOR19SRUFET05MWSA9IDB4MDIsCj4gKwlPUEFMX0xP
Q0tJTkdfTE9DS0VEID0gMHgwMywKPiArfTsKPiArCj4gKy8qCj4gKyAqIFN0cnVjdHVyZXMgdG8g
YnVpbGQgYW5kIGRlY29kZSB0aGUgT3BhbCBTU0MgbWVzc2FnZXMKPiArICogZmllbGRzIHRoYXQg
YXJlIE5PVCByZWFsbHkgbnVtZXJpYyBhcmUgZGVmaW5lZCBhcyB1OFtdIHRvCj4gKyAqIGhlbHAg
cmVkdWNlIHRoZSBlbmRpYW5uZXNzIGlzc3Vlcwo+ICsgKi8KPiArCj4gKy8qIENvbW0gUGFja2V0
IChoZWFkZXIpIGZvciB0cmFuc21pc3Npb25zLiAqLwo+ICtzdHJ1Y3Qgb3BhbF9jb21wYWNrZXQg
ewo+ICsJdTMyIHJlc2VydmVkMDsKPiArCXU4IGV4dGVuZGVkQ29tSURbNF07Cj4gKwl1MzIgb3V0
c3RhbmRpbmdEYXRhOwo+ICsJdTMyIG1pblRyYW5zZmVyOwo+ICsJdTMyIGxlbmd0aDsKPiArfTsK
PiArCj4gKy8qIFBhY2tldCBzdHJ1Y3R1cmUuICovCj4gK3N0cnVjdCBvcGFsX3BhY2tldCB7Cj4g
Kwl1MzIgVFNOOwo+ICsJdTMyIEhTTjsKPiArCXUzMiBzZXFfbnVtYmVyOwo+ICsJdTE2IHJlc2Vy
dmVkMDsKPiArCXUxNiBhY2tfdHlwZTsKPiArCXUzMiBhY2tub3dsZWRnbWVudDsKPiArCXUzMiBs
ZW5ndGg7Cj4gK307Cj4gKwo+ICsvKiBEYXRhIHN1YiBwYWNrZXQgaGVhZGVyICovCj4gK3N0cnVj
dCBvcGFsX2RhdGFfc3VicGFja2V0IHsKPiArCXU4IHJlc2VydmVkMFs2XTsKPiArCXUxNiBraW5k
Owo+ICsJdTMyIGxlbmd0aDsKPiArfTsKPiArCj4gKy8qIGhlYWRlciBvZiBhIHJlc3BvbnNlICov
Cj4gK3N0cnVjdCBvcGFsX2hlYWRlciB7Cj4gKwlzdHJ1Y3Qgb3BhbF9jb21wYWNrZXQgY3A7Cj4g
KwlzdHJ1Y3Qgb3BhbF9wYWNrZXQgcGt0Owo+ICsJc3RydWN0IG9wYWxfZGF0YV9zdWJwYWNrZXQg
c3VicGt0Owo+ICt9Owo+ICsKPiArI2RlZmluZSBGQ19UUEVSICAgICAgIDB4MDAwMQo+ICsjZGVm
aW5lIEZDX0xPQ0tJTkcgICAgMHgwMDAyCj4gKyNkZWZpbmUgRkNfR0VPTUVUUlkgICAweDAwMDMK
PiArI2RlZmluZSBGQ19FTlRFUlBSSVNFIDB4MDEwMAo+ICsjZGVmaW5lIEZDX0RBVEFTVE9SRSAg
MHgwMjAyCj4gKyNkZWZpbmUgRkNfU0lOR0xFVVNFUiAweDAyMDEKPiArI2RlZmluZSBGQ19PUEFM
VjEwMCAgIDB4MDIwMAo+ICsjZGVmaW5lIEZDX09QQUxWMjAwICAgMHgwMjAzCj4gKwo+ICsvKgo+
ICsgKiBUaGUgRGlzY292ZXJ5IDAgSGVhZGVyLiBBcyBkZWZpbmVkIGluCj4gKyAqIE9wYWwgU1ND
IERvY3VtZW50YXRpb24KPiArICovCj4gK3N0cnVjdCBkMF9oZWFkZXIgewo+ICsJdTMyIGxlbmd0
aDsgLyogdGhlIGxlbmd0aCBvZiB0aGUgaGVhZGVyIDQ4IGluIDIuMDAuMTAwICovCj4gKwl1MzIg
cmV2aXNpb247IC8qKjwgcmV2aXNpb24gb2YgdGhlIGhlYWRlciAxIGluIDIuMDAuMTAwICovCj4g
Kwl1MzIgcmVzZXJ2ZWQwMTsKPiArCXUzMiByZXNlcnZlZDAyOwo+ICsJLyoKPiArCSAqIHRoZSBy
ZW1haW5kZXIgb2YgdGhlIHN0cnVjdHVyZSBpcyB2ZW5kb3Igc3BlY2lmaWMgYW5kIHdpbGwgbm90
IGJlCj4gKwkgKiBhZGRyZXNzZWQgbm93Cj4gKwkgKi8KPiArCXU4IGlnbm9yZWRbMzJdOwo+ICt9
Owo+ICsKPiArLyoKPiArICogVFBlciBGZWF0dXJlIERlc2NyaXB0b3IuIENvbnRhaW5zIGZsYWdz
IGluZGljYXRpbmcgc3VwcG9ydCBmb3IgdGhlCj4gKyAqIFRQZXIgZmVhdHVyZXMgZGVzY3JpYmVk
IGluIHRoZSBPUEFMIHNwZWNpZmljYXRpb24uIFRoZSBuYW1lcyBtYXRjaCB0aGUKPiArICogT1BB
TCB0ZXJtaW5vbG9neQo+ICsgKgo+ICsgKiBjb2RlID09IDB4MDAxIGluIDIuMDAuMTAwCj4gKyAq
Lwo+ICtzdHJ1Y3QgZDBfdHBlcl9mZWF0dXJlcyB7Cj4gKwkvKgo+ICsJICogc3VwcG9ydGVkX2Zl
YXR1cmVzIGJpdHM6Cj4gKwkgKiBiaXQgNzogcmVzZXJ2ZWQKPiArCSAqIGJpdCA2OiBjb20gSUQg
bWFuYWdlbWVudAo+ICsJICogYml0IDU6IHJlc2VydmVkCj4gKwkgKiBiaXQgNDogc3RyZWFtaW5n
IHN1cHBvcnQKPiArCSAqIGJpdCAzOiBidWZmZXIgbWFuYWdlbWVudAo+ICsJICogYml0IDI6IEFD
Sy9OQUNLCj4gKwkgKiBiaXQgMTogYXN5bmMKPiArCSAqIGJpdCAwOiBzeW5jCj4gKwkgKi8KPiAr
CXU4IHN1cHBvcnRlZF9mZWF0dXJlczsKPiArCS8qCj4gKwkgKiBieXRlcyA1IHRocm91Z2ggMTUg
YXJlIHJlc2VydmVkLCBidXQgd2UgcmVwcmVzZW50IHRoZSBmaXJzdCAzIGFzCj4gKwkgKiB1OCB0
byBrZWVwIHRoZSBvdGhlciB0d28gMzJiaXRzIGludGVnZXJzIGFsaWduZWQuCj4gKwkgKi8KPiAr
CXU4IHJlc2VydmVkMDFbM107Cj4gKwl1MzIgcmVzZXJ2ZWQwMjsKPiArCXUzMiByZXNlcnZlZDAz
Owo+ICt9Owo+ICsKPiArLyoKPiArICogTG9ja2luZyBGZWF0dXJlIERlc2NyaXB0b3IuIENvbnRh
aW5zIGZsYWdzIGluZGljYXRpbmcgc3VwcG9ydCBmb3IgdGhlCj4gKyAqIGxvY2tpbmcgZmVhdHVy
ZXMgZGVzY3JpYmVkIGluIHRoZSBPUEFMIHNwZWNpZmljYXRpb24uIFRoZSBuYW1lcyBtYXRjaCB0
aGUKPiArICogT1BBTCB0ZXJtaW5vbG9neQo+ICsgKgo+ICsgKiBjb2RlID09IDB4MDAwMiBpbiAy
LjAwLjEwMAo+ICsgKi8KPiArc3RydWN0IGQwX2xvY2tpbmdfZmVhdHVyZXMgewo+ICsJLyoKPiAr
CSAqIHN1cHBvcnRlZF9mZWF0dXJlcyBiaXRzOgo+ICsJICogYml0cyA2LTc6IHJlc2VydmVkCj4g
KwkgKiBiaXQgNTogTUJSIGRvbmUKPiArCSAqIGJpdCA0OiBNQlIgZW5hYmxlZAo+ICsJICogYml0
IDM6IG1lZGlhIGVuY3J5cHRpb24KPiArCSAqIGJpdCAyOiBsb2NrZWQKPiArCSAqIGJpdCAxOiBs
b2NraW5nIGVuYWJsZWQKPiArCSAqIGJpdCAwOiBsb2NraW5nIHN1cHBvcnRlZAo+ICsJICovCj4g
Kwl1OCBzdXBwb3J0ZWRfZmVhdHVyZXM7Cj4gKwkvKgo+ICsJICogYnl0ZXMgNSB0aHJvdWdoIDE1
IGFyZSByZXNlcnZlZCwgYnV0IHdlIHJlcHJlc2VudCB0aGUgZmlyc3QgMyBhcwo+ICsJICogdTgg
dG8ga2VlcCB0aGUgb3RoZXIgdHdvIDMyYml0cyBpbnRlZ2VycyBhbGlnbmVkLgo+ICsJICovCj4g
Kwl1OCByZXNlcnZlZDAxWzNdOwo+ICsJdTMyIHJlc2VydmVkMDI7Cj4gKwl1MzIgcmVzZXJ2ZWQw
MzsKPiArfTsKPiArCj4gKy8qCj4gKyAqIEdlb21ldHJ5IEZlYXR1cmUgRGVzY3JpcHRvci4gQ29u
dGFpbnMgZmxhZ3MgaW5kaWNhdGluZyBzdXBwb3J0IGZvciB0aGUKPiArICogZ2VvbWV0cnkgZmVh
dHVyZXMgZGVzY3JpYmVkIGluIHRoZSBPUEFMIHNwZWNpZmljYXRpb24uIFRoZSBuYW1lcyBtYXRj
aCB0aGUKPiArICogT1BBTCB0ZXJtaW5vbG9neQo+ICsgKgo+ICsgKiBjb2RlID09IDB4MDAwMyBp
biAyLjAwLjEwMAo+ICsgKi8KPiArc3RydWN0IGQwX2dlb21ldHJ5X2ZlYXR1cmVzIHsKPiArCS8q
Cj4gKwkgKiBza2lwIDMyIGJpdHMgZnJvbSBoZWFkZXIsIG5lZWRlZCB0byBhbGlnbiB0aGUgc3Ry
dWN0IHRvIDY0IGJpdHMuCj4gKwkgKi8KPiArCXU4IGhlYWRlcls0XTsKPiArCS8qCj4gKwkgKiBy
ZXNlcnZlZDAxOgo+ICsJICogYml0cyAxLTY6IHJlc2VydmVkCj4gKwkgKiBiaXQgMDogYWxpZ24K
PiArCSAqLwo+ICsJdTggcmVzZXJ2ZWQwMTsKPiArCXU4IHJlc2VydmVkMDJbN107Cj4gKwl1MzIg
bG9naWNhbF9ibG9ja19zaXplOwo+ICsJdTY0IGFsaWdubWVudF9ncmFudWxhcml0eTsKPiArCXU2
NCBsb3dlc3RfYWxpZ25lZF9sYmE7Cj4gK307Cj4gKwo+ICsvKgo+ICsgKiBFbnRlcnByaXNlIFNT
QyBGZWF0dXJlCj4gKyAqCj4gKyAqIGNvZGUgPT0gMHgwMTAwCj4gKyAqLwo+ICtzdHJ1Y3QgZDBf
ZW50ZXJwcmlzZV9zc2Mgewo+ICsJdTE2IGJhc2VDb21JRDsKPiArCXUxNiBudW1Db21JRHM7Cj4g
KwkvKiByYW5nZV9jcm9zc2luZzoKPiArCSAqIGJpdHMgMS02OiByZXNlcnZlZAo+ICsJICogYml0
IDA6IHJhbmdlIGNyb3NzaW5nCj4gKwkgKi8KPiArCXU4IHJhbmdlX2Nyb3NzaW5nOwo+ICsJdTgg
cmVzZXJ2ZWQwMTsKPiArCXUxNiByZXNlcnZlZDAyOwo+ICsJdTMyIHJlc2VydmVkMDM7Cj4gKwl1
MzIgcmVzZXJ2ZWQwNDsKPiArfTsKPiArCj4gKy8qCj4gKyAqIE9wYWwgVjEgZmVhdHVyZQo+ICsg
Kgo+ICsgKiBjb2RlID09IDB4MDIwMAo+ICsgKi8KPiArc3RydWN0IGQwX29wYWxfdjEwMCB7Cj4g
Kwl1MTYgYmFzZUNvbUlEOwo+ICsJdTE2IG51bUNvbUlEczsKPiArfTsKPiArCj4gKy8qCj4gKyAq
IFNpbmdsZSBVc2VyIE1vZGUgZmVhdHVyZQo+ICsgKgo+ICsgKiBjb2RlID09IDB4MDIwMQo+ICsg
Ki8KPiArc3RydWN0IGQwX3NpbmdsZV91c2VyX21vZGUgewo+ICsJdTMyIG51bV9sb2NraW5nX29i
amVjdHM7Cj4gKwkvKiByZXNlcnZlZDAxOgo+ICsJICogYml0IDA6IGFueQo+ICsJICogYml0IDE6
IGFsbAo+ICsJICogYml0IDI6IHBvbGljeQo+ICsJICogYml0cyAzLTc6IHJlc2VydmVkCj4gKwkg
Ki8KPiArCXU4IHJlc2VydmVkMDE7Cj4gKwl1OCByZXNlcnZlZDAyOwo+ICsJdTE2IHJlc2VydmVk
MDM7Cj4gKwl1MzIgcmVzZXJ2ZWQwNDsKPiArfTsKPiArCj4gKy8qCj4gKyAqIEFkZGl0b25hbCBE
YXRhc3RvcmVzIGZlYXR1cmUKPiArICoKPiArICogY29kZSA9PSAweDAyMDIKPiArICovCj4gK3N0
cnVjdCBkMF9kYXRhc3RvcmVfdGFibGUgewo+ICsJdTE2IHJlc2VydmVkMDE7Cj4gKwl1MTYgbWF4
X3RhYmxlczsKPiArCXUzMiBtYXhfc2l6ZV90YWJsZXM7Cj4gKwl1MzIgdGFibGVfc2l6ZV9hbGln
bm1lbnQ7Cj4gK307Cj4gKwo+ICsvKgo+ICsgKiBPUEFMIDIuMCBmZWF0dXJlCj4gKyAqCj4gKyAq
IGNvZGUgPT0gMHgwMjAzCj4gKyAqLwo+ICtzdHJ1Y3QgZDBfb3BhbF92MjAwIHsKPiArCXUxNiBi
YXNlQ29tSUQ7Cj4gKwl1MTYgbnVtQ29tSURzOwo+ICsJLyogcmFuZ2VfY3Jvc3Npbmc6Cj4gKwkg
KiBiaXRzIDEtNjogcmVzZXJ2ZWQKPiArCSAqIGJpdCAwOiByYW5nZSBjcm9zc2luZwo+ICsJICov
Cj4gKwl1OCByYW5nZV9jcm9zc2luZzsKPiArCS8qIG51bV9sb2NraW5nX2FkbWluX2F1dGg6Cj4g
KwkgKiBub3QgYWxpZ25lZCB0byAxNiBiaXRzLCBzbyB1c2UgdHdvIHU4Lgo+ICsJICogc3RvcmVk
IGluIGJpZyBlbmRpYW46Cj4gKwkgKiAwOiBNU0IKPiArCSAqIDE6IExTQgo+ICsJICovCj4gKwl1
OCBudW1fbG9ja2luZ19hZG1pbl9hdXRoWzJdOwo+ICsJLyogbnVtX2xvY2tpbmdfdXNlcl9hdXRo
Ogo+ICsJICogbm90IGFsaWduZWQgdG8gMTYgYml0cywgc28gdXNlIHR3byB1OC4KPiArCSAqIHN0
b3JlZCBpbiBiaWcgZW5kaWFuOgo+ICsJICogMDogTVNCCj4gKwkgKiAxOiBMU0IKPiArCSAqLwo+
ICsJdTggbnVtX2xvY2tpbmdfdXNlcl9hdXRoWzJdOwo+ICsJdTggaW5pdGlhbFBJTjsKPiArCXU4
IHJldmVydGVkUElOOwo+ICsJdTggcmVzZXJ2ZWQwMTsKPiArCXUzMiByZXNlcnZlZDAyOwo+ICt9
Owo+ICsKPiArLyogVW5pb24gb2YgZmVhdHVyZXMgdXNlZCB0byBwYXJzZSB0aGUgZGlzY292ZXJ5
IDAgcmVzcG9uc2UgKi8KPiArc3RydWN0IGQwX2ZlYXR1cmVzIHsKPiArCXUxNiBjb2RlOwo+ICsJ
LyoKPiArCSAqIHJfdmVyc2lvbiBiaXRzOgo+ICsJICogYml0cyA0LTc6IHZlcnNpb24KPiArCSAq
IGJpdHMgMC0zOiByZXNlcnZlZAo+ICsJICovCj4gKwl1OCByX3ZlcnNpb247Cj4gKwl1OCBsZW5n
dGg7Cj4gKwl1OCBmZWF0dXJlc1tdOwo+ICt9Owo+ICsKPiArc3RydWN0IGtleSAqcmVxdWVzdF91
c2VyX2tleShjb25zdCBjaGFyICptYXN0ZXJfZGVzYywgY29uc3QgdTggKiptYXN0ZXJfa2V5LAo+
ICsJCQkgICAgIHNpemVfdCAqbWFzdGVyX2tleWxlbik7Cj4gKwo+ICsjZW5kaWYgLyogX05WTUVf
T1BBTF9JTlRFUk5BTF9IICovCj4gZGlmZiAtLWdpdCBhL2xpYi9zZWQtb3BhbF9rZXkuYyBiL2xp
Yi9zZWQtb3BhbF9rZXkuYwo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMC4u
MGI0ZGUwMQo+IC0tLSAvZGV2L251bGwKPiArKysgYi9saWIvc2VkLW9wYWxfa2V5LmMKPiBAQCAt
MCwwICsxLDQ2IEBACj4gKy8qCj4gKyAqIENvcHlyaWdodCDCqSAyMDE2IEludGVsIENvcnBvcmF0
aW9uCj4gKyAqCj4gKyAqIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hh
cmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhCj4gKyAqIGNvcHkgb2YgdGhpcyBzb2Z0d2Fy
ZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksCj4g
KyAqIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGlu
ZyB3aXRob3V0IGxpbWl0YXRpb24KPiArICogdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlm
eSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsCj4gKyAqIGFuZC9vciBz
ZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9t
IHRoZQo+ICsgKiBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhl
IGZvbGxvd2luZyBjb25kaXRpb25zOgo+ICsgKgo+ICsgKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5v
dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSAoaW5jbHVkaW5nIHRoZSBuZXh0Cj4gKyAq
IHBhcmFncmFwaCkgc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlh
bCBwb3J0aW9ucyBvZiB0aGUKPiArICogU29mdHdhcmUuCj4gKyAqCj4gKyAqIFRIRSBTT0ZUV0FS
RSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBS
RVNTIE9SCj4gKyAqIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdB
UlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLAo+ICsgKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VM
QVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiAgSU4gTk8gRVZFTlQgU0hBTEwKPiArICog
VEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0s
IERBTUFHRVMgT1IgT1RIRVIKPiArICogTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBP
RiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcKPiArICogRlJPTSwgT1VUIE9G
IE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBE
RUFMSU5HUwo+ICsgKiBJTiBUSEUgU09GVFdBUkUuCj4gKyAqCj4gKyAqIEF1dGhvcjoKPiArICog
ICAgUmFmYWVsIEFudG9nbm9sbGkgPHJhZmFlbC5hbnRvZ25vbGxpQGludGVsLmNvbT4KPiArICov
Cj4gKwo+ICsjaW5jbHVkZSA8bGludXgva2V5Lmg+Cj4gKyNpbmNsdWRlICJzZWQtb3BhbF9pbnRl
cm5hbC5oIgo+ICsKPiArc3RydWN0IGtleSAqcmVxdWVzdF91c2VyX2tleShjb25zdCBjaGFyICpt
YXN0ZXJfZGVzYywgY29uc3QgdTggKiptYXN0ZXJfa2V5LAo+ICsJCQkgICAgIHNpemVfdCAqbWFz
dGVyX2tleWxlbikKPiArewo+ICsJY29uc3Qgc3RydWN0IHVzZXJfa2V5X3BheWxvYWQgKnVwYXls
b2FkOwo+ICsJc3RydWN0IGtleSAqdWtleTsKPiArCj4gKwl1a2V5ID0gcmVxdWVzdF9rZXkoJmtl
eV90eXBlX3VzZXIsIG1hc3Rlcl9kZXNjLCBOVUxMKTsKPiArCWlmIChJU19FUlIodWtleSkpCj4g
KwkJZ290byBlcnJvcjsKPiArCj4gKwlkb3duX3JlYWQoJnVrZXktPnNlbSk7Cj4gKwl1cGF5bG9h
ZCA9IHVzZXJfa2V5X3BheWxvYWQodWtleSk7Cj4gKwkqbWFzdGVyX2tleSA9IHVwYXlsb2FkLT5k
YXRhOwo+ICsJKm1hc3Rlcl9rZXlsZW4gPSB1cGF5bG9hZC0+ZGF0YWxlbjsKPiArZXJyb3I6Cj4g
KwlyZXR1cm4gdWtleTsKPiArfQo+IGRpZmYgLS1naXQgYS9saWIvc2VkLmMgYi9saWIvc2VkLmMK
PiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAuLjA2Y2FjZDkKPiAtLS0gL2Rl
di9udWxsCj4gKysrIGIvbGliL3NlZC5jCj4gQEAgLTAsMCArMSwzMDMgQEAKPiArI2luY2x1ZGUg
PGxpbnV4L2Jsa2Rldi5oPgo+ICsjaW5jbHVkZSA8bGludXgvc2VkLmg+Cj4gKyNpbmNsdWRlIDxs
aW51eC9zZWQtb3BhbC5oPgo+ICsKPiArI2lmbmRlZiBDT05GSUdfU0VEX09QQUwKPiArc3RhdGlj
IGludCBzZWRfb3BhbF9zYXZlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRf
a2V5ICpzZWQpCj4gKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQo+ICtzdGF0aWMgaW50IHNlZF9v
cGFsX2xvY2tfdW5sb2NrKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5
ICprZXkpCj4gKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQo+ICtzdGF0aWMgaW50IHNlZF9vcGFs
X3Rha2Vfb3duZXJzaGlwKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5
ICprZXkpCj4gKwl7IHJldHVybiAtRU9QTk9UU1VQUDsgfQo+ICtzdGF0aWMgaW50IHNlZF9vcGFs
X2FjdGl2YXRlX2xzcChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAq
a2V5KQo+ICsJeyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KPiArc3RhdGljIGludCBzZWRfb3BhbF9z
ZXRfcHcoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiAr
CXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9Cj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfYWN0aXZhdGVf
dXNlcihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICsJ
eyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KPiArc3RhdGljIGludCBzZWRfb3BhbF9yZXZlcnR0cGVy
KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gKwl7IHJl
dHVybiAtRU9QTk9UU1VQUDsgfQo+ICtzdGF0aWMgaW50IHNlZF9vcGFsX3NldHVwX2xvY2tpbmdf
cmFuZ2Uoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiAr
CXsgcmV0dXJuIC1FT1BOT1RTVVBQOyB9Cj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfYWRkdXNlcl90
b19scihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICsJ
eyByZXR1cm4gLUVPUE5PVFNVUFA7IH0KPiArc3RhdGljIGludCBzZWRfb3BhbF9kb19tYnIoc3Ry
dWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArCXsgcmV0dXJu
IC1FT1BOT1RTVVBQOyB9Cj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfZXJhc2VfbHIoc3RydWN0IGJs
b2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArCXsgcmV0dXJuIC1FT1BO
T1RTVVBQOyB9Cj4gKwo+ICsjZWxzZQo+ICsKPiArc3RhdGljIGludCBzZWRfb3BhbF9zYXZlKHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gK3sKPiArCj4g
KwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwK
PiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5P
VFNVUFA7CllvdSBtaWdodCBjb25zaWRlciBwdWxsaW5nIHRoaXMgYm9pbGVycGxhdGUgb3V0IGlu
dG8gc29tZXRoaW5nIGxpa2U6CnN0YXRpYyBpbmxpbmUgYm9vbCBiZGV2X3NlY19jYXBhYmxlKHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYpCnsKCXJldHVybiBiZGV2ICYmIGJkZXYtPmJkX2Rpc2sg
JiYgYmRldi0+YmRfZGlzay0+Zm9wcyAmJgoJICAgICAgIGJkZXYtPmJkX2Rpc2stPmZvcHMtPnNl
Y19vcHM7Cn0KCgo+ICsKPiArCXJldHVybiBvcGFsX3NhdmUoYmRldiwga2V5KTsKPiArfQo+ICsK
PiArc3RhdGljIGludCBzZWRfb3BhbF9sb2NrX3VubG9jayhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpi
ZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2
LT5iZF9kaXNrIHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rp
c2stPmZvcHMtPnNlY19vcHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXJldHVy
biBvcGFsX2xvY2tfdW5sb2NrKGJkZXYsIGtleSk7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgc2Vk
X29wYWxfdGFrZV9vd25lcnNoaXAoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKPiArCQkJCSAg
IHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gK3sKPiArCj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJk
X2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+
Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJcmV0dXJuIG9w
YWxfdGFrZV9vd25lcnNoaXAoYmRldiwga2V5KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBzZWRf
b3BhbF9hY3RpdmF0ZV9sc3Aoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKPiArCQkJCSBzdHJ1
Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNr
IHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMt
PnNlY19vcHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXJldHVybiBvcGFsX2Fj
dGl2YXRlX2xzcChiZGV2LCBrZXkpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNlZF9vcGFsX3Nl
dF9wdyhzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LAo+ICsJCQkgICBzdHJ1Y3Qgc2VkX2tleSAq
a2V5KQo+ICt7Cj4gKwo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFiZGV2LT5i
ZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCj4g
KwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXJldHVybiBvcGFsX3NldF9uZXdfcHcoYmRl
diwga2V5KTsKPiArfQo+ICsKPiArc3RhdGljIGludCBzZWRfb3BhbF9hY3RpdmF0ZV91c2VyKHN0
cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCj4gKwkJCQkgIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4g
K3sKPiArCj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2st
PmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1
cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfYWN0aXZhdGVfdXNlcihiZGV2LCBr
ZXkpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNlZF9vcGFsX3JldmVydHRwZXIoc3RydWN0IGJs
b2NrX2RldmljZSAqYmRldiwKPiArCQkJICAgICAgIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gK3sK
PiArCj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZv
cHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4g
LUVPUE5PVFNVUFA7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfcmV2ZXJ0dHBlcihiZGV2LCBrZXkpOwo+
ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNlZF9vcGFsX3NldHVwX2xyKHN0cnVjdCBibG9ja19kZXZp
Y2UgKmJkZXYsCj4gKwkJCSAgICAgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsKPiArCWlm
ICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlzay0+Zm9wcyB8fAo+ICsJ
ICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+ICsJCXJldHVybiAtRU9QTk9UU1VQ
UDsKPiArCj4gKwlyZXR1cm4gb3BhbF9zZXR1cF9sb2NraW5nX3JhbmdlKGJkZXYsIGtleSk7Cj4g
K30KPiArCj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfYWRkdXNlcl90b19scihzdHJ1Y3QgYmxvY2tf
ZGV2aWNlICpiZGV2LAo+ICsJCQkgICAgIHN0cnVjdCBzZWRfa2V5ICprZXkpCj4gK3sKPiArCj4g
KwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwK
PiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5P
VFNVUFA7Cj4gKwo+ICsJcmV0dXJuIG9wYWxfYWRkX3VzZXJfdG9fbHIoYmRldiwga2V5KTsKPiAr
fQo+ICsKPiArc3RhdGljIGludCBzZWRfb3BhbF9kb19tYnIoc3RydWN0IGJsb2NrX2RldmljZSAq
YmRldiwKPiArCQkJICAgc3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsKPiArCWlmICghYmRl
diB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRfZGlzay0+Zm9wcyB8fAo+ICsJICAgICFi
ZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiAr
Cj4gKwlyZXR1cm4gb3BhbF9lbmFibGVfZGlzYWJsZV9zaGFkb3dfbWJyKGJkZXYsIGtleSk7Cj4g
K30KPiArCj4gK3N0YXRpYyBpbnQgc2VkX29wYWxfZXJhc2VfbHIoc3RydWN0IGJsb2NrX2Rldmlj
ZSAqYmRldiwKPiArCQkJICAgICBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwo+ICsJaWYg
KCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkg
ICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19vcHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQ
Owo+ICsKPiArCXJldHVybiBvcGFsX2VyYXNlX2xvY2tpbmdfcmFuZ2UoYmRldiwga2V5KTsKPiAr
fQo+ICsjZW5kaWYKPiArCj4gK2ludCBzZWRfc2F2ZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2
LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rp
c2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9w
cy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNoIChrZXkt
PnNlZF90eXBlKSB7Cj4gKwljYXNlIE9QQUxfTE9DS19VTkxPQ0s6Cj4gKwkJcmV0dXJuIHNlZF9v
cGFsX3NhdmUoYmRldiwga2V5KTsKPiArCX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4g
K30KPiArCj4gK2ludCBzZWRfbG9ja191bmxvY2soc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwg
c3RydWN0IHNlZF9rZXkgKmtleSkKPiArewo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNr
IHx8ICFiZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMt
PnNlY19vcHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXN3aXRjaCAoa2V5LT5z
ZWRfdHlwZSkgewo+ICsJY2FzZSBPUEFMX0xPQ0tfVU5MT0NLOgo+ICsJCXJldHVybiBzZWRfb3Bh
bF9sb2NrX3VubG9jayhiZGV2LCBrZXkpOwo+ICsJfQo+ICsKPiArCXJldHVybiAtRU9QTk9UU1VQ
UDsKPiArfQo+ICsKPiAraW50IHNlZF90YWtlX293bmVyc2hpcChzdHJ1Y3QgYmxvY2tfZGV2aWNl
ICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYt
PmJkX2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlz
ay0+Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNo
IChrZXktPnNlZF90eXBlKSB7Cj4gKwljYXNlIE9QQUw6Cj4gKwkJcmV0dXJuIHNlZF9vcGFsX3Rh
a2Vfb3duZXJzaGlwKGJkZXYsIGtleSk7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIC1FT1BOT1RTVVBQ
Owo+ICt9Cj4gKwo+ICtpbnQgc2VkX2FjdGl2YXRlX2xzcChzdHJ1Y3QgYmxvY2tfZGV2aWNlICpi
ZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJk
X2Rpc2sgfHwgIWJkZXYtPmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+
Zm9wcy0+c2VjX29wcykKPiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNoIChr
ZXktPnNlZF90eXBlKSB7Cj4gKwljYXNlIE9QQUw6Cj4gKwkJcmV0dXJuIHNlZF9vcGFsX2FjdGl2
YXRlX2xzcChiZGV2LCBrZXkpOwo+ICsJfQo+ICsKPiArCXJldHVybiAtRU9QTk9UU1VQUDsKPiAr
fQo+ICsKPiAraW50IHNlZF9zZXRfcHcoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0
IHNlZF9rZXkgKmtleSkKPiArewo+ICsJaWYgKCFiZGV2IHx8ICFiZGV2LT5iZF9kaXNrIHx8ICFi
ZGV2LT5iZF9kaXNrLT5mb3BzIHx8Cj4gKwkgICAgIWJkZXYtPmJkX2Rpc2stPmZvcHMtPnNlY19v
cHMpCj4gKwkJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICsKPiArCXN3aXRjaCAoa2V5LT5zZWRfdHlw
ZSkgewo+ICsJY2FzZSBPUEFMX1BXOgo+ICsJCXJldHVybiBzZWRfb3BhbF9zZXRfcHcoYmRldiwg
a2V5KTsKPiArCX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gK30KPiArCj4gK2ludCBz
ZWRfYWN0aXZhdGVfdXNlcihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tl
eSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYtPmJk
X2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykKPiAr
CQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7Cj4g
KwljYXNlIE9QQUxfQUNUX1VTUjoKPiArCQlyZXR1cm4gc2VkX29wYWxfYWN0aXZhdGVfdXNlcihi
ZGV2LCBrZXkpOwo+ICsJfQo+ICsKPiArCXJldHVybiAtRU9QTk9UU1VQUDsKPiArfQo+ICsKPiAr
aW50IHNlZF9yZXZlcnR0cGVyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRf
a2V5ICprZXkpCj4gK3sKPiArCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+
YmRfZGlzay0+Zm9wcyB8fAo+ICsJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+
ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCj4gKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsK
PiArCWNhc2UgT1BBTDoKPiArCQlyZXR1cm4gc2VkX29wYWxfcmV2ZXJ0dHBlcihiZGV2LCBrZXkp
Owo+ICsJfQo+ICsKPiArCXJldHVybiAtRU9QTk9UU1VQUDsKPiArfQo+ICsKPiAraW50IHNlZF9z
ZXR1cF9sb2NraW5nX3JhbmdlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRf
a2V5ICprZXkpCj4gK3sKPiArCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+
YmRfZGlzay0+Zm9wcyB8fAo+ICsJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+
ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCj4gKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsK
PiArCWNhc2UgT1BBTF9MUl9TRVRVUDoKPiArCQlyZXR1cm4gc2VkX29wYWxfc2V0dXBfbHIoYmRl
diwga2V5KTsKPiArCX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gK30KPiArCj4gK2lu
dCBzZWRfYWRkdXNlcl90b19scihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2Vk
X2tleSAqa2V5KQo+ICt7Cj4gKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJkX2Rpc2sgfHwgIWJkZXYt
PmJkX2Rpc2stPmZvcHMgfHwKPiArCSAgICAhYmRldi0+YmRfZGlzay0+Zm9wcy0+c2VjX29wcykK
PiArCQlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gKwo+ICsJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7
Cj4gKwljYXNlIE9QQUxfTE9DS19VTkxPQ0s6Cj4gKwkJcmV0dXJuIHNlZF9vcGFsX2FkZHVzZXJf
dG9fbHIoYmRldiwga2V5KTsKPiArCX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gK30K
PiArCj4gK2ludCBzZWRfZG9fbWJyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBz
ZWRfa2V5ICprZXkpCj4gK3sKPiArCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRl
di0+YmRfZGlzay0+Zm9wcyB8fAo+ICsJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3Bz
KQo+ICsJCXJldHVybiAtRU9QTk9UU1VQUDsKPiArCj4gKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUp
IHsKPiArCWNhc2UgT1BBTF9NQlJfREFUQToKPiArCQlyZXR1cm4gc2VkX29wYWxfZG9fbWJyKGJk
ZXYsIGtleSk7Cj4gKwl9Cj4gKwo+ICsJcmV0dXJuIC1FT1BOT1RTVVBQOwo+ICt9Cj4gKwo+ICtp
bnQgc2VkX2VyYXNlX2xyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5
ICprZXkpCj4gK3sKPiArCWlmICghYmRldiB8fCAhYmRldi0+YmRfZGlzayB8fCAhYmRldi0+YmRf
ZGlzay0+Zm9wcyB8fAo+ICsJICAgICFiZGV2LT5iZF9kaXNrLT5mb3BzLT5zZWNfb3BzKQo+ICsJ
CXJldHVybiAtRU9QTk9UU1VQUDsKPiArCj4gKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsKPiAr
CWNhc2UgT1BBTDoKPiArCQlyZXR1cm4gc2VkX29wYWxfZXJhc2VfbHIoYmRldiwga2V5KTsKPiAr
CX0KPiArCj4gKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cj4gK30KPiAtLSAKPiAyLjcuNAo+IAoKX19f
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KTGludXgtbnZtZSBt
YWlsaW5nIGxpc3QKTGludXgtbnZtZUBsaXN0cy5pbmZyYWRlYWQub3JnCmh0dHA6Ly9saXN0cy5p
bmZyYWRlYWQub3JnL21haWxtYW4vbGlzdGluZm8vbGludXgtbnZtZQo=

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

* [RFC PATCH 2/6] lib: Add Sed-opal library
@ 2016-11-01 18:56     ` Jon Derrick
  0 siblings, 0 replies; 32+ messages in thread
From: Jon Derrick @ 2016-11-01 18:56 UTC (permalink / raw)


Hi Rafael, Scott,


First off, congrats on the set! It looks good so far.

Just some small nits below since you have to respin it anyways :)

On Mon, Oct 31, 2016@03:58:15PM -0600, Scott Bauer wrote:
> 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          | 3337 +++++++++++++++++++++++++++++++++++++++++++++++
>  lib/sed-opal_internal.h |  586 +++++++++
>  lib/sed-opal_key.c      |   46 +
>  lib/sed.c               |  303 +++++
>  4 files changed, 4272 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..10b3348
> --- /dev/null
> +++ b/lib/sed-opal.c
> @@ -0,0 +1,3337 @@
> +/*
> + * 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;
> +	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 int __opal_send_cmd(struct opal_suspend_unlk *data, u16 comID,
> +			   void *buffer, size_t buflen, sec_cb *cb,
> +			   void *cb_data)
> +{
> +	return data->ops.send(data->data, comID, TCG_SECP_01, buffer, buflen,
> +			     cb, cb_data);
> +}
> +static int _opal_send_cmd(struct block_device *bdev, u16 comID,
> +			  void *buffer, size_t buflen,
> +			  sec_cb *cb, void *cb_data)
> +{
> +	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
> +
> +	return ops->send(bdev->bd_disk->private_data, comID,
> +			 TCG_SECP_01, buffer, buflen,
> +			 cb, cb_data);
> +}
> +
> +static int __opal_recv_cmd(struct opal_suspend_unlk *data, u16 comID,
> +			   void *buffer, size_t buflen, sec_cb *cb,
> +			   void *cb_data)
> +{
> +	return data->ops.recv(data->data, comID, TCG_SECP_01, buffer, buflen,
> +			     cb, cb_data);
> +}
> +
> +static int _opal_recv_cmd(struct block_device *bdev, u16 comID,
> +			  void *buffer, size_t buflen,
> +			  sec_cb *cb, void *cb_data)
> +{
> +	const struct sec_ops *ops = bdev->bd_disk->fops->sec_ops;
> +
> +	return ops->recv(bdev->bd_disk->private_data, comID,
> +			 TCG_SECP_01, buffer, buflen,
> +			 cb, cb_data);
> +}
> +
> +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);
> +	if (dev->resume_from_suspend)
> +		__opal_recv_cmd(dev->resume_data, dev->comID,
> +				buffer, buflen, opal_send_cb_cont, dev);
> +	else
> +		_opal_recv_cmd(dev->bdev, dev->comID, buffer, buflen,
> +			       opal_send_cb_cont, dev);
> +}
> +
> +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);
> +	if (dev->resume_from_suspend)
> +		__opal_recv_cmd(dev->resume_data, dev->comID,
> +				buffer, buflen, opal_send_cb_cont, dev);
> +	else
> +		_opal_recv_cmd(dev->bdev, dev->comID, buffer, buflen,
> +			       opal_send_cb_cont, dev);
> +}
> +
> +static int opal_send_recv(struct opal_dev *dev, sec_cb *cb, void *cb_data)
> +{
> +	size_t buflen = IO_BUFFER_LENGTH;
> +	void *buffer = dev->cmd.cmd;
> +	int ret;
> +
> +	dev->cmd.cb = cb;
> +	dev->cmd.cb_data = cb_data;
> +	if (dev->resume_from_suspend)
> +		ret = __opal_send_cmd(dev->resume_data, dev->comID, buffer,
> +				      buflen, opal_send_cb, dev);
> +	else
> +		ret = _opal_send_cmd(dev->bdev, dev->comID, buffer, buflen,
> +				     opal_send_cb, dev);
> +
> +	return ret;
> +}
> +
> +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;
> +		default:
> +			if (be16_to_cpu(body->code) > 0xbfff) {
> +				/* vendor specific, just ignore */
> +			} else {
> +				pr_warn("%s: OPAL Unknown feature: %d\n",
> +					dev->disk_name, be16_to_cpu(body->code));
> +			}
Small nit, how about:

case 0xbfff ... 0xffff:
	/* vendor specific, just ignore */
	break;
default:
	pr_warn(...



> +		}
> +		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)
> +{
> +	memset(dev->cmd.resp, 0, IO_BUFFER_LENGTH);
> +
> +	if (dev->resume_from_suspend)
> +		return __opal_recv_cmd(dev->resume_data, 0x0001,
> +				       dev->cmd.resp, IO_BUFFER_LENGTH,
> +				       opal_discovery0_end, dev);
> +
> +	return _opal_recv_cmd(dev->bdev, 0x0001, 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)
Should this be len > 8 or len >= 9 ?

> +			pr_warn("uint64 with more than 8 bytes\n");
> +		for (i = tok->len - 1; i > 0; i--) {
> +			u_integer |= ((u64)pos[i] << (8 * b));
> +			b++;
> +		}
It doesn't look particularly safe to keep using this driver on a drive
if it returns a len > 8. But the specs do allow 16-byte data in a short
atom, so maybe we should bail on allowing the driver to manage the
drive, or change the types to some 16-byte type?

> +		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);
> +
> +		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);
> +}

How about:

static void generic_cont(int error, void *data)
{
	struct opal_dev *dev = data;

	if (!error)
		error = parse_and_check_status(dev);

	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);
> +
> +	ret = opal_send_recv(dev, cont, dev);
> +	if (ret)
> +		pr_err("%s: Error running command: %d\n",
> +		       dev->disk_name, ret);
> +
> +	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 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];
> +
> +	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 = 0x41;
> +
> +	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 = 0x41;
> +
> +	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 = 0x41;
Can we #define this; it's used a few other places and is magicky

> +
> +	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 Dont/Not done command\n",
s/Dont/Done/ ?


> +		       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 Dont/Not done command\n",
s/Dont/Done/ ?


> +		       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)
> +{
> +	if (build_end_opal_session(dev) < 0)
> +		return -1;
> +	return finalize_and_send(dev, &dev->cmd, end_session_cont);
> +}
Any reason we cant:

int ret = build_...
if (ret < 0)
	return ret;


> +
> +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;
> +
> +	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;
> +
> +	if (use_new)
> +		return alloc_opal_dev(bdev, lr);
> +
> +	dev = get_registered_opal_dev(bdev, lr);
> +	if (!dev) {
> +		dev = alloc_opal_dev(bdev, lr);
> +		if (!dev)
> +			return NULL;
No need for this check when you already return dev


> +	}
> +	return dev;
> +}
Instead, how about:
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;
> +}
> +
> +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;
> +
> +	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
> +	};
> +	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)
Should this be > 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 };
> +	const opal_step _unlock_funcs_SUM[] = {
> +		opal_discovery0,
> +		start_auth_opal_session,
> +		lock_unlock_locking_range,
Did you mean to use lock_unlock_locking_range_SUM ?
Can we pull these two arrays out since they are required for both this
function and lock_unlock_internal ?


> +		end_opal_session,
> +		NULL
> +	};
> +	const opal_step _unlock_funcs[] = {
> +		opal_discovery0,
> +		start_auth_opal_session,
> +		lock_unlock_locking_range,
> +		end_opal_session,
> +		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 = _unlock_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..c9d3883
> --- /dev/null
> +++ b/lib/sed-opal_internal.h
> @@ -0,0 +1,586 @@
> +/*
> + * 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
> +
> +static const char *opal_errors[19] = {
Remove the 19 so it's just opal_errors[] (doesnt silently truncate any
new additions)


> +	"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 >= sizeof(opal_errors) || error < 0)
You want sizeof(opal_errors)/sizeof(*opal_errors) here, but you can just
use the ARRAY_SIZE macro instead


> +		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..06cacd9
> --- /dev/null
> +++ b/lib/sed.c
> @@ -0,0 +1,303 @@
> +#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 int sed_opal_save(struct block_device *bdev, struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
You might consider pulling this boilerplate out into something like:
static inline bool bdev_sec_capable(struct block_device *bdev)
{
	return bdev && bdev->bd_disk && bdev->bd_disk->fops &&
	       bdev->bd_disk->fops->sec_ops;
}


> +
> +	return opal_save(bdev, key);
> +}
> +
> +static int sed_opal_lock_unlock(struct block_device *bdev, struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_lock_unlock(bdev, key);
> +}
> +
> +static int sed_opal_take_ownership(struct block_device *bdev,
> +				   struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_take_ownership(bdev, key);
> +}
> +
> +static int sed_opal_activate_lsp(struct block_device *bdev,
> +				 struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_activate_lsp(bdev, key);
> +}
> +
> +static int sed_opal_set_pw(struct block_device *bdev,
> +			   struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_set_new_pw(bdev, key);
> +}
> +
> +static int sed_opal_activate_user(struct block_device *bdev,
> +				  struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_activate_user(bdev, key);
> +}
> +
> +static int sed_opal_reverttper(struct block_device *bdev,
> +			       struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_reverttper(bdev, key);
> +}
> +
> +static int sed_opal_setup_lr(struct block_device *bdev,
> +			     struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_setup_locking_range(bdev, key);
> +}
> +
> +static int sed_opal_adduser_to_lr(struct block_device *bdev,
> +			     struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_add_user_to_lr(bdev, key);
> +}
> +
> +static int sed_opal_do_mbr(struct block_device *bdev,
> +			   struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_enable_disable_shadow_mbr(bdev, key);
> +}
> +
> +static int sed_opal_erase_lr(struct block_device *bdev,
> +			     struct sed_key *key)
> +{
> +
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	return opal_erase_locking_range(bdev, key);
> +}
> +#endif
> +
> +int sed_save(struct block_device *bdev, struct sed_key *key)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	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)
> +{
> +	if (!bdev || !bdev->bd_disk || !bdev->bd_disk->fops ||
> +	    !bdev->bd_disk->fops->sec_ops)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->sed_type) {
> +	case OPAL:
> +		return sed_opal_erase_lr(bdev, key);
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> -- 
> 2.7.4
> 

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

* Re: [RFC PATCH 5/6] nvme: Add unlock_from_suspend
  2016-11-07 18:45       ` Keith Busch
@ 2016-11-07 18:33         ` Scott Bauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-11-07 18:33 UTC (permalink / raw)
  To: Keith Busch
  Cc: Sagi Grimberg, linux-nvme, Rafael.Antognolli, axboe,
	jonathan.derrick, j.naumann, hch, linux-block

On Mon, Nov 07, 2016 at 01:45:42PM -0500, Keith Busch wrote:
> On Tue, Nov 01, 2016 at 10:18:13AM +0200, Sagi Grimberg wrote:
> > > -	spin_lock_irq(&nvmeq->q_lock);
> > > +	spin_lock_irqsave(&nvmeq->q_lock, flags);
> > >  	if (unlikely(nvmeq->cq_vector < 0)) {
> > >  		if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
> > >  			ret = BLK_MQ_RQ_QUEUE_BUSY;
> > >  		else
> > >  			ret = BLK_MQ_RQ_QUEUE_ERROR;
> > > -		spin_unlock_irq(&nvmeq->q_lock);
> > > +		spin_unlock_irqrestore(&nvmeq->q_lock, flags);
> > >  		goto out;
> > >  	}
> > >  	__nvme_submit_cmd(nvmeq, &cmnd);
> > >  	nvme_process_cq(nvmeq);
> > > -	spin_unlock_irq(&nvmeq->q_lock);
> > > +	spin_unlock_irqrestore(&nvmeq->q_lock, flags);
> > 
> > No documentation why this is needed...
> 
> Let's forget documenting why it's needed; this solution should instead
> figure out a way to make it so it's not needed.

This is some code that was used for previous iterations while we were testing.
We missed this and some other things in this patch set when we were cleaning up.
It's gone from V2 as well as the other weirdness in the patch.


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

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
@ 2016-11-07 18:33         ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-11-07 18:33 UTC (permalink / raw)


On Mon, Nov 07, 2016@01:45:42PM -0500, Keith Busch wrote:
> On Tue, Nov 01, 2016@10:18:13AM +0200, Sagi Grimberg wrote:
> > > -	spin_lock_irq(&nvmeq->q_lock);
> > > +	spin_lock_irqsave(&nvmeq->q_lock, flags);
> > >  	if (unlikely(nvmeq->cq_vector < 0)) {
> > >  		if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
> > >  			ret = BLK_MQ_RQ_QUEUE_BUSY;
> > >  		else
> > >  			ret = BLK_MQ_RQ_QUEUE_ERROR;
> > > -		spin_unlock_irq(&nvmeq->q_lock);
> > > +		spin_unlock_irqrestore(&nvmeq->q_lock, flags);
> > >  		goto out;
> > >  	}
> > >  	__nvme_submit_cmd(nvmeq, &cmnd);
> > >  	nvme_process_cq(nvmeq);
> > > -	spin_unlock_irq(&nvmeq->q_lock);
> > > +	spin_unlock_irqrestore(&nvmeq->q_lock, flags);
> > 
> > No documentation why this is needed...
> 
> Let's forget documenting why it's needed; this solution should instead
> figure out a way to make it so it's not needed.

This is some code that was used for previous iterations while we were testing.
We missed this and some other things in this patch set when we were cleaning up.
It's gone from V2 as well as the other weirdness in the patch.

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

* Re: [RFC PATCH 5/6] nvme: Add unlock_from_suspend
  2016-11-01  8:18     ` Sagi Grimberg
@ 2016-11-07 18:45       ` Keith Busch
  -1 siblings, 0 replies; 32+ messages in thread
From: Keith Busch @ 2016-11-07 18:45 UTC (permalink / raw)
  To: Sagi Grimberg
  Cc: Scott Bauer, linux-nvme, Rafael.Antognolli, axboe,
	jonathan.derrick, j.naumann, hch, linux-block

On Tue, Nov 01, 2016 at 10:18:13AM +0200, Sagi Grimberg wrote:
> > -	spin_lock_irq(&nvmeq->q_lock);
> > +	spin_lock_irqsave(&nvmeq->q_lock, flags);
> >  	if (unlikely(nvmeq->cq_vector < 0)) {
> >  		if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
> >  			ret = BLK_MQ_RQ_QUEUE_BUSY;
> >  		else
> >  			ret = BLK_MQ_RQ_QUEUE_ERROR;
> > -		spin_unlock_irq(&nvmeq->q_lock);
> > +		spin_unlock_irqrestore(&nvmeq->q_lock, flags);
> >  		goto out;
> >  	}
> >  	__nvme_submit_cmd(nvmeq, &cmnd);
> >  	nvme_process_cq(nvmeq);
> > -	spin_unlock_irq(&nvmeq->q_lock);
> > +	spin_unlock_irqrestore(&nvmeq->q_lock, flags);
> 
> No documentation why this is needed...

Let's forget documenting why it's needed; this solution should instead
figure out a way to make it so it's not needed.

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

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
@ 2016-11-07 18:45       ` Keith Busch
  0 siblings, 0 replies; 32+ messages in thread
From: Keith Busch @ 2016-11-07 18:45 UTC (permalink / raw)


On Tue, Nov 01, 2016@10:18:13AM +0200, Sagi Grimberg wrote:
> > -	spin_lock_irq(&nvmeq->q_lock);
> > +	spin_lock_irqsave(&nvmeq->q_lock, flags);
> >  	if (unlikely(nvmeq->cq_vector < 0)) {
> >  		if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
> >  			ret = BLK_MQ_RQ_QUEUE_BUSY;
> >  		else
> >  			ret = BLK_MQ_RQ_QUEUE_ERROR;
> > -		spin_unlock_irq(&nvmeq->q_lock);
> > +		spin_unlock_irqrestore(&nvmeq->q_lock, flags);
> >  		goto out;
> >  	}
> >  	__nvme_submit_cmd(nvmeq, &cmnd);
> >  	nvme_process_cq(nvmeq);
> > -	spin_unlock_irq(&nvmeq->q_lock);
> > +	spin_unlock_irqrestore(&nvmeq->q_lock, flags);
> 
> No documentation why this is needed...

Let's forget documenting why it's needed; this solution should instead
figure out a way to make it so it's not needed.

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

* Re: [RFC PATCH 5/6] nvme: Add unlock_from_suspend
  2016-11-01 13:57       ` Christoph Hellwig
@ 2016-11-10 23:01         ` Scott Bauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-11-10 23:01 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Sagi Grimberg, linux-nvme, keith.busch, Rafael.Antognolli, axboe,
	linux-block, jonathan.derrick, j.naumann

On Tue, Nov 01, 2016 at 06:57:05AM -0700, Christoph Hellwig wrote:
> On Tue, Nov 01, 2016 at 10:18:13AM +0200, Sagi Grimberg wrote:
> > > +
> > > +	return nvme_insert_rq(q, req, 1, sec_submit_endio);
> > 
> > No need to introduce nvme_insert_rq at all, just call
> > blk_mq_insert_request (other examples call blk_execute_rq_nowait
> > but its pretty much the same...)
> 
> blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
> even exported.

I remember now, after I changed it to use rq_nowait, why we added this wrapper
function and used blk_mq_insert_request.

When we dispatch opal commands down to the controller we're doing so in an IRQ,
so if we use rq_nowait, we lockup.

Will there be pushback if we continue with the original patch idea, where we 
export blk_mq_insert_request (forgot to send that) and use it? I looked through
the block API and I didn't see a execute_rq that was irq safe.

Any suggestions?





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

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
@ 2016-11-10 23:01         ` Scott Bauer
  0 siblings, 0 replies; 32+ messages in thread
From: Scott Bauer @ 2016-11-10 23:01 UTC (permalink / raw)


On Tue, Nov 01, 2016@06:57:05AM -0700, Christoph Hellwig wrote:
> On Tue, Nov 01, 2016@10:18:13AM +0200, Sagi Grimberg wrote:
> > > +
> > > +	return nvme_insert_rq(q, req, 1, sec_submit_endio);
> > 
> > No need to introduce nvme_insert_rq at all, just call
> > blk_mq_insert_request (other examples call blk_execute_rq_nowait
> > but its pretty much the same...)
> 
> blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
> even exported.

I remember now, after I changed it to use rq_nowait, why we added this wrapper
function and used blk_mq_insert_request.

When we dispatch opal commands down to the controller we're doing so in an IRQ,
so if we use rq_nowait, we lockup.

Will there be pushback if we continue with the original patch idea, where we 
export blk_mq_insert_request (forgot to send that) and use it? I looked through
the block API and I didn't see a execute_rq that was irq safe.

Any suggestions?

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

* Re: [RFC PATCH 5/6] nvme: Add unlock_from_suspend
  2016-11-10 23:23           ` Keith Busch
@ 2016-11-10 23:19             ` Christoph Hellwig
  -1 siblings, 0 replies; 32+ messages in thread
From: Christoph Hellwig @ 2016-11-10 23:19 UTC (permalink / raw)
  To: Keith Busch
  Cc: Scott Bauer, Christoph Hellwig, Sagi Grimberg, linux-nvme,
	Rafael.Antognolli, axboe, linux-block, jonathan.derrick,
	j.naumann

On Thu, Nov 10, 2016 at 06:23:12PM -0500, Keith Busch wrote:
> On Thu, Nov 10, 2016 at 04:01:31PM -0700, Scott Bauer wrote:
> > On Tue, Nov 01, 2016 at 06:57:05AM -0700, Christoph Hellwig wrote:
> > > blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
> > > even exported.
> > 
> > I remember now, after I changed it to use rq_nowait, why we added this wrapper
> > function and used blk_mq_insert_request.
> > 
> > When we dispatch opal commands down to the controller we're doing so in an IRQ,
> > so if we use rq_nowait, we lockup.
> 
> In this case can we push the submission off to a work queue and use
> blk_mq_insert_rq_nowait?

That's what we have to do anyway to avoid taking irqsafe locks.
(and the function is blk_execute_rq_nowait)

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

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
@ 2016-11-10 23:19             ` Christoph Hellwig
  0 siblings, 0 replies; 32+ messages in thread
From: Christoph Hellwig @ 2016-11-10 23:19 UTC (permalink / raw)


On Thu, Nov 10, 2016@06:23:12PM -0500, Keith Busch wrote:
> On Thu, Nov 10, 2016@04:01:31PM -0700, Scott Bauer wrote:
> > On Tue, Nov 01, 2016@06:57:05AM -0700, Christoph Hellwig wrote:
> > > blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
> > > even exported.
> > 
> > I remember now, after I changed it to use rq_nowait, why we added this wrapper
> > function and used blk_mq_insert_request.
> > 
> > When we dispatch opal commands down to the controller we're doing so in an IRQ,
> > so if we use rq_nowait, we lockup.
> 
> In this case can we push the submission off to a work queue and use
> blk_mq_insert_rq_nowait?

That's what we have to do anyway to avoid taking irqsafe locks.
(and the function is blk_execute_rq_nowait)

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

* Re: [RFC PATCH 5/6] nvme: Add unlock_from_suspend
  2016-11-10 23:01         ` Scott Bauer
@ 2016-11-10 23:23           ` Keith Busch
  -1 siblings, 0 replies; 32+ messages in thread
From: Keith Busch @ 2016-11-10 23:23 UTC (permalink / raw)
  To: Scott Bauer
  Cc: Christoph Hellwig, Sagi Grimberg, linux-nvme, Rafael.Antognolli,
	axboe, linux-block, jonathan.derrick, j.naumann

On Thu, Nov 10, 2016 at 04:01:31PM -0700, Scott Bauer wrote:
> On Tue, Nov 01, 2016 at 06:57:05AM -0700, Christoph Hellwig wrote:
> > blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
> > even exported.
> 
> I remember now, after I changed it to use rq_nowait, why we added this wrapper
> function and used blk_mq_insert_request.
> 
> When we dispatch opal commands down to the controller we're doing so in an IRQ,
> so if we use rq_nowait, we lockup.

In this case can we push the submission off to a work queue and use
blk_mq_insert_rq_nowait?

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

* [RFC PATCH 5/6] nvme: Add unlock_from_suspend
@ 2016-11-10 23:23           ` Keith Busch
  0 siblings, 0 replies; 32+ messages in thread
From: Keith Busch @ 2016-11-10 23:23 UTC (permalink / raw)


On Thu, Nov 10, 2016@04:01:31PM -0700, Scott Bauer wrote:
> On Tue, Nov 01, 2016@06:57:05AM -0700, Christoph Hellwig wrote:
> > blk_execute_rq_nowait is the API to use - blk_mq_insert_request isn't
> > even exported.
> 
> I remember now, after I changed it to use rq_nowait, why we added this wrapper
> function and used blk_mq_insert_request.
> 
> When we dispatch opal commands down to the controller we're doing so in an IRQ,
> so if we use rq_nowait, we lockup.

In this case can we push the submission off to a work queue and use
blk_mq_insert_rq_nowait?

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

end of thread, other threads:[~2016-11-10 23:23 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-31 21:58 [RFC PATCH 0/6] Sed Opal Scott Bauer
2016-10-31 21:58 ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 1/6] Include: Add definitions for sed Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 2/6] lib: Add Sed-opal library Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-11-01 18:56   ` Jon Derrick
2016-11-01 18:56     ` Jon Derrick
2016-10-31 21:58 ` [RFC PATCH 3/6] lib: Add Sed to Kconfig and Makefile Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 4/6] include: Add sec_ops to block device operations Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 5/6] nvme: Add unlock_from_suspend Scott Bauer
2016-10-31 21:58   ` Scott Bauer
2016-11-01  8:18   ` Sagi Grimberg
2016-11-01  8:18     ` Sagi Grimberg
2016-11-01 13:57     ` Christoph Hellwig
2016-11-01 13:57       ` Christoph Hellwig
2016-11-01 14:40       ` Scott Bauer
2016-11-01 14:40         ` Scott Bauer
2016-11-10 23:01       ` Scott Bauer
2016-11-10 23:01         ` Scott Bauer
2016-11-10 23:23         ` Keith Busch
2016-11-10 23:23           ` Keith Busch
2016-11-10 23:19           ` Christoph Hellwig
2016-11-10 23:19             ` Christoph Hellwig
2016-11-07 18:45     ` Keith Busch
2016-11-07 18:45       ` Keith Busch
2016-11-07 18:33       ` Scott Bauer
2016-11-07 18:33         ` Scott Bauer
2016-10-31 21:58 ` [RFC PATCH 6/6] block: ioctl: Wire up Sed to block ioctls Scott Bauer
2016-10-31 21:58   ` 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.