blob: b1aa0cc25803092a5dffff49469661dcf92ca3b3 [file] [log] [blame]
Scott Bauer455a7b22017-02-03 12:50:31 -07001/*
2 * Copyright © 2016 Intel Corporation
3 *
4 * Authors:
5 * Scott Bauer <scott.bauer@intel.com>
6 * Rafael Antognolli <rafael.antognolli@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 */
17
18#define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt
19
20#include <linux/delay.h>
21#include <linux/device.h>
22#include <linux/kernel.h>
23#include <linux/list.h>
24#include <linux/genhd.h>
25#include <linux/slab.h>
26#include <linux/uaccess.h>
27#include <uapi/linux/sed-opal.h>
28#include <linux/sed-opal.h>
29#include <linux/string.h>
30#include <linux/kdev_t.h>
31
32#include "opal_proto.h"
33
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010034#define IO_BUFFER_LENGTH 2048
35#define MAX_TOKS 64
36
Jon Derrickeed64952017-02-22 07:55:13 -070037struct opal_step {
38 int (*fn)(struct opal_dev *dev, void *data);
39 void *data;
40};
41typedef int (cont_fn)(struct opal_dev *dev);
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010042
43enum opal_atom_width {
44 OPAL_WIDTH_TINY,
45 OPAL_WIDTH_SHORT,
46 OPAL_WIDTH_MEDIUM,
47 OPAL_WIDTH_LONG,
48 OPAL_WIDTH_TOKEN
49};
50
51/*
52 * On the parsed response, we don't store again the toks that are already
53 * stored in the response buffer. Instead, for each token, we just store a
54 * pointer to the position in the buffer where the token starts, and the size
55 * of the token in bytes.
56 */
57struct opal_resp_tok {
58 const u8 *pos;
59 size_t len;
60 enum opal_response_token type;
61 enum opal_atom_width width;
62 union {
63 u64 u;
64 s64 s;
65 } stored;
66};
67
68/*
69 * From the response header it's not possible to know how many tokens there are
70 * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
71 * if we start dealing with messages that have more than that, we can increase
72 * this number. This is done to avoid having to make two passes through the
73 * response, the first one counting how many tokens we have and the second one
74 * actually storing the positions.
75 */
76struct parsed_resp {
77 int num;
78 struct opal_resp_tok toks[MAX_TOKS];
79};
80
81struct opal_dev {
82 bool supported;
Scott Bauerdbec491b2017-09-01 08:53:35 -060083 bool mbr_enabled;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010084
85 void *data;
86 sec_send_recv *send_recv;
87
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010088 struct mutex dev_lock;
89 u16 comid;
90 u32 hsn;
91 u32 tsn;
92 u64 align;
93 u64 lowest_lba;
94
95 size_t pos;
96 u8 cmd[IO_BUFFER_LENGTH];
97 u8 resp[IO_BUFFER_LENGTH];
98
99 struct parsed_resp parsed;
100 size_t prev_d_len;
101 void *prev_data;
102
103 struct list_head unlk_lst;
104};
105
106
Scott Bauer455a7b22017-02-03 12:50:31 -0700107static const u8 opaluid[][OPAL_UID_LENGTH] = {
108 /* users */
109 [OPAL_SMUID_UID] =
110 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
111 [OPAL_THISSP_UID] =
112 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
113 [OPAL_ADMINSP_UID] =
114 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
115 [OPAL_LOCKINGSP_UID] =
116 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
117 [OPAL_ENTERPRISE_LOCKINGSP_UID] =
118 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
119 [OPAL_ANYBODY_UID] =
120 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
121 [OPAL_SID_UID] =
122 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
123 [OPAL_ADMIN1_UID] =
124 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
125 [OPAL_USER1_UID] =
126 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
127 [OPAL_USER2_UID] =
128 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
129 [OPAL_PSID_UID] =
130 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
131 [OPAL_ENTERPRISE_BANDMASTER0_UID] =
132 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
133 [OPAL_ENTERPRISE_ERASEMASTER_UID] =
134 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
135
136 /* tables */
137
138 [OPAL_LOCKINGRANGE_GLOBAL] =
139 { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
140 [OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
141 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
142 [OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
143 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
144 [OPAL_MBRCONTROL] =
145 { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
146 [OPAL_MBR] =
147 { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
148 [OPAL_AUTHORITY_TABLE] =
149 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
150 [OPAL_C_PIN_TABLE] =
151 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
152 [OPAL_LOCKING_INFO_TABLE] =
153 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
154 [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
155 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
156
157 /* C_PIN_TABLE object ID's */
158
David Kozub1e815b32019-02-14 01:15:54 +0100159 [OPAL_C_PIN_MSID] =
Scott Bauer455a7b22017-02-03 12:50:31 -0700160 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
161 [OPAL_C_PIN_SID] =
162 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
163 [OPAL_C_PIN_ADMIN1] =
164 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
165
166 /* half UID's (only first 4 bytes used) */
167
168 [OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
169 { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
170 [OPAL_HALF_UID_BOOLEAN_ACE] =
171 { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
172
173 /* special value for omitted optional parameter */
174 [OPAL_UID_HEXFF] =
175 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
176};
177
178/*
179 * TCG Storage SSC Methods.
180 * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
181 * Section: 6.3 Assigned UIDs
182 */
Jonas Rabenstein1b6b75b2019-02-14 01:15:55 +0100183static const u8 opalmethod[][OPAL_METHOD_LENGTH] = {
Scott Bauer455a7b22017-02-03 12:50:31 -0700184 [OPAL_PROPERTIES] =
185 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
186 [OPAL_STARTSESSION] =
187 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
188 [OPAL_REVERT] =
189 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
190 [OPAL_ACTIVATE] =
191 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
192 [OPAL_EGET] =
193 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
194 [OPAL_ESET] =
195 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
196 [OPAL_NEXT] =
197 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
198 [OPAL_EAUTHENTICATE] =
199 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
200 [OPAL_GETACL] =
201 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
202 [OPAL_GENKEY] =
203 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
204 [OPAL_REVERTSP] =
205 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
206 [OPAL_GET] =
207 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
208 [OPAL_SET] =
209 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
210 [OPAL_AUTHENTICATE] =
211 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
212 [OPAL_RANDOM] =
213 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
214 [OPAL_ERASE] =
215 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
216};
217
Scott Bauer455a7b22017-02-03 12:50:31 -0700218static int end_opal_session_error(struct opal_dev *dev);
David Kozub0af26482019-02-14 01:16:07 +0100219static int opal_discovery0_step(struct opal_dev *dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700220
221struct opal_suspend_data {
222 struct opal_lock_unlock unlk;
223 u8 lr;
224 struct list_head node;
225};
226
227/*
228 * Derived from:
229 * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
230 * Section: 5.1.5 Method Status Codes
231 */
232static const char * const opal_errors[] = {
233 "Success",
234 "Not Authorized",
235 "Unknown Error",
236 "SP Busy",
237 "SP Failed",
238 "SP Disabled",
239 "SP Frozen",
240 "No Sessions Available",
241 "Uniqueness Conflict",
242 "Insufficient Space",
243 "Insufficient Rows",
244 "Invalid Function",
245 "Invalid Parameter",
246 "Invalid Reference",
247 "Unknown Error",
248 "TPER Malfunction",
249 "Transaction Failure",
250 "Response Overflow",
251 "Authority Locked Out",
252};
253
254static const char *opal_error_to_human(int error)
255{
256 if (error == 0x3f)
257 return "Failed";
258
259 if (error >= ARRAY_SIZE(opal_errors) || error < 0)
260 return "Unknown Error";
261
262 return opal_errors[error];
263}
264
265static void print_buffer(const u8 *ptr, u32 length)
266{
267#ifdef DEBUG
268 print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
269 pr_debug("\n");
270#endif
271}
272
273static bool check_tper(const void *data)
274{
275 const struct d0_tper_features *tper = data;
276 u8 flags = tper->supported_features;
277
278 if (!(flags & TPER_SYNC_SUPPORTED)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600279 pr_debug("TPer sync not supported. flags = %d\n",
280 tper->supported_features);
Scott Bauer455a7b22017-02-03 12:50:31 -0700281 return false;
282 }
283
284 return true;
285}
286
Scott Bauerdbec491b2017-09-01 08:53:35 -0600287static bool check_mbrenabled(const void *data)
288{
289 const struct d0_locking_features *lfeat = data;
290 u8 sup_feat = lfeat->supported_features;
291
292 return !!(sup_feat & MBR_ENABLED_MASK);
293}
294
Scott Bauer455a7b22017-02-03 12:50:31 -0700295static bool check_sum(const void *data)
296{
297 const struct d0_single_user_mode *sum = data;
298 u32 nlo = be32_to_cpu(sum->num_locking_objects);
299
300 if (nlo == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600301 pr_debug("Need at least one locking object.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700302 return false;
303 }
304
305 pr_debug("Number of locking objects: %d\n", nlo);
306
307 return true;
308}
309
310static u16 get_comid_v100(const void *data)
311{
312 const struct d0_opal_v100 *v100 = data;
313
314 return be16_to_cpu(v100->baseComID);
315}
316
317static u16 get_comid_v200(const void *data)
318{
319 const struct d0_opal_v200 *v200 = data;
320
321 return be16_to_cpu(v200->baseComID);
322}
323
324static int opal_send_cmd(struct opal_dev *dev)
325{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100326 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700327 dev->cmd, IO_BUFFER_LENGTH,
328 true);
329}
330
331static int opal_recv_cmd(struct opal_dev *dev)
332{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100333 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700334 dev->resp, IO_BUFFER_LENGTH,
335 false);
336}
337
338static int opal_recv_check(struct opal_dev *dev)
339{
340 size_t buflen = IO_BUFFER_LENGTH;
341 void *buffer = dev->resp;
342 struct opal_header *hdr = buffer;
343 int ret;
344
345 do {
346 pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
347 hdr->cp.outstandingData,
348 hdr->cp.minTransfer);
349
350 if (hdr->cp.outstandingData == 0 ||
351 hdr->cp.minTransfer != 0)
352 return 0;
353
354 memset(buffer, 0, buflen);
355 ret = opal_recv_cmd(dev);
356 } while (!ret);
357
358 return ret;
359}
360
361static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
362{
363 int ret;
364
365 ret = opal_send_cmd(dev);
366 if (ret)
367 return ret;
368 ret = opal_recv_cmd(dev);
369 if (ret)
370 return ret;
371 ret = opal_recv_check(dev);
372 if (ret)
373 return ret;
374 return cont(dev);
375}
376
377static void check_geometry(struct opal_dev *dev, const void *data)
378{
379 const struct d0_geometry_features *geo = data;
380
381 dev->align = geo->alignment_granularity;
382 dev->lowest_lba = geo->lowest_aligned_lba;
383}
384
David Kozub0af26482019-02-14 01:16:07 +0100385static int execute_step(struct opal_dev *dev,
386 const struct opal_step *step, size_t stepIndex)
387{
388 int error = step->fn(dev, step->data);
389
390 if (error) {
391 pr_debug("Step %zu (%pS) failed with error %d: %s\n",
392 stepIndex, step->fn, error,
393 opal_error_to_human(error));
394 }
395
396 return error;
397}
398
David Kozuba80f36c2019-02-14 01:16:08 +0100399static int execute_steps(struct opal_dev *dev,
400 const struct opal_step *steps, size_t n_steps)
Scott Bauer455a7b22017-02-03 12:50:31 -0700401{
David Kozub0af26482019-02-14 01:16:07 +0100402 size_t state = 0;
403 int error;
404
405 /* first do a discovery0 */
406 error = opal_discovery0_step(dev);
407 if (error)
408 return error;
Scott Bauer455a7b22017-02-03 12:50:31 -0700409
David Kozub3db87232019-02-14 01:16:06 +0100410 for (state = 0; state < n_steps; state++) {
David Kozub0af26482019-02-14 01:16:07 +0100411 error = execute_step(dev, &steps[state], state);
David Kozub3db87232019-02-14 01:16:06 +0100412 if (error)
413 goto out_error;
414 }
Scott Bauer455a7b22017-02-03 12:50:31 -0700415
David Kozub3db87232019-02-14 01:16:06 +0100416 return 0;
Scott Bauer2d190202017-02-22 10:15:08 -0700417
David Kozub3db87232019-02-14 01:16:06 +0100418out_error:
419 /*
David Kozub0af26482019-02-14 01:16:07 +0100420 * For each OPAL command the first step in steps starts some sort of
421 * session. If an error occurred in the initial discovery0 or if an
422 * error occurred in the first step (and thus stopping the loop with
423 * state == 0) then there was an error before or during the attempt to
424 * start a session. Therefore we shouldn't attempt to terminate a
425 * session, as one has not yet been created.
David Kozub3db87232019-02-14 01:16:06 +0100426 */
David Kozub0af26482019-02-14 01:16:07 +0100427 if (state > 0)
David Kozub3db87232019-02-14 01:16:06 +0100428 end_opal_session_error(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700429
430 return error;
431}
432
433static int opal_discovery0_end(struct opal_dev *dev)
434{
435 bool found_com_id = false, supported = true, single_user = false;
436 const struct d0_header *hdr = (struct d0_header *)dev->resp;
437 const u8 *epos = dev->resp, *cpos = dev->resp;
438 u16 comid = 0;
Jon Derrick77039b92017-02-21 11:59:15 -0700439 u32 hlen = be32_to_cpu(hdr->length);
Scott Bauer455a7b22017-02-03 12:50:31 -0700440
Jon Derrick77039b92017-02-21 11:59:15 -0700441 print_buffer(dev->resp, hlen);
Scott Bauerdbec491b2017-09-01 08:53:35 -0600442 dev->mbr_enabled = false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700443
Jon Derrick77039b92017-02-21 11:59:15 -0700444 if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600445 pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
446 sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
Jon Derrick77039b92017-02-21 11:59:15 -0700447 return -EFAULT;
448 }
449
450 epos += hlen; /* end of buffer */
Scott Bauer455a7b22017-02-03 12:50:31 -0700451 cpos += sizeof(*hdr); /* current position on buffer */
452
453 while (cpos < epos && supported) {
454 const struct d0_features *body =
455 (const struct d0_features *)cpos;
456
457 switch (be16_to_cpu(body->code)) {
458 case FC_TPER:
459 supported = check_tper(body->features);
460 break;
461 case FC_SINGLEUSER:
462 single_user = check_sum(body->features);
463 break;
464 case FC_GEOMETRY:
465 check_geometry(dev, body);
466 break;
467 case FC_LOCKING:
Scott Bauerdbec491b2017-09-01 08:53:35 -0600468 dev->mbr_enabled = check_mbrenabled(body->features);
469 break;
Scott Bauer455a7b22017-02-03 12:50:31 -0700470 case FC_ENTERPRISE:
471 case FC_DATASTORE:
472 /* some ignored properties */
473 pr_debug("Found OPAL feature description: %d\n",
474 be16_to_cpu(body->code));
475 break;
476 case FC_OPALV100:
477 comid = get_comid_v100(body->features);
478 found_com_id = true;
479 break;
480 case FC_OPALV200:
481 comid = get_comid_v200(body->features);
482 found_com_id = true;
483 break;
484 case 0xbfff ... 0xffff:
485 /* vendor specific, just ignore */
486 break;
487 default:
488 pr_debug("OPAL Unknown feature: %d\n",
489 be16_to_cpu(body->code));
490
491 }
492 cpos += body->length + 4;
493 }
494
495 if (!supported) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100496 pr_debug("This device is not Opal enabled. Not Supported!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700497 return -EOPNOTSUPP;
498 }
499
500 if (!single_user)
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100501 pr_debug("Device doesn't support single user mode\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700502
503
504 if (!found_com_id) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100505 pr_debug("Could not find OPAL comid for device. Returning early\n");
Ingo Molnared7158b2018-02-22 10:54:55 +0100506 return -EOPNOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -0700507 }
508
509 dev->comid = comid;
510
511 return 0;
512}
513
Jon Derrickeed64952017-02-22 07:55:13 -0700514static int opal_discovery0(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -0700515{
516 int ret;
517
518 memset(dev->resp, 0, IO_BUFFER_LENGTH);
519 dev->comid = OPAL_DISCOVERY_COMID;
520 ret = opal_recv_cmd(dev);
521 if (ret)
522 return ret;
523 return opal_discovery0_end(dev);
524}
525
David Kozub0af26482019-02-14 01:16:07 +0100526static int opal_discovery0_step(struct opal_dev *dev)
527{
528 const struct opal_step discovery0_step = {
529 opal_discovery0,
530 };
531 return execute_step(dev, &discovery0_step, 0);
532}
533
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100534static bool can_add(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700535{
536 if (*err)
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100537 return false;
538
539 if (len > IO_BUFFER_LENGTH || cmd->pos > IO_BUFFER_LENGTH - len) {
540 pr_debug("Error adding %zu bytes: end of buffer.\n", len);
Scott Bauer455a7b22017-02-03 12:50:31 -0700541 *err = -ERANGE;
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100542 return false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700543 }
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100544
545 return true;
546}
547
548static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
549{
550 if (!can_add(err, cmd, 1))
551 return;
Scott Bauer455a7b22017-02-03 12:50:31 -0700552 cmd->cmd[cmd->pos++] = tok;
553}
554
555static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
556 bool has_sign, int len)
557{
558 u8 atom;
559 int err = 0;
560
561 atom = SHORT_ATOM_ID;
562 atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
563 atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
564 atom |= len & SHORT_ATOM_LEN_MASK;
565
566 add_token_u8(&err, cmd, atom);
567}
568
569static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
570 bool has_sign, int len)
571{
572 u8 header0;
573
574 header0 = MEDIUM_ATOM_ID;
575 header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
576 header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
577 header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
578 cmd->cmd[cmd->pos++] = header0;
579 cmd->cmd[cmd->pos++] = len;
580}
581
582static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
583{
Scott Bauer455a7b22017-02-03 12:50:31 -0700584 size_t len;
585 int msb;
Scott Bauer455a7b22017-02-03 12:50:31 -0700586
587 if (!(number & ~TINY_ATOM_DATA_MASK)) {
588 add_token_u8(err, cmd, number);
589 return;
590 }
591
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100592 msb = fls64(number);
593 len = DIV_ROUND_UP(msb, 8);
Scott Bauer455a7b22017-02-03 12:50:31 -0700594
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100595 if (!can_add(err, cmd, len + 1)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600596 pr_debug("Error adding u64: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700597 return;
598 }
599 add_short_atom_header(cmd, false, false, len);
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100600 while (len--)
601 add_token_u8(err, cmd, number >> (len * 8));
Scott Bauer455a7b22017-02-03 12:50:31 -0700602}
603
Jonas Rabenstein28559952019-02-14 01:16:02 +0100604static u8 *add_bytestring_header(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700605{
606 size_t header_len = 1;
607 bool is_short_atom = true;
608
Scott Bauer455a7b22017-02-03 12:50:31 -0700609 if (len & ~SHORT_ATOM_LEN_MASK) {
610 header_len = 2;
611 is_short_atom = false;
612 }
613
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100614 if (!can_add(err, cmd, header_len + len)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600615 pr_debug("Error adding bytestring: end of buffer.\n");
Jonas Rabenstein28559952019-02-14 01:16:02 +0100616 return NULL;
Scott Bauer455a7b22017-02-03 12:50:31 -0700617 }
618
619 if (is_short_atom)
620 add_short_atom_header(cmd, true, false, len);
621 else
622 add_medium_atom_header(cmd, true, false, len);
623
Jonas Rabenstein28559952019-02-14 01:16:02 +0100624 return &cmd->cmd[cmd->pos];
625}
Scott Bauer455a7b22017-02-03 12:50:31 -0700626
Jonas Rabenstein28559952019-02-14 01:16:02 +0100627static void add_token_bytestring(int *err, struct opal_dev *cmd,
628 const u8 *bytestring, size_t len)
629{
630 u8 *start;
631
632 start = add_bytestring_header(err, cmd, len);
633 if (!start)
634 return;
635 memcpy(start, bytestring, len);
636 cmd->pos += len;
Scott Bauer455a7b22017-02-03 12:50:31 -0700637}
638
639static int build_locking_range(u8 *buffer, size_t length, u8 lr)
640{
641 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600642 pr_debug("Can't build locking range. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700643 return -ERANGE;
644 }
645
646 memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
647
648 if (lr == 0)
649 return 0;
650 buffer[5] = LOCKING_RANGE_NON_GLOBAL;
651 buffer[7] = lr;
652
653 return 0;
654}
655
656static int build_locking_user(u8 *buffer, size_t length, u8 lr)
657{
658 if (length > OPAL_UID_LENGTH) {
David Kozub1e815b32019-02-14 01:15:54 +0100659 pr_debug("Can't build locking range user. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700660 return -ERANGE;
661 }
662
663 memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
664
665 buffer[7] = lr + 1;
666
667 return 0;
668}
669
670static void set_comid(struct opal_dev *cmd, u16 comid)
671{
672 struct opal_header *hdr = (struct opal_header *)cmd->cmd;
673
674 hdr->cp.extendedComID[0] = comid >> 8;
675 hdr->cp.extendedComID[1] = comid;
676 hdr->cp.extendedComID[2] = 0;
677 hdr->cp.extendedComID[3] = 0;
678}
679
680static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
681{
682 struct opal_header *hdr;
683 int err = 0;
684
David Kozube8b29222019-02-14 01:15:58 +0100685 /* close the parameter list opened from cmd_start */
David Kozub78d584c2019-02-14 01:15:57 +0100686 add_token_u8(&err, cmd, OPAL_ENDLIST);
687
Scott Bauer455a7b22017-02-03 12:50:31 -0700688 add_token_u8(&err, cmd, OPAL_ENDOFDATA);
689 add_token_u8(&err, cmd, OPAL_STARTLIST);
690 add_token_u8(&err, cmd, 0);
691 add_token_u8(&err, cmd, 0);
692 add_token_u8(&err, cmd, 0);
693 add_token_u8(&err, cmd, OPAL_ENDLIST);
694
695 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600696 pr_debug("Error finalizing command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700697 return -EFAULT;
698 }
699
700 hdr = (struct opal_header *) cmd->cmd;
701
702 hdr->pkt.tsn = cpu_to_be32(tsn);
703 hdr->pkt.hsn = cpu_to_be32(hsn);
704
705 hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
706 while (cmd->pos % 4) {
707 if (cmd->pos >= IO_BUFFER_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600708 pr_debug("Error: Buffer overrun\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700709 return -ERANGE;
710 }
711 cmd->cmd[cmd->pos++] = 0;
712 }
713 hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
714 sizeof(hdr->pkt));
715 hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
716
717 return 0;
718}
719
Jon Derrickcccb9242017-02-21 11:59:14 -0700720static const struct opal_resp_tok *response_get_token(
721 const struct parsed_resp *resp,
722 int n)
Scott Bauer455a7b22017-02-03 12:50:31 -0700723{
724 const struct opal_resp_tok *tok;
725
David Kozub7d9b62a2019-02-14 01:15:59 +0100726 if (!resp) {
727 pr_debug("Response is NULL\n");
728 return ERR_PTR(-EINVAL);
729 }
730
Scott Bauer455a7b22017-02-03 12:50:31 -0700731 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600732 pr_debug("Token number doesn't exist: %d, resp: %d\n",
733 n, resp->num);
Jon Derrickcccb9242017-02-21 11:59:14 -0700734 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700735 }
736
737 tok = &resp->toks[n];
738 if (tok->len == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600739 pr_debug("Token length must be non-zero\n");
Jon Derrickcccb9242017-02-21 11:59:14 -0700740 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700741 }
742
Jon Derrickcccb9242017-02-21 11:59:14 -0700743 return tok;
Scott Bauer455a7b22017-02-03 12:50:31 -0700744}
745
Jon Derrickaedb6e22017-02-21 11:59:13 -0700746static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
747 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700748{
749 tok->pos = pos;
750 tok->len = 1;
751 tok->width = OPAL_WIDTH_TINY;
752
753 if (pos[0] & TINY_ATOM_SIGNED) {
754 tok->type = OPAL_DTA_TOKENID_SINT;
755 } else {
756 tok->type = OPAL_DTA_TOKENID_UINT;
757 tok->stored.u = pos[0] & 0x3f;
758 }
759
760 return tok->len;
761}
762
Jon Derrickaedb6e22017-02-21 11:59:13 -0700763static ssize_t response_parse_short(struct opal_resp_tok *tok,
764 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700765{
766 tok->pos = pos;
767 tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
768 tok->width = OPAL_WIDTH_SHORT;
769
770 if (pos[0] & SHORT_ATOM_BYTESTRING) {
771 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
772 } else if (pos[0] & SHORT_ATOM_SIGNED) {
773 tok->type = OPAL_DTA_TOKENID_SINT;
774 } else {
775 u64 u_integer = 0;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700776 ssize_t i, b = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700777
778 tok->type = OPAL_DTA_TOKENID_UINT;
779 if (tok->len > 9) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600780 pr_debug("uint64 with more than 8 bytes\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700781 return -EINVAL;
782 }
783 for (i = tok->len - 1; i > 0; i--) {
784 u_integer |= ((u64)pos[i] << (8 * b));
785 b++;
786 }
787 tok->stored.u = u_integer;
788 }
789
790 return tok->len;
791}
792
Jon Derrickaedb6e22017-02-21 11:59:13 -0700793static ssize_t response_parse_medium(struct opal_resp_tok *tok,
794 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700795{
796 tok->pos = pos;
797 tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
798 tok->width = OPAL_WIDTH_MEDIUM;
799
800 if (pos[0] & MEDIUM_ATOM_BYTESTRING)
801 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
802 else if (pos[0] & MEDIUM_ATOM_SIGNED)
803 tok->type = OPAL_DTA_TOKENID_SINT;
804 else
805 tok->type = OPAL_DTA_TOKENID_UINT;
806
807 return tok->len;
808}
809
Jon Derrickaedb6e22017-02-21 11:59:13 -0700810static ssize_t response_parse_long(struct opal_resp_tok *tok,
811 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700812{
813 tok->pos = pos;
814 tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
815 tok->width = OPAL_WIDTH_LONG;
816
817 if (pos[0] & LONG_ATOM_BYTESTRING)
818 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
819 else if (pos[0] & LONG_ATOM_SIGNED)
820 tok->type = OPAL_DTA_TOKENID_SINT;
821 else
822 tok->type = OPAL_DTA_TOKENID_UINT;
823
824 return tok->len;
825}
826
Jon Derrickaedb6e22017-02-21 11:59:13 -0700827static ssize_t response_parse_token(struct opal_resp_tok *tok,
828 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700829{
830 tok->pos = pos;
831 tok->len = 1;
832 tok->type = OPAL_DTA_TOKENID_TOKEN;
833 tok->width = OPAL_WIDTH_TOKEN;
834
835 return tok->len;
836}
837
838static int response_parse(const u8 *buf, size_t length,
839 struct parsed_resp *resp)
840{
841 const struct opal_header *hdr;
842 struct opal_resp_tok *iter;
843 int num_entries = 0;
844 int total;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700845 ssize_t token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700846 const u8 *pos;
Jon Derrick77039b92017-02-21 11:59:15 -0700847 u32 clen, plen, slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700848
849 if (!buf)
850 return -EFAULT;
851
852 if (!resp)
853 return -EFAULT;
854
855 hdr = (struct opal_header *)buf;
856 pos = buf;
857 pos += sizeof(*hdr);
858
Jon Derrick77039b92017-02-21 11:59:15 -0700859 clen = be32_to_cpu(hdr->cp.length);
860 plen = be32_to_cpu(hdr->pkt.length);
861 slen = be32_to_cpu(hdr->subpkt.length);
862 pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
863 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700864
Jon Derrick77039b92017-02-21 11:59:15 -0700865 if (clen == 0 || plen == 0 || slen == 0 ||
866 slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600867 pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
868 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700869 print_buffer(pos, sizeof(*hdr));
870 return -EINVAL;
871 }
872
873 if (pos > buf + length)
874 return -EFAULT;
875
876 iter = resp->toks;
Jon Derrick77039b92017-02-21 11:59:15 -0700877 total = slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700878 print_buffer(pos, total);
879 while (total > 0) {
880 if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
881 token_length = response_parse_tiny(iter, pos);
882 else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
883 token_length = response_parse_short(iter, pos);
884 else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
885 token_length = response_parse_medium(iter, pos);
886 else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
887 token_length = response_parse_long(iter, pos);
888 else /* TOKEN */
889 token_length = response_parse_token(iter, pos);
890
Jon Derrickaedb6e22017-02-21 11:59:13 -0700891 if (token_length < 0)
892 return token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700893
894 pos += token_length;
895 total -= token_length;
896 iter++;
897 num_entries++;
898 }
899
900 if (num_entries == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600901 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700902 return -EINVAL;
903 }
904 resp->num = num_entries;
905
906 return 0;
907}
908
909static size_t response_get_string(const struct parsed_resp *resp, int n,
910 const char **store)
911{
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100912 u8 skip;
David Kozubb68f09e2019-02-14 01:16:00 +0100913 const struct opal_resp_tok *tok;
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100914
Scott Bauer455a7b22017-02-03 12:50:31 -0700915 *store = NULL;
David Kozubb68f09e2019-02-14 01:16:00 +0100916 tok = response_get_token(resp, n);
917 if (IS_ERR(tok))
Scott Bauer455a7b22017-02-03 12:50:31 -0700918 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700919
David Kozubb68f09e2019-02-14 01:16:00 +0100920 if (tok->type != OPAL_DTA_TOKENID_BYTESTRING) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600921 pr_debug("Token is not a byte string!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700922 return 0;
923 }
924
David Kozubb68f09e2019-02-14 01:16:00 +0100925 switch (tok->width) {
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100926 case OPAL_WIDTH_TINY:
927 case OPAL_WIDTH_SHORT:
928 skip = 1;
929 break;
930 case OPAL_WIDTH_MEDIUM:
931 skip = 2;
932 break;
933 case OPAL_WIDTH_LONG:
934 skip = 4;
935 break;
936 default:
937 pr_debug("Token has invalid width!\n");
938 return 0;
939 }
940
David Kozubb68f09e2019-02-14 01:16:00 +0100941 *store = tok->pos + skip;
942 return tok->len - skip;
Scott Bauer455a7b22017-02-03 12:50:31 -0700943}
944
945static u64 response_get_u64(const struct parsed_resp *resp, int n)
946{
David Kozubb68f09e2019-02-14 01:16:00 +0100947 const struct opal_resp_tok *tok;
948
949 tok = response_get_token(resp, n);
950 if (IS_ERR(tok))
951 return 0;
952
953 if (tok->type != OPAL_DTA_TOKENID_UINT) {
954 pr_debug("Token is not unsigned int: %d\n", tok->type);
Scott Bauer455a7b22017-02-03 12:50:31 -0700955 return 0;
956 }
957
David Kozubb68f09e2019-02-14 01:16:00 +0100958 if (tok->width != OPAL_WIDTH_TINY && tok->width != OPAL_WIDTH_SHORT) {
959 pr_debug("Atom is not short or tiny: %d\n", tok->width);
Scott Bauer455a7b22017-02-03 12:50:31 -0700960 return 0;
961 }
962
David Kozubb68f09e2019-02-14 01:16:00 +0100963 return tok->stored.u;
Scott Bauer455a7b22017-02-03 12:50:31 -0700964}
965
Jon Derrickcccb9242017-02-21 11:59:14 -0700966static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
967{
968 if (IS_ERR(token) ||
969 token->type != OPAL_DTA_TOKENID_TOKEN ||
970 token->pos[0] != match)
971 return false;
972 return true;
973}
974
Scott Bauer455a7b22017-02-03 12:50:31 -0700975static u8 response_status(const struct parsed_resp *resp)
976{
Jon Derrickcccb9242017-02-21 11:59:14 -0700977 const struct opal_resp_tok *tok;
978
979 tok = response_get_token(resp, 0);
980 if (response_token_matches(tok, OPAL_ENDOFSESSION))
Scott Bauer455a7b22017-02-03 12:50:31 -0700981 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700982
983 if (resp->num < 5)
984 return DTAERROR_NO_METHOD_STATUS;
985
Jon Derrickcccb9242017-02-21 11:59:14 -0700986 tok = response_get_token(resp, resp->num - 5);
987 if (!response_token_matches(tok, OPAL_STARTLIST))
988 return DTAERROR_NO_METHOD_STATUS;
989
990 tok = response_get_token(resp, resp->num - 1);
991 if (!response_token_matches(tok, OPAL_ENDLIST))
Scott Bauer455a7b22017-02-03 12:50:31 -0700992 return DTAERROR_NO_METHOD_STATUS;
993
994 return response_get_u64(resp, resp->num - 4);
995}
996
997/* Parses and checks for errors */
998static int parse_and_check_status(struct opal_dev *dev)
999{
1000 int error;
1001
1002 print_buffer(dev->cmd, dev->pos);
1003
1004 error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
1005 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001006 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001007 return error;
1008 }
1009
1010 return response_status(&dev->parsed);
1011}
1012
1013static void clear_opal_cmd(struct opal_dev *dev)
1014{
1015 dev->pos = sizeof(struct opal_header);
1016 memset(dev->cmd, 0, IO_BUFFER_LENGTH);
1017}
1018
David Kozube8b29222019-02-14 01:15:58 +01001019static int cmd_start(struct opal_dev *dev, const u8 *uid, const u8 *method)
1020{
1021 int err = 0;
1022
1023 clear_opal_cmd(dev);
1024 set_comid(dev, dev->comid);
1025
1026 add_token_u8(&err, dev, OPAL_CALL);
1027 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1028 add_token_bytestring(&err, dev, method, OPAL_METHOD_LENGTH);
1029
1030 /*
1031 * Every method call is followed by its parameters enclosed within
1032 * OPAL_STARTLIST and OPAL_ENDLIST tokens. We automatically open the
1033 * parameter list here and close it later in cmd_finalize.
1034 */
1035 add_token_u8(&err, dev, OPAL_STARTLIST);
1036
1037 return err;
1038}
1039
Scott Bauer455a7b22017-02-03 12:50:31 -07001040static int start_opal_session_cont(struct opal_dev *dev)
1041{
1042 u32 hsn, tsn;
1043 int error = 0;
1044
1045 error = parse_and_check_status(dev);
1046 if (error)
1047 return error;
1048
1049 hsn = response_get_u64(&dev->parsed, 4);
1050 tsn = response_get_u64(&dev->parsed, 5);
1051
1052 if (hsn == 0 && tsn == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001053 pr_debug("Couldn't authenticate session\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001054 return -EPERM;
1055 }
1056
1057 dev->hsn = hsn;
1058 dev->tsn = tsn;
1059 return 0;
1060}
1061
1062static void add_suspend_info(struct opal_dev *dev,
1063 struct opal_suspend_data *sus)
1064{
1065 struct opal_suspend_data *iter;
1066
1067 list_for_each_entry(iter, &dev->unlk_lst, node) {
1068 if (iter->lr == sus->lr) {
1069 list_del(&iter->node);
1070 kfree(iter);
1071 break;
1072 }
1073 }
1074 list_add_tail(&sus->node, &dev->unlk_lst);
1075}
1076
1077static int end_session_cont(struct opal_dev *dev)
1078{
1079 dev->hsn = 0;
1080 dev->tsn = 0;
1081 return parse_and_check_status(dev);
1082}
1083
1084static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1085{
1086 int ret;
1087
1088 ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1089 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001090 pr_debug("Error finalizing command buffer: %d\n", ret);
Scott Bauer455a7b22017-02-03 12:50:31 -07001091 return ret;
1092 }
1093
1094 print_buffer(dev->cmd, dev->pos);
1095
1096 return opal_send_recv(dev, cont);
1097}
1098
David Kozub3fff2342019-02-14 01:16:04 +01001099/*
1100 * request @column from table @table on device @dev. On success, the column
1101 * data will be available in dev->resp->tok[4]
1102 */
1103static int generic_get_column(struct opal_dev *dev, const u8 *table,
1104 u64 column)
1105{
1106 int err;
1107
1108 err = cmd_start(dev, table, opalmethod[OPAL_GET]);
1109
1110 add_token_u8(&err, dev, OPAL_STARTLIST);
1111
1112 add_token_u8(&err, dev, OPAL_STARTNAME);
1113 add_token_u8(&err, dev, OPAL_STARTCOLUMN);
1114 add_token_u64(&err, dev, column);
1115 add_token_u8(&err, dev, OPAL_ENDNAME);
1116
1117 add_token_u8(&err, dev, OPAL_STARTNAME);
1118 add_token_u8(&err, dev, OPAL_ENDCOLUMN);
1119 add_token_u64(&err, dev, column);
1120 add_token_u8(&err, dev, OPAL_ENDNAME);
1121
1122 add_token_u8(&err, dev, OPAL_ENDLIST);
1123
1124 if (err)
1125 return err;
1126
1127 return finalize_and_send(dev, parse_and_check_status);
1128}
1129
Jon Derrickeed64952017-02-22 07:55:13 -07001130static int gen_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001131{
Scott Bauer455a7b22017-02-03 12:50:31 -07001132 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001133 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001134
1135 memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
Scott Bauer455a7b22017-02-03 12:50:31 -07001136 kfree(dev->prev_data);
1137 dev->prev_data = NULL;
1138
David Kozube8b29222019-02-14 01:15:58 +01001139 err = cmd_start(dev, uid, opalmethod[OPAL_GENKEY]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001140
1141 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001142 pr_debug("Error building gen key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001143 return err;
1144
1145 }
1146 return finalize_and_send(dev, parse_and_check_status);
1147}
1148
1149static int get_active_key_cont(struct opal_dev *dev)
1150{
1151 const char *activekey;
1152 size_t keylen;
1153 int error = 0;
1154
1155 error = parse_and_check_status(dev);
1156 if (error)
1157 return error;
1158 keylen = response_get_string(&dev->parsed, 4, &activekey);
1159 if (!activekey) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001160 pr_debug("%s: Couldn't extract the Activekey from the response\n",
1161 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001162 return OPAL_INVAL_PARAM;
1163 }
1164 dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1165
1166 if (!dev->prev_data)
1167 return -ENOMEM;
1168
1169 dev->prev_d_len = keylen;
1170
1171 return 0;
1172}
1173
Jon Derrickeed64952017-02-22 07:55:13 -07001174static int get_active_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001175{
1176 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001177 int err;
Jon Derrickeed64952017-02-22 07:55:13 -07001178 u8 *lr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001179
Scott Bauer455a7b22017-02-03 12:50:31 -07001180 err = build_locking_range(uid, sizeof(uid), *lr);
1181 if (err)
1182 return err;
1183
David Kozub3fff2342019-02-14 01:16:04 +01001184 err = generic_get_column(dev, uid, OPAL_ACTIVEKEY);
1185 if (err)
Scott Bauer455a7b22017-02-03 12:50:31 -07001186 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001187
David Kozub3fff2342019-02-14 01:16:04 +01001188 return get_active_key_cont(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001189}
1190
1191static int generic_lr_enable_disable(struct opal_dev *dev,
1192 u8 *uid, bool rle, bool wle,
1193 bool rl, bool wl)
1194{
David Kozube8b29222019-02-14 01:15:58 +01001195 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001196
David Kozube8b29222019-02-14 01:15:58 +01001197 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001198
Scott Bauer455a7b22017-02-03 12:50:31 -07001199 add_token_u8(&err, dev, OPAL_STARTNAME);
1200 add_token_u8(&err, dev, OPAL_VALUES);
1201 add_token_u8(&err, dev, OPAL_STARTLIST);
1202
1203 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001204 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001205 add_token_u8(&err, dev, rle);
1206 add_token_u8(&err, dev, OPAL_ENDNAME);
1207
1208 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001209 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001210 add_token_u8(&err, dev, wle);
1211 add_token_u8(&err, dev, OPAL_ENDNAME);
1212
1213 add_token_u8(&err, dev, OPAL_STARTNAME);
1214 add_token_u8(&err, dev, OPAL_READLOCKED);
1215 add_token_u8(&err, dev, rl);
1216 add_token_u8(&err, dev, OPAL_ENDNAME);
1217
1218 add_token_u8(&err, dev, OPAL_STARTNAME);
1219 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1220 add_token_u8(&err, dev, wl);
1221 add_token_u8(&err, dev, OPAL_ENDNAME);
1222
1223 add_token_u8(&err, dev, OPAL_ENDLIST);
1224 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001225 return err;
1226}
1227
1228static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1229 struct opal_user_lr_setup *setup)
1230{
1231 int err;
1232
1233 err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1234 0, 0);
1235 if (err)
Scott Bauer591c59d2017-04-07 13:58:50 -06001236 pr_debug("Failed to create enable global lr command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001237 return err;
1238}
1239
Jon Derrickeed64952017-02-22 07:55:13 -07001240static int setup_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001241{
1242 u8 uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001243 struct opal_user_lr_setup *setup = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001244 u8 lr;
David Kozube8b29222019-02-14 01:15:58 +01001245 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001246
Scott Bauer455a7b22017-02-03 12:50:31 -07001247 lr = setup->session.opal_key.lr;
1248 err = build_locking_range(uid, sizeof(uid), lr);
1249 if (err)
1250 return err;
1251
1252 if (lr == 0)
1253 err = enable_global_lr(dev, uid, setup);
1254 else {
David Kozube8b29222019-02-14 01:15:58 +01001255 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001256
Scott Bauer455a7b22017-02-03 12:50:31 -07001257 add_token_u8(&err, dev, OPAL_STARTNAME);
1258 add_token_u8(&err, dev, OPAL_VALUES);
1259 add_token_u8(&err, dev, OPAL_STARTLIST);
1260
1261 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001262 add_token_u8(&err, dev, OPAL_RANGESTART);
Scott Bauer455a7b22017-02-03 12:50:31 -07001263 add_token_u64(&err, dev, setup->range_start);
1264 add_token_u8(&err, dev, OPAL_ENDNAME);
1265
1266 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001267 add_token_u8(&err, dev, OPAL_RANGELENGTH);
Scott Bauer455a7b22017-02-03 12:50:31 -07001268 add_token_u64(&err, dev, setup->range_length);
1269 add_token_u8(&err, dev, OPAL_ENDNAME);
1270
1271 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001272 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001273 add_token_u64(&err, dev, !!setup->RLE);
1274 add_token_u8(&err, dev, OPAL_ENDNAME);
1275
1276 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001277 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001278 add_token_u64(&err, dev, !!setup->WLE);
1279 add_token_u8(&err, dev, OPAL_ENDNAME);
1280
1281 add_token_u8(&err, dev, OPAL_ENDLIST);
1282 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001283 }
1284 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001285 pr_debug("Error building Setup Locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001286 return err;
1287
1288 }
1289
1290 return finalize_and_send(dev, parse_and_check_status);
1291}
1292
1293static int start_generic_opal_session(struct opal_dev *dev,
1294 enum opal_uid auth,
1295 enum opal_uid sp_type,
1296 const char *key,
1297 u8 key_len)
1298{
1299 u32 hsn;
David Kozube8b29222019-02-14 01:15:58 +01001300 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001301
Scott Bauer591c59d2017-04-07 13:58:50 -06001302 if (key == NULL && auth != OPAL_ANYBODY_UID)
Scott Bauer455a7b22017-02-03 12:50:31 -07001303 return OPAL_INVAL_PARAM;
Scott Bauer455a7b22017-02-03 12:50:31 -07001304
Scott Bauer455a7b22017-02-03 12:50:31 -07001305 hsn = GENERIC_HOST_SESSION_NUM;
David Kozube8b29222019-02-14 01:15:58 +01001306 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1307 opalmethod[OPAL_STARTSESSION]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001308
Scott Bauer455a7b22017-02-03 12:50:31 -07001309 add_token_u64(&err, dev, hsn);
1310 add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1311 add_token_u8(&err, dev, 1);
1312
1313 switch (auth) {
1314 case OPAL_ANYBODY_UID:
Scott Bauer455a7b22017-02-03 12:50:31 -07001315 break;
1316 case OPAL_ADMIN1_UID:
1317 case OPAL_SID_UID:
1318 add_token_u8(&err, dev, OPAL_STARTNAME);
1319 add_token_u8(&err, dev, 0); /* HostChallenge */
1320 add_token_bytestring(&err, dev, key, key_len);
1321 add_token_u8(&err, dev, OPAL_ENDNAME);
1322 add_token_u8(&err, dev, OPAL_STARTNAME);
1323 add_token_u8(&err, dev, 3); /* HostSignAuth */
1324 add_token_bytestring(&err, dev, opaluid[auth],
1325 OPAL_UID_LENGTH);
1326 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001327 break;
1328 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001329 pr_debug("Cannot start Admin SP session with auth %d\n", auth);
Scott Bauer455a7b22017-02-03 12:50:31 -07001330 return OPAL_INVAL_PARAM;
1331 }
1332
1333 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001334 pr_debug("Error building start adminsp session command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001335 return err;
1336 }
1337
1338 return finalize_and_send(dev, start_opal_session_cont);
1339}
1340
Jon Derrickeed64952017-02-22 07:55:13 -07001341static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001342{
1343 return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1344 OPAL_ADMINSP_UID, NULL, 0);
1345}
1346
Jon Derrickeed64952017-02-22 07:55:13 -07001347static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001348{
1349 int ret;
1350 const u8 *key = dev->prev_data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001351
1352 if (!key) {
Jon Derrickeed64952017-02-22 07:55:13 -07001353 const struct opal_key *okey = data;
David Kozub1e815b32019-02-14 01:15:54 +01001354
Scott Bauer455a7b22017-02-03 12:50:31 -07001355 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1356 OPAL_ADMINSP_UID,
1357 okey->key,
1358 okey->key_len);
1359 } else {
1360 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1361 OPAL_ADMINSP_UID,
1362 key, dev->prev_d_len);
1363 kfree(key);
1364 dev->prev_data = NULL;
1365 }
1366 return ret;
1367}
1368
Jon Derrickeed64952017-02-22 07:55:13 -07001369static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001370{
Jon Derrickeed64952017-02-22 07:55:13 -07001371 struct opal_key *key = data;
David Kozub1e815b32019-02-14 01:15:54 +01001372
Scott Bauer455a7b22017-02-03 12:50:31 -07001373 return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1374 OPAL_LOCKINGSP_UID,
1375 key->key, key->key_len);
1376}
1377
Jon Derrickeed64952017-02-22 07:55:13 -07001378static int start_auth_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001379{
Jon Derrickeed64952017-02-22 07:55:13 -07001380 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001381 u8 lk_ul_user[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001382 size_t keylen = session->opal_key.key_len;
Scott Bauer455a7b22017-02-03 12:50:31 -07001383 int err = 0;
1384
Scott Bauer455a7b22017-02-03 12:50:31 -07001385 u8 *key = session->opal_key.key;
1386 u32 hsn = GENERIC_HOST_SESSION_NUM;
1387
David Kozube8b29222019-02-14 01:15:58 +01001388 if (session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001389 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1390 session->opal_key.lr);
David Kozube8b29222019-02-14 01:15:58 +01001391 else if (session->who != OPAL_ADMIN1 && !session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001392 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1393 session->who - 1);
David Kozube8b29222019-02-14 01:15:58 +01001394 else
Scott Bauer455a7b22017-02-03 12:50:31 -07001395 memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1396
David Kozube8b29222019-02-14 01:15:58 +01001397 if (err)
1398 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001399
David Kozube8b29222019-02-14 01:15:58 +01001400 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1401 opalmethod[OPAL_STARTSESSION]);
1402
Scott Bauer455a7b22017-02-03 12:50:31 -07001403 add_token_u64(&err, dev, hsn);
1404 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1405 OPAL_UID_LENGTH);
1406 add_token_u8(&err, dev, 1);
1407 add_token_u8(&err, dev, OPAL_STARTNAME);
1408 add_token_u8(&err, dev, 0);
1409 add_token_bytestring(&err, dev, key, keylen);
1410 add_token_u8(&err, dev, OPAL_ENDNAME);
1411 add_token_u8(&err, dev, OPAL_STARTNAME);
1412 add_token_u8(&err, dev, 3);
1413 add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1414 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001415
1416 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001417 pr_debug("Error building STARTSESSION command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001418 return err;
1419 }
1420
1421 return finalize_and_send(dev, start_opal_session_cont);
1422}
1423
Jon Derrickeed64952017-02-22 07:55:13 -07001424static int revert_tper(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001425{
David Kozube8b29222019-02-14 01:15:58 +01001426 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001427
David Kozube8b29222019-02-14 01:15:58 +01001428 err = cmd_start(dev, opaluid[OPAL_ADMINSP_UID],
1429 opalmethod[OPAL_REVERT]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001430 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001431 pr_debug("Error building REVERT TPER command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001432 return err;
1433 }
1434
1435 return finalize_and_send(dev, parse_and_check_status);
1436}
1437
Jon Derrickeed64952017-02-22 07:55:13 -07001438static int internal_activate_user(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001439{
Jon Derrickeed64952017-02-22 07:55:13 -07001440 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001441 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001442 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001443
1444 memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1445 uid[7] = session->who;
1446
David Kozube8b29222019-02-14 01:15:58 +01001447 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001448 add_token_u8(&err, dev, OPAL_STARTNAME);
1449 add_token_u8(&err, dev, OPAL_VALUES);
1450 add_token_u8(&err, dev, OPAL_STARTLIST);
1451 add_token_u8(&err, dev, OPAL_STARTNAME);
1452 add_token_u8(&err, dev, 5); /* Enabled */
1453 add_token_u8(&err, dev, OPAL_TRUE);
1454 add_token_u8(&err, dev, OPAL_ENDNAME);
1455 add_token_u8(&err, dev, OPAL_ENDLIST);
1456 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001457
1458 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001459 pr_debug("Error building Activate UserN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001460 return err;
1461 }
1462
1463 return finalize_and_send(dev, parse_and_check_status);
1464}
1465
Jon Derrickeed64952017-02-22 07:55:13 -07001466static int erase_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001467{
Jon Derrickeed64952017-02-22 07:55:13 -07001468 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001469 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001470 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001471
1472 if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1473 return -ERANGE;
1474
David Kozube8b29222019-02-14 01:15:58 +01001475 err = cmd_start(dev, uid, opalmethod[OPAL_ERASE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001476
1477 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001478 pr_debug("Error building Erase Locking Range Command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001479 return err;
1480 }
1481 return finalize_and_send(dev, parse_and_check_status);
1482}
1483
Jon Derrickeed64952017-02-22 07:55:13 -07001484static int set_mbr_done(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001485{
Jon Derrickeed64952017-02-22 07:55:13 -07001486 u8 *mbr_done_tf = data;
David Kozube8b29222019-02-14 01:15:58 +01001487 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001488
David Kozube8b29222019-02-14 01:15:58 +01001489 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1490 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001491
Scott Bauer455a7b22017-02-03 12:50:31 -07001492 add_token_u8(&err, dev, OPAL_STARTNAME);
1493 add_token_u8(&err, dev, OPAL_VALUES);
1494 add_token_u8(&err, dev, OPAL_STARTLIST);
1495 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001496 add_token_u8(&err, dev, OPAL_MBRDONE);
Jon Derrickeed64952017-02-22 07:55:13 -07001497 add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
Scott Bauer455a7b22017-02-03 12:50:31 -07001498 add_token_u8(&err, dev, OPAL_ENDNAME);
1499 add_token_u8(&err, dev, OPAL_ENDLIST);
1500 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001501
1502 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001503 pr_debug("Error Building set MBR Done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001504 return err;
1505 }
1506
1507 return finalize_and_send(dev, parse_and_check_status);
1508}
1509
Jon Derrickeed64952017-02-22 07:55:13 -07001510static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001511{
Jon Derrickeed64952017-02-22 07:55:13 -07001512 u8 *mbr_en_dis = data;
David Kozube8b29222019-02-14 01:15:58 +01001513 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001514
David Kozube8b29222019-02-14 01:15:58 +01001515 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1516 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001517
Scott Bauer455a7b22017-02-03 12:50:31 -07001518 add_token_u8(&err, dev, OPAL_STARTNAME);
1519 add_token_u8(&err, dev, OPAL_VALUES);
1520 add_token_u8(&err, dev, OPAL_STARTLIST);
1521 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001522 add_token_u8(&err, dev, OPAL_MBRENABLE);
Jon Derrickeed64952017-02-22 07:55:13 -07001523 add_token_u8(&err, dev, *mbr_en_dis);
Scott Bauer455a7b22017-02-03 12:50:31 -07001524 add_token_u8(&err, dev, OPAL_ENDNAME);
1525 add_token_u8(&err, dev, OPAL_ENDLIST);
1526 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001527
1528 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001529 pr_debug("Error Building set MBR done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001530 return err;
1531 }
1532
1533 return finalize_and_send(dev, parse_and_check_status);
1534}
1535
1536static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1537 struct opal_dev *dev)
1538{
David Kozube8b29222019-02-14 01:15:58 +01001539 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001540
David Kozube8b29222019-02-14 01:15:58 +01001541 err = cmd_start(dev, cpin_uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001542
Scott Bauer455a7b22017-02-03 12:50:31 -07001543 add_token_u8(&err, dev, OPAL_STARTNAME);
1544 add_token_u8(&err, dev, OPAL_VALUES);
1545 add_token_u8(&err, dev, OPAL_STARTLIST);
1546 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001547 add_token_u8(&err, dev, OPAL_PIN);
Scott Bauer455a7b22017-02-03 12:50:31 -07001548 add_token_bytestring(&err, dev, key, key_len);
1549 add_token_u8(&err, dev, OPAL_ENDNAME);
1550 add_token_u8(&err, dev, OPAL_ENDLIST);
1551 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001552
1553 return err;
1554}
1555
Jon Derrickeed64952017-02-22 07:55:13 -07001556static int set_new_pw(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001557{
1558 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001559 struct opal_session_info *usr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001560
1561 memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1562
1563 if (usr->who != OPAL_ADMIN1) {
1564 cpin_uid[5] = 0x03;
1565 if (usr->sum)
1566 cpin_uid[7] = usr->opal_key.lr + 1;
1567 else
1568 cpin_uid[7] = usr->who;
1569 }
1570
1571 if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1572 cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001573 pr_debug("Error building set password command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001574 return -ERANGE;
1575 }
1576
1577 return finalize_and_send(dev, parse_and_check_status);
1578}
1579
Jon Derrickeed64952017-02-22 07:55:13 -07001580static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001581{
1582 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001583 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001584
1585 memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1586
1587 if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001588 pr_debug("Error building Set SID cpin\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001589 return -ERANGE;
1590 }
1591 return finalize_and_send(dev, parse_and_check_status);
1592}
1593
Jon Derrickeed64952017-02-22 07:55:13 -07001594static int add_user_to_lr(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001595{
1596 u8 lr_buffer[OPAL_UID_LENGTH];
1597 u8 user_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001598 struct opal_lock_unlock *lkul = data;
David Kozube8b29222019-02-14 01:15:58 +01001599 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001600
Scott Bauer455a7b22017-02-03 12:50:31 -07001601 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1602 OPAL_UID_LENGTH);
1603
1604 if (lkul->l_state == OPAL_RW)
1605 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1606 OPAL_UID_LENGTH);
1607
1608 lr_buffer[7] = lkul->session.opal_key.lr;
1609
1610 memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1611
1612 user_uid[7] = lkul->session.who;
1613
David Kozube8b29222019-02-14 01:15:58 +01001614 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001615
Scott Bauer455a7b22017-02-03 12:50:31 -07001616 add_token_u8(&err, dev, OPAL_STARTNAME);
1617 add_token_u8(&err, dev, OPAL_VALUES);
1618
1619 add_token_u8(&err, dev, OPAL_STARTLIST);
1620 add_token_u8(&err, dev, OPAL_STARTNAME);
1621 add_token_u8(&err, dev, 3);
1622
1623 add_token_u8(&err, dev, OPAL_STARTLIST);
1624
1625
1626 add_token_u8(&err, dev, OPAL_STARTNAME);
1627 add_token_bytestring(&err, dev,
1628 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1629 OPAL_UID_LENGTH/2);
1630 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1631 add_token_u8(&err, dev, OPAL_ENDNAME);
1632
1633
1634 add_token_u8(&err, dev, OPAL_STARTNAME);
1635 add_token_bytestring(&err, dev,
1636 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1637 OPAL_UID_LENGTH/2);
1638 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1639 add_token_u8(&err, dev, OPAL_ENDNAME);
1640
1641
1642 add_token_u8(&err, dev, OPAL_STARTNAME);
1643 add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1644 OPAL_UID_LENGTH/2);
1645 add_token_u8(&err, dev, 1);
1646 add_token_u8(&err, dev, OPAL_ENDNAME);
1647
1648
1649 add_token_u8(&err, dev, OPAL_ENDLIST);
1650 add_token_u8(&err, dev, OPAL_ENDNAME);
1651 add_token_u8(&err, dev, OPAL_ENDLIST);
1652 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001653
1654 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001655 pr_debug("Error building add user to locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001656 return err;
1657 }
1658
1659 return finalize_and_send(dev, parse_and_check_status);
1660}
1661
Jon Derrickeed64952017-02-22 07:55:13 -07001662static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001663{
1664 u8 lr_buffer[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001665 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001666 u8 read_locked = 1, write_locked = 1;
1667 int err = 0;
1668
Scott Bauer455a7b22017-02-03 12:50:31 -07001669 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1670 lkul->session.opal_key.lr) < 0)
1671 return -ERANGE;
1672
1673 switch (lkul->l_state) {
1674 case OPAL_RO:
1675 read_locked = 0;
1676 write_locked = 1;
1677 break;
1678 case OPAL_RW:
1679 read_locked = 0;
1680 write_locked = 0;
1681 break;
1682 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001683 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001684 break;
1685 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001686 pr_debug("Tried to set an invalid locking state... returning to uland\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001687 return OPAL_INVAL_PARAM;
1688 }
1689
David Kozube8b29222019-02-14 01:15:58 +01001690 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
1691
Scott Bauer455a7b22017-02-03 12:50:31 -07001692 add_token_u8(&err, dev, OPAL_STARTNAME);
1693 add_token_u8(&err, dev, OPAL_VALUES);
1694 add_token_u8(&err, dev, OPAL_STARTLIST);
1695
1696 add_token_u8(&err, dev, OPAL_STARTNAME);
1697 add_token_u8(&err, dev, OPAL_READLOCKED);
1698 add_token_u8(&err, dev, read_locked);
1699 add_token_u8(&err, dev, OPAL_ENDNAME);
1700
1701 add_token_u8(&err, dev, OPAL_STARTNAME);
1702 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1703 add_token_u8(&err, dev, write_locked);
1704 add_token_u8(&err, dev, OPAL_ENDNAME);
1705
1706 add_token_u8(&err, dev, OPAL_ENDLIST);
1707 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001708
1709 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001710 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001711 return err;
1712 }
1713 return finalize_and_send(dev, parse_and_check_status);
1714}
1715
1716
Jon Derrickeed64952017-02-22 07:55:13 -07001717static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001718{
1719 u8 lr_buffer[OPAL_UID_LENGTH];
1720 u8 read_locked = 1, write_locked = 1;
Jon Derrickeed64952017-02-22 07:55:13 -07001721 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001722 int ret;
1723
1724 clear_opal_cmd(dev);
1725 set_comid(dev, dev->comid);
1726
Scott Bauer455a7b22017-02-03 12:50:31 -07001727 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1728 lkul->session.opal_key.lr) < 0)
1729 return -ERANGE;
1730
1731 switch (lkul->l_state) {
1732 case OPAL_RO:
1733 read_locked = 0;
1734 write_locked = 1;
1735 break;
1736 case OPAL_RW:
1737 read_locked = 0;
1738 write_locked = 0;
1739 break;
1740 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001741 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001742 break;
1743 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001744 pr_debug("Tried to set an invalid locking state.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001745 return OPAL_INVAL_PARAM;
1746 }
1747 ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1748 read_locked, write_locked);
1749
1750 if (ret < 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001751 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001752 return ret;
1753 }
1754 return finalize_and_send(dev, parse_and_check_status);
1755}
1756
Jon Derrickeed64952017-02-22 07:55:13 -07001757static int activate_lsp(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001758{
Jon Derrickeed64952017-02-22 07:55:13 -07001759 struct opal_lr_act *opal_act = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001760 u8 user_lr[OPAL_UID_LENGTH];
1761 u8 uint_3 = 0x83;
David Kozube8b29222019-02-14 01:15:58 +01001762 int err, i;
Scott Bauer455a7b22017-02-03 12:50:31 -07001763
David Kozube8b29222019-02-14 01:15:58 +01001764 err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID],
1765 opalmethod[OPAL_ACTIVATE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001766
1767 if (opal_act->sum) {
1768 err = build_locking_range(user_lr, sizeof(user_lr),
1769 opal_act->lr[0]);
1770 if (err)
1771 return err;
1772
Scott Bauer455a7b22017-02-03 12:50:31 -07001773 add_token_u8(&err, dev, OPAL_STARTNAME);
1774 add_token_u8(&err, dev, uint_3);
1775 add_token_u8(&err, dev, 6);
1776 add_token_u8(&err, dev, 0);
1777 add_token_u8(&err, dev, 0);
1778
1779 add_token_u8(&err, dev, OPAL_STARTLIST);
1780 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1781 for (i = 1; i < opal_act->num_lrs; i++) {
1782 user_lr[7] = opal_act->lr[i];
1783 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1784 }
1785 add_token_u8(&err, dev, OPAL_ENDLIST);
1786 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001787 }
1788
1789 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001790 pr_debug("Error building Activate LockingSP command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001791 return err;
1792 }
1793
1794 return finalize_and_send(dev, parse_and_check_status);
1795}
1796
David Kozub3fff2342019-02-14 01:16:04 +01001797/* Determine if we're in the Manufactured Inactive or Active state */
1798static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001799{
1800 u8 lc_status;
David Kozub3fff2342019-02-14 01:16:04 +01001801 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001802
David Kozub3fff2342019-02-14 01:16:04 +01001803 err = generic_get_column(dev, opaluid[OPAL_LOCKINGSP_UID],
1804 OPAL_LIFECYCLE);
1805 if (err)
1806 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001807
1808 lc_status = response_get_u64(&dev->parsed, 4);
David Kozub1e815b32019-02-14 01:15:54 +01001809 /* 0x08 is Manufactured Inactive */
Scott Bauer455a7b22017-02-03 12:50:31 -07001810 /* 0x09 is Manufactured */
1811 if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001812 pr_debug("Couldn't determine the status of the Lifecycle state\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001813 return -ENODEV;
1814 }
1815
1816 return 0;
1817}
1818
David Kozub3fff2342019-02-14 01:16:04 +01001819static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001820{
1821 const char *msid_pin;
1822 size_t strlen;
David Kozub3fff2342019-02-14 01:16:04 +01001823 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001824
David Kozub3fff2342019-02-14 01:16:04 +01001825 err = generic_get_column(dev, opaluid[OPAL_C_PIN_MSID], OPAL_PIN);
1826 if (err)
1827 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001828
1829 strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1830 if (!msid_pin) {
David Kozub3fff2342019-02-14 01:16:04 +01001831 pr_debug("Couldn't extract MSID_CPIN from response\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001832 return OPAL_INVAL_PARAM;
1833 }
1834
1835 dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1836 if (!dev->prev_data)
1837 return -ENOMEM;
1838
1839 dev->prev_d_len = strlen;
1840
1841 return 0;
1842}
1843
Jon Derrickeed64952017-02-22 07:55:13 -07001844static int end_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001845{
1846 int err = 0;
1847
1848 clear_opal_cmd(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001849 set_comid(dev, dev->comid);
1850 add_token_u8(&err, dev, OPAL_ENDOFSESSION);
Scott Bauer455a7b22017-02-03 12:50:31 -07001851
Jon Derrickeed64952017-02-22 07:55:13 -07001852 if (err < 0)
1853 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001854 return finalize_and_send(dev, end_session_cont);
1855}
1856
1857static int end_opal_session_error(struct opal_dev *dev)
1858{
David Kozub0af26482019-02-14 01:16:07 +01001859 const struct opal_step error_end_session = {
1860 end_opal_session,
Scott Bauer455a7b22017-02-03 12:50:31 -07001861 };
David Kozub0af26482019-02-14 01:16:07 +01001862 return execute_step(dev, &error_end_session, 0);
Scott Bauer455a7b22017-02-03 12:50:31 -07001863}
1864
David Kozub3db87232019-02-14 01:16:06 +01001865static inline void setup_opal_dev(struct opal_dev *dev)
Scott Bauer455a7b22017-02-03 12:50:31 -07001866{
Scott Bauer455a7b22017-02-03 12:50:31 -07001867 dev->tsn = 0;
1868 dev->hsn = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -07001869 dev->prev_data = NULL;
1870}
1871
1872static int check_opal_support(struct opal_dev *dev)
1873{
Scott Bauer455a7b22017-02-03 12:50:31 -07001874 int ret;
1875
1876 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001877 setup_opal_dev(dev);
David Kozub0af26482019-02-14 01:16:07 +01001878 ret = opal_discovery0_step(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001879 dev->supported = !ret;
1880 mutex_unlock(&dev->dev_lock);
1881 return ret;
1882}
1883
Scott Bauer7d6d1572017-02-22 10:15:06 -07001884static void clean_opal_dev(struct opal_dev *dev)
1885{
1886
1887 struct opal_suspend_data *suspend, *next;
1888
1889 mutex_lock(&dev->dev_lock);
1890 list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
1891 list_del(&suspend->node);
1892 kfree(suspend);
1893 }
1894 mutex_unlock(&dev->dev_lock);
1895}
1896
1897void free_opal_dev(struct opal_dev *dev)
1898{
1899 if (!dev)
1900 return;
1901 clean_opal_dev(dev);
1902 kfree(dev);
1903}
1904EXPORT_SYMBOL(free_opal_dev);
1905
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01001906struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
Scott Bauer455a7b22017-02-03 12:50:31 -07001907{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01001908 struct opal_dev *dev;
1909
1910 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
1911 if (!dev)
1912 return NULL;
1913
1914 INIT_LIST_HEAD(&dev->unlk_lst);
1915 mutex_init(&dev->dev_lock);
1916 dev->data = data;
1917 dev->send_recv = send_recv;
1918 if (check_opal_support(dev) != 0) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +01001919 pr_debug("Opal is not supported on this device\n");
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01001920 kfree(dev);
1921 return NULL;
1922 }
1923 return dev;
Scott Bauer455a7b22017-02-03 12:50:31 -07001924}
1925EXPORT_SYMBOL(init_opal_dev);
1926
1927static int opal_secure_erase_locking_range(struct opal_dev *dev,
1928 struct opal_session_info *opal_session)
1929{
Jon Derrickeed64952017-02-22 07:55:13 -07001930 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07001931 { start_auth_opal_session, opal_session },
1932 { get_active_key, &opal_session->opal_key.lr },
1933 { gen_key, },
David Kozub3db87232019-02-14 01:16:06 +01001934 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001935 };
1936 int ret;
1937
1938 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001939 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01001940 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07001941 mutex_unlock(&dev->dev_lock);
1942 return ret;
1943}
1944
1945static int opal_erase_locking_range(struct opal_dev *dev,
1946 struct opal_session_info *opal_session)
1947{
Jon Derrickeed64952017-02-22 07:55:13 -07001948 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07001949 { start_auth_opal_session, opal_session },
1950 { erase_locking_range, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01001951 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001952 };
1953 int ret;
1954
1955 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001956 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01001957 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07001958 mutex_unlock(&dev->dev_lock);
1959 return ret;
1960}
1961
1962static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
1963 struct opal_mbr_data *opal_mbr)
1964{
David Kozub78bf4732019-02-14 01:15:53 +01001965 u8 enable_disable = opal_mbr->enable_disable == OPAL_MBR_ENABLE ?
1966 OPAL_TRUE : OPAL_FALSE;
1967
Jon Derrickeed64952017-02-22 07:55:13 -07001968 const struct opal_step mbr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07001969 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01001970 { set_mbr_done, &enable_disable },
Jon Derrickeed64952017-02-22 07:55:13 -07001971 { end_opal_session, },
1972 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01001973 { set_mbr_enable_disable, &enable_disable },
David Kozub3db87232019-02-14 01:16:06 +01001974 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001975 };
1976 int ret;
1977
1978 if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
1979 opal_mbr->enable_disable != OPAL_MBR_DISABLE)
1980 return -EINVAL;
1981
1982 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001983 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01001984 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07001985 mutex_unlock(&dev->dev_lock);
1986 return ret;
1987}
1988
1989static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
1990{
1991 struct opal_suspend_data *suspend;
1992
1993 suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
1994 if (!suspend)
1995 return -ENOMEM;
1996
1997 suspend->unlk = *lk_unlk;
1998 suspend->lr = lk_unlk->session.opal_key.lr;
1999
2000 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002001 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002002 add_suspend_info(dev, suspend);
2003 mutex_unlock(&dev->dev_lock);
2004 return 0;
2005}
2006
2007static int opal_add_user_to_lr(struct opal_dev *dev,
2008 struct opal_lock_unlock *lk_unlk)
2009{
Jon Derrickeed64952017-02-22 07:55:13 -07002010 const struct opal_step steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002011 { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2012 { add_user_to_lr, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002013 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002014 };
2015 int ret;
2016
2017 if (lk_unlk->l_state != OPAL_RO &&
2018 lk_unlk->l_state != OPAL_RW) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002019 pr_debug("Locking state was not RO or RW\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07002020 return -EINVAL;
2021 }
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002022 if (lk_unlk->session.who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002023 lk_unlk->session.who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002024 pr_debug("Authority was not within the range of users: %d\n",
2025 lk_unlk->session.who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002026 return -EINVAL;
2027 }
2028 if (lk_unlk->session.sum) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002029 pr_debug("%s not supported in sum. Use setup locking range\n",
2030 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07002031 return -EINVAL;
2032 }
2033
2034 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002035 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002036 ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002037 mutex_unlock(&dev->dev_lock);
2038 return ret;
2039}
2040
2041static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal)
2042{
Jon Derrickeed64952017-02-22 07:55:13 -07002043 const struct opal_step revert_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002044 { start_SIDASP_opal_session, opal },
David Kozub3db87232019-02-14 01:16:06 +01002045 { revert_tper, } /* controller will terminate session */
Scott Bauer455a7b22017-02-03 12:50:31 -07002046 };
2047 int ret;
2048
2049 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002050 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002051 ret = execute_steps(dev, revert_steps, ARRAY_SIZE(revert_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002052 mutex_unlock(&dev->dev_lock);
Scott Bauer7d6d1572017-02-22 10:15:06 -07002053
2054 /*
2055 * If we successfully reverted lets clean
2056 * any saved locking ranges.
2057 */
2058 if (!ret)
2059 clean_opal_dev(dev);
2060
Scott Bauer455a7b22017-02-03 12:50:31 -07002061 return ret;
2062}
2063
Jon Derrickeed64952017-02-22 07:55:13 -07002064static int __opal_lock_unlock(struct opal_dev *dev,
2065 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002066{
Jon Derrickeed64952017-02-22 07:55:13 -07002067 const struct opal_step unlock_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002068 { start_auth_opal_session, &lk_unlk->session },
2069 { lock_unlock_locking_range, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002070 { end_opal_session, }
Jon Derrickeed64952017-02-22 07:55:13 -07002071 };
2072 const struct opal_step unlock_sum_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002073 { start_auth_opal_session, &lk_unlk->session },
2074 { lock_unlock_locking_range_sum, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002075 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002076 };
2077
David Kozub3db87232019-02-14 01:16:06 +01002078 if (lk_unlk->session.sum)
David Kozuba80f36c2019-02-14 01:16:08 +01002079 return execute_steps(dev, unlock_sum_steps,
2080 ARRAY_SIZE(unlock_sum_steps));
David Kozub3db87232019-02-14 01:16:06 +01002081 else
David Kozuba80f36c2019-02-14 01:16:08 +01002082 return execute_steps(dev, unlock_steps,
2083 ARRAY_SIZE(unlock_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002084}
2085
Scott Bauerdbec491b2017-09-01 08:53:35 -06002086static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2087{
David Kozub78bf4732019-02-14 01:15:53 +01002088 u8 mbr_done_tf = OPAL_TRUE;
David Kozub1e815b32019-02-14 01:15:54 +01002089 const struct opal_step mbrdone_step[] = {
Scott Bauerdbec491b2017-09-01 08:53:35 -06002090 { start_admin1LSP_opal_session, key },
2091 { set_mbr_done, &mbr_done_tf },
David Kozub3db87232019-02-14 01:16:06 +01002092 { end_opal_session, }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002093 };
2094
David Kozuba80f36c2019-02-14 01:16:08 +01002095 return execute_steps(dev, mbrdone_step, ARRAY_SIZE(mbrdone_step));
Scott Bauerdbec491b2017-09-01 08:53:35 -06002096}
2097
Jon Derrickeed64952017-02-22 07:55:13 -07002098static int opal_lock_unlock(struct opal_dev *dev,
2099 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002100{
Scott Bauer455a7b22017-02-03 12:50:31 -07002101 int ret;
2102
2103 if (lk_unlk->session.who < OPAL_ADMIN1 ||
2104 lk_unlk->session.who > OPAL_USER9)
2105 return -EINVAL;
2106
2107 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002108 ret = __opal_lock_unlock(dev, lk_unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002109 mutex_unlock(&dev->dev_lock);
2110 return ret;
2111}
2112
2113static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2114{
Jon Derrickeed64952017-02-22 07:55:13 -07002115 const struct opal_step owner_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002116 { start_anybodyASP_opal_session, },
2117 { get_msid_cpin_pin, },
2118 { end_opal_session, },
2119 { start_SIDASP_opal_session, opal },
2120 { set_sid_cpin_pin, opal },
David Kozub3db87232019-02-14 01:16:06 +01002121 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002122 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002123 int ret;
2124
2125 if (!dev)
2126 return -ENODEV;
2127
2128 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002129 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002130 ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002131 mutex_unlock(&dev->dev_lock);
2132 return ret;
2133}
2134
David Kozub1e815b32019-02-14 01:15:54 +01002135static int opal_activate_lsp(struct opal_dev *dev,
2136 struct opal_lr_act *opal_lr_act)
Scott Bauer455a7b22017-02-03 12:50:31 -07002137{
Jon Derrickeed64952017-02-22 07:55:13 -07002138 const struct opal_step active_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002139 { start_SIDASP_opal_session, &opal_lr_act->key },
2140 { get_lsp_lifecycle, },
2141 { activate_lsp, opal_lr_act },
David Kozub3db87232019-02-14 01:16:06 +01002142 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002143 };
2144 int ret;
2145
2146 if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2147 return -EINVAL;
2148
2149 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002150 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002151 ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002152 mutex_unlock(&dev->dev_lock);
2153 return ret;
2154}
2155
2156static int opal_setup_locking_range(struct opal_dev *dev,
2157 struct opal_user_lr_setup *opal_lrs)
2158{
Jon Derrickeed64952017-02-22 07:55:13 -07002159 const struct opal_step lr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002160 { start_auth_opal_session, &opal_lrs->session },
2161 { setup_locking_range, opal_lrs },
David Kozub3db87232019-02-14 01:16:06 +01002162 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002163 };
2164 int ret;
2165
2166 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002167 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002168 ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002169 mutex_unlock(&dev->dev_lock);
2170 return ret;
2171}
2172
2173static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2174{
Jon Derrickeed64952017-02-22 07:55:13 -07002175 const struct opal_step pw_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002176 { start_auth_opal_session, &opal_pw->session },
2177 { set_new_pw, &opal_pw->new_user_pw },
David Kozub3db87232019-02-14 01:16:06 +01002178 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002179 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002180 int ret;
2181
2182 if (opal_pw->session.who < OPAL_ADMIN1 ||
2183 opal_pw->session.who > OPAL_USER9 ||
2184 opal_pw->new_user_pw.who < OPAL_ADMIN1 ||
2185 opal_pw->new_user_pw.who > OPAL_USER9)
2186 return -EINVAL;
2187
2188 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002189 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002190 ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002191 mutex_unlock(&dev->dev_lock);
2192 return ret;
2193}
2194
2195static int opal_activate_user(struct opal_dev *dev,
2196 struct opal_session_info *opal_session)
2197{
Jon Derrickeed64952017-02-22 07:55:13 -07002198 const struct opal_step act_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002199 { start_admin1LSP_opal_session, &opal_session->opal_key },
2200 { internal_activate_user, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01002201 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002202 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002203 int ret;
2204
2205 /* We can't activate Admin1 it's active as manufactured */
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002206 if (opal_session->who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002207 opal_session->who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002208 pr_debug("Who was not a valid user: %d\n", opal_session->who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002209 return -EINVAL;
2210 }
2211
2212 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002213 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002214 ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002215 mutex_unlock(&dev->dev_lock);
2216 return ret;
2217}
2218
2219bool opal_unlock_from_suspend(struct opal_dev *dev)
2220{
2221 struct opal_suspend_data *suspend;
Scott Bauer455a7b22017-02-03 12:50:31 -07002222 bool was_failure = false;
2223 int ret = 0;
2224
2225 if (!dev)
2226 return false;
2227 if (!dev->supported)
2228 return false;
2229
2230 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002231 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002232
2233 list_for_each_entry(suspend, &dev->unlk_lst, node) {
Scott Bauer455a7b22017-02-03 12:50:31 -07002234 dev->tsn = 0;
2235 dev->hsn = 0;
2236
Jon Derrickeed64952017-02-22 07:55:13 -07002237 ret = __opal_lock_unlock(dev, &suspend->unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002238 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002239 pr_debug("Failed to unlock LR %hhu with sum %d\n",
2240 suspend->unlk.session.opal_key.lr,
2241 suspend->unlk.session.sum);
Scott Bauer455a7b22017-02-03 12:50:31 -07002242 was_failure = true;
2243 }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002244 if (dev->mbr_enabled) {
2245 ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
2246 if (ret)
2247 pr_debug("Failed to set MBR Done in S3 resume\n");
2248 }
Scott Bauer455a7b22017-02-03 12:50:31 -07002249 }
2250 mutex_unlock(&dev->dev_lock);
2251 return was_failure;
2252}
2253EXPORT_SYMBOL(opal_unlock_from_suspend);
2254
Scott Bauere225c202017-02-14 17:29:36 -07002255int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
Scott Bauer455a7b22017-02-03 12:50:31 -07002256{
Scott Bauere225c202017-02-14 17:29:36 -07002257 void *p;
2258 int ret = -ENOTTY;
Scott Bauer455a7b22017-02-03 12:50:31 -07002259
2260 if (!capable(CAP_SYS_ADMIN))
2261 return -EACCES;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002262 if (!dev)
2263 return -ENOTSUPP;
Scott Bauer591c59d2017-04-07 13:58:50 -06002264 if (!dev->supported)
Scott Bauer455a7b22017-02-03 12:50:31 -07002265 return -ENOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -07002266
Jon Derrickeed64952017-02-22 07:55:13 -07002267 p = memdup_user(arg, _IOC_SIZE(cmd));
Scott Bauere225c202017-02-14 17:29:36 -07002268 if (IS_ERR(p))
2269 return PTR_ERR(p);
2270
Scott Bauer455a7b22017-02-03 12:50:31 -07002271 switch (cmd) {
Scott Bauere225c202017-02-14 17:29:36 -07002272 case IOC_OPAL_SAVE:
2273 ret = opal_save(dev, p);
2274 break;
2275 case IOC_OPAL_LOCK_UNLOCK:
2276 ret = opal_lock_unlock(dev, p);
2277 break;
2278 case IOC_OPAL_TAKE_OWNERSHIP:
2279 ret = opal_take_ownership(dev, p);
2280 break;
2281 case IOC_OPAL_ACTIVATE_LSP:
2282 ret = opal_activate_lsp(dev, p);
2283 break;
2284 case IOC_OPAL_SET_PW:
2285 ret = opal_set_new_pw(dev, p);
2286 break;
2287 case IOC_OPAL_ACTIVATE_USR:
2288 ret = opal_activate_user(dev, p);
2289 break;
2290 case IOC_OPAL_REVERT_TPR:
2291 ret = opal_reverttper(dev, p);
2292 break;
2293 case IOC_OPAL_LR_SETUP:
2294 ret = opal_setup_locking_range(dev, p);
2295 break;
2296 case IOC_OPAL_ADD_USR_TO_LR:
2297 ret = opal_add_user_to_lr(dev, p);
2298 break;
2299 case IOC_OPAL_ENABLE_DISABLE_MBR:
2300 ret = opal_enable_disable_shadow_mbr(dev, p);
2301 break;
2302 case IOC_OPAL_ERASE_LR:
2303 ret = opal_erase_locking_range(dev, p);
2304 break;
2305 case IOC_OPAL_SECURE_ERASE_LR:
2306 ret = opal_secure_erase_locking_range(dev, p);
2307 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002308 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06002309 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002310 }
Scott Bauere225c202017-02-14 17:29:36 -07002311
2312 kfree(p);
2313 return ret;
Scott Bauer455a7b22017-02-03 12:50:31 -07002314}
2315EXPORT_SYMBOL_GPL(sed_ioctl);