blob: b4c761973ac102fda9f75a3f92c56e77f5a718cd [file] [log] [blame]
Christoph Hellwig8c165672019-04-30 14:42:39 -04001// SPDX-License-Identifier: GPL-2.0
Scott Bauer455a7b22017-02-03 12:50:31 -07002/*
3 * Copyright © 2016 Intel Corporation
4 *
5 * Authors:
6 * Scott Bauer <scott.bauer@intel.com>
7 * Rafael Antognolli <rafael.antognolli@intel.com>
Scott Bauer455a7b22017-02-03 12:50:31 -07008 */
9
10#define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt
11
12#include <linux/delay.h>
13#include <linux/device.h>
14#include <linux/kernel.h>
15#include <linux/list.h>
16#include <linux/genhd.h>
17#include <linux/slab.h>
18#include <linux/uaccess.h>
19#include <uapi/linux/sed-opal.h>
20#include <linux/sed-opal.h>
21#include <linux/string.h>
22#include <linux/kdev_t.h>
23
24#include "opal_proto.h"
25
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010026#define IO_BUFFER_LENGTH 2048
27#define MAX_TOKS 64
28
Jonas Rabensteina9b25b42019-05-21 22:46:45 +020029/* Number of bytes needed by cmd_finalize. */
30#define CMD_FINALIZE_BYTES_NEEDED 7
31
Jon Derrickeed64952017-02-22 07:55:13 -070032struct opal_step {
33 int (*fn)(struct opal_dev *dev, void *data);
34 void *data;
35};
36typedef int (cont_fn)(struct opal_dev *dev);
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010037
38enum opal_atom_width {
39 OPAL_WIDTH_TINY,
40 OPAL_WIDTH_SHORT,
41 OPAL_WIDTH_MEDIUM,
42 OPAL_WIDTH_LONG,
43 OPAL_WIDTH_TOKEN
44};
45
46/*
47 * On the parsed response, we don't store again the toks that are already
48 * stored in the response buffer. Instead, for each token, we just store a
49 * pointer to the position in the buffer where the token starts, and the size
50 * of the token in bytes.
51 */
52struct opal_resp_tok {
53 const u8 *pos;
54 size_t len;
55 enum opal_response_token type;
56 enum opal_atom_width width;
57 union {
58 u64 u;
59 s64 s;
60 } stored;
61};
62
63/*
64 * From the response header it's not possible to know how many tokens there are
65 * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
66 * if we start dealing with messages that have more than that, we can increase
67 * this number. This is done to avoid having to make two passes through the
68 * response, the first one counting how many tokens we have and the second one
69 * actually storing the positions.
70 */
71struct parsed_resp {
72 int num;
73 struct opal_resp_tok toks[MAX_TOKS];
74};
75
76struct opal_dev {
77 bool supported;
Scott Bauerdbec491b2017-09-01 08:53:35 -060078 bool mbr_enabled;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010079
80 void *data;
81 sec_send_recv *send_recv;
82
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010083 struct mutex dev_lock;
84 u16 comid;
85 u32 hsn;
86 u32 tsn;
87 u64 align;
88 u64 lowest_lba;
89
90 size_t pos;
91 u8 cmd[IO_BUFFER_LENGTH];
92 u8 resp[IO_BUFFER_LENGTH];
93
94 struct parsed_resp parsed;
95 size_t prev_d_len;
96 void *prev_data;
97
98 struct list_head unlk_lst;
99};
100
101
Scott Bauer455a7b22017-02-03 12:50:31 -0700102static const u8 opaluid[][OPAL_UID_LENGTH] = {
103 /* users */
104 [OPAL_SMUID_UID] =
105 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
106 [OPAL_THISSP_UID] =
107 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
108 [OPAL_ADMINSP_UID] =
109 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
110 [OPAL_LOCKINGSP_UID] =
111 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
112 [OPAL_ENTERPRISE_LOCKINGSP_UID] =
113 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
114 [OPAL_ANYBODY_UID] =
115 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
116 [OPAL_SID_UID] =
117 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
118 [OPAL_ADMIN1_UID] =
119 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
120 [OPAL_USER1_UID] =
121 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
122 [OPAL_USER2_UID] =
123 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
124 [OPAL_PSID_UID] =
125 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
126 [OPAL_ENTERPRISE_BANDMASTER0_UID] =
127 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
128 [OPAL_ENTERPRISE_ERASEMASTER_UID] =
129 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
130
131 /* tables */
Randy Dunlapdc301022019-10-02 19:23:05 -0700132 [OPAL_TABLE_TABLE] =
Jonas Rabensteinff910642019-05-21 22:46:46 +0200133 { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 },
Scott Bauer455a7b22017-02-03 12:50:31 -0700134 [OPAL_LOCKINGRANGE_GLOBAL] =
135 { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
136 [OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
137 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
138 [OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
139 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
140 [OPAL_MBRCONTROL] =
141 { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
142 [OPAL_MBR] =
143 { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
144 [OPAL_AUTHORITY_TABLE] =
145 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
146 [OPAL_C_PIN_TABLE] =
147 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
148 [OPAL_LOCKING_INFO_TABLE] =
149 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
150 [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
151 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
152
153 /* C_PIN_TABLE object ID's */
David Kozub1e815b32019-02-14 01:15:54 +0100154 [OPAL_C_PIN_MSID] =
Scott Bauer455a7b22017-02-03 12:50:31 -0700155 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
156 [OPAL_C_PIN_SID] =
157 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
158 [OPAL_C_PIN_ADMIN1] =
159 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
160
161 /* half UID's (only first 4 bytes used) */
Scott Bauer455a7b22017-02-03 12:50:31 -0700162 [OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
163 { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
164 [OPAL_HALF_UID_BOOLEAN_ACE] =
165 { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
166
167 /* special value for omitted optional parameter */
168 [OPAL_UID_HEXFF] =
169 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
170};
171
172/*
173 * TCG Storage SSC Methods.
174 * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
175 * Section: 6.3 Assigned UIDs
176 */
Jonas Rabenstein1b6b75b2019-02-14 01:15:55 +0100177static const u8 opalmethod[][OPAL_METHOD_LENGTH] = {
Scott Bauer455a7b22017-02-03 12:50:31 -0700178 [OPAL_PROPERTIES] =
179 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
180 [OPAL_STARTSESSION] =
181 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
182 [OPAL_REVERT] =
183 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
184 [OPAL_ACTIVATE] =
185 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
186 [OPAL_EGET] =
187 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
188 [OPAL_ESET] =
189 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
190 [OPAL_NEXT] =
191 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
192 [OPAL_EAUTHENTICATE] =
193 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
194 [OPAL_GETACL] =
195 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
196 [OPAL_GENKEY] =
197 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
198 [OPAL_REVERTSP] =
199 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
200 [OPAL_GET] =
201 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
202 [OPAL_SET] =
203 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
204 [OPAL_AUTHENTICATE] =
205 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
206 [OPAL_RANDOM] =
207 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
208 [OPAL_ERASE] =
209 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
210};
211
Scott Bauer455a7b22017-02-03 12:50:31 -0700212static int end_opal_session_error(struct opal_dev *dev);
David Kozub0af26482019-02-14 01:16:07 +0100213static int opal_discovery0_step(struct opal_dev *dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700214
215struct opal_suspend_data {
216 struct opal_lock_unlock unlk;
217 u8 lr;
218 struct list_head node;
219};
220
221/*
222 * Derived from:
223 * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
224 * Section: 5.1.5 Method Status Codes
225 */
226static const char * const opal_errors[] = {
227 "Success",
228 "Not Authorized",
229 "Unknown Error",
230 "SP Busy",
231 "SP Failed",
232 "SP Disabled",
233 "SP Frozen",
234 "No Sessions Available",
235 "Uniqueness Conflict",
236 "Insufficient Space",
237 "Insufficient Rows",
238 "Invalid Function",
239 "Invalid Parameter",
240 "Invalid Reference",
241 "Unknown Error",
242 "TPER Malfunction",
243 "Transaction Failure",
244 "Response Overflow",
245 "Authority Locked Out",
246};
247
248static const char *opal_error_to_human(int error)
249{
250 if (error == 0x3f)
251 return "Failed";
252
253 if (error >= ARRAY_SIZE(opal_errors) || error < 0)
254 return "Unknown Error";
255
256 return opal_errors[error];
257}
258
259static void print_buffer(const u8 *ptr, u32 length)
260{
261#ifdef DEBUG
262 print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
263 pr_debug("\n");
264#endif
265}
266
267static bool check_tper(const void *data)
268{
269 const struct d0_tper_features *tper = data;
270 u8 flags = tper->supported_features;
271
272 if (!(flags & TPER_SYNC_SUPPORTED)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600273 pr_debug("TPer sync not supported. flags = %d\n",
274 tper->supported_features);
Scott Bauer455a7b22017-02-03 12:50:31 -0700275 return false;
276 }
277
278 return true;
279}
280
Scott Bauerdbec491b2017-09-01 08:53:35 -0600281static bool check_mbrenabled(const void *data)
282{
283 const struct d0_locking_features *lfeat = data;
284 u8 sup_feat = lfeat->supported_features;
285
286 return !!(sup_feat & MBR_ENABLED_MASK);
287}
288
Scott Bauer455a7b22017-02-03 12:50:31 -0700289static bool check_sum(const void *data)
290{
291 const struct d0_single_user_mode *sum = data;
292 u32 nlo = be32_to_cpu(sum->num_locking_objects);
293
294 if (nlo == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600295 pr_debug("Need at least one locking object.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700296 return false;
297 }
298
299 pr_debug("Number of locking objects: %d\n", nlo);
300
301 return true;
302}
303
304static u16 get_comid_v100(const void *data)
305{
306 const struct d0_opal_v100 *v100 = data;
307
308 return be16_to_cpu(v100->baseComID);
309}
310
311static u16 get_comid_v200(const void *data)
312{
313 const struct d0_opal_v200 *v200 = data;
314
315 return be16_to_cpu(v200->baseComID);
316}
317
318static int opal_send_cmd(struct opal_dev *dev)
319{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100320 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700321 dev->cmd, IO_BUFFER_LENGTH,
322 true);
323}
324
325static int opal_recv_cmd(struct opal_dev *dev)
326{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100327 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700328 dev->resp, IO_BUFFER_LENGTH,
329 false);
330}
331
332static int opal_recv_check(struct opal_dev *dev)
333{
334 size_t buflen = IO_BUFFER_LENGTH;
335 void *buffer = dev->resp;
336 struct opal_header *hdr = buffer;
337 int ret;
338
339 do {
340 pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
341 hdr->cp.outstandingData,
342 hdr->cp.minTransfer);
343
344 if (hdr->cp.outstandingData == 0 ||
345 hdr->cp.minTransfer != 0)
346 return 0;
347
348 memset(buffer, 0, buflen);
349 ret = opal_recv_cmd(dev);
350 } while (!ret);
351
352 return ret;
353}
354
355static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
356{
357 int ret;
358
359 ret = opal_send_cmd(dev);
360 if (ret)
361 return ret;
362 ret = opal_recv_cmd(dev);
363 if (ret)
364 return ret;
365 ret = opal_recv_check(dev);
366 if (ret)
367 return ret;
368 return cont(dev);
369}
370
371static void check_geometry(struct opal_dev *dev, const void *data)
372{
373 const struct d0_geometry_features *geo = data;
374
Randy Dunlapa9eb49c2019-10-02 19:23:15 -0700375 dev->align = be64_to_cpu(geo->alignment_granularity);
376 dev->lowest_lba = be64_to_cpu(geo->lowest_aligned_lba);
Scott Bauer455a7b22017-02-03 12:50:31 -0700377}
378
David Kozub0af26482019-02-14 01:16:07 +0100379static int execute_step(struct opal_dev *dev,
380 const struct opal_step *step, size_t stepIndex)
381{
382 int error = step->fn(dev, step->data);
383
384 if (error) {
385 pr_debug("Step %zu (%pS) failed with error %d: %s\n",
386 stepIndex, step->fn, error,
387 opal_error_to_human(error));
388 }
389
390 return error;
391}
392
David Kozuba80f36c2019-02-14 01:16:08 +0100393static int execute_steps(struct opal_dev *dev,
394 const struct opal_step *steps, size_t n_steps)
Scott Bauer455a7b22017-02-03 12:50:31 -0700395{
David Kozub0af26482019-02-14 01:16:07 +0100396 size_t state = 0;
397 int error;
398
399 /* first do a discovery0 */
400 error = opal_discovery0_step(dev);
401 if (error)
402 return error;
Scott Bauer455a7b22017-02-03 12:50:31 -0700403
David Kozub3db87232019-02-14 01:16:06 +0100404 for (state = 0; state < n_steps; state++) {
David Kozub0af26482019-02-14 01:16:07 +0100405 error = execute_step(dev, &steps[state], state);
David Kozub3db87232019-02-14 01:16:06 +0100406 if (error)
407 goto out_error;
408 }
Scott Bauer455a7b22017-02-03 12:50:31 -0700409
David Kozub3db87232019-02-14 01:16:06 +0100410 return 0;
Scott Bauer2d190202017-02-22 10:15:08 -0700411
David Kozub3db87232019-02-14 01:16:06 +0100412out_error:
413 /*
David Kozub0af26482019-02-14 01:16:07 +0100414 * For each OPAL command the first step in steps starts some sort of
415 * session. If an error occurred in the initial discovery0 or if an
416 * error occurred in the first step (and thus stopping the loop with
417 * state == 0) then there was an error before or during the attempt to
418 * start a session. Therefore we shouldn't attempt to terminate a
419 * session, as one has not yet been created.
David Kozub3db87232019-02-14 01:16:06 +0100420 */
David Kozub0af26482019-02-14 01:16:07 +0100421 if (state > 0)
David Kozub3db87232019-02-14 01:16:06 +0100422 end_opal_session_error(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -0700423
424 return error;
425}
426
427static int opal_discovery0_end(struct opal_dev *dev)
428{
429 bool found_com_id = false, supported = true, single_user = false;
430 const struct d0_header *hdr = (struct d0_header *)dev->resp;
431 const u8 *epos = dev->resp, *cpos = dev->resp;
432 u16 comid = 0;
Jon Derrick77039b92017-02-21 11:59:15 -0700433 u32 hlen = be32_to_cpu(hdr->length);
Scott Bauer455a7b22017-02-03 12:50:31 -0700434
Jon Derrick77039b92017-02-21 11:59:15 -0700435 print_buffer(dev->resp, hlen);
Scott Bauerdbec491b2017-09-01 08:53:35 -0600436 dev->mbr_enabled = false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700437
Jon Derrick77039b92017-02-21 11:59:15 -0700438 if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600439 pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
440 sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
Jon Derrick77039b92017-02-21 11:59:15 -0700441 return -EFAULT;
442 }
443
444 epos += hlen; /* end of buffer */
Scott Bauer455a7b22017-02-03 12:50:31 -0700445 cpos += sizeof(*hdr); /* current position on buffer */
446
447 while (cpos < epos && supported) {
448 const struct d0_features *body =
449 (const struct d0_features *)cpos;
450
451 switch (be16_to_cpu(body->code)) {
452 case FC_TPER:
453 supported = check_tper(body->features);
454 break;
455 case FC_SINGLEUSER:
456 single_user = check_sum(body->features);
457 break;
458 case FC_GEOMETRY:
459 check_geometry(dev, body);
460 break;
461 case FC_LOCKING:
Scott Bauerdbec491b2017-09-01 08:53:35 -0600462 dev->mbr_enabled = check_mbrenabled(body->features);
463 break;
Scott Bauer455a7b22017-02-03 12:50:31 -0700464 case FC_ENTERPRISE:
465 case FC_DATASTORE:
466 /* some ignored properties */
467 pr_debug("Found OPAL feature description: %d\n",
468 be16_to_cpu(body->code));
469 break;
470 case FC_OPALV100:
471 comid = get_comid_v100(body->features);
472 found_com_id = true;
473 break;
474 case FC_OPALV200:
475 comid = get_comid_v200(body->features);
476 found_com_id = true;
477 break;
478 case 0xbfff ... 0xffff:
479 /* vendor specific, just ignore */
480 break;
481 default:
482 pr_debug("OPAL Unknown feature: %d\n",
483 be16_to_cpu(body->code));
484
485 }
486 cpos += body->length + 4;
487 }
488
489 if (!supported) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100490 pr_debug("This device is not Opal enabled. Not Supported!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700491 return -EOPNOTSUPP;
492 }
493
494 if (!single_user)
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100495 pr_debug("Device doesn't support single user mode\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700496
497
498 if (!found_com_id) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100499 pr_debug("Could not find OPAL comid for device. Returning early\n");
Ingo Molnared7158b2018-02-22 10:54:55 +0100500 return -EOPNOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -0700501 }
502
503 dev->comid = comid;
504
505 return 0;
506}
507
Jon Derrickeed64952017-02-22 07:55:13 -0700508static int opal_discovery0(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -0700509{
510 int ret;
511
512 memset(dev->resp, 0, IO_BUFFER_LENGTH);
513 dev->comid = OPAL_DISCOVERY_COMID;
514 ret = opal_recv_cmd(dev);
515 if (ret)
516 return ret;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600517
Scott Bauer455a7b22017-02-03 12:50:31 -0700518 return opal_discovery0_end(dev);
519}
520
David Kozub0af26482019-02-14 01:16:07 +0100521static int opal_discovery0_step(struct opal_dev *dev)
522{
523 const struct opal_step discovery0_step = {
524 opal_discovery0,
525 };
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600526
David Kozub0af26482019-02-14 01:16:07 +0100527 return execute_step(dev, &discovery0_step, 0);
528}
529
Jonas Rabensteina9b25b42019-05-21 22:46:45 +0200530static size_t remaining_size(struct opal_dev *cmd)
531{
532 return IO_BUFFER_LENGTH - cmd->pos;
533}
534
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100535static bool can_add(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700536{
537 if (*err)
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100538 return false;
539
Jonas Rabensteina9b25b42019-05-21 22:46:45 +0200540 if (remaining_size(cmd) < len) {
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100541 pr_debug("Error adding %zu bytes: end of buffer.\n", len);
Scott Bauer455a7b22017-02-03 12:50:31 -0700542 *err = -ERANGE;
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100543 return false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700544 }
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100545
546 return true;
547}
548
549static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
550{
551 if (!can_add(err, cmd, 1))
552 return;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600553
Scott Bauer455a7b22017-02-03 12:50:31 -0700554 cmd->cmd[cmd->pos++] = tok;
555}
556
557static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
558 bool has_sign, int len)
559{
560 u8 atom;
561 int err = 0;
562
563 atom = SHORT_ATOM_ID;
564 atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
565 atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
566 atom |= len & SHORT_ATOM_LEN_MASK;
567
568 add_token_u8(&err, cmd, atom);
569}
570
571static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
572 bool has_sign, int len)
573{
574 u8 header0;
575
576 header0 = MEDIUM_ATOM_ID;
577 header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
578 header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
579 header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600580
Scott Bauer455a7b22017-02-03 12:50:31 -0700581 cmd->cmd[cmd->pos++] = header0;
582 cmd->cmd[cmd->pos++] = len;
583}
584
585static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
586{
Scott Bauer455a7b22017-02-03 12:50:31 -0700587 size_t len;
588 int msb;
Scott Bauer455a7b22017-02-03 12:50:31 -0700589
590 if (!(number & ~TINY_ATOM_DATA_MASK)) {
591 add_token_u8(err, cmd, number);
592 return;
593 }
594
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100595 msb = fls64(number);
596 len = DIV_ROUND_UP(msb, 8);
Scott Bauer455a7b22017-02-03 12:50:31 -0700597
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100598 if (!can_add(err, cmd, len + 1)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600599 pr_debug("Error adding u64: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700600 return;
601 }
602 add_short_atom_header(cmd, false, false, len);
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100603 while (len--)
604 add_token_u8(err, cmd, number >> (len * 8));
Scott Bauer455a7b22017-02-03 12:50:31 -0700605}
606
Jonas Rabenstein28559952019-02-14 01:16:02 +0100607static u8 *add_bytestring_header(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700608{
609 size_t header_len = 1;
610 bool is_short_atom = true;
611
Scott Bauer455a7b22017-02-03 12:50:31 -0700612 if (len & ~SHORT_ATOM_LEN_MASK) {
613 header_len = 2;
614 is_short_atom = false;
615 }
616
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100617 if (!can_add(err, cmd, header_len + len)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600618 pr_debug("Error adding bytestring: end of buffer.\n");
Jonas Rabenstein28559952019-02-14 01:16:02 +0100619 return NULL;
Scott Bauer455a7b22017-02-03 12:50:31 -0700620 }
621
622 if (is_short_atom)
623 add_short_atom_header(cmd, true, false, len);
624 else
625 add_medium_atom_header(cmd, true, false, len);
626
Jonas Rabenstein28559952019-02-14 01:16:02 +0100627 return &cmd->cmd[cmd->pos];
628}
Scott Bauer455a7b22017-02-03 12:50:31 -0700629
Jonas Rabenstein28559952019-02-14 01:16:02 +0100630static void add_token_bytestring(int *err, struct opal_dev *cmd,
631 const u8 *bytestring, size_t len)
632{
633 u8 *start;
634
635 start = add_bytestring_header(err, cmd, len);
636 if (!start)
637 return;
638 memcpy(start, bytestring, len);
639 cmd->pos += len;
Scott Bauer455a7b22017-02-03 12:50:31 -0700640}
641
642static int build_locking_range(u8 *buffer, size_t length, u8 lr)
643{
644 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600645 pr_debug("Can't build locking range. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700646 return -ERANGE;
647 }
648
649 memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
650
651 if (lr == 0)
652 return 0;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600653
Scott Bauer455a7b22017-02-03 12:50:31 -0700654 buffer[5] = LOCKING_RANGE_NON_GLOBAL;
655 buffer[7] = lr;
656
657 return 0;
658}
659
660static int build_locking_user(u8 *buffer, size_t length, u8 lr)
661{
662 if (length > OPAL_UID_LENGTH) {
David Kozub1e815b32019-02-14 01:15:54 +0100663 pr_debug("Can't build locking range user. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700664 return -ERANGE;
665 }
666
667 memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
668
669 buffer[7] = lr + 1;
670
671 return 0;
672}
673
674static void set_comid(struct opal_dev *cmd, u16 comid)
675{
676 struct opal_header *hdr = (struct opal_header *)cmd->cmd;
677
678 hdr->cp.extendedComID[0] = comid >> 8;
679 hdr->cp.extendedComID[1] = comid;
680 hdr->cp.extendedComID[2] = 0;
681 hdr->cp.extendedComID[3] = 0;
682}
683
684static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
685{
686 struct opal_header *hdr;
687 int err = 0;
688
Jonas Rabensteina9b25b42019-05-21 22:46:45 +0200689 /*
690 * Close the parameter list opened from cmd_start.
691 * The number of bytes added must be equal to
692 * CMD_FINALIZE_BYTES_NEEDED.
693 */
David Kozub78d584c2019-02-14 01:15:57 +0100694 add_token_u8(&err, cmd, OPAL_ENDLIST);
695
Scott Bauer455a7b22017-02-03 12:50:31 -0700696 add_token_u8(&err, cmd, OPAL_ENDOFDATA);
697 add_token_u8(&err, cmd, OPAL_STARTLIST);
698 add_token_u8(&err, cmd, 0);
699 add_token_u8(&err, cmd, 0);
700 add_token_u8(&err, cmd, 0);
701 add_token_u8(&err, cmd, OPAL_ENDLIST);
702
703 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600704 pr_debug("Error finalizing command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700705 return -EFAULT;
706 }
707
708 hdr = (struct opal_header *) cmd->cmd;
709
710 hdr->pkt.tsn = cpu_to_be32(tsn);
711 hdr->pkt.hsn = cpu_to_be32(hsn);
712
713 hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
714 while (cmd->pos % 4) {
715 if (cmd->pos >= IO_BUFFER_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600716 pr_debug("Error: Buffer overrun\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700717 return -ERANGE;
718 }
719 cmd->cmd[cmd->pos++] = 0;
720 }
721 hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
722 sizeof(hdr->pkt));
723 hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
724
725 return 0;
726}
727
Jon Derrickcccb9242017-02-21 11:59:14 -0700728static const struct opal_resp_tok *response_get_token(
729 const struct parsed_resp *resp,
730 int n)
Scott Bauer455a7b22017-02-03 12:50:31 -0700731{
732 const struct opal_resp_tok *tok;
733
David Kozub7d9b62a2019-02-14 01:15:59 +0100734 if (!resp) {
735 pr_debug("Response is NULL\n");
736 return ERR_PTR(-EINVAL);
737 }
738
Scott Bauer455a7b22017-02-03 12:50:31 -0700739 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600740 pr_debug("Token number doesn't exist: %d, resp: %d\n",
741 n, resp->num);
Jon Derrickcccb9242017-02-21 11:59:14 -0700742 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700743 }
744
745 tok = &resp->toks[n];
746 if (tok->len == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600747 pr_debug("Token length must be non-zero\n");
Jon Derrickcccb9242017-02-21 11:59:14 -0700748 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700749 }
750
Jon Derrickcccb9242017-02-21 11:59:14 -0700751 return tok;
Scott Bauer455a7b22017-02-03 12:50:31 -0700752}
753
Jon Derrickaedb6e22017-02-21 11:59:13 -0700754static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
755 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700756{
757 tok->pos = pos;
758 tok->len = 1;
759 tok->width = OPAL_WIDTH_TINY;
760
761 if (pos[0] & TINY_ATOM_SIGNED) {
762 tok->type = OPAL_DTA_TOKENID_SINT;
763 } else {
764 tok->type = OPAL_DTA_TOKENID_UINT;
765 tok->stored.u = pos[0] & 0x3f;
766 }
767
768 return tok->len;
769}
770
Jon Derrickaedb6e22017-02-21 11:59:13 -0700771static ssize_t response_parse_short(struct opal_resp_tok *tok,
772 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700773{
774 tok->pos = pos;
775 tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
776 tok->width = OPAL_WIDTH_SHORT;
777
778 if (pos[0] & SHORT_ATOM_BYTESTRING) {
779 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
780 } else if (pos[0] & SHORT_ATOM_SIGNED) {
781 tok->type = OPAL_DTA_TOKENID_SINT;
782 } else {
783 u64 u_integer = 0;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700784 ssize_t i, b = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700785
786 tok->type = OPAL_DTA_TOKENID_UINT;
787 if (tok->len > 9) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600788 pr_debug("uint64 with more than 8 bytes\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700789 return -EINVAL;
790 }
791 for (i = tok->len - 1; i > 0; i--) {
792 u_integer |= ((u64)pos[i] << (8 * b));
793 b++;
794 }
795 tok->stored.u = u_integer;
796 }
797
798 return tok->len;
799}
800
Jon Derrickaedb6e22017-02-21 11:59:13 -0700801static ssize_t response_parse_medium(struct opal_resp_tok *tok,
802 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700803{
804 tok->pos = pos;
805 tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
806 tok->width = OPAL_WIDTH_MEDIUM;
807
808 if (pos[0] & MEDIUM_ATOM_BYTESTRING)
809 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
810 else if (pos[0] & MEDIUM_ATOM_SIGNED)
811 tok->type = OPAL_DTA_TOKENID_SINT;
812 else
813 tok->type = OPAL_DTA_TOKENID_UINT;
814
815 return tok->len;
816}
817
Jon Derrickaedb6e22017-02-21 11:59:13 -0700818static ssize_t response_parse_long(struct opal_resp_tok *tok,
819 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700820{
821 tok->pos = pos;
822 tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
823 tok->width = OPAL_WIDTH_LONG;
824
825 if (pos[0] & LONG_ATOM_BYTESTRING)
826 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
827 else if (pos[0] & LONG_ATOM_SIGNED)
828 tok->type = OPAL_DTA_TOKENID_SINT;
829 else
830 tok->type = OPAL_DTA_TOKENID_UINT;
831
832 return tok->len;
833}
834
Jon Derrickaedb6e22017-02-21 11:59:13 -0700835static ssize_t response_parse_token(struct opal_resp_tok *tok,
836 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700837{
838 tok->pos = pos;
839 tok->len = 1;
840 tok->type = OPAL_DTA_TOKENID_TOKEN;
841 tok->width = OPAL_WIDTH_TOKEN;
842
843 return tok->len;
844}
845
846static int response_parse(const u8 *buf, size_t length,
847 struct parsed_resp *resp)
848{
849 const struct opal_header *hdr;
850 struct opal_resp_tok *iter;
851 int num_entries = 0;
852 int total;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700853 ssize_t token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700854 const u8 *pos;
Jon Derrick77039b92017-02-21 11:59:15 -0700855 u32 clen, plen, slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700856
857 if (!buf)
858 return -EFAULT;
859
860 if (!resp)
861 return -EFAULT;
862
863 hdr = (struct opal_header *)buf;
864 pos = buf;
865 pos += sizeof(*hdr);
866
Jon Derrick77039b92017-02-21 11:59:15 -0700867 clen = be32_to_cpu(hdr->cp.length);
868 plen = be32_to_cpu(hdr->pkt.length);
869 slen = be32_to_cpu(hdr->subpkt.length);
870 pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
871 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700872
Jon Derrick77039b92017-02-21 11:59:15 -0700873 if (clen == 0 || plen == 0 || slen == 0 ||
874 slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600875 pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
876 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700877 print_buffer(pos, sizeof(*hdr));
878 return -EINVAL;
879 }
880
881 if (pos > buf + length)
882 return -EFAULT;
883
884 iter = resp->toks;
Jon Derrick77039b92017-02-21 11:59:15 -0700885 total = slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700886 print_buffer(pos, total);
887 while (total > 0) {
888 if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
889 token_length = response_parse_tiny(iter, pos);
890 else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
891 token_length = response_parse_short(iter, pos);
892 else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
893 token_length = response_parse_medium(iter, pos);
894 else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
895 token_length = response_parse_long(iter, pos);
896 else /* TOKEN */
897 token_length = response_parse_token(iter, pos);
898
Jon Derrickaedb6e22017-02-21 11:59:13 -0700899 if (token_length < 0)
900 return token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700901
902 pos += token_length;
903 total -= token_length;
904 iter++;
905 num_entries++;
906 }
907
Scott Bauer455a7b22017-02-03 12:50:31 -0700908 resp->num = num_entries;
909
910 return 0;
911}
912
913static size_t response_get_string(const struct parsed_resp *resp, int n,
914 const char **store)
915{
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100916 u8 skip;
David Kozubb68f09e2019-02-14 01:16:00 +0100917 const struct opal_resp_tok *tok;
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100918
Scott Bauer455a7b22017-02-03 12:50:31 -0700919 *store = NULL;
David Kozubb68f09e2019-02-14 01:16:00 +0100920 tok = response_get_token(resp, n);
921 if (IS_ERR(tok))
Scott Bauer455a7b22017-02-03 12:50:31 -0700922 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700923
David Kozubb68f09e2019-02-14 01:16:00 +0100924 if (tok->type != OPAL_DTA_TOKENID_BYTESTRING) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600925 pr_debug("Token is not a byte string!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700926 return 0;
927 }
928
David Kozubb68f09e2019-02-14 01:16:00 +0100929 switch (tok->width) {
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100930 case OPAL_WIDTH_TINY:
931 case OPAL_WIDTH_SHORT:
932 skip = 1;
933 break;
934 case OPAL_WIDTH_MEDIUM:
935 skip = 2;
936 break;
937 case OPAL_WIDTH_LONG:
938 skip = 4;
939 break;
940 default:
941 pr_debug("Token has invalid width!\n");
942 return 0;
943 }
944
David Kozubb68f09e2019-02-14 01:16:00 +0100945 *store = tok->pos + skip;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -0600946
David Kozubb68f09e2019-02-14 01:16:00 +0100947 return tok->len - skip;
Scott Bauer455a7b22017-02-03 12:50:31 -0700948}
949
950static u64 response_get_u64(const struct parsed_resp *resp, int n)
951{
David Kozubb68f09e2019-02-14 01:16:00 +0100952 const struct opal_resp_tok *tok;
953
954 tok = response_get_token(resp, n);
955 if (IS_ERR(tok))
956 return 0;
957
958 if (tok->type != OPAL_DTA_TOKENID_UINT) {
959 pr_debug("Token is not unsigned int: %d\n", tok->type);
Scott Bauer455a7b22017-02-03 12:50:31 -0700960 return 0;
961 }
962
David Kozubb68f09e2019-02-14 01:16:00 +0100963 if (tok->width != OPAL_WIDTH_TINY && tok->width != OPAL_WIDTH_SHORT) {
964 pr_debug("Atom is not short or tiny: %d\n", tok->width);
Scott Bauer455a7b22017-02-03 12:50:31 -0700965 return 0;
966 }
967
David Kozubb68f09e2019-02-14 01:16:00 +0100968 return tok->stored.u;
Scott Bauer455a7b22017-02-03 12:50:31 -0700969}
970
Jon Derrickcccb9242017-02-21 11:59:14 -0700971static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
972{
973 if (IS_ERR(token) ||
974 token->type != OPAL_DTA_TOKENID_TOKEN ||
975 token->pos[0] != match)
976 return false;
977 return true;
978}
979
Scott Bauer455a7b22017-02-03 12:50:31 -0700980static u8 response_status(const struct parsed_resp *resp)
981{
Jon Derrickcccb9242017-02-21 11:59:14 -0700982 const struct opal_resp_tok *tok;
983
984 tok = response_get_token(resp, 0);
985 if (response_token_matches(tok, OPAL_ENDOFSESSION))
Scott Bauer455a7b22017-02-03 12:50:31 -0700986 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700987
988 if (resp->num < 5)
989 return DTAERROR_NO_METHOD_STATUS;
990
Jon Derrickcccb9242017-02-21 11:59:14 -0700991 tok = response_get_token(resp, resp->num - 5);
992 if (!response_token_matches(tok, OPAL_STARTLIST))
993 return DTAERROR_NO_METHOD_STATUS;
994
995 tok = response_get_token(resp, resp->num - 1);
996 if (!response_token_matches(tok, OPAL_ENDLIST))
Scott Bauer455a7b22017-02-03 12:50:31 -0700997 return DTAERROR_NO_METHOD_STATUS;
998
999 return response_get_u64(resp, resp->num - 4);
1000}
1001
1002/* Parses and checks for errors */
1003static int parse_and_check_status(struct opal_dev *dev)
1004{
1005 int error;
1006
1007 print_buffer(dev->cmd, dev->pos);
1008
1009 error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
1010 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001011 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001012 return error;
1013 }
1014
1015 return response_status(&dev->parsed);
1016}
1017
1018static void clear_opal_cmd(struct opal_dev *dev)
1019{
1020 dev->pos = sizeof(struct opal_header);
1021 memset(dev->cmd, 0, IO_BUFFER_LENGTH);
1022}
1023
David Kozube8b29222019-02-14 01:15:58 +01001024static int cmd_start(struct opal_dev *dev, const u8 *uid, const u8 *method)
1025{
1026 int err = 0;
1027
1028 clear_opal_cmd(dev);
1029 set_comid(dev, dev->comid);
1030
1031 add_token_u8(&err, dev, OPAL_CALL);
1032 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1033 add_token_bytestring(&err, dev, method, OPAL_METHOD_LENGTH);
1034
1035 /*
1036 * Every method call is followed by its parameters enclosed within
1037 * OPAL_STARTLIST and OPAL_ENDLIST tokens. We automatically open the
1038 * parameter list here and close it later in cmd_finalize.
1039 */
1040 add_token_u8(&err, dev, OPAL_STARTLIST);
1041
1042 return err;
1043}
1044
Scott Bauer455a7b22017-02-03 12:50:31 -07001045static int start_opal_session_cont(struct opal_dev *dev)
1046{
1047 u32 hsn, tsn;
1048 int error = 0;
1049
1050 error = parse_and_check_status(dev);
1051 if (error)
1052 return error;
1053
1054 hsn = response_get_u64(&dev->parsed, 4);
1055 tsn = response_get_u64(&dev->parsed, 5);
1056
1057 if (hsn == 0 && tsn == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001058 pr_debug("Couldn't authenticate session\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001059 return -EPERM;
1060 }
1061
1062 dev->hsn = hsn;
1063 dev->tsn = tsn;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001064
Scott Bauer455a7b22017-02-03 12:50:31 -07001065 return 0;
1066}
1067
1068static void add_suspend_info(struct opal_dev *dev,
1069 struct opal_suspend_data *sus)
1070{
1071 struct opal_suspend_data *iter;
1072
1073 list_for_each_entry(iter, &dev->unlk_lst, node) {
1074 if (iter->lr == sus->lr) {
1075 list_del(&iter->node);
1076 kfree(iter);
1077 break;
1078 }
1079 }
1080 list_add_tail(&sus->node, &dev->unlk_lst);
1081}
1082
1083static int end_session_cont(struct opal_dev *dev)
1084{
1085 dev->hsn = 0;
1086 dev->tsn = 0;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001087
Scott Bauer455a7b22017-02-03 12:50:31 -07001088 return parse_and_check_status(dev);
1089}
1090
1091static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1092{
1093 int ret;
1094
1095 ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1096 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001097 pr_debug("Error finalizing command buffer: %d\n", ret);
Scott Bauer455a7b22017-02-03 12:50:31 -07001098 return ret;
1099 }
1100
1101 print_buffer(dev->cmd, dev->pos);
1102
1103 return opal_send_recv(dev, cont);
1104}
1105
David Kozub3fff2342019-02-14 01:16:04 +01001106/*
1107 * request @column from table @table on device @dev. On success, the column
1108 * data will be available in dev->resp->tok[4]
1109 */
1110static int generic_get_column(struct opal_dev *dev, const u8 *table,
1111 u64 column)
1112{
1113 int err;
1114
1115 err = cmd_start(dev, table, opalmethod[OPAL_GET]);
1116
1117 add_token_u8(&err, dev, OPAL_STARTLIST);
1118
1119 add_token_u8(&err, dev, OPAL_STARTNAME);
1120 add_token_u8(&err, dev, OPAL_STARTCOLUMN);
1121 add_token_u64(&err, dev, column);
1122 add_token_u8(&err, dev, OPAL_ENDNAME);
1123
1124 add_token_u8(&err, dev, OPAL_STARTNAME);
1125 add_token_u8(&err, dev, OPAL_ENDCOLUMN);
1126 add_token_u64(&err, dev, column);
1127 add_token_u8(&err, dev, OPAL_ENDNAME);
1128
1129 add_token_u8(&err, dev, OPAL_ENDLIST);
1130
1131 if (err)
1132 return err;
1133
1134 return finalize_and_send(dev, parse_and_check_status);
1135}
1136
Jonas Rabensteinff910642019-05-21 22:46:46 +02001137/*
1138 * see TCG SAS 5.3.2.3 for a description of the available columns
1139 *
1140 * the result is provided in dev->resp->tok[4]
1141 */
1142static int generic_get_table_info(struct opal_dev *dev, enum opal_uid table,
1143 u64 column)
1144{
1145 u8 uid[OPAL_UID_LENGTH];
1146 const unsigned int half = OPAL_UID_LENGTH/2;
1147
1148 /* sed-opal UIDs can be split in two halves:
1149 * first: actual table index
1150 * second: relative index in the table
1151 * so we have to get the first half of the OPAL_TABLE_TABLE and use the
1152 * first part of the target table as relative index into that table
1153 */
1154 memcpy(uid, opaluid[OPAL_TABLE_TABLE], half);
1155 memcpy(uid+half, opaluid[table], half);
1156
1157 return generic_get_column(dev, uid, column);
1158}
1159
Jon Derrickeed64952017-02-22 07:55:13 -07001160static int gen_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001161{
Scott Bauer455a7b22017-02-03 12:50:31 -07001162 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001163 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001164
1165 memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
Scott Bauer455a7b22017-02-03 12:50:31 -07001166 kfree(dev->prev_data);
1167 dev->prev_data = NULL;
1168
David Kozube8b29222019-02-14 01:15:58 +01001169 err = cmd_start(dev, uid, opalmethod[OPAL_GENKEY]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001170
1171 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001172 pr_debug("Error building gen key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001173 return err;
1174
1175 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001176
Scott Bauer455a7b22017-02-03 12:50:31 -07001177 return finalize_and_send(dev, parse_and_check_status);
1178}
1179
1180static int get_active_key_cont(struct opal_dev *dev)
1181{
1182 const char *activekey;
1183 size_t keylen;
1184 int error = 0;
1185
1186 error = parse_and_check_status(dev);
1187 if (error)
1188 return error;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001189
Scott Bauer455a7b22017-02-03 12:50:31 -07001190 keylen = response_get_string(&dev->parsed, 4, &activekey);
1191 if (!activekey) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001192 pr_debug("%s: Couldn't extract the Activekey from the response\n",
1193 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001194 return OPAL_INVAL_PARAM;
1195 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001196
Scott Bauer455a7b22017-02-03 12:50:31 -07001197 dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1198
1199 if (!dev->prev_data)
1200 return -ENOMEM;
1201
1202 dev->prev_d_len = keylen;
1203
1204 return 0;
1205}
1206
Jon Derrickeed64952017-02-22 07:55:13 -07001207static int get_active_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001208{
1209 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001210 int err;
Jon Derrickeed64952017-02-22 07:55:13 -07001211 u8 *lr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001212
Scott Bauer455a7b22017-02-03 12:50:31 -07001213 err = build_locking_range(uid, sizeof(uid), *lr);
1214 if (err)
1215 return err;
1216
David Kozub3fff2342019-02-14 01:16:04 +01001217 err = generic_get_column(dev, uid, OPAL_ACTIVEKEY);
1218 if (err)
Scott Bauer455a7b22017-02-03 12:50:31 -07001219 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001220
David Kozub3fff2342019-02-14 01:16:04 +01001221 return get_active_key_cont(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001222}
1223
1224static int generic_lr_enable_disable(struct opal_dev *dev,
1225 u8 *uid, bool rle, bool wle,
1226 bool rl, bool wl)
1227{
David Kozube8b29222019-02-14 01:15:58 +01001228 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001229
David Kozube8b29222019-02-14 01:15:58 +01001230 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001231
Scott Bauer455a7b22017-02-03 12:50:31 -07001232 add_token_u8(&err, dev, OPAL_STARTNAME);
1233 add_token_u8(&err, dev, OPAL_VALUES);
1234 add_token_u8(&err, dev, OPAL_STARTLIST);
1235
1236 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001237 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001238 add_token_u8(&err, dev, rle);
1239 add_token_u8(&err, dev, OPAL_ENDNAME);
1240
1241 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001242 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001243 add_token_u8(&err, dev, wle);
1244 add_token_u8(&err, dev, OPAL_ENDNAME);
1245
1246 add_token_u8(&err, dev, OPAL_STARTNAME);
1247 add_token_u8(&err, dev, OPAL_READLOCKED);
1248 add_token_u8(&err, dev, rl);
1249 add_token_u8(&err, dev, OPAL_ENDNAME);
1250
1251 add_token_u8(&err, dev, OPAL_STARTNAME);
1252 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1253 add_token_u8(&err, dev, wl);
1254 add_token_u8(&err, dev, OPAL_ENDNAME);
1255
1256 add_token_u8(&err, dev, OPAL_ENDLIST);
1257 add_token_u8(&err, dev, OPAL_ENDNAME);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001258
Scott Bauer455a7b22017-02-03 12:50:31 -07001259 return err;
1260}
1261
1262static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1263 struct opal_user_lr_setup *setup)
1264{
1265 int err;
1266
1267 err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1268 0, 0);
1269 if (err)
Scott Bauer591c59d2017-04-07 13:58:50 -06001270 pr_debug("Failed to create enable global lr command\n");
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001271
Scott Bauer455a7b22017-02-03 12:50:31 -07001272 return err;
1273}
1274
Jon Derrickeed64952017-02-22 07:55:13 -07001275static int setup_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001276{
1277 u8 uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001278 struct opal_user_lr_setup *setup = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001279 u8 lr;
David Kozube8b29222019-02-14 01:15:58 +01001280 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001281
Scott Bauer455a7b22017-02-03 12:50:31 -07001282 lr = setup->session.opal_key.lr;
1283 err = build_locking_range(uid, sizeof(uid), lr);
1284 if (err)
1285 return err;
1286
1287 if (lr == 0)
1288 err = enable_global_lr(dev, uid, setup);
1289 else {
David Kozube8b29222019-02-14 01:15:58 +01001290 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001291
Scott Bauer455a7b22017-02-03 12:50:31 -07001292 add_token_u8(&err, dev, OPAL_STARTNAME);
1293 add_token_u8(&err, dev, OPAL_VALUES);
1294 add_token_u8(&err, dev, OPAL_STARTLIST);
1295
1296 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001297 add_token_u8(&err, dev, OPAL_RANGESTART);
Scott Bauer455a7b22017-02-03 12:50:31 -07001298 add_token_u64(&err, dev, setup->range_start);
1299 add_token_u8(&err, dev, OPAL_ENDNAME);
1300
1301 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001302 add_token_u8(&err, dev, OPAL_RANGELENGTH);
Scott Bauer455a7b22017-02-03 12:50:31 -07001303 add_token_u64(&err, dev, setup->range_length);
1304 add_token_u8(&err, dev, OPAL_ENDNAME);
1305
1306 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001307 add_token_u8(&err, dev, OPAL_READLOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001308 add_token_u64(&err, dev, !!setup->RLE);
1309 add_token_u8(&err, dev, OPAL_ENDNAME);
1310
1311 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001312 add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
Scott Bauer455a7b22017-02-03 12:50:31 -07001313 add_token_u64(&err, dev, !!setup->WLE);
1314 add_token_u8(&err, dev, OPAL_ENDNAME);
1315
1316 add_token_u8(&err, dev, OPAL_ENDLIST);
1317 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001318 }
1319 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001320 pr_debug("Error building Setup Locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001321 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001322 }
1323
1324 return finalize_and_send(dev, parse_and_check_status);
1325}
1326
1327static int start_generic_opal_session(struct opal_dev *dev,
1328 enum opal_uid auth,
1329 enum opal_uid sp_type,
1330 const char *key,
1331 u8 key_len)
1332{
1333 u32 hsn;
David Kozube8b29222019-02-14 01:15:58 +01001334 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001335
Scott Bauer591c59d2017-04-07 13:58:50 -06001336 if (key == NULL && auth != OPAL_ANYBODY_UID)
Scott Bauer455a7b22017-02-03 12:50:31 -07001337 return OPAL_INVAL_PARAM;
Scott Bauer455a7b22017-02-03 12:50:31 -07001338
Scott Bauer455a7b22017-02-03 12:50:31 -07001339 hsn = GENERIC_HOST_SESSION_NUM;
David Kozube8b29222019-02-14 01:15:58 +01001340 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1341 opalmethod[OPAL_STARTSESSION]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001342
Scott Bauer455a7b22017-02-03 12:50:31 -07001343 add_token_u64(&err, dev, hsn);
1344 add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1345 add_token_u8(&err, dev, 1);
1346
1347 switch (auth) {
1348 case OPAL_ANYBODY_UID:
Scott Bauer455a7b22017-02-03 12:50:31 -07001349 break;
1350 case OPAL_ADMIN1_UID:
1351 case OPAL_SID_UID:
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06001352 case OPAL_PSID_UID:
Scott Bauer455a7b22017-02-03 12:50:31 -07001353 add_token_u8(&err, dev, OPAL_STARTNAME);
1354 add_token_u8(&err, dev, 0); /* HostChallenge */
1355 add_token_bytestring(&err, dev, key, key_len);
1356 add_token_u8(&err, dev, OPAL_ENDNAME);
1357 add_token_u8(&err, dev, OPAL_STARTNAME);
1358 add_token_u8(&err, dev, 3); /* HostSignAuth */
1359 add_token_bytestring(&err, dev, opaluid[auth],
1360 OPAL_UID_LENGTH);
1361 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001362 break;
1363 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001364 pr_debug("Cannot start Admin SP session with auth %d\n", auth);
Scott Bauer455a7b22017-02-03 12:50:31 -07001365 return OPAL_INVAL_PARAM;
1366 }
1367
1368 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001369 pr_debug("Error building start adminsp session command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001370 return err;
1371 }
1372
1373 return finalize_and_send(dev, start_opal_session_cont);
1374}
1375
Jon Derrickeed64952017-02-22 07:55:13 -07001376static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001377{
1378 return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1379 OPAL_ADMINSP_UID, NULL, 0);
1380}
1381
Jon Derrickeed64952017-02-22 07:55:13 -07001382static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001383{
1384 int ret;
1385 const u8 *key = dev->prev_data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001386
1387 if (!key) {
Jon Derrickeed64952017-02-22 07:55:13 -07001388 const struct opal_key *okey = data;
David Kozub1e815b32019-02-14 01:15:54 +01001389
Scott Bauer455a7b22017-02-03 12:50:31 -07001390 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1391 OPAL_ADMINSP_UID,
1392 okey->key,
1393 okey->key_len);
1394 } else {
1395 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1396 OPAL_ADMINSP_UID,
1397 key, dev->prev_d_len);
1398 kfree(key);
1399 dev->prev_data = NULL;
1400 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001401
Scott Bauer455a7b22017-02-03 12:50:31 -07001402 return ret;
1403}
1404
Jon Derrickeed64952017-02-22 07:55:13 -07001405static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001406{
Jon Derrickeed64952017-02-22 07:55:13 -07001407 struct opal_key *key = data;
David Kozub1e815b32019-02-14 01:15:54 +01001408
Scott Bauer455a7b22017-02-03 12:50:31 -07001409 return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1410 OPAL_LOCKINGSP_UID,
1411 key->key, key->key_len);
1412}
1413
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06001414static int start_PSID_opal_session(struct opal_dev *dev, void *data)
1415{
1416 const struct opal_key *okey = data;
1417
1418 return start_generic_opal_session(dev, OPAL_PSID_UID,
1419 OPAL_ADMINSP_UID,
1420 okey->key,
1421 okey->key_len);
1422}
1423
Jon Derrickeed64952017-02-22 07:55:13 -07001424static int start_auth_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001425{
Jon Derrickeed64952017-02-22 07:55:13 -07001426 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001427 u8 lk_ul_user[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001428 size_t keylen = session->opal_key.key_len;
Scott Bauer455a7b22017-02-03 12:50:31 -07001429 int err = 0;
1430
Scott Bauer455a7b22017-02-03 12:50:31 -07001431 u8 *key = session->opal_key.key;
1432 u32 hsn = GENERIC_HOST_SESSION_NUM;
1433
David Kozube8b29222019-02-14 01:15:58 +01001434 if (session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001435 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1436 session->opal_key.lr);
David Kozube8b29222019-02-14 01:15:58 +01001437 else if (session->who != OPAL_ADMIN1 && !session->sum)
Scott Bauer455a7b22017-02-03 12:50:31 -07001438 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1439 session->who - 1);
David Kozube8b29222019-02-14 01:15:58 +01001440 else
Scott Bauer455a7b22017-02-03 12:50:31 -07001441 memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1442
David Kozube8b29222019-02-14 01:15:58 +01001443 if (err)
1444 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001445
David Kozube8b29222019-02-14 01:15:58 +01001446 err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1447 opalmethod[OPAL_STARTSESSION]);
1448
Scott Bauer455a7b22017-02-03 12:50:31 -07001449 add_token_u64(&err, dev, hsn);
1450 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1451 OPAL_UID_LENGTH);
1452 add_token_u8(&err, dev, 1);
1453 add_token_u8(&err, dev, OPAL_STARTNAME);
1454 add_token_u8(&err, dev, 0);
1455 add_token_bytestring(&err, dev, key, keylen);
1456 add_token_u8(&err, dev, OPAL_ENDNAME);
1457 add_token_u8(&err, dev, OPAL_STARTNAME);
1458 add_token_u8(&err, dev, 3);
1459 add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1460 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001461
1462 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001463 pr_debug("Error building STARTSESSION command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001464 return err;
1465 }
1466
1467 return finalize_and_send(dev, start_opal_session_cont);
1468}
1469
Jon Derrickeed64952017-02-22 07:55:13 -07001470static int revert_tper(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001471{
David Kozube8b29222019-02-14 01:15:58 +01001472 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001473
David Kozube8b29222019-02-14 01:15:58 +01001474 err = cmd_start(dev, opaluid[OPAL_ADMINSP_UID],
1475 opalmethod[OPAL_REVERT]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001476 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001477 pr_debug("Error building REVERT TPER command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001478 return err;
1479 }
1480
1481 return finalize_and_send(dev, parse_and_check_status);
1482}
1483
Jon Derrickeed64952017-02-22 07:55:13 -07001484static int internal_activate_user(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001485{
Jon Derrickeed64952017-02-22 07:55:13 -07001486 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001487 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001488 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001489
1490 memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1491 uid[7] = session->who;
1492
David Kozube8b29222019-02-14 01:15:58 +01001493 err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001494 add_token_u8(&err, dev, OPAL_STARTNAME);
1495 add_token_u8(&err, dev, OPAL_VALUES);
1496 add_token_u8(&err, dev, OPAL_STARTLIST);
1497 add_token_u8(&err, dev, OPAL_STARTNAME);
1498 add_token_u8(&err, dev, 5); /* Enabled */
1499 add_token_u8(&err, dev, OPAL_TRUE);
1500 add_token_u8(&err, dev, OPAL_ENDNAME);
1501 add_token_u8(&err, dev, OPAL_ENDLIST);
1502 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001503
1504 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001505 pr_debug("Error building Activate UserN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001506 return err;
1507 }
1508
1509 return finalize_and_send(dev, parse_and_check_status);
1510}
1511
Jon Derrickeed64952017-02-22 07:55:13 -07001512static int erase_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001513{
Jon Derrickeed64952017-02-22 07:55:13 -07001514 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001515 u8 uid[OPAL_UID_LENGTH];
David Kozube8b29222019-02-14 01:15:58 +01001516 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001517
1518 if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1519 return -ERANGE;
1520
David Kozube8b29222019-02-14 01:15:58 +01001521 err = cmd_start(dev, uid, opalmethod[OPAL_ERASE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001522
1523 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001524 pr_debug("Error building Erase Locking Range Command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001525 return err;
1526 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001527
Scott Bauer455a7b22017-02-03 12:50:31 -07001528 return finalize_and_send(dev, parse_and_check_status);
1529}
1530
Jon Derrickeed64952017-02-22 07:55:13 -07001531static int set_mbr_done(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001532{
Jon Derrickeed64952017-02-22 07:55:13 -07001533 u8 *mbr_done_tf = data;
David Kozube8b29222019-02-14 01:15:58 +01001534 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001535
David Kozube8b29222019-02-14 01:15:58 +01001536 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1537 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001538
Scott Bauer455a7b22017-02-03 12:50:31 -07001539 add_token_u8(&err, dev, OPAL_STARTNAME);
1540 add_token_u8(&err, dev, OPAL_VALUES);
1541 add_token_u8(&err, dev, OPAL_STARTLIST);
1542 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001543 add_token_u8(&err, dev, OPAL_MBRDONE);
Jon Derrickeed64952017-02-22 07:55:13 -07001544 add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
Scott Bauer455a7b22017-02-03 12:50:31 -07001545 add_token_u8(&err, dev, OPAL_ENDNAME);
1546 add_token_u8(&err, dev, OPAL_ENDLIST);
1547 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001548
1549 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001550 pr_debug("Error Building set MBR Done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001551 return err;
1552 }
1553
1554 return finalize_and_send(dev, parse_and_check_status);
1555}
1556
Jon Derrickeed64952017-02-22 07:55:13 -07001557static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001558{
Jon Derrickeed64952017-02-22 07:55:13 -07001559 u8 *mbr_en_dis = data;
David Kozube8b29222019-02-14 01:15:58 +01001560 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001561
David Kozube8b29222019-02-14 01:15:58 +01001562 err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1563 opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001564
Scott Bauer455a7b22017-02-03 12:50:31 -07001565 add_token_u8(&err, dev, OPAL_STARTNAME);
1566 add_token_u8(&err, dev, OPAL_VALUES);
1567 add_token_u8(&err, dev, OPAL_STARTLIST);
1568 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001569 add_token_u8(&err, dev, OPAL_MBRENABLE);
Jon Derrickeed64952017-02-22 07:55:13 -07001570 add_token_u8(&err, dev, *mbr_en_dis);
Scott Bauer455a7b22017-02-03 12:50:31 -07001571 add_token_u8(&err, dev, OPAL_ENDNAME);
1572 add_token_u8(&err, dev, OPAL_ENDLIST);
1573 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001574
1575 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001576 pr_debug("Error Building set MBR done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001577 return err;
1578 }
1579
1580 return finalize_and_send(dev, parse_and_check_status);
1581}
1582
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02001583static int write_shadow_mbr(struct opal_dev *dev, void *data)
1584{
1585 struct opal_shadow_mbr *shadow = data;
1586 const u8 __user *src;
1587 u8 *dst;
1588 size_t off = 0;
1589 u64 len;
1590 int err = 0;
1591
Jonas Rabensteinff910642019-05-21 22:46:46 +02001592 /* do we fit in the available shadow mbr space? */
1593 err = generic_get_table_info(dev, OPAL_MBR, OPAL_TABLE_ROWS);
1594 if (err) {
1595 pr_debug("MBR: could not get shadow size\n");
1596 return err;
1597 }
1598
1599 len = response_get_u64(&dev->parsed, 4);
1600 if (shadow->size > len || shadow->offset > len - shadow->size) {
1601 pr_debug("MBR: does not fit in shadow (%llu vs. %llu)\n",
1602 shadow->offset + shadow->size, len);
1603 return -ENOSPC;
1604 }
1605
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02001606 /* do the actual transmission(s) */
1607 src = (u8 __user *)(uintptr_t)shadow->data;
1608 while (off < shadow->size) {
1609 err = cmd_start(dev, opaluid[OPAL_MBR], opalmethod[OPAL_SET]);
1610 add_token_u8(&err, dev, OPAL_STARTNAME);
1611 add_token_u8(&err, dev, OPAL_WHERE);
1612 add_token_u64(&err, dev, shadow->offset + off);
1613 add_token_u8(&err, dev, OPAL_ENDNAME);
1614
1615 add_token_u8(&err, dev, OPAL_STARTNAME);
1616 add_token_u8(&err, dev, OPAL_VALUES);
1617
1618 /*
1619 * The bytestring header is either 1 or 2 bytes, so assume 2.
1620 * There also needs to be enough space to accommodate the
1621 * trailing OPAL_ENDNAME (1 byte) and tokens added by
1622 * cmd_finalize.
1623 */
1624 len = min(remaining_size(dev) - (2+1+CMD_FINALIZE_BYTES_NEEDED),
1625 (size_t)(shadow->size - off));
1626 pr_debug("MBR: write bytes %zu+%llu/%llu\n",
1627 off, len, shadow->size);
1628
1629 dst = add_bytestring_header(&err, dev, len);
1630 if (!dst)
1631 break;
1632 if (copy_from_user(dst, src + off, len))
1633 err = -EFAULT;
1634 dev->pos += len;
1635
1636 add_token_u8(&err, dev, OPAL_ENDNAME);
1637 if (err)
1638 break;
1639
1640 err = finalize_and_send(dev, parse_and_check_status);
1641 if (err)
1642 break;
1643
1644 off += len;
1645 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001646
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02001647 return err;
1648}
1649
Scott Bauer455a7b22017-02-03 12:50:31 -07001650static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1651 struct opal_dev *dev)
1652{
David Kozube8b29222019-02-14 01:15:58 +01001653 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001654
David Kozube8b29222019-02-14 01:15:58 +01001655 err = cmd_start(dev, cpin_uid, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001656
Scott Bauer455a7b22017-02-03 12:50:31 -07001657 add_token_u8(&err, dev, OPAL_STARTNAME);
1658 add_token_u8(&err, dev, OPAL_VALUES);
1659 add_token_u8(&err, dev, OPAL_STARTLIST);
1660 add_token_u8(&err, dev, OPAL_STARTNAME);
David Kozub372be402019-02-14 01:16:05 +01001661 add_token_u8(&err, dev, OPAL_PIN);
Scott Bauer455a7b22017-02-03 12:50:31 -07001662 add_token_bytestring(&err, dev, key, key_len);
1663 add_token_u8(&err, dev, OPAL_ENDNAME);
1664 add_token_u8(&err, dev, OPAL_ENDLIST);
1665 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001666
1667 return err;
1668}
1669
Jon Derrickeed64952017-02-22 07:55:13 -07001670static int set_new_pw(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001671{
1672 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001673 struct opal_session_info *usr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001674
1675 memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1676
1677 if (usr->who != OPAL_ADMIN1) {
1678 cpin_uid[5] = 0x03;
1679 if (usr->sum)
1680 cpin_uid[7] = usr->opal_key.lr + 1;
1681 else
1682 cpin_uid[7] = usr->who;
1683 }
1684
1685 if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1686 cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001687 pr_debug("Error building set password command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001688 return -ERANGE;
1689 }
1690
1691 return finalize_and_send(dev, parse_and_check_status);
1692}
1693
Jon Derrickeed64952017-02-22 07:55:13 -07001694static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001695{
1696 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001697 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001698
1699 memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1700
1701 if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001702 pr_debug("Error building Set SID cpin\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001703 return -ERANGE;
1704 }
1705 return finalize_and_send(dev, parse_and_check_status);
1706}
1707
Jon Derrickeed64952017-02-22 07:55:13 -07001708static int add_user_to_lr(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001709{
1710 u8 lr_buffer[OPAL_UID_LENGTH];
1711 u8 user_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001712 struct opal_lock_unlock *lkul = data;
David Kozube8b29222019-02-14 01:15:58 +01001713 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001714
Scott Bauer455a7b22017-02-03 12:50:31 -07001715 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1716 OPAL_UID_LENGTH);
1717
1718 if (lkul->l_state == OPAL_RW)
1719 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1720 OPAL_UID_LENGTH);
1721
1722 lr_buffer[7] = lkul->session.opal_key.lr;
1723
1724 memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1725
1726 user_uid[7] = lkul->session.who;
1727
David Kozube8b29222019-02-14 01:15:58 +01001728 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001729
Scott Bauer455a7b22017-02-03 12:50:31 -07001730 add_token_u8(&err, dev, OPAL_STARTNAME);
1731 add_token_u8(&err, dev, OPAL_VALUES);
1732
1733 add_token_u8(&err, dev, OPAL_STARTLIST);
1734 add_token_u8(&err, dev, OPAL_STARTNAME);
1735 add_token_u8(&err, dev, 3);
1736
1737 add_token_u8(&err, dev, OPAL_STARTLIST);
1738
1739
1740 add_token_u8(&err, dev, OPAL_STARTNAME);
1741 add_token_bytestring(&err, dev,
1742 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1743 OPAL_UID_LENGTH/2);
1744 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1745 add_token_u8(&err, dev, OPAL_ENDNAME);
1746
1747
1748 add_token_u8(&err, dev, OPAL_STARTNAME);
1749 add_token_bytestring(&err, dev,
1750 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1751 OPAL_UID_LENGTH/2);
1752 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1753 add_token_u8(&err, dev, OPAL_ENDNAME);
1754
1755
1756 add_token_u8(&err, dev, OPAL_STARTNAME);
1757 add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1758 OPAL_UID_LENGTH/2);
1759 add_token_u8(&err, dev, 1);
1760 add_token_u8(&err, dev, OPAL_ENDNAME);
1761
1762
1763 add_token_u8(&err, dev, OPAL_ENDLIST);
1764 add_token_u8(&err, dev, OPAL_ENDNAME);
1765 add_token_u8(&err, dev, OPAL_ENDLIST);
1766 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001767
1768 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001769 pr_debug("Error building add user to locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001770 return err;
1771 }
1772
1773 return finalize_and_send(dev, parse_and_check_status);
1774}
1775
Jon Derrickeed64952017-02-22 07:55:13 -07001776static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001777{
1778 u8 lr_buffer[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001779 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001780 u8 read_locked = 1, write_locked = 1;
1781 int err = 0;
1782
Scott Bauer455a7b22017-02-03 12:50:31 -07001783 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1784 lkul->session.opal_key.lr) < 0)
1785 return -ERANGE;
1786
1787 switch (lkul->l_state) {
1788 case OPAL_RO:
1789 read_locked = 0;
1790 write_locked = 1;
1791 break;
1792 case OPAL_RW:
1793 read_locked = 0;
1794 write_locked = 0;
1795 break;
1796 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001797 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001798 break;
1799 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001800 pr_debug("Tried to set an invalid locking state... returning to uland\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001801 return OPAL_INVAL_PARAM;
1802 }
1803
David Kozube8b29222019-02-14 01:15:58 +01001804 err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
1805
Scott Bauer455a7b22017-02-03 12:50:31 -07001806 add_token_u8(&err, dev, OPAL_STARTNAME);
1807 add_token_u8(&err, dev, OPAL_VALUES);
1808 add_token_u8(&err, dev, OPAL_STARTLIST);
1809
1810 add_token_u8(&err, dev, OPAL_STARTNAME);
1811 add_token_u8(&err, dev, OPAL_READLOCKED);
1812 add_token_u8(&err, dev, read_locked);
1813 add_token_u8(&err, dev, OPAL_ENDNAME);
1814
1815 add_token_u8(&err, dev, OPAL_STARTNAME);
1816 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1817 add_token_u8(&err, dev, write_locked);
1818 add_token_u8(&err, dev, OPAL_ENDNAME);
1819
1820 add_token_u8(&err, dev, OPAL_ENDLIST);
1821 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001822
1823 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001824 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001825 return err;
1826 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001827
Scott Bauer455a7b22017-02-03 12:50:31 -07001828 return finalize_and_send(dev, parse_and_check_status);
1829}
1830
1831
Jon Derrickeed64952017-02-22 07:55:13 -07001832static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001833{
1834 u8 lr_buffer[OPAL_UID_LENGTH];
1835 u8 read_locked = 1, write_locked = 1;
Jon Derrickeed64952017-02-22 07:55:13 -07001836 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001837 int ret;
1838
1839 clear_opal_cmd(dev);
1840 set_comid(dev, dev->comid);
1841
Scott Bauer455a7b22017-02-03 12:50:31 -07001842 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1843 lkul->session.opal_key.lr) < 0)
1844 return -ERANGE;
1845
1846 switch (lkul->l_state) {
1847 case OPAL_RO:
1848 read_locked = 0;
1849 write_locked = 1;
1850 break;
1851 case OPAL_RW:
1852 read_locked = 0;
1853 write_locked = 0;
1854 break;
1855 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001856 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001857 break;
1858 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001859 pr_debug("Tried to set an invalid locking state.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001860 return OPAL_INVAL_PARAM;
1861 }
1862 ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1863 read_locked, write_locked);
1864
1865 if (ret < 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001866 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001867 return ret;
1868 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001869
Scott Bauer455a7b22017-02-03 12:50:31 -07001870 return finalize_and_send(dev, parse_and_check_status);
1871}
1872
Jon Derrickeed64952017-02-22 07:55:13 -07001873static int activate_lsp(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001874{
Jon Derrickeed64952017-02-22 07:55:13 -07001875 struct opal_lr_act *opal_act = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001876 u8 user_lr[OPAL_UID_LENGTH];
1877 u8 uint_3 = 0x83;
David Kozube8b29222019-02-14 01:15:58 +01001878 int err, i;
Scott Bauer455a7b22017-02-03 12:50:31 -07001879
David Kozube8b29222019-02-14 01:15:58 +01001880 err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID],
1881 opalmethod[OPAL_ACTIVATE]);
Scott Bauer455a7b22017-02-03 12:50:31 -07001882
1883 if (opal_act->sum) {
1884 err = build_locking_range(user_lr, sizeof(user_lr),
1885 opal_act->lr[0]);
1886 if (err)
1887 return err;
1888
Scott Bauer455a7b22017-02-03 12:50:31 -07001889 add_token_u8(&err, dev, OPAL_STARTNAME);
1890 add_token_u8(&err, dev, uint_3);
1891 add_token_u8(&err, dev, 6);
1892 add_token_u8(&err, dev, 0);
1893 add_token_u8(&err, dev, 0);
1894
1895 add_token_u8(&err, dev, OPAL_STARTLIST);
1896 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1897 for (i = 1; i < opal_act->num_lrs; i++) {
1898 user_lr[7] = opal_act->lr[i];
1899 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1900 }
1901 add_token_u8(&err, dev, OPAL_ENDLIST);
1902 add_token_u8(&err, dev, OPAL_ENDNAME);
Scott Bauer455a7b22017-02-03 12:50:31 -07001903 }
1904
1905 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001906 pr_debug("Error building Activate LockingSP command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001907 return err;
1908 }
1909
1910 return finalize_and_send(dev, parse_and_check_status);
1911}
1912
David Kozub3fff2342019-02-14 01:16:04 +01001913/* Determine if we're in the Manufactured Inactive or Active state */
1914static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001915{
1916 u8 lc_status;
David Kozub3fff2342019-02-14 01:16:04 +01001917 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001918
David Kozub3fff2342019-02-14 01:16:04 +01001919 err = generic_get_column(dev, opaluid[OPAL_LOCKINGSP_UID],
1920 OPAL_LIFECYCLE);
1921 if (err)
1922 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001923
1924 lc_status = response_get_u64(&dev->parsed, 4);
David Kozub1e815b32019-02-14 01:15:54 +01001925 /* 0x08 is Manufactured Inactive */
Scott Bauer455a7b22017-02-03 12:50:31 -07001926 /* 0x09 is Manufactured */
1927 if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001928 pr_debug("Couldn't determine the status of the Lifecycle state\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001929 return -ENODEV;
1930 }
1931
1932 return 0;
1933}
1934
David Kozub3fff2342019-02-14 01:16:04 +01001935static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001936{
1937 const char *msid_pin;
1938 size_t strlen;
David Kozub3fff2342019-02-14 01:16:04 +01001939 int err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001940
David Kozub3fff2342019-02-14 01:16:04 +01001941 err = generic_get_column(dev, opaluid[OPAL_C_PIN_MSID], OPAL_PIN);
1942 if (err)
1943 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001944
1945 strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1946 if (!msid_pin) {
David Kozub3fff2342019-02-14 01:16:04 +01001947 pr_debug("Couldn't extract MSID_CPIN from response\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001948 return OPAL_INVAL_PARAM;
1949 }
1950
1951 dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1952 if (!dev->prev_data)
1953 return -ENOMEM;
1954
1955 dev->prev_d_len = strlen;
1956
1957 return 0;
1958}
1959
Jon Derrickeed64952017-02-22 07:55:13 -07001960static int end_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001961{
1962 int err = 0;
1963
1964 clear_opal_cmd(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001965 set_comid(dev, dev->comid);
1966 add_token_u8(&err, dev, OPAL_ENDOFSESSION);
Scott Bauer455a7b22017-02-03 12:50:31 -07001967
Jon Derrickeed64952017-02-22 07:55:13 -07001968 if (err < 0)
1969 return err;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001970
Scott Bauer455a7b22017-02-03 12:50:31 -07001971 return finalize_and_send(dev, end_session_cont);
1972}
1973
1974static int end_opal_session_error(struct opal_dev *dev)
1975{
David Kozub0af26482019-02-14 01:16:07 +01001976 const struct opal_step error_end_session = {
1977 end_opal_session,
Scott Bauer455a7b22017-02-03 12:50:31 -07001978 };
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001979
David Kozub0af26482019-02-14 01:16:07 +01001980 return execute_step(dev, &error_end_session, 0);
Scott Bauer455a7b22017-02-03 12:50:31 -07001981}
1982
David Kozub3db87232019-02-14 01:16:06 +01001983static inline void setup_opal_dev(struct opal_dev *dev)
Scott Bauer455a7b22017-02-03 12:50:31 -07001984{
Scott Bauer455a7b22017-02-03 12:50:31 -07001985 dev->tsn = 0;
1986 dev->hsn = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -07001987 dev->prev_data = NULL;
1988}
1989
1990static int check_opal_support(struct opal_dev *dev)
1991{
Scott Bauer455a7b22017-02-03 12:50:31 -07001992 int ret;
1993
1994 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01001995 setup_opal_dev(dev);
David Kozub0af26482019-02-14 01:16:07 +01001996 ret = opal_discovery0_step(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001997 dev->supported = !ret;
1998 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06001999
Scott Bauer455a7b22017-02-03 12:50:31 -07002000 return ret;
2001}
2002
Scott Bauer7d6d1572017-02-22 10:15:06 -07002003static void clean_opal_dev(struct opal_dev *dev)
2004{
2005
2006 struct opal_suspend_data *suspend, *next;
2007
2008 mutex_lock(&dev->dev_lock);
2009 list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
2010 list_del(&suspend->node);
2011 kfree(suspend);
2012 }
2013 mutex_unlock(&dev->dev_lock);
2014}
2015
2016void free_opal_dev(struct opal_dev *dev)
2017{
2018 if (!dev)
2019 return;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002020
Scott Bauer7d6d1572017-02-22 10:15:06 -07002021 clean_opal_dev(dev);
2022 kfree(dev);
2023}
2024EXPORT_SYMBOL(free_opal_dev);
2025
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002026struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
Scott Bauer455a7b22017-02-03 12:50:31 -07002027{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002028 struct opal_dev *dev;
2029
2030 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
2031 if (!dev)
2032 return NULL;
2033
2034 INIT_LIST_HEAD(&dev->unlk_lst);
2035 mutex_init(&dev->dev_lock);
2036 dev->data = data;
2037 dev->send_recv = send_recv;
2038 if (check_opal_support(dev) != 0) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +01002039 pr_debug("Opal is not supported on this device\n");
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002040 kfree(dev);
2041 return NULL;
2042 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002043
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002044 return dev;
Scott Bauer455a7b22017-02-03 12:50:31 -07002045}
2046EXPORT_SYMBOL(init_opal_dev);
2047
2048static int opal_secure_erase_locking_range(struct opal_dev *dev,
2049 struct opal_session_info *opal_session)
2050{
Jon Derrickeed64952017-02-22 07:55:13 -07002051 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002052 { start_auth_opal_session, opal_session },
2053 { get_active_key, &opal_session->opal_key.lr },
2054 { gen_key, },
David Kozub3db87232019-02-14 01:16:06 +01002055 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002056 };
2057 int ret;
2058
2059 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002060 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002061 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002062 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002063
Scott Bauer455a7b22017-02-03 12:50:31 -07002064 return ret;
2065}
2066
2067static int opal_erase_locking_range(struct opal_dev *dev,
2068 struct opal_session_info *opal_session)
2069{
Jon Derrickeed64952017-02-22 07:55:13 -07002070 const struct opal_step erase_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002071 { start_auth_opal_session, opal_session },
2072 { erase_locking_range, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01002073 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002074 };
2075 int ret;
2076
2077 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002078 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002079 ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002080 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002081
Scott Bauer455a7b22017-02-03 12:50:31 -07002082 return ret;
2083}
2084
2085static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
2086 struct opal_mbr_data *opal_mbr)
2087{
David Kozub78bf4732019-02-14 01:15:53 +01002088 u8 enable_disable = opal_mbr->enable_disable == OPAL_MBR_ENABLE ?
2089 OPAL_TRUE : OPAL_FALSE;
2090
Jon Derrickeed64952017-02-22 07:55:13 -07002091 const struct opal_step mbr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002092 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01002093 { set_mbr_done, &enable_disable },
Jon Derrickeed64952017-02-22 07:55:13 -07002094 { end_opal_session, },
2095 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01002096 { set_mbr_enable_disable, &enable_disable },
David Kozub3db87232019-02-14 01:16:06 +01002097 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002098 };
2099 int ret;
2100
2101 if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
2102 opal_mbr->enable_disable != OPAL_MBR_DISABLE)
2103 return -EINVAL;
2104
2105 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002106 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002107 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002108 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002109
Scott Bauer455a7b22017-02-03 12:50:31 -07002110 return ret;
2111}
2112
Jonas Rabensteinc9888442019-05-21 22:46:44 +02002113static int opal_set_mbr_done(struct opal_dev *dev,
2114 struct opal_mbr_done *mbr_done)
2115{
2116 u8 mbr_done_tf = mbr_done->done_flag == OPAL_MBR_DONE ?
2117 OPAL_TRUE : OPAL_FALSE;
2118
2119 const struct opal_step mbr_steps[] = {
2120 { start_admin1LSP_opal_session, &mbr_done->key },
2121 { set_mbr_done, &mbr_done_tf },
2122 { end_opal_session, }
2123 };
2124 int ret;
2125
2126 if (mbr_done->done_flag != OPAL_MBR_DONE &&
2127 mbr_done->done_flag != OPAL_MBR_NOT_DONE)
2128 return -EINVAL;
2129
2130 mutex_lock(&dev->dev_lock);
2131 setup_opal_dev(dev);
2132 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
2133 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002134
Jonas Rabensteinc9888442019-05-21 22:46:44 +02002135 return ret;
2136}
2137
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02002138static int opal_write_shadow_mbr(struct opal_dev *dev,
2139 struct opal_shadow_mbr *info)
2140{
2141 const struct opal_step mbr_steps[] = {
2142 { start_admin1LSP_opal_session, &info->key },
2143 { write_shadow_mbr, info },
2144 { end_opal_session, }
2145 };
2146 int ret;
2147
2148 if (info->size == 0)
2149 return 0;
2150
2151 mutex_lock(&dev->dev_lock);
2152 setup_opal_dev(dev);
2153 ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
2154 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002155
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02002156 return ret;
2157}
2158
Scott Bauer455a7b22017-02-03 12:50:31 -07002159static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
2160{
2161 struct opal_suspend_data *suspend;
2162
2163 suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
2164 if (!suspend)
2165 return -ENOMEM;
2166
2167 suspend->unlk = *lk_unlk;
2168 suspend->lr = lk_unlk->session.opal_key.lr;
2169
2170 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002171 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002172 add_suspend_info(dev, suspend);
2173 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002174
Scott Bauer455a7b22017-02-03 12:50:31 -07002175 return 0;
2176}
2177
2178static int opal_add_user_to_lr(struct opal_dev *dev,
2179 struct opal_lock_unlock *lk_unlk)
2180{
Jon Derrickeed64952017-02-22 07:55:13 -07002181 const struct opal_step steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002182 { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2183 { add_user_to_lr, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002184 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002185 };
2186 int ret;
2187
2188 if (lk_unlk->l_state != OPAL_RO &&
2189 lk_unlk->l_state != OPAL_RW) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002190 pr_debug("Locking state was not RO or RW\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07002191 return -EINVAL;
2192 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002193
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002194 if (lk_unlk->session.who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002195 lk_unlk->session.who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002196 pr_debug("Authority was not within the range of users: %d\n",
2197 lk_unlk->session.who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002198 return -EINVAL;
2199 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002200
Scott Bauer455a7b22017-02-03 12:50:31 -07002201 if (lk_unlk->session.sum) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002202 pr_debug("%s not supported in sum. Use setup locking range\n",
2203 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07002204 return -EINVAL;
2205 }
2206
2207 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002208 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002209 ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002210 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002211
Scott Bauer455a7b22017-02-03 12:50:31 -07002212 return ret;
2213}
2214
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002215static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal, bool psid)
Scott Bauer455a7b22017-02-03 12:50:31 -07002216{
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002217 /* controller will terminate session */
Jon Derrickeed64952017-02-22 07:55:13 -07002218 const struct opal_step revert_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002219 { start_SIDASP_opal_session, opal },
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002220 { revert_tper, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002221 };
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002222 const struct opal_step psid_revert_steps[] = {
2223 { start_PSID_opal_session, opal },
2224 { revert_tper, }
2225 };
2226
Scott Bauer455a7b22017-02-03 12:50:31 -07002227 int ret;
2228
2229 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002230 setup_opal_dev(dev);
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002231 if (psid)
2232 ret = execute_steps(dev, psid_revert_steps,
2233 ARRAY_SIZE(psid_revert_steps));
2234 else
2235 ret = execute_steps(dev, revert_steps,
2236 ARRAY_SIZE(revert_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002237 mutex_unlock(&dev->dev_lock);
Scott Bauer7d6d1572017-02-22 10:15:06 -07002238
2239 /*
2240 * If we successfully reverted lets clean
2241 * any saved locking ranges.
2242 */
2243 if (!ret)
2244 clean_opal_dev(dev);
2245
Scott Bauer455a7b22017-02-03 12:50:31 -07002246 return ret;
2247}
2248
Jon Derrickeed64952017-02-22 07:55:13 -07002249static int __opal_lock_unlock(struct opal_dev *dev,
2250 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002251{
Jon Derrickeed64952017-02-22 07:55:13 -07002252 const struct opal_step unlock_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002253 { start_auth_opal_session, &lk_unlk->session },
2254 { lock_unlock_locking_range, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002255 { end_opal_session, }
Jon Derrickeed64952017-02-22 07:55:13 -07002256 };
2257 const struct opal_step unlock_sum_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002258 { start_auth_opal_session, &lk_unlk->session },
2259 { lock_unlock_locking_range_sum, lk_unlk },
David Kozub3db87232019-02-14 01:16:06 +01002260 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002261 };
2262
David Kozub3db87232019-02-14 01:16:06 +01002263 if (lk_unlk->session.sum)
David Kozuba80f36c2019-02-14 01:16:08 +01002264 return execute_steps(dev, unlock_sum_steps,
2265 ARRAY_SIZE(unlock_sum_steps));
David Kozub3db87232019-02-14 01:16:06 +01002266 else
David Kozuba80f36c2019-02-14 01:16:08 +01002267 return execute_steps(dev, unlock_steps,
2268 ARRAY_SIZE(unlock_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002269}
2270
Scott Bauerdbec491b2017-09-01 08:53:35 -06002271static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2272{
David Kozub78bf4732019-02-14 01:15:53 +01002273 u8 mbr_done_tf = OPAL_TRUE;
David Kozub1e815b32019-02-14 01:15:54 +01002274 const struct opal_step mbrdone_step[] = {
Scott Bauerdbec491b2017-09-01 08:53:35 -06002275 { start_admin1LSP_opal_session, key },
2276 { set_mbr_done, &mbr_done_tf },
David Kozub3db87232019-02-14 01:16:06 +01002277 { end_opal_session, }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002278 };
2279
David Kozuba80f36c2019-02-14 01:16:08 +01002280 return execute_steps(dev, mbrdone_step, ARRAY_SIZE(mbrdone_step));
Scott Bauerdbec491b2017-09-01 08:53:35 -06002281}
2282
Jon Derrickeed64952017-02-22 07:55:13 -07002283static int opal_lock_unlock(struct opal_dev *dev,
2284 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002285{
Scott Bauer455a7b22017-02-03 12:50:31 -07002286 int ret;
2287
Revanth Rajashekar15ddffc2019-06-27 16:31:09 -06002288 if (lk_unlk->session.who > OPAL_USER9)
Scott Bauer455a7b22017-02-03 12:50:31 -07002289 return -EINVAL;
2290
2291 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002292 ret = __opal_lock_unlock(dev, lk_unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002293 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002294
Scott Bauer455a7b22017-02-03 12:50:31 -07002295 return ret;
2296}
2297
2298static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2299{
Jon Derrickeed64952017-02-22 07:55:13 -07002300 const struct opal_step owner_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002301 { start_anybodyASP_opal_session, },
2302 { get_msid_cpin_pin, },
2303 { end_opal_session, },
2304 { start_SIDASP_opal_session, opal },
2305 { set_sid_cpin_pin, opal },
David Kozub3db87232019-02-14 01:16:06 +01002306 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002307 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002308 int ret;
2309
2310 if (!dev)
2311 return -ENODEV;
2312
2313 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002314 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002315 ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002316 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002317
Scott Bauer455a7b22017-02-03 12:50:31 -07002318 return ret;
2319}
2320
David Kozub1e815b32019-02-14 01:15:54 +01002321static int opal_activate_lsp(struct opal_dev *dev,
2322 struct opal_lr_act *opal_lr_act)
Scott Bauer455a7b22017-02-03 12:50:31 -07002323{
Jon Derrickeed64952017-02-22 07:55:13 -07002324 const struct opal_step active_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002325 { start_SIDASP_opal_session, &opal_lr_act->key },
2326 { get_lsp_lifecycle, },
2327 { activate_lsp, opal_lr_act },
David Kozub3db87232019-02-14 01:16:06 +01002328 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002329 };
2330 int ret;
2331
2332 if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2333 return -EINVAL;
2334
2335 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002336 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002337 ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002338 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002339
Scott Bauer455a7b22017-02-03 12:50:31 -07002340 return ret;
2341}
2342
2343static int opal_setup_locking_range(struct opal_dev *dev,
2344 struct opal_user_lr_setup *opal_lrs)
2345{
Jon Derrickeed64952017-02-22 07:55:13 -07002346 const struct opal_step lr_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002347 { start_auth_opal_session, &opal_lrs->session },
2348 { setup_locking_range, opal_lrs },
David Kozub3db87232019-02-14 01:16:06 +01002349 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002350 };
2351 int ret;
2352
2353 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002354 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002355 ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002356 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002357
Scott Bauer455a7b22017-02-03 12:50:31 -07002358 return ret;
2359}
2360
2361static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2362{
Jon Derrickeed64952017-02-22 07:55:13 -07002363 const struct opal_step pw_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002364 { start_auth_opal_session, &opal_pw->session },
2365 { set_new_pw, &opal_pw->new_user_pw },
David Kozub3db87232019-02-14 01:16:06 +01002366 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002367 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002368 int ret;
2369
Revanth Rajashekar15ddffc2019-06-27 16:31:09 -06002370 if (opal_pw->session.who > OPAL_USER9 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002371 opal_pw->new_user_pw.who > OPAL_USER9)
2372 return -EINVAL;
2373
2374 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002375 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002376 ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002377 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002378
Scott Bauer455a7b22017-02-03 12:50:31 -07002379 return ret;
2380}
2381
2382static int opal_activate_user(struct opal_dev *dev,
2383 struct opal_session_info *opal_session)
2384{
Jon Derrickeed64952017-02-22 07:55:13 -07002385 const struct opal_step act_steps[] = {
Jon Derrickeed64952017-02-22 07:55:13 -07002386 { start_admin1LSP_opal_session, &opal_session->opal_key },
2387 { internal_activate_user, opal_session },
David Kozub3db87232019-02-14 01:16:06 +01002388 { end_opal_session, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002389 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002390 int ret;
2391
2392 /* We can't activate Admin1 it's active as manufactured */
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002393 if (opal_session->who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002394 opal_session->who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002395 pr_debug("Who was not a valid user: %d\n", opal_session->who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002396 return -EINVAL;
2397 }
2398
2399 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002400 setup_opal_dev(dev);
David Kozuba80f36c2019-02-14 01:16:08 +01002401 ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps));
Scott Bauer455a7b22017-02-03 12:50:31 -07002402 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002403
Scott Bauer455a7b22017-02-03 12:50:31 -07002404 return ret;
2405}
2406
2407bool opal_unlock_from_suspend(struct opal_dev *dev)
2408{
2409 struct opal_suspend_data *suspend;
Scott Bauer455a7b22017-02-03 12:50:31 -07002410 bool was_failure = false;
2411 int ret = 0;
2412
2413 if (!dev)
2414 return false;
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002415
Scott Bauer455a7b22017-02-03 12:50:31 -07002416 if (!dev->supported)
2417 return false;
2418
2419 mutex_lock(&dev->dev_lock);
David Kozub3db87232019-02-14 01:16:06 +01002420 setup_opal_dev(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07002421
2422 list_for_each_entry(suspend, &dev->unlk_lst, node) {
Scott Bauer455a7b22017-02-03 12:50:31 -07002423 dev->tsn = 0;
2424 dev->hsn = 0;
2425
Jon Derrickeed64952017-02-22 07:55:13 -07002426 ret = __opal_lock_unlock(dev, &suspend->unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002427 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002428 pr_debug("Failed to unlock LR %hhu with sum %d\n",
2429 suspend->unlk.session.opal_key.lr,
2430 suspend->unlk.session.sum);
Scott Bauer455a7b22017-02-03 12:50:31 -07002431 was_failure = true;
2432 }
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002433
Scott Bauerdbec491b2017-09-01 08:53:35 -06002434 if (dev->mbr_enabled) {
2435 ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
2436 if (ret)
2437 pr_debug("Failed to set MBR Done in S3 resume\n");
2438 }
Scott Bauer455a7b22017-02-03 12:50:31 -07002439 }
2440 mutex_unlock(&dev->dev_lock);
Revanth Rajashekar5cc23ed2019-08-20 09:30:49 -06002441
Scott Bauer455a7b22017-02-03 12:50:31 -07002442 return was_failure;
2443}
2444EXPORT_SYMBOL(opal_unlock_from_suspend);
2445
Scott Bauere225c202017-02-14 17:29:36 -07002446int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
Scott Bauer455a7b22017-02-03 12:50:31 -07002447{
Scott Bauere225c202017-02-14 17:29:36 -07002448 void *p;
2449 int ret = -ENOTTY;
Scott Bauer455a7b22017-02-03 12:50:31 -07002450
2451 if (!capable(CAP_SYS_ADMIN))
2452 return -EACCES;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002453 if (!dev)
2454 return -ENOTSUPP;
Scott Bauer591c59d2017-04-07 13:58:50 -06002455 if (!dev->supported)
Scott Bauer455a7b22017-02-03 12:50:31 -07002456 return -ENOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -07002457
Jon Derrickeed64952017-02-22 07:55:13 -07002458 p = memdup_user(arg, _IOC_SIZE(cmd));
Scott Bauere225c202017-02-14 17:29:36 -07002459 if (IS_ERR(p))
2460 return PTR_ERR(p);
2461
Scott Bauer455a7b22017-02-03 12:50:31 -07002462 switch (cmd) {
Scott Bauere225c202017-02-14 17:29:36 -07002463 case IOC_OPAL_SAVE:
2464 ret = opal_save(dev, p);
2465 break;
2466 case IOC_OPAL_LOCK_UNLOCK:
2467 ret = opal_lock_unlock(dev, p);
2468 break;
2469 case IOC_OPAL_TAKE_OWNERSHIP:
2470 ret = opal_take_ownership(dev, p);
2471 break;
2472 case IOC_OPAL_ACTIVATE_LSP:
2473 ret = opal_activate_lsp(dev, p);
2474 break;
2475 case IOC_OPAL_SET_PW:
2476 ret = opal_set_new_pw(dev, p);
2477 break;
2478 case IOC_OPAL_ACTIVATE_USR:
2479 ret = opal_activate_user(dev, p);
2480 break;
2481 case IOC_OPAL_REVERT_TPR:
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002482 ret = opal_reverttper(dev, p, false);
Scott Bauere225c202017-02-14 17:29:36 -07002483 break;
2484 case IOC_OPAL_LR_SETUP:
2485 ret = opal_setup_locking_range(dev, p);
2486 break;
2487 case IOC_OPAL_ADD_USR_TO_LR:
2488 ret = opal_add_user_to_lr(dev, p);
2489 break;
2490 case IOC_OPAL_ENABLE_DISABLE_MBR:
2491 ret = opal_enable_disable_shadow_mbr(dev, p);
2492 break;
Jonas Rabensteinc9888442019-05-21 22:46:44 +02002493 case IOC_OPAL_MBR_DONE:
2494 ret = opal_set_mbr_done(dev, p);
2495 break;
Jonas Rabensteina9b25b42019-05-21 22:46:45 +02002496 case IOC_OPAL_WRITE_SHADOW_MBR:
2497 ret = opal_write_shadow_mbr(dev, p);
2498 break;
Scott Bauere225c202017-02-14 17:29:36 -07002499 case IOC_OPAL_ERASE_LR:
2500 ret = opal_erase_locking_range(dev, p);
2501 break;
2502 case IOC_OPAL_SECURE_ERASE_LR:
2503 ret = opal_secure_erase_locking_range(dev, p);
2504 break;
Revanth Rajashekar5e4c7cf2019-06-27 16:30:02 -06002505 case IOC_OPAL_PSID_REVERT_TPR:
2506 ret = opal_reverttper(dev, p, true);
2507 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002508 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06002509 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002510 }
Scott Bauere225c202017-02-14 17:29:36 -07002511
2512 kfree(p);
2513 return ret;
Scott Bauer455a7b22017-02-03 12:50:31 -07002514}
2515EXPORT_SYMBOL_GPL(sed_ioctl);