xref: /openbmc/linux/block/sed-opal.c (revision e8b2922459cf15140ab8cc1f92b6861674fff1a3)
1455a7b23SScott Bauer /*
2455a7b23SScott Bauer  * Copyright © 2016 Intel Corporation
3455a7b23SScott Bauer  *
4455a7b23SScott Bauer  * Authors:
5455a7b23SScott Bauer  *    Scott  Bauer      <scott.bauer@intel.com>
6455a7b23SScott Bauer  *    Rafael Antognolli <rafael.antognolli@intel.com>
7455a7b23SScott Bauer  *
8455a7b23SScott Bauer  * This program is free software; you can redistribute it and/or modify it
9455a7b23SScott Bauer  * under the terms and conditions of the GNU General Public License,
10455a7b23SScott Bauer  * version 2, as published by the Free Software Foundation.
11455a7b23SScott Bauer  *
12455a7b23SScott Bauer  * This program is distributed in the hope it will be useful, but WITHOUT
13455a7b23SScott Bauer  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14455a7b23SScott Bauer  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15455a7b23SScott Bauer  * more details.
16455a7b23SScott Bauer  */
17455a7b23SScott Bauer 
18455a7b23SScott Bauer #define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt
19455a7b23SScott Bauer 
20455a7b23SScott Bauer #include <linux/delay.h>
21455a7b23SScott Bauer #include <linux/device.h>
22455a7b23SScott Bauer #include <linux/kernel.h>
23455a7b23SScott Bauer #include <linux/list.h>
24455a7b23SScott Bauer #include <linux/genhd.h>
25455a7b23SScott Bauer #include <linux/slab.h>
26455a7b23SScott Bauer #include <linux/uaccess.h>
27455a7b23SScott Bauer #include <uapi/linux/sed-opal.h>
28455a7b23SScott Bauer #include <linux/sed-opal.h>
29455a7b23SScott Bauer #include <linux/string.h>
30455a7b23SScott Bauer #include <linux/kdev_t.h>
31455a7b23SScott Bauer 
32455a7b23SScott Bauer #include "opal_proto.h"
33455a7b23SScott Bauer 
344f1244c8SChristoph Hellwig #define IO_BUFFER_LENGTH 2048
354f1244c8SChristoph Hellwig #define MAX_TOKS 64
364f1244c8SChristoph Hellwig 
37eed64951SJon Derrick struct opal_step {
38eed64951SJon Derrick 	int (*fn)(struct opal_dev *dev, void *data);
39eed64951SJon Derrick 	void *data;
40eed64951SJon Derrick };
41eed64951SJon Derrick typedef int (cont_fn)(struct opal_dev *dev);
424f1244c8SChristoph Hellwig 
434f1244c8SChristoph Hellwig enum opal_atom_width {
444f1244c8SChristoph Hellwig 	OPAL_WIDTH_TINY,
454f1244c8SChristoph Hellwig 	OPAL_WIDTH_SHORT,
464f1244c8SChristoph Hellwig 	OPAL_WIDTH_MEDIUM,
474f1244c8SChristoph Hellwig 	OPAL_WIDTH_LONG,
484f1244c8SChristoph Hellwig 	OPAL_WIDTH_TOKEN
494f1244c8SChristoph Hellwig };
504f1244c8SChristoph Hellwig 
514f1244c8SChristoph Hellwig /*
524f1244c8SChristoph Hellwig  * On the parsed response, we don't store again the toks that are already
534f1244c8SChristoph Hellwig  * stored in the response buffer. Instead, for each token, we just store a
544f1244c8SChristoph Hellwig  * pointer to the position in the buffer where the token starts, and the size
554f1244c8SChristoph Hellwig  * of the token in bytes.
564f1244c8SChristoph Hellwig  */
574f1244c8SChristoph Hellwig struct opal_resp_tok {
584f1244c8SChristoph Hellwig 	const u8 *pos;
594f1244c8SChristoph Hellwig 	size_t len;
604f1244c8SChristoph Hellwig 	enum opal_response_token type;
614f1244c8SChristoph Hellwig 	enum opal_atom_width width;
624f1244c8SChristoph Hellwig 	union {
634f1244c8SChristoph Hellwig 		u64 u;
644f1244c8SChristoph Hellwig 		s64 s;
654f1244c8SChristoph Hellwig 	} stored;
664f1244c8SChristoph Hellwig };
674f1244c8SChristoph Hellwig 
684f1244c8SChristoph Hellwig /*
694f1244c8SChristoph Hellwig  * From the response header it's not possible to know how many tokens there are
704f1244c8SChristoph Hellwig  * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
714f1244c8SChristoph Hellwig  * if we start dealing with messages that have more than that, we can increase
724f1244c8SChristoph Hellwig  * this number. This is done to avoid having to make two passes through the
734f1244c8SChristoph Hellwig  * response, the first one counting how many tokens we have and the second one
744f1244c8SChristoph Hellwig  * actually storing the positions.
754f1244c8SChristoph Hellwig  */
764f1244c8SChristoph Hellwig struct parsed_resp {
774f1244c8SChristoph Hellwig 	int num;
784f1244c8SChristoph Hellwig 	struct opal_resp_tok toks[MAX_TOKS];
794f1244c8SChristoph Hellwig };
804f1244c8SChristoph Hellwig 
814f1244c8SChristoph Hellwig struct opal_dev {
824f1244c8SChristoph Hellwig 	bool supported;
83dbec491bSScott Bauer 	bool mbr_enabled;
844f1244c8SChristoph Hellwig 
854f1244c8SChristoph Hellwig 	void *data;
864f1244c8SChristoph Hellwig 	sec_send_recv *send_recv;
874f1244c8SChristoph Hellwig 
88eed64951SJon Derrick 	const struct opal_step *steps;
894f1244c8SChristoph Hellwig 	struct mutex dev_lock;
904f1244c8SChristoph Hellwig 	u16 comid;
914f1244c8SChristoph Hellwig 	u32 hsn;
924f1244c8SChristoph Hellwig 	u32 tsn;
934f1244c8SChristoph Hellwig 	u64 align;
944f1244c8SChristoph Hellwig 	u64 lowest_lba;
954f1244c8SChristoph Hellwig 
964f1244c8SChristoph Hellwig 	size_t pos;
974f1244c8SChristoph Hellwig 	u8 cmd[IO_BUFFER_LENGTH];
984f1244c8SChristoph Hellwig 	u8 resp[IO_BUFFER_LENGTH];
994f1244c8SChristoph Hellwig 
1004f1244c8SChristoph Hellwig 	struct parsed_resp parsed;
1014f1244c8SChristoph Hellwig 	size_t prev_d_len;
1024f1244c8SChristoph Hellwig 	void *prev_data;
1034f1244c8SChristoph Hellwig 
1044f1244c8SChristoph Hellwig 	struct list_head unlk_lst;
1054f1244c8SChristoph Hellwig };
1064f1244c8SChristoph Hellwig 
1074f1244c8SChristoph Hellwig 
108455a7b23SScott Bauer static const u8 opaluid[][OPAL_UID_LENGTH] = {
109455a7b23SScott Bauer 	/* users */
110455a7b23SScott Bauer 	[OPAL_SMUID_UID] =
111455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
112455a7b23SScott Bauer 	[OPAL_THISSP_UID] =
113455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
114455a7b23SScott Bauer 	[OPAL_ADMINSP_UID] =
115455a7b23SScott Bauer 		{ 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
116455a7b23SScott Bauer 	[OPAL_LOCKINGSP_UID] =
117455a7b23SScott Bauer 		{ 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
118455a7b23SScott Bauer 	[OPAL_ENTERPRISE_LOCKINGSP_UID] =
119455a7b23SScott Bauer 		{ 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
120455a7b23SScott Bauer 	[OPAL_ANYBODY_UID] =
121455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
122455a7b23SScott Bauer 	[OPAL_SID_UID] =
123455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
124455a7b23SScott Bauer 	[OPAL_ADMIN1_UID] =
125455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
126455a7b23SScott Bauer 	[OPAL_USER1_UID] =
127455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
128455a7b23SScott Bauer 	[OPAL_USER2_UID] =
129455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
130455a7b23SScott Bauer 	[OPAL_PSID_UID] =
131455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
132455a7b23SScott Bauer 	[OPAL_ENTERPRISE_BANDMASTER0_UID] =
133455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
134455a7b23SScott Bauer 	[OPAL_ENTERPRISE_ERASEMASTER_UID] =
135455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
136455a7b23SScott Bauer 
137455a7b23SScott Bauer 	/* tables */
138455a7b23SScott Bauer 
139455a7b23SScott Bauer 	[OPAL_LOCKINGRANGE_GLOBAL] =
140455a7b23SScott Bauer 		{ 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
141455a7b23SScott Bauer 	[OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
142455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
143455a7b23SScott Bauer 	[OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
144455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
145455a7b23SScott Bauer 	[OPAL_MBRCONTROL] =
146455a7b23SScott Bauer 		{ 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
147455a7b23SScott Bauer 	[OPAL_MBR] =
148455a7b23SScott Bauer 		{ 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
149455a7b23SScott Bauer 	[OPAL_AUTHORITY_TABLE] =
150455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
151455a7b23SScott Bauer 	[OPAL_C_PIN_TABLE] =
152455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
153455a7b23SScott Bauer 	[OPAL_LOCKING_INFO_TABLE] =
154455a7b23SScott Bauer 		{ 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
155455a7b23SScott Bauer 	[OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
156455a7b23SScott Bauer 		{ 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
157455a7b23SScott Bauer 
158455a7b23SScott Bauer 	/* C_PIN_TABLE object ID's */
159455a7b23SScott Bauer 
160455a7b23SScott Bauer 	[OPAL_C_PIN_MSID] =
161455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
162455a7b23SScott Bauer 	[OPAL_C_PIN_SID] =
163455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
164455a7b23SScott Bauer 	[OPAL_C_PIN_ADMIN1] =
165455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
166455a7b23SScott Bauer 
167455a7b23SScott Bauer 	/* half UID's (only first 4 bytes used) */
168455a7b23SScott Bauer 
169455a7b23SScott Bauer 	[OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
170455a7b23SScott Bauer 		{ 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
171455a7b23SScott Bauer 	[OPAL_HALF_UID_BOOLEAN_ACE] =
172455a7b23SScott Bauer 		{ 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
173455a7b23SScott Bauer 
174455a7b23SScott Bauer 	/* special value for omitted optional parameter */
175455a7b23SScott Bauer 	[OPAL_UID_HEXFF] =
176455a7b23SScott Bauer 		{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
177455a7b23SScott Bauer };
178455a7b23SScott Bauer 
179455a7b23SScott Bauer /*
180455a7b23SScott Bauer  * TCG Storage SSC Methods.
181455a7b23SScott Bauer  * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
182455a7b23SScott Bauer  * Section: 6.3 Assigned UIDs
183455a7b23SScott Bauer  */
1841b6b75b0SJonas Rabenstein static const u8 opalmethod[][OPAL_METHOD_LENGTH] = {
185455a7b23SScott Bauer 	[OPAL_PROPERTIES] =
186455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
187455a7b23SScott Bauer 	[OPAL_STARTSESSION] =
188455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
189455a7b23SScott Bauer 	[OPAL_REVERT] =
190455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
191455a7b23SScott Bauer 	[OPAL_ACTIVATE] =
192455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
193455a7b23SScott Bauer 	[OPAL_EGET] =
194455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
195455a7b23SScott Bauer 	[OPAL_ESET] =
196455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
197455a7b23SScott Bauer 	[OPAL_NEXT] =
198455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
199455a7b23SScott Bauer 	[OPAL_EAUTHENTICATE] =
200455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
201455a7b23SScott Bauer 	[OPAL_GETACL] =
202455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
203455a7b23SScott Bauer 	[OPAL_GENKEY] =
204455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
205455a7b23SScott Bauer 	[OPAL_REVERTSP] =
206455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
207455a7b23SScott Bauer 	[OPAL_GET] =
208455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
209455a7b23SScott Bauer 	[OPAL_SET] =
210455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
211455a7b23SScott Bauer 	[OPAL_AUTHENTICATE] =
212455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
213455a7b23SScott Bauer 	[OPAL_RANDOM] =
214455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
215455a7b23SScott Bauer 	[OPAL_ERASE] =
216455a7b23SScott Bauer 		{ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
217455a7b23SScott Bauer };
218455a7b23SScott Bauer 
219455a7b23SScott Bauer static int end_opal_session_error(struct opal_dev *dev);
220455a7b23SScott Bauer 
221455a7b23SScott Bauer struct opal_suspend_data {
222455a7b23SScott Bauer 	struct opal_lock_unlock unlk;
223455a7b23SScott Bauer 	u8 lr;
224455a7b23SScott Bauer 	struct list_head node;
225455a7b23SScott Bauer };
226455a7b23SScott Bauer 
227455a7b23SScott Bauer /*
228455a7b23SScott Bauer  * Derived from:
229455a7b23SScott Bauer  * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
230455a7b23SScott Bauer  * Section: 5.1.5 Method Status Codes
231455a7b23SScott Bauer  */
232455a7b23SScott Bauer static const char * const opal_errors[] = {
233455a7b23SScott Bauer 	"Success",
234455a7b23SScott Bauer 	"Not Authorized",
235455a7b23SScott Bauer 	"Unknown Error",
236455a7b23SScott Bauer 	"SP Busy",
237455a7b23SScott Bauer 	"SP Failed",
238455a7b23SScott Bauer 	"SP Disabled",
239455a7b23SScott Bauer 	"SP Frozen",
240455a7b23SScott Bauer 	"No Sessions Available",
241455a7b23SScott Bauer 	"Uniqueness Conflict",
242455a7b23SScott Bauer 	"Insufficient Space",
243455a7b23SScott Bauer 	"Insufficient Rows",
244455a7b23SScott Bauer 	"Invalid Function",
245455a7b23SScott Bauer 	"Invalid Parameter",
246455a7b23SScott Bauer 	"Invalid Reference",
247455a7b23SScott Bauer 	"Unknown Error",
248455a7b23SScott Bauer 	"TPER Malfunction",
249455a7b23SScott Bauer 	"Transaction Failure",
250455a7b23SScott Bauer 	"Response Overflow",
251455a7b23SScott Bauer 	"Authority Locked Out",
252455a7b23SScott Bauer };
253455a7b23SScott Bauer 
254455a7b23SScott Bauer static const char *opal_error_to_human(int error)
255455a7b23SScott Bauer {
256455a7b23SScott Bauer 	if (error == 0x3f)
257455a7b23SScott Bauer 		return "Failed";
258455a7b23SScott Bauer 
259455a7b23SScott Bauer 	if (error >= ARRAY_SIZE(opal_errors) || error < 0)
260455a7b23SScott Bauer 		return "Unknown Error";
261455a7b23SScott Bauer 
262455a7b23SScott Bauer 	return opal_errors[error];
263455a7b23SScott Bauer }
264455a7b23SScott Bauer 
265455a7b23SScott Bauer static void print_buffer(const u8 *ptr, u32 length)
266455a7b23SScott Bauer {
267455a7b23SScott Bauer #ifdef DEBUG
268455a7b23SScott Bauer 	print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
269455a7b23SScott Bauer 	pr_debug("\n");
270455a7b23SScott Bauer #endif
271455a7b23SScott Bauer }
272455a7b23SScott Bauer 
273455a7b23SScott Bauer static bool check_tper(const void *data)
274455a7b23SScott Bauer {
275455a7b23SScott Bauer 	const struct d0_tper_features *tper = data;
276455a7b23SScott Bauer 	u8 flags = tper->supported_features;
277455a7b23SScott Bauer 
278455a7b23SScott Bauer 	if (!(flags & TPER_SYNC_SUPPORTED)) {
279591c59d1SScott Bauer 		pr_debug("TPer sync not supported. flags = %d\n",
280455a7b23SScott Bauer 			 tper->supported_features);
281455a7b23SScott Bauer 		return false;
282455a7b23SScott Bauer 	}
283455a7b23SScott Bauer 
284455a7b23SScott Bauer 	return true;
285455a7b23SScott Bauer }
286455a7b23SScott Bauer 
287dbec491bSScott Bauer static bool check_mbrenabled(const void *data)
288dbec491bSScott Bauer {
289dbec491bSScott Bauer 	const struct d0_locking_features *lfeat = data;
290dbec491bSScott Bauer 	u8 sup_feat = lfeat->supported_features;
291dbec491bSScott Bauer 
292dbec491bSScott Bauer 	return !!(sup_feat & MBR_ENABLED_MASK);
293dbec491bSScott Bauer }
294dbec491bSScott Bauer 
295455a7b23SScott Bauer static bool check_sum(const void *data)
296455a7b23SScott Bauer {
297455a7b23SScott Bauer 	const struct d0_single_user_mode *sum = data;
298455a7b23SScott Bauer 	u32 nlo = be32_to_cpu(sum->num_locking_objects);
299455a7b23SScott Bauer 
300455a7b23SScott Bauer 	if (nlo == 0) {
301591c59d1SScott Bauer 		pr_debug("Need at least one locking object.\n");
302455a7b23SScott Bauer 		return false;
303455a7b23SScott Bauer 	}
304455a7b23SScott Bauer 
305455a7b23SScott Bauer 	pr_debug("Number of locking objects: %d\n", nlo);
306455a7b23SScott Bauer 
307455a7b23SScott Bauer 	return true;
308455a7b23SScott Bauer }
309455a7b23SScott Bauer 
310455a7b23SScott Bauer static u16 get_comid_v100(const void *data)
311455a7b23SScott Bauer {
312455a7b23SScott Bauer 	const struct d0_opal_v100 *v100 = data;
313455a7b23SScott Bauer 
314455a7b23SScott Bauer 	return be16_to_cpu(v100->baseComID);
315455a7b23SScott Bauer }
316455a7b23SScott Bauer 
317455a7b23SScott Bauer static u16 get_comid_v200(const void *data)
318455a7b23SScott Bauer {
319455a7b23SScott Bauer 	const struct d0_opal_v200 *v200 = data;
320455a7b23SScott Bauer 
321455a7b23SScott Bauer 	return be16_to_cpu(v200->baseComID);
322455a7b23SScott Bauer }
323455a7b23SScott Bauer 
324455a7b23SScott Bauer static int opal_send_cmd(struct opal_dev *dev)
325455a7b23SScott Bauer {
3264f1244c8SChristoph Hellwig 	return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
327455a7b23SScott Bauer 			      dev->cmd, IO_BUFFER_LENGTH,
328455a7b23SScott Bauer 			      true);
329455a7b23SScott Bauer }
330455a7b23SScott Bauer 
331455a7b23SScott Bauer static int opal_recv_cmd(struct opal_dev *dev)
332455a7b23SScott Bauer {
3334f1244c8SChristoph Hellwig 	return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
334455a7b23SScott Bauer 			      dev->resp, IO_BUFFER_LENGTH,
335455a7b23SScott Bauer 			      false);
336455a7b23SScott Bauer }
337455a7b23SScott Bauer 
338455a7b23SScott Bauer static int opal_recv_check(struct opal_dev *dev)
339455a7b23SScott Bauer {
340455a7b23SScott Bauer 	size_t buflen = IO_BUFFER_LENGTH;
341455a7b23SScott Bauer 	void *buffer = dev->resp;
342455a7b23SScott Bauer 	struct opal_header *hdr = buffer;
343455a7b23SScott Bauer 	int ret;
344455a7b23SScott Bauer 
345455a7b23SScott Bauer 	do {
346455a7b23SScott Bauer 		pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
347455a7b23SScott Bauer 			 hdr->cp.outstandingData,
348455a7b23SScott Bauer 			 hdr->cp.minTransfer);
349455a7b23SScott Bauer 
350455a7b23SScott Bauer 		if (hdr->cp.outstandingData == 0 ||
351455a7b23SScott Bauer 		    hdr->cp.minTransfer != 0)
352455a7b23SScott Bauer 			return 0;
353455a7b23SScott Bauer 
354455a7b23SScott Bauer 		memset(buffer, 0, buflen);
355455a7b23SScott Bauer 		ret = opal_recv_cmd(dev);
356455a7b23SScott Bauer 	} while (!ret);
357455a7b23SScott Bauer 
358455a7b23SScott Bauer 	return ret;
359455a7b23SScott Bauer }
360455a7b23SScott Bauer 
361455a7b23SScott Bauer static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
362455a7b23SScott Bauer {
363455a7b23SScott Bauer 	int ret;
364455a7b23SScott Bauer 
365455a7b23SScott Bauer 	ret = opal_send_cmd(dev);
366455a7b23SScott Bauer 	if (ret)
367455a7b23SScott Bauer 		return ret;
368455a7b23SScott Bauer 	ret = opal_recv_cmd(dev);
369455a7b23SScott Bauer 	if (ret)
370455a7b23SScott Bauer 		return ret;
371455a7b23SScott Bauer 	ret = opal_recv_check(dev);
372455a7b23SScott Bauer 	if (ret)
373455a7b23SScott Bauer 		return ret;
374455a7b23SScott Bauer 	return cont(dev);
375455a7b23SScott Bauer }
376455a7b23SScott Bauer 
377455a7b23SScott Bauer static void check_geometry(struct opal_dev *dev, const void *data)
378455a7b23SScott Bauer {
379455a7b23SScott Bauer 	const struct d0_geometry_features *geo = data;
380455a7b23SScott Bauer 
381455a7b23SScott Bauer 	dev->align = geo->alignment_granularity;
382455a7b23SScott Bauer 	dev->lowest_lba = geo->lowest_aligned_lba;
383455a7b23SScott Bauer }
384455a7b23SScott Bauer 
385455a7b23SScott Bauer static int next(struct opal_dev *dev)
386455a7b23SScott Bauer {
387eed64951SJon Derrick 	const struct opal_step *step;
388eed64951SJon Derrick 	int state = 0, error = 0;
389455a7b23SScott Bauer 
390455a7b23SScott Bauer 	do {
391eed64951SJon Derrick 		step = &dev->steps[state];
392eed64951SJon Derrick 		if (!step->fn)
393455a7b23SScott Bauer 			break;
394455a7b23SScott Bauer 
395eed64951SJon Derrick 		error = step->fn(dev, step->data);
396455a7b23SScott Bauer 		if (error) {
397591c59d1SScott Bauer 			pr_debug("Error on step function: %d with error %d: %s\n",
398eed64951SJon Derrick 				 state, error,
399455a7b23SScott Bauer 				 opal_error_to_human(error));
400455a7b23SScott Bauer 
401455a7b23SScott Bauer 			/* For each OPAL command we do a discovery0 then we
402455a7b23SScott Bauer 			 * start some sort of session.
403455a7b23SScott Bauer 			 * If we haven't passed state 1 then there was an error
404455a7b23SScott Bauer 			 * on discovery0 or during the attempt to start a
405455a7b23SScott Bauer 			 * session. Therefore we shouldn't attempt to terminate
406455a7b23SScott Bauer 			 * a session, as one has not yet been created.
407455a7b23SScott Bauer 			 */
4082d19020bSScott Bauer 			if (state > 1) {
4092d19020bSScott Bauer 				end_opal_session_error(dev);
4102d19020bSScott Bauer 				return error;
4112d19020bSScott Bauer 			}
4122d19020bSScott Bauer 
413455a7b23SScott Bauer 		}
414eed64951SJon Derrick 		state++;
415455a7b23SScott Bauer 	} while (!error);
416455a7b23SScott Bauer 
417455a7b23SScott Bauer 	return error;
418455a7b23SScott Bauer }
419455a7b23SScott Bauer 
420455a7b23SScott Bauer static int opal_discovery0_end(struct opal_dev *dev)
421455a7b23SScott Bauer {
422455a7b23SScott Bauer 	bool found_com_id = false, supported = true, single_user = false;
423455a7b23SScott Bauer 	const struct d0_header *hdr = (struct d0_header *)dev->resp;
424455a7b23SScott Bauer 	const u8 *epos = dev->resp, *cpos = dev->resp;
425455a7b23SScott Bauer 	u16 comid = 0;
42677039b96SJon Derrick 	u32 hlen = be32_to_cpu(hdr->length);
427455a7b23SScott Bauer 
42877039b96SJon Derrick 	print_buffer(dev->resp, hlen);
429dbec491bSScott Bauer 	dev->mbr_enabled = false;
430455a7b23SScott Bauer 
43177039b96SJon Derrick 	if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
432591c59d1SScott Bauer 		pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
43377039b96SJon Derrick 			 sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
43477039b96SJon Derrick 		return -EFAULT;
43577039b96SJon Derrick 	}
43677039b96SJon Derrick 
43777039b96SJon Derrick 	epos += hlen; /* end of buffer */
438455a7b23SScott Bauer 	cpos += sizeof(*hdr); /* current position on buffer */
439455a7b23SScott Bauer 
440455a7b23SScott Bauer 	while (cpos < epos && supported) {
441455a7b23SScott Bauer 		const struct d0_features *body =
442455a7b23SScott Bauer 			(const struct d0_features *)cpos;
443455a7b23SScott Bauer 
444455a7b23SScott Bauer 		switch (be16_to_cpu(body->code)) {
445455a7b23SScott Bauer 		case FC_TPER:
446455a7b23SScott Bauer 			supported = check_tper(body->features);
447455a7b23SScott Bauer 			break;
448455a7b23SScott Bauer 		case FC_SINGLEUSER:
449455a7b23SScott Bauer 			single_user = check_sum(body->features);
450455a7b23SScott Bauer 			break;
451455a7b23SScott Bauer 		case FC_GEOMETRY:
452455a7b23SScott Bauer 			check_geometry(dev, body);
453455a7b23SScott Bauer 			break;
454455a7b23SScott Bauer 		case FC_LOCKING:
455dbec491bSScott Bauer 			dev->mbr_enabled = check_mbrenabled(body->features);
456dbec491bSScott Bauer 			break;
457455a7b23SScott Bauer 		case FC_ENTERPRISE:
458455a7b23SScott Bauer 		case FC_DATASTORE:
459455a7b23SScott Bauer 			/* some ignored properties */
460455a7b23SScott Bauer 			pr_debug("Found OPAL feature description: %d\n",
461455a7b23SScott Bauer 				 be16_to_cpu(body->code));
462455a7b23SScott Bauer 			break;
463455a7b23SScott Bauer 		case FC_OPALV100:
464455a7b23SScott Bauer 			comid = get_comid_v100(body->features);
465455a7b23SScott Bauer 			found_com_id = true;
466455a7b23SScott Bauer 			break;
467455a7b23SScott Bauer 		case FC_OPALV200:
468455a7b23SScott Bauer 			comid = get_comid_v200(body->features);
469455a7b23SScott Bauer 			found_com_id = true;
470455a7b23SScott Bauer 			break;
471455a7b23SScott Bauer 		case 0xbfff ... 0xffff:
472455a7b23SScott Bauer 			/* vendor specific, just ignore */
473455a7b23SScott Bauer 			break;
474455a7b23SScott Bauer 		default:
475455a7b23SScott Bauer 			pr_debug("OPAL Unknown feature: %d\n",
476455a7b23SScott Bauer 				 be16_to_cpu(body->code));
477455a7b23SScott Bauer 
478455a7b23SScott Bauer 		}
479455a7b23SScott Bauer 		cpos += body->length + 4;
480455a7b23SScott Bauer 	}
481455a7b23SScott Bauer 
482455a7b23SScott Bauer 	if (!supported) {
483f5b37b7cSChristoph Hellwig 		pr_debug("This device is not Opal enabled. Not Supported!\n");
484455a7b23SScott Bauer 		return -EOPNOTSUPP;
485455a7b23SScott Bauer 	}
486455a7b23SScott Bauer 
487455a7b23SScott Bauer 	if (!single_user)
488f5b37b7cSChristoph Hellwig 		pr_debug("Device doesn't support single user mode\n");
489455a7b23SScott Bauer 
490455a7b23SScott Bauer 
491455a7b23SScott Bauer 	if (!found_com_id) {
492f5b37b7cSChristoph Hellwig 		pr_debug("Could not find OPAL comid for device. Returning early\n");
493ed7158baSIngo Molnar 		return -EOPNOTSUPP;
494455a7b23SScott Bauer 	}
495455a7b23SScott Bauer 
496455a7b23SScott Bauer 	dev->comid = comid;
497455a7b23SScott Bauer 
498455a7b23SScott Bauer 	return 0;
499455a7b23SScott Bauer }
500455a7b23SScott Bauer 
501eed64951SJon Derrick static int opal_discovery0(struct opal_dev *dev, void *data)
502455a7b23SScott Bauer {
503455a7b23SScott Bauer 	int ret;
504455a7b23SScott Bauer 
505455a7b23SScott Bauer 	memset(dev->resp, 0, IO_BUFFER_LENGTH);
506455a7b23SScott Bauer 	dev->comid = OPAL_DISCOVERY_COMID;
507455a7b23SScott Bauer 	ret = opal_recv_cmd(dev);
508455a7b23SScott Bauer 	if (ret)
509455a7b23SScott Bauer 		return ret;
510455a7b23SScott Bauer 	return opal_discovery0_end(dev);
511455a7b23SScott Bauer }
512455a7b23SScott Bauer 
513e2821a50SJonas Rabenstein static bool can_add(int *err, struct opal_dev *cmd, size_t len)
514455a7b23SScott Bauer {
515455a7b23SScott Bauer 	if (*err)
516e2821a50SJonas Rabenstein 		return false;
517e2821a50SJonas Rabenstein 
518e2821a50SJonas Rabenstein 	if (len > IO_BUFFER_LENGTH || cmd->pos > IO_BUFFER_LENGTH - len) {
519e2821a50SJonas Rabenstein 		pr_debug("Error adding %zu bytes: end of buffer.\n", len);
520455a7b23SScott Bauer 		*err = -ERANGE;
521e2821a50SJonas Rabenstein 		return false;
522455a7b23SScott Bauer 	}
523e2821a50SJonas Rabenstein 
524e2821a50SJonas Rabenstein 	return true;
525e2821a50SJonas Rabenstein }
526e2821a50SJonas Rabenstein 
527e2821a50SJonas Rabenstein static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
528e2821a50SJonas Rabenstein {
529e2821a50SJonas Rabenstein 	if (!can_add(err, cmd, 1))
530e2821a50SJonas Rabenstein 		return;
531455a7b23SScott Bauer 	cmd->cmd[cmd->pos++] = tok;
532455a7b23SScott Bauer }
533455a7b23SScott Bauer 
534455a7b23SScott Bauer static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
535455a7b23SScott Bauer 				  bool has_sign, int len)
536455a7b23SScott Bauer {
537455a7b23SScott Bauer 	u8 atom;
538455a7b23SScott Bauer 	int err = 0;
539455a7b23SScott Bauer 
540455a7b23SScott Bauer 	atom = SHORT_ATOM_ID;
541455a7b23SScott Bauer 	atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
542455a7b23SScott Bauer 	atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
543455a7b23SScott Bauer 	atom |= len & SHORT_ATOM_LEN_MASK;
544455a7b23SScott Bauer 
545455a7b23SScott Bauer 	add_token_u8(&err, cmd, atom);
546455a7b23SScott Bauer }
547455a7b23SScott Bauer 
548455a7b23SScott Bauer static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
549455a7b23SScott Bauer 				   bool has_sign, int len)
550455a7b23SScott Bauer {
551455a7b23SScott Bauer 	u8 header0;
552455a7b23SScott Bauer 
553455a7b23SScott Bauer 	header0 = MEDIUM_ATOM_ID;
554455a7b23SScott Bauer 	header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
555455a7b23SScott Bauer 	header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
556455a7b23SScott Bauer 	header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
557455a7b23SScott Bauer 	cmd->cmd[cmd->pos++] = header0;
558455a7b23SScott Bauer 	cmd->cmd[cmd->pos++] = len;
559455a7b23SScott Bauer }
560455a7b23SScott Bauer 
561455a7b23SScott Bauer static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
562455a7b23SScott Bauer {
563455a7b23SScott Bauer 	size_t len;
564455a7b23SScott Bauer 	int msb;
565455a7b23SScott Bauer 
566455a7b23SScott Bauer 	if (!(number & ~TINY_ATOM_DATA_MASK)) {
567455a7b23SScott Bauer 		add_token_u8(err, cmd, number);
568455a7b23SScott Bauer 		return;
569455a7b23SScott Bauer 	}
570455a7b23SScott Bauer 
5715f990d31SJonas Rabenstein 	msb = fls64(number);
5725f990d31SJonas Rabenstein 	len = DIV_ROUND_UP(msb, 8);
573455a7b23SScott Bauer 
574e2821a50SJonas Rabenstein 	if (!can_add(err, cmd, len + 1)) {
575591c59d1SScott Bauer 		pr_debug("Error adding u64: end of buffer.\n");
576455a7b23SScott Bauer 		return;
577455a7b23SScott Bauer 	}
578455a7b23SScott Bauer 	add_short_atom_header(cmd, false, false, len);
5795f990d31SJonas Rabenstein 	while (len--)
5805f990d31SJonas Rabenstein 		add_token_u8(err, cmd, number >> (len * 8));
581455a7b23SScott Bauer }
582455a7b23SScott Bauer 
583455a7b23SScott Bauer static void add_token_bytestring(int *err, struct opal_dev *cmd,
584455a7b23SScott Bauer 				 const u8 *bytestring, size_t len)
585455a7b23SScott Bauer {
586455a7b23SScott Bauer 	size_t header_len = 1;
587455a7b23SScott Bauer 	bool is_short_atom = true;
588455a7b23SScott Bauer 
589455a7b23SScott Bauer 	if (*err)
590455a7b23SScott Bauer 		return;
591455a7b23SScott Bauer 
592455a7b23SScott Bauer 	if (len & ~SHORT_ATOM_LEN_MASK) {
593455a7b23SScott Bauer 		header_len = 2;
594455a7b23SScott Bauer 		is_short_atom = false;
595455a7b23SScott Bauer 	}
596455a7b23SScott Bauer 
597e2821a50SJonas Rabenstein 	if (!can_add(err, cmd, header_len + len)) {
598591c59d1SScott Bauer 		pr_debug("Error adding bytestring: end of buffer.\n");
599455a7b23SScott Bauer 		return;
600455a7b23SScott Bauer 	}
601455a7b23SScott Bauer 
602455a7b23SScott Bauer 	if (is_short_atom)
603455a7b23SScott Bauer 		add_short_atom_header(cmd, true, false, len);
604455a7b23SScott Bauer 	else
605455a7b23SScott Bauer 		add_medium_atom_header(cmd, true, false, len);
606455a7b23SScott Bauer 
607455a7b23SScott Bauer 	memcpy(&cmd->cmd[cmd->pos], bytestring, len);
608455a7b23SScott Bauer 	cmd->pos += len;
609455a7b23SScott Bauer 
610455a7b23SScott Bauer }
611455a7b23SScott Bauer 
612455a7b23SScott Bauer static int build_locking_range(u8 *buffer, size_t length, u8 lr)
613455a7b23SScott Bauer {
614455a7b23SScott Bauer 	if (length > OPAL_UID_LENGTH) {
615591c59d1SScott Bauer 		pr_debug("Can't build locking range. Length OOB\n");
616455a7b23SScott Bauer 		return -ERANGE;
617455a7b23SScott Bauer 	}
618455a7b23SScott Bauer 
619455a7b23SScott Bauer 	memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
620455a7b23SScott Bauer 
621455a7b23SScott Bauer 	if (lr == 0)
622455a7b23SScott Bauer 		return 0;
623455a7b23SScott Bauer 	buffer[5] = LOCKING_RANGE_NON_GLOBAL;
624455a7b23SScott Bauer 	buffer[7] = lr;
625455a7b23SScott Bauer 
626455a7b23SScott Bauer 	return 0;
627455a7b23SScott Bauer }
628455a7b23SScott Bauer 
629455a7b23SScott Bauer static int build_locking_user(u8 *buffer, size_t length, u8 lr)
630455a7b23SScott Bauer {
631455a7b23SScott Bauer 	if (length > OPAL_UID_LENGTH) {
6321e815b33SDavid Kozub 		pr_debug("Can't build locking range user. Length OOB\n");
633455a7b23SScott Bauer 		return -ERANGE;
634455a7b23SScott Bauer 	}
635455a7b23SScott Bauer 
636455a7b23SScott Bauer 	memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
637455a7b23SScott Bauer 
638455a7b23SScott Bauer 	buffer[7] = lr + 1;
639455a7b23SScott Bauer 
640455a7b23SScott Bauer 	return 0;
641455a7b23SScott Bauer }
642455a7b23SScott Bauer 
643455a7b23SScott Bauer static void set_comid(struct opal_dev *cmd, u16 comid)
644455a7b23SScott Bauer {
645455a7b23SScott Bauer 	struct opal_header *hdr = (struct opal_header *)cmd->cmd;
646455a7b23SScott Bauer 
647455a7b23SScott Bauer 	hdr->cp.extendedComID[0] = comid >> 8;
648455a7b23SScott Bauer 	hdr->cp.extendedComID[1] = comid;
649455a7b23SScott Bauer 	hdr->cp.extendedComID[2] = 0;
650455a7b23SScott Bauer 	hdr->cp.extendedComID[3] = 0;
651455a7b23SScott Bauer }
652455a7b23SScott Bauer 
653455a7b23SScott Bauer static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
654455a7b23SScott Bauer {
655455a7b23SScott Bauer 	struct opal_header *hdr;
656455a7b23SScott Bauer 	int err = 0;
657455a7b23SScott Bauer 
658*e8b29224SDavid Kozub 	/* close the parameter list opened from cmd_start */
65978d584caSDavid Kozub 	add_token_u8(&err, cmd, OPAL_ENDLIST);
66078d584caSDavid Kozub 
661455a7b23SScott Bauer 	add_token_u8(&err, cmd, OPAL_ENDOFDATA);
662455a7b23SScott Bauer 	add_token_u8(&err, cmd, OPAL_STARTLIST);
663455a7b23SScott Bauer 	add_token_u8(&err, cmd, 0);
664455a7b23SScott Bauer 	add_token_u8(&err, cmd, 0);
665455a7b23SScott Bauer 	add_token_u8(&err, cmd, 0);
666455a7b23SScott Bauer 	add_token_u8(&err, cmd, OPAL_ENDLIST);
667455a7b23SScott Bauer 
668455a7b23SScott Bauer 	if (err) {
669591c59d1SScott Bauer 		pr_debug("Error finalizing command.\n");
670455a7b23SScott Bauer 		return -EFAULT;
671455a7b23SScott Bauer 	}
672455a7b23SScott Bauer 
673455a7b23SScott Bauer 	hdr = (struct opal_header *) cmd->cmd;
674455a7b23SScott Bauer 
675455a7b23SScott Bauer 	hdr->pkt.tsn = cpu_to_be32(tsn);
676455a7b23SScott Bauer 	hdr->pkt.hsn = cpu_to_be32(hsn);
677455a7b23SScott Bauer 
678455a7b23SScott Bauer 	hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
679455a7b23SScott Bauer 	while (cmd->pos % 4) {
680455a7b23SScott Bauer 		if (cmd->pos >= IO_BUFFER_LENGTH) {
681591c59d1SScott Bauer 			pr_debug("Error: Buffer overrun\n");
682455a7b23SScott Bauer 			return -ERANGE;
683455a7b23SScott Bauer 		}
684455a7b23SScott Bauer 		cmd->cmd[cmd->pos++] = 0;
685455a7b23SScott Bauer 	}
686455a7b23SScott Bauer 	hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
687455a7b23SScott Bauer 				      sizeof(hdr->pkt));
688455a7b23SScott Bauer 	hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
689455a7b23SScott Bauer 
690455a7b23SScott Bauer 	return 0;
691455a7b23SScott Bauer }
692455a7b23SScott Bauer 
693cccb9241SJon Derrick static const struct opal_resp_tok *response_get_token(
694cccb9241SJon Derrick 				const struct parsed_resp *resp,
695455a7b23SScott Bauer 				int n)
696455a7b23SScott Bauer {
697455a7b23SScott Bauer 	const struct opal_resp_tok *tok;
698455a7b23SScott Bauer 
699455a7b23SScott Bauer 	if (n >= resp->num) {
700591c59d1SScott Bauer 		pr_debug("Token number doesn't exist: %d, resp: %d\n",
701455a7b23SScott Bauer 			 n, resp->num);
702cccb9241SJon Derrick 		return ERR_PTR(-EINVAL);
703455a7b23SScott Bauer 	}
704455a7b23SScott Bauer 
705455a7b23SScott Bauer 	tok = &resp->toks[n];
706455a7b23SScott Bauer 	if (tok->len == 0) {
707591c59d1SScott Bauer 		pr_debug("Token length must be non-zero\n");
708cccb9241SJon Derrick 		return ERR_PTR(-EINVAL);
709455a7b23SScott Bauer 	}
710455a7b23SScott Bauer 
711cccb9241SJon Derrick 	return tok;
712455a7b23SScott Bauer }
713455a7b23SScott Bauer 
714aedb6e24SJon Derrick static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
715455a7b23SScott Bauer 				   const u8 *pos)
716455a7b23SScott Bauer {
717455a7b23SScott Bauer 	tok->pos = pos;
718455a7b23SScott Bauer 	tok->len = 1;
719455a7b23SScott Bauer 	tok->width = OPAL_WIDTH_TINY;
720455a7b23SScott Bauer 
721455a7b23SScott Bauer 	if (pos[0] & TINY_ATOM_SIGNED) {
722455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_SINT;
723455a7b23SScott Bauer 	} else {
724455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_UINT;
725455a7b23SScott Bauer 		tok->stored.u = pos[0] & 0x3f;
726455a7b23SScott Bauer 	}
727455a7b23SScott Bauer 
728455a7b23SScott Bauer 	return tok->len;
729455a7b23SScott Bauer }
730455a7b23SScott Bauer 
731aedb6e24SJon Derrick static ssize_t response_parse_short(struct opal_resp_tok *tok,
732455a7b23SScott Bauer 				    const u8 *pos)
733455a7b23SScott Bauer {
734455a7b23SScott Bauer 	tok->pos = pos;
735455a7b23SScott Bauer 	tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
736455a7b23SScott Bauer 	tok->width = OPAL_WIDTH_SHORT;
737455a7b23SScott Bauer 
738455a7b23SScott Bauer 	if (pos[0] & SHORT_ATOM_BYTESTRING) {
739455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_BYTESTRING;
740455a7b23SScott Bauer 	} else if (pos[0] & SHORT_ATOM_SIGNED) {
741455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_SINT;
742455a7b23SScott Bauer 	} else {
743455a7b23SScott Bauer 		u64 u_integer = 0;
744aedb6e24SJon Derrick 		ssize_t i, b = 0;
745455a7b23SScott Bauer 
746455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_UINT;
747455a7b23SScott Bauer 		if (tok->len > 9) {
748591c59d1SScott Bauer 			pr_debug("uint64 with more than 8 bytes\n");
749455a7b23SScott Bauer 			return -EINVAL;
750455a7b23SScott Bauer 		}
751455a7b23SScott Bauer 		for (i = tok->len - 1; i > 0; i--) {
752455a7b23SScott Bauer 			u_integer |= ((u64)pos[i] << (8 * b));
753455a7b23SScott Bauer 			b++;
754455a7b23SScott Bauer 		}
755455a7b23SScott Bauer 		tok->stored.u = u_integer;
756455a7b23SScott Bauer 	}
757455a7b23SScott Bauer 
758455a7b23SScott Bauer 	return tok->len;
759455a7b23SScott Bauer }
760455a7b23SScott Bauer 
761aedb6e24SJon Derrick static ssize_t response_parse_medium(struct opal_resp_tok *tok,
762455a7b23SScott Bauer 				     const u8 *pos)
763455a7b23SScott Bauer {
764455a7b23SScott Bauer 	tok->pos = pos;
765455a7b23SScott Bauer 	tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
766455a7b23SScott Bauer 	tok->width = OPAL_WIDTH_MEDIUM;
767455a7b23SScott Bauer 
768455a7b23SScott Bauer 	if (pos[0] & MEDIUM_ATOM_BYTESTRING)
769455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_BYTESTRING;
770455a7b23SScott Bauer 	else if (pos[0] & MEDIUM_ATOM_SIGNED)
771455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_SINT;
772455a7b23SScott Bauer 	else
773455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_UINT;
774455a7b23SScott Bauer 
775455a7b23SScott Bauer 	return tok->len;
776455a7b23SScott Bauer }
777455a7b23SScott Bauer 
778aedb6e24SJon Derrick static ssize_t response_parse_long(struct opal_resp_tok *tok,
779455a7b23SScott Bauer 				   const u8 *pos)
780455a7b23SScott Bauer {
781455a7b23SScott Bauer 	tok->pos = pos;
782455a7b23SScott Bauer 	tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
783455a7b23SScott Bauer 	tok->width = OPAL_WIDTH_LONG;
784455a7b23SScott Bauer 
785455a7b23SScott Bauer 	if (pos[0] & LONG_ATOM_BYTESTRING)
786455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_BYTESTRING;
787455a7b23SScott Bauer 	else if (pos[0] & LONG_ATOM_SIGNED)
788455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_SINT;
789455a7b23SScott Bauer 	else
790455a7b23SScott Bauer 		tok->type = OPAL_DTA_TOKENID_UINT;
791455a7b23SScott Bauer 
792455a7b23SScott Bauer 	return tok->len;
793455a7b23SScott Bauer }
794455a7b23SScott Bauer 
795aedb6e24SJon Derrick static ssize_t response_parse_token(struct opal_resp_tok *tok,
796455a7b23SScott Bauer 				    const u8 *pos)
797455a7b23SScott Bauer {
798455a7b23SScott Bauer 	tok->pos = pos;
799455a7b23SScott Bauer 	tok->len = 1;
800455a7b23SScott Bauer 	tok->type = OPAL_DTA_TOKENID_TOKEN;
801455a7b23SScott Bauer 	tok->width = OPAL_WIDTH_TOKEN;
802455a7b23SScott Bauer 
803455a7b23SScott Bauer 	return tok->len;
804455a7b23SScott Bauer }
805455a7b23SScott Bauer 
806455a7b23SScott Bauer static int response_parse(const u8 *buf, size_t length,
807455a7b23SScott Bauer 			  struct parsed_resp *resp)
808455a7b23SScott Bauer {
809455a7b23SScott Bauer 	const struct opal_header *hdr;
810455a7b23SScott Bauer 	struct opal_resp_tok *iter;
811455a7b23SScott Bauer 	int num_entries = 0;
812455a7b23SScott Bauer 	int total;
813aedb6e24SJon Derrick 	ssize_t token_length;
814455a7b23SScott Bauer 	const u8 *pos;
81577039b96SJon Derrick 	u32 clen, plen, slen;
816455a7b23SScott Bauer 
817455a7b23SScott Bauer 	if (!buf)
818455a7b23SScott Bauer 		return -EFAULT;
819455a7b23SScott Bauer 
820455a7b23SScott Bauer 	if (!resp)
821455a7b23SScott Bauer 		return -EFAULT;
822455a7b23SScott Bauer 
823455a7b23SScott Bauer 	hdr = (struct opal_header *)buf;
824455a7b23SScott Bauer 	pos = buf;
825455a7b23SScott Bauer 	pos += sizeof(*hdr);
826455a7b23SScott Bauer 
82777039b96SJon Derrick 	clen = be32_to_cpu(hdr->cp.length);
82877039b96SJon Derrick 	plen = be32_to_cpu(hdr->pkt.length);
82977039b96SJon Derrick 	slen = be32_to_cpu(hdr->subpkt.length);
83077039b96SJon Derrick 	pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
83177039b96SJon Derrick 		 clen, plen, slen);
832455a7b23SScott Bauer 
83377039b96SJon Derrick 	if (clen == 0 || plen == 0 || slen == 0 ||
83477039b96SJon Derrick 	    slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
835591c59d1SScott Bauer 		pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
83677039b96SJon Derrick 			 clen, plen, slen);
837455a7b23SScott Bauer 		print_buffer(pos, sizeof(*hdr));
838455a7b23SScott Bauer 		return -EINVAL;
839455a7b23SScott Bauer 	}
840455a7b23SScott Bauer 
841455a7b23SScott Bauer 	if (pos > buf + length)
842455a7b23SScott Bauer 		return -EFAULT;
843455a7b23SScott Bauer 
844455a7b23SScott Bauer 	iter = resp->toks;
84577039b96SJon Derrick 	total = slen;
846455a7b23SScott Bauer 	print_buffer(pos, total);
847455a7b23SScott Bauer 	while (total > 0) {
848455a7b23SScott Bauer 		if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
849455a7b23SScott Bauer 			token_length = response_parse_tiny(iter, pos);
850455a7b23SScott Bauer 		else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
851455a7b23SScott Bauer 			token_length = response_parse_short(iter, pos);
852455a7b23SScott Bauer 		else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
853455a7b23SScott Bauer 			token_length = response_parse_medium(iter, pos);
854455a7b23SScott Bauer 		else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
855455a7b23SScott Bauer 			token_length = response_parse_long(iter, pos);
856455a7b23SScott Bauer 		else /* TOKEN */
857455a7b23SScott Bauer 			token_length = response_parse_token(iter, pos);
858455a7b23SScott Bauer 
859aedb6e24SJon Derrick 		if (token_length < 0)
860aedb6e24SJon Derrick 			return token_length;
861455a7b23SScott Bauer 
862455a7b23SScott Bauer 		pos += token_length;
863455a7b23SScott Bauer 		total -= token_length;
864455a7b23SScott Bauer 		iter++;
865455a7b23SScott Bauer 		num_entries++;
866455a7b23SScott Bauer 	}
867455a7b23SScott Bauer 
868455a7b23SScott Bauer 	if (num_entries == 0) {
869591c59d1SScott Bauer 		pr_debug("Couldn't parse response.\n");
870455a7b23SScott Bauer 		return -EINVAL;
871455a7b23SScott Bauer 	}
872455a7b23SScott Bauer 	resp->num = num_entries;
873455a7b23SScott Bauer 
874455a7b23SScott Bauer 	return 0;
875455a7b23SScott Bauer }
876455a7b23SScott Bauer 
877455a7b23SScott Bauer static size_t response_get_string(const struct parsed_resp *resp, int n,
878455a7b23SScott Bauer 				  const char **store)
879455a7b23SScott Bauer {
880d15e1175SJonas Rabenstein 	u8 skip;
881d15e1175SJonas Rabenstein 	const struct opal_resp_tok *token;
882d15e1175SJonas Rabenstein 
883455a7b23SScott Bauer 	*store = NULL;
884455a7b23SScott Bauer 	if (!resp) {
885591c59d1SScott Bauer 		pr_debug("Response is NULL\n");
886455a7b23SScott Bauer 		return 0;
887455a7b23SScott Bauer 	}
888455a7b23SScott Bauer 
889ce042c18SDan Carpenter 	if (n >= resp->num) {
890591c59d1SScott Bauer 		pr_debug("Response has %d tokens. Can't access %d\n",
891455a7b23SScott Bauer 			 resp->num, n);
892455a7b23SScott Bauer 		return 0;
893455a7b23SScott Bauer 	}
894455a7b23SScott Bauer 
895d15e1175SJonas Rabenstein 	token = &resp->toks[n];
896d15e1175SJonas Rabenstein 	if (token->type != OPAL_DTA_TOKENID_BYTESTRING) {
897591c59d1SScott Bauer 		pr_debug("Token is not a byte string!\n");
898455a7b23SScott Bauer 		return 0;
899455a7b23SScott Bauer 	}
900455a7b23SScott Bauer 
901d15e1175SJonas Rabenstein 	switch (token->width) {
902d15e1175SJonas Rabenstein 	case OPAL_WIDTH_TINY:
903d15e1175SJonas Rabenstein 	case OPAL_WIDTH_SHORT:
904d15e1175SJonas Rabenstein 		skip = 1;
905d15e1175SJonas Rabenstein 		break;
906d15e1175SJonas Rabenstein 	case OPAL_WIDTH_MEDIUM:
907d15e1175SJonas Rabenstein 		skip = 2;
908d15e1175SJonas Rabenstein 		break;
909d15e1175SJonas Rabenstein 	case OPAL_WIDTH_LONG:
910d15e1175SJonas Rabenstein 		skip = 4;
911d15e1175SJonas Rabenstein 		break;
912d15e1175SJonas Rabenstein 	default:
913d15e1175SJonas Rabenstein 		pr_debug("Token has invalid width!\n");
914d15e1175SJonas Rabenstein 		return 0;
915d15e1175SJonas Rabenstein 	}
916d15e1175SJonas Rabenstein 
917d15e1175SJonas Rabenstein 	*store = token->pos + skip;
918d15e1175SJonas Rabenstein 	return token->len - skip;
919455a7b23SScott Bauer }
920455a7b23SScott Bauer 
921455a7b23SScott Bauer static u64 response_get_u64(const struct parsed_resp *resp, int n)
922455a7b23SScott Bauer {
923455a7b23SScott Bauer 	if (!resp) {
924591c59d1SScott Bauer 		pr_debug("Response is NULL\n");
925455a7b23SScott Bauer 		return 0;
926455a7b23SScott Bauer 	}
927455a7b23SScott Bauer 
928ce042c18SDan Carpenter 	if (n >= resp->num) {
929591c59d1SScott Bauer 		pr_debug("Response has %d tokens. Can't access %d\n",
930455a7b23SScott Bauer 			 resp->num, n);
931455a7b23SScott Bauer 		return 0;
932455a7b23SScott Bauer 	}
933455a7b23SScott Bauer 
934455a7b23SScott Bauer 	if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) {
935591c59d1SScott Bauer 		pr_debug("Token is not unsigned it: %d\n",
936455a7b23SScott Bauer 			 resp->toks[n].type);
937455a7b23SScott Bauer 		return 0;
938455a7b23SScott Bauer 	}
939455a7b23SScott Bauer 
940455a7b23SScott Bauer 	if (!(resp->toks[n].width == OPAL_WIDTH_TINY ||
941455a7b23SScott Bauer 	      resp->toks[n].width == OPAL_WIDTH_SHORT)) {
942591c59d1SScott Bauer 		pr_debug("Atom is not short or tiny: %d\n",
943455a7b23SScott Bauer 			 resp->toks[n].width);
944455a7b23SScott Bauer 		return 0;
945455a7b23SScott Bauer 	}
946455a7b23SScott Bauer 
947455a7b23SScott Bauer 	return resp->toks[n].stored.u;
948455a7b23SScott Bauer }
949455a7b23SScott Bauer 
950cccb9241SJon Derrick static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
951cccb9241SJon Derrick {
952cccb9241SJon Derrick 	if (IS_ERR(token) ||
953cccb9241SJon Derrick 	    token->type != OPAL_DTA_TOKENID_TOKEN ||
954cccb9241SJon Derrick 	    token->pos[0] != match)
955cccb9241SJon Derrick 		return false;
956cccb9241SJon Derrick 	return true;
957cccb9241SJon Derrick }
958cccb9241SJon Derrick 
959455a7b23SScott Bauer static u8 response_status(const struct parsed_resp *resp)
960455a7b23SScott Bauer {
961cccb9241SJon Derrick 	const struct opal_resp_tok *tok;
962cccb9241SJon Derrick 
963cccb9241SJon Derrick 	tok = response_get_token(resp, 0);
964cccb9241SJon Derrick 	if (response_token_matches(tok, OPAL_ENDOFSESSION))
965455a7b23SScott Bauer 		return 0;
966455a7b23SScott Bauer 
967455a7b23SScott Bauer 	if (resp->num < 5)
968455a7b23SScott Bauer 		return DTAERROR_NO_METHOD_STATUS;
969455a7b23SScott Bauer 
970cccb9241SJon Derrick 	tok = response_get_token(resp, resp->num - 5);
971cccb9241SJon Derrick 	if (!response_token_matches(tok, OPAL_STARTLIST))
972cccb9241SJon Derrick 		return DTAERROR_NO_METHOD_STATUS;
973cccb9241SJon Derrick 
974cccb9241SJon Derrick 	tok = response_get_token(resp, resp->num - 1);
975cccb9241SJon Derrick 	if (!response_token_matches(tok, OPAL_ENDLIST))
976455a7b23SScott Bauer 		return DTAERROR_NO_METHOD_STATUS;
977455a7b23SScott Bauer 
978455a7b23SScott Bauer 	return response_get_u64(resp, resp->num - 4);
979455a7b23SScott Bauer }
980455a7b23SScott Bauer 
981455a7b23SScott Bauer /* Parses and checks for errors */
982455a7b23SScott Bauer static int parse_and_check_status(struct opal_dev *dev)
983455a7b23SScott Bauer {
984455a7b23SScott Bauer 	int error;
985455a7b23SScott Bauer 
986455a7b23SScott Bauer 	print_buffer(dev->cmd, dev->pos);
987455a7b23SScott Bauer 
988455a7b23SScott Bauer 	error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
989455a7b23SScott Bauer 	if (error) {
990591c59d1SScott Bauer 		pr_debug("Couldn't parse response.\n");
991455a7b23SScott Bauer 		return error;
992455a7b23SScott Bauer 	}
993455a7b23SScott Bauer 
994455a7b23SScott Bauer 	return response_status(&dev->parsed);
995455a7b23SScott Bauer }
996455a7b23SScott Bauer 
997455a7b23SScott Bauer static void clear_opal_cmd(struct opal_dev *dev)
998455a7b23SScott Bauer {
999455a7b23SScott Bauer 	dev->pos = sizeof(struct opal_header);
1000455a7b23SScott Bauer 	memset(dev->cmd, 0, IO_BUFFER_LENGTH);
1001455a7b23SScott Bauer }
1002455a7b23SScott Bauer 
1003*e8b29224SDavid Kozub static int cmd_start(struct opal_dev *dev, const u8 *uid, const u8 *method)
1004*e8b29224SDavid Kozub {
1005*e8b29224SDavid Kozub 	int err = 0;
1006*e8b29224SDavid Kozub 
1007*e8b29224SDavid Kozub 	clear_opal_cmd(dev);
1008*e8b29224SDavid Kozub 	set_comid(dev, dev->comid);
1009*e8b29224SDavid Kozub 
1010*e8b29224SDavid Kozub 	add_token_u8(&err, dev, OPAL_CALL);
1011*e8b29224SDavid Kozub 	add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1012*e8b29224SDavid Kozub 	add_token_bytestring(&err, dev, method, OPAL_METHOD_LENGTH);
1013*e8b29224SDavid Kozub 
1014*e8b29224SDavid Kozub 	/*
1015*e8b29224SDavid Kozub 	 * Every method call is followed by its parameters enclosed within
1016*e8b29224SDavid Kozub 	 * OPAL_STARTLIST and OPAL_ENDLIST tokens. We automatically open the
1017*e8b29224SDavid Kozub 	 * parameter list here and close it later in cmd_finalize.
1018*e8b29224SDavid Kozub 	 */
1019*e8b29224SDavid Kozub 	add_token_u8(&err, dev, OPAL_STARTLIST);
1020*e8b29224SDavid Kozub 
1021*e8b29224SDavid Kozub 	return err;
1022*e8b29224SDavid Kozub }
1023*e8b29224SDavid Kozub 
1024455a7b23SScott Bauer static int start_opal_session_cont(struct opal_dev *dev)
1025455a7b23SScott Bauer {
1026455a7b23SScott Bauer 	u32 hsn, tsn;
1027455a7b23SScott Bauer 	int error = 0;
1028455a7b23SScott Bauer 
1029455a7b23SScott Bauer 	error = parse_and_check_status(dev);
1030455a7b23SScott Bauer 	if (error)
1031455a7b23SScott Bauer 		return error;
1032455a7b23SScott Bauer 
1033455a7b23SScott Bauer 	hsn = response_get_u64(&dev->parsed, 4);
1034455a7b23SScott Bauer 	tsn = response_get_u64(&dev->parsed, 5);
1035455a7b23SScott Bauer 
1036455a7b23SScott Bauer 	if (hsn == 0 && tsn == 0) {
1037591c59d1SScott Bauer 		pr_debug("Couldn't authenticate session\n");
1038455a7b23SScott Bauer 		return -EPERM;
1039455a7b23SScott Bauer 	}
1040455a7b23SScott Bauer 
1041455a7b23SScott Bauer 	dev->hsn = hsn;
1042455a7b23SScott Bauer 	dev->tsn = tsn;
1043455a7b23SScott Bauer 	return 0;
1044455a7b23SScott Bauer }
1045455a7b23SScott Bauer 
1046455a7b23SScott Bauer static void add_suspend_info(struct opal_dev *dev,
1047455a7b23SScott Bauer 			     struct opal_suspend_data *sus)
1048455a7b23SScott Bauer {
1049455a7b23SScott Bauer 	struct opal_suspend_data *iter;
1050455a7b23SScott Bauer 
1051455a7b23SScott Bauer 	list_for_each_entry(iter, &dev->unlk_lst, node) {
1052455a7b23SScott Bauer 		if (iter->lr == sus->lr) {
1053455a7b23SScott Bauer 			list_del(&iter->node);
1054455a7b23SScott Bauer 			kfree(iter);
1055455a7b23SScott Bauer 			break;
1056455a7b23SScott Bauer 		}
1057455a7b23SScott Bauer 	}
1058455a7b23SScott Bauer 	list_add_tail(&sus->node, &dev->unlk_lst);
1059455a7b23SScott Bauer }
1060455a7b23SScott Bauer 
1061455a7b23SScott Bauer static int end_session_cont(struct opal_dev *dev)
1062455a7b23SScott Bauer {
1063455a7b23SScott Bauer 	dev->hsn = 0;
1064455a7b23SScott Bauer 	dev->tsn = 0;
1065455a7b23SScott Bauer 	return parse_and_check_status(dev);
1066455a7b23SScott Bauer }
1067455a7b23SScott Bauer 
1068455a7b23SScott Bauer static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1069455a7b23SScott Bauer {
1070455a7b23SScott Bauer 	int ret;
1071455a7b23SScott Bauer 
1072455a7b23SScott Bauer 	ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1073455a7b23SScott Bauer 	if (ret) {
1074591c59d1SScott Bauer 		pr_debug("Error finalizing command buffer: %d\n", ret);
1075455a7b23SScott Bauer 		return ret;
1076455a7b23SScott Bauer 	}
1077455a7b23SScott Bauer 
1078455a7b23SScott Bauer 	print_buffer(dev->cmd, dev->pos);
1079455a7b23SScott Bauer 
1080455a7b23SScott Bauer 	return opal_send_recv(dev, cont);
1081455a7b23SScott Bauer }
1082455a7b23SScott Bauer 
1083eed64951SJon Derrick static int gen_key(struct opal_dev *dev, void *data)
1084455a7b23SScott Bauer {
1085455a7b23SScott Bauer 	u8 uid[OPAL_UID_LENGTH];
1086*e8b29224SDavid Kozub 	int err;
1087455a7b23SScott Bauer 
1088455a7b23SScott Bauer 	memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
1089455a7b23SScott Bauer 	kfree(dev->prev_data);
1090455a7b23SScott Bauer 	dev->prev_data = NULL;
1091455a7b23SScott Bauer 
1092*e8b29224SDavid Kozub 	err = cmd_start(dev, uid, opalmethod[OPAL_GENKEY]);
1093455a7b23SScott Bauer 
1094455a7b23SScott Bauer 	if (err) {
1095591c59d1SScott Bauer 		pr_debug("Error building gen key command\n");
1096455a7b23SScott Bauer 		return err;
1097455a7b23SScott Bauer 
1098455a7b23SScott Bauer 	}
1099455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1100455a7b23SScott Bauer }
1101455a7b23SScott Bauer 
1102455a7b23SScott Bauer static int get_active_key_cont(struct opal_dev *dev)
1103455a7b23SScott Bauer {
1104455a7b23SScott Bauer 	const char *activekey;
1105455a7b23SScott Bauer 	size_t keylen;
1106455a7b23SScott Bauer 	int error = 0;
1107455a7b23SScott Bauer 
1108455a7b23SScott Bauer 	error = parse_and_check_status(dev);
1109455a7b23SScott Bauer 	if (error)
1110455a7b23SScott Bauer 		return error;
1111455a7b23SScott Bauer 	keylen = response_get_string(&dev->parsed, 4, &activekey);
1112455a7b23SScott Bauer 	if (!activekey) {
1113591c59d1SScott Bauer 		pr_debug("%s: Couldn't extract the Activekey from the response\n",
1114455a7b23SScott Bauer 			 __func__);
1115455a7b23SScott Bauer 		return OPAL_INVAL_PARAM;
1116455a7b23SScott Bauer 	}
1117455a7b23SScott Bauer 	dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1118455a7b23SScott Bauer 
1119455a7b23SScott Bauer 	if (!dev->prev_data)
1120455a7b23SScott Bauer 		return -ENOMEM;
1121455a7b23SScott Bauer 
1122455a7b23SScott Bauer 	dev->prev_d_len = keylen;
1123455a7b23SScott Bauer 
1124455a7b23SScott Bauer 	return 0;
1125455a7b23SScott Bauer }
1126455a7b23SScott Bauer 
1127eed64951SJon Derrick static int get_active_key(struct opal_dev *dev, void *data)
1128455a7b23SScott Bauer {
1129455a7b23SScott Bauer 	u8 uid[OPAL_UID_LENGTH];
1130*e8b29224SDavid Kozub 	int err;
1131eed64951SJon Derrick 	u8 *lr = data;
1132455a7b23SScott Bauer 
1133455a7b23SScott Bauer 	err = build_locking_range(uid, sizeof(uid), *lr);
1134455a7b23SScott Bauer 	if (err)
1135455a7b23SScott Bauer 		return err;
1136455a7b23SScott Bauer 
1137*e8b29224SDavid Kozub 	err = cmd_start(dev, uid, opalmethod[OPAL_GET]);
1138455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1139455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1140455a7b23SScott Bauer 	add_token_u8(&err, dev, 3); /* startCloumn */
1141455a7b23SScott Bauer 	add_token_u8(&err, dev, 10); /* ActiveKey */
1142455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1143455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1144455a7b23SScott Bauer 	add_token_u8(&err, dev, 4); /* endColumn */
1145455a7b23SScott Bauer 	add_token_u8(&err, dev, 10); /* ActiveKey */
1146455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1147455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1148455a7b23SScott Bauer 	if (err) {
1149591c59d1SScott Bauer 		pr_debug("Error building get active key command\n");
1150455a7b23SScott Bauer 		return err;
1151455a7b23SScott Bauer 	}
1152455a7b23SScott Bauer 
1153455a7b23SScott Bauer 	return finalize_and_send(dev, get_active_key_cont);
1154455a7b23SScott Bauer }
1155455a7b23SScott Bauer 
1156455a7b23SScott Bauer static int generic_lr_enable_disable(struct opal_dev *dev,
1157455a7b23SScott Bauer 				     u8 *uid, bool rle, bool wle,
1158455a7b23SScott Bauer 				     bool rl, bool wl)
1159455a7b23SScott Bauer {
1160*e8b29224SDavid Kozub 	int err;
1161455a7b23SScott Bauer 
1162*e8b29224SDavid Kozub 	err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
1163455a7b23SScott Bauer 
1164455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1165455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_VALUES);
1166455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1167455a7b23SScott Bauer 
1168455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1169455a7b23SScott Bauer 	add_token_u8(&err, dev, 5); /* ReadLockEnabled */
1170455a7b23SScott Bauer 	add_token_u8(&err, dev, rle);
1171455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1172455a7b23SScott Bauer 
1173455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1174455a7b23SScott Bauer 	add_token_u8(&err, dev, 6); /* WriteLockEnabled */
1175455a7b23SScott Bauer 	add_token_u8(&err, dev, wle);
1176455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1177455a7b23SScott Bauer 
1178455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1179455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_READLOCKED);
1180455a7b23SScott Bauer 	add_token_u8(&err, dev, rl);
1181455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1182455a7b23SScott Bauer 
1183455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1184455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_WRITELOCKED);
1185455a7b23SScott Bauer 	add_token_u8(&err, dev, wl);
1186455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1187455a7b23SScott Bauer 
1188455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1189455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1190455a7b23SScott Bauer 	return err;
1191455a7b23SScott Bauer }
1192455a7b23SScott Bauer 
1193455a7b23SScott Bauer static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1194455a7b23SScott Bauer 				   struct opal_user_lr_setup *setup)
1195455a7b23SScott Bauer {
1196455a7b23SScott Bauer 	int err;
1197455a7b23SScott Bauer 
1198455a7b23SScott Bauer 	err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1199455a7b23SScott Bauer 					0, 0);
1200455a7b23SScott Bauer 	if (err)
1201591c59d1SScott Bauer 		pr_debug("Failed to create enable global lr command\n");
1202455a7b23SScott Bauer 	return err;
1203455a7b23SScott Bauer }
1204455a7b23SScott Bauer 
1205eed64951SJon Derrick static int setup_locking_range(struct opal_dev *dev, void *data)
1206455a7b23SScott Bauer {
1207455a7b23SScott Bauer 	u8 uid[OPAL_UID_LENGTH];
1208eed64951SJon Derrick 	struct opal_user_lr_setup *setup = data;
1209455a7b23SScott Bauer 	u8 lr;
1210*e8b29224SDavid Kozub 	int err;
1211455a7b23SScott Bauer 
1212455a7b23SScott Bauer 	lr = setup->session.opal_key.lr;
1213455a7b23SScott Bauer 	err = build_locking_range(uid, sizeof(uid), lr);
1214455a7b23SScott Bauer 	if (err)
1215455a7b23SScott Bauer 		return err;
1216455a7b23SScott Bauer 
1217455a7b23SScott Bauer 	if (lr == 0)
1218455a7b23SScott Bauer 		err = enable_global_lr(dev, uid, setup);
1219455a7b23SScott Bauer 	else {
1220*e8b29224SDavid Kozub 		err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
1221455a7b23SScott Bauer 
1222455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTNAME);
1223455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_VALUES);
1224455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTLIST);
1225455a7b23SScott Bauer 
1226455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTNAME);
1227455a7b23SScott Bauer 		add_token_u8(&err, dev, 3); /* Ranges Start */
1228455a7b23SScott Bauer 		add_token_u64(&err, dev, setup->range_start);
1229455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDNAME);
1230455a7b23SScott Bauer 
1231455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTNAME);
1232455a7b23SScott Bauer 		add_token_u8(&err, dev, 4); /* Ranges length */
1233455a7b23SScott Bauer 		add_token_u64(&err, dev, setup->range_length);
1234455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDNAME);
1235455a7b23SScott Bauer 
1236455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTNAME);
1237455a7b23SScott Bauer 		add_token_u8(&err, dev, 5); /*ReadLockEnabled */
1238455a7b23SScott Bauer 		add_token_u64(&err, dev, !!setup->RLE);
1239455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDNAME);
1240455a7b23SScott Bauer 
1241455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTNAME);
1242455a7b23SScott Bauer 		add_token_u8(&err, dev, 6); /*WriteLockEnabled*/
1243455a7b23SScott Bauer 		add_token_u64(&err, dev, !!setup->WLE);
1244455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDNAME);
1245455a7b23SScott Bauer 
1246455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDLIST);
1247455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDNAME);
1248455a7b23SScott Bauer 	}
1249455a7b23SScott Bauer 	if (err) {
1250591c59d1SScott Bauer 		pr_debug("Error building Setup Locking range command.\n");
1251455a7b23SScott Bauer 		return err;
1252455a7b23SScott Bauer 
1253455a7b23SScott Bauer 	}
1254455a7b23SScott Bauer 
1255455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1256455a7b23SScott Bauer }
1257455a7b23SScott Bauer 
1258455a7b23SScott Bauer static int start_generic_opal_session(struct opal_dev *dev,
1259455a7b23SScott Bauer 				      enum opal_uid auth,
1260455a7b23SScott Bauer 				      enum opal_uid sp_type,
1261455a7b23SScott Bauer 				      const char *key,
1262455a7b23SScott Bauer 				      u8 key_len)
1263455a7b23SScott Bauer {
1264455a7b23SScott Bauer 	u32 hsn;
1265*e8b29224SDavid Kozub 	int err;
1266455a7b23SScott Bauer 
1267591c59d1SScott Bauer 	if (key == NULL && auth != OPAL_ANYBODY_UID)
1268455a7b23SScott Bauer 		return OPAL_INVAL_PARAM;
1269455a7b23SScott Bauer 
1270455a7b23SScott Bauer 	hsn = GENERIC_HOST_SESSION_NUM;
1271*e8b29224SDavid Kozub 	err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1272*e8b29224SDavid Kozub 			opalmethod[OPAL_STARTSESSION]);
1273455a7b23SScott Bauer 
1274455a7b23SScott Bauer 	add_token_u64(&err, dev, hsn);
1275455a7b23SScott Bauer 	add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1276455a7b23SScott Bauer 	add_token_u8(&err, dev, 1);
1277455a7b23SScott Bauer 
1278455a7b23SScott Bauer 	switch (auth) {
1279455a7b23SScott Bauer 	case OPAL_ANYBODY_UID:
1280455a7b23SScott Bauer 		break;
1281455a7b23SScott Bauer 	case OPAL_ADMIN1_UID:
1282455a7b23SScott Bauer 	case OPAL_SID_UID:
1283455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTNAME);
1284455a7b23SScott Bauer 		add_token_u8(&err, dev, 0); /* HostChallenge */
1285455a7b23SScott Bauer 		add_token_bytestring(&err, dev, key, key_len);
1286455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDNAME);
1287455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTNAME);
1288455a7b23SScott Bauer 		add_token_u8(&err, dev, 3); /* HostSignAuth */
1289455a7b23SScott Bauer 		add_token_bytestring(&err, dev, opaluid[auth],
1290455a7b23SScott Bauer 				     OPAL_UID_LENGTH);
1291455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDNAME);
1292455a7b23SScott Bauer 		break;
1293455a7b23SScott Bauer 	default:
1294591c59d1SScott Bauer 		pr_debug("Cannot start Admin SP session with auth %d\n", auth);
1295455a7b23SScott Bauer 		return OPAL_INVAL_PARAM;
1296455a7b23SScott Bauer 	}
1297455a7b23SScott Bauer 
1298455a7b23SScott Bauer 	if (err) {
1299591c59d1SScott Bauer 		pr_debug("Error building start adminsp session command.\n");
1300455a7b23SScott Bauer 		return err;
1301455a7b23SScott Bauer 	}
1302455a7b23SScott Bauer 
1303455a7b23SScott Bauer 	return finalize_and_send(dev, start_opal_session_cont);
1304455a7b23SScott Bauer }
1305455a7b23SScott Bauer 
1306eed64951SJon Derrick static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
1307455a7b23SScott Bauer {
1308455a7b23SScott Bauer 	return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1309455a7b23SScott Bauer 					  OPAL_ADMINSP_UID, NULL, 0);
1310455a7b23SScott Bauer }
1311455a7b23SScott Bauer 
1312eed64951SJon Derrick static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
1313455a7b23SScott Bauer {
1314455a7b23SScott Bauer 	int ret;
1315455a7b23SScott Bauer 	const u8 *key = dev->prev_data;
1316455a7b23SScott Bauer 
1317455a7b23SScott Bauer 	if (!key) {
1318eed64951SJon Derrick 		const struct opal_key *okey = data;
13191e815b33SDavid Kozub 
1320455a7b23SScott Bauer 		ret = start_generic_opal_session(dev, OPAL_SID_UID,
1321455a7b23SScott Bauer 						 OPAL_ADMINSP_UID,
1322455a7b23SScott Bauer 						 okey->key,
1323455a7b23SScott Bauer 						 okey->key_len);
1324455a7b23SScott Bauer 	} else {
1325455a7b23SScott Bauer 		ret = start_generic_opal_session(dev, OPAL_SID_UID,
1326455a7b23SScott Bauer 						 OPAL_ADMINSP_UID,
1327455a7b23SScott Bauer 						 key, dev->prev_d_len);
1328455a7b23SScott Bauer 		kfree(key);
1329455a7b23SScott Bauer 		dev->prev_data = NULL;
1330455a7b23SScott Bauer 	}
1331455a7b23SScott Bauer 	return ret;
1332455a7b23SScott Bauer }
1333455a7b23SScott Bauer 
1334eed64951SJon Derrick static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
1335455a7b23SScott Bauer {
1336eed64951SJon Derrick 	struct opal_key *key = data;
13371e815b33SDavid Kozub 
1338455a7b23SScott Bauer 	return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1339455a7b23SScott Bauer 					  OPAL_LOCKINGSP_UID,
1340455a7b23SScott Bauer 					  key->key, key->key_len);
1341455a7b23SScott Bauer }
1342455a7b23SScott Bauer 
1343eed64951SJon Derrick static int start_auth_opal_session(struct opal_dev *dev, void *data)
1344455a7b23SScott Bauer {
1345eed64951SJon Derrick 	struct opal_session_info *session = data;
1346455a7b23SScott Bauer 	u8 lk_ul_user[OPAL_UID_LENGTH];
1347eed64951SJon Derrick 	size_t keylen = session->opal_key.key_len;
1348455a7b23SScott Bauer 	int err = 0;
1349455a7b23SScott Bauer 
1350455a7b23SScott Bauer 	u8 *key = session->opal_key.key;
1351455a7b23SScott Bauer 	u32 hsn = GENERIC_HOST_SESSION_NUM;
1352455a7b23SScott Bauer 
1353*e8b29224SDavid Kozub 	if (session->sum)
1354455a7b23SScott Bauer 		err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1355455a7b23SScott Bauer 					 session->opal_key.lr);
1356*e8b29224SDavid Kozub 	else if (session->who != OPAL_ADMIN1 && !session->sum)
1357455a7b23SScott Bauer 		err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1358455a7b23SScott Bauer 					 session->who - 1);
1359*e8b29224SDavid Kozub 	else
1360455a7b23SScott Bauer 		memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1361455a7b23SScott Bauer 
1362*e8b29224SDavid Kozub 	if (err)
1363*e8b29224SDavid Kozub 		return err;
1364455a7b23SScott Bauer 
1365*e8b29224SDavid Kozub 	err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1366*e8b29224SDavid Kozub 			opalmethod[OPAL_STARTSESSION]);
1367*e8b29224SDavid Kozub 
1368455a7b23SScott Bauer 	add_token_u64(&err, dev, hsn);
1369455a7b23SScott Bauer 	add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1370455a7b23SScott Bauer 			     OPAL_UID_LENGTH);
1371455a7b23SScott Bauer 	add_token_u8(&err, dev, 1);
1372455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1373455a7b23SScott Bauer 	add_token_u8(&err, dev, 0);
1374455a7b23SScott Bauer 	add_token_bytestring(&err, dev, key, keylen);
1375455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1376455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1377455a7b23SScott Bauer 	add_token_u8(&err, dev, 3);
1378455a7b23SScott Bauer 	add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1379455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1380455a7b23SScott Bauer 
1381455a7b23SScott Bauer 	if (err) {
1382591c59d1SScott Bauer 		pr_debug("Error building STARTSESSION command.\n");
1383455a7b23SScott Bauer 		return err;
1384455a7b23SScott Bauer 	}
1385455a7b23SScott Bauer 
1386455a7b23SScott Bauer 	return finalize_and_send(dev, start_opal_session_cont);
1387455a7b23SScott Bauer }
1388455a7b23SScott Bauer 
1389eed64951SJon Derrick static int revert_tper(struct opal_dev *dev, void *data)
1390455a7b23SScott Bauer {
1391*e8b29224SDavid Kozub 	int err;
1392455a7b23SScott Bauer 
1393*e8b29224SDavid Kozub 	err = cmd_start(dev, opaluid[OPAL_ADMINSP_UID],
1394*e8b29224SDavid Kozub 			opalmethod[OPAL_REVERT]);
1395455a7b23SScott Bauer 	if (err) {
1396591c59d1SScott Bauer 		pr_debug("Error building REVERT TPER command.\n");
1397455a7b23SScott Bauer 		return err;
1398455a7b23SScott Bauer 	}
1399455a7b23SScott Bauer 
1400455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1401455a7b23SScott Bauer }
1402455a7b23SScott Bauer 
1403eed64951SJon Derrick static int internal_activate_user(struct opal_dev *dev, void *data)
1404455a7b23SScott Bauer {
1405eed64951SJon Derrick 	struct opal_session_info *session = data;
1406455a7b23SScott Bauer 	u8 uid[OPAL_UID_LENGTH];
1407*e8b29224SDavid Kozub 	int err;
1408455a7b23SScott Bauer 
1409455a7b23SScott Bauer 	memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1410455a7b23SScott Bauer 	uid[7] = session->who;
1411455a7b23SScott Bauer 
1412*e8b29224SDavid Kozub 	err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
1413455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1414455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_VALUES);
1415455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1416455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1417455a7b23SScott Bauer 	add_token_u8(&err, dev, 5); /* Enabled */
1418455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_TRUE);
1419455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1420455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1421455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1422455a7b23SScott Bauer 
1423455a7b23SScott Bauer 	if (err) {
1424591c59d1SScott Bauer 		pr_debug("Error building Activate UserN command.\n");
1425455a7b23SScott Bauer 		return err;
1426455a7b23SScott Bauer 	}
1427455a7b23SScott Bauer 
1428455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1429455a7b23SScott Bauer }
1430455a7b23SScott Bauer 
1431eed64951SJon Derrick static int erase_locking_range(struct opal_dev *dev, void *data)
1432455a7b23SScott Bauer {
1433eed64951SJon Derrick 	struct opal_session_info *session = data;
1434455a7b23SScott Bauer 	u8 uid[OPAL_UID_LENGTH];
1435*e8b29224SDavid Kozub 	int err;
1436455a7b23SScott Bauer 
1437455a7b23SScott Bauer 	if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1438455a7b23SScott Bauer 		return -ERANGE;
1439455a7b23SScott Bauer 
1440*e8b29224SDavid Kozub 	err = cmd_start(dev, uid, opalmethod[OPAL_ERASE]);
1441455a7b23SScott Bauer 
1442455a7b23SScott Bauer 	if (err) {
1443591c59d1SScott Bauer 		pr_debug("Error building Erase Locking Range Command.\n");
1444455a7b23SScott Bauer 		return err;
1445455a7b23SScott Bauer 	}
1446455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1447455a7b23SScott Bauer }
1448455a7b23SScott Bauer 
1449eed64951SJon Derrick static int set_mbr_done(struct opal_dev *dev, void *data)
1450455a7b23SScott Bauer {
1451eed64951SJon Derrick 	u8 *mbr_done_tf = data;
1452*e8b29224SDavid Kozub 	int err;
1453455a7b23SScott Bauer 
1454*e8b29224SDavid Kozub 	err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1455*e8b29224SDavid Kozub 			opalmethod[OPAL_SET]);
1456455a7b23SScott Bauer 
1457455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1458455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_VALUES);
1459455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1460455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1461455a7b23SScott Bauer 	add_token_u8(&err, dev, 2); /* Done */
1462eed64951SJon Derrick 	add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
1463455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1464455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1465455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1466455a7b23SScott Bauer 
1467455a7b23SScott Bauer 	if (err) {
1468591c59d1SScott Bauer 		pr_debug("Error Building set MBR Done command\n");
1469455a7b23SScott Bauer 		return err;
1470455a7b23SScott Bauer 	}
1471455a7b23SScott Bauer 
1472455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1473455a7b23SScott Bauer }
1474455a7b23SScott Bauer 
1475eed64951SJon Derrick static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
1476455a7b23SScott Bauer {
1477eed64951SJon Derrick 	u8 *mbr_en_dis = data;
1478*e8b29224SDavid Kozub 	int err;
1479455a7b23SScott Bauer 
1480*e8b29224SDavid Kozub 	err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1481*e8b29224SDavid Kozub 			opalmethod[OPAL_SET]);
1482455a7b23SScott Bauer 
1483455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1484455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_VALUES);
1485455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1486455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1487455a7b23SScott Bauer 	add_token_u8(&err, dev, 1);
1488eed64951SJon Derrick 	add_token_u8(&err, dev, *mbr_en_dis);
1489455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1490455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1491455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1492455a7b23SScott Bauer 
1493455a7b23SScott Bauer 	if (err) {
1494591c59d1SScott Bauer 		pr_debug("Error Building set MBR done command\n");
1495455a7b23SScott Bauer 		return err;
1496455a7b23SScott Bauer 	}
1497455a7b23SScott Bauer 
1498455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1499455a7b23SScott Bauer }
1500455a7b23SScott Bauer 
1501455a7b23SScott Bauer static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1502455a7b23SScott Bauer 			  struct opal_dev *dev)
1503455a7b23SScott Bauer {
1504*e8b29224SDavid Kozub 	int err;
1505455a7b23SScott Bauer 
1506*e8b29224SDavid Kozub 	err = cmd_start(dev, cpin_uid, opalmethod[OPAL_SET]);
1507455a7b23SScott Bauer 
1508455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1509455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_VALUES);
1510455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1511455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1512455a7b23SScott Bauer 	add_token_u8(&err, dev, 3); /* PIN */
1513455a7b23SScott Bauer 	add_token_bytestring(&err, dev, key, key_len);
1514455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1515455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1516455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1517455a7b23SScott Bauer 
1518455a7b23SScott Bauer 	return err;
1519455a7b23SScott Bauer }
1520455a7b23SScott Bauer 
1521eed64951SJon Derrick static int set_new_pw(struct opal_dev *dev, void *data)
1522455a7b23SScott Bauer {
1523455a7b23SScott Bauer 	u8 cpin_uid[OPAL_UID_LENGTH];
1524eed64951SJon Derrick 	struct opal_session_info *usr = data;
1525455a7b23SScott Bauer 
1526455a7b23SScott Bauer 	memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1527455a7b23SScott Bauer 
1528455a7b23SScott Bauer 	if (usr->who != OPAL_ADMIN1) {
1529455a7b23SScott Bauer 		cpin_uid[5] = 0x03;
1530455a7b23SScott Bauer 		if (usr->sum)
1531455a7b23SScott Bauer 			cpin_uid[7] = usr->opal_key.lr + 1;
1532455a7b23SScott Bauer 		else
1533455a7b23SScott Bauer 			cpin_uid[7] = usr->who;
1534455a7b23SScott Bauer 	}
1535455a7b23SScott Bauer 
1536455a7b23SScott Bauer 	if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1537455a7b23SScott Bauer 			   cpin_uid, dev)) {
1538591c59d1SScott Bauer 		pr_debug("Error building set password command.\n");
1539455a7b23SScott Bauer 		return -ERANGE;
1540455a7b23SScott Bauer 	}
1541455a7b23SScott Bauer 
1542455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1543455a7b23SScott Bauer }
1544455a7b23SScott Bauer 
1545eed64951SJon Derrick static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
1546455a7b23SScott Bauer {
1547455a7b23SScott Bauer 	u8 cpin_uid[OPAL_UID_LENGTH];
1548eed64951SJon Derrick 	struct opal_key *key = data;
1549455a7b23SScott Bauer 
1550455a7b23SScott Bauer 	memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1551455a7b23SScott Bauer 
1552455a7b23SScott Bauer 	if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
1553591c59d1SScott Bauer 		pr_debug("Error building Set SID cpin\n");
1554455a7b23SScott Bauer 		return -ERANGE;
1555455a7b23SScott Bauer 	}
1556455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1557455a7b23SScott Bauer }
1558455a7b23SScott Bauer 
1559eed64951SJon Derrick static int add_user_to_lr(struct opal_dev *dev, void *data)
1560455a7b23SScott Bauer {
1561455a7b23SScott Bauer 	u8 lr_buffer[OPAL_UID_LENGTH];
1562455a7b23SScott Bauer 	u8 user_uid[OPAL_UID_LENGTH];
1563eed64951SJon Derrick 	struct opal_lock_unlock *lkul = data;
1564*e8b29224SDavid Kozub 	int err;
1565455a7b23SScott Bauer 
1566455a7b23SScott Bauer 	memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1567455a7b23SScott Bauer 	       OPAL_UID_LENGTH);
1568455a7b23SScott Bauer 
1569455a7b23SScott Bauer 	if (lkul->l_state == OPAL_RW)
1570455a7b23SScott Bauer 		memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1571455a7b23SScott Bauer 		       OPAL_UID_LENGTH);
1572455a7b23SScott Bauer 
1573455a7b23SScott Bauer 	lr_buffer[7] = lkul->session.opal_key.lr;
1574455a7b23SScott Bauer 
1575455a7b23SScott Bauer 	memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1576455a7b23SScott Bauer 
1577455a7b23SScott Bauer 	user_uid[7] = lkul->session.who;
1578455a7b23SScott Bauer 
1579*e8b29224SDavid Kozub 	err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
1580455a7b23SScott Bauer 
1581455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1582455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_VALUES);
1583455a7b23SScott Bauer 
1584455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1585455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1586455a7b23SScott Bauer 	add_token_u8(&err, dev, 3);
1587455a7b23SScott Bauer 
1588455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1589455a7b23SScott Bauer 
1590455a7b23SScott Bauer 
1591455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1592455a7b23SScott Bauer 	add_token_bytestring(&err, dev,
1593455a7b23SScott Bauer 			     opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1594455a7b23SScott Bauer 			     OPAL_UID_LENGTH/2);
1595455a7b23SScott Bauer 	add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1596455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1597455a7b23SScott Bauer 
1598455a7b23SScott Bauer 
1599455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1600455a7b23SScott Bauer 	add_token_bytestring(&err, dev,
1601455a7b23SScott Bauer 			     opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1602455a7b23SScott Bauer 			     OPAL_UID_LENGTH/2);
1603455a7b23SScott Bauer 	add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1604455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1605455a7b23SScott Bauer 
1606455a7b23SScott Bauer 
1607455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1608455a7b23SScott Bauer 	add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1609455a7b23SScott Bauer 			     OPAL_UID_LENGTH/2);
1610455a7b23SScott Bauer 	add_token_u8(&err, dev, 1);
1611455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1612455a7b23SScott Bauer 
1613455a7b23SScott Bauer 
1614455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1615455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1616455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1617455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1618455a7b23SScott Bauer 
1619455a7b23SScott Bauer 	if (err) {
1620591c59d1SScott Bauer 		pr_debug("Error building add user to locking range command.\n");
1621455a7b23SScott Bauer 		return err;
1622455a7b23SScott Bauer 	}
1623455a7b23SScott Bauer 
1624455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1625455a7b23SScott Bauer }
1626455a7b23SScott Bauer 
1627eed64951SJon Derrick static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
1628455a7b23SScott Bauer {
1629455a7b23SScott Bauer 	u8 lr_buffer[OPAL_UID_LENGTH];
1630eed64951SJon Derrick 	struct opal_lock_unlock *lkul = data;
1631455a7b23SScott Bauer 	u8 read_locked = 1, write_locked = 1;
1632455a7b23SScott Bauer 	int err = 0;
1633455a7b23SScott Bauer 
1634455a7b23SScott Bauer 	if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1635455a7b23SScott Bauer 				lkul->session.opal_key.lr) < 0)
1636455a7b23SScott Bauer 		return -ERANGE;
1637455a7b23SScott Bauer 
1638455a7b23SScott Bauer 	switch (lkul->l_state) {
1639455a7b23SScott Bauer 	case OPAL_RO:
1640455a7b23SScott Bauer 		read_locked = 0;
1641455a7b23SScott Bauer 		write_locked = 1;
1642455a7b23SScott Bauer 		break;
1643455a7b23SScott Bauer 	case OPAL_RW:
1644455a7b23SScott Bauer 		read_locked = 0;
1645455a7b23SScott Bauer 		write_locked = 0;
1646455a7b23SScott Bauer 		break;
1647455a7b23SScott Bauer 	case OPAL_LK:
16481e815b33SDavid Kozub 		/* vars are initialized to locked */
1649455a7b23SScott Bauer 		break;
1650455a7b23SScott Bauer 	default:
1651591c59d1SScott Bauer 		pr_debug("Tried to set an invalid locking state... returning to uland\n");
1652455a7b23SScott Bauer 		return OPAL_INVAL_PARAM;
1653455a7b23SScott Bauer 	}
1654455a7b23SScott Bauer 
1655*e8b29224SDavid Kozub 	err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
1656*e8b29224SDavid Kozub 
1657455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1658455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_VALUES);
1659455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1660455a7b23SScott Bauer 
1661455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1662455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_READLOCKED);
1663455a7b23SScott Bauer 	add_token_u8(&err, dev, read_locked);
1664455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1665455a7b23SScott Bauer 
1666455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1667455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_WRITELOCKED);
1668455a7b23SScott Bauer 	add_token_u8(&err, dev, write_locked);
1669455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1670455a7b23SScott Bauer 
1671455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1672455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1673455a7b23SScott Bauer 
1674455a7b23SScott Bauer 	if (err) {
1675591c59d1SScott Bauer 		pr_debug("Error building SET command.\n");
1676455a7b23SScott Bauer 		return err;
1677455a7b23SScott Bauer 	}
1678455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1679455a7b23SScott Bauer }
1680455a7b23SScott Bauer 
1681455a7b23SScott Bauer 
1682eed64951SJon Derrick static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
1683455a7b23SScott Bauer {
1684455a7b23SScott Bauer 	u8 lr_buffer[OPAL_UID_LENGTH];
1685455a7b23SScott Bauer 	u8 read_locked = 1, write_locked = 1;
1686eed64951SJon Derrick 	struct opal_lock_unlock *lkul = data;
1687455a7b23SScott Bauer 	int ret;
1688455a7b23SScott Bauer 
1689455a7b23SScott Bauer 	clear_opal_cmd(dev);
1690455a7b23SScott Bauer 	set_comid(dev, dev->comid);
1691455a7b23SScott Bauer 
1692455a7b23SScott Bauer 	if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1693455a7b23SScott Bauer 				lkul->session.opal_key.lr) < 0)
1694455a7b23SScott Bauer 		return -ERANGE;
1695455a7b23SScott Bauer 
1696455a7b23SScott Bauer 	switch (lkul->l_state) {
1697455a7b23SScott Bauer 	case OPAL_RO:
1698455a7b23SScott Bauer 		read_locked = 0;
1699455a7b23SScott Bauer 		write_locked = 1;
1700455a7b23SScott Bauer 		break;
1701455a7b23SScott Bauer 	case OPAL_RW:
1702455a7b23SScott Bauer 		read_locked = 0;
1703455a7b23SScott Bauer 		write_locked = 0;
1704455a7b23SScott Bauer 		break;
1705455a7b23SScott Bauer 	case OPAL_LK:
17061e815b33SDavid Kozub 		/* vars are initialized to locked */
1707455a7b23SScott Bauer 		break;
1708455a7b23SScott Bauer 	default:
1709591c59d1SScott Bauer 		pr_debug("Tried to set an invalid locking state.\n");
1710455a7b23SScott Bauer 		return OPAL_INVAL_PARAM;
1711455a7b23SScott Bauer 	}
1712455a7b23SScott Bauer 	ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1713455a7b23SScott Bauer 					read_locked, write_locked);
1714455a7b23SScott Bauer 
1715455a7b23SScott Bauer 	if (ret < 0) {
1716591c59d1SScott Bauer 		pr_debug("Error building SET command.\n");
1717455a7b23SScott Bauer 		return ret;
1718455a7b23SScott Bauer 	}
1719455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1720455a7b23SScott Bauer }
1721455a7b23SScott Bauer 
1722eed64951SJon Derrick static int activate_lsp(struct opal_dev *dev, void *data)
1723455a7b23SScott Bauer {
1724eed64951SJon Derrick 	struct opal_lr_act *opal_act = data;
1725455a7b23SScott Bauer 	u8 user_lr[OPAL_UID_LENGTH];
1726455a7b23SScott Bauer 	u8 uint_3 = 0x83;
1727*e8b29224SDavid Kozub 	int err, i;
1728455a7b23SScott Bauer 
1729*e8b29224SDavid Kozub 	err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID],
1730*e8b29224SDavid Kozub 			opalmethod[OPAL_ACTIVATE]);
1731455a7b23SScott Bauer 
1732455a7b23SScott Bauer 	if (opal_act->sum) {
1733455a7b23SScott Bauer 		err = build_locking_range(user_lr, sizeof(user_lr),
1734455a7b23SScott Bauer 					  opal_act->lr[0]);
1735455a7b23SScott Bauer 		if (err)
1736455a7b23SScott Bauer 			return err;
1737455a7b23SScott Bauer 
1738455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTNAME);
1739455a7b23SScott Bauer 		add_token_u8(&err, dev, uint_3);
1740455a7b23SScott Bauer 		add_token_u8(&err, dev, 6);
1741455a7b23SScott Bauer 		add_token_u8(&err, dev, 0);
1742455a7b23SScott Bauer 		add_token_u8(&err, dev, 0);
1743455a7b23SScott Bauer 
1744455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_STARTLIST);
1745455a7b23SScott Bauer 		add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1746455a7b23SScott Bauer 		for (i = 1; i < opal_act->num_lrs; i++) {
1747455a7b23SScott Bauer 			user_lr[7] = opal_act->lr[i];
1748455a7b23SScott Bauer 			add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1749455a7b23SScott Bauer 		}
1750455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDLIST);
1751455a7b23SScott Bauer 		add_token_u8(&err, dev, OPAL_ENDNAME);
1752455a7b23SScott Bauer 	}
1753455a7b23SScott Bauer 
1754455a7b23SScott Bauer 	if (err) {
1755591c59d1SScott Bauer 		pr_debug("Error building Activate LockingSP command.\n");
1756455a7b23SScott Bauer 		return err;
1757455a7b23SScott Bauer 	}
1758455a7b23SScott Bauer 
1759455a7b23SScott Bauer 	return finalize_and_send(dev, parse_and_check_status);
1760455a7b23SScott Bauer }
1761455a7b23SScott Bauer 
1762455a7b23SScott Bauer static int get_lsp_lifecycle_cont(struct opal_dev *dev)
1763455a7b23SScott Bauer {
1764455a7b23SScott Bauer 	u8 lc_status;
1765455a7b23SScott Bauer 	int error = 0;
1766455a7b23SScott Bauer 
1767455a7b23SScott Bauer 	error = parse_and_check_status(dev);
1768455a7b23SScott Bauer 	if (error)
1769455a7b23SScott Bauer 		return error;
1770455a7b23SScott Bauer 
1771455a7b23SScott Bauer 	lc_status = response_get_u64(&dev->parsed, 4);
17721e815b33SDavid Kozub 	/* 0x08 is Manufactured Inactive */
1773455a7b23SScott Bauer 	/* 0x09 is Manufactured */
1774455a7b23SScott Bauer 	if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
1775591c59d1SScott Bauer 		pr_debug("Couldn't determine the status of the Lifecycle state\n");
1776455a7b23SScott Bauer 		return -ENODEV;
1777455a7b23SScott Bauer 	}
1778455a7b23SScott Bauer 
1779455a7b23SScott Bauer 	return 0;
1780455a7b23SScott Bauer }
1781455a7b23SScott Bauer 
1782455a7b23SScott Bauer /* Determine if we're in the Manufactured Inactive or Active state */
1783eed64951SJon Derrick static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
1784455a7b23SScott Bauer {
1785*e8b29224SDavid Kozub 	int err;
1786455a7b23SScott Bauer 
1787*e8b29224SDavid Kozub 	err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID],
1788*e8b29224SDavid Kozub 			opalmethod[OPAL_GET]);
1789455a7b23SScott Bauer 
1790455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1791455a7b23SScott Bauer 
1792455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1793455a7b23SScott Bauer 	add_token_u8(&err, dev, 3); /* Start Column */
1794455a7b23SScott Bauer 	add_token_u8(&err, dev, 6); /* Lifecycle Column */
1795455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1796455a7b23SScott Bauer 
1797455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1798455a7b23SScott Bauer 	add_token_u8(&err, dev, 4); /* End Column */
1799455a7b23SScott Bauer 	add_token_u8(&err, dev, 6); /* Lifecycle Column */
1800455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1801455a7b23SScott Bauer 
1802455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1803455a7b23SScott Bauer 
1804455a7b23SScott Bauer 	if (err) {
1805591c59d1SScott Bauer 		pr_debug("Error Building GET Lifecycle Status command\n");
1806455a7b23SScott Bauer 		return err;
1807455a7b23SScott Bauer 	}
1808455a7b23SScott Bauer 
1809455a7b23SScott Bauer 	return finalize_and_send(dev, get_lsp_lifecycle_cont);
1810455a7b23SScott Bauer }
1811455a7b23SScott Bauer 
1812455a7b23SScott Bauer static int get_msid_cpin_pin_cont(struct opal_dev *dev)
1813455a7b23SScott Bauer {
1814455a7b23SScott Bauer 	const char *msid_pin;
1815455a7b23SScott Bauer 	size_t strlen;
1816455a7b23SScott Bauer 	int error = 0;
1817455a7b23SScott Bauer 
1818455a7b23SScott Bauer 	error = parse_and_check_status(dev);
1819455a7b23SScott Bauer 	if (error)
1820455a7b23SScott Bauer 		return error;
1821455a7b23SScott Bauer 
1822455a7b23SScott Bauer 	strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1823455a7b23SScott Bauer 	if (!msid_pin) {
1824591c59d1SScott Bauer 		pr_debug("%s: Couldn't extract PIN from response\n", __func__);
1825455a7b23SScott Bauer 		return OPAL_INVAL_PARAM;
1826455a7b23SScott Bauer 	}
1827455a7b23SScott Bauer 
1828455a7b23SScott Bauer 	dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1829455a7b23SScott Bauer 	if (!dev->prev_data)
1830455a7b23SScott Bauer 		return -ENOMEM;
1831455a7b23SScott Bauer 
1832455a7b23SScott Bauer 	dev->prev_d_len = strlen;
1833455a7b23SScott Bauer 
1834455a7b23SScott Bauer 	return 0;
1835455a7b23SScott Bauer }
1836455a7b23SScott Bauer 
1837eed64951SJon Derrick static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
1838455a7b23SScott Bauer {
1839*e8b29224SDavid Kozub 	int err;
1840455a7b23SScott Bauer 
1841*e8b29224SDavid Kozub 	err = cmd_start(dev, opaluid[OPAL_C_PIN_MSID],
1842*e8b29224SDavid Kozub 			opalmethod[OPAL_GET]);
1843455a7b23SScott Bauer 
1844455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTLIST);
1845455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1846455a7b23SScott Bauer 	add_token_u8(&err, dev, 3); /* Start Column */
1847455a7b23SScott Bauer 	add_token_u8(&err, dev, 3); /* PIN */
1848455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1849455a7b23SScott Bauer 
1850455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_STARTNAME);
1851455a7b23SScott Bauer 	add_token_u8(&err, dev, 4); /* End Column */
1852455a7b23SScott Bauer 	add_token_u8(&err, dev, 3); /* Lifecycle Column */
1853455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDNAME);
1854455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDLIST);
1855455a7b23SScott Bauer 
1856455a7b23SScott Bauer 	if (err) {
1857591c59d1SScott Bauer 		pr_debug("Error building Get MSID CPIN PIN command.\n");
1858455a7b23SScott Bauer 		return err;
1859455a7b23SScott Bauer 	}
1860455a7b23SScott Bauer 
1861455a7b23SScott Bauer 	return finalize_and_send(dev, get_msid_cpin_pin_cont);
1862455a7b23SScott Bauer }
1863455a7b23SScott Bauer 
1864eed64951SJon Derrick static int end_opal_session(struct opal_dev *dev, void *data)
1865455a7b23SScott Bauer {
1866455a7b23SScott Bauer 	int err = 0;
1867455a7b23SScott Bauer 
1868455a7b23SScott Bauer 	clear_opal_cmd(dev);
1869455a7b23SScott Bauer 	set_comid(dev, dev->comid);
1870455a7b23SScott Bauer 	add_token_u8(&err, dev, OPAL_ENDOFSESSION);
1871eed64951SJon Derrick 
1872eed64951SJon Derrick 	if (err < 0)
1873455a7b23SScott Bauer 		return err;
1874455a7b23SScott Bauer 	return finalize_and_send(dev, end_session_cont);
1875455a7b23SScott Bauer }
1876455a7b23SScott Bauer 
1877455a7b23SScott Bauer static int end_opal_session_error(struct opal_dev *dev)
1878455a7b23SScott Bauer {
1879eed64951SJon Derrick 	const struct opal_step error_end_session[] = {
1880eed64951SJon Derrick 		{ end_opal_session, },
1881eed64951SJon Derrick 		{ NULL, }
1882455a7b23SScott Bauer 	};
1883eed64951SJon Derrick 	dev->steps = error_end_session;
1884455a7b23SScott Bauer 	return next(dev);
1885455a7b23SScott Bauer }
1886455a7b23SScott Bauer 
1887455a7b23SScott Bauer static inline void setup_opal_dev(struct opal_dev *dev,
1888eed64951SJon Derrick 				  const struct opal_step *steps)
1889455a7b23SScott Bauer {
1890eed64951SJon Derrick 	dev->steps = steps;
1891455a7b23SScott Bauer 	dev->tsn = 0;
1892455a7b23SScott Bauer 	dev->hsn = 0;
1893455a7b23SScott Bauer 	dev->prev_data = NULL;
1894455a7b23SScott Bauer }
1895455a7b23SScott Bauer 
1896455a7b23SScott Bauer static int check_opal_support(struct opal_dev *dev)
1897455a7b23SScott Bauer {
1898eed64951SJon Derrick 	const struct opal_step steps[] = {
1899eed64951SJon Derrick 		{ opal_discovery0, },
1900eed64951SJon Derrick 		{ NULL, }
1901455a7b23SScott Bauer 	};
1902455a7b23SScott Bauer 	int ret;
1903455a7b23SScott Bauer 
1904455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
1905eed64951SJon Derrick 	setup_opal_dev(dev, steps);
1906455a7b23SScott Bauer 	ret = next(dev);
1907455a7b23SScott Bauer 	dev->supported = !ret;
1908455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
1909455a7b23SScott Bauer 	return ret;
1910455a7b23SScott Bauer }
1911455a7b23SScott Bauer 
19127d6d1578SScott Bauer static void clean_opal_dev(struct opal_dev *dev)
19137d6d1578SScott Bauer {
19147d6d1578SScott Bauer 
19157d6d1578SScott Bauer 	struct opal_suspend_data *suspend, *next;
19167d6d1578SScott Bauer 
19177d6d1578SScott Bauer 	mutex_lock(&dev->dev_lock);
19187d6d1578SScott Bauer 	list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
19197d6d1578SScott Bauer 		list_del(&suspend->node);
19207d6d1578SScott Bauer 		kfree(suspend);
19217d6d1578SScott Bauer 	}
19227d6d1578SScott Bauer 	mutex_unlock(&dev->dev_lock);
19237d6d1578SScott Bauer }
19247d6d1578SScott Bauer 
19257d6d1578SScott Bauer void free_opal_dev(struct opal_dev *dev)
19267d6d1578SScott Bauer {
19277d6d1578SScott Bauer 	if (!dev)
19287d6d1578SScott Bauer 		return;
19297d6d1578SScott Bauer 	clean_opal_dev(dev);
19307d6d1578SScott Bauer 	kfree(dev);
19317d6d1578SScott Bauer }
19327d6d1578SScott Bauer EXPORT_SYMBOL(free_opal_dev);
19337d6d1578SScott Bauer 
19344f1244c8SChristoph Hellwig struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
1935455a7b23SScott Bauer {
19364f1244c8SChristoph Hellwig 	struct opal_dev *dev;
19374f1244c8SChristoph Hellwig 
19384f1244c8SChristoph Hellwig 	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
19394f1244c8SChristoph Hellwig 	if (!dev)
19404f1244c8SChristoph Hellwig 		return NULL;
19414f1244c8SChristoph Hellwig 
19424f1244c8SChristoph Hellwig 	INIT_LIST_HEAD(&dev->unlk_lst);
19434f1244c8SChristoph Hellwig 	mutex_init(&dev->dev_lock);
19444f1244c8SChristoph Hellwig 	dev->data = data;
19454f1244c8SChristoph Hellwig 	dev->send_recv = send_recv;
19464f1244c8SChristoph Hellwig 	if (check_opal_support(dev) != 0) {
1947f5b37b7cSChristoph Hellwig 		pr_debug("Opal is not supported on this device\n");
19484f1244c8SChristoph Hellwig 		kfree(dev);
19494f1244c8SChristoph Hellwig 		return NULL;
19504f1244c8SChristoph Hellwig 	}
19514f1244c8SChristoph Hellwig 	return dev;
1952455a7b23SScott Bauer }
1953455a7b23SScott Bauer EXPORT_SYMBOL(init_opal_dev);
1954455a7b23SScott Bauer 
1955455a7b23SScott Bauer static int opal_secure_erase_locking_range(struct opal_dev *dev,
1956455a7b23SScott Bauer 					   struct opal_session_info *opal_session)
1957455a7b23SScott Bauer {
1958eed64951SJon Derrick 	const struct opal_step erase_steps[] = {
1959eed64951SJon Derrick 		{ opal_discovery0, },
1960eed64951SJon Derrick 		{ start_auth_opal_session, opal_session },
1961eed64951SJon Derrick 		{ get_active_key, &opal_session->opal_key.lr },
1962eed64951SJon Derrick 		{ gen_key, },
1963eed64951SJon Derrick 		{ end_opal_session, },
1964eed64951SJon Derrick 		{ NULL, }
1965455a7b23SScott Bauer 	};
1966455a7b23SScott Bauer 	int ret;
1967455a7b23SScott Bauer 
1968455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
1969eed64951SJon Derrick 	setup_opal_dev(dev, erase_steps);
1970455a7b23SScott Bauer 	ret = next(dev);
1971455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
1972455a7b23SScott Bauer 	return ret;
1973455a7b23SScott Bauer }
1974455a7b23SScott Bauer 
1975455a7b23SScott Bauer static int opal_erase_locking_range(struct opal_dev *dev,
1976455a7b23SScott Bauer 				    struct opal_session_info *opal_session)
1977455a7b23SScott Bauer {
1978eed64951SJon Derrick 	const struct opal_step erase_steps[] = {
1979eed64951SJon Derrick 		{ opal_discovery0, },
1980eed64951SJon Derrick 		{ start_auth_opal_session, opal_session },
1981eed64951SJon Derrick 		{ erase_locking_range, opal_session },
1982eed64951SJon Derrick 		{ end_opal_session, },
1983eed64951SJon Derrick 		{ NULL, }
1984455a7b23SScott Bauer 	};
1985455a7b23SScott Bauer 	int ret;
1986455a7b23SScott Bauer 
1987455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
1988eed64951SJon Derrick 	setup_opal_dev(dev, erase_steps);
1989455a7b23SScott Bauer 	ret = next(dev);
1990455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
1991455a7b23SScott Bauer 	return ret;
1992455a7b23SScott Bauer }
1993455a7b23SScott Bauer 
1994455a7b23SScott Bauer static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
1995455a7b23SScott Bauer 					  struct opal_mbr_data *opal_mbr)
1996455a7b23SScott Bauer {
199778bf4735SDavid Kozub 	u8 enable_disable = opal_mbr->enable_disable == OPAL_MBR_ENABLE ?
199878bf4735SDavid Kozub 		OPAL_TRUE : OPAL_FALSE;
199978bf4735SDavid Kozub 
2000eed64951SJon Derrick 	const struct opal_step mbr_steps[] = {
2001eed64951SJon Derrick 		{ opal_discovery0, },
2002eed64951SJon Derrick 		{ start_admin1LSP_opal_session, &opal_mbr->key },
200378bf4735SDavid Kozub 		{ set_mbr_done, &enable_disable },
2004eed64951SJon Derrick 		{ end_opal_session, },
2005eed64951SJon Derrick 		{ start_admin1LSP_opal_session, &opal_mbr->key },
200678bf4735SDavid Kozub 		{ set_mbr_enable_disable, &enable_disable },
2007eed64951SJon Derrick 		{ end_opal_session, },
2008eed64951SJon Derrick 		{ NULL, }
2009455a7b23SScott Bauer 	};
2010455a7b23SScott Bauer 	int ret;
2011455a7b23SScott Bauer 
2012455a7b23SScott Bauer 	if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
2013455a7b23SScott Bauer 	    opal_mbr->enable_disable != OPAL_MBR_DISABLE)
2014455a7b23SScott Bauer 		return -EINVAL;
2015455a7b23SScott Bauer 
2016455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2017eed64951SJon Derrick 	setup_opal_dev(dev, mbr_steps);
2018455a7b23SScott Bauer 	ret = next(dev);
2019455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2020455a7b23SScott Bauer 	return ret;
2021455a7b23SScott Bauer }
2022455a7b23SScott Bauer 
2023455a7b23SScott Bauer static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
2024455a7b23SScott Bauer {
2025455a7b23SScott Bauer 	struct opal_suspend_data *suspend;
2026455a7b23SScott Bauer 
2027455a7b23SScott Bauer 	suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
2028455a7b23SScott Bauer 	if (!suspend)
2029455a7b23SScott Bauer 		return -ENOMEM;
2030455a7b23SScott Bauer 
2031455a7b23SScott Bauer 	suspend->unlk = *lk_unlk;
2032455a7b23SScott Bauer 	suspend->lr = lk_unlk->session.opal_key.lr;
2033455a7b23SScott Bauer 
2034455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2035455a7b23SScott Bauer 	setup_opal_dev(dev, NULL);
2036455a7b23SScott Bauer 	add_suspend_info(dev, suspend);
2037455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2038455a7b23SScott Bauer 	return 0;
2039455a7b23SScott Bauer }
2040455a7b23SScott Bauer 
2041455a7b23SScott Bauer static int opal_add_user_to_lr(struct opal_dev *dev,
2042455a7b23SScott Bauer 			       struct opal_lock_unlock *lk_unlk)
2043455a7b23SScott Bauer {
2044eed64951SJon Derrick 	const struct opal_step steps[] = {
2045eed64951SJon Derrick 		{ opal_discovery0, },
2046eed64951SJon Derrick 		{ start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2047eed64951SJon Derrick 		{ add_user_to_lr, lk_unlk },
2048eed64951SJon Derrick 		{ end_opal_session, },
2049eed64951SJon Derrick 		{ NULL, }
2050455a7b23SScott Bauer 	};
2051455a7b23SScott Bauer 	int ret;
2052455a7b23SScott Bauer 
2053455a7b23SScott Bauer 	if (lk_unlk->l_state != OPAL_RO &&
2054455a7b23SScott Bauer 	    lk_unlk->l_state != OPAL_RW) {
2055591c59d1SScott Bauer 		pr_debug("Locking state was not RO or RW\n");
2056455a7b23SScott Bauer 		return -EINVAL;
2057455a7b23SScott Bauer 	}
2058b0bfdfc2SJon Derrick 	if (lk_unlk->session.who < OPAL_USER1 ||
2059455a7b23SScott Bauer 	    lk_unlk->session.who > OPAL_USER9) {
2060591c59d1SScott Bauer 		pr_debug("Authority was not within the range of users: %d\n",
2061455a7b23SScott Bauer 			 lk_unlk->session.who);
2062455a7b23SScott Bauer 		return -EINVAL;
2063455a7b23SScott Bauer 	}
2064455a7b23SScott Bauer 	if (lk_unlk->session.sum) {
2065591c59d1SScott Bauer 		pr_debug("%s not supported in sum. Use setup locking range\n",
2066455a7b23SScott Bauer 			 __func__);
2067455a7b23SScott Bauer 		return -EINVAL;
2068455a7b23SScott Bauer 	}
2069455a7b23SScott Bauer 
2070455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2071eed64951SJon Derrick 	setup_opal_dev(dev, steps);
2072455a7b23SScott Bauer 	ret = next(dev);
2073455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2074455a7b23SScott Bauer 	return ret;
2075455a7b23SScott Bauer }
2076455a7b23SScott Bauer 
2077455a7b23SScott Bauer static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal)
2078455a7b23SScott Bauer {
2079eed64951SJon Derrick 	const struct opal_step revert_steps[] = {
2080eed64951SJon Derrick 		{ opal_discovery0, },
2081eed64951SJon Derrick 		{ start_SIDASP_opal_session, opal },
2082eed64951SJon Derrick 		{ revert_tper, }, /* controller will terminate session */
2083eed64951SJon Derrick 		{ NULL, }
2084455a7b23SScott Bauer 	};
2085455a7b23SScott Bauer 	int ret;
2086455a7b23SScott Bauer 
2087455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2088eed64951SJon Derrick 	setup_opal_dev(dev, revert_steps);
2089455a7b23SScott Bauer 	ret = next(dev);
2090455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
20917d6d1578SScott Bauer 
20927d6d1578SScott Bauer 	/*
20937d6d1578SScott Bauer 	 * If we successfully reverted lets clean
20947d6d1578SScott Bauer 	 * any saved locking ranges.
20957d6d1578SScott Bauer 	 */
20967d6d1578SScott Bauer 	if (!ret)
20977d6d1578SScott Bauer 		clean_opal_dev(dev);
20987d6d1578SScott Bauer 
2099455a7b23SScott Bauer 	return ret;
2100455a7b23SScott Bauer }
2101455a7b23SScott Bauer 
2102eed64951SJon Derrick static int __opal_lock_unlock(struct opal_dev *dev,
2103eed64951SJon Derrick 			      struct opal_lock_unlock *lk_unlk)
2104455a7b23SScott Bauer {
2105eed64951SJon Derrick 	const struct opal_step unlock_steps[] = {
2106eed64951SJon Derrick 		{ opal_discovery0, },
2107eed64951SJon Derrick 		{ start_auth_opal_session, &lk_unlk->session },
2108eed64951SJon Derrick 		{ lock_unlock_locking_range, lk_unlk },
2109eed64951SJon Derrick 		{ end_opal_session, },
2110eed64951SJon Derrick 		{ NULL, }
2111eed64951SJon Derrick 	};
2112eed64951SJon Derrick 	const struct opal_step unlock_sum_steps[] = {
2113eed64951SJon Derrick 		{ opal_discovery0, },
2114eed64951SJon Derrick 		{ start_auth_opal_session, &lk_unlk->session },
2115eed64951SJon Derrick 		{ lock_unlock_locking_range_sum, lk_unlk },
2116eed64951SJon Derrick 		{ end_opal_session, },
2117eed64951SJon Derrick 		{ NULL, }
2118455a7b23SScott Bauer 	};
2119455a7b23SScott Bauer 
2120eed64951SJon Derrick 	dev->steps = lk_unlk->session.sum ? unlock_sum_steps : unlock_steps;
2121455a7b23SScott Bauer 	return next(dev);
2122455a7b23SScott Bauer }
2123455a7b23SScott Bauer 
2124dbec491bSScott Bauer static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2125dbec491bSScott Bauer {
212678bf4735SDavid Kozub 	u8 mbr_done_tf = OPAL_TRUE;
2127dbec491bSScott Bauer 	const struct opal_step mbrdone_step[] = {
2128dbec491bSScott Bauer 		{ opal_discovery0, },
2129dbec491bSScott Bauer 		{ start_admin1LSP_opal_session, key },
2130dbec491bSScott Bauer 		{ set_mbr_done, &mbr_done_tf },
2131dbec491bSScott Bauer 		{ end_opal_session, },
2132dbec491bSScott Bauer 		{ NULL, }
2133dbec491bSScott Bauer 	};
2134dbec491bSScott Bauer 
2135dbec491bSScott Bauer 	dev->steps = mbrdone_step;
2136dbec491bSScott Bauer 	return next(dev);
2137dbec491bSScott Bauer }
2138dbec491bSScott Bauer 
2139eed64951SJon Derrick static int opal_lock_unlock(struct opal_dev *dev,
2140eed64951SJon Derrick 			    struct opal_lock_unlock *lk_unlk)
2141455a7b23SScott Bauer {
2142455a7b23SScott Bauer 	int ret;
2143455a7b23SScott Bauer 
2144455a7b23SScott Bauer 	if (lk_unlk->session.who < OPAL_ADMIN1 ||
2145455a7b23SScott Bauer 	    lk_unlk->session.who > OPAL_USER9)
2146455a7b23SScott Bauer 		return -EINVAL;
2147455a7b23SScott Bauer 
2148455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2149eed64951SJon Derrick 	ret = __opal_lock_unlock(dev, lk_unlk);
2150455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2151455a7b23SScott Bauer 	return ret;
2152455a7b23SScott Bauer }
2153455a7b23SScott Bauer 
2154455a7b23SScott Bauer static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2155455a7b23SScott Bauer {
2156eed64951SJon Derrick 	const struct opal_step owner_steps[] = {
2157eed64951SJon Derrick 		{ opal_discovery0, },
2158eed64951SJon Derrick 		{ start_anybodyASP_opal_session, },
2159eed64951SJon Derrick 		{ get_msid_cpin_pin, },
2160eed64951SJon Derrick 		{ end_opal_session, },
2161eed64951SJon Derrick 		{ start_SIDASP_opal_session, opal },
2162eed64951SJon Derrick 		{ set_sid_cpin_pin, opal },
2163eed64951SJon Derrick 		{ end_opal_session, },
2164eed64951SJon Derrick 		{ NULL, }
2165455a7b23SScott Bauer 	};
2166455a7b23SScott Bauer 	int ret;
2167455a7b23SScott Bauer 
2168455a7b23SScott Bauer 	if (!dev)
2169455a7b23SScott Bauer 		return -ENODEV;
2170455a7b23SScott Bauer 
2171455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2172eed64951SJon Derrick 	setup_opal_dev(dev, owner_steps);
2173455a7b23SScott Bauer 	ret = next(dev);
2174455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2175455a7b23SScott Bauer 	return ret;
2176455a7b23SScott Bauer }
2177455a7b23SScott Bauer 
21781e815b33SDavid Kozub static int opal_activate_lsp(struct opal_dev *dev,
21791e815b33SDavid Kozub 			     struct opal_lr_act *opal_lr_act)
2180455a7b23SScott Bauer {
2181eed64951SJon Derrick 	const struct opal_step active_steps[] = {
2182eed64951SJon Derrick 		{ opal_discovery0, },
2183eed64951SJon Derrick 		{ start_SIDASP_opal_session, &opal_lr_act->key },
2184eed64951SJon Derrick 		{ get_lsp_lifecycle, },
2185eed64951SJon Derrick 		{ activate_lsp, opal_lr_act },
2186eed64951SJon Derrick 		{ end_opal_session, },
2187eed64951SJon Derrick 		{ NULL, }
2188455a7b23SScott Bauer 	};
2189455a7b23SScott Bauer 	int ret;
2190455a7b23SScott Bauer 
2191455a7b23SScott Bauer 	if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2192455a7b23SScott Bauer 		return -EINVAL;
2193455a7b23SScott Bauer 
2194455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2195eed64951SJon Derrick 	setup_opal_dev(dev, active_steps);
2196455a7b23SScott Bauer 	ret = next(dev);
2197455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2198455a7b23SScott Bauer 	return ret;
2199455a7b23SScott Bauer }
2200455a7b23SScott Bauer 
2201455a7b23SScott Bauer static int opal_setup_locking_range(struct opal_dev *dev,
2202455a7b23SScott Bauer 				    struct opal_user_lr_setup *opal_lrs)
2203455a7b23SScott Bauer {
2204eed64951SJon Derrick 	const struct opal_step lr_steps[] = {
2205eed64951SJon Derrick 		{ opal_discovery0, },
2206eed64951SJon Derrick 		{ start_auth_opal_session, &opal_lrs->session },
2207eed64951SJon Derrick 		{ setup_locking_range, opal_lrs },
2208eed64951SJon Derrick 		{ end_opal_session, },
2209eed64951SJon Derrick 		{ NULL, }
2210455a7b23SScott Bauer 	};
2211455a7b23SScott Bauer 	int ret;
2212455a7b23SScott Bauer 
2213455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2214eed64951SJon Derrick 	setup_opal_dev(dev, lr_steps);
2215455a7b23SScott Bauer 	ret = next(dev);
2216455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2217455a7b23SScott Bauer 	return ret;
2218455a7b23SScott Bauer }
2219455a7b23SScott Bauer 
2220455a7b23SScott Bauer static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2221455a7b23SScott Bauer {
2222eed64951SJon Derrick 	const struct opal_step pw_steps[] = {
2223eed64951SJon Derrick 		{ opal_discovery0, },
2224eed64951SJon Derrick 		{ start_auth_opal_session, &opal_pw->session },
2225eed64951SJon Derrick 		{ set_new_pw, &opal_pw->new_user_pw },
2226eed64951SJon Derrick 		{ end_opal_session, },
2227eed64951SJon Derrick 		{ NULL }
2228455a7b23SScott Bauer 	};
2229455a7b23SScott Bauer 	int ret;
2230455a7b23SScott Bauer 
2231455a7b23SScott Bauer 	if (opal_pw->session.who < OPAL_ADMIN1 ||
2232455a7b23SScott Bauer 	    opal_pw->session.who > OPAL_USER9  ||
2233455a7b23SScott Bauer 	    opal_pw->new_user_pw.who < OPAL_ADMIN1 ||
2234455a7b23SScott Bauer 	    opal_pw->new_user_pw.who > OPAL_USER9)
2235455a7b23SScott Bauer 		return -EINVAL;
2236455a7b23SScott Bauer 
2237455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2238eed64951SJon Derrick 	setup_opal_dev(dev, pw_steps);
2239455a7b23SScott Bauer 	ret = next(dev);
2240455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2241455a7b23SScott Bauer 	return ret;
2242455a7b23SScott Bauer }
2243455a7b23SScott Bauer 
2244455a7b23SScott Bauer static int opal_activate_user(struct opal_dev *dev,
2245455a7b23SScott Bauer 			      struct opal_session_info *opal_session)
2246455a7b23SScott Bauer {
2247eed64951SJon Derrick 	const struct opal_step act_steps[] = {
2248eed64951SJon Derrick 		{ opal_discovery0, },
2249eed64951SJon Derrick 		{ start_admin1LSP_opal_session, &opal_session->opal_key },
2250eed64951SJon Derrick 		{ internal_activate_user, opal_session },
2251eed64951SJon Derrick 		{ end_opal_session, },
2252eed64951SJon Derrick 		{ NULL, }
2253455a7b23SScott Bauer 	};
2254455a7b23SScott Bauer 	int ret;
2255455a7b23SScott Bauer 
2256455a7b23SScott Bauer 	/* We can't activate Admin1 it's active as manufactured */
2257b0bfdfc2SJon Derrick 	if (opal_session->who < OPAL_USER1 ||
2258455a7b23SScott Bauer 	    opal_session->who > OPAL_USER9) {
2259591c59d1SScott Bauer 		pr_debug("Who was not a valid user: %d\n", opal_session->who);
2260455a7b23SScott Bauer 		return -EINVAL;
2261455a7b23SScott Bauer 	}
2262455a7b23SScott Bauer 
2263455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2264eed64951SJon Derrick 	setup_opal_dev(dev, act_steps);
2265455a7b23SScott Bauer 	ret = next(dev);
2266455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2267455a7b23SScott Bauer 	return ret;
2268455a7b23SScott Bauer }
2269455a7b23SScott Bauer 
2270455a7b23SScott Bauer bool opal_unlock_from_suspend(struct opal_dev *dev)
2271455a7b23SScott Bauer {
2272455a7b23SScott Bauer 	struct opal_suspend_data *suspend;
2273455a7b23SScott Bauer 	bool was_failure = false;
2274455a7b23SScott Bauer 	int ret = 0;
2275455a7b23SScott Bauer 
2276455a7b23SScott Bauer 	if (!dev)
2277455a7b23SScott Bauer 		return false;
2278455a7b23SScott Bauer 	if (!dev->supported)
2279455a7b23SScott Bauer 		return false;
2280455a7b23SScott Bauer 
2281455a7b23SScott Bauer 	mutex_lock(&dev->dev_lock);
2282455a7b23SScott Bauer 	setup_opal_dev(dev, NULL);
2283455a7b23SScott Bauer 
2284455a7b23SScott Bauer 	list_for_each_entry(suspend, &dev->unlk_lst, node) {
2285455a7b23SScott Bauer 		dev->tsn = 0;
2286455a7b23SScott Bauer 		dev->hsn = 0;
2287455a7b23SScott Bauer 
2288eed64951SJon Derrick 		ret = __opal_lock_unlock(dev, &suspend->unlk);
2289455a7b23SScott Bauer 		if (ret) {
2290591c59d1SScott Bauer 			pr_debug("Failed to unlock LR %hhu with sum %d\n",
2291455a7b23SScott Bauer 				 suspend->unlk.session.opal_key.lr,
2292455a7b23SScott Bauer 				 suspend->unlk.session.sum);
2293455a7b23SScott Bauer 			was_failure = true;
2294455a7b23SScott Bauer 		}
2295dbec491bSScott Bauer 		if (dev->mbr_enabled) {
2296dbec491bSScott Bauer 			ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
2297dbec491bSScott Bauer 			if (ret)
2298dbec491bSScott Bauer 				pr_debug("Failed to set MBR Done in S3 resume\n");
2299dbec491bSScott Bauer 		}
2300455a7b23SScott Bauer 	}
2301455a7b23SScott Bauer 	mutex_unlock(&dev->dev_lock);
2302455a7b23SScott Bauer 	return was_failure;
2303455a7b23SScott Bauer }
2304455a7b23SScott Bauer EXPORT_SYMBOL(opal_unlock_from_suspend);
2305455a7b23SScott Bauer 
2306e225c20eSScott Bauer int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
2307455a7b23SScott Bauer {
2308e225c20eSScott Bauer 	void *p;
2309e225c20eSScott Bauer 	int ret = -ENOTTY;
2310455a7b23SScott Bauer 
2311455a7b23SScott Bauer 	if (!capable(CAP_SYS_ADMIN))
2312455a7b23SScott Bauer 		return -EACCES;
23134f1244c8SChristoph Hellwig 	if (!dev)
23144f1244c8SChristoph Hellwig 		return -ENOTSUPP;
2315591c59d1SScott Bauer 	if (!dev->supported)
2316455a7b23SScott Bauer 		return -ENOTSUPP;
2317455a7b23SScott Bauer 
2318e225c20eSScott Bauer 	p = memdup_user(arg, _IOC_SIZE(cmd));
2319e225c20eSScott Bauer 	if (IS_ERR(p))
2320e225c20eSScott Bauer 		return PTR_ERR(p);
2321e225c20eSScott Bauer 
2322455a7b23SScott Bauer 	switch (cmd) {
2323e225c20eSScott Bauer 	case IOC_OPAL_SAVE:
2324e225c20eSScott Bauer 		ret = opal_save(dev, p);
2325e225c20eSScott Bauer 		break;
2326e225c20eSScott Bauer 	case IOC_OPAL_LOCK_UNLOCK:
2327e225c20eSScott Bauer 		ret = opal_lock_unlock(dev, p);
2328e225c20eSScott Bauer 		break;
2329e225c20eSScott Bauer 	case IOC_OPAL_TAKE_OWNERSHIP:
2330e225c20eSScott Bauer 		ret = opal_take_ownership(dev, p);
2331e225c20eSScott Bauer 		break;
2332e225c20eSScott Bauer 	case IOC_OPAL_ACTIVATE_LSP:
2333e225c20eSScott Bauer 		ret = opal_activate_lsp(dev, p);
2334e225c20eSScott Bauer 		break;
2335e225c20eSScott Bauer 	case IOC_OPAL_SET_PW:
2336e225c20eSScott Bauer 		ret = opal_set_new_pw(dev, p);
2337e225c20eSScott Bauer 		break;
2338e225c20eSScott Bauer 	case IOC_OPAL_ACTIVATE_USR:
2339e225c20eSScott Bauer 		ret = opal_activate_user(dev, p);
2340e225c20eSScott Bauer 		break;
2341e225c20eSScott Bauer 	case IOC_OPAL_REVERT_TPR:
2342e225c20eSScott Bauer 		ret = opal_reverttper(dev, p);
2343e225c20eSScott Bauer 		break;
2344e225c20eSScott Bauer 	case IOC_OPAL_LR_SETUP:
2345e225c20eSScott Bauer 		ret = opal_setup_locking_range(dev, p);
2346e225c20eSScott Bauer 		break;
2347e225c20eSScott Bauer 	case IOC_OPAL_ADD_USR_TO_LR:
2348e225c20eSScott Bauer 		ret = opal_add_user_to_lr(dev, p);
2349e225c20eSScott Bauer 		break;
2350e225c20eSScott Bauer 	case IOC_OPAL_ENABLE_DISABLE_MBR:
2351e225c20eSScott Bauer 		ret = opal_enable_disable_shadow_mbr(dev, p);
2352e225c20eSScott Bauer 		break;
2353e225c20eSScott Bauer 	case IOC_OPAL_ERASE_LR:
2354e225c20eSScott Bauer 		ret = opal_erase_locking_range(dev, p);
2355e225c20eSScott Bauer 		break;
2356e225c20eSScott Bauer 	case IOC_OPAL_SECURE_ERASE_LR:
2357e225c20eSScott Bauer 		ret = opal_secure_erase_locking_range(dev, p);
2358e225c20eSScott Bauer 		break;
2359455a7b23SScott Bauer 	default:
2360591c59d1SScott Bauer 		break;
2361455a7b23SScott Bauer 	}
2362e225c20eSScott Bauer 
2363e225c20eSScott Bauer 	kfree(p);
2364e225c20eSScott Bauer 	return ret;
2365455a7b23SScott Bauer }
2366455a7b23SScott Bauer EXPORT_SYMBOL_GPL(sed_ioctl);
2367