blob: bb8ef7963d11a0ed807622199d10b14c3f4f6e5c [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
Jon Derrickeed64952017-02-22 07:55:13 -070029struct opal_step {
30 int (*fn)(struct opal_dev *dev, void *data);
31 void *data;
32};
33typedef int (cont_fn)(struct opal_dev *dev);
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010034
35enum opal_atom_width {
36 OPAL_WIDTH_TINY,
37 OPAL_WIDTH_SHORT,
38 OPAL_WIDTH_MEDIUM,
39 OPAL_WIDTH_LONG,
40 OPAL_WIDTH_TOKEN
41};
42
43/*
44 * On the parsed response, we don't store again the toks that are already
45 * stored in the response buffer. Instead, for each token, we just store a
46 * pointer to the position in the buffer where the token starts, and the size
47 * of the token in bytes.
48 */
49struct opal_resp_tok {
50 const u8 *pos;
51 size_t len;
52 enum opal_response_token type;
53 enum opal_atom_width width;
54 union {
55 u64 u;
56 s64 s;
57 } stored;
58};
59
60/*
61 * From the response header it's not possible to know how many tokens there are
62 * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
63 * if we start dealing with messages that have more than that, we can increase
64 * this number. This is done to avoid having to make two passes through the
65 * response, the first one counting how many tokens we have and the second one
66 * actually storing the positions.
67 */
68struct parsed_resp {
69 int num;
70 struct opal_resp_tok toks[MAX_TOKS];
71};
72
73struct opal_dev {
74 bool supported;
Scott Bauerdbec491b2017-09-01 08:53:35 -060075 bool mbr_enabled;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010076
77 void *data;
78 sec_send_recv *send_recv;
79
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010080 struct mutex dev_lock;
81 u16 comid;
82 u32 hsn;
83 u32 tsn;
84 u64 align;
85 u64 lowest_lba;
86
87 size_t pos;
88 u8 cmd[IO_BUFFER_LENGTH];
89 u8 resp[IO_BUFFER_LENGTH];
90
91 struct parsed_resp parsed;
92 size_t prev_d_len;
93 void *prev_data;
94
95 struct list_head unlk_lst;
96};
97
98
Scott Bauer455a7b22017-02-03 12:50:31 -070099static const u8 opaluid[][OPAL_UID_LENGTH] = {
100 /* users */
101 [OPAL_SMUID_UID] =
102 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
103 [OPAL_THISSP_UID] =
104 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
105 [OPAL_ADMINSP_UID] =
106 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
107 [OPAL_LOCKINGSP_UID] =
108 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
109 [OPAL_ENTERPRISE_LOCKINGSP_UID] =
110 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
111 [OPAL_ANYBODY_UID] =
112 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
113 [OPAL_SID_UID] =
114 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
115 [OPAL_ADMIN1_UID] =
116 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
117 [OPAL_USER1_UID] =
118 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
119 [OPAL_USER2_UID] =
120 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
121 [OPAL_PSID_UID] =
122 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
123 [OPAL_ENTERPRISE_BANDMASTER0_UID] =
124 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
125 [OPAL_ENTERPRISE_ERASEMASTER_UID] =
126 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
127
128 /* tables */
129
130 [OPAL_LOCKINGRANGE_GLOBAL] =
131 { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
132 [OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
133 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
134 [OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
135 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
136 [OPAL_MBRCONTROL] =
137 { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
138 [OPAL_MBR] =
139 { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
140 [OPAL_AUTHORITY_TABLE] =
141 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
142 [OPAL_C_PIN_TABLE] =
143 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
144 [OPAL_LOCKING_INFO_TABLE] =
145 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
146 [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
147 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
148
149 /* C_PIN_TABLE object ID's */
150
David Kozub1e815b32019-02-14 01:15:54 +0100151 [OPAL_C_PIN_MSID] =
Scott Bauer455a7b22017-02-03 12:50:31 -0700152 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
153 [OPAL_C_PIN_SID] =
154 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
155 [OPAL_C_PIN_ADMIN1] =
156 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
157
158 /* half UID's (only first 4 bytes used) */
159
160 [OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
161 { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
162 [OPAL_HALF_UID_BOOLEAN_ACE] =
163 { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
164
165 /* special value for omitted optional parameter */
166 [OPAL_UID_HEXFF] =
167 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
168};
169
170/*
171 * TCG Storage SSC Methods.
172 * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
173 * Section: 6.3 Assigned UIDs
174 */
Jonas Rabenstein1b6b75b2019-02-14 01:15:55 +0100175static const u8 opalmethod[][OPAL_METHOD_LENGTH] = {
Scott Bauer455a7b22017-02-03 12:50:31 -0700176 [OPAL_PROPERTIES] =
177 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
178 [OPAL_STARTSESSION] =
179 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
180 [OPAL_REVERT] =
181 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
182 [OPAL_ACTIVATE] =
183 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
184 [OPAL_EGET] =
185 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
186 [OPAL_ESET] =
187 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
188 [OPAL_NEXT] =
189 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
190 [OPAL_EAUTHENTICATE] =
191 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
192 [OPAL_GETACL] =
193 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
194 [OPAL_GENKEY] =
195 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
196 [OPAL_REVERTSP] =
197 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
198 [OPAL_GET] =
199 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
200 [OPAL_SET] =
201 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
202 [OPAL_AUTHENTICATE] =
203 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
204 [OPAL_RANDOM] =
205 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
206 [OPAL_ERASE] =
207 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
208};
209
Scott Bauer455a7b22017-02-03 12:50:31 -0700210static int end_opal_session_error(struct opal_dev *dev);
David Kozub0af26482019-02-14 01:16:07 +0100211static int opal_discovery0_step(struct opal_dev *dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700212
213struct opal_suspend_data {
214 struct opal_lock_unlock unlk;
215 u8 lr;
216 struct list_head node;
217};
218
219/*
220 * Derived from:
221 * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
222 * Section: 5.1.5 Method Status Codes
223 */
224static const char * const opal_errors[] = {
225 "Success",
226 "Not Authorized",
227 "Unknown Error",
228 "SP Busy",
229 "SP Failed",
230 "SP Disabled",
231 "SP Frozen",
232 "No Sessions Available",
233 "Uniqueness Conflict",
234 "Insufficient Space",
235 "Insufficient Rows",
236 "Invalid Function",
237 "Invalid Parameter",
238 "Invalid Reference",
239 "Unknown Error",
240 "TPER Malfunction",
241 "Transaction Failure",
242 "Response Overflow",
243 "Authority Locked Out",
244};
245
246static const char *opal_error_to_human(int error)
247{
248 if (error == 0x3f)
249 return "Failed";
250
251 if (error >= ARRAY_SIZE(opal_errors) || error < 0)
252 return "Unknown Error";
253
254 return opal_errors[error];
255}
256
257static void print_buffer(const u8 *ptr, u32 length)
258{
259#ifdef DEBUG
260 print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
261 pr_debug("\n");
262#endif
263}
264
265static bool check_tper(const void *data)
266{
267 const struct d0_tper_features *tper = data;
268 u8 flags = tper->supported_features;
269
270 if (!(flags & TPER_SYNC_SUPPORTED)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600271 pr_debug("TPer sync not supported. flags = %d\n",
272 tper->supported_features);
Scott Bauer455a7b22017-02-03 12:50:31 -0700273 return false;
274 }
275
276 return true;
277}
278
Scott Bauerdbec491b2017-09-01 08:53:35 -0600279static bool check_mbrenabled(const void *data)
280{
281 const struct d0_locking_features *lfeat = data;
282 u8 sup_feat = lfeat->supported_features;
283
284 return !!(sup_feat & MBR_ENABLED_MASK);
285}
286
Scott Bauer455a7b22017-02-03 12:50:31 -0700287static bool check_sum(const void *data)
288{
289 const struct d0_single_user_mode *sum = data;
290 u32 nlo = be32_to_cpu(sum->num_locking_objects);
291
292 if (nlo == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600293 pr_debug("Need at least one locking object.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700294 return false;
295 }
296
297 pr_debug("Number of locking objects: %d\n", nlo);
298
299 return true;
300}
301
302static u16 get_comid_v100(const void *data)
303{
304 const struct d0_opal_v100 *v100 = data;
305
306 return be16_to_cpu(v100->baseComID);
307}
308
309static u16 get_comid_v200(const void *data)
310{
311 const struct d0_opal_v200 *v200 = data;
312
313 return be16_to_cpu(v200->baseComID);
314}
315
316static int opal_send_cmd(struct opal_dev *dev)
317{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100318 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700319 dev->cmd, IO_BUFFER_LENGTH,
320 true);
321}
322
323static int opal_recv_cmd(struct opal_dev *dev)
324{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100325 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700326 dev->resp, IO_BUFFER_LENGTH,
327 false);
328}
329
330static int opal_recv_check(struct opal_dev *dev)
331{
332 size_t buflen = IO_BUFFER_LENGTH;
333 void *buffer = dev->resp;
334 struct opal_header *hdr = buffer;
335 int ret;
336
337 do {
338 pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
339 hdr->cp.outstandingData,
340 hdr->cp.minTransfer);
341
342 if (hdr->cp.outstandingData == 0 ||
343 hdr->cp.minTransfer != 0)
344 return 0;
345
346 memset(buffer, 0, buflen);
347 ret = opal_recv_cmd(dev);
348 } while (!ret);
349
350 return ret;
351}
352
353static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
354{
355 int ret;
356
357 ret = opal_send_cmd(dev);
358 if (ret)
359 return ret;
360 ret = opal_recv_cmd(dev);
361 if (ret)
362 return ret;
363 ret = opal_recv_check(dev);
364 if (ret)
365 return ret;
366 return cont(dev);
367}
368
369static void check_geometry(struct opal_dev *dev, const void *data)
370{
371 const struct d0_geometry_features *geo = data;
372
373 dev->align = geo->alignment_granularity;
374 dev->lowest_lba = geo->lowest_aligned_lba;
375}
376
David Kozub0af26482019-02-14 01:16:07 +0100377static int execute_step(struct opal_dev *dev,
378 const struct opal_step *step, size_t stepIndex)
379{
380 int error = step->fn(dev, step->data);
381
382 if (error) {
383 pr_debug("Step %zu (%pS) failed with error %d: %s\n",
384 stepIndex, step->fn, error,
385 opal_error_to_human(error));
386 }
387
388 return error;
389}
390
David Kozuba80f36c2019-02-14 01:16:08 +0100391static int execute_steps(struct opal_dev *dev,
392 const struct opal_step *steps, size_t n_steps)
Scott Bauer455a7b22017-02-03 12:50:31 -0700393{
David Kozub0af26482019-02-14 01:16:07 +0100394 size_t state = 0;
395 int error;
396
397 /* first do a discovery0 */
398 error = opal_discovery0_step(dev);
399 if (error)
400 return error;
Scott Bauer455a7b22017-02-03 12:50:31 -0700401
David Kozub3db87232019-02-14 01:16:06 +0100402 for (state = 0; state < n_steps; state++) {
David Kozub0af26482019-02-14 01:16:07 +0100403 error = execute_step(dev, &steps[state], state);
David Kozub3db87232019-02-14 01:16:06 +0100404 if (error)
405 goto out_error;
406 }
Scott Bauer455a7b22017-02-03 12:50:31 -0700407
David Kozub3db87232019-02-14 01:16:06 +0100408 return 0;
Scott Bauer2d190202017-02-22 10:15:08 -0700409
David Kozub3db87232019-02-14 01:16:06 +0100410out_error:
411 /*
David Kozub0af26482019-02-14 01:16:07 +0100412 * For each OPAL command the first step in steps starts some sort of
413 * session. If an error occurred in the initial discovery0 or if an
414 * error occurred in the first step (and thus stopping the loop with
415 * state == 0) then there was an error before or during the attempt to
416 * start a session. Therefore we shouldn't attempt to terminate a
417 * session, as one has not yet been created.
David Kozub3db87232019-02-14 01:16:06 +0100418 */
David Kozub0af26482019-02-14 01:16:07 +0100419 if (state > 0)
David Kozub3db87232019-02-14 01:16:06 +0100420 end_opal_session_error(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700421
422 return error;
423}
424
425static int opal_discovery0_end(struct opal_dev *dev)
426{
427 bool found_com_id = false, supported = true, single_user = false;
428 const struct d0_header *hdr = (struct d0_header *)dev->resp;
429 const u8 *epos = dev->resp, *cpos = dev->resp;
430 u16 comid = 0;
Jon Derrick77039b92017-02-21 11:59:15 -0700431 u32 hlen = be32_to_cpu(hdr->length);
Scott Bauer455a7b22017-02-03 12:50:31 -0700432
Jon Derrick77039b92017-02-21 11:59:15 -0700433 print_buffer(dev->resp, hlen);
Scott Bauerdbec491b2017-09-01 08:53:35 -0600434 dev->mbr_enabled = false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700435
Jon Derrick77039b92017-02-21 11:59:15 -0700436 if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600437 pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
438 sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
Jon Derrick77039b92017-02-21 11:59:15 -0700439 return -EFAULT;
440 }
441
442 epos += hlen; /* end of buffer */
Scott Bauer455a7b22017-02-03 12:50:31 -0700443 cpos += sizeof(*hdr); /* current position on buffer */
444
445 while (cpos < epos && supported) {
446 const struct d0_features *body =
447 (const struct d0_features *)cpos;
448
449 switch (be16_to_cpu(body->code)) {
450 case FC_TPER:
451 supported = check_tper(body->features);
452 break;
453 case FC_SINGLEUSER:
454 single_user = check_sum(body->features);
455 break;
456 case FC_GEOMETRY:
457 check_geometry(dev, body);
458 break;
459 case FC_LOCKING:
Scott Bauerdbec491b2017-09-01 08:53:35 -0600460 dev->mbr_enabled = check_mbrenabled(body->features);
461 break;
Scott Bauer455a7b22017-02-03 12:50:31 -0700462 case FC_ENTERPRISE:
463 case FC_DATASTORE:
464 /* some ignored properties */
465 pr_debug("Found OPAL feature description: %d\n",
466 be16_to_cpu(body->code));
467 break;
468 case FC_OPALV100:
469 comid = get_comid_v100(body->features);
470 found_com_id = true;
471 break;
472 case FC_OPALV200:
473 comid = get_comid_v200(body->features);
474 found_com_id = true;
475 break;
476 case 0xbfff ... 0xffff:
477 /* vendor specific, just ignore */
478 break;
479 default:
480 pr_debug("OPAL Unknown feature: %d\n",
481 be16_to_cpu(body->code));
482
483 }
484 cpos += body->length + 4;
485 }
486
487 if (!supported) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100488 pr_debug("This device is not Opal enabled. Not Supported!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700489 return -EOPNOTSUPP;
490 }
491
492 if (!single_user)
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100493 pr_debug("Device doesn't support single user mode\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700494
495
496 if (!found_com_id) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100497 pr_debug("Could not find OPAL comid for device. Returning early\n");
Ingo Molnared7158b2018-02-22 10:54:55 +0100498 return -EOPNOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -0700499 }
500
501 dev->comid = comid;
502
503 return 0;
504}
505
Jon Derrickeed64952017-02-22 07:55:13 -0700506static int opal_discovery0(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -0700507{
508 int ret;
509
510 memset(dev->resp, 0, IO_BUFFER_LENGTH);
511 dev->comid = OPAL_DISCOVERY_COMID;
512 ret = opal_recv_cmd(dev);
513 if (ret)
514 return ret;
515 return opal_discovery0_end(dev);
516}
517
David Kozub0af26482019-02-14 01:16:07 +0100518static int opal_discovery0_step(struct opal_dev *dev)
519{
520 const struct opal_step discovery0_step = {
521 opal_discovery0,
522 };
523 return execute_step(dev, &discovery0_step, 0);
524}
525
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100526static bool can_add(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700527{
528 if (*err)
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100529 return false;
530
531 if (len > IO_BUFFER_LENGTH || cmd->pos > IO_BUFFER_LENGTH - len) {
532 pr_debug("Error adding %zu bytes: end of buffer.\n", len);
Scott Bauer455a7b22017-02-03 12:50:31 -0700533 *err = -ERANGE;
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100534 return false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700535 }
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100536
537 return true;
538}
539
540static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
541{
542 if (!can_add(err, cmd, 1))
543 return;
Scott Bauer455a7b22017-02-03 12:50:31 -0700544 cmd->cmd[cmd->pos++] = tok;
545}
546
547static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
548 bool has_sign, int len)
549{
550 u8 atom;
551 int err = 0;
552
553 atom = SHORT_ATOM_ID;
554 atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
555 atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
556 atom |= len & SHORT_ATOM_LEN_MASK;
557
558 add_token_u8(&err, cmd, atom);
559}
560
561static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
562 bool has_sign, int len)
563{
564 u8 header0;
565
566 header0 = MEDIUM_ATOM_ID;
567 header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
568 header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
569 header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
570 cmd->cmd[cmd->pos++] = header0;
571 cmd->cmd[cmd->pos++] = len;
572}
573
574static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
575{
Scott Bauer455a7b22017-02-03 12:50:31 -0700576 size_t len;
577 int msb;
Scott Bauer455a7b22017-02-03 12:50:31 -0700578
579 if (!(number & ~TINY_ATOM_DATA_MASK)) {
580 add_token_u8(err, cmd, number);
581 return;
582 }
583
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100584 msb = fls64(number);
585 len = DIV_ROUND_UP(msb, 8);
Scott Bauer455a7b22017-02-03 12:50:31 -0700586
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100587 if (!can_add(err, cmd, len + 1)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600588 pr_debug("Error adding u64: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700589 return;
590 }
591 add_short_atom_header(cmd, false, false, len);
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100592 while (len--)
593 add_token_u8(err, cmd, number >> (len * 8));
Scott Bauer455a7b22017-02-03 12:50:31 -0700594}
595
Jonas Rabenstein28559952019-02-14 01:16:02 +0100596static u8 *add_bytestring_header(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700597{
598 size_t header_len = 1;
599 bool is_short_atom = true;
600
Scott Bauer455a7b22017-02-03 12:50:31 -0700601 if (len & ~SHORT_ATOM_LEN_MASK) {
602 header_len = 2;
603 is_short_atom = false;
604 }
605
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100606 if (!can_add(err, cmd, header_len + len)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600607 pr_debug("Error adding bytestring: end of buffer.\n");
Jonas Rabenstein28559952019-02-14 01:16:02 +0100608 return NULL;
Scott Bauer455a7b22017-02-03 12:50:31 -0700609 }
610
611 if (is_short_atom)
612 add_short_atom_header(cmd, true, false, len);
613 else
614 add_medium_atom_header(cmd, true, false, len);
615
Jonas Rabenstein28559952019-02-14 01:16:02 +0100616 return &cmd->cmd[cmd->pos];
617}
Scott Bauer455a7b22017-02-03 12:50:31 -0700618
Jonas Rabenstein28559952019-02-14 01:16:02 +0100619static void add_token_bytestring(int *err, struct opal_dev *cmd,
620 const u8 *bytestring, size_t len)
621{
622 u8 *start;
623
624 start = add_bytestring_header(err, cmd, len);
625 if (!start)
626 return;
627 memcpy(start, bytestring, len);
628 cmd->pos += len;
Scott Bauer455a7b22017-02-03 12:50:31 -0700629}
630
631static int build_locking_range(u8 *buffer, size_t length, u8 lr)
632{
633 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600634 pr_debug("Can't build locking range. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700635 return -ERANGE;
636 }
637
638 memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
639
640 if (lr == 0)
641 return 0;
642 buffer[5] = LOCKING_RANGE_NON_GLOBAL;
643 buffer[7] = lr;
644
645 return 0;
646}
647
648static int build_locking_user(u8 *buffer, size_t length, u8 lr)
649{
650 if (length > OPAL_UID_LENGTH) {
David Kozub1e815b32019-02-14 01:15:54 +0100651 pr_debug("Can't build locking range user. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700652 return -ERANGE;
653 }
654
655 memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
656
657 buffer[7] = lr + 1;
658
659 return 0;
660}
661
662static void set_comid(struct opal_dev *cmd, u16 comid)
663{
664 struct opal_header *hdr = (struct opal_header *)cmd->cmd;
665
666 hdr->cp.extendedComID[0] = comid >> 8;
667 hdr->cp.extendedComID[1] = comid;
668 hdr->cp.extendedComID[2] = 0;
669 hdr->cp.extendedComID[3] = 0;
670}
671
672static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
673{
674 struct opal_header *hdr;
675 int err = 0;
676
David Kozube8b29222019-02-14 01:15:58 +0100677 /* close the parameter list opened from cmd_start */
David Kozub78d584c2019-02-14 01:15:57 +0100678 add_token_u8(&err, cmd, OPAL_ENDLIST);
679
Scott Bauer455a7b22017-02-03 12:50:31 -0700680 add_token_u8(&err, cmd, OPAL_ENDOFDATA);
681 add_token_u8(&err, cmd, OPAL_STARTLIST);
682 add_token_u8(&err, cmd, 0);
683 add_token_u8(&err, cmd, 0);
684 add_token_u8(&err, cmd, 0);
685 add_token_u8(&err, cmd, OPAL_ENDLIST);
686
687 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600688 pr_debug("Error finalizing command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700689 return -EFAULT;
690 }
691
692 hdr = (struct opal_header *) cmd->cmd;
693
694 hdr->pkt.tsn = cpu_to_be32(tsn);
695 hdr->pkt.hsn = cpu_to_be32(hsn);
696
697 hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
698 while (cmd->pos % 4) {
699 if (cmd->pos >= IO_BUFFER_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600700 pr_debug("Error: Buffer overrun\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700701 return -ERANGE;
702 }
703 cmd->cmd[cmd->pos++] = 0;
704 }
705 hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
706 sizeof(hdr->pkt));
707 hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
708
709 return 0;
710}
711
Jon Derrickcccb9242017-02-21 11:59:14 -0700712static const struct opal_resp_tok *response_get_token(
713 const struct parsed_resp *resp,
714 int n)
Scott Bauer455a7b22017-02-03 12:50:31 -0700715{
716 const struct opal_resp_tok *tok;
717
David Kozub7d9b62a2019-02-14 01:15:59 +0100718 if (!resp) {
719 pr_debug("Response is NULL\n");
720 return ERR_PTR(-EINVAL);
721 }
722
Scott Bauer455a7b22017-02-03 12:50:31 -0700723 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600724 pr_debug("Token number doesn't exist: %d, resp: %d\n",
725 n, resp->num);
Jon Derrickcccb9242017-02-21 11:59:14 -0700726 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700727 }
728
729 tok = &resp->toks[n];
730 if (tok->len == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600731 pr_debug("Token length must be non-zero\n");
Jon Derrickcccb9242017-02-21 11:59:14 -0700732 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700733 }
734
Jon Derrickcccb9242017-02-21 11:59:14 -0700735 return tok;
Scott Bauer455a7b22017-02-03 12:50:31 -0700736}
737
Jon Derrickaedb6e22017-02-21 11:59:13 -0700738static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
739 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700740{
741 tok->pos = pos;
742 tok->len = 1;
743 tok->width = OPAL_WIDTH_TINY;
744
745 if (pos[0] & TINY_ATOM_SIGNED) {
746 tok->type = OPAL_DTA_TOKENID_SINT;
747 } else {
748 tok->type = OPAL_DTA_TOKENID_UINT;
749 tok->stored.u = pos[0] & 0x3f;
750 }
751
752 return tok->len;
753}
754
Jon Derrickaedb6e22017-02-21 11:59:13 -0700755static ssize_t response_parse_short(struct opal_resp_tok *tok,
756 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700757{
758 tok->pos = pos;
759 tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
760 tok->width = OPAL_WIDTH_SHORT;
761
762 if (pos[0] & SHORT_ATOM_BYTESTRING) {
763 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
764 } else if (pos[0] & SHORT_ATOM_SIGNED) {
765 tok->type = OPAL_DTA_TOKENID_SINT;
766 } else {
767 u64 u_integer = 0;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700768 ssize_t i, b = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700769
770 tok->type = OPAL_DTA_TOKENID_UINT;
771 if (tok->len > 9) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600772 pr_debug("uint64 with more than 8 bytes\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700773 return -EINVAL;
774 }
775 for (i = tok->len - 1; i > 0; i--) {
776 u_integer |= ((u64)pos[i] << (8 * b));
777 b++;
778 }
779 tok->stored.u = u_integer;
780 }
781
782 return tok->len;
783}
784
Jon Derrickaedb6e22017-02-21 11:59:13 -0700785static ssize_t response_parse_medium(struct opal_resp_tok *tok,
786 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700787{
788 tok->pos = pos;
789 tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
790 tok->width = OPAL_WIDTH_MEDIUM;
791
792 if (pos[0] & MEDIUM_ATOM_BYTESTRING)
793 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
794 else if (pos[0] & MEDIUM_ATOM_SIGNED)
795 tok->type = OPAL_DTA_TOKENID_SINT;
796 else
797 tok->type = OPAL_DTA_TOKENID_UINT;
798
799 return tok->len;
800}
801
Jon Derrickaedb6e22017-02-21 11:59:13 -0700802static ssize_t response_parse_long(struct opal_resp_tok *tok,
803 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700804{
805 tok->pos = pos;
806 tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
807 tok->width = OPAL_WIDTH_LONG;
808
809 if (pos[0] & LONG_ATOM_BYTESTRING)
810 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
811 else if (pos[0] & LONG_ATOM_SIGNED)
812 tok->type = OPAL_DTA_TOKENID_SINT;
813 else
814 tok->type = OPAL_DTA_TOKENID_UINT;
815
816 return tok->len;
817}
818
Jon Derrickaedb6e22017-02-21 11:59:13 -0700819static ssize_t response_parse_token(struct opal_resp_tok *tok,
820 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700821{
822 tok->pos = pos;
823 tok->len = 1;
824 tok->type = OPAL_DTA_TOKENID_TOKEN;
825 tok->width = OPAL_WIDTH_TOKEN;
826
827 return tok->len;
828}
829
830static int response_parse(const u8 *buf, size_t length,
831 struct parsed_resp *resp)
832{
833 const struct opal_header *hdr;
834 struct opal_resp_tok *iter;
835 int num_entries = 0;
836 int total;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700837 ssize_t token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700838 const u8 *pos;
Jon Derrick77039b92017-02-21 11:59:15 -0700839 u32 clen, plen, slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700840
841 if (!buf)
842 return -EFAULT;
843
844 if (!resp)
845 return -EFAULT;
846
847 hdr = (struct opal_header *)buf;
848 pos = buf;
849 pos += sizeof(*hdr);
850
Jon Derrick77039b92017-02-21 11:59:15 -0700851 clen = be32_to_cpu(hdr->cp.length);
852 plen = be32_to_cpu(hdr->pkt.length);
853 slen = be32_to_cpu(hdr->subpkt.length);
854 pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
855 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700856
Jon Derrick77039b92017-02-21 11:59:15 -0700857 if (clen == 0 || plen == 0 || slen == 0 ||
858 slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600859 pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
860 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700861 print_buffer(pos, sizeof(*hdr));
862 return -EINVAL;
863 }
864
865 if (pos > buf + length)
866 return -EFAULT;
867
868 iter = resp->toks;
Jon Derrick77039b92017-02-21 11:59:15 -0700869 total = slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700870 print_buffer(pos, total);
871 while (total > 0) {
872 if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
873 token_length = response_parse_tiny(iter, pos);
874 else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
875 token_length = response_parse_short(iter, pos);
876 else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
877 token_length = response_parse_medium(iter, pos);
878 else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
879 token_length = response_parse_long(iter, pos);
880 else /* TOKEN */
881 token_length = response_parse_token(iter, pos);
882
Jon Derrickaedb6e22017-02-21 11:59:13 -0700883 if (token_length < 0)
884 return token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700885
886 pos += token_length;
887 total -= token_length;
888 iter++;
889 num_entries++;
890 }
891
892 if (num_entries == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600893 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700894 return -EINVAL;
895 }
896 resp->num = num_entries;
897
898 return 0;
899}
900
901static size_t response_get_string(const struct parsed_resp *resp, int n,
902 const char **store)
903{
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100904 u8 skip;
David Kozubb68f09e2019-02-14 01:16:00 +0100905 const struct opal_resp_tok *tok;
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100906
Scott Bauer455a7b22017-02-03 12:50:31 -0700907 *store = NULL;
David Kozubb68f09e2019-02-14 01:16:00 +0100908 tok = response_get_token(resp, n);
909 if (IS_ERR(tok))
Scott Bauer455a7b22017-02-03 12:50:31 -0700910 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700911
David Kozubb68f09e2019-02-14 01:16:00 +0100912 if (tok->type != OPAL_DTA_TOKENID_BYTESTRING) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600913 pr_debug("Token is not a byte string!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700914 return 0;
915 }
916
David Kozubb68f09e2019-02-14 01:16:00 +0100917 switch (tok->width) {
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100918 case OPAL_WIDTH_TINY:
919 case OPAL_WIDTH_SHORT:
920 skip = 1;
921 break;
922 case OPAL_WIDTH_MEDIUM:
923 skip = 2;
924 break;
925 case OPAL_WIDTH_LONG:
926 skip = 4;
927 break;
928 default:
929 pr_debug("Token has invalid width!\n");
930 return 0;
931 }
932
David Kozubb68f09e2019-02-14 01:16:00 +0100933 *store = tok->pos + skip;
934 return tok->len - skip;
Scott Bauer455a7b22017-02-03 12:50:31 -0700935}
936
937static u64 response_get_u64(const struct parsed_resp *resp, int n)
938{
David Kozubb68f09e2019-02-14 01:16:00 +0100939 const struct opal_resp_tok *tok;
940
941 tok = response_get_token(resp, n);
942 if (IS_ERR(tok))
943 return 0;
944
945 if (tok->type != OPAL_DTA_TOKENID_UINT) {
946 pr_debug("Token is not unsigned int: %d\n", tok->type);
Scott Bauer455a7b22017-02-03 12:50:31 -0700947 return 0;
948 }
949
David Kozubb68f09e2019-02-14 01:16:00 +0100950 if (tok->width != OPAL_WIDTH_TINY && tok->width != OPAL_WIDTH_SHORT) {
951 pr_debug("Atom is not short or tiny: %d\n", tok->width);
Scott Bauer455a7b22017-02-03 12:50:31 -0700952 return 0;
953 }
954
David Kozubb68f09e2019-02-14 01:16:00 +0100955 return tok->stored.u;
Scott Bauer455a7b22017-02-03 12:50:31 -0700956}
957
Jon Derrickcccb9242017-02-21 11:59:14 -0700958static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
959{
960 if (IS_ERR(token) ||
961 token->type != OPAL_DTA_TOKENID_TOKEN ||
962 token->pos[0] != match)
963 return false;
964 return true;
965}
966
Scott Bauer455a7b22017-02-03 12:50:31 -0700967static u8 response_status(const struct parsed_resp *resp)
968{
Jon Derrickcccb9242017-02-21 11:59:14 -0700969 const struct opal_resp_tok *tok;
970
971 tok = response_get_token(resp, 0);
972 if (response_token_matches(tok, OPAL_ENDOFSESSION))
Scott Bauer455a7b22017-02-03 12:50:31 -0700973 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700974
975 if (resp->num < 5)
976 return DTAERROR_NO_METHOD_STATUS;
977
Jon Derrickcccb9242017-02-21 11:59:14 -0700978 tok = response_get_token(resp, resp->num - 5);
979 if (!response_token_matches(tok, OPAL_STARTLIST))
980 return DTAERROR_NO_METHOD_STATUS;
981
982 tok = response_get_token(resp, resp->num - 1);
983 if (!response_token_matches(tok, OPAL_ENDLIST))
Scott Bauer455a7b22017-02-03 12:50:31 -0700984 return DTAERROR_NO_METHOD_STATUS;
985
986 return response_get_u64(resp, resp->num - 4);
987}
988
989/* Parses and checks for errors */
990static int parse_and_check_status(struct opal_dev *dev)
991{
992 int error;
993
994 print_buffer(dev->cmd, dev->pos);
995
996 error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
997 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600998 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700999 return error;
1000 }
1001
1002 return response_status(&dev->parsed);
1003}
1004
1005static void clear_opal_cmd(struct opal_dev *dev)
1006{
1007 dev->pos = sizeof(struct opal_header);
1008 memset(dev->cmd, 0, IO_BUFFER_LENGTH);
1009}
1010
David Kozube8b29222019-02-14 01:15:58 +01001011static int cmd_start(struct opal_dev *dev, const u8 *uid, const u8 *method)
1012{
1013 int err = 0;
1014
1015 clear_opal_cmd(dev);
1016 set_comid(dev, dev->comid);
1017
1018 add_token_u8(&err, dev, OPAL_CALL);
1019 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1020 add_token_bytestring(&err, dev, method, OPAL_METHOD_LENGTH);
1021
1022 /*
1023 * Every method call is followed by its parameters enclosed within
1024 * OPAL_STARTLIST and OPAL_ENDLIST tokens. We automatically open the
1025 * parameter list here and close it later in cmd_finalize.
1026 */
1027 add_token_u8(&err, dev, OPAL_STARTLIST);
1028
1029 return err;
1030}
1031
Scott Bauer455a7b22017-02-03 12:50:31 -07001032static int start_opal_session_cont(struct opal_dev *dev)
1033{
1034 u32 hsn, tsn;
1035 int error = 0;
1036
1037 error = parse_and_check_status(dev);
1038 if (error)
1039 return error;
1040
1041 hsn = response_get_u64(&dev->parsed, 4);
1042 tsn = response_get_u64(&dev->parsed, 5);
1043
1044 if (hsn == 0 && tsn == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001045 pr_debug("Couldn't authenticate session\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001046 return -EPERM;
1047 }
1048
1049 dev->hsn = hsn;
1050 dev->tsn = tsn;
1051 return 0;
1052}
1053
1054static void add_suspend_info(struct opal_dev *dev,
1055 struct opal_suspend_data *sus)
1056{
1057 struct opal_suspend_data *iter;
1058
1059 list_for_each_entry(iter, &dev->unlk_lst, node) {
1060 if (iter->lr == sus->lr) {
1061 list_del(&iter->node);
1062 kfree(iter);
1063 break;
1064 }
1065 }
1066 list_add_tail(&sus->node, &dev->unlk_lst);
1067}
1068
1069static int end_session_cont(struct opal_dev *dev)
1070{
1071 dev->hsn = 0;
1072 dev->tsn = 0;
1073 return parse_and_check_status(dev);
1074}
1075
1076static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1077{
1078 int ret;
1079
1080 ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1081 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001082 pr_debug("Error finalizing command buffer: %d\n", ret);
Scott Bauer455a7b22017-02-03 12:50:31 -07001083 return ret;
1084 }
1085
1086 print_buffer(dev->cmd, dev->pos);
1087
1088 return opal_send_recv(dev, cont);
1089}
1090
David Kozub3fff2342019-02-14 01:16:04 +01001091/*
1092 * request @column from table @table on device @dev. On success, the column
1093 * data will be available in dev->resp->tok[4]
1094 */
1095static int generic_get_column(struct opal_dev *dev, const u8 *table,
1096 u64 column)
1097{
1098 int err;
1099
1100 err = cmd_start(dev, table, opalmethod[OPAL_GET]);
1101
1102 add_token_u8(&err, dev, OPAL_STARTLIST);
1103
1104 add_token_u8(&err, dev, OPAL_STARTNAME);
1105 add_token_u8(&err, dev, OPAL_STARTCOLUMN);
1106 add_token_u64(&err, dev, column);
1107 add_token_u8(&err, dev, OPAL_ENDNAME);
1108
1109 add_token_u8(&err, dev, OPAL_STARTNAME);
1110 add_token_u8(&err, dev, OPAL_ENDCOLUMN);
1111 add_token_u64(&err, dev, column);
1112 add_token_u8(&err, dev, OPAL_ENDNAME);
1113
1114 add_token_u8(&err, dev, OPAL_ENDLIST);
1115
1116 if (err)
1117 return err;
1118
1119 return finalize_and_send(dev, parse_and_check_status);
1120}
1121
Jon Derrickeed64952017-02-22 07:55:13 -07001122static int gen_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001123{
Scott Bauer455a7b22017-02-03 12:50:31 -07001124 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001125 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001126
1127 memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
Scott Bauer455a7b22017-02-03 12:50:31 -07001128 kfree(dev->prev_data);
1129 dev->prev_data = NULL;
1130
David Kozube8b29222019-02-14 01:15:58 +01001131 err = cmd_start(dev, uid, opalmethod[OPAL_GENKEY]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001132
1133 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001134 pr_debug("Error building gen key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001135 return err;
1136
1137 }
1138 return finalize_and_send(dev, parse_and_check_status);
1139}
1140
1141static int get_active_key_cont(struct opal_dev *dev)
1142{
1143 const char *activekey;
1144 size_t keylen;
1145 int error = 0;
1146
1147 error = parse_and_check_status(dev);
1148 if (error)
1149 return error;
1150 keylen = response_get_string(&dev->parsed, 4, &activekey);
1151 if (!activekey) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001152 pr_debug("%s: Couldn't extract the Activekey from the response\n",
1153 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001154 return OPAL_INVAL_PARAM;
1155 }
1156 dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1157
1158 if (!dev->prev_data)
1159 return -ENOMEM;
1160
1161 dev->prev_d_len = keylen;
1162
1163 return 0;
1164}
1165
Jon Derrickeed64952017-02-22 07:55:13 -07001166static int get_active_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001167{
1168 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001169 int err;
Jon Derrickeed64952017-02-22 07:55:13 -07001170 u8 *lr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001171
Scott Bauer455a7b22017-02-03 12:50:31 -07001172 err = build_locking_range(uid, sizeof(uid), *lr);
1173 if (err)
1174 return err;
1175
David Kozub3fff2342019-02-14 01:16:04 +01001176 err = generic_get_column(dev, uid, OPAL_ACTIVEKEY);
1177 if (err)
Scott Bauer455a7b22017-02-03 12:50:31 -07001178 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001179
David Kozub3fff2342019-02-14 01:16:04 +01001180 return get_active_key_cont(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001181}
1182
1183static int generic_lr_enable_disable(struct opal_dev *dev,
1184 u8 *uid, bool rle, bool wle,
1185 bool rl, bool wl)
1186{
David Kozube8b29222019-02-14 01:15:58 +01001187 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001188
David Kozube8b29222019-02-14 01:15:58 +01001189 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001190
Scott Bauer455a7b22017-02-03 12:50:31 -07001191 add_token_u8(&err, dev, OPAL_STARTNAME);
1192 add_token_u8(&err, dev, OPAL_VALUES);
1193 add_token_u8(&err, dev, OPAL_STARTLIST);
1194
1195 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001196 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001197 add_token_u8(&err, dev, rle);
1198 add_token_u8(&err, dev, OPAL_ENDNAME);
1199
1200 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001201 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001202 add_token_u8(&err, dev, wle);
1203 add_token_u8(&err, dev, OPAL_ENDNAME);
1204
1205 add_token_u8(&err, dev, OPAL_STARTNAME);
1206 add_token_u8(&err, dev, OPAL_READLOCKED);
1207 add_token_u8(&err, dev, rl);
1208 add_token_u8(&err, dev, OPAL_ENDNAME);
1209
1210 add_token_u8(&err, dev, OPAL_STARTNAME);
1211 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1212 add_token_u8(&err, dev, wl);
1213 add_token_u8(&err, dev, OPAL_ENDNAME);
1214
1215 add_token_u8(&err, dev, OPAL_ENDLIST);
1216 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001217 return err;
1218}
1219
1220static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1221 struct opal_user_lr_setup *setup)
1222{
1223 int err;
1224
1225 err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1226 0, 0);
1227 if (err)
Scott Bauer591c59d2017-04-07 13:58:50 -06001228 pr_debug("Failed to create enable global lr command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001229 return err;
1230}
1231
Jon Derrickeed64952017-02-22 07:55:13 -07001232static int setup_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001233{
1234 u8 uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001235 struct opal_user_lr_setup *setup = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001236 u8 lr;
David Kozube8b29222019-02-14 01:15:58 +01001237 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001238
Scott Bauer455a7b22017-02-03 12:50:31 -07001239 lr = setup->session.opal_key.lr;
1240 err = build_locking_range(uid, sizeof(uid), lr);
1241 if (err)
1242 return err;
1243
1244 if (lr == 0)
1245 err = enable_global_lr(dev, uid, setup);
1246 else {
David Kozube8b29222019-02-14 01:15:58 +01001247 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001248
Scott Bauer455a7b22017-02-03 12:50:31 -07001249 add_token_u8(&err, dev, OPAL_STARTNAME);
1250 add_token_u8(&err, dev, OPAL_VALUES);
1251 add_token_u8(&err, dev, OPAL_STARTLIST);
1252
1253 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001254 add_token_u8(&err, dev, OPAL_RANGESTART);
Scott Bauer455a7b22017-02-03 12:50:31 -07001255 add_token_u64(&err, dev, setup->range_start);
1256 add_token_u8(&err, dev, OPAL_ENDNAME);
1257
1258 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001259 add_token_u8(&err, dev, OPAL_RANGELENGTH);
Scott Bauer455a7b22017-02-03 12:50:31 -07001260 add_token_u64(&err, dev, setup->range_length);
1261 add_token_u8(&err, dev, OPAL_ENDNAME);
1262
1263 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001264 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001265 add_token_u64(&err, dev, !!setup->RLE);
1266 add_token_u8(&err, dev, OPAL_ENDNAME);
1267
1268 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001269 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001270 add_token_u64(&err, dev, !!setup->WLE);
1271 add_token_u8(&err, dev, OPAL_ENDNAME);
1272
1273 add_token_u8(&err, dev, OPAL_ENDLIST);
1274 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001275 }
1276 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001277 pr_debug("Error building Setup Locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001278 return err;
1279
1280 }
1281
1282 return finalize_and_send(dev, parse_and_check_status);
1283}
1284
1285static int start_generic_opal_session(struct opal_dev *dev,
1286 enum opal_uid auth,
1287 enum opal_uid sp_type,
1288 const char *key,
1289 u8 key_len)
1290{
1291 u32 hsn;
David Kozube8b29222019-02-14 01:15:58 +01001292 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001293
Scott Bauer591c59d2017-04-07 13:58:50 -06001294 if (key == NULL && auth != OPAL_ANYBODY_UID)
Scott Bauer455a7b22017-02-03 12:50:31 -07001295 return OPAL_INVAL_PARAM;
Scott Bauer455a7b22017-02-03 12:50:31 -07001296
Scott Bauer455a7b22017-02-03 12:50:31 -07001297 hsn = GENERIC_HOST_SESSION_NUM;
David Kozube8b29222019-02-14 01:15:58 +01001298 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1299 opalmethod[OPAL_STARTSESSION]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001300
Scott Bauer455a7b22017-02-03 12:50:31 -07001301 add_token_u64(&err, dev, hsn);
1302 add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1303 add_token_u8(&err, dev, 1);
1304
1305 switch (auth) {
1306 case OPAL_ANYBODY_UID:
Scott Bauer455a7b22017-02-03 12:50:31 -07001307 break;
1308 case OPAL_ADMIN1_UID:
1309 case OPAL_SID_UID:
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06001310 case OPAL_PSID_UID:
Scott Bauer455a7b22017-02-03 12:50:31 -07001311 add_token_u8(&err, dev, OPAL_STARTNAME);
1312 add_token_u8(&err, dev, 0); /* HostChallenge */
1313 add_token_bytestring(&err, dev, key, key_len);
1314 add_token_u8(&err, dev, OPAL_ENDNAME);
1315 add_token_u8(&err, dev, OPAL_STARTNAME);
1316 add_token_u8(&err, dev, 3); /* HostSignAuth */
1317 add_token_bytestring(&err, dev, opaluid[auth],
1318 OPAL_UID_LENGTH);
1319 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001320 break;
1321 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001322 pr_debug("Cannot start Admin SP session with auth %d\n", auth);
Scott Bauer455a7b22017-02-03 12:50:31 -07001323 return OPAL_INVAL_PARAM;
1324 }
1325
1326 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001327 pr_debug("Error building start adminsp session command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001328 return err;
1329 }
1330
1331 return finalize_and_send(dev, start_opal_session_cont);
1332}
1333
Jon Derrickeed64952017-02-22 07:55:13 -07001334static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001335{
1336 return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1337 OPAL_ADMINSP_UID, NULL, 0);
1338}
1339
Jon Derrickeed64952017-02-22 07:55:13 -07001340static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001341{
1342 int ret;
1343 const u8 *key = dev->prev_data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001344
1345 if (!key) {
Jon Derrickeed64952017-02-22 07:55:13 -07001346 const struct opal_key *okey = data;
David Kozub1e815b32019-02-14 01:15:54 +01001347
Scott Bauer455a7b22017-02-03 12:50:31 -07001348 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1349 OPAL_ADMINSP_UID,
1350 okey->key,
1351 okey->key_len);
1352 } else {
1353 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1354 OPAL_ADMINSP_UID,
1355 key, dev->prev_d_len);
1356 kfree(key);
1357 dev->prev_data = NULL;
1358 }
1359 return ret;
1360}
1361
Jon Derrickeed64952017-02-22 07:55:13 -07001362static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001363{
Jon Derrickeed64952017-02-22 07:55:13 -07001364 struct opal_key *key = data;
David Kozub1e815b32019-02-14 01:15:54 +01001365
Scott Bauer455a7b22017-02-03 12:50:31 -07001366 return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1367 OPAL_LOCKINGSP_UID,
1368 key->key, key->key_len);
1369}
1370
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06001371static int start_PSID_opal_session(struct opal_dev *dev, void *data)
1372{
1373 const struct opal_key *okey = data;
1374
1375 return start_generic_opal_session(dev, OPAL_PSID_UID,
1376 OPAL_ADMINSP_UID,
1377 okey->key,
1378 okey->key_len);
1379}
1380
Jon Derrickeed64952017-02-22 07:55:13 -07001381static int start_auth_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001382{
Jon Derrickeed64952017-02-22 07:55:13 -07001383 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001384 u8 lk_ul_user[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001385 size_t keylen = session->opal_key.key_len;
Scott Bauer455a7b22017-02-03 12:50:31 -07001386 int err = 0;
1387
Scott Bauer455a7b22017-02-03 12:50:31 -07001388 u8 *key = session->opal_key.key;
1389 u32 hsn = GENERIC_HOST_SESSION_NUM;
1390
David Kozube8b29222019-02-14 01:15:58 +01001391 if (session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001392 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1393 session->opal_key.lr);
David Kozube8b29222019-02-14 01:15:58 +01001394 else if (session->who != OPAL_ADMIN1 && !session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001395 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1396 session->who - 1);
David Kozube8b29222019-02-14 01:15:58 +01001397 else
Scott Bauer455a7b22017-02-03 12:50:31 -07001398 memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1399
David Kozube8b29222019-02-14 01:15:58 +01001400 if (err)
1401 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001402
David Kozube8b29222019-02-14 01:15:58 +01001403 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1404 opalmethod[OPAL_STARTSESSION]);
1405
Scott Bauer455a7b22017-02-03 12:50:31 -07001406 add_token_u64(&err, dev, hsn);
1407 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1408 OPAL_UID_LENGTH);
1409 add_token_u8(&err, dev, 1);
1410 add_token_u8(&err, dev, OPAL_STARTNAME);
1411 add_token_u8(&err, dev, 0);
1412 add_token_bytestring(&err, dev, key, keylen);
1413 add_token_u8(&err, dev, OPAL_ENDNAME);
1414 add_token_u8(&err, dev, OPAL_STARTNAME);
1415 add_token_u8(&err, dev, 3);
1416 add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1417 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001418
1419 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001420 pr_debug("Error building STARTSESSION command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001421 return err;
1422 }
1423
1424 return finalize_and_send(dev, start_opal_session_cont);
1425}
1426
Jon Derrickeed64952017-02-22 07:55:13 -07001427static int revert_tper(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001428{
David Kozube8b29222019-02-14 01:15:58 +01001429 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001430
David Kozube8b29222019-02-14 01:15:58 +01001431 err = cmd_start(dev, opaluid[OPAL_ADMINSP_UID],
1432 opalmethod[OPAL_REVERT]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001433 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001434 pr_debug("Error building REVERT TPER command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001435 return err;
1436 }
1437
1438 return finalize_and_send(dev, parse_and_check_status);
1439}
1440
Jon Derrickeed64952017-02-22 07:55:13 -07001441static int internal_activate_user(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001442{
Jon Derrickeed64952017-02-22 07:55:13 -07001443 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001444 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001445 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001446
1447 memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1448 uid[7] = session->who;
1449
David Kozube8b29222019-02-14 01:15:58 +01001450 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001451 add_token_u8(&err, dev, OPAL_STARTNAME);
1452 add_token_u8(&err, dev, OPAL_VALUES);
1453 add_token_u8(&err, dev, OPAL_STARTLIST);
1454 add_token_u8(&err, dev, OPAL_STARTNAME);
1455 add_token_u8(&err, dev, 5); /* Enabled */
1456 add_token_u8(&err, dev, OPAL_TRUE);
1457 add_token_u8(&err, dev, OPAL_ENDNAME);
1458 add_token_u8(&err, dev, OPAL_ENDLIST);
1459 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001460
1461 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001462 pr_debug("Error building Activate UserN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001463 return err;
1464 }
1465
1466 return finalize_and_send(dev, parse_and_check_status);
1467}
1468
Jon Derrickeed64952017-02-22 07:55:13 -07001469static int erase_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001470{
Jon Derrickeed64952017-02-22 07:55:13 -07001471 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001472 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001473 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001474
1475 if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1476 return -ERANGE;
1477
David Kozube8b29222019-02-14 01:15:58 +01001478 err = cmd_start(dev, uid, opalmethod[OPAL_ERASE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001479
1480 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001481 pr_debug("Error building Erase Locking Range Command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001482 return err;
1483 }
1484 return finalize_and_send(dev, parse_and_check_status);
1485}
1486
Jon Derrickeed64952017-02-22 07:55:13 -07001487static int set_mbr_done(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001488{
Jon Derrickeed64952017-02-22 07:55:13 -07001489 u8 *mbr_done_tf = data;
David Kozube8b29222019-02-14 01:15:58 +01001490 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001491
David Kozube8b29222019-02-14 01:15:58 +01001492 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1493 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001494
Scott Bauer455a7b22017-02-03 12:50:31 -07001495 add_token_u8(&err, dev, OPAL_STARTNAME);
1496 add_token_u8(&err, dev, OPAL_VALUES);
1497 add_token_u8(&err, dev, OPAL_STARTLIST);
1498 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001499 add_token_u8(&err, dev, OPAL_MBRDONE);
Jon Derrickeed64952017-02-22 07:55:13 -07001500 add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
Scott Bauer455a7b22017-02-03 12:50:31 -07001501 add_token_u8(&err, dev, OPAL_ENDNAME);
1502 add_token_u8(&err, dev, OPAL_ENDLIST);
1503 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001504
1505 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001506 pr_debug("Error Building set MBR Done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001507 return err;
1508 }
1509
1510 return finalize_and_send(dev, parse_and_check_status);
1511}
1512
Jon Derrickeed64952017-02-22 07:55:13 -07001513static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001514{
Jon Derrickeed64952017-02-22 07:55:13 -07001515 u8 *mbr_en_dis = data;
David Kozube8b29222019-02-14 01:15:58 +01001516 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001517
David Kozube8b29222019-02-14 01:15:58 +01001518 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1519 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001520
Scott Bauer455a7b22017-02-03 12:50:31 -07001521 add_token_u8(&err, dev, OPAL_STARTNAME);
1522 add_token_u8(&err, dev, OPAL_VALUES);
1523 add_token_u8(&err, dev, OPAL_STARTLIST);
1524 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001525 add_token_u8(&err, dev, OPAL_MBRENABLE);
Jon Derrickeed64952017-02-22 07:55:13 -07001526 add_token_u8(&err, dev, *mbr_en_dis);
Scott Bauer455a7b22017-02-03 12:50:31 -07001527 add_token_u8(&err, dev, OPAL_ENDNAME);
1528 add_token_u8(&err, dev, OPAL_ENDLIST);
1529 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001530
1531 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001532 pr_debug("Error Building set MBR done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001533 return err;
1534 }
1535
1536 return finalize_and_send(dev, parse_and_check_status);
1537}
1538
1539static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1540 struct opal_dev *dev)
1541{
David Kozube8b29222019-02-14 01:15:58 +01001542 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001543
David Kozube8b29222019-02-14 01:15:58 +01001544 err = cmd_start(dev, cpin_uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001545
Scott Bauer455a7b22017-02-03 12:50:31 -07001546 add_token_u8(&err, dev, OPAL_STARTNAME);
1547 add_token_u8(&err, dev, OPAL_VALUES);
1548 add_token_u8(&err, dev, OPAL_STARTLIST);
1549 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001550 add_token_u8(&err, dev, OPAL_PIN);
Scott Bauer455a7b22017-02-03 12:50:31 -07001551 add_token_bytestring(&err, dev, key, key_len);
1552 add_token_u8(&err, dev, OPAL_ENDNAME);
1553 add_token_u8(&err, dev, OPAL_ENDLIST);
1554 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001555
1556 return err;
1557}
1558
Jon Derrickeed64952017-02-22 07:55:13 -07001559static int set_new_pw(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001560{
1561 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001562 struct opal_session_info *usr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001563
1564 memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1565
1566 if (usr->who != OPAL_ADMIN1) {
1567 cpin_uid[5] = 0x03;
1568 if (usr->sum)
1569 cpin_uid[7] = usr->opal_key.lr + 1;
1570 else
1571 cpin_uid[7] = usr->who;
1572 }
1573
1574 if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1575 cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001576 pr_debug("Error building set password command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001577 return -ERANGE;
1578 }
1579
1580 return finalize_and_send(dev, parse_and_check_status);
1581}
1582
Jon Derrickeed64952017-02-22 07:55:13 -07001583static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001584{
1585 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001586 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001587
1588 memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1589
1590 if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001591 pr_debug("Error building Set SID cpin\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001592 return -ERANGE;
1593 }
1594 return finalize_and_send(dev, parse_and_check_status);
1595}
1596
Jon Derrickeed64952017-02-22 07:55:13 -07001597static int add_user_to_lr(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001598{
1599 u8 lr_buffer[OPAL_UID_LENGTH];
1600 u8 user_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001601 struct opal_lock_unlock *lkul = data;
David Kozube8b29222019-02-14 01:15:58 +01001602 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001603
Scott Bauer455a7b22017-02-03 12:50:31 -07001604 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1605 OPAL_UID_LENGTH);
1606
1607 if (lkul->l_state == OPAL_RW)
1608 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1609 OPAL_UID_LENGTH);
1610
1611 lr_buffer[7] = lkul->session.opal_key.lr;
1612
1613 memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1614
1615 user_uid[7] = lkul->session.who;
1616
David Kozube8b29222019-02-14 01:15:58 +01001617 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001618
Scott Bauer455a7b22017-02-03 12:50:31 -07001619 add_token_u8(&err, dev, OPAL_STARTNAME);
1620 add_token_u8(&err, dev, OPAL_VALUES);
1621
1622 add_token_u8(&err, dev, OPAL_STARTLIST);
1623 add_token_u8(&err, dev, OPAL_STARTNAME);
1624 add_token_u8(&err, dev, 3);
1625
1626 add_token_u8(&err, dev, OPAL_STARTLIST);
1627
1628
1629 add_token_u8(&err, dev, OPAL_STARTNAME);
1630 add_token_bytestring(&err, dev,
1631 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1632 OPAL_UID_LENGTH/2);
1633 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1634 add_token_u8(&err, dev, OPAL_ENDNAME);
1635
1636
1637 add_token_u8(&err, dev, OPAL_STARTNAME);
1638 add_token_bytestring(&err, dev,
1639 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1640 OPAL_UID_LENGTH/2);
1641 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1642 add_token_u8(&err, dev, OPAL_ENDNAME);
1643
1644
1645 add_token_u8(&err, dev, OPAL_STARTNAME);
1646 add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1647 OPAL_UID_LENGTH/2);
1648 add_token_u8(&err, dev, 1);
1649 add_token_u8(&err, dev, OPAL_ENDNAME);
1650
1651
1652 add_token_u8(&err, dev, OPAL_ENDLIST);
1653 add_token_u8(&err, dev, OPAL_ENDNAME);
1654 add_token_u8(&err, dev, OPAL_ENDLIST);
1655 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001656
1657 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001658 pr_debug("Error building add user to locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001659 return err;
1660 }
1661
1662 return finalize_and_send(dev, parse_and_check_status);
1663}
1664
Jon Derrickeed64952017-02-22 07:55:13 -07001665static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001666{
1667 u8 lr_buffer[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001668 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001669 u8 read_locked = 1, write_locked = 1;
1670 int err = 0;
1671
Scott Bauer455a7b22017-02-03 12:50:31 -07001672 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1673 lkul->session.opal_key.lr) < 0)
1674 return -ERANGE;
1675
1676 switch (lkul->l_state) {
1677 case OPAL_RO:
1678 read_locked = 0;
1679 write_locked = 1;
1680 break;
1681 case OPAL_RW:
1682 read_locked = 0;
1683 write_locked = 0;
1684 break;
1685 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001686 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001687 break;
1688 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001689 pr_debug("Tried to set an invalid locking state... returning to uland\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001690 return OPAL_INVAL_PARAM;
1691 }
1692
David Kozube8b29222019-02-14 01:15:58 +01001693 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
1694
Scott Bauer455a7b22017-02-03 12:50:31 -07001695 add_token_u8(&err, dev, OPAL_STARTNAME);
1696 add_token_u8(&err, dev, OPAL_VALUES);
1697 add_token_u8(&err, dev, OPAL_STARTLIST);
1698
1699 add_token_u8(&err, dev, OPAL_STARTNAME);
1700 add_token_u8(&err, dev, OPAL_READLOCKED);
1701 add_token_u8(&err, dev, read_locked);
1702 add_token_u8(&err, dev, OPAL_ENDNAME);
1703
1704 add_token_u8(&err, dev, OPAL_STARTNAME);
1705 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1706 add_token_u8(&err, dev, write_locked);
1707 add_token_u8(&err, dev, OPAL_ENDNAME);
1708
1709 add_token_u8(&err, dev, OPAL_ENDLIST);
1710 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001711
1712 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001713 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001714 return err;
1715 }
1716 return finalize_and_send(dev, parse_and_check_status);
1717}
1718
1719
Jon Derrickeed64952017-02-22 07:55:13 -07001720static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001721{
1722 u8 lr_buffer[OPAL_UID_LENGTH];
1723 u8 read_locked = 1, write_locked = 1;
Jon Derrickeed64952017-02-22 07:55:13 -07001724 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001725 int ret;
1726
1727 clear_opal_cmd(dev);
1728 set_comid(dev, dev->comid);
1729
Scott Bauer455a7b22017-02-03 12:50:31 -07001730 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1731 lkul->session.opal_key.lr) < 0)
1732 return -ERANGE;
1733
1734 switch (lkul->l_state) {
1735 case OPAL_RO:
1736 read_locked = 0;
1737 write_locked = 1;
1738 break;
1739 case OPAL_RW:
1740 read_locked = 0;
1741 write_locked = 0;
1742 break;
1743 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001744 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001745 break;
1746 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001747 pr_debug("Tried to set an invalid locking state.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001748 return OPAL_INVAL_PARAM;
1749 }
1750 ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1751 read_locked, write_locked);
1752
1753 if (ret < 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001754 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001755 return ret;
1756 }
1757 return finalize_and_send(dev, parse_and_check_status);
1758}
1759
Jon Derrickeed64952017-02-22 07:55:13 -07001760static int activate_lsp(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001761{
Jon Derrickeed64952017-02-22 07:55:13 -07001762 struct opal_lr_act *opal_act = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001763 u8 user_lr[OPAL_UID_LENGTH];
1764 u8 uint_3 = 0x83;
David Kozube8b29222019-02-14 01:15:58 +01001765 int err, i;
Scott Bauer455a7b22017-02-03 12:50:31 -07001766
David Kozube8b29222019-02-14 01:15:58 +01001767 err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID],
1768 opalmethod[OPAL_ACTIVATE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001769
1770 if (opal_act->sum) {
1771 err = build_locking_range(user_lr, sizeof(user_lr),
1772 opal_act->lr[0]);
1773 if (err)
1774 return err;
1775
Scott Bauer455a7b22017-02-03 12:50:31 -07001776 add_token_u8(&err, dev, OPAL_STARTNAME);
1777 add_token_u8(&err, dev, uint_3);
1778 add_token_u8(&err, dev, 6);
1779 add_token_u8(&err, dev, 0);
1780 add_token_u8(&err, dev, 0);
1781
1782 add_token_u8(&err, dev, OPAL_STARTLIST);
1783 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1784 for (i = 1; i < opal_act->num_lrs; i++) {
1785 user_lr[7] = opal_act->lr[i];
1786 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1787 }
1788 add_token_u8(&err, dev, OPAL_ENDLIST);
1789 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001790 }
1791
1792 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001793 pr_debug("Error building Activate LockingSP command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001794 return err;
1795 }
1796
1797 return finalize_and_send(dev, parse_and_check_status);
1798}
1799
David Kozub3fff2342019-02-14 01:16:04 +01001800/* Determine if we're in the Manufactured Inactive or Active state */
1801static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001802{
1803 u8 lc_status;
David Kozub3fff2342019-02-14 01:16:04 +01001804 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001805
David Kozub3fff2342019-02-14 01:16:04 +01001806 err = generic_get_column(dev, opaluid[OPAL_LOCKINGSP_UID],
1807 OPAL_LIFECYCLE);
1808 if (err)
1809 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001810
1811 lc_status = response_get_u64(&dev->parsed, 4);
David Kozub1e815b32019-02-14 01:15:54 +01001812 /* 0x08 is Manufactured Inactive */
Scott Bauer455a7b22017-02-03 12:50:31 -07001813 /* 0x09 is Manufactured */
1814 if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001815 pr_debug("Couldn't determine the status of the Lifecycle state\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001816 return -ENODEV;
1817 }
1818
1819 return 0;
1820}
1821
David Kozub3fff2342019-02-14 01:16:04 +01001822static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001823{
1824 const char *msid_pin;
1825 size_t strlen;
David Kozub3fff2342019-02-14 01:16:04 +01001826 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001827
David Kozub3fff2342019-02-14 01:16:04 +01001828 err = generic_get_column(dev, opaluid[OPAL_C_PIN_MSID], OPAL_PIN);
1829 if (err)
1830 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001831
1832 strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1833 if (!msid_pin) {
David Kozub3fff2342019-02-14 01:16:04 +01001834 pr_debug("Couldn't extract MSID_CPIN from response\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001835 return OPAL_INVAL_PARAM;
1836 }
1837
1838 dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1839 if (!dev->prev_data)
1840 return -ENOMEM;
1841
1842 dev->prev_d_len = strlen;
1843
1844 return 0;
1845}
1846
Jon Derrickeed64952017-02-22 07:55:13 -07001847static int end_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001848{
1849 int err = 0;
1850
1851 clear_opal_cmd(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001852 set_comid(dev, dev->comid);
1853 add_token_u8(&err, dev, OPAL_ENDOFSESSION);
Scott Bauer455a7b22017-02-03 12:50:31 -07001854
Jon Derrickeed64952017-02-22 07:55:13 -07001855 if (err < 0)
1856 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001857 return finalize_and_send(dev, end_session_cont);
1858}
1859
1860static int end_opal_session_error(struct opal_dev *dev)
1861{
David Kozub0af26482019-02-14 01:16:07 +01001862 const struct opal_step error_end_session = {
1863 end_opal_session,
Scott Bauer455a7b22017-02-03 12:50:31 -07001864 };
David Kozub0af26482019-02-14 01:16:07 +01001865 return execute_step(dev, &error_end_session, 0);
Scott Bauer455a7b22017-02-03 12:50:31 -07001866}
1867
David Kozub3db87232019-02-14 01:16:06 +01001868static inline void setup_opal_dev(struct opal_dev *dev)
Scott Bauer455a7b22017-02-03 12:50:31 -07001869{
Scott Bauer455a7b22017-02-03 12:50:31 -07001870 dev->tsn = 0;
1871 dev->hsn = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -07001872 dev->prev_data = NULL;
1873}
1874
1875static int check_opal_support(struct opal_dev *dev)
1876{
Scott Bauer455a7b22017-02-03 12:50:31 -07001877 int ret;
1878
1879 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001880 setup_opal_dev(dev);
David Kozub0af26482019-02-14 01:16:07 +01001881 ret = opal_discovery0_step(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001882 dev->supported = !ret;
1883 mutex_unlock(&dev->dev_lock);
1884 return ret;
1885}
1886
Scott Bauer7d6d1572017-02-22 10:15:06 -07001887static void clean_opal_dev(struct opal_dev *dev)
1888{
1889
1890 struct opal_suspend_data *suspend, *next;
1891
1892 mutex_lock(&dev->dev_lock);
1893 list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
1894 list_del(&suspend->node);
1895 kfree(suspend);
1896 }
1897 mutex_unlock(&dev->dev_lock);
1898}
1899
1900void free_opal_dev(struct opal_dev *dev)
1901{
1902 if (!dev)
1903 return;
1904 clean_opal_dev(dev);
1905 kfree(dev);
1906}
1907EXPORT_SYMBOL(free_opal_dev);
1908
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01001909struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
Scott Bauer455a7b22017-02-03 12:50:31 -07001910{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01001911 struct opal_dev *dev;
1912
1913 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
1914 if (!dev)
1915 return NULL;
1916
1917 INIT_LIST_HEAD(&dev->unlk_lst);
1918 mutex_init(&dev->dev_lock);
1919 dev->data = data;
1920 dev->send_recv = send_recv;
1921 if (check_opal_support(dev) != 0) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +01001922 pr_debug("Opal is not supported on this device\n");
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01001923 kfree(dev);
1924 return NULL;
1925 }
1926 return dev;
Scott Bauer455a7b22017-02-03 12:50:31 -07001927}
1928EXPORT_SYMBOL(init_opal_dev);
1929
1930static int opal_secure_erase_locking_range(struct opal_dev *dev,
1931 struct opal_session_info *opal_session)
1932{
Jon Derrickeed64952017-02-22 07:55:13 -07001933 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07001934 { start_auth_opal_session, opal_session },
1935 { get_active_key, &opal_session->opal_key.lr },
1936 { gen_key, },
David Kozub3db87232019-02-14 01:16:06 +01001937 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001938 };
1939 int ret;
1940
1941 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001942 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01001943 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07001944 mutex_unlock(&dev->dev_lock);
1945 return ret;
1946}
1947
1948static int opal_erase_locking_range(struct opal_dev *dev,
1949 struct opal_session_info *opal_session)
1950{
Jon Derrickeed64952017-02-22 07:55:13 -07001951 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07001952 { start_auth_opal_session, opal_session },
1953 { erase_locking_range, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01001954 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001955 };
1956 int ret;
1957
1958 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001959 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01001960 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07001961 mutex_unlock(&dev->dev_lock);
1962 return ret;
1963}
1964
1965static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
1966 struct opal_mbr_data *opal_mbr)
1967{
David Kozub78bf4732019-02-14 01:15:53 +01001968 u8 enable_disable = opal_mbr->enable_disable == OPAL_MBR_ENABLE ?
1969 OPAL_TRUE : OPAL_FALSE;
1970
Jon Derrickeed64952017-02-22 07:55:13 -07001971 const struct opal_step mbr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07001972 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01001973 { set_mbr_done, &enable_disable },
Jon Derrickeed64952017-02-22 07:55:13 -07001974 { end_opal_session, },
1975 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01001976 { set_mbr_enable_disable, &enable_disable },
David Kozub3db87232019-02-14 01:16:06 +01001977 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001978 };
1979 int ret;
1980
1981 if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
1982 opal_mbr->enable_disable != OPAL_MBR_DISABLE)
1983 return -EINVAL;
1984
1985 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001986 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01001987 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07001988 mutex_unlock(&dev->dev_lock);
1989 return ret;
1990}
1991
1992static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
1993{
1994 struct opal_suspend_data *suspend;
1995
1996 suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
1997 if (!suspend)
1998 return -ENOMEM;
1999
2000 suspend->unlk = *lk_unlk;
2001 suspend->lr = lk_unlk->session.opal_key.lr;
2002
2003 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002004 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002005 add_suspend_info(dev, suspend);
2006 mutex_unlock(&dev->dev_lock);
2007 return 0;
2008}
2009
2010static int opal_add_user_to_lr(struct opal_dev *dev,
2011 struct opal_lock_unlock *lk_unlk)
2012{
Jon Derrickeed64952017-02-22 07:55:13 -07002013 const struct opal_step steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002014 { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2015 { add_user_to_lr, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002016 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002017 };
2018 int ret;
2019
2020 if (lk_unlk->l_state != OPAL_RO &&
2021 lk_unlk->l_state != OPAL_RW) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002022 pr_debug("Locking state was not RO or RW\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07002023 return -EINVAL;
2024 }
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002025 if (lk_unlk->session.who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002026 lk_unlk->session.who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002027 pr_debug("Authority was not within the range of users: %d\n",
2028 lk_unlk->session.who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002029 return -EINVAL;
2030 }
2031 if (lk_unlk->session.sum) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002032 pr_debug("%s not supported in sum. Use setup locking range\n",
2033 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07002034 return -EINVAL;
2035 }
2036
2037 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002038 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002039 ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002040 mutex_unlock(&dev->dev_lock);
2041 return ret;
2042}
2043
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002044static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal, bool psid)
Scott Bauer455a7b22017-02-03 12:50:31 -07002045{
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002046 /* controller will terminate session */
Jon Derrickeed64952017-02-22 07:55:13 -07002047 const struct opal_step revert_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002048 { start_SIDASP_opal_session, opal },
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002049 { revert_tper, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002050 };
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002051 const struct opal_step psid_revert_steps[] = {
2052 { start_PSID_opal_session, opal },
2053 { revert_tper, }
2054 };
2055
Scott Bauer455a7b22017-02-03 12:50:31 -07002056 int ret;
2057
2058 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002059 setup_opal_dev(dev);
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002060 if (psid)
2061 ret = execute_steps(dev, psid_revert_steps,
2062 ARRAY_SIZE(psid_revert_steps));
2063 else
2064 ret = execute_steps(dev, revert_steps,
2065 ARRAY_SIZE(revert_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002066 mutex_unlock(&dev->dev_lock);
Scott Bauer7d6d1572017-02-22 10:15:06 -07002067
2068 /*
2069 * If we successfully reverted lets clean
2070 * any saved locking ranges.
2071 */
2072 if (!ret)
2073 clean_opal_dev(dev);
2074
Scott Bauer455a7b22017-02-03 12:50:31 -07002075 return ret;
2076}
2077
Jon Derrickeed64952017-02-22 07:55:13 -07002078static int __opal_lock_unlock(struct opal_dev *dev,
2079 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002080{
Jon Derrickeed64952017-02-22 07:55:13 -07002081 const struct opal_step unlock_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002082 { start_auth_opal_session, &lk_unlk->session },
2083 { lock_unlock_locking_range, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002084 { end_opal_session, }
Jon Derrickeed64952017-02-22 07:55:13 -07002085 };
2086 const struct opal_step unlock_sum_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002087 { start_auth_opal_session, &lk_unlk->session },
2088 { lock_unlock_locking_range_sum, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002089 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002090 };
2091
David Kozub3db87232019-02-14 01:16:06 +01002092 if (lk_unlk->session.sum)
David Kozuba80f36c2019-02-14 01:16:08 +01002093 return execute_steps(dev, unlock_sum_steps,
2094 ARRAY_SIZE(unlock_sum_steps));
David Kozub3db87232019-02-14 01:16:06 +01002095 else
David Kozuba80f36c2019-02-14 01:16:08 +01002096 return execute_steps(dev, unlock_steps,
2097 ARRAY_SIZE(unlock_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002098}
2099
Scott Bauerdbec491b2017-09-01 08:53:35 -06002100static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2101{
David Kozub78bf4732019-02-14 01:15:53 +01002102 u8 mbr_done_tf = OPAL_TRUE;
David Kozub1e815b32019-02-14 01:15:54 +01002103 const struct opal_step mbrdone_step[] = {
Scott Bauerdbec491b2017-09-01 08:53:35 -06002104 { start_admin1LSP_opal_session, key },
2105 { set_mbr_done, &mbr_done_tf },
David Kozub3db87232019-02-14 01:16:06 +01002106 { end_opal_session, }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002107 };
2108
David Kozuba80f36c2019-02-14 01:16:08 +01002109 return execute_steps(dev, mbrdone_step, ARRAY_SIZE(mbrdone_step));
Scott Bauerdbec491b2017-09-01 08:53:35 -06002110}
2111
Jon Derrickeed64952017-02-22 07:55:13 -07002112static int opal_lock_unlock(struct opal_dev *dev,
2113 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002114{
Scott Bauer455a7b22017-02-03 12:50:31 -07002115 int ret;
2116
2117 if (lk_unlk->session.who < OPAL_ADMIN1 ||
2118 lk_unlk->session.who > OPAL_USER9)
2119 return -EINVAL;
2120
2121 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002122 ret = __opal_lock_unlock(dev, lk_unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002123 mutex_unlock(&dev->dev_lock);
2124 return ret;
2125}
2126
2127static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2128{
Jon Derrickeed64952017-02-22 07:55:13 -07002129 const struct opal_step owner_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002130 { start_anybodyASP_opal_session, },
2131 { get_msid_cpin_pin, },
2132 { end_opal_session, },
2133 { start_SIDASP_opal_session, opal },
2134 { set_sid_cpin_pin, opal },
David Kozub3db87232019-02-14 01:16:06 +01002135 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002136 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002137 int ret;
2138
2139 if (!dev)
2140 return -ENODEV;
2141
2142 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002143 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002144 ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002145 mutex_unlock(&dev->dev_lock);
2146 return ret;
2147}
2148
David Kozub1e815b32019-02-14 01:15:54 +01002149static int opal_activate_lsp(struct opal_dev *dev,
2150 struct opal_lr_act *opal_lr_act)
Scott Bauer455a7b22017-02-03 12:50:31 -07002151{
Jon Derrickeed64952017-02-22 07:55:13 -07002152 const struct opal_step active_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002153 { start_SIDASP_opal_session, &opal_lr_act->key },
2154 { get_lsp_lifecycle, },
2155 { activate_lsp, opal_lr_act },
David Kozub3db87232019-02-14 01:16:06 +01002156 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002157 };
2158 int ret;
2159
2160 if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2161 return -EINVAL;
2162
2163 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002164 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002165 ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002166 mutex_unlock(&dev->dev_lock);
2167 return ret;
2168}
2169
2170static int opal_setup_locking_range(struct opal_dev *dev,
2171 struct opal_user_lr_setup *opal_lrs)
2172{
Jon Derrickeed64952017-02-22 07:55:13 -07002173 const struct opal_step lr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002174 { start_auth_opal_session, &opal_lrs->session },
2175 { setup_locking_range, opal_lrs },
David Kozub3db87232019-02-14 01:16:06 +01002176 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002177 };
2178 int ret;
2179
2180 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002181 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002182 ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002183 mutex_unlock(&dev->dev_lock);
2184 return ret;
2185}
2186
2187static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2188{
Jon Derrickeed64952017-02-22 07:55:13 -07002189 const struct opal_step pw_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002190 { start_auth_opal_session, &opal_pw->session },
2191 { set_new_pw, &opal_pw->new_user_pw },
David Kozub3db87232019-02-14 01:16:06 +01002192 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002193 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002194 int ret;
2195
2196 if (opal_pw->session.who < OPAL_ADMIN1 ||
2197 opal_pw->session.who > OPAL_USER9 ||
2198 opal_pw->new_user_pw.who < OPAL_ADMIN1 ||
2199 opal_pw->new_user_pw.who > OPAL_USER9)
2200 return -EINVAL;
2201
2202 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002203 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002204 ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002205 mutex_unlock(&dev->dev_lock);
2206 return ret;
2207}
2208
2209static int opal_activate_user(struct opal_dev *dev,
2210 struct opal_session_info *opal_session)
2211{
Jon Derrickeed64952017-02-22 07:55:13 -07002212 const struct opal_step act_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002213 { start_admin1LSP_opal_session, &opal_session->opal_key },
2214 { internal_activate_user, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01002215 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002216 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002217 int ret;
2218
2219 /* We can't activate Admin1 it's active as manufactured */
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002220 if (opal_session->who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002221 opal_session->who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002222 pr_debug("Who was not a valid user: %d\n", opal_session->who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002223 return -EINVAL;
2224 }
2225
2226 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002227 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002228 ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002229 mutex_unlock(&dev->dev_lock);
2230 return ret;
2231}
2232
2233bool opal_unlock_from_suspend(struct opal_dev *dev)
2234{
2235 struct opal_suspend_data *suspend;
Scott Bauer455a7b22017-02-03 12:50:31 -07002236 bool was_failure = false;
2237 int ret = 0;
2238
2239 if (!dev)
2240 return false;
2241 if (!dev->supported)
2242 return false;
2243
2244 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002245 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002246
2247 list_for_each_entry(suspend, &dev->unlk_lst, node) {
Scott Bauer455a7b22017-02-03 12:50:31 -07002248 dev->tsn = 0;
2249 dev->hsn = 0;
2250
Jon Derrickeed64952017-02-22 07:55:13 -07002251 ret = __opal_lock_unlock(dev, &suspend->unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002252 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002253 pr_debug("Failed to unlock LR %hhu with sum %d\n",
2254 suspend->unlk.session.opal_key.lr,
2255 suspend->unlk.session.sum);
Scott Bauer455a7b22017-02-03 12:50:31 -07002256 was_failure = true;
2257 }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002258 if (dev->mbr_enabled) {
2259 ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
2260 if (ret)
2261 pr_debug("Failed to set MBR Done in S3 resume\n");
2262 }
Scott Bauer455a7b22017-02-03 12:50:31 -07002263 }
2264 mutex_unlock(&dev->dev_lock);
2265 return was_failure;
2266}
2267EXPORT_SYMBOL(opal_unlock_from_suspend);
2268
Scott Bauere225c202017-02-14 17:29:36 -07002269int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
Scott Bauer455a7b22017-02-03 12:50:31 -07002270{
Scott Bauere225c202017-02-14 17:29:36 -07002271 void *p;
2272 int ret = -ENOTTY;
Scott Bauer455a7b22017-02-03 12:50:31 -07002273
2274 if (!capable(CAP_SYS_ADMIN))
2275 return -EACCES;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002276 if (!dev)
2277 return -ENOTSUPP;
Scott Bauer591c59d2017-04-07 13:58:50 -06002278 if (!dev->supported)
Scott Bauer455a7b22017-02-03 12:50:31 -07002279 return -ENOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -07002280
Jon Derrickeed64952017-02-22 07:55:13 -07002281 p = memdup_user(arg, _IOC_SIZE(cmd));
Scott Bauere225c202017-02-14 17:29:36 -07002282 if (IS_ERR(p))
2283 return PTR_ERR(p);
2284
Scott Bauer455a7b22017-02-03 12:50:31 -07002285 switch (cmd) {
Scott Bauere225c202017-02-14 17:29:36 -07002286 case IOC_OPAL_SAVE:
2287 ret = opal_save(dev, p);
2288 break;
2289 case IOC_OPAL_LOCK_UNLOCK:
2290 ret = opal_lock_unlock(dev, p);
2291 break;
2292 case IOC_OPAL_TAKE_OWNERSHIP:
2293 ret = opal_take_ownership(dev, p);
2294 break;
2295 case IOC_OPAL_ACTIVATE_LSP:
2296 ret = opal_activate_lsp(dev, p);
2297 break;
2298 case IOC_OPAL_SET_PW:
2299 ret = opal_set_new_pw(dev, p);
2300 break;
2301 case IOC_OPAL_ACTIVATE_USR:
2302 ret = opal_activate_user(dev, p);
2303 break;
2304 case IOC_OPAL_REVERT_TPR:
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002305 ret = opal_reverttper(dev, p, false);
Scott Bauere225c202017-02-14 17:29:36 -07002306 break;
2307 case IOC_OPAL_LR_SETUP:
2308 ret = opal_setup_locking_range(dev, p);
2309 break;
2310 case IOC_OPAL_ADD_USR_TO_LR:
2311 ret = opal_add_user_to_lr(dev, p);
2312 break;
2313 case IOC_OPAL_ENABLE_DISABLE_MBR:
2314 ret = opal_enable_disable_shadow_mbr(dev, p);
2315 break;
2316 case IOC_OPAL_ERASE_LR:
2317 ret = opal_erase_locking_range(dev, p);
2318 break;
2319 case IOC_OPAL_SECURE_ERASE_LR:
2320 ret = opal_secure_erase_locking_range(dev, p);
2321 break;
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002322 case IOC_OPAL_PSID_REVERT_TPR:
2323 ret = opal_reverttper(dev, p, true);
2324 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002325 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06002326 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002327 }
Scott Bauere225c202017-02-14 17:29:36 -07002328
2329 kfree(p);
2330 return ret;
Scott Bauer455a7b22017-02-03 12:50:31 -07002331}
2332EXPORT_SYMBOL_GPL(sed_ioctl);