blob: 7e1a444a25b2372967ad0aac0bb3a3a2d44238dd [file] [log] [blame]
Christoph Hellwig8c165672019-04-30 14:42:39 -04001// SPDX-License-Identifier: GPL-2.0
Scott Bauer455a7b22017-02-03 12:50:31 -07002/*
3 * Copyright © 2016 Intel Corporation
4 *
5 * Authors:
6 * Scott Bauer <scott.bauer@intel.com>
7 * Rafael Antognolli <rafael.antognolli@intel.com>
Scott Bauer455a7b22017-02-03 12:50:31 -07008 */
9
10#define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt
11
12#include <linux/delay.h>
13#include <linux/device.h>
14#include <linux/kernel.h>
15#include <linux/list.h>
16#include <linux/genhd.h>
17#include <linux/slab.h>
18#include <linux/uaccess.h>
19#include <uapi/linux/sed-opal.h>
20#include <linux/sed-opal.h>
21#include <linux/string.h>
22#include <linux/kdev_t.h>
23
24#include "opal_proto.h"
25
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010026#define IO_BUFFER_LENGTH 2048
27#define MAX_TOKS 64
28
Jonas Rabensteina9b25b42019-05-21 22:46:45 +020029/* Number of bytes needed by cmd_finalize. */
30#define CMD_FINALIZE_BYTES_NEEDED 7
31
Jon Derrickeed64952017-02-22 07:55:13 -070032struct opal_step {
33 int (*fn)(struct opal_dev *dev, void *data);
34 void *data;
35};
36typedef int (cont_fn)(struct opal_dev *dev);
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010037
38enum opal_atom_width {
39 OPAL_WIDTH_TINY,
40 OPAL_WIDTH_SHORT,
41 OPAL_WIDTH_MEDIUM,
42 OPAL_WIDTH_LONG,
43 OPAL_WIDTH_TOKEN
44};
45
46/*
47 * On the parsed response, we don't store again the toks that are already
48 * stored in the response buffer. Instead, for each token, we just store a
49 * pointer to the position in the buffer where the token starts, and the size
50 * of the token in bytes.
51 */
52struct opal_resp_tok {
53 const u8 *pos;
54 size_t len;
55 enum opal_response_token type;
56 enum opal_atom_width width;
57 union {
58 u64 u;
59 s64 s;
60 } stored;
61};
62
63/*
64 * From the response header it's not possible to know how many tokens there are
65 * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
66 * if we start dealing with messages that have more than that, we can increase
67 * this number. This is done to avoid having to make two passes through the
68 * response, the first one counting how many tokens we have and the second one
69 * actually storing the positions.
70 */
71struct parsed_resp {
72 int num;
73 struct opal_resp_tok toks[MAX_TOKS];
74};
75
76struct opal_dev {
77 bool supported;
Scott Bauerdbec491b2017-09-01 08:53:35 -060078 bool mbr_enabled;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010079
80 void *data;
81 sec_send_recv *send_recv;
82
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010083 struct mutex dev_lock;
84 u16 comid;
85 u32 hsn;
86 u32 tsn;
87 u64 align;
88 u64 lowest_lba;
89
90 size_t pos;
91 u8 cmd[IO_BUFFER_LENGTH];
92 u8 resp[IO_BUFFER_LENGTH];
93
94 struct parsed_resp parsed;
95 size_t prev_d_len;
96 void *prev_data;
97
98 struct list_head unlk_lst;
99};
100
101
Scott Bauer455a7b22017-02-03 12:50:31 -0700102static const u8 opaluid[][OPAL_UID_LENGTH] = {
103 /* users */
104 [OPAL_SMUID_UID] =
105 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
106 [OPAL_THISSP_UID] =
107 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
108 [OPAL_ADMINSP_UID] =
109 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
110 [OPAL_LOCKINGSP_UID] =
111 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
112 [OPAL_ENTERPRISE_LOCKINGSP_UID] =
113 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
114 [OPAL_ANYBODY_UID] =
115 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
116 [OPAL_SID_UID] =
117 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
118 [OPAL_ADMIN1_UID] =
119 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
120 [OPAL_USER1_UID] =
121 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
122 [OPAL_USER2_UID] =
123 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
124 [OPAL_PSID_UID] =
125 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
126 [OPAL_ENTERPRISE_BANDMASTER0_UID] =
127 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
128 [OPAL_ENTERPRISE_ERASEMASTER_UID] =
129 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
130
131 /* tables */
132
Jonas Rabensteinff910642019-05-21 22:46:46 +0200133 [OPAL_TABLE_TABLE]
134 { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 },
Scott Bauer455a7b22017-02-03 12:50:31 -0700135 [OPAL_LOCKINGRANGE_GLOBAL] =
136 { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
137 [OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
138 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
139 [OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
140 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
141 [OPAL_MBRCONTROL] =
142 { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
143 [OPAL_MBR] =
144 { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
145 [OPAL_AUTHORITY_TABLE] =
146 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
147 [OPAL_C_PIN_TABLE] =
148 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
149 [OPAL_LOCKING_INFO_TABLE] =
150 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
151 [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
152 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
153
154 /* C_PIN_TABLE object ID's */
155
David Kozub1e815b32019-02-14 01:15:54 +0100156 [OPAL_C_PIN_MSID] =
Scott Bauer455a7b22017-02-03 12:50:31 -0700157 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
158 [OPAL_C_PIN_SID] =
159 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
160 [OPAL_C_PIN_ADMIN1] =
161 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
162
163 /* half UID's (only first 4 bytes used) */
164
165 [OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
166 { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
167 [OPAL_HALF_UID_BOOLEAN_ACE] =
168 { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
169
170 /* special value for omitted optional parameter */
171 [OPAL_UID_HEXFF] =
172 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
173};
174
175/*
176 * TCG Storage SSC Methods.
177 * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
178 * Section: 6.3 Assigned UIDs
179 */
Jonas Rabenstein1b6b75b2019-02-14 01:15:55 +0100180static const u8 opalmethod[][OPAL_METHOD_LENGTH] = {
Scott Bauer455a7b22017-02-03 12:50:31 -0700181 [OPAL_PROPERTIES] =
182 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
183 [OPAL_STARTSESSION] =
184 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
185 [OPAL_REVERT] =
186 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
187 [OPAL_ACTIVATE] =
188 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
189 [OPAL_EGET] =
190 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
191 [OPAL_ESET] =
192 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
193 [OPAL_NEXT] =
194 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
195 [OPAL_EAUTHENTICATE] =
196 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
197 [OPAL_GETACL] =
198 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
199 [OPAL_GENKEY] =
200 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
201 [OPAL_REVERTSP] =
202 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
203 [OPAL_GET] =
204 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
205 [OPAL_SET] =
206 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
207 [OPAL_AUTHENTICATE] =
208 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
209 [OPAL_RANDOM] =
210 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
211 [OPAL_ERASE] =
212 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
213};
214
Scott Bauer455a7b22017-02-03 12:50:31 -0700215static int end_opal_session_error(struct opal_dev *dev);
David Kozub0af26482019-02-14 01:16:07 +0100216static int opal_discovery0_step(struct opal_dev *dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700217
218struct opal_suspend_data {
219 struct opal_lock_unlock unlk;
220 u8 lr;
221 struct list_head node;
222};
223
224/*
225 * Derived from:
226 * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
227 * Section: 5.1.5 Method Status Codes
228 */
229static const char * const opal_errors[] = {
230 "Success",
231 "Not Authorized",
232 "Unknown Error",
233 "SP Busy",
234 "SP Failed",
235 "SP Disabled",
236 "SP Frozen",
237 "No Sessions Available",
238 "Uniqueness Conflict",
239 "Insufficient Space",
240 "Insufficient Rows",
241 "Invalid Function",
242 "Invalid Parameter",
243 "Invalid Reference",
244 "Unknown Error",
245 "TPER Malfunction",
246 "Transaction Failure",
247 "Response Overflow",
248 "Authority Locked Out",
249};
250
251static const char *opal_error_to_human(int error)
252{
253 if (error == 0x3f)
254 return "Failed";
255
256 if (error >= ARRAY_SIZE(opal_errors) || error < 0)
257 return "Unknown Error";
258
259 return opal_errors[error];
260}
261
262static void print_buffer(const u8 *ptr, u32 length)
263{
264#ifdef DEBUG
265 print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
266 pr_debug("\n");
267#endif
268}
269
270static bool check_tper(const void *data)
271{
272 const struct d0_tper_features *tper = data;
273 u8 flags = tper->supported_features;
274
275 if (!(flags & TPER_SYNC_SUPPORTED)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600276 pr_debug("TPer sync not supported. flags = %d\n",
277 tper->supported_features);
Scott Bauer455a7b22017-02-03 12:50:31 -0700278 return false;
279 }
280
281 return true;
282}
283
Scott Bauerdbec491b2017-09-01 08:53:35 -0600284static bool check_mbrenabled(const void *data)
285{
286 const struct d0_locking_features *lfeat = data;
287 u8 sup_feat = lfeat->supported_features;
288
289 return !!(sup_feat & MBR_ENABLED_MASK);
290}
291
Scott Bauer455a7b22017-02-03 12:50:31 -0700292static bool check_sum(const void *data)
293{
294 const struct d0_single_user_mode *sum = data;
295 u32 nlo = be32_to_cpu(sum->num_locking_objects);
296
297 if (nlo == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600298 pr_debug("Need at least one locking object.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700299 return false;
300 }
301
302 pr_debug("Number of locking objects: %d\n", nlo);
303
304 return true;
305}
306
307static u16 get_comid_v100(const void *data)
308{
309 const struct d0_opal_v100 *v100 = data;
310
311 return be16_to_cpu(v100->baseComID);
312}
313
314static u16 get_comid_v200(const void *data)
315{
316 const struct d0_opal_v200 *v200 = data;
317
318 return be16_to_cpu(v200->baseComID);
319}
320
321static int opal_send_cmd(struct opal_dev *dev)
322{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100323 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700324 dev->cmd, IO_BUFFER_LENGTH,
325 true);
326}
327
328static int opal_recv_cmd(struct opal_dev *dev)
329{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100330 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700331 dev->resp, IO_BUFFER_LENGTH,
332 false);
333}
334
335static int opal_recv_check(struct opal_dev *dev)
336{
337 size_t buflen = IO_BUFFER_LENGTH;
338 void *buffer = dev->resp;
339 struct opal_header *hdr = buffer;
340 int ret;
341
342 do {
343 pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
344 hdr->cp.outstandingData,
345 hdr->cp.minTransfer);
346
347 if (hdr->cp.outstandingData == 0 ||
348 hdr->cp.minTransfer != 0)
349 return 0;
350
351 memset(buffer, 0, buflen);
352 ret = opal_recv_cmd(dev);
353 } while (!ret);
354
355 return ret;
356}
357
358static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
359{
360 int ret;
361
362 ret = opal_send_cmd(dev);
363 if (ret)
364 return ret;
365 ret = opal_recv_cmd(dev);
366 if (ret)
367 return ret;
368 ret = opal_recv_check(dev);
369 if (ret)
370 return ret;
371 return cont(dev);
372}
373
374static void check_geometry(struct opal_dev *dev, const void *data)
375{
376 const struct d0_geometry_features *geo = data;
377
378 dev->align = geo->alignment_granularity;
379 dev->lowest_lba = geo->lowest_aligned_lba;
380}
381
David Kozub0af26482019-02-14 01:16:07 +0100382static int execute_step(struct opal_dev *dev,
383 const struct opal_step *step, size_t stepIndex)
384{
385 int error = step->fn(dev, step->data);
386
387 if (error) {
388 pr_debug("Step %zu (%pS) failed with error %d: %s\n",
389 stepIndex, step->fn, error,
390 opal_error_to_human(error));
391 }
392
393 return error;
394}
395
David Kozuba80f36c2019-02-14 01:16:08 +0100396static int execute_steps(struct opal_dev *dev,
397 const struct opal_step *steps, size_t n_steps)
Scott Bauer455a7b22017-02-03 12:50:31 -0700398{
David Kozub0af26482019-02-14 01:16:07 +0100399 size_t state = 0;
400 int error;
401
402 /* first do a discovery0 */
403 error = opal_discovery0_step(dev);
404 if (error)
405 return error;
Scott Bauer455a7b22017-02-03 12:50:31 -0700406
David Kozub3db87232019-02-14 01:16:06 +0100407 for (state = 0; state < n_steps; state++) {
David Kozub0af26482019-02-14 01:16:07 +0100408 error = execute_step(dev, &steps[state], state);
David Kozub3db87232019-02-14 01:16:06 +0100409 if (error)
410 goto out_error;
411 }
Scott Bauer455a7b22017-02-03 12:50:31 -0700412
David Kozub3db87232019-02-14 01:16:06 +0100413 return 0;
Scott Bauer2d190202017-02-22 10:15:08 -0700414
David Kozub3db87232019-02-14 01:16:06 +0100415out_error:
416 /*
David Kozub0af26482019-02-14 01:16:07 +0100417 * For each OPAL command the first step in steps starts some sort of
418 * session. If an error occurred in the initial discovery0 or if an
419 * error occurred in the first step (and thus stopping the loop with
420 * state == 0) then there was an error before or during the attempt to
421 * start a session. Therefore we shouldn't attempt to terminate a
422 * session, as one has not yet been created.
David Kozub3db87232019-02-14 01:16:06 +0100423 */
David Kozub0af26482019-02-14 01:16:07 +0100424 if (state > 0)
David Kozub3db87232019-02-14 01:16:06 +0100425 end_opal_session_error(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700426
427 return error;
428}
429
430static int opal_discovery0_end(struct opal_dev *dev)
431{
432 bool found_com_id = false, supported = true, single_user = false;
433 const struct d0_header *hdr = (struct d0_header *)dev->resp;
434 const u8 *epos = dev->resp, *cpos = dev->resp;
435 u16 comid = 0;
Jon Derrick77039b92017-02-21 11:59:15 -0700436 u32 hlen = be32_to_cpu(hdr->length);
Scott Bauer455a7b22017-02-03 12:50:31 -0700437
Jon Derrick77039b92017-02-21 11:59:15 -0700438 print_buffer(dev->resp, hlen);
Scott Bauerdbec491b2017-09-01 08:53:35 -0600439 dev->mbr_enabled = false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700440
Jon Derrick77039b92017-02-21 11:59:15 -0700441 if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600442 pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
443 sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
Jon Derrick77039b92017-02-21 11:59:15 -0700444 return -EFAULT;
445 }
446
447 epos += hlen; /* end of buffer */
Scott Bauer455a7b22017-02-03 12:50:31 -0700448 cpos += sizeof(*hdr); /* current position on buffer */
449
450 while (cpos < epos && supported) {
451 const struct d0_features *body =
452 (const struct d0_features *)cpos;
453
454 switch (be16_to_cpu(body->code)) {
455 case FC_TPER:
456 supported = check_tper(body->features);
457 break;
458 case FC_SINGLEUSER:
459 single_user = check_sum(body->features);
460 break;
461 case FC_GEOMETRY:
462 check_geometry(dev, body);
463 break;
464 case FC_LOCKING:
Scott Bauerdbec491b2017-09-01 08:53:35 -0600465 dev->mbr_enabled = check_mbrenabled(body->features);
466 break;
Scott Bauer455a7b22017-02-03 12:50:31 -0700467 case FC_ENTERPRISE:
468 case FC_DATASTORE:
469 /* some ignored properties */
470 pr_debug("Found OPAL feature description: %d\n",
471 be16_to_cpu(body->code));
472 break;
473 case FC_OPALV100:
474 comid = get_comid_v100(body->features);
475 found_com_id = true;
476 break;
477 case FC_OPALV200:
478 comid = get_comid_v200(body->features);
479 found_com_id = true;
480 break;
481 case 0xbfff ... 0xffff:
482 /* vendor specific, just ignore */
483 break;
484 default:
485 pr_debug("OPAL Unknown feature: %d\n",
486 be16_to_cpu(body->code));
487
488 }
489 cpos += body->length + 4;
490 }
491
492 if (!supported) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100493 pr_debug("This device is not Opal enabled. Not Supported!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700494 return -EOPNOTSUPP;
495 }
496
497 if (!single_user)
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100498 pr_debug("Device doesn't support single user mode\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700499
500
501 if (!found_com_id) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100502 pr_debug("Could not find OPAL comid for device. Returning early\n");
Ingo Molnared7158b2018-02-22 10:54:55 +0100503 return -EOPNOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -0700504 }
505
506 dev->comid = comid;
507
508 return 0;
509}
510
Jon Derrickeed64952017-02-22 07:55:13 -0700511static int opal_discovery0(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -0700512{
513 int ret;
514
515 memset(dev->resp, 0, IO_BUFFER_LENGTH);
516 dev->comid = OPAL_DISCOVERY_COMID;
517 ret = opal_recv_cmd(dev);
518 if (ret)
519 return ret;
520 return opal_discovery0_end(dev);
521}
522
David Kozub0af26482019-02-14 01:16:07 +0100523static int opal_discovery0_step(struct opal_dev *dev)
524{
525 const struct opal_step discovery0_step = {
526 opal_discovery0,
527 };
528 return execute_step(dev, &discovery0_step, 0);
529}
530
Jonas Rabensteina9b25b42019-05-21 22:46:45 +0200531static size_t remaining_size(struct opal_dev *cmd)
532{
533 return IO_BUFFER_LENGTH - cmd->pos;
534}
535
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100536static bool can_add(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700537{
538 if (*err)
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100539 return false;
540
Jonas Rabensteina9b25b42019-05-21 22:46:45 +0200541 if (remaining_size(cmd) < len) {
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100542 pr_debug("Error adding %zu bytes: end of buffer.\n", len);
Scott Bauer455a7b22017-02-03 12:50:31 -0700543 *err = -ERANGE;
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100544 return false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700545 }
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100546
547 return true;
548}
549
550static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
551{
552 if (!can_add(err, cmd, 1))
553 return;
Scott Bauer455a7b22017-02-03 12:50:31 -0700554 cmd->cmd[cmd->pos++] = tok;
555}
556
557static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
558 bool has_sign, int len)
559{
560 u8 atom;
561 int err = 0;
562
563 atom = SHORT_ATOM_ID;
564 atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
565 atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
566 atom |= len & SHORT_ATOM_LEN_MASK;
567
568 add_token_u8(&err, cmd, atom);
569}
570
571static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
572 bool has_sign, int len)
573{
574 u8 header0;
575
576 header0 = MEDIUM_ATOM_ID;
577 header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
578 header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
579 header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
580 cmd->cmd[cmd->pos++] = header0;
581 cmd->cmd[cmd->pos++] = len;
582}
583
584static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
585{
Scott Bauer455a7b22017-02-03 12:50:31 -0700586 size_t len;
587 int msb;
Scott Bauer455a7b22017-02-03 12:50:31 -0700588
589 if (!(number & ~TINY_ATOM_DATA_MASK)) {
590 add_token_u8(err, cmd, number);
591 return;
592 }
593
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100594 msb = fls64(number);
595 len = DIV_ROUND_UP(msb, 8);
Scott Bauer455a7b22017-02-03 12:50:31 -0700596
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100597 if (!can_add(err, cmd, len + 1)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600598 pr_debug("Error adding u64: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700599 return;
600 }
601 add_short_atom_header(cmd, false, false, len);
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100602 while (len--)
603 add_token_u8(err, cmd, number >> (len * 8));
Scott Bauer455a7b22017-02-03 12:50:31 -0700604}
605
Jonas Rabenstein28559952019-02-14 01:16:02 +0100606static u8 *add_bytestring_header(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700607{
608 size_t header_len = 1;
609 bool is_short_atom = true;
610
Scott Bauer455a7b22017-02-03 12:50:31 -0700611 if (len & ~SHORT_ATOM_LEN_MASK) {
612 header_len = 2;
613 is_short_atom = false;
614 }
615
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100616 if (!can_add(err, cmd, header_len + len)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600617 pr_debug("Error adding bytestring: end of buffer.\n");
Jonas Rabenstein28559952019-02-14 01:16:02 +0100618 return NULL;
Scott Bauer455a7b22017-02-03 12:50:31 -0700619 }
620
621 if (is_short_atom)
622 add_short_atom_header(cmd, true, false, len);
623 else
624 add_medium_atom_header(cmd, true, false, len);
625
Jonas Rabenstein28559952019-02-14 01:16:02 +0100626 return &cmd->cmd[cmd->pos];
627}
Scott Bauer455a7b22017-02-03 12:50:31 -0700628
Jonas Rabenstein28559952019-02-14 01:16:02 +0100629static void add_token_bytestring(int *err, struct opal_dev *cmd,
630 const u8 *bytestring, size_t len)
631{
632 u8 *start;
633
634 start = add_bytestring_header(err, cmd, len);
635 if (!start)
636 return;
637 memcpy(start, bytestring, len);
638 cmd->pos += len;
Scott Bauer455a7b22017-02-03 12:50:31 -0700639}
640
641static int build_locking_range(u8 *buffer, size_t length, u8 lr)
642{
643 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600644 pr_debug("Can't build locking range. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700645 return -ERANGE;
646 }
647
648 memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
649
650 if (lr == 0)
651 return 0;
652 buffer[5] = LOCKING_RANGE_NON_GLOBAL;
653 buffer[7] = lr;
654
655 return 0;
656}
657
658static int build_locking_user(u8 *buffer, size_t length, u8 lr)
659{
660 if (length > OPAL_UID_LENGTH) {
David Kozub1e815b32019-02-14 01:15:54 +0100661 pr_debug("Can't build locking range user. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700662 return -ERANGE;
663 }
664
665 memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
666
667 buffer[7] = lr + 1;
668
669 return 0;
670}
671
672static void set_comid(struct opal_dev *cmd, u16 comid)
673{
674 struct opal_header *hdr = (struct opal_header *)cmd->cmd;
675
676 hdr->cp.extendedComID[0] = comid >> 8;
677 hdr->cp.extendedComID[1] = comid;
678 hdr->cp.extendedComID[2] = 0;
679 hdr->cp.extendedComID[3] = 0;
680}
681
682static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
683{
684 struct opal_header *hdr;
685 int err = 0;
686
Jonas Rabensteina9b25b42019-05-21 22:46:45 +0200687 /*
688 * Close the parameter list opened from cmd_start.
689 * The number of bytes added must be equal to
690 * CMD_FINALIZE_BYTES_NEEDED.
691 */
David Kozub78d584c2019-02-14 01:15:57 +0100692 add_token_u8(&err, cmd, OPAL_ENDLIST);
693
Scott Bauer455a7b22017-02-03 12:50:31 -0700694 add_token_u8(&err, cmd, OPAL_ENDOFDATA);
695 add_token_u8(&err, cmd, OPAL_STARTLIST);
696 add_token_u8(&err, cmd, 0);
697 add_token_u8(&err, cmd, 0);
698 add_token_u8(&err, cmd, 0);
699 add_token_u8(&err, cmd, OPAL_ENDLIST);
700
701 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600702 pr_debug("Error finalizing command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700703 return -EFAULT;
704 }
705
706 hdr = (struct opal_header *) cmd->cmd;
707
708 hdr->pkt.tsn = cpu_to_be32(tsn);
709 hdr->pkt.hsn = cpu_to_be32(hsn);
710
711 hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
712 while (cmd->pos % 4) {
713 if (cmd->pos >= IO_BUFFER_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600714 pr_debug("Error: Buffer overrun\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700715 return -ERANGE;
716 }
717 cmd->cmd[cmd->pos++] = 0;
718 }
719 hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
720 sizeof(hdr->pkt));
721 hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
722
723 return 0;
724}
725
Jon Derrickcccb9242017-02-21 11:59:14 -0700726static const struct opal_resp_tok *response_get_token(
727 const struct parsed_resp *resp,
728 int n)
Scott Bauer455a7b22017-02-03 12:50:31 -0700729{
730 const struct opal_resp_tok *tok;
731
David Kozub7d9b62a2019-02-14 01:15:59 +0100732 if (!resp) {
733 pr_debug("Response is NULL\n");
734 return ERR_PTR(-EINVAL);
735 }
736
Scott Bauer455a7b22017-02-03 12:50:31 -0700737 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600738 pr_debug("Token number doesn't exist: %d, resp: %d\n",
739 n, resp->num);
Jon Derrickcccb9242017-02-21 11:59:14 -0700740 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700741 }
742
743 tok = &resp->toks[n];
744 if (tok->len == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600745 pr_debug("Token length must be non-zero\n");
Jon Derrickcccb9242017-02-21 11:59:14 -0700746 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700747 }
748
Jon Derrickcccb9242017-02-21 11:59:14 -0700749 return tok;
Scott Bauer455a7b22017-02-03 12:50:31 -0700750}
751
Jon Derrickaedb6e22017-02-21 11:59:13 -0700752static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
753 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700754{
755 tok->pos = pos;
756 tok->len = 1;
757 tok->width = OPAL_WIDTH_TINY;
758
759 if (pos[0] & TINY_ATOM_SIGNED) {
760 tok->type = OPAL_DTA_TOKENID_SINT;
761 } else {
762 tok->type = OPAL_DTA_TOKENID_UINT;
763 tok->stored.u = pos[0] & 0x3f;
764 }
765
766 return tok->len;
767}
768
Jon Derrickaedb6e22017-02-21 11:59:13 -0700769static ssize_t response_parse_short(struct opal_resp_tok *tok,
770 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700771{
772 tok->pos = pos;
773 tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
774 tok->width = OPAL_WIDTH_SHORT;
775
776 if (pos[0] & SHORT_ATOM_BYTESTRING) {
777 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
778 } else if (pos[0] & SHORT_ATOM_SIGNED) {
779 tok->type = OPAL_DTA_TOKENID_SINT;
780 } else {
781 u64 u_integer = 0;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700782 ssize_t i, b = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700783
784 tok->type = OPAL_DTA_TOKENID_UINT;
785 if (tok->len > 9) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600786 pr_debug("uint64 with more than 8 bytes\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700787 return -EINVAL;
788 }
789 for (i = tok->len - 1; i > 0; i--) {
790 u_integer |= ((u64)pos[i] << (8 * b));
791 b++;
792 }
793 tok->stored.u = u_integer;
794 }
795
796 return tok->len;
797}
798
Jon Derrickaedb6e22017-02-21 11:59:13 -0700799static ssize_t response_parse_medium(struct opal_resp_tok *tok,
800 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700801{
802 tok->pos = pos;
803 tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
804 tok->width = OPAL_WIDTH_MEDIUM;
805
806 if (pos[0] & MEDIUM_ATOM_BYTESTRING)
807 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
808 else if (pos[0] & MEDIUM_ATOM_SIGNED)
809 tok->type = OPAL_DTA_TOKENID_SINT;
810 else
811 tok->type = OPAL_DTA_TOKENID_UINT;
812
813 return tok->len;
814}
815
Jon Derrickaedb6e22017-02-21 11:59:13 -0700816static ssize_t response_parse_long(struct opal_resp_tok *tok,
817 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700818{
819 tok->pos = pos;
820 tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
821 tok->width = OPAL_WIDTH_LONG;
822
823 if (pos[0] & LONG_ATOM_BYTESTRING)
824 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
825 else if (pos[0] & LONG_ATOM_SIGNED)
826 tok->type = OPAL_DTA_TOKENID_SINT;
827 else
828 tok->type = OPAL_DTA_TOKENID_UINT;
829
830 return tok->len;
831}
832
Jon Derrickaedb6e22017-02-21 11:59:13 -0700833static ssize_t response_parse_token(struct opal_resp_tok *tok,
834 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700835{
836 tok->pos = pos;
837 tok->len = 1;
838 tok->type = OPAL_DTA_TOKENID_TOKEN;
839 tok->width = OPAL_WIDTH_TOKEN;
840
841 return tok->len;
842}
843
844static int response_parse(const u8 *buf, size_t length,
845 struct parsed_resp *resp)
846{
847 const struct opal_header *hdr;
848 struct opal_resp_tok *iter;
849 int num_entries = 0;
850 int total;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700851 ssize_t token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700852 const u8 *pos;
Jon Derrick77039b92017-02-21 11:59:15 -0700853 u32 clen, plen, slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700854
855 if (!buf)
856 return -EFAULT;
857
858 if (!resp)
859 return -EFAULT;
860
861 hdr = (struct opal_header *)buf;
862 pos = buf;
863 pos += sizeof(*hdr);
864
Jon Derrick77039b92017-02-21 11:59:15 -0700865 clen = be32_to_cpu(hdr->cp.length);
866 plen = be32_to_cpu(hdr->pkt.length);
867 slen = be32_to_cpu(hdr->subpkt.length);
868 pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
869 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700870
Jon Derrick77039b92017-02-21 11:59:15 -0700871 if (clen == 0 || plen == 0 || slen == 0 ||
872 slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600873 pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
874 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700875 print_buffer(pos, sizeof(*hdr));
876 return -EINVAL;
877 }
878
879 if (pos > buf + length)
880 return -EFAULT;
881
882 iter = resp->toks;
Jon Derrick77039b92017-02-21 11:59:15 -0700883 total = slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700884 print_buffer(pos, total);
885 while (total > 0) {
886 if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
887 token_length = response_parse_tiny(iter, pos);
888 else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
889 token_length = response_parse_short(iter, pos);
890 else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
891 token_length = response_parse_medium(iter, pos);
892 else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
893 token_length = response_parse_long(iter, pos);
894 else /* TOKEN */
895 token_length = response_parse_token(iter, pos);
896
Jon Derrickaedb6e22017-02-21 11:59:13 -0700897 if (token_length < 0)
898 return token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700899
900 pos += token_length;
901 total -= token_length;
902 iter++;
903 num_entries++;
904 }
905
906 if (num_entries == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600907 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700908 return -EINVAL;
909 }
910 resp->num = num_entries;
911
912 return 0;
913}
914
915static size_t response_get_string(const struct parsed_resp *resp, int n,
916 const char **store)
917{
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100918 u8 skip;
David Kozubb68f09e2019-02-14 01:16:00 +0100919 const struct opal_resp_tok *tok;
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100920
Scott Bauer455a7b22017-02-03 12:50:31 -0700921 *store = NULL;
David Kozubb68f09e2019-02-14 01:16:00 +0100922 tok = response_get_token(resp, n);
923 if (IS_ERR(tok))
Scott Bauer455a7b22017-02-03 12:50:31 -0700924 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700925
David Kozubb68f09e2019-02-14 01:16:00 +0100926 if (tok->type != OPAL_DTA_TOKENID_BYTESTRING) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600927 pr_debug("Token is not a byte string!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700928 return 0;
929 }
930
David Kozubb68f09e2019-02-14 01:16:00 +0100931 switch (tok->width) {
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100932 case OPAL_WIDTH_TINY:
933 case OPAL_WIDTH_SHORT:
934 skip = 1;
935 break;
936 case OPAL_WIDTH_MEDIUM:
937 skip = 2;
938 break;
939 case OPAL_WIDTH_LONG:
940 skip = 4;
941 break;
942 default:
943 pr_debug("Token has invalid width!\n");
944 return 0;
945 }
946
David Kozubb68f09e2019-02-14 01:16:00 +0100947 *store = tok->pos + skip;
948 return tok->len - skip;
Scott Bauer455a7b22017-02-03 12:50:31 -0700949}
950
951static u64 response_get_u64(const struct parsed_resp *resp, int n)
952{
David Kozubb68f09e2019-02-14 01:16:00 +0100953 const struct opal_resp_tok *tok;
954
955 tok = response_get_token(resp, n);
956 if (IS_ERR(tok))
957 return 0;
958
959 if (tok->type != OPAL_DTA_TOKENID_UINT) {
960 pr_debug("Token is not unsigned int: %d\n", tok->type);
Scott Bauer455a7b22017-02-03 12:50:31 -0700961 return 0;
962 }
963
David Kozubb68f09e2019-02-14 01:16:00 +0100964 if (tok->width != OPAL_WIDTH_TINY && tok->width != OPAL_WIDTH_SHORT) {
965 pr_debug("Atom is not short or tiny: %d\n", tok->width);
Scott Bauer455a7b22017-02-03 12:50:31 -0700966 return 0;
967 }
968
David Kozubb68f09e2019-02-14 01:16:00 +0100969 return tok->stored.u;
Scott Bauer455a7b22017-02-03 12:50:31 -0700970}
971
Jon Derrickcccb9242017-02-21 11:59:14 -0700972static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
973{
974 if (IS_ERR(token) ||
975 token->type != OPAL_DTA_TOKENID_TOKEN ||
976 token->pos[0] != match)
977 return false;
978 return true;
979}
980
Scott Bauer455a7b22017-02-03 12:50:31 -0700981static u8 response_status(const struct parsed_resp *resp)
982{
Jon Derrickcccb9242017-02-21 11:59:14 -0700983 const struct opal_resp_tok *tok;
984
985 tok = response_get_token(resp, 0);
986 if (response_token_matches(tok, OPAL_ENDOFSESSION))
Scott Bauer455a7b22017-02-03 12:50:31 -0700987 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700988
989 if (resp->num < 5)
990 return DTAERROR_NO_METHOD_STATUS;
991
Jon Derrickcccb9242017-02-21 11:59:14 -0700992 tok = response_get_token(resp, resp->num - 5);
993 if (!response_token_matches(tok, OPAL_STARTLIST))
994 return DTAERROR_NO_METHOD_STATUS;
995
996 tok = response_get_token(resp, resp->num - 1);
997 if (!response_token_matches(tok, OPAL_ENDLIST))
Scott Bauer455a7b22017-02-03 12:50:31 -0700998 return DTAERROR_NO_METHOD_STATUS;
999
1000 return response_get_u64(resp, resp->num - 4);
1001}
1002
1003/* Parses and checks for errors */
1004static int parse_and_check_status(struct opal_dev *dev)
1005{
1006 int error;
1007
1008 print_buffer(dev->cmd, dev->pos);
1009
1010 error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
1011 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001012 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001013 return error;
1014 }
1015
1016 return response_status(&dev->parsed);
1017}
1018
1019static void clear_opal_cmd(struct opal_dev *dev)
1020{
1021 dev->pos = sizeof(struct opal_header);
1022 memset(dev->cmd, 0, IO_BUFFER_LENGTH);
1023}
1024
David Kozube8b29222019-02-14 01:15:58 +01001025static int cmd_start(struct opal_dev *dev, const u8 *uid, const u8 *method)
1026{
1027 int err = 0;
1028
1029 clear_opal_cmd(dev);
1030 set_comid(dev, dev->comid);
1031
1032 add_token_u8(&err, dev, OPAL_CALL);
1033 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1034 add_token_bytestring(&err, dev, method, OPAL_METHOD_LENGTH);
1035
1036 /*
1037 * Every method call is followed by its parameters enclosed within
1038 * OPAL_STARTLIST and OPAL_ENDLIST tokens. We automatically open the
1039 * parameter list here and close it later in cmd_finalize.
1040 */
1041 add_token_u8(&err, dev, OPAL_STARTLIST);
1042
1043 return err;
1044}
1045
Scott Bauer455a7b22017-02-03 12:50:31 -07001046static int start_opal_session_cont(struct opal_dev *dev)
1047{
1048 u32 hsn, tsn;
1049 int error = 0;
1050
1051 error = parse_and_check_status(dev);
1052 if (error)
1053 return error;
1054
1055 hsn = response_get_u64(&dev->parsed, 4);
1056 tsn = response_get_u64(&dev->parsed, 5);
1057
1058 if (hsn == 0 && tsn == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001059 pr_debug("Couldn't authenticate session\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001060 return -EPERM;
1061 }
1062
1063 dev->hsn = hsn;
1064 dev->tsn = tsn;
1065 return 0;
1066}
1067
1068static void add_suspend_info(struct opal_dev *dev,
1069 struct opal_suspend_data *sus)
1070{
1071 struct opal_suspend_data *iter;
1072
1073 list_for_each_entry(iter, &dev->unlk_lst, node) {
1074 if (iter->lr == sus->lr) {
1075 list_del(&iter->node);
1076 kfree(iter);
1077 break;
1078 }
1079 }
1080 list_add_tail(&sus->node, &dev->unlk_lst);
1081}
1082
1083static int end_session_cont(struct opal_dev *dev)
1084{
1085 dev->hsn = 0;
1086 dev->tsn = 0;
1087 return parse_and_check_status(dev);
1088}
1089
1090static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1091{
1092 int ret;
1093
1094 ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1095 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001096 pr_debug("Error finalizing command buffer: %d\n", ret);
Scott Bauer455a7b22017-02-03 12:50:31 -07001097 return ret;
1098 }
1099
1100 print_buffer(dev->cmd, dev->pos);
1101
1102 return opal_send_recv(dev, cont);
1103}
1104
David Kozub3fff2342019-02-14 01:16:04 +01001105/*
1106 * request @column from table @table on device @dev. On success, the column
1107 * data will be available in dev->resp->tok[4]
1108 */
1109static int generic_get_column(struct opal_dev *dev, const u8 *table,
1110 u64 column)
1111{
1112 int err;
1113
1114 err = cmd_start(dev, table, opalmethod[OPAL_GET]);
1115
1116 add_token_u8(&err, dev, OPAL_STARTLIST);
1117
1118 add_token_u8(&err, dev, OPAL_STARTNAME);
1119 add_token_u8(&err, dev, OPAL_STARTCOLUMN);
1120 add_token_u64(&err, dev, column);
1121 add_token_u8(&err, dev, OPAL_ENDNAME);
1122
1123 add_token_u8(&err, dev, OPAL_STARTNAME);
1124 add_token_u8(&err, dev, OPAL_ENDCOLUMN);
1125 add_token_u64(&err, dev, column);
1126 add_token_u8(&err, dev, OPAL_ENDNAME);
1127
1128 add_token_u8(&err, dev, OPAL_ENDLIST);
1129
1130 if (err)
1131 return err;
1132
1133 return finalize_and_send(dev, parse_and_check_status);
1134}
1135
Jonas Rabensteinff910642019-05-21 22:46:46 +02001136/*
1137 * see TCG SAS 5.3.2.3 for a description of the available columns
1138 *
1139 * the result is provided in dev->resp->tok[4]
1140 */
1141static int generic_get_table_info(struct opal_dev *dev, enum opal_uid table,
1142 u64 column)
1143{
1144 u8 uid[OPAL_UID_LENGTH];
1145 const unsigned int half = OPAL_UID_LENGTH/2;
1146
1147 /* sed-opal UIDs can be split in two halves:
1148 * first: actual table index
1149 * second: relative index in the table
1150 * so we have to get the first half of the OPAL_TABLE_TABLE and use the
1151 * first part of the target table as relative index into that table
1152 */
1153 memcpy(uid, opaluid[OPAL_TABLE_TABLE], half);
1154 memcpy(uid+half, opaluid[table], half);
1155
1156 return generic_get_column(dev, uid, column);
1157}
1158
Jon Derrickeed64952017-02-22 07:55:13 -07001159static int gen_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001160{
Scott Bauer455a7b22017-02-03 12:50:31 -07001161 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001162 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001163
1164 memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
Scott Bauer455a7b22017-02-03 12:50:31 -07001165 kfree(dev->prev_data);
1166 dev->prev_data = NULL;
1167
David Kozube8b29222019-02-14 01:15:58 +01001168 err = cmd_start(dev, uid, opalmethod[OPAL_GENKEY]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001169
1170 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001171 pr_debug("Error building gen key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001172 return err;
1173
1174 }
1175 return finalize_and_send(dev, parse_and_check_status);
1176}
1177
1178static int get_active_key_cont(struct opal_dev *dev)
1179{
1180 const char *activekey;
1181 size_t keylen;
1182 int error = 0;
1183
1184 error = parse_and_check_status(dev);
1185 if (error)
1186 return error;
1187 keylen = response_get_string(&dev->parsed, 4, &activekey);
1188 if (!activekey) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001189 pr_debug("%s: Couldn't extract the Activekey from the response\n",
1190 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001191 return OPAL_INVAL_PARAM;
1192 }
1193 dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1194
1195 if (!dev->prev_data)
1196 return -ENOMEM;
1197
1198 dev->prev_d_len = keylen;
1199
1200 return 0;
1201}
1202
Jon Derrickeed64952017-02-22 07:55:13 -07001203static int get_active_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001204{
1205 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001206 int err;
Jon Derrickeed64952017-02-22 07:55:13 -07001207 u8 *lr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001208
Scott Bauer455a7b22017-02-03 12:50:31 -07001209 err = build_locking_range(uid, sizeof(uid), *lr);
1210 if (err)
1211 return err;
1212
David Kozub3fff2342019-02-14 01:16:04 +01001213 err = generic_get_column(dev, uid, OPAL_ACTIVEKEY);
1214 if (err)
Scott Bauer455a7b22017-02-03 12:50:31 -07001215 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001216
David Kozub3fff2342019-02-14 01:16:04 +01001217 return get_active_key_cont(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001218}
1219
1220static int generic_lr_enable_disable(struct opal_dev *dev,
1221 u8 *uid, bool rle, bool wle,
1222 bool rl, bool wl)
1223{
David Kozube8b29222019-02-14 01:15:58 +01001224 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001225
David Kozube8b29222019-02-14 01:15:58 +01001226 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001227
Scott Bauer455a7b22017-02-03 12:50:31 -07001228 add_token_u8(&err, dev, OPAL_STARTNAME);
1229 add_token_u8(&err, dev, OPAL_VALUES);
1230 add_token_u8(&err, dev, OPAL_STARTLIST);
1231
1232 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001233 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001234 add_token_u8(&err, dev, rle);
1235 add_token_u8(&err, dev, OPAL_ENDNAME);
1236
1237 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001238 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001239 add_token_u8(&err, dev, wle);
1240 add_token_u8(&err, dev, OPAL_ENDNAME);
1241
1242 add_token_u8(&err, dev, OPAL_STARTNAME);
1243 add_token_u8(&err, dev, OPAL_READLOCKED);
1244 add_token_u8(&err, dev, rl);
1245 add_token_u8(&err, dev, OPAL_ENDNAME);
1246
1247 add_token_u8(&err, dev, OPAL_STARTNAME);
1248 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1249 add_token_u8(&err, dev, wl);
1250 add_token_u8(&err, dev, OPAL_ENDNAME);
1251
1252 add_token_u8(&err, dev, OPAL_ENDLIST);
1253 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001254 return err;
1255}
1256
1257static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1258 struct opal_user_lr_setup *setup)
1259{
1260 int err;
1261
1262 err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1263 0, 0);
1264 if (err)
Scott Bauer591c59d2017-04-07 13:58:50 -06001265 pr_debug("Failed to create enable global lr command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001266 return err;
1267}
1268
Jon Derrickeed64952017-02-22 07:55:13 -07001269static int setup_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001270{
1271 u8 uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001272 struct opal_user_lr_setup *setup = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001273 u8 lr;
David Kozube8b29222019-02-14 01:15:58 +01001274 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001275
Scott Bauer455a7b22017-02-03 12:50:31 -07001276 lr = setup->session.opal_key.lr;
1277 err = build_locking_range(uid, sizeof(uid), lr);
1278 if (err)
1279 return err;
1280
1281 if (lr == 0)
1282 err = enable_global_lr(dev, uid, setup);
1283 else {
David Kozube8b29222019-02-14 01:15:58 +01001284 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001285
Scott Bauer455a7b22017-02-03 12:50:31 -07001286 add_token_u8(&err, dev, OPAL_STARTNAME);
1287 add_token_u8(&err, dev, OPAL_VALUES);
1288 add_token_u8(&err, dev, OPAL_STARTLIST);
1289
1290 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001291 add_token_u8(&err, dev, OPAL_RANGESTART);
Scott Bauer455a7b22017-02-03 12:50:31 -07001292 add_token_u64(&err, dev, setup->range_start);
1293 add_token_u8(&err, dev, OPAL_ENDNAME);
1294
1295 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001296 add_token_u8(&err, dev, OPAL_RANGELENGTH);
Scott Bauer455a7b22017-02-03 12:50:31 -07001297 add_token_u64(&err, dev, setup->range_length);
1298 add_token_u8(&err, dev, OPAL_ENDNAME);
1299
1300 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001301 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001302 add_token_u64(&err, dev, !!setup->RLE);
1303 add_token_u8(&err, dev, OPAL_ENDNAME);
1304
1305 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001306 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001307 add_token_u64(&err, dev, !!setup->WLE);
1308 add_token_u8(&err, dev, OPAL_ENDNAME);
1309
1310 add_token_u8(&err, dev, OPAL_ENDLIST);
1311 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001312 }
1313 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001314 pr_debug("Error building Setup Locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001315 return err;
1316
1317 }
1318
1319 return finalize_and_send(dev, parse_and_check_status);
1320}
1321
1322static int start_generic_opal_session(struct opal_dev *dev,
1323 enum opal_uid auth,
1324 enum opal_uid sp_type,
1325 const char *key,
1326 u8 key_len)
1327{
1328 u32 hsn;
David Kozube8b29222019-02-14 01:15:58 +01001329 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001330
Scott Bauer591c59d2017-04-07 13:58:50 -06001331 if (key == NULL && auth != OPAL_ANYBODY_UID)
Scott Bauer455a7b22017-02-03 12:50:31 -07001332 return OPAL_INVAL_PARAM;
Scott Bauer455a7b22017-02-03 12:50:31 -07001333
Scott Bauer455a7b22017-02-03 12:50:31 -07001334 hsn = GENERIC_HOST_SESSION_NUM;
David Kozube8b29222019-02-14 01:15:58 +01001335 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1336 opalmethod[OPAL_STARTSESSION]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001337
Scott Bauer455a7b22017-02-03 12:50:31 -07001338 add_token_u64(&err, dev, hsn);
1339 add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1340 add_token_u8(&err, dev, 1);
1341
1342 switch (auth) {
1343 case OPAL_ANYBODY_UID:
Scott Bauer455a7b22017-02-03 12:50:31 -07001344 break;
1345 case OPAL_ADMIN1_UID:
1346 case OPAL_SID_UID:
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06001347 case OPAL_PSID_UID:
Scott Bauer455a7b22017-02-03 12:50:31 -07001348 add_token_u8(&err, dev, OPAL_STARTNAME);
1349 add_token_u8(&err, dev, 0); /* HostChallenge */
1350 add_token_bytestring(&err, dev, key, key_len);
1351 add_token_u8(&err, dev, OPAL_ENDNAME);
1352 add_token_u8(&err, dev, OPAL_STARTNAME);
1353 add_token_u8(&err, dev, 3); /* HostSignAuth */
1354 add_token_bytestring(&err, dev, opaluid[auth],
1355 OPAL_UID_LENGTH);
1356 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001357 break;
1358 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001359 pr_debug("Cannot start Admin SP session with auth %d\n", auth);
Scott Bauer455a7b22017-02-03 12:50:31 -07001360 return OPAL_INVAL_PARAM;
1361 }
1362
1363 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001364 pr_debug("Error building start adminsp session command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001365 return err;
1366 }
1367
1368 return finalize_and_send(dev, start_opal_session_cont);
1369}
1370
Jon Derrickeed64952017-02-22 07:55:13 -07001371static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001372{
1373 return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1374 OPAL_ADMINSP_UID, NULL, 0);
1375}
1376
Jon Derrickeed64952017-02-22 07:55:13 -07001377static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001378{
1379 int ret;
1380 const u8 *key = dev->prev_data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001381
1382 if (!key) {
Jon Derrickeed64952017-02-22 07:55:13 -07001383 const struct opal_key *okey = data;
David Kozub1e815b32019-02-14 01:15:54 +01001384
Scott Bauer455a7b22017-02-03 12:50:31 -07001385 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1386 OPAL_ADMINSP_UID,
1387 okey->key,
1388 okey->key_len);
1389 } else {
1390 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1391 OPAL_ADMINSP_UID,
1392 key, dev->prev_d_len);
1393 kfree(key);
1394 dev->prev_data = NULL;
1395 }
1396 return ret;
1397}
1398
Jon Derrickeed64952017-02-22 07:55:13 -07001399static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001400{
Jon Derrickeed64952017-02-22 07:55:13 -07001401 struct opal_key *key = data;
David Kozub1e815b32019-02-14 01:15:54 +01001402
Scott Bauer455a7b22017-02-03 12:50:31 -07001403 return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1404 OPAL_LOCKINGSP_UID,
1405 key->key, key->key_len);
1406}
1407
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06001408static int start_PSID_opal_session(struct opal_dev *dev, void *data)
1409{
1410 const struct opal_key *okey = data;
1411
1412 return start_generic_opal_session(dev, OPAL_PSID_UID,
1413 OPAL_ADMINSP_UID,
1414 okey->key,
1415 okey->key_len);
1416}
1417
Jon Derrickeed64952017-02-22 07:55:13 -07001418static int start_auth_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001419{
Jon Derrickeed64952017-02-22 07:55:13 -07001420 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001421 u8 lk_ul_user[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001422 size_t keylen = session->opal_key.key_len;
Scott Bauer455a7b22017-02-03 12:50:31 -07001423 int err = 0;
1424
Scott Bauer455a7b22017-02-03 12:50:31 -07001425 u8 *key = session->opal_key.key;
1426 u32 hsn = GENERIC_HOST_SESSION_NUM;
1427
David Kozube8b29222019-02-14 01:15:58 +01001428 if (session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001429 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1430 session->opal_key.lr);
David Kozube8b29222019-02-14 01:15:58 +01001431 else if (session->who != OPAL_ADMIN1 && !session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001432 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1433 session->who - 1);
David Kozube8b29222019-02-14 01:15:58 +01001434 else
Scott Bauer455a7b22017-02-03 12:50:31 -07001435 memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1436
David Kozube8b29222019-02-14 01:15:58 +01001437 if (err)
1438 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001439
David Kozube8b29222019-02-14 01:15:58 +01001440 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1441 opalmethod[OPAL_STARTSESSION]);
1442
Scott Bauer455a7b22017-02-03 12:50:31 -07001443 add_token_u64(&err, dev, hsn);
1444 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1445 OPAL_UID_LENGTH);
1446 add_token_u8(&err, dev, 1);
1447 add_token_u8(&err, dev, OPAL_STARTNAME);
1448 add_token_u8(&err, dev, 0);
1449 add_token_bytestring(&err, dev, key, keylen);
1450 add_token_u8(&err, dev, OPAL_ENDNAME);
1451 add_token_u8(&err, dev, OPAL_STARTNAME);
1452 add_token_u8(&err, dev, 3);
1453 add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1454 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001455
1456 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001457 pr_debug("Error building STARTSESSION command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001458 return err;
1459 }
1460
1461 return finalize_and_send(dev, start_opal_session_cont);
1462}
1463
Jon Derrickeed64952017-02-22 07:55:13 -07001464static int revert_tper(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001465{
David Kozube8b29222019-02-14 01:15:58 +01001466 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001467
David Kozube8b29222019-02-14 01:15:58 +01001468 err = cmd_start(dev, opaluid[OPAL_ADMINSP_UID],
1469 opalmethod[OPAL_REVERT]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001470 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001471 pr_debug("Error building REVERT TPER command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001472 return err;
1473 }
1474
1475 return finalize_and_send(dev, parse_and_check_status);
1476}
1477
Jon Derrickeed64952017-02-22 07:55:13 -07001478static int internal_activate_user(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001479{
Jon Derrickeed64952017-02-22 07:55:13 -07001480 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001481 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001482 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001483
1484 memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1485 uid[7] = session->who;
1486
David Kozube8b29222019-02-14 01:15:58 +01001487 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001488 add_token_u8(&err, dev, OPAL_STARTNAME);
1489 add_token_u8(&err, dev, OPAL_VALUES);
1490 add_token_u8(&err, dev, OPAL_STARTLIST);
1491 add_token_u8(&err, dev, OPAL_STARTNAME);
1492 add_token_u8(&err, dev, 5); /* Enabled */
1493 add_token_u8(&err, dev, OPAL_TRUE);
1494 add_token_u8(&err, dev, OPAL_ENDNAME);
1495 add_token_u8(&err, dev, OPAL_ENDLIST);
1496 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001497
1498 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001499 pr_debug("Error building Activate UserN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001500 return err;
1501 }
1502
1503 return finalize_and_send(dev, parse_and_check_status);
1504}
1505
Jon Derrickeed64952017-02-22 07:55:13 -07001506static int erase_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001507{
Jon Derrickeed64952017-02-22 07:55:13 -07001508 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001509 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001510 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001511
1512 if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1513 return -ERANGE;
1514
David Kozube8b29222019-02-14 01:15:58 +01001515 err = cmd_start(dev, uid, opalmethod[OPAL_ERASE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001516
1517 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001518 pr_debug("Error building Erase Locking Range Command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001519 return err;
1520 }
1521 return finalize_and_send(dev, parse_and_check_status);
1522}
1523
Jon Derrickeed64952017-02-22 07:55:13 -07001524static int set_mbr_done(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001525{
Jon Derrickeed64952017-02-22 07:55:13 -07001526 u8 *mbr_done_tf = data;
David Kozube8b29222019-02-14 01:15:58 +01001527 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001528
David Kozube8b29222019-02-14 01:15:58 +01001529 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1530 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001531
Scott Bauer455a7b22017-02-03 12:50:31 -07001532 add_token_u8(&err, dev, OPAL_STARTNAME);
1533 add_token_u8(&err, dev, OPAL_VALUES);
1534 add_token_u8(&err, dev, OPAL_STARTLIST);
1535 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001536 add_token_u8(&err, dev, OPAL_MBRDONE);
Jon Derrickeed64952017-02-22 07:55:13 -07001537 add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
Scott Bauer455a7b22017-02-03 12:50:31 -07001538 add_token_u8(&err, dev, OPAL_ENDNAME);
1539 add_token_u8(&err, dev, OPAL_ENDLIST);
1540 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001541
1542 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001543 pr_debug("Error Building set MBR Done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001544 return err;
1545 }
1546
1547 return finalize_and_send(dev, parse_and_check_status);
1548}
1549
Jon Derrickeed64952017-02-22 07:55:13 -07001550static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001551{
Jon Derrickeed64952017-02-22 07:55:13 -07001552 u8 *mbr_en_dis = data;
David Kozube8b29222019-02-14 01:15:58 +01001553 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001554
David Kozube8b29222019-02-14 01:15:58 +01001555 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1556 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001557
Scott Bauer455a7b22017-02-03 12:50:31 -07001558 add_token_u8(&err, dev, OPAL_STARTNAME);
1559 add_token_u8(&err, dev, OPAL_VALUES);
1560 add_token_u8(&err, dev, OPAL_STARTLIST);
1561 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001562 add_token_u8(&err, dev, OPAL_MBRENABLE);
Jon Derrickeed64952017-02-22 07:55:13 -07001563 add_token_u8(&err, dev, *mbr_en_dis);
Scott Bauer455a7b22017-02-03 12:50:31 -07001564 add_token_u8(&err, dev, OPAL_ENDNAME);
1565 add_token_u8(&err, dev, OPAL_ENDLIST);
1566 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001567
1568 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001569 pr_debug("Error Building set MBR done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001570 return err;
1571 }
1572
1573 return finalize_and_send(dev, parse_and_check_status);
1574}
1575
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02001576static int write_shadow_mbr(struct opal_dev *dev, void *data)
1577{
1578 struct opal_shadow_mbr *shadow = data;
1579 const u8 __user *src;
1580 u8 *dst;
1581 size_t off = 0;
1582 u64 len;
1583 int err = 0;
1584
Jonas Rabensteinff910642019-05-21 22:46:46 +02001585 /* do we fit in the available shadow mbr space? */
1586 err = generic_get_table_info(dev, OPAL_MBR, OPAL_TABLE_ROWS);
1587 if (err) {
1588 pr_debug("MBR: could not get shadow size\n");
1589 return err;
1590 }
1591
1592 len = response_get_u64(&dev->parsed, 4);
1593 if (shadow->size > len || shadow->offset > len - shadow->size) {
1594 pr_debug("MBR: does not fit in shadow (%llu vs. %llu)\n",
1595 shadow->offset + shadow->size, len);
1596 return -ENOSPC;
1597 }
1598
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02001599 /* do the actual transmission(s) */
1600 src = (u8 __user *)(uintptr_t)shadow->data;
1601 while (off < shadow->size) {
1602 err = cmd_start(dev, opaluid[OPAL_MBR], opalmethod[OPAL_SET]);
1603 add_token_u8(&err, dev, OPAL_STARTNAME);
1604 add_token_u8(&err, dev, OPAL_WHERE);
1605 add_token_u64(&err, dev, shadow->offset + off);
1606 add_token_u8(&err, dev, OPAL_ENDNAME);
1607
1608 add_token_u8(&err, dev, OPAL_STARTNAME);
1609 add_token_u8(&err, dev, OPAL_VALUES);
1610
1611 /*
1612 * The bytestring header is either 1 or 2 bytes, so assume 2.
1613 * There also needs to be enough space to accommodate the
1614 * trailing OPAL_ENDNAME (1 byte) and tokens added by
1615 * cmd_finalize.
1616 */
1617 len = min(remaining_size(dev) - (2+1+CMD_FINALIZE_BYTES_NEEDED),
1618 (size_t)(shadow->size - off));
1619 pr_debug("MBR: write bytes %zu+%llu/%llu\n",
1620 off, len, shadow->size);
1621
1622 dst = add_bytestring_header(&err, dev, len);
1623 if (!dst)
1624 break;
1625 if (copy_from_user(dst, src + off, len))
1626 err = -EFAULT;
1627 dev->pos += len;
1628
1629 add_token_u8(&err, dev, OPAL_ENDNAME);
1630 if (err)
1631 break;
1632
1633 err = finalize_and_send(dev, parse_and_check_status);
1634 if (err)
1635 break;
1636
1637 off += len;
1638 }
1639 return err;
1640}
1641
Scott Bauer455a7b22017-02-03 12:50:31 -07001642static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1643 struct opal_dev *dev)
1644{
David Kozube8b29222019-02-14 01:15:58 +01001645 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001646
David Kozube8b29222019-02-14 01:15:58 +01001647 err = cmd_start(dev, cpin_uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001648
Scott Bauer455a7b22017-02-03 12:50:31 -07001649 add_token_u8(&err, dev, OPAL_STARTNAME);
1650 add_token_u8(&err, dev, OPAL_VALUES);
1651 add_token_u8(&err, dev, OPAL_STARTLIST);
1652 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001653 add_token_u8(&err, dev, OPAL_PIN);
Scott Bauer455a7b22017-02-03 12:50:31 -07001654 add_token_bytestring(&err, dev, key, key_len);
1655 add_token_u8(&err, dev, OPAL_ENDNAME);
1656 add_token_u8(&err, dev, OPAL_ENDLIST);
1657 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001658
1659 return err;
1660}
1661
Jon Derrickeed64952017-02-22 07:55:13 -07001662static int set_new_pw(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001663{
1664 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001665 struct opal_session_info *usr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001666
1667 memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1668
1669 if (usr->who != OPAL_ADMIN1) {
1670 cpin_uid[5] = 0x03;
1671 if (usr->sum)
1672 cpin_uid[7] = usr->opal_key.lr + 1;
1673 else
1674 cpin_uid[7] = usr->who;
1675 }
1676
1677 if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1678 cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001679 pr_debug("Error building set password command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001680 return -ERANGE;
1681 }
1682
1683 return finalize_and_send(dev, parse_and_check_status);
1684}
1685
Jon Derrickeed64952017-02-22 07:55:13 -07001686static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001687{
1688 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001689 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001690
1691 memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1692
1693 if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001694 pr_debug("Error building Set SID cpin\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001695 return -ERANGE;
1696 }
1697 return finalize_and_send(dev, parse_and_check_status);
1698}
1699
Jon Derrickeed64952017-02-22 07:55:13 -07001700static int add_user_to_lr(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001701{
1702 u8 lr_buffer[OPAL_UID_LENGTH];
1703 u8 user_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001704 struct opal_lock_unlock *lkul = data;
David Kozube8b29222019-02-14 01:15:58 +01001705 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001706
Scott Bauer455a7b22017-02-03 12:50:31 -07001707 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1708 OPAL_UID_LENGTH);
1709
1710 if (lkul->l_state == OPAL_RW)
1711 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1712 OPAL_UID_LENGTH);
1713
1714 lr_buffer[7] = lkul->session.opal_key.lr;
1715
1716 memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1717
1718 user_uid[7] = lkul->session.who;
1719
David Kozube8b29222019-02-14 01:15:58 +01001720 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001721
Scott Bauer455a7b22017-02-03 12:50:31 -07001722 add_token_u8(&err, dev, OPAL_STARTNAME);
1723 add_token_u8(&err, dev, OPAL_VALUES);
1724
1725 add_token_u8(&err, dev, OPAL_STARTLIST);
1726 add_token_u8(&err, dev, OPAL_STARTNAME);
1727 add_token_u8(&err, dev, 3);
1728
1729 add_token_u8(&err, dev, OPAL_STARTLIST);
1730
1731
1732 add_token_u8(&err, dev, OPAL_STARTNAME);
1733 add_token_bytestring(&err, dev,
1734 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1735 OPAL_UID_LENGTH/2);
1736 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1737 add_token_u8(&err, dev, OPAL_ENDNAME);
1738
1739
1740 add_token_u8(&err, dev, OPAL_STARTNAME);
1741 add_token_bytestring(&err, dev,
1742 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1743 OPAL_UID_LENGTH/2);
1744 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1745 add_token_u8(&err, dev, OPAL_ENDNAME);
1746
1747
1748 add_token_u8(&err, dev, OPAL_STARTNAME);
1749 add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1750 OPAL_UID_LENGTH/2);
1751 add_token_u8(&err, dev, 1);
1752 add_token_u8(&err, dev, OPAL_ENDNAME);
1753
1754
1755 add_token_u8(&err, dev, OPAL_ENDLIST);
1756 add_token_u8(&err, dev, OPAL_ENDNAME);
1757 add_token_u8(&err, dev, OPAL_ENDLIST);
1758 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001759
1760 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001761 pr_debug("Error building add user to locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001762 return err;
1763 }
1764
1765 return finalize_and_send(dev, parse_and_check_status);
1766}
1767
Jon Derrickeed64952017-02-22 07:55:13 -07001768static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001769{
1770 u8 lr_buffer[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001771 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001772 u8 read_locked = 1, write_locked = 1;
1773 int err = 0;
1774
Scott Bauer455a7b22017-02-03 12:50:31 -07001775 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1776 lkul->session.opal_key.lr) < 0)
1777 return -ERANGE;
1778
1779 switch (lkul->l_state) {
1780 case OPAL_RO:
1781 read_locked = 0;
1782 write_locked = 1;
1783 break;
1784 case OPAL_RW:
1785 read_locked = 0;
1786 write_locked = 0;
1787 break;
1788 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001789 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001790 break;
1791 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001792 pr_debug("Tried to set an invalid locking state... returning to uland\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001793 return OPAL_INVAL_PARAM;
1794 }
1795
David Kozube8b29222019-02-14 01:15:58 +01001796 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
1797
Scott Bauer455a7b22017-02-03 12:50:31 -07001798 add_token_u8(&err, dev, OPAL_STARTNAME);
1799 add_token_u8(&err, dev, OPAL_VALUES);
1800 add_token_u8(&err, dev, OPAL_STARTLIST);
1801
1802 add_token_u8(&err, dev, OPAL_STARTNAME);
1803 add_token_u8(&err, dev, OPAL_READLOCKED);
1804 add_token_u8(&err, dev, read_locked);
1805 add_token_u8(&err, dev, OPAL_ENDNAME);
1806
1807 add_token_u8(&err, dev, OPAL_STARTNAME);
1808 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1809 add_token_u8(&err, dev, write_locked);
1810 add_token_u8(&err, dev, OPAL_ENDNAME);
1811
1812 add_token_u8(&err, dev, OPAL_ENDLIST);
1813 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001814
1815 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001816 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001817 return err;
1818 }
1819 return finalize_and_send(dev, parse_and_check_status);
1820}
1821
1822
Jon Derrickeed64952017-02-22 07:55:13 -07001823static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001824{
1825 u8 lr_buffer[OPAL_UID_LENGTH];
1826 u8 read_locked = 1, write_locked = 1;
Jon Derrickeed64952017-02-22 07:55:13 -07001827 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001828 int ret;
1829
1830 clear_opal_cmd(dev);
1831 set_comid(dev, dev->comid);
1832
Scott Bauer455a7b22017-02-03 12:50:31 -07001833 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1834 lkul->session.opal_key.lr) < 0)
1835 return -ERANGE;
1836
1837 switch (lkul->l_state) {
1838 case OPAL_RO:
1839 read_locked = 0;
1840 write_locked = 1;
1841 break;
1842 case OPAL_RW:
1843 read_locked = 0;
1844 write_locked = 0;
1845 break;
1846 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001847 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001848 break;
1849 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001850 pr_debug("Tried to set an invalid locking state.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001851 return OPAL_INVAL_PARAM;
1852 }
1853 ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1854 read_locked, write_locked);
1855
1856 if (ret < 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001857 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001858 return ret;
1859 }
1860 return finalize_and_send(dev, parse_and_check_status);
1861}
1862
Jon Derrickeed64952017-02-22 07:55:13 -07001863static int activate_lsp(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001864{
Jon Derrickeed64952017-02-22 07:55:13 -07001865 struct opal_lr_act *opal_act = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001866 u8 user_lr[OPAL_UID_LENGTH];
1867 u8 uint_3 = 0x83;
David Kozube8b29222019-02-14 01:15:58 +01001868 int err, i;
Scott Bauer455a7b22017-02-03 12:50:31 -07001869
David Kozube8b29222019-02-14 01:15:58 +01001870 err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID],
1871 opalmethod[OPAL_ACTIVATE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001872
1873 if (opal_act->sum) {
1874 err = build_locking_range(user_lr, sizeof(user_lr),
1875 opal_act->lr[0]);
1876 if (err)
1877 return err;
1878
Scott Bauer455a7b22017-02-03 12:50:31 -07001879 add_token_u8(&err, dev, OPAL_STARTNAME);
1880 add_token_u8(&err, dev, uint_3);
1881 add_token_u8(&err, dev, 6);
1882 add_token_u8(&err, dev, 0);
1883 add_token_u8(&err, dev, 0);
1884
1885 add_token_u8(&err, dev, OPAL_STARTLIST);
1886 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1887 for (i = 1; i < opal_act->num_lrs; i++) {
1888 user_lr[7] = opal_act->lr[i];
1889 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1890 }
1891 add_token_u8(&err, dev, OPAL_ENDLIST);
1892 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001893 }
1894
1895 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001896 pr_debug("Error building Activate LockingSP command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001897 return err;
1898 }
1899
1900 return finalize_and_send(dev, parse_and_check_status);
1901}
1902
David Kozub3fff2342019-02-14 01:16:04 +01001903/* Determine if we're in the Manufactured Inactive or Active state */
1904static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001905{
1906 u8 lc_status;
David Kozub3fff2342019-02-14 01:16:04 +01001907 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001908
David Kozub3fff2342019-02-14 01:16:04 +01001909 err = generic_get_column(dev, opaluid[OPAL_LOCKINGSP_UID],
1910 OPAL_LIFECYCLE);
1911 if (err)
1912 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001913
1914 lc_status = response_get_u64(&dev->parsed, 4);
David Kozub1e815b32019-02-14 01:15:54 +01001915 /* 0x08 is Manufactured Inactive */
Scott Bauer455a7b22017-02-03 12:50:31 -07001916 /* 0x09 is Manufactured */
1917 if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001918 pr_debug("Couldn't determine the status of the Lifecycle state\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001919 return -ENODEV;
1920 }
1921
1922 return 0;
1923}
1924
David Kozub3fff2342019-02-14 01:16:04 +01001925static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001926{
1927 const char *msid_pin;
1928 size_t strlen;
David Kozub3fff2342019-02-14 01:16:04 +01001929 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001930
David Kozub3fff2342019-02-14 01:16:04 +01001931 err = generic_get_column(dev, opaluid[OPAL_C_PIN_MSID], OPAL_PIN);
1932 if (err)
1933 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001934
1935 strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1936 if (!msid_pin) {
David Kozub3fff2342019-02-14 01:16:04 +01001937 pr_debug("Couldn't extract MSID_CPIN from response\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001938 return OPAL_INVAL_PARAM;
1939 }
1940
1941 dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1942 if (!dev->prev_data)
1943 return -ENOMEM;
1944
1945 dev->prev_d_len = strlen;
1946
1947 return 0;
1948}
1949
Jon Derrickeed64952017-02-22 07:55:13 -07001950static int end_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001951{
1952 int err = 0;
1953
1954 clear_opal_cmd(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001955 set_comid(dev, dev->comid);
1956 add_token_u8(&err, dev, OPAL_ENDOFSESSION);
Scott Bauer455a7b22017-02-03 12:50:31 -07001957
Jon Derrickeed64952017-02-22 07:55:13 -07001958 if (err < 0)
1959 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001960 return finalize_and_send(dev, end_session_cont);
1961}
1962
1963static int end_opal_session_error(struct opal_dev *dev)
1964{
David Kozub0af26482019-02-14 01:16:07 +01001965 const struct opal_step error_end_session = {
1966 end_opal_session,
Scott Bauer455a7b22017-02-03 12:50:31 -07001967 };
David Kozub0af26482019-02-14 01:16:07 +01001968 return execute_step(dev, &error_end_session, 0);
Scott Bauer455a7b22017-02-03 12:50:31 -07001969}
1970
David Kozub3db87232019-02-14 01:16:06 +01001971static inline void setup_opal_dev(struct opal_dev *dev)
Scott Bauer455a7b22017-02-03 12:50:31 -07001972{
Scott Bauer455a7b22017-02-03 12:50:31 -07001973 dev->tsn = 0;
1974 dev->hsn = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -07001975 dev->prev_data = NULL;
1976}
1977
1978static int check_opal_support(struct opal_dev *dev)
1979{
Scott Bauer455a7b22017-02-03 12:50:31 -07001980 int ret;
1981
1982 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001983 setup_opal_dev(dev);
David Kozub0af26482019-02-14 01:16:07 +01001984 ret = opal_discovery0_step(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001985 dev->supported = !ret;
1986 mutex_unlock(&dev->dev_lock);
1987 return ret;
1988}
1989
Scott Bauer7d6d1572017-02-22 10:15:06 -07001990static void clean_opal_dev(struct opal_dev *dev)
1991{
1992
1993 struct opal_suspend_data *suspend, *next;
1994
1995 mutex_lock(&dev->dev_lock);
1996 list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
1997 list_del(&suspend->node);
1998 kfree(suspend);
1999 }
2000 mutex_unlock(&dev->dev_lock);
2001}
2002
2003void free_opal_dev(struct opal_dev *dev)
2004{
2005 if (!dev)
2006 return;
2007 clean_opal_dev(dev);
2008 kfree(dev);
2009}
2010EXPORT_SYMBOL(free_opal_dev);
2011
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002012struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
Scott Bauer455a7b22017-02-03 12:50:31 -07002013{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002014 struct opal_dev *dev;
2015
2016 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
2017 if (!dev)
2018 return NULL;
2019
2020 INIT_LIST_HEAD(&dev->unlk_lst);
2021 mutex_init(&dev->dev_lock);
2022 dev->data = data;
2023 dev->send_recv = send_recv;
2024 if (check_opal_support(dev) != 0) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +01002025 pr_debug("Opal is not supported on this device\n");
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002026 kfree(dev);
2027 return NULL;
2028 }
2029 return dev;
Scott Bauer455a7b22017-02-03 12:50:31 -07002030}
2031EXPORT_SYMBOL(init_opal_dev);
2032
2033static int opal_secure_erase_locking_range(struct opal_dev *dev,
2034 struct opal_session_info *opal_session)
2035{
Jon Derrickeed64952017-02-22 07:55:13 -07002036 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002037 { start_auth_opal_session, opal_session },
2038 { get_active_key, &opal_session->opal_key.lr },
2039 { gen_key, },
David Kozub3db87232019-02-14 01:16:06 +01002040 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002041 };
2042 int ret;
2043
2044 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002045 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002046 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002047 mutex_unlock(&dev->dev_lock);
2048 return ret;
2049}
2050
2051static int opal_erase_locking_range(struct opal_dev *dev,
2052 struct opal_session_info *opal_session)
2053{
Jon Derrickeed64952017-02-22 07:55:13 -07002054 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002055 { start_auth_opal_session, opal_session },
2056 { erase_locking_range, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01002057 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002058 };
2059 int ret;
2060
2061 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002062 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002063 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002064 mutex_unlock(&dev->dev_lock);
2065 return ret;
2066}
2067
2068static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
2069 struct opal_mbr_data *opal_mbr)
2070{
David Kozub78bf4732019-02-14 01:15:53 +01002071 u8 enable_disable = opal_mbr->enable_disable == OPAL_MBR_ENABLE ?
2072 OPAL_TRUE : OPAL_FALSE;
2073
Jon Derrickeed64952017-02-22 07:55:13 -07002074 const struct opal_step mbr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002075 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01002076 { set_mbr_done, &enable_disable },
Jon Derrickeed64952017-02-22 07:55:13 -07002077 { end_opal_session, },
2078 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01002079 { set_mbr_enable_disable, &enable_disable },
David Kozub3db87232019-02-14 01:16:06 +01002080 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002081 };
2082 int ret;
2083
2084 if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
2085 opal_mbr->enable_disable != OPAL_MBR_DISABLE)
2086 return -EINVAL;
2087
2088 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002089 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002090 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002091 mutex_unlock(&dev->dev_lock);
2092 return ret;
2093}
2094
Jonas Rabensteinc9888442019-05-21 22:46:44 +02002095static int opal_set_mbr_done(struct opal_dev *dev,
2096 struct opal_mbr_done *mbr_done)
2097{
2098 u8 mbr_done_tf = mbr_done->done_flag == OPAL_MBR_DONE ?
2099 OPAL_TRUE : OPAL_FALSE;
2100
2101 const struct opal_step mbr_steps[] = {
2102 { start_admin1LSP_opal_session, &mbr_done->key },
2103 { set_mbr_done, &mbr_done_tf },
2104 { end_opal_session, }
2105 };
2106 int ret;
2107
2108 if (mbr_done->done_flag != OPAL_MBR_DONE &&
2109 mbr_done->done_flag != OPAL_MBR_NOT_DONE)
2110 return -EINVAL;
2111
2112 mutex_lock(&dev->dev_lock);
2113 setup_opal_dev(dev);
2114 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
2115 mutex_unlock(&dev->dev_lock);
2116 return ret;
2117}
2118
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02002119static int opal_write_shadow_mbr(struct opal_dev *dev,
2120 struct opal_shadow_mbr *info)
2121{
2122 const struct opal_step mbr_steps[] = {
2123 { start_admin1LSP_opal_session, &info->key },
2124 { write_shadow_mbr, info },
2125 { end_opal_session, }
2126 };
2127 int ret;
2128
2129 if (info->size == 0)
2130 return 0;
2131
2132 mutex_lock(&dev->dev_lock);
2133 setup_opal_dev(dev);
2134 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
2135 mutex_unlock(&dev->dev_lock);
2136 return ret;
2137}
2138
Scott Bauer455a7b22017-02-03 12:50:31 -07002139static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
2140{
2141 struct opal_suspend_data *suspend;
2142
2143 suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
2144 if (!suspend)
2145 return -ENOMEM;
2146
2147 suspend->unlk = *lk_unlk;
2148 suspend->lr = lk_unlk->session.opal_key.lr;
2149
2150 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002151 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002152 add_suspend_info(dev, suspend);
2153 mutex_unlock(&dev->dev_lock);
2154 return 0;
2155}
2156
2157static int opal_add_user_to_lr(struct opal_dev *dev,
2158 struct opal_lock_unlock *lk_unlk)
2159{
Jon Derrickeed64952017-02-22 07:55:13 -07002160 const struct opal_step steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002161 { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2162 { add_user_to_lr, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002163 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002164 };
2165 int ret;
2166
2167 if (lk_unlk->l_state != OPAL_RO &&
2168 lk_unlk->l_state != OPAL_RW) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002169 pr_debug("Locking state was not RO or RW\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07002170 return -EINVAL;
2171 }
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002172 if (lk_unlk->session.who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002173 lk_unlk->session.who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002174 pr_debug("Authority was not within the range of users: %d\n",
2175 lk_unlk->session.who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002176 return -EINVAL;
2177 }
2178 if (lk_unlk->session.sum) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002179 pr_debug("%s not supported in sum. Use setup locking range\n",
2180 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07002181 return -EINVAL;
2182 }
2183
2184 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002185 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002186 ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002187 mutex_unlock(&dev->dev_lock);
2188 return ret;
2189}
2190
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002191static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal, bool psid)
Scott Bauer455a7b22017-02-03 12:50:31 -07002192{
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002193 /* controller will terminate session */
Jon Derrickeed64952017-02-22 07:55:13 -07002194 const struct opal_step revert_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002195 { start_SIDASP_opal_session, opal },
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002196 { revert_tper, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002197 };
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002198 const struct opal_step psid_revert_steps[] = {
2199 { start_PSID_opal_session, opal },
2200 { revert_tper, }
2201 };
2202
Scott Bauer455a7b22017-02-03 12:50:31 -07002203 int ret;
2204
2205 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002206 setup_opal_dev(dev);
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002207 if (psid)
2208 ret = execute_steps(dev, psid_revert_steps,
2209 ARRAY_SIZE(psid_revert_steps));
2210 else
2211 ret = execute_steps(dev, revert_steps,
2212 ARRAY_SIZE(revert_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002213 mutex_unlock(&dev->dev_lock);
Scott Bauer7d6d1572017-02-22 10:15:06 -07002214
2215 /*
2216 * If we successfully reverted lets clean
2217 * any saved locking ranges.
2218 */
2219 if (!ret)
2220 clean_opal_dev(dev);
2221
Scott Bauer455a7b22017-02-03 12:50:31 -07002222 return ret;
2223}
2224
Jon Derrickeed64952017-02-22 07:55:13 -07002225static int __opal_lock_unlock(struct opal_dev *dev,
2226 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002227{
Jon Derrickeed64952017-02-22 07:55:13 -07002228 const struct opal_step unlock_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002229 { start_auth_opal_session, &lk_unlk->session },
2230 { lock_unlock_locking_range, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002231 { end_opal_session, }
Jon Derrickeed64952017-02-22 07:55:13 -07002232 };
2233 const struct opal_step unlock_sum_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002234 { start_auth_opal_session, &lk_unlk->session },
2235 { lock_unlock_locking_range_sum, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002236 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002237 };
2238
David Kozub3db87232019-02-14 01:16:06 +01002239 if (lk_unlk->session.sum)
David Kozuba80f36c2019-02-14 01:16:08 +01002240 return execute_steps(dev, unlock_sum_steps,
2241 ARRAY_SIZE(unlock_sum_steps));
David Kozub3db87232019-02-14 01:16:06 +01002242 else
David Kozuba80f36c2019-02-14 01:16:08 +01002243 return execute_steps(dev, unlock_steps,
2244 ARRAY_SIZE(unlock_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002245}
2246
Scott Bauerdbec491b2017-09-01 08:53:35 -06002247static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2248{
David Kozub78bf4732019-02-14 01:15:53 +01002249 u8 mbr_done_tf = OPAL_TRUE;
David Kozub1e815b32019-02-14 01:15:54 +01002250 const struct opal_step mbrdone_step[] = {
Scott Bauerdbec491b2017-09-01 08:53:35 -06002251 { start_admin1LSP_opal_session, key },
2252 { set_mbr_done, &mbr_done_tf },
David Kozub3db87232019-02-14 01:16:06 +01002253 { end_opal_session, }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002254 };
2255
David Kozuba80f36c2019-02-14 01:16:08 +01002256 return execute_steps(dev, mbrdone_step, ARRAY_SIZE(mbrdone_step));
Scott Bauerdbec491b2017-09-01 08:53:35 -06002257}
2258
Jon Derrickeed64952017-02-22 07:55:13 -07002259static int opal_lock_unlock(struct opal_dev *dev,
2260 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002261{
Scott Bauer455a7b22017-02-03 12:50:31 -07002262 int ret;
2263
Revanth Rajashekar15ddffc2019-06-27 16:31:09 -06002264 if (lk_unlk->session.who > OPAL_USER9)
Scott Bauer455a7b22017-02-03 12:50:31 -07002265 return -EINVAL;
2266
2267 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002268 ret = __opal_lock_unlock(dev, lk_unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002269 mutex_unlock(&dev->dev_lock);
2270 return ret;
2271}
2272
2273static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2274{
Jon Derrickeed64952017-02-22 07:55:13 -07002275 const struct opal_step owner_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002276 { start_anybodyASP_opal_session, },
2277 { get_msid_cpin_pin, },
2278 { end_opal_session, },
2279 { start_SIDASP_opal_session, opal },
2280 { set_sid_cpin_pin, opal },
David Kozub3db87232019-02-14 01:16:06 +01002281 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002282 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002283 int ret;
2284
2285 if (!dev)
2286 return -ENODEV;
2287
2288 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002289 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002290 ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002291 mutex_unlock(&dev->dev_lock);
2292 return ret;
2293}
2294
David Kozub1e815b32019-02-14 01:15:54 +01002295static int opal_activate_lsp(struct opal_dev *dev,
2296 struct opal_lr_act *opal_lr_act)
Scott Bauer455a7b22017-02-03 12:50:31 -07002297{
Jon Derrickeed64952017-02-22 07:55:13 -07002298 const struct opal_step active_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002299 { start_SIDASP_opal_session, &opal_lr_act->key },
2300 { get_lsp_lifecycle, },
2301 { activate_lsp, opal_lr_act },
David Kozub3db87232019-02-14 01:16:06 +01002302 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002303 };
2304 int ret;
2305
2306 if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2307 return -EINVAL;
2308
2309 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002310 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002311 ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002312 mutex_unlock(&dev->dev_lock);
2313 return ret;
2314}
2315
2316static int opal_setup_locking_range(struct opal_dev *dev,
2317 struct opal_user_lr_setup *opal_lrs)
2318{
Jon Derrickeed64952017-02-22 07:55:13 -07002319 const struct opal_step lr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002320 { start_auth_opal_session, &opal_lrs->session },
2321 { setup_locking_range, opal_lrs },
David Kozub3db87232019-02-14 01:16:06 +01002322 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002323 };
2324 int ret;
2325
2326 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002327 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002328 ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002329 mutex_unlock(&dev->dev_lock);
2330 return ret;
2331}
2332
2333static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2334{
Jon Derrickeed64952017-02-22 07:55:13 -07002335 const struct opal_step pw_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002336 { start_auth_opal_session, &opal_pw->session },
2337 { set_new_pw, &opal_pw->new_user_pw },
David Kozub3db87232019-02-14 01:16:06 +01002338 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002339 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002340 int ret;
2341
Revanth Rajashekar15ddffc2019-06-27 16:31:09 -06002342 if (opal_pw->session.who > OPAL_USER9 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002343 opal_pw->new_user_pw.who > OPAL_USER9)
2344 return -EINVAL;
2345
2346 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002347 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002348 ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002349 mutex_unlock(&dev->dev_lock);
2350 return ret;
2351}
2352
2353static int opal_activate_user(struct opal_dev *dev,
2354 struct opal_session_info *opal_session)
2355{
Jon Derrickeed64952017-02-22 07:55:13 -07002356 const struct opal_step act_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002357 { start_admin1LSP_opal_session, &opal_session->opal_key },
2358 { internal_activate_user, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01002359 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002360 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002361 int ret;
2362
2363 /* We can't activate Admin1 it's active as manufactured */
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002364 if (opal_session->who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002365 opal_session->who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002366 pr_debug("Who was not a valid user: %d\n", opal_session->who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002367 return -EINVAL;
2368 }
2369
2370 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002371 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002372 ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002373 mutex_unlock(&dev->dev_lock);
2374 return ret;
2375}
2376
2377bool opal_unlock_from_suspend(struct opal_dev *dev)
2378{
2379 struct opal_suspend_data *suspend;
Scott Bauer455a7b22017-02-03 12:50:31 -07002380 bool was_failure = false;
2381 int ret = 0;
2382
2383 if (!dev)
2384 return false;
2385 if (!dev->supported)
2386 return false;
2387
2388 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002389 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002390
2391 list_for_each_entry(suspend, &dev->unlk_lst, node) {
Scott Bauer455a7b22017-02-03 12:50:31 -07002392 dev->tsn = 0;
2393 dev->hsn = 0;
2394
Jon Derrickeed64952017-02-22 07:55:13 -07002395 ret = __opal_lock_unlock(dev, &suspend->unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002396 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002397 pr_debug("Failed to unlock LR %hhu with sum %d\n",
2398 suspend->unlk.session.opal_key.lr,
2399 suspend->unlk.session.sum);
Scott Bauer455a7b22017-02-03 12:50:31 -07002400 was_failure = true;
2401 }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002402 if (dev->mbr_enabled) {
2403 ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
2404 if (ret)
2405 pr_debug("Failed to set MBR Done in S3 resume\n");
2406 }
Scott Bauer455a7b22017-02-03 12:50:31 -07002407 }
2408 mutex_unlock(&dev->dev_lock);
2409 return was_failure;
2410}
2411EXPORT_SYMBOL(opal_unlock_from_suspend);
2412
Scott Bauere225c202017-02-14 17:29:36 -07002413int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
Scott Bauer455a7b22017-02-03 12:50:31 -07002414{
Scott Bauere225c202017-02-14 17:29:36 -07002415 void *p;
2416 int ret = -ENOTTY;
Scott Bauer455a7b22017-02-03 12:50:31 -07002417
2418 if (!capable(CAP_SYS_ADMIN))
2419 return -EACCES;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002420 if (!dev)
2421 return -ENOTSUPP;
Scott Bauer591c59d2017-04-07 13:58:50 -06002422 if (!dev->supported)
Scott Bauer455a7b22017-02-03 12:50:31 -07002423 return -ENOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -07002424
Jon Derrickeed64952017-02-22 07:55:13 -07002425 p = memdup_user(arg, _IOC_SIZE(cmd));
Scott Bauere225c202017-02-14 17:29:36 -07002426 if (IS_ERR(p))
2427 return PTR_ERR(p);
2428
Scott Bauer455a7b22017-02-03 12:50:31 -07002429 switch (cmd) {
Scott Bauere225c202017-02-14 17:29:36 -07002430 case IOC_OPAL_SAVE:
2431 ret = opal_save(dev, p);
2432 break;
2433 case IOC_OPAL_LOCK_UNLOCK:
2434 ret = opal_lock_unlock(dev, p);
2435 break;
2436 case IOC_OPAL_TAKE_OWNERSHIP:
2437 ret = opal_take_ownership(dev, p);
2438 break;
2439 case IOC_OPAL_ACTIVATE_LSP:
2440 ret = opal_activate_lsp(dev, p);
2441 break;
2442 case IOC_OPAL_SET_PW:
2443 ret = opal_set_new_pw(dev, p);
2444 break;
2445 case IOC_OPAL_ACTIVATE_USR:
2446 ret = opal_activate_user(dev, p);
2447 break;
2448 case IOC_OPAL_REVERT_TPR:
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002449 ret = opal_reverttper(dev, p, false);
Scott Bauere225c202017-02-14 17:29:36 -07002450 break;
2451 case IOC_OPAL_LR_SETUP:
2452 ret = opal_setup_locking_range(dev, p);
2453 break;
2454 case IOC_OPAL_ADD_USR_TO_LR:
2455 ret = opal_add_user_to_lr(dev, p);
2456 break;
2457 case IOC_OPAL_ENABLE_DISABLE_MBR:
2458 ret = opal_enable_disable_shadow_mbr(dev, p);
2459 break;
Jonas Rabensteinc9888442019-05-21 22:46:44 +02002460 case IOC_OPAL_MBR_DONE:
2461 ret = opal_set_mbr_done(dev, p);
2462 break;
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02002463 case IOC_OPAL_WRITE_SHADOW_MBR:
2464 ret = opal_write_shadow_mbr(dev, p);
2465 break;
Scott Bauere225c202017-02-14 17:29:36 -07002466 case IOC_OPAL_ERASE_LR:
2467 ret = opal_erase_locking_range(dev, p);
2468 break;
2469 case IOC_OPAL_SECURE_ERASE_LR:
2470 ret = opal_secure_erase_locking_range(dev, p);
2471 break;
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002472 case IOC_OPAL_PSID_REVERT_TPR:
2473 ret = opal_reverttper(dev, p, true);
2474 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002475 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06002476 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002477 }
Scott Bauere225c202017-02-14 17:29:36 -07002478
2479 kfree(p);
2480 return ret;
Scott Bauer455a7b22017-02-03 12:50:31 -07002481}
2482EXPORT_SYMBOL_GPL(sed_ioctl);