blob: daafadbb88cae7d256d4bab708ec3ac4900ac821 [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 */
Randy Dunlapdc301022019-10-02 19:23:05 -0700132 [OPAL_TABLE_TABLE] =
Jonas Rabensteinff910642019-05-21 22:46:46 +0200133 { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 },
Scott Bauer455a7b22017-02-03 12:50:31 -0700134 [OPAL_LOCKINGRANGE_GLOBAL] =
135 { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
136 [OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
137 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
138 [OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
139 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
140 [OPAL_MBRCONTROL] =
141 { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
142 [OPAL_MBR] =
143 { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
144 [OPAL_AUTHORITY_TABLE] =
145 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
146 [OPAL_C_PIN_TABLE] =
147 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
148 [OPAL_LOCKING_INFO_TABLE] =
149 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
150 [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
151 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
Revanth Rajashekar62c441c2019-10-31 10:13:22 -0600152 [OPAL_DATASTORE] =
153 { 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00 },
Scott Bauer455a7b22017-02-03 12:50:31 -0700154
155 /* C_PIN_TABLE object ID's */
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) */
Scott Bauer455a7b22017-02-03 12:50:31 -0700164 [OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
165 { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
166 [OPAL_HALF_UID_BOOLEAN_ACE] =
167 { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
168
169 /* special value for omitted optional parameter */
170 [OPAL_UID_HEXFF] =
171 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
172};
173
174/*
175 * TCG Storage SSC Methods.
176 * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
177 * Section: 6.3 Assigned UIDs
178 */
Jonas Rabenstein1b6b75b2019-02-14 01:15:55 +0100179static const u8 opalmethod[][OPAL_METHOD_LENGTH] = {
Scott Bauer455a7b22017-02-03 12:50:31 -0700180 [OPAL_PROPERTIES] =
181 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
182 [OPAL_STARTSESSION] =
183 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
184 [OPAL_REVERT] =
185 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
186 [OPAL_ACTIVATE] =
187 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
188 [OPAL_EGET] =
189 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
190 [OPAL_ESET] =
191 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
192 [OPAL_NEXT] =
193 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
194 [OPAL_EAUTHENTICATE] =
195 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
196 [OPAL_GETACL] =
197 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
198 [OPAL_GENKEY] =
199 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
200 [OPAL_REVERTSP] =
201 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
202 [OPAL_GET] =
203 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
204 [OPAL_SET] =
205 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
206 [OPAL_AUTHENTICATE] =
207 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
208 [OPAL_RANDOM] =
209 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
210 [OPAL_ERASE] =
211 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
212};
213
Scott Bauer455a7b22017-02-03 12:50:31 -0700214static int end_opal_session_error(struct opal_dev *dev);
David Kozub0af26482019-02-14 01:16:07 +0100215static int opal_discovery0_step(struct opal_dev *dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700216
217struct opal_suspend_data {
218 struct opal_lock_unlock unlk;
219 u8 lr;
220 struct list_head node;
221};
222
223/*
224 * Derived from:
225 * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
226 * Section: 5.1.5 Method Status Codes
227 */
228static const char * const opal_errors[] = {
229 "Success",
230 "Not Authorized",
231 "Unknown Error",
232 "SP Busy",
233 "SP Failed",
234 "SP Disabled",
235 "SP Frozen",
236 "No Sessions Available",
237 "Uniqueness Conflict",
238 "Insufficient Space",
239 "Insufficient Rows",
240 "Invalid Function",
241 "Invalid Parameter",
242 "Invalid Reference",
243 "Unknown Error",
244 "TPER Malfunction",
245 "Transaction Failure",
246 "Response Overflow",
247 "Authority Locked Out",
248};
249
250static const char *opal_error_to_human(int error)
251{
252 if (error == 0x3f)
253 return "Failed";
254
255 if (error >= ARRAY_SIZE(opal_errors) || error < 0)
256 return "Unknown Error";
257
258 return opal_errors[error];
259}
260
261static void print_buffer(const u8 *ptr, u32 length)
262{
263#ifdef DEBUG
264 print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
265 pr_debug("\n");
266#endif
267}
268
269static bool check_tper(const void *data)
270{
271 const struct d0_tper_features *tper = data;
272 u8 flags = tper->supported_features;
273
274 if (!(flags & TPER_SYNC_SUPPORTED)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600275 pr_debug("TPer sync not supported. flags = %d\n",
276 tper->supported_features);
Scott Bauer455a7b22017-02-03 12:50:31 -0700277 return false;
278 }
279
280 return true;
281}
282
Scott Bauerdbec491b2017-09-01 08:53:35 -0600283static bool check_mbrenabled(const void *data)
284{
285 const struct d0_locking_features *lfeat = data;
286 u8 sup_feat = lfeat->supported_features;
287
288 return !!(sup_feat & MBR_ENABLED_MASK);
289}
290
Scott Bauer455a7b22017-02-03 12:50:31 -0700291static bool check_sum(const void *data)
292{
293 const struct d0_single_user_mode *sum = data;
294 u32 nlo = be32_to_cpu(sum->num_locking_objects);
295
296 if (nlo == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600297 pr_debug("Need at least one locking object.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700298 return false;
299 }
300
301 pr_debug("Number of locking objects: %d\n", nlo);
302
303 return true;
304}
305
306static u16 get_comid_v100(const void *data)
307{
308 const struct d0_opal_v100 *v100 = data;
309
310 return be16_to_cpu(v100->baseComID);
311}
312
313static u16 get_comid_v200(const void *data)
314{
315 const struct d0_opal_v200 *v200 = data;
316
317 return be16_to_cpu(v200->baseComID);
318}
319
320static int opal_send_cmd(struct opal_dev *dev)
321{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100322 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700323 dev->cmd, IO_BUFFER_LENGTH,
324 true);
325}
326
327static int opal_recv_cmd(struct opal_dev *dev)
328{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100329 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700330 dev->resp, IO_BUFFER_LENGTH,
331 false);
332}
333
334static int opal_recv_check(struct opal_dev *dev)
335{
336 size_t buflen = IO_BUFFER_LENGTH;
337 void *buffer = dev->resp;
338 struct opal_header *hdr = buffer;
339 int ret;
340
341 do {
342 pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
343 hdr->cp.outstandingData,
344 hdr->cp.minTransfer);
345
346 if (hdr->cp.outstandingData == 0 ||
347 hdr->cp.minTransfer != 0)
348 return 0;
349
350 memset(buffer, 0, buflen);
351 ret = opal_recv_cmd(dev);
352 } while (!ret);
353
354 return ret;
355}
356
357static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
358{
359 int ret;
360
361 ret = opal_send_cmd(dev);
362 if (ret)
363 return ret;
364 ret = opal_recv_cmd(dev);
365 if (ret)
366 return ret;
367 ret = opal_recv_check(dev);
368 if (ret)
369 return ret;
370 return cont(dev);
371}
372
373static void check_geometry(struct opal_dev *dev, const void *data)
374{
375 const struct d0_geometry_features *geo = data;
376
Randy Dunlapa9eb49c2019-10-02 19:23:15 -0700377 dev->align = be64_to_cpu(geo->alignment_granularity);
378 dev->lowest_lba = be64_to_cpu(geo->lowest_aligned_lba);
Scott Bauer455a7b22017-02-03 12:50:31 -0700379}
380
David Kozub0af26482019-02-14 01:16:07 +0100381static int execute_step(struct opal_dev *dev,
382 const struct opal_step *step, size_t stepIndex)
383{
384 int error = step->fn(dev, step->data);
385
386 if (error) {
387 pr_debug("Step %zu (%pS) failed with error %d: %s\n",
388 stepIndex, step->fn, error,
389 opal_error_to_human(error));
390 }
391
392 return error;
393}
394
David Kozuba80f36c2019-02-14 01:16:08 +0100395static int execute_steps(struct opal_dev *dev,
396 const struct opal_step *steps, size_t n_steps)
Scott Bauer455a7b22017-02-03 12:50:31 -0700397{
David Kozub0af26482019-02-14 01:16:07 +0100398 size_t state = 0;
399 int error;
400
401 /* first do a discovery0 */
402 error = opal_discovery0_step(dev);
403 if (error)
404 return error;
Scott Bauer455a7b22017-02-03 12:50:31 -0700405
David Kozub3db87232019-02-14 01:16:06 +0100406 for (state = 0; state < n_steps; state++) {
David Kozub0af26482019-02-14 01:16:07 +0100407 error = execute_step(dev, &steps[state], state);
David Kozub3db87232019-02-14 01:16:06 +0100408 if (error)
409 goto out_error;
410 }
Scott Bauer455a7b22017-02-03 12:50:31 -0700411
David Kozub3db87232019-02-14 01:16:06 +0100412 return 0;
Scott Bauer2d190202017-02-22 10:15:08 -0700413
David Kozub3db87232019-02-14 01:16:06 +0100414out_error:
415 /*
David Kozub0af26482019-02-14 01:16:07 +0100416 * For each OPAL command the first step in steps starts some sort of
417 * session. If an error occurred in the initial discovery0 or if an
418 * error occurred in the first step (and thus stopping the loop with
419 * state == 0) then there was an error before or during the attempt to
420 * start a session. Therefore we shouldn't attempt to terminate a
421 * session, as one has not yet been created.
David Kozub3db87232019-02-14 01:16:06 +0100422 */
David Kozub0af26482019-02-14 01:16:07 +0100423 if (state > 0)
David Kozub3db87232019-02-14 01:16:06 +0100424 end_opal_session_error(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700425
426 return error;
427}
428
429static int opal_discovery0_end(struct opal_dev *dev)
430{
431 bool found_com_id = false, supported = true, single_user = false;
432 const struct d0_header *hdr = (struct d0_header *)dev->resp;
433 const u8 *epos = dev->resp, *cpos = dev->resp;
434 u16 comid = 0;
Jon Derrick77039b92017-02-21 11:59:15 -0700435 u32 hlen = be32_to_cpu(hdr->length);
Scott Bauer455a7b22017-02-03 12:50:31 -0700436
Jon Derrick77039b92017-02-21 11:59:15 -0700437 print_buffer(dev->resp, hlen);
Scott Bauerdbec491b2017-09-01 08:53:35 -0600438 dev->mbr_enabled = false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700439
Jon Derrick77039b92017-02-21 11:59:15 -0700440 if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600441 pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
442 sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
Jon Derrick77039b92017-02-21 11:59:15 -0700443 return -EFAULT;
444 }
445
446 epos += hlen; /* end of buffer */
Scott Bauer455a7b22017-02-03 12:50:31 -0700447 cpos += sizeof(*hdr); /* current position on buffer */
448
449 while (cpos < epos && supported) {
450 const struct d0_features *body =
451 (const struct d0_features *)cpos;
452
453 switch (be16_to_cpu(body->code)) {
454 case FC_TPER:
455 supported = check_tper(body->features);
456 break;
457 case FC_SINGLEUSER:
458 single_user = check_sum(body->features);
459 break;
460 case FC_GEOMETRY:
461 check_geometry(dev, body);
462 break;
463 case FC_LOCKING:
Scott Bauerdbec491b2017-09-01 08:53:35 -0600464 dev->mbr_enabled = check_mbrenabled(body->features);
465 break;
Scott Bauer455a7b22017-02-03 12:50:31 -0700466 case FC_ENTERPRISE:
467 case FC_DATASTORE:
468 /* some ignored properties */
469 pr_debug("Found OPAL feature description: %d\n",
470 be16_to_cpu(body->code));
471 break;
472 case FC_OPALV100:
473 comid = get_comid_v100(body->features);
474 found_com_id = true;
475 break;
476 case FC_OPALV200:
477 comid = get_comid_v200(body->features);
478 found_com_id = true;
479 break;
480 case 0xbfff ... 0xffff:
481 /* vendor specific, just ignore */
482 break;
483 default:
484 pr_debug("OPAL Unknown feature: %d\n",
485 be16_to_cpu(body->code));
486
487 }
488 cpos += body->length + 4;
489 }
490
491 if (!supported) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100492 pr_debug("This device is not Opal enabled. Not Supported!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700493 return -EOPNOTSUPP;
494 }
495
496 if (!single_user)
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100497 pr_debug("Device doesn't support single user mode\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700498
499
500 if (!found_com_id) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100501 pr_debug("Could not find OPAL comid for device. Returning early\n");
Ingo Molnared7158b2018-02-22 10:54:55 +0100502 return -EOPNOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -0700503 }
504
505 dev->comid = comid;
506
507 return 0;
508}
509
Jon Derrickeed64952017-02-22 07:55:13 -0700510static int opal_discovery0(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -0700511{
512 int ret;
513
514 memset(dev->resp, 0, IO_BUFFER_LENGTH);
515 dev->comid = OPAL_DISCOVERY_COMID;
516 ret = opal_recv_cmd(dev);
517 if (ret)
518 return ret;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600519
Scott Bauer455a7b22017-02-03 12:50:31 -0700520 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 };
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600528
David Kozub0af26482019-02-14 01:16:07 +0100529 return execute_step(dev, &discovery0_step, 0);
530}
531
Jonas Rabensteina9b25b42019-05-21 22:46:45 +0200532static size_t remaining_size(struct opal_dev *cmd)
533{
534 return IO_BUFFER_LENGTH - cmd->pos;
535}
536
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100537static bool can_add(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700538{
539 if (*err)
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100540 return false;
541
Jonas Rabensteina9b25b42019-05-21 22:46:45 +0200542 if (remaining_size(cmd) < len) {
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100543 pr_debug("Error adding %zu bytes: end of buffer.\n", len);
Scott Bauer455a7b22017-02-03 12:50:31 -0700544 *err = -ERANGE;
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100545 return false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700546 }
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100547
548 return true;
549}
550
551static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
552{
553 if (!can_add(err, cmd, 1))
554 return;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600555
Scott Bauer455a7b22017-02-03 12:50:31 -0700556 cmd->cmd[cmd->pos++] = tok;
557}
558
559static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
560 bool has_sign, int len)
561{
562 u8 atom;
563 int err = 0;
564
565 atom = SHORT_ATOM_ID;
566 atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
567 atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
568 atom |= len & SHORT_ATOM_LEN_MASK;
569
570 add_token_u8(&err, cmd, atom);
571}
572
573static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
574 bool has_sign, int len)
575{
576 u8 header0;
577
578 header0 = MEDIUM_ATOM_ID;
579 header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
580 header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
581 header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600582
Scott Bauer455a7b22017-02-03 12:50:31 -0700583 cmd->cmd[cmd->pos++] = header0;
584 cmd->cmd[cmd->pos++] = len;
585}
586
587static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
588{
Scott Bauer455a7b22017-02-03 12:50:31 -0700589 size_t len;
590 int msb;
Scott Bauer455a7b22017-02-03 12:50:31 -0700591
592 if (!(number & ~TINY_ATOM_DATA_MASK)) {
593 add_token_u8(err, cmd, number);
594 return;
595 }
596
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100597 msb = fls64(number);
598 len = DIV_ROUND_UP(msb, 8);
Scott Bauer455a7b22017-02-03 12:50:31 -0700599
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100600 if (!can_add(err, cmd, len + 1)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600601 pr_debug("Error adding u64: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700602 return;
603 }
604 add_short_atom_header(cmd, false, false, len);
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100605 while (len--)
606 add_token_u8(err, cmd, number >> (len * 8));
Scott Bauer455a7b22017-02-03 12:50:31 -0700607}
608
Jonas Rabenstein28559952019-02-14 01:16:02 +0100609static u8 *add_bytestring_header(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700610{
611 size_t header_len = 1;
612 bool is_short_atom = true;
613
Scott Bauer455a7b22017-02-03 12:50:31 -0700614 if (len & ~SHORT_ATOM_LEN_MASK) {
615 header_len = 2;
616 is_short_atom = false;
617 }
618
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100619 if (!can_add(err, cmd, header_len + len)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600620 pr_debug("Error adding bytestring: end of buffer.\n");
Jonas Rabenstein28559952019-02-14 01:16:02 +0100621 return NULL;
Scott Bauer455a7b22017-02-03 12:50:31 -0700622 }
623
624 if (is_short_atom)
625 add_short_atom_header(cmd, true, false, len);
626 else
627 add_medium_atom_header(cmd, true, false, len);
628
Jonas Rabenstein28559952019-02-14 01:16:02 +0100629 return &cmd->cmd[cmd->pos];
630}
Scott Bauer455a7b22017-02-03 12:50:31 -0700631
Jonas Rabenstein28559952019-02-14 01:16:02 +0100632static void add_token_bytestring(int *err, struct opal_dev *cmd,
633 const u8 *bytestring, size_t len)
634{
635 u8 *start;
636
637 start = add_bytestring_header(err, cmd, len);
638 if (!start)
639 return;
640 memcpy(start, bytestring, len);
641 cmd->pos += len;
Scott Bauer455a7b22017-02-03 12:50:31 -0700642}
643
644static int build_locking_range(u8 *buffer, size_t length, u8 lr)
645{
646 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600647 pr_debug("Can't build locking range. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700648 return -ERANGE;
649 }
650
651 memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
652
653 if (lr == 0)
654 return 0;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600655
Scott Bauer455a7b22017-02-03 12:50:31 -0700656 buffer[5] = LOCKING_RANGE_NON_GLOBAL;
657 buffer[7] = lr;
658
659 return 0;
660}
661
662static int build_locking_user(u8 *buffer, size_t length, u8 lr)
663{
664 if (length > OPAL_UID_LENGTH) {
David Kozub1e815b32019-02-14 01:15:54 +0100665 pr_debug("Can't build locking range user. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700666 return -ERANGE;
667 }
668
669 memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
670
671 buffer[7] = lr + 1;
672
673 return 0;
674}
675
676static void set_comid(struct opal_dev *cmd, u16 comid)
677{
678 struct opal_header *hdr = (struct opal_header *)cmd->cmd;
679
680 hdr->cp.extendedComID[0] = comid >> 8;
681 hdr->cp.extendedComID[1] = comid;
682 hdr->cp.extendedComID[2] = 0;
683 hdr->cp.extendedComID[3] = 0;
684}
685
686static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
687{
688 struct opal_header *hdr;
689 int err = 0;
690
Jonas Rabensteina9b25b42019-05-21 22:46:45 +0200691 /*
692 * Close the parameter list opened from cmd_start.
693 * The number of bytes added must be equal to
694 * CMD_FINALIZE_BYTES_NEEDED.
695 */
David Kozub78d584c2019-02-14 01:15:57 +0100696 add_token_u8(&err, cmd, OPAL_ENDLIST);
697
Scott Bauer455a7b22017-02-03 12:50:31 -0700698 add_token_u8(&err, cmd, OPAL_ENDOFDATA);
699 add_token_u8(&err, cmd, OPAL_STARTLIST);
700 add_token_u8(&err, cmd, 0);
701 add_token_u8(&err, cmd, 0);
702 add_token_u8(&err, cmd, 0);
703 add_token_u8(&err, cmd, OPAL_ENDLIST);
704
705 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600706 pr_debug("Error finalizing command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700707 return -EFAULT;
708 }
709
710 hdr = (struct opal_header *) cmd->cmd;
711
712 hdr->pkt.tsn = cpu_to_be32(tsn);
713 hdr->pkt.hsn = cpu_to_be32(hsn);
714
715 hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
716 while (cmd->pos % 4) {
717 if (cmd->pos >= IO_BUFFER_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600718 pr_debug("Error: Buffer overrun\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700719 return -ERANGE;
720 }
721 cmd->cmd[cmd->pos++] = 0;
722 }
723 hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
724 sizeof(hdr->pkt));
725 hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
726
727 return 0;
728}
729
Jon Derrickcccb9242017-02-21 11:59:14 -0700730static const struct opal_resp_tok *response_get_token(
731 const struct parsed_resp *resp,
732 int n)
Scott Bauer455a7b22017-02-03 12:50:31 -0700733{
734 const struct opal_resp_tok *tok;
735
David Kozub7d9b62a2019-02-14 01:15:59 +0100736 if (!resp) {
737 pr_debug("Response is NULL\n");
738 return ERR_PTR(-EINVAL);
739 }
740
Scott Bauer455a7b22017-02-03 12:50:31 -0700741 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600742 pr_debug("Token number doesn't exist: %d, resp: %d\n",
743 n, resp->num);
Jon Derrickcccb9242017-02-21 11:59:14 -0700744 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700745 }
746
747 tok = &resp->toks[n];
748 if (tok->len == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600749 pr_debug("Token length must be non-zero\n");
Jon Derrickcccb9242017-02-21 11:59:14 -0700750 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700751 }
752
Jon Derrickcccb9242017-02-21 11:59:14 -0700753 return tok;
Scott Bauer455a7b22017-02-03 12:50:31 -0700754}
755
Jon Derrickaedb6e22017-02-21 11:59:13 -0700756static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
757 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700758{
759 tok->pos = pos;
760 tok->len = 1;
761 tok->width = OPAL_WIDTH_TINY;
762
763 if (pos[0] & TINY_ATOM_SIGNED) {
764 tok->type = OPAL_DTA_TOKENID_SINT;
765 } else {
766 tok->type = OPAL_DTA_TOKENID_UINT;
767 tok->stored.u = pos[0] & 0x3f;
768 }
769
770 return tok->len;
771}
772
Jon Derrickaedb6e22017-02-21 11:59:13 -0700773static ssize_t response_parse_short(struct opal_resp_tok *tok,
774 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700775{
776 tok->pos = pos;
777 tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
778 tok->width = OPAL_WIDTH_SHORT;
779
780 if (pos[0] & SHORT_ATOM_BYTESTRING) {
781 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
782 } else if (pos[0] & SHORT_ATOM_SIGNED) {
783 tok->type = OPAL_DTA_TOKENID_SINT;
784 } else {
785 u64 u_integer = 0;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700786 ssize_t i, b = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700787
788 tok->type = OPAL_DTA_TOKENID_UINT;
789 if (tok->len > 9) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600790 pr_debug("uint64 with more than 8 bytes\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700791 return -EINVAL;
792 }
793 for (i = tok->len - 1; i > 0; i--) {
794 u_integer |= ((u64)pos[i] << (8 * b));
795 b++;
796 }
797 tok->stored.u = u_integer;
798 }
799
800 return tok->len;
801}
802
Jon Derrickaedb6e22017-02-21 11:59:13 -0700803static ssize_t response_parse_medium(struct opal_resp_tok *tok,
804 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700805{
806 tok->pos = pos;
807 tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
808 tok->width = OPAL_WIDTH_MEDIUM;
809
810 if (pos[0] & MEDIUM_ATOM_BYTESTRING)
811 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
812 else if (pos[0] & MEDIUM_ATOM_SIGNED)
813 tok->type = OPAL_DTA_TOKENID_SINT;
814 else
815 tok->type = OPAL_DTA_TOKENID_UINT;
816
817 return tok->len;
818}
819
Jon Derrickaedb6e22017-02-21 11:59:13 -0700820static ssize_t response_parse_long(struct opal_resp_tok *tok,
821 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700822{
823 tok->pos = pos;
824 tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
825 tok->width = OPAL_WIDTH_LONG;
826
827 if (pos[0] & LONG_ATOM_BYTESTRING)
828 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
829 else if (pos[0] & LONG_ATOM_SIGNED)
830 tok->type = OPAL_DTA_TOKENID_SINT;
831 else
832 tok->type = OPAL_DTA_TOKENID_UINT;
833
834 return tok->len;
835}
836
Jon Derrickaedb6e22017-02-21 11:59:13 -0700837static ssize_t response_parse_token(struct opal_resp_tok *tok,
838 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700839{
840 tok->pos = pos;
841 tok->len = 1;
842 tok->type = OPAL_DTA_TOKENID_TOKEN;
843 tok->width = OPAL_WIDTH_TOKEN;
844
845 return tok->len;
846}
847
848static int response_parse(const u8 *buf, size_t length,
849 struct parsed_resp *resp)
850{
851 const struct opal_header *hdr;
852 struct opal_resp_tok *iter;
853 int num_entries = 0;
854 int total;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700855 ssize_t token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700856 const u8 *pos;
Jon Derrick77039b92017-02-21 11:59:15 -0700857 u32 clen, plen, slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700858
859 if (!buf)
860 return -EFAULT;
861
862 if (!resp)
863 return -EFAULT;
864
865 hdr = (struct opal_header *)buf;
866 pos = buf;
867 pos += sizeof(*hdr);
868
Jon Derrick77039b92017-02-21 11:59:15 -0700869 clen = be32_to_cpu(hdr->cp.length);
870 plen = be32_to_cpu(hdr->pkt.length);
871 slen = be32_to_cpu(hdr->subpkt.length);
872 pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
873 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700874
Jon Derrick77039b92017-02-21 11:59:15 -0700875 if (clen == 0 || plen == 0 || slen == 0 ||
876 slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600877 pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
878 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700879 print_buffer(pos, sizeof(*hdr));
880 return -EINVAL;
881 }
882
883 if (pos > buf + length)
884 return -EFAULT;
885
886 iter = resp->toks;
Jon Derrick77039b92017-02-21 11:59:15 -0700887 total = slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700888 print_buffer(pos, total);
889 while (total > 0) {
890 if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
891 token_length = response_parse_tiny(iter, pos);
892 else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
893 token_length = response_parse_short(iter, pos);
894 else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
895 token_length = response_parse_medium(iter, pos);
896 else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
897 token_length = response_parse_long(iter, pos);
898 else /* TOKEN */
899 token_length = response_parse_token(iter, pos);
900
Jon Derrickaedb6e22017-02-21 11:59:13 -0700901 if (token_length < 0)
902 return token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700903
904 pos += token_length;
905 total -= token_length;
906 iter++;
907 num_entries++;
908 }
909
Scott Bauer455a7b22017-02-03 12:50:31 -0700910 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;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600948
David Kozubb68f09e2019-02-14 01:16:00 +0100949 return tok->len - skip;
Scott Bauer455a7b22017-02-03 12:50:31 -0700950}
951
952static u64 response_get_u64(const struct parsed_resp *resp, int n)
953{
David Kozubb68f09e2019-02-14 01:16:00 +0100954 const struct opal_resp_tok *tok;
955
956 tok = response_get_token(resp, n);
957 if (IS_ERR(tok))
958 return 0;
959
960 if (tok->type != OPAL_DTA_TOKENID_UINT) {
961 pr_debug("Token is not unsigned int: %d\n", tok->type);
Scott Bauer455a7b22017-02-03 12:50:31 -0700962 return 0;
963 }
964
David Kozubb68f09e2019-02-14 01:16:00 +0100965 if (tok->width != OPAL_WIDTH_TINY && tok->width != OPAL_WIDTH_SHORT) {
966 pr_debug("Atom is not short or tiny: %d\n", tok->width);
Scott Bauer455a7b22017-02-03 12:50:31 -0700967 return 0;
968 }
969
David Kozubb68f09e2019-02-14 01:16:00 +0100970 return tok->stored.u;
Scott Bauer455a7b22017-02-03 12:50:31 -0700971}
972
Jon Derrickcccb9242017-02-21 11:59:14 -0700973static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
974{
975 if (IS_ERR(token) ||
976 token->type != OPAL_DTA_TOKENID_TOKEN ||
977 token->pos[0] != match)
978 return false;
979 return true;
980}
981
Scott Bauer455a7b22017-02-03 12:50:31 -0700982static u8 response_status(const struct parsed_resp *resp)
983{
Jon Derrickcccb9242017-02-21 11:59:14 -0700984 const struct opal_resp_tok *tok;
985
986 tok = response_get_token(resp, 0);
987 if (response_token_matches(tok, OPAL_ENDOFSESSION))
Scott Bauer455a7b22017-02-03 12:50:31 -0700988 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700989
990 if (resp->num < 5)
991 return DTAERROR_NO_METHOD_STATUS;
992
Jon Derrickcccb9242017-02-21 11:59:14 -0700993 tok = response_get_token(resp, resp->num - 5);
994 if (!response_token_matches(tok, OPAL_STARTLIST))
995 return DTAERROR_NO_METHOD_STATUS;
996
997 tok = response_get_token(resp, resp->num - 1);
998 if (!response_token_matches(tok, OPAL_ENDLIST))
Scott Bauer455a7b22017-02-03 12:50:31 -0700999 return DTAERROR_NO_METHOD_STATUS;
1000
1001 return response_get_u64(resp, resp->num - 4);
1002}
1003
1004/* Parses and checks for errors */
1005static int parse_and_check_status(struct opal_dev *dev)
1006{
1007 int error;
1008
1009 print_buffer(dev->cmd, dev->pos);
1010
1011 error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
1012 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001013 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001014 return error;
1015 }
1016
1017 return response_status(&dev->parsed);
1018}
1019
1020static void clear_opal_cmd(struct opal_dev *dev)
1021{
1022 dev->pos = sizeof(struct opal_header);
1023 memset(dev->cmd, 0, IO_BUFFER_LENGTH);
1024}
1025
David Kozube8b29222019-02-14 01:15:58 +01001026static int cmd_start(struct opal_dev *dev, const u8 *uid, const u8 *method)
1027{
1028 int err = 0;
1029
1030 clear_opal_cmd(dev);
1031 set_comid(dev, dev->comid);
1032
1033 add_token_u8(&err, dev, OPAL_CALL);
1034 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1035 add_token_bytestring(&err, dev, method, OPAL_METHOD_LENGTH);
1036
1037 /*
1038 * Every method call is followed by its parameters enclosed within
1039 * OPAL_STARTLIST and OPAL_ENDLIST tokens. We automatically open the
1040 * parameter list here and close it later in cmd_finalize.
1041 */
1042 add_token_u8(&err, dev, OPAL_STARTLIST);
1043
1044 return err;
1045}
1046
Scott Bauer455a7b22017-02-03 12:50:31 -07001047static int start_opal_session_cont(struct opal_dev *dev)
1048{
1049 u32 hsn, tsn;
1050 int error = 0;
1051
1052 error = parse_and_check_status(dev);
1053 if (error)
1054 return error;
1055
1056 hsn = response_get_u64(&dev->parsed, 4);
1057 tsn = response_get_u64(&dev->parsed, 5);
1058
Revanth Rajashekar88d60412020-03-03 12:17:00 -07001059 if (hsn != GENERIC_HOST_SESSION_NUM || tsn < FIRST_TPER_SESSION_NUM) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001060 pr_debug("Couldn't authenticate session\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001061 return -EPERM;
1062 }
1063
1064 dev->hsn = hsn;
1065 dev->tsn = tsn;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001066
Scott Bauer455a7b22017-02-03 12:50:31 -07001067 return 0;
1068}
1069
1070static void add_suspend_info(struct opal_dev *dev,
1071 struct opal_suspend_data *sus)
1072{
1073 struct opal_suspend_data *iter;
1074
1075 list_for_each_entry(iter, &dev->unlk_lst, node) {
1076 if (iter->lr == sus->lr) {
1077 list_del(&iter->node);
1078 kfree(iter);
1079 break;
1080 }
1081 }
1082 list_add_tail(&sus->node, &dev->unlk_lst);
1083}
1084
1085static int end_session_cont(struct opal_dev *dev)
1086{
1087 dev->hsn = 0;
1088 dev->tsn = 0;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001089
Scott Bauer455a7b22017-02-03 12:50:31 -07001090 return parse_and_check_status(dev);
1091}
1092
1093static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1094{
1095 int ret;
1096
1097 ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1098 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001099 pr_debug("Error finalizing command buffer: %d\n", ret);
Scott Bauer455a7b22017-02-03 12:50:31 -07001100 return ret;
1101 }
1102
1103 print_buffer(dev->cmd, dev->pos);
1104
1105 return opal_send_recv(dev, cont);
1106}
1107
David Kozub3fff2342019-02-14 01:16:04 +01001108/*
1109 * request @column from table @table on device @dev. On success, the column
1110 * data will be available in dev->resp->tok[4]
1111 */
1112static int generic_get_column(struct opal_dev *dev, const u8 *table,
1113 u64 column)
1114{
1115 int err;
1116
1117 err = cmd_start(dev, table, opalmethod[OPAL_GET]);
1118
1119 add_token_u8(&err, dev, OPAL_STARTLIST);
1120
1121 add_token_u8(&err, dev, OPAL_STARTNAME);
1122 add_token_u8(&err, dev, OPAL_STARTCOLUMN);
1123 add_token_u64(&err, dev, column);
1124 add_token_u8(&err, dev, OPAL_ENDNAME);
1125
1126 add_token_u8(&err, dev, OPAL_STARTNAME);
1127 add_token_u8(&err, dev, OPAL_ENDCOLUMN);
1128 add_token_u64(&err, dev, column);
1129 add_token_u8(&err, dev, OPAL_ENDNAME);
1130
1131 add_token_u8(&err, dev, OPAL_ENDLIST);
1132
1133 if (err)
1134 return err;
1135
1136 return finalize_and_send(dev, parse_and_check_status);
1137}
1138
Jonas Rabensteinff910642019-05-21 22:46:46 +02001139/*
1140 * see TCG SAS 5.3.2.3 for a description of the available columns
1141 *
1142 * the result is provided in dev->resp->tok[4]
1143 */
Revanth Rajashekar3495ea12019-10-31 10:13:20 -06001144static int generic_get_table_info(struct opal_dev *dev, const u8 *table_uid,
Jonas Rabensteinff910642019-05-21 22:46:46 +02001145 u64 column)
1146{
1147 u8 uid[OPAL_UID_LENGTH];
Revanth Rajashekar3495ea12019-10-31 10:13:20 -06001148 const unsigned int half = OPAL_UID_LENGTH_HALF;
Jonas Rabensteinff910642019-05-21 22:46:46 +02001149
1150 /* sed-opal UIDs can be split in two halves:
1151 * first: actual table index
1152 * second: relative index in the table
1153 * so we have to get the first half of the OPAL_TABLE_TABLE and use the
1154 * first part of the target table as relative index into that table
1155 */
1156 memcpy(uid, opaluid[OPAL_TABLE_TABLE], half);
Revanth Rajashekar3495ea12019-10-31 10:13:20 -06001157 memcpy(uid + half, table_uid, half);
Jonas Rabensteinff910642019-05-21 22:46:46 +02001158
1159 return generic_get_column(dev, uid, column);
1160}
1161
Jon Derrickeed64952017-02-22 07:55:13 -07001162static int gen_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001163{
Scott Bauer455a7b22017-02-03 12:50:31 -07001164 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001165 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001166
1167 memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
Scott Bauer455a7b22017-02-03 12:50:31 -07001168 kfree(dev->prev_data);
1169 dev->prev_data = NULL;
1170
David Kozube8b29222019-02-14 01:15:58 +01001171 err = cmd_start(dev, uid, opalmethod[OPAL_GENKEY]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001172
1173 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001174 pr_debug("Error building gen key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001175 return err;
1176
1177 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001178
Scott Bauer455a7b22017-02-03 12:50:31 -07001179 return finalize_and_send(dev, parse_and_check_status);
1180}
1181
1182static int get_active_key_cont(struct opal_dev *dev)
1183{
1184 const char *activekey;
1185 size_t keylen;
1186 int error = 0;
1187
1188 error = parse_and_check_status(dev);
1189 if (error)
1190 return error;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001191
Scott Bauer455a7b22017-02-03 12:50:31 -07001192 keylen = response_get_string(&dev->parsed, 4, &activekey);
1193 if (!activekey) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001194 pr_debug("%s: Couldn't extract the Activekey from the response\n",
1195 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001196 return OPAL_INVAL_PARAM;
1197 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001198
Scott Bauer455a7b22017-02-03 12:50:31 -07001199 dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1200
1201 if (!dev->prev_data)
1202 return -ENOMEM;
1203
1204 dev->prev_d_len = keylen;
1205
1206 return 0;
1207}
1208
Jon Derrickeed64952017-02-22 07:55:13 -07001209static int get_active_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001210{
1211 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001212 int err;
Jon Derrickeed64952017-02-22 07:55:13 -07001213 u8 *lr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001214
Scott Bauer455a7b22017-02-03 12:50:31 -07001215 err = build_locking_range(uid, sizeof(uid), *lr);
1216 if (err)
1217 return err;
1218
David Kozub3fff2342019-02-14 01:16:04 +01001219 err = generic_get_column(dev, uid, OPAL_ACTIVEKEY);
1220 if (err)
Scott Bauer455a7b22017-02-03 12:50:31 -07001221 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001222
David Kozub3fff2342019-02-14 01:16:04 +01001223 return get_active_key_cont(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001224}
1225
Revanth Rajashekar3495ea12019-10-31 10:13:20 -06001226static int generic_table_write_data(struct opal_dev *dev, const u64 data,
1227 u64 offset, u64 size, const u8 *uid)
1228{
1229 const u8 __user *src = (u8 __user *)(uintptr_t)data;
1230 u8 *dst;
1231 u64 len;
1232 size_t off = 0;
1233 int err;
1234
1235 /* do we fit in the available space? */
1236 err = generic_get_table_info(dev, uid, OPAL_TABLE_ROWS);
1237 if (err) {
1238 pr_debug("Couldn't get the table size\n");
1239 return err;
1240 }
1241
1242 len = response_get_u64(&dev->parsed, 4);
1243 if (size > len || offset > len - size) {
1244 pr_debug("Does not fit in the table (%llu vs. %llu)\n",
1245 offset + size, len);
1246 return -ENOSPC;
1247 }
1248
1249 /* do the actual transmission(s) */
1250 while (off < size) {
1251 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
1252 add_token_u8(&err, dev, OPAL_STARTNAME);
1253 add_token_u8(&err, dev, OPAL_WHERE);
1254 add_token_u64(&err, dev, offset + off);
1255 add_token_u8(&err, dev, OPAL_ENDNAME);
1256
1257 add_token_u8(&err, dev, OPAL_STARTNAME);
1258 add_token_u8(&err, dev, OPAL_VALUES);
1259
1260 /*
1261 * The bytestring header is either 1 or 2 bytes, so assume 2.
1262 * There also needs to be enough space to accommodate the
1263 * trailing OPAL_ENDNAME (1 byte) and tokens added by
1264 * cmd_finalize.
1265 */
1266 len = min(remaining_size(dev) - (2+1+CMD_FINALIZE_BYTES_NEEDED),
1267 (size_t)(size - off));
1268 pr_debug("Write bytes %zu+%llu/%llu\n", off, len, size);
1269
1270 dst = add_bytestring_header(&err, dev, len);
1271 if (!dst)
1272 break;
1273
1274 if (copy_from_user(dst, src + off, len)) {
1275 err = -EFAULT;
1276 break;
1277 }
1278
1279 dev->pos += len;
1280
1281 add_token_u8(&err, dev, OPAL_ENDNAME);
1282 if (err)
1283 break;
1284
1285 err = finalize_and_send(dev, parse_and_check_status);
1286 if (err)
1287 break;
1288
1289 off += len;
1290 }
1291
1292 return err;
1293}
1294
Scott Bauer455a7b22017-02-03 12:50:31 -07001295static int generic_lr_enable_disable(struct opal_dev *dev,
1296 u8 *uid, bool rle, bool wle,
1297 bool rl, bool wl)
1298{
David Kozube8b29222019-02-14 01:15:58 +01001299 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001300
David Kozube8b29222019-02-14 01:15:58 +01001301 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001302
Scott Bauer455a7b22017-02-03 12:50:31 -07001303 add_token_u8(&err, dev, OPAL_STARTNAME);
1304 add_token_u8(&err, dev, OPAL_VALUES);
1305 add_token_u8(&err, dev, OPAL_STARTLIST);
1306
1307 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001308 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001309 add_token_u8(&err, dev, rle);
1310 add_token_u8(&err, dev, OPAL_ENDNAME);
1311
1312 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001313 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001314 add_token_u8(&err, dev, wle);
1315 add_token_u8(&err, dev, OPAL_ENDNAME);
1316
1317 add_token_u8(&err, dev, OPAL_STARTNAME);
1318 add_token_u8(&err, dev, OPAL_READLOCKED);
1319 add_token_u8(&err, dev, rl);
1320 add_token_u8(&err, dev, OPAL_ENDNAME);
1321
1322 add_token_u8(&err, dev, OPAL_STARTNAME);
1323 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1324 add_token_u8(&err, dev, wl);
1325 add_token_u8(&err, dev, OPAL_ENDNAME);
1326
1327 add_token_u8(&err, dev, OPAL_ENDLIST);
1328 add_token_u8(&err, dev, OPAL_ENDNAME);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001329
Scott Bauer455a7b22017-02-03 12:50:31 -07001330 return err;
1331}
1332
1333static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1334 struct opal_user_lr_setup *setup)
1335{
1336 int err;
1337
1338 err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1339 0, 0);
1340 if (err)
Scott Bauer591c59d2017-04-07 13:58:50 -06001341 pr_debug("Failed to create enable global lr command\n");
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001342
Scott Bauer455a7b22017-02-03 12:50:31 -07001343 return err;
1344}
1345
Jon Derrickeed64952017-02-22 07:55:13 -07001346static int setup_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001347{
1348 u8 uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001349 struct opal_user_lr_setup *setup = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001350 u8 lr;
David Kozube8b29222019-02-14 01:15:58 +01001351 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001352
Scott Bauer455a7b22017-02-03 12:50:31 -07001353 lr = setup->session.opal_key.lr;
1354 err = build_locking_range(uid, sizeof(uid), lr);
1355 if (err)
1356 return err;
1357
1358 if (lr == 0)
1359 err = enable_global_lr(dev, uid, setup);
1360 else {
David Kozube8b29222019-02-14 01:15:58 +01001361 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001362
Scott Bauer455a7b22017-02-03 12:50:31 -07001363 add_token_u8(&err, dev, OPAL_STARTNAME);
1364 add_token_u8(&err, dev, OPAL_VALUES);
1365 add_token_u8(&err, dev, OPAL_STARTLIST);
1366
1367 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001368 add_token_u8(&err, dev, OPAL_RANGESTART);
Scott Bauer455a7b22017-02-03 12:50:31 -07001369 add_token_u64(&err, dev, setup->range_start);
1370 add_token_u8(&err, dev, OPAL_ENDNAME);
1371
1372 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001373 add_token_u8(&err, dev, OPAL_RANGELENGTH);
Scott Bauer455a7b22017-02-03 12:50:31 -07001374 add_token_u64(&err, dev, setup->range_length);
1375 add_token_u8(&err, dev, OPAL_ENDNAME);
1376
1377 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001378 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001379 add_token_u64(&err, dev, !!setup->RLE);
1380 add_token_u8(&err, dev, OPAL_ENDNAME);
1381
1382 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001383 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001384 add_token_u64(&err, dev, !!setup->WLE);
1385 add_token_u8(&err, dev, OPAL_ENDNAME);
1386
1387 add_token_u8(&err, dev, OPAL_ENDLIST);
1388 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001389 }
1390 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001391 pr_debug("Error building Setup Locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001392 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001393 }
1394
1395 return finalize_and_send(dev, parse_and_check_status);
1396}
1397
1398static int start_generic_opal_session(struct opal_dev *dev,
1399 enum opal_uid auth,
1400 enum opal_uid sp_type,
1401 const char *key,
1402 u8 key_len)
1403{
1404 u32 hsn;
David Kozube8b29222019-02-14 01:15:58 +01001405 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001406
Scott Bauer591c59d2017-04-07 13:58:50 -06001407 if (key == NULL && auth != OPAL_ANYBODY_UID)
Scott Bauer455a7b22017-02-03 12:50:31 -07001408 return OPAL_INVAL_PARAM;
Scott Bauer455a7b22017-02-03 12:50:31 -07001409
Scott Bauer455a7b22017-02-03 12:50:31 -07001410 hsn = GENERIC_HOST_SESSION_NUM;
David Kozube8b29222019-02-14 01:15:58 +01001411 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1412 opalmethod[OPAL_STARTSESSION]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001413
Scott Bauer455a7b22017-02-03 12:50:31 -07001414 add_token_u64(&err, dev, hsn);
1415 add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1416 add_token_u8(&err, dev, 1);
1417
1418 switch (auth) {
1419 case OPAL_ANYBODY_UID:
Scott Bauer455a7b22017-02-03 12:50:31 -07001420 break;
1421 case OPAL_ADMIN1_UID:
1422 case OPAL_SID_UID:
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06001423 case OPAL_PSID_UID:
Scott Bauer455a7b22017-02-03 12:50:31 -07001424 add_token_u8(&err, dev, OPAL_STARTNAME);
1425 add_token_u8(&err, dev, 0); /* HostChallenge */
1426 add_token_bytestring(&err, dev, key, key_len);
1427 add_token_u8(&err, dev, OPAL_ENDNAME);
1428 add_token_u8(&err, dev, OPAL_STARTNAME);
1429 add_token_u8(&err, dev, 3); /* HostSignAuth */
1430 add_token_bytestring(&err, dev, opaluid[auth],
1431 OPAL_UID_LENGTH);
1432 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001433 break;
1434 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001435 pr_debug("Cannot start Admin SP session with auth %d\n", auth);
Scott Bauer455a7b22017-02-03 12:50:31 -07001436 return OPAL_INVAL_PARAM;
1437 }
1438
1439 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001440 pr_debug("Error building start adminsp session command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001441 return err;
1442 }
1443
1444 return finalize_and_send(dev, start_opal_session_cont);
1445}
1446
Jon Derrickeed64952017-02-22 07:55:13 -07001447static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001448{
1449 return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1450 OPAL_ADMINSP_UID, NULL, 0);
1451}
1452
Jon Derrickeed64952017-02-22 07:55:13 -07001453static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001454{
1455 int ret;
1456 const u8 *key = dev->prev_data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001457
1458 if (!key) {
Jon Derrickeed64952017-02-22 07:55:13 -07001459 const struct opal_key *okey = data;
David Kozub1e815b32019-02-14 01:15:54 +01001460
Scott Bauer455a7b22017-02-03 12:50:31 -07001461 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1462 OPAL_ADMINSP_UID,
1463 okey->key,
1464 okey->key_len);
1465 } else {
1466 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1467 OPAL_ADMINSP_UID,
1468 key, dev->prev_d_len);
1469 kfree(key);
1470 dev->prev_data = NULL;
1471 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001472
Scott Bauer455a7b22017-02-03 12:50:31 -07001473 return ret;
1474}
1475
Jon Derrickeed64952017-02-22 07:55:13 -07001476static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001477{
Jon Derrickeed64952017-02-22 07:55:13 -07001478 struct opal_key *key = data;
David Kozub1e815b32019-02-14 01:15:54 +01001479
Scott Bauer455a7b22017-02-03 12:50:31 -07001480 return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1481 OPAL_LOCKINGSP_UID,
1482 key->key, key->key_len);
1483}
1484
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06001485static int start_PSID_opal_session(struct opal_dev *dev, void *data)
1486{
1487 const struct opal_key *okey = data;
1488
1489 return start_generic_opal_session(dev, OPAL_PSID_UID,
1490 OPAL_ADMINSP_UID,
1491 okey->key,
1492 okey->key_len);
1493}
1494
Jon Derrickeed64952017-02-22 07:55:13 -07001495static int start_auth_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001496{
Jon Derrickeed64952017-02-22 07:55:13 -07001497 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001498 u8 lk_ul_user[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001499 size_t keylen = session->opal_key.key_len;
Scott Bauer455a7b22017-02-03 12:50:31 -07001500 int err = 0;
1501
Scott Bauer455a7b22017-02-03 12:50:31 -07001502 u8 *key = session->opal_key.key;
1503 u32 hsn = GENERIC_HOST_SESSION_NUM;
1504
David Kozube8b29222019-02-14 01:15:58 +01001505 if (session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001506 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1507 session->opal_key.lr);
David Kozube8b29222019-02-14 01:15:58 +01001508 else if (session->who != OPAL_ADMIN1 && !session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001509 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1510 session->who - 1);
David Kozube8b29222019-02-14 01:15:58 +01001511 else
Scott Bauer455a7b22017-02-03 12:50:31 -07001512 memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1513
David Kozube8b29222019-02-14 01:15:58 +01001514 if (err)
1515 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001516
David Kozube8b29222019-02-14 01:15:58 +01001517 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1518 opalmethod[OPAL_STARTSESSION]);
1519
Scott Bauer455a7b22017-02-03 12:50:31 -07001520 add_token_u64(&err, dev, hsn);
1521 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1522 OPAL_UID_LENGTH);
1523 add_token_u8(&err, dev, 1);
1524 add_token_u8(&err, dev, OPAL_STARTNAME);
1525 add_token_u8(&err, dev, 0);
1526 add_token_bytestring(&err, dev, key, keylen);
1527 add_token_u8(&err, dev, OPAL_ENDNAME);
1528 add_token_u8(&err, dev, OPAL_STARTNAME);
1529 add_token_u8(&err, dev, 3);
1530 add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1531 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001532
1533 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001534 pr_debug("Error building STARTSESSION command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001535 return err;
1536 }
1537
1538 return finalize_and_send(dev, start_opal_session_cont);
1539}
1540
Jon Derrickeed64952017-02-22 07:55:13 -07001541static int revert_tper(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001542{
David Kozube8b29222019-02-14 01:15:58 +01001543 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001544
David Kozube8b29222019-02-14 01:15:58 +01001545 err = cmd_start(dev, opaluid[OPAL_ADMINSP_UID],
1546 opalmethod[OPAL_REVERT]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001547 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001548 pr_debug("Error building REVERT TPER command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001549 return err;
1550 }
1551
1552 return finalize_and_send(dev, parse_and_check_status);
1553}
1554
Jon Derrickeed64952017-02-22 07:55:13 -07001555static int internal_activate_user(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001556{
Jon Derrickeed64952017-02-22 07:55:13 -07001557 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001558 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001559 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001560
1561 memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1562 uid[7] = session->who;
1563
David Kozube8b29222019-02-14 01:15:58 +01001564 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001565 add_token_u8(&err, dev, OPAL_STARTNAME);
1566 add_token_u8(&err, dev, OPAL_VALUES);
1567 add_token_u8(&err, dev, OPAL_STARTLIST);
1568 add_token_u8(&err, dev, OPAL_STARTNAME);
1569 add_token_u8(&err, dev, 5); /* Enabled */
1570 add_token_u8(&err, dev, OPAL_TRUE);
1571 add_token_u8(&err, dev, OPAL_ENDNAME);
1572 add_token_u8(&err, dev, OPAL_ENDLIST);
1573 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001574
1575 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001576 pr_debug("Error building Activate UserN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001577 return err;
1578 }
1579
1580 return finalize_and_send(dev, parse_and_check_status);
1581}
1582
Jon Derrickeed64952017-02-22 07:55:13 -07001583static int erase_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001584{
Jon Derrickeed64952017-02-22 07:55:13 -07001585 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001586 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001587 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001588
1589 if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1590 return -ERANGE;
1591
David Kozube8b29222019-02-14 01:15:58 +01001592 err = cmd_start(dev, uid, opalmethod[OPAL_ERASE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001593
1594 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001595 pr_debug("Error building Erase Locking Range Command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001596 return err;
1597 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001598
Scott Bauer455a7b22017-02-03 12:50:31 -07001599 return finalize_and_send(dev, parse_and_check_status);
1600}
1601
Jon Derrickeed64952017-02-22 07:55:13 -07001602static int set_mbr_done(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001603{
Jon Derrickeed64952017-02-22 07:55:13 -07001604 u8 *mbr_done_tf = data;
David Kozube8b29222019-02-14 01:15:58 +01001605 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001606
David Kozube8b29222019-02-14 01:15:58 +01001607 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1608 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001609
Scott Bauer455a7b22017-02-03 12:50:31 -07001610 add_token_u8(&err, dev, OPAL_STARTNAME);
1611 add_token_u8(&err, dev, OPAL_VALUES);
1612 add_token_u8(&err, dev, OPAL_STARTLIST);
1613 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001614 add_token_u8(&err, dev, OPAL_MBRDONE);
Jon Derrickeed64952017-02-22 07:55:13 -07001615 add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
Scott Bauer455a7b22017-02-03 12:50:31 -07001616 add_token_u8(&err, dev, OPAL_ENDNAME);
1617 add_token_u8(&err, dev, OPAL_ENDLIST);
1618 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001619
1620 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001621 pr_debug("Error Building set MBR Done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001622 return err;
1623 }
1624
1625 return finalize_and_send(dev, parse_and_check_status);
1626}
1627
Jon Derrickeed64952017-02-22 07:55:13 -07001628static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001629{
Jon Derrickeed64952017-02-22 07:55:13 -07001630 u8 *mbr_en_dis = data;
David Kozube8b29222019-02-14 01:15:58 +01001631 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001632
David Kozube8b29222019-02-14 01:15:58 +01001633 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1634 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001635
Scott Bauer455a7b22017-02-03 12:50:31 -07001636 add_token_u8(&err, dev, OPAL_STARTNAME);
1637 add_token_u8(&err, dev, OPAL_VALUES);
1638 add_token_u8(&err, dev, OPAL_STARTLIST);
1639 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001640 add_token_u8(&err, dev, OPAL_MBRENABLE);
Jon Derrickeed64952017-02-22 07:55:13 -07001641 add_token_u8(&err, dev, *mbr_en_dis);
Scott Bauer455a7b22017-02-03 12:50:31 -07001642 add_token_u8(&err, dev, OPAL_ENDNAME);
1643 add_token_u8(&err, dev, OPAL_ENDLIST);
1644 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001645
1646 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001647 pr_debug("Error Building set MBR done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001648 return err;
1649 }
1650
1651 return finalize_and_send(dev, parse_and_check_status);
1652}
1653
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02001654static int write_shadow_mbr(struct opal_dev *dev, void *data)
1655{
1656 struct opal_shadow_mbr *shadow = data;
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02001657
Revanth Rajashekar3495ea12019-10-31 10:13:20 -06001658 return generic_table_write_data(dev, shadow->data, shadow->offset,
1659 shadow->size, opaluid[OPAL_MBR]);
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02001660}
1661
Scott Bauer455a7b22017-02-03 12:50:31 -07001662static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1663 struct opal_dev *dev)
1664{
David Kozube8b29222019-02-14 01:15:58 +01001665 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001666
David Kozube8b29222019-02-14 01:15:58 +01001667 err = cmd_start(dev, cpin_uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001668
Scott Bauer455a7b22017-02-03 12:50:31 -07001669 add_token_u8(&err, dev, OPAL_STARTNAME);
1670 add_token_u8(&err, dev, OPAL_VALUES);
1671 add_token_u8(&err, dev, OPAL_STARTLIST);
1672 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001673 add_token_u8(&err, dev, OPAL_PIN);
Scott Bauer455a7b22017-02-03 12:50:31 -07001674 add_token_bytestring(&err, dev, key, key_len);
1675 add_token_u8(&err, dev, OPAL_ENDNAME);
1676 add_token_u8(&err, dev, OPAL_ENDLIST);
1677 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001678
1679 return err;
1680}
1681
Jon Derrickeed64952017-02-22 07:55:13 -07001682static int set_new_pw(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001683{
1684 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001685 struct opal_session_info *usr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001686
1687 memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1688
1689 if (usr->who != OPAL_ADMIN1) {
1690 cpin_uid[5] = 0x03;
1691 if (usr->sum)
1692 cpin_uid[7] = usr->opal_key.lr + 1;
1693 else
1694 cpin_uid[7] = usr->who;
1695 }
1696
1697 if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1698 cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001699 pr_debug("Error building set password command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001700 return -ERANGE;
1701 }
1702
1703 return finalize_and_send(dev, parse_and_check_status);
1704}
1705
Jon Derrickeed64952017-02-22 07:55:13 -07001706static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001707{
1708 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001709 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001710
1711 memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1712
1713 if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001714 pr_debug("Error building Set SID cpin\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001715 return -ERANGE;
1716 }
1717 return finalize_and_send(dev, parse_and_check_status);
1718}
1719
Jon Derrickeed64952017-02-22 07:55:13 -07001720static int add_user_to_lr(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001721{
1722 u8 lr_buffer[OPAL_UID_LENGTH];
1723 u8 user_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001724 struct opal_lock_unlock *lkul = data;
David Kozube8b29222019-02-14 01:15:58 +01001725 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001726
Scott Bauer455a7b22017-02-03 12:50:31 -07001727 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1728 OPAL_UID_LENGTH);
1729
1730 if (lkul->l_state == OPAL_RW)
1731 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1732 OPAL_UID_LENGTH);
1733
1734 lr_buffer[7] = lkul->session.opal_key.lr;
1735
1736 memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1737
1738 user_uid[7] = lkul->session.who;
1739
David Kozube8b29222019-02-14 01:15:58 +01001740 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001741
Scott Bauer455a7b22017-02-03 12:50:31 -07001742 add_token_u8(&err, dev, OPAL_STARTNAME);
1743 add_token_u8(&err, dev, OPAL_VALUES);
1744
1745 add_token_u8(&err, dev, OPAL_STARTLIST);
1746 add_token_u8(&err, dev, OPAL_STARTNAME);
1747 add_token_u8(&err, dev, 3);
1748
1749 add_token_u8(&err, dev, OPAL_STARTLIST);
1750
1751
1752 add_token_u8(&err, dev, OPAL_STARTNAME);
1753 add_token_bytestring(&err, dev,
1754 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1755 OPAL_UID_LENGTH/2);
1756 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1757 add_token_u8(&err, dev, OPAL_ENDNAME);
1758
1759
1760 add_token_u8(&err, dev, OPAL_STARTNAME);
1761 add_token_bytestring(&err, dev,
1762 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1763 OPAL_UID_LENGTH/2);
1764 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1765 add_token_u8(&err, dev, OPAL_ENDNAME);
1766
1767
1768 add_token_u8(&err, dev, OPAL_STARTNAME);
1769 add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1770 OPAL_UID_LENGTH/2);
1771 add_token_u8(&err, dev, 1);
1772 add_token_u8(&err, dev, OPAL_ENDNAME);
1773
1774
1775 add_token_u8(&err, dev, OPAL_ENDLIST);
1776 add_token_u8(&err, dev, OPAL_ENDNAME);
1777 add_token_u8(&err, dev, OPAL_ENDLIST);
1778 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001779
1780 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001781 pr_debug("Error building add user to locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001782 return err;
1783 }
1784
1785 return finalize_and_send(dev, parse_and_check_status);
1786}
1787
Jon Derrickeed64952017-02-22 07:55:13 -07001788static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001789{
1790 u8 lr_buffer[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001791 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001792 u8 read_locked = 1, write_locked = 1;
1793 int err = 0;
1794
Scott Bauer455a7b22017-02-03 12:50:31 -07001795 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1796 lkul->session.opal_key.lr) < 0)
1797 return -ERANGE;
1798
1799 switch (lkul->l_state) {
1800 case OPAL_RO:
1801 read_locked = 0;
1802 write_locked = 1;
1803 break;
1804 case OPAL_RW:
1805 read_locked = 0;
1806 write_locked = 0;
1807 break;
1808 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001809 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001810 break;
1811 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001812 pr_debug("Tried to set an invalid locking state... returning to uland\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001813 return OPAL_INVAL_PARAM;
1814 }
1815
David Kozube8b29222019-02-14 01:15:58 +01001816 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
1817
Scott Bauer455a7b22017-02-03 12:50:31 -07001818 add_token_u8(&err, dev, OPAL_STARTNAME);
1819 add_token_u8(&err, dev, OPAL_VALUES);
1820 add_token_u8(&err, dev, OPAL_STARTLIST);
1821
1822 add_token_u8(&err, dev, OPAL_STARTNAME);
1823 add_token_u8(&err, dev, OPAL_READLOCKED);
1824 add_token_u8(&err, dev, read_locked);
1825 add_token_u8(&err, dev, OPAL_ENDNAME);
1826
1827 add_token_u8(&err, dev, OPAL_STARTNAME);
1828 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1829 add_token_u8(&err, dev, write_locked);
1830 add_token_u8(&err, dev, OPAL_ENDNAME);
1831
1832 add_token_u8(&err, dev, OPAL_ENDLIST);
1833 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001834
1835 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001836 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001837 return err;
1838 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001839
Scott Bauer455a7b22017-02-03 12:50:31 -07001840 return finalize_and_send(dev, parse_and_check_status);
1841}
1842
1843
Jon Derrickeed64952017-02-22 07:55:13 -07001844static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001845{
1846 u8 lr_buffer[OPAL_UID_LENGTH];
1847 u8 read_locked = 1, write_locked = 1;
Jon Derrickeed64952017-02-22 07:55:13 -07001848 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001849 int ret;
1850
1851 clear_opal_cmd(dev);
1852 set_comid(dev, dev->comid);
1853
Scott Bauer455a7b22017-02-03 12:50:31 -07001854 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1855 lkul->session.opal_key.lr) < 0)
1856 return -ERANGE;
1857
1858 switch (lkul->l_state) {
1859 case OPAL_RO:
1860 read_locked = 0;
1861 write_locked = 1;
1862 break;
1863 case OPAL_RW:
1864 read_locked = 0;
1865 write_locked = 0;
1866 break;
1867 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001868 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001869 break;
1870 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001871 pr_debug("Tried to set an invalid locking state.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001872 return OPAL_INVAL_PARAM;
1873 }
1874 ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1875 read_locked, write_locked);
1876
1877 if (ret < 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001878 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001879 return ret;
1880 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001881
Scott Bauer455a7b22017-02-03 12:50:31 -07001882 return finalize_and_send(dev, parse_and_check_status);
1883}
1884
Jon Derrickeed64952017-02-22 07:55:13 -07001885static int activate_lsp(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001886{
Jon Derrickeed64952017-02-22 07:55:13 -07001887 struct opal_lr_act *opal_act = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001888 u8 user_lr[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001889 int err, i;
Scott Bauer455a7b22017-02-03 12:50:31 -07001890
David Kozube8b29222019-02-14 01:15:58 +01001891 err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID],
1892 opalmethod[OPAL_ACTIVATE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001893
1894 if (opal_act->sum) {
1895 err = build_locking_range(user_lr, sizeof(user_lr),
1896 opal_act->lr[0]);
1897 if (err)
1898 return err;
1899
Scott Bauer455a7b22017-02-03 12:50:31 -07001900 add_token_u8(&err, dev, OPAL_STARTNAME);
Revanth Rajashekarc6da4292019-11-08 16:09:04 -07001901 add_token_u64(&err, dev, OPAL_SUM_SET_LIST);
Scott Bauer455a7b22017-02-03 12:50:31 -07001902
1903 add_token_u8(&err, dev, OPAL_STARTLIST);
1904 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1905 for (i = 1; i < opal_act->num_lrs; i++) {
1906 user_lr[7] = opal_act->lr[i];
1907 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1908 }
1909 add_token_u8(&err, dev, OPAL_ENDLIST);
1910 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001911 }
1912
1913 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001914 pr_debug("Error building Activate LockingSP command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001915 return err;
1916 }
1917
1918 return finalize_and_send(dev, parse_and_check_status);
1919}
1920
David Kozub3fff2342019-02-14 01:16:04 +01001921/* Determine if we're in the Manufactured Inactive or Active state */
1922static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001923{
1924 u8 lc_status;
David Kozub3fff2342019-02-14 01:16:04 +01001925 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001926
David Kozub3fff2342019-02-14 01:16:04 +01001927 err = generic_get_column(dev, opaluid[OPAL_LOCKINGSP_UID],
1928 OPAL_LIFECYCLE);
1929 if (err)
1930 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001931
1932 lc_status = response_get_u64(&dev->parsed, 4);
David Kozub1e815b32019-02-14 01:15:54 +01001933 /* 0x08 is Manufactured Inactive */
Scott Bauer455a7b22017-02-03 12:50:31 -07001934 /* 0x09 is Manufactured */
1935 if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001936 pr_debug("Couldn't determine the status of the Lifecycle state\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001937 return -ENODEV;
1938 }
1939
1940 return 0;
1941}
1942
David Kozub3fff2342019-02-14 01:16:04 +01001943static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001944{
1945 const char *msid_pin;
1946 size_t strlen;
David Kozub3fff2342019-02-14 01:16:04 +01001947 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001948
David Kozub3fff2342019-02-14 01:16:04 +01001949 err = generic_get_column(dev, opaluid[OPAL_C_PIN_MSID], OPAL_PIN);
1950 if (err)
1951 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001952
1953 strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1954 if (!msid_pin) {
David Kozub3fff2342019-02-14 01:16:04 +01001955 pr_debug("Couldn't extract MSID_CPIN from response\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001956 return OPAL_INVAL_PARAM;
1957 }
1958
1959 dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1960 if (!dev->prev_data)
1961 return -ENOMEM;
1962
1963 dev->prev_d_len = strlen;
1964
1965 return 0;
1966}
1967
Revanth Rajashekar51f421c2019-10-31 10:13:21 -06001968static int write_table_data(struct opal_dev *dev, void *data)
1969{
1970 struct opal_read_write_table *write_tbl = data;
1971
1972 return generic_table_write_data(dev, write_tbl->data, write_tbl->offset,
1973 write_tbl->size, write_tbl->table_uid);
1974}
1975
1976static int read_table_data_cont(struct opal_dev *dev)
1977{
1978 int err;
1979 const char *data_read;
1980
1981 err = parse_and_check_status(dev);
1982 if (err)
1983 return err;
1984
1985 dev->prev_d_len = response_get_string(&dev->parsed, 1, &data_read);
1986 dev->prev_data = (void *)data_read;
1987 if (!dev->prev_data) {
1988 pr_debug("%s: Couldn't read data from the table.\n", __func__);
1989 return OPAL_INVAL_PARAM;
1990 }
1991
1992 return 0;
1993}
1994
1995/*
1996 * IO_BUFFER_LENGTH = 2048
1997 * sizeof(header) = 56
1998 * No. of Token Bytes in the Response = 11
1999 * MAX size of data that can be carried in response buffer
2000 * at a time is : 2048 - (56 + 11) = 1981 = 0x7BD.
2001 */
2002#define OPAL_MAX_READ_TABLE (0x7BD)
2003
2004static int read_table_data(struct opal_dev *dev, void *data)
2005{
2006 struct opal_read_write_table *read_tbl = data;
2007 int err;
2008 size_t off = 0, max_read_size = OPAL_MAX_READ_TABLE;
2009 u64 table_len, len;
2010 u64 offset = read_tbl->offset, read_size = read_tbl->size - 1;
2011 u8 __user *dst;
2012
2013 err = generic_get_table_info(dev, read_tbl->table_uid, OPAL_TABLE_ROWS);
2014 if (err) {
2015 pr_debug("Couldn't get the table size\n");
2016 return err;
2017 }
2018
2019 table_len = response_get_u64(&dev->parsed, 4);
2020
2021 /* Check if the user is trying to read from the table limits */
2022 if (read_size > table_len || offset > table_len - read_size) {
2023 pr_debug("Read size exceeds the Table size limits (%llu vs. %llu)\n",
2024 offset + read_size, table_len);
2025 return -EINVAL;
2026 }
2027
2028 while (off < read_size) {
2029 err = cmd_start(dev, read_tbl->table_uid, opalmethod[OPAL_GET]);
2030
2031 add_token_u8(&err, dev, OPAL_STARTLIST);
2032 add_token_u8(&err, dev, OPAL_STARTNAME);
2033 add_token_u8(&err, dev, OPAL_STARTROW);
2034 add_token_u64(&err, dev, offset + off); /* start row value */
2035 add_token_u8(&err, dev, OPAL_ENDNAME);
2036
2037 add_token_u8(&err, dev, OPAL_STARTNAME);
2038 add_token_u8(&err, dev, OPAL_ENDROW);
2039
2040 len = min(max_read_size, (size_t)(read_size - off));
2041 add_token_u64(&err, dev, offset + off + len); /* end row value
2042 */
2043 add_token_u8(&err, dev, OPAL_ENDNAME);
2044 add_token_u8(&err, dev, OPAL_ENDLIST);
2045
2046 if (err) {
2047 pr_debug("Error building read table data command.\n");
2048 break;
2049 }
2050
2051 err = finalize_and_send(dev, read_table_data_cont);
2052 if (err)
2053 break;
2054
2055 /* len+1: This includes the NULL terminator at the end*/
2056 if (dev->prev_d_len > len + 1) {
2057 err = -EOVERFLOW;
2058 break;
2059 }
2060
2061 dst = (u8 __user *)(uintptr_t)read_tbl->data;
2062 if (copy_to_user(dst + off, dev->prev_data, dev->prev_d_len)) {
2063 pr_debug("Error copying data to userspace\n");
2064 err = -EFAULT;
2065 break;
2066 }
2067 dev->prev_data = NULL;
2068
2069 off += len;
2070 }
2071
2072 return err;
2073}
2074
Jon Derrickeed64952017-02-22 07:55:13 -07002075static int end_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07002076{
2077 int err = 0;
2078
2079 clear_opal_cmd(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002080 set_comid(dev, dev->comid);
2081 add_token_u8(&err, dev, OPAL_ENDOFSESSION);
Scott Bauer455a7b22017-02-03 12:50:31 -07002082
Jon Derrickeed64952017-02-22 07:55:13 -07002083 if (err < 0)
2084 return err;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002085
Scott Bauer455a7b22017-02-03 12:50:31 -07002086 return finalize_and_send(dev, end_session_cont);
2087}
2088
2089static int end_opal_session_error(struct opal_dev *dev)
2090{
David Kozub0af26482019-02-14 01:16:07 +01002091 const struct opal_step error_end_session = {
2092 end_opal_session,
Scott Bauer455a7b22017-02-03 12:50:31 -07002093 };
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002094
David Kozub0af26482019-02-14 01:16:07 +01002095 return execute_step(dev, &error_end_session, 0);
Scott Bauer455a7b22017-02-03 12:50:31 -07002096}
2097
David Kozub3db87232019-02-14 01:16:06 +01002098static inline void setup_opal_dev(struct opal_dev *dev)
Scott Bauer455a7b22017-02-03 12:50:31 -07002099{
Scott Bauer455a7b22017-02-03 12:50:31 -07002100 dev->tsn = 0;
2101 dev->hsn = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -07002102 dev->prev_data = NULL;
2103}
2104
2105static int check_opal_support(struct opal_dev *dev)
2106{
Scott Bauer455a7b22017-02-03 12:50:31 -07002107 int ret;
2108
2109 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002110 setup_opal_dev(dev);
David Kozub0af26482019-02-14 01:16:07 +01002111 ret = opal_discovery0_step(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002112 dev->supported = !ret;
2113 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002114
Scott Bauer455a7b22017-02-03 12:50:31 -07002115 return ret;
2116}
2117
Scott Bauer7d6d1572017-02-22 10:15:06 -07002118static void clean_opal_dev(struct opal_dev *dev)
2119{
2120
2121 struct opal_suspend_data *suspend, *next;
2122
2123 mutex_lock(&dev->dev_lock);
2124 list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
2125 list_del(&suspend->node);
2126 kfree(suspend);
2127 }
2128 mutex_unlock(&dev->dev_lock);
2129}
2130
2131void free_opal_dev(struct opal_dev *dev)
2132{
2133 if (!dev)
2134 return;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002135
Scott Bauer7d6d1572017-02-22 10:15:06 -07002136 clean_opal_dev(dev);
2137 kfree(dev);
2138}
2139EXPORT_SYMBOL(free_opal_dev);
2140
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002141struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
Scott Bauer455a7b22017-02-03 12:50:31 -07002142{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002143 struct opal_dev *dev;
2144
2145 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
2146 if (!dev)
2147 return NULL;
2148
2149 INIT_LIST_HEAD(&dev->unlk_lst);
2150 mutex_init(&dev->dev_lock);
2151 dev->data = data;
2152 dev->send_recv = send_recv;
2153 if (check_opal_support(dev) != 0) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +01002154 pr_debug("Opal is not supported on this device\n");
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002155 kfree(dev);
2156 return NULL;
2157 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002158
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002159 return dev;
Scott Bauer455a7b22017-02-03 12:50:31 -07002160}
2161EXPORT_SYMBOL(init_opal_dev);
2162
2163static int opal_secure_erase_locking_range(struct opal_dev *dev,
2164 struct opal_session_info *opal_session)
2165{
Jon Derrickeed64952017-02-22 07:55:13 -07002166 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002167 { start_auth_opal_session, opal_session },
2168 { get_active_key, &opal_session->opal_key.lr },
2169 { gen_key, },
David Kozub3db87232019-02-14 01:16:06 +01002170 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002171 };
2172 int ret;
2173
2174 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002175 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002176 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002177 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002178
Scott Bauer455a7b22017-02-03 12:50:31 -07002179 return ret;
2180}
2181
2182static int opal_erase_locking_range(struct opal_dev *dev,
2183 struct opal_session_info *opal_session)
2184{
Jon Derrickeed64952017-02-22 07:55:13 -07002185 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002186 { start_auth_opal_session, opal_session },
2187 { erase_locking_range, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01002188 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002189 };
2190 int ret;
2191
2192 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002193 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002194 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002195 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002196
Scott Bauer455a7b22017-02-03 12:50:31 -07002197 return ret;
2198}
2199
2200static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
2201 struct opal_mbr_data *opal_mbr)
2202{
David Kozub78bf4732019-02-14 01:15:53 +01002203 u8 enable_disable = opal_mbr->enable_disable == OPAL_MBR_ENABLE ?
2204 OPAL_TRUE : OPAL_FALSE;
2205
Jon Derrickeed64952017-02-22 07:55:13 -07002206 const struct opal_step mbr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002207 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01002208 { set_mbr_done, &enable_disable },
Jon Derrickeed64952017-02-22 07:55:13 -07002209 { end_opal_session, },
2210 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01002211 { set_mbr_enable_disable, &enable_disable },
David Kozub3db87232019-02-14 01:16:06 +01002212 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002213 };
2214 int ret;
2215
2216 if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
2217 opal_mbr->enable_disable != OPAL_MBR_DISABLE)
2218 return -EINVAL;
2219
2220 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002221 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002222 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002223 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002224
Scott Bauer455a7b22017-02-03 12:50:31 -07002225 return ret;
2226}
2227
Jonas Rabensteinc9888442019-05-21 22:46:44 +02002228static int opal_set_mbr_done(struct opal_dev *dev,
2229 struct opal_mbr_done *mbr_done)
2230{
2231 u8 mbr_done_tf = mbr_done->done_flag == OPAL_MBR_DONE ?
2232 OPAL_TRUE : OPAL_FALSE;
2233
2234 const struct opal_step mbr_steps[] = {
2235 { start_admin1LSP_opal_session, &mbr_done->key },
2236 { set_mbr_done, &mbr_done_tf },
2237 { end_opal_session, }
2238 };
2239 int ret;
2240
2241 if (mbr_done->done_flag != OPAL_MBR_DONE &&
2242 mbr_done->done_flag != OPAL_MBR_NOT_DONE)
2243 return -EINVAL;
2244
2245 mutex_lock(&dev->dev_lock);
2246 setup_opal_dev(dev);
2247 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
2248 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002249
Jonas Rabensteinc9888442019-05-21 22:46:44 +02002250 return ret;
2251}
2252
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02002253static int opal_write_shadow_mbr(struct opal_dev *dev,
2254 struct opal_shadow_mbr *info)
2255{
2256 const struct opal_step mbr_steps[] = {
2257 { start_admin1LSP_opal_session, &info->key },
2258 { write_shadow_mbr, info },
2259 { end_opal_session, }
2260 };
2261 int ret;
2262
2263 if (info->size == 0)
2264 return 0;
2265
2266 mutex_lock(&dev->dev_lock);
2267 setup_opal_dev(dev);
2268 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
2269 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002270
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02002271 return ret;
2272}
2273
Scott Bauer455a7b22017-02-03 12:50:31 -07002274static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
2275{
2276 struct opal_suspend_data *suspend;
2277
2278 suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
2279 if (!suspend)
2280 return -ENOMEM;
2281
2282 suspend->unlk = *lk_unlk;
2283 suspend->lr = lk_unlk->session.opal_key.lr;
2284
2285 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002286 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002287 add_suspend_info(dev, suspend);
2288 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002289
Scott Bauer455a7b22017-02-03 12:50:31 -07002290 return 0;
2291}
2292
2293static int opal_add_user_to_lr(struct opal_dev *dev,
2294 struct opal_lock_unlock *lk_unlk)
2295{
Jon Derrickeed64952017-02-22 07:55:13 -07002296 const struct opal_step steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002297 { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2298 { add_user_to_lr, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002299 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002300 };
2301 int ret;
2302
2303 if (lk_unlk->l_state != OPAL_RO &&
2304 lk_unlk->l_state != OPAL_RW) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002305 pr_debug("Locking state was not RO or RW\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07002306 return -EINVAL;
2307 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002308
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002309 if (lk_unlk->session.who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002310 lk_unlk->session.who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002311 pr_debug("Authority was not within the range of users: %d\n",
2312 lk_unlk->session.who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002313 return -EINVAL;
2314 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002315
Scott Bauer455a7b22017-02-03 12:50:31 -07002316 if (lk_unlk->session.sum) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002317 pr_debug("%s not supported in sum. Use setup locking range\n",
2318 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07002319 return -EINVAL;
2320 }
2321
2322 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002323 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002324 ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002325 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002326
Scott Bauer455a7b22017-02-03 12:50:31 -07002327 return ret;
2328}
2329
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002330static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal, bool psid)
Scott Bauer455a7b22017-02-03 12:50:31 -07002331{
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002332 /* controller will terminate session */
Jon Derrickeed64952017-02-22 07:55:13 -07002333 const struct opal_step revert_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002334 { start_SIDASP_opal_session, opal },
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002335 { revert_tper, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002336 };
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002337 const struct opal_step psid_revert_steps[] = {
2338 { start_PSID_opal_session, opal },
2339 { revert_tper, }
2340 };
2341
Scott Bauer455a7b22017-02-03 12:50:31 -07002342 int ret;
2343
2344 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002345 setup_opal_dev(dev);
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002346 if (psid)
2347 ret = execute_steps(dev, psid_revert_steps,
2348 ARRAY_SIZE(psid_revert_steps));
2349 else
2350 ret = execute_steps(dev, revert_steps,
2351 ARRAY_SIZE(revert_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002352 mutex_unlock(&dev->dev_lock);
Scott Bauer7d6d1572017-02-22 10:15:06 -07002353
2354 /*
2355 * If we successfully reverted lets clean
2356 * any saved locking ranges.
2357 */
2358 if (!ret)
2359 clean_opal_dev(dev);
2360
Scott Bauer455a7b22017-02-03 12:50:31 -07002361 return ret;
2362}
2363
Jon Derrickeed64952017-02-22 07:55:13 -07002364static int __opal_lock_unlock(struct opal_dev *dev,
2365 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002366{
Jon Derrickeed64952017-02-22 07:55:13 -07002367 const struct opal_step unlock_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002368 { start_auth_opal_session, &lk_unlk->session },
2369 { lock_unlock_locking_range, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002370 { end_opal_session, }
Jon Derrickeed64952017-02-22 07:55:13 -07002371 };
2372 const struct opal_step unlock_sum_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002373 { start_auth_opal_session, &lk_unlk->session },
2374 { lock_unlock_locking_range_sum, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002375 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002376 };
2377
David Kozub3db87232019-02-14 01:16:06 +01002378 if (lk_unlk->session.sum)
David Kozuba80f36c2019-02-14 01:16:08 +01002379 return execute_steps(dev, unlock_sum_steps,
2380 ARRAY_SIZE(unlock_sum_steps));
David Kozub3db87232019-02-14 01:16:06 +01002381 else
David Kozuba80f36c2019-02-14 01:16:08 +01002382 return execute_steps(dev, unlock_steps,
2383 ARRAY_SIZE(unlock_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002384}
2385
Scott Bauerdbec491b2017-09-01 08:53:35 -06002386static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2387{
David Kozub78bf4732019-02-14 01:15:53 +01002388 u8 mbr_done_tf = OPAL_TRUE;
David Kozub1e815b32019-02-14 01:15:54 +01002389 const struct opal_step mbrdone_step[] = {
Scott Bauerdbec491b2017-09-01 08:53:35 -06002390 { start_admin1LSP_opal_session, key },
2391 { set_mbr_done, &mbr_done_tf },
David Kozub3db87232019-02-14 01:16:06 +01002392 { end_opal_session, }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002393 };
2394
David Kozuba80f36c2019-02-14 01:16:08 +01002395 return execute_steps(dev, mbrdone_step, ARRAY_SIZE(mbrdone_step));
Scott Bauerdbec491b2017-09-01 08:53:35 -06002396}
2397
Jon Derrickeed64952017-02-22 07:55:13 -07002398static int opal_lock_unlock(struct opal_dev *dev,
2399 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002400{
Scott Bauer455a7b22017-02-03 12:50:31 -07002401 int ret;
2402
Revanth Rajashekar15ddffc2019-06-27 16:31:09 -06002403 if (lk_unlk->session.who > OPAL_USER9)
Scott Bauer455a7b22017-02-03 12:50:31 -07002404 return -EINVAL;
2405
2406 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002407 ret = __opal_lock_unlock(dev, lk_unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002408 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002409
Scott Bauer455a7b22017-02-03 12:50:31 -07002410 return ret;
2411}
2412
2413static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2414{
Jon Derrickeed64952017-02-22 07:55:13 -07002415 const struct opal_step owner_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002416 { start_anybodyASP_opal_session, },
2417 { get_msid_cpin_pin, },
2418 { end_opal_session, },
2419 { start_SIDASP_opal_session, opal },
2420 { set_sid_cpin_pin, opal },
David Kozub3db87232019-02-14 01:16:06 +01002421 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002422 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002423 int ret;
2424
2425 if (!dev)
2426 return -ENODEV;
2427
2428 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002429 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002430 ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002431 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002432
Scott Bauer455a7b22017-02-03 12:50:31 -07002433 return ret;
2434}
2435
David Kozub1e815b32019-02-14 01:15:54 +01002436static int opal_activate_lsp(struct opal_dev *dev,
2437 struct opal_lr_act *opal_lr_act)
Scott Bauer455a7b22017-02-03 12:50:31 -07002438{
Jon Derrickeed64952017-02-22 07:55:13 -07002439 const struct opal_step active_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002440 { start_SIDASP_opal_session, &opal_lr_act->key },
2441 { get_lsp_lifecycle, },
2442 { activate_lsp, opal_lr_act },
David Kozub3db87232019-02-14 01:16:06 +01002443 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002444 };
2445 int ret;
2446
2447 if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2448 return -EINVAL;
2449
2450 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002451 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002452 ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002453 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002454
Scott Bauer455a7b22017-02-03 12:50:31 -07002455 return ret;
2456}
2457
2458static int opal_setup_locking_range(struct opal_dev *dev,
2459 struct opal_user_lr_setup *opal_lrs)
2460{
Jon Derrickeed64952017-02-22 07:55:13 -07002461 const struct opal_step lr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002462 { start_auth_opal_session, &opal_lrs->session },
2463 { setup_locking_range, opal_lrs },
David Kozub3db87232019-02-14 01:16:06 +01002464 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002465 };
2466 int ret;
2467
2468 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002469 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002470 ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002471 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002472
Scott Bauer455a7b22017-02-03 12:50:31 -07002473 return ret;
2474}
2475
2476static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2477{
Jon Derrickeed64952017-02-22 07:55:13 -07002478 const struct opal_step pw_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002479 { start_auth_opal_session, &opal_pw->session },
2480 { set_new_pw, &opal_pw->new_user_pw },
David Kozub3db87232019-02-14 01:16:06 +01002481 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002482 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002483 int ret;
2484
Revanth Rajashekar15ddffc2019-06-27 16:31:09 -06002485 if (opal_pw->session.who > OPAL_USER9 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002486 opal_pw->new_user_pw.who > OPAL_USER9)
2487 return -EINVAL;
2488
2489 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002490 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002491 ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002492 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002493
Scott Bauer455a7b22017-02-03 12:50:31 -07002494 return ret;
2495}
2496
2497static int opal_activate_user(struct opal_dev *dev,
2498 struct opal_session_info *opal_session)
2499{
Jon Derrickeed64952017-02-22 07:55:13 -07002500 const struct opal_step act_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002501 { start_admin1LSP_opal_session, &opal_session->opal_key },
2502 { internal_activate_user, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01002503 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002504 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002505 int ret;
2506
2507 /* We can't activate Admin1 it's active as manufactured */
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002508 if (opal_session->who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002509 opal_session->who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002510 pr_debug("Who was not a valid user: %d\n", opal_session->who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002511 return -EINVAL;
2512 }
2513
2514 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002515 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002516 ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002517 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002518
Scott Bauer455a7b22017-02-03 12:50:31 -07002519 return ret;
2520}
2521
2522bool opal_unlock_from_suspend(struct opal_dev *dev)
2523{
2524 struct opal_suspend_data *suspend;
Scott Bauer455a7b22017-02-03 12:50:31 -07002525 bool was_failure = false;
2526 int ret = 0;
2527
2528 if (!dev)
2529 return false;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002530
Scott Bauer455a7b22017-02-03 12:50:31 -07002531 if (!dev->supported)
2532 return false;
2533
2534 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002535 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002536
2537 list_for_each_entry(suspend, &dev->unlk_lst, node) {
Scott Bauer455a7b22017-02-03 12:50:31 -07002538 dev->tsn = 0;
2539 dev->hsn = 0;
2540
Jon Derrickeed64952017-02-22 07:55:13 -07002541 ret = __opal_lock_unlock(dev, &suspend->unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002542 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002543 pr_debug("Failed to unlock LR %hhu with sum %d\n",
2544 suspend->unlk.session.opal_key.lr,
2545 suspend->unlk.session.sum);
Scott Bauer455a7b22017-02-03 12:50:31 -07002546 was_failure = true;
2547 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002548
Scott Bauerdbec491b2017-09-01 08:53:35 -06002549 if (dev->mbr_enabled) {
2550 ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
2551 if (ret)
2552 pr_debug("Failed to set MBR Done in S3 resume\n");
2553 }
Scott Bauer455a7b22017-02-03 12:50:31 -07002554 }
2555 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002556
Scott Bauer455a7b22017-02-03 12:50:31 -07002557 return was_failure;
2558}
2559EXPORT_SYMBOL(opal_unlock_from_suspend);
2560
Revanth Rajashekar51f421c2019-10-31 10:13:21 -06002561static int opal_read_table(struct opal_dev *dev,
2562 struct opal_read_write_table *rw_tbl)
2563{
2564 const struct opal_step read_table_steps[] = {
2565 { start_admin1LSP_opal_session, &rw_tbl->key },
2566 { read_table_data, rw_tbl },
2567 { end_opal_session, }
2568 };
2569 int ret = 0;
2570
2571 if (!rw_tbl->size)
2572 return ret;
2573
2574 return execute_steps(dev, read_table_steps,
2575 ARRAY_SIZE(read_table_steps));
2576}
2577
2578static int opal_write_table(struct opal_dev *dev,
2579 struct opal_read_write_table *rw_tbl)
2580{
2581 const struct opal_step write_table_steps[] = {
2582 { start_admin1LSP_opal_session, &rw_tbl->key },
2583 { write_table_data, rw_tbl },
2584 { end_opal_session, }
2585 };
2586 int ret = 0;
2587
2588 if (!rw_tbl->size)
2589 return ret;
2590
2591 return execute_steps(dev, write_table_steps,
2592 ARRAY_SIZE(write_table_steps));
2593}
2594
2595static int opal_generic_read_write_table(struct opal_dev *dev,
2596 struct opal_read_write_table *rw_tbl)
2597{
2598 int ret, bit_set;
2599
2600 mutex_lock(&dev->dev_lock);
2601 setup_opal_dev(dev);
2602
2603 bit_set = fls64(rw_tbl->flags) - 1;
2604 switch (bit_set) {
2605 case OPAL_READ_TABLE:
2606 ret = opal_read_table(dev, rw_tbl);
2607 break;
2608 case OPAL_WRITE_TABLE:
2609 ret = opal_write_table(dev, rw_tbl);
2610 break;
2611 default:
2612 pr_debug("Invalid bit set in the flag (%016llx).\n",
2613 rw_tbl->flags);
2614 ret = -EINVAL;
2615 break;
2616 }
2617
2618 mutex_unlock(&dev->dev_lock);
2619
2620 return ret;
2621}
2622
Scott Bauere225c202017-02-14 17:29:36 -07002623int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
Scott Bauer455a7b22017-02-03 12:50:31 -07002624{
Scott Bauere225c202017-02-14 17:29:36 -07002625 void *p;
2626 int ret = -ENOTTY;
Scott Bauer455a7b22017-02-03 12:50:31 -07002627
2628 if (!capable(CAP_SYS_ADMIN))
2629 return -EACCES;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002630 if (!dev)
2631 return -ENOTSUPP;
Scott Bauer591c59d2017-04-07 13:58:50 -06002632 if (!dev->supported)
Scott Bauer455a7b22017-02-03 12:50:31 -07002633 return -ENOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -07002634
Jon Derrickeed64952017-02-22 07:55:13 -07002635 p = memdup_user(arg, _IOC_SIZE(cmd));
Scott Bauere225c202017-02-14 17:29:36 -07002636 if (IS_ERR(p))
2637 return PTR_ERR(p);
2638
Scott Bauer455a7b22017-02-03 12:50:31 -07002639 switch (cmd) {
Scott Bauere225c202017-02-14 17:29:36 -07002640 case IOC_OPAL_SAVE:
2641 ret = opal_save(dev, p);
2642 break;
2643 case IOC_OPAL_LOCK_UNLOCK:
2644 ret = opal_lock_unlock(dev, p);
2645 break;
2646 case IOC_OPAL_TAKE_OWNERSHIP:
2647 ret = opal_take_ownership(dev, p);
2648 break;
2649 case IOC_OPAL_ACTIVATE_LSP:
2650 ret = opal_activate_lsp(dev, p);
2651 break;
2652 case IOC_OPAL_SET_PW:
2653 ret = opal_set_new_pw(dev, p);
2654 break;
2655 case IOC_OPAL_ACTIVATE_USR:
2656 ret = opal_activate_user(dev, p);
2657 break;
2658 case IOC_OPAL_REVERT_TPR:
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002659 ret = opal_reverttper(dev, p, false);
Scott Bauere225c202017-02-14 17:29:36 -07002660 break;
2661 case IOC_OPAL_LR_SETUP:
2662 ret = opal_setup_locking_range(dev, p);
2663 break;
2664 case IOC_OPAL_ADD_USR_TO_LR:
2665 ret = opal_add_user_to_lr(dev, p);
2666 break;
2667 case IOC_OPAL_ENABLE_DISABLE_MBR:
2668 ret = opal_enable_disable_shadow_mbr(dev, p);
2669 break;
Jonas Rabensteinc9888442019-05-21 22:46:44 +02002670 case IOC_OPAL_MBR_DONE:
2671 ret = opal_set_mbr_done(dev, p);
2672 break;
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02002673 case IOC_OPAL_WRITE_SHADOW_MBR:
2674 ret = opal_write_shadow_mbr(dev, p);
2675 break;
Scott Bauere225c202017-02-14 17:29:36 -07002676 case IOC_OPAL_ERASE_LR:
2677 ret = opal_erase_locking_range(dev, p);
2678 break;
2679 case IOC_OPAL_SECURE_ERASE_LR:
2680 ret = opal_secure_erase_locking_range(dev, p);
2681 break;
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002682 case IOC_OPAL_PSID_REVERT_TPR:
2683 ret = opal_reverttper(dev, p, true);
2684 break;
Revanth Rajashekar51f421c2019-10-31 10:13:21 -06002685 case IOC_OPAL_GENERIC_TABLE_RW:
2686 ret = opal_generic_read_write_table(dev, p);
2687 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002688 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06002689 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002690 }
Scott Bauere225c202017-02-14 17:29:36 -07002691
2692 kfree(p);
2693 return ret;
Scott Bauer455a7b22017-02-03 12:50:31 -07002694}
2695EXPORT_SYMBOL_GPL(sed_ioctl);