blob: d285bd4b2b9bb5efa55b5cf7a724db23407c3e48 [file] [log] [blame]
Scott Bauer455a7b22017-02-03 12:50:31 -07001/*
2 * Copyright © 2016 Intel Corporation
3 *
4 * Authors:
5 * Scott Bauer <scott.bauer@intel.com>
6 * Rafael Antognolli <rafael.antognolli@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 */
17
18#define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt
19
20#include <linux/delay.h>
21#include <linux/device.h>
22#include <linux/kernel.h>
23#include <linux/list.h>
24#include <linux/genhd.h>
25#include <linux/slab.h>
26#include <linux/uaccess.h>
27#include <uapi/linux/sed-opal.h>
28#include <linux/sed-opal.h>
29#include <linux/string.h>
30#include <linux/kdev_t.h>
31
32#include "opal_proto.h"
33
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010034#define IO_BUFFER_LENGTH 2048
35#define MAX_TOKS 64
36
Jon Derrickeed64952017-02-22 07:55:13 -070037struct opal_step {
38 int (*fn)(struct opal_dev *dev, void *data);
39 void *data;
40};
41typedef int (cont_fn)(struct opal_dev *dev);
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010042
43enum opal_atom_width {
44 OPAL_WIDTH_TINY,
45 OPAL_WIDTH_SHORT,
46 OPAL_WIDTH_MEDIUM,
47 OPAL_WIDTH_LONG,
48 OPAL_WIDTH_TOKEN
49};
50
51/*
52 * On the parsed response, we don't store again the toks that are already
53 * stored in the response buffer. Instead, for each token, we just store a
54 * pointer to the position in the buffer where the token starts, and the size
55 * of the token in bytes.
56 */
57struct opal_resp_tok {
58 const u8 *pos;
59 size_t len;
60 enum opal_response_token type;
61 enum opal_atom_width width;
62 union {
63 u64 u;
64 s64 s;
65 } stored;
66};
67
68/*
69 * From the response header it's not possible to know how many tokens there are
70 * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
71 * if we start dealing with messages that have more than that, we can increase
72 * this number. This is done to avoid having to make two passes through the
73 * response, the first one counting how many tokens we have and the second one
74 * actually storing the positions.
75 */
76struct parsed_resp {
77 int num;
78 struct opal_resp_tok toks[MAX_TOKS];
79};
80
81struct opal_dev {
82 bool supported;
Scott Bauerdbec491b2017-09-01 08:53:35 -060083 bool mbr_enabled;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010084
85 void *data;
86 sec_send_recv *send_recv;
87
Jon Derrickeed64952017-02-22 07:55:13 -070088 const struct opal_step *steps;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010089 struct mutex dev_lock;
90 u16 comid;
91 u32 hsn;
92 u32 tsn;
93 u64 align;
94 u64 lowest_lba;
95
96 size_t pos;
97 u8 cmd[IO_BUFFER_LENGTH];
98 u8 resp[IO_BUFFER_LENGTH];
99
100 struct parsed_resp parsed;
101 size_t prev_d_len;
102 void *prev_data;
103
104 struct list_head unlk_lst;
105};
106
107
Scott Bauer455a7b22017-02-03 12:50:31 -0700108static const u8 opaluid[][OPAL_UID_LENGTH] = {
109 /* users */
110 [OPAL_SMUID_UID] =
111 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
112 [OPAL_THISSP_UID] =
113 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
114 [OPAL_ADMINSP_UID] =
115 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
116 [OPAL_LOCKINGSP_UID] =
117 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
118 [OPAL_ENTERPRISE_LOCKINGSP_UID] =
119 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
120 [OPAL_ANYBODY_UID] =
121 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
122 [OPAL_SID_UID] =
123 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
124 [OPAL_ADMIN1_UID] =
125 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
126 [OPAL_USER1_UID] =
127 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
128 [OPAL_USER2_UID] =
129 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
130 [OPAL_PSID_UID] =
131 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
132 [OPAL_ENTERPRISE_BANDMASTER0_UID] =
133 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
134 [OPAL_ENTERPRISE_ERASEMASTER_UID] =
135 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
136
137 /* tables */
138
139 [OPAL_LOCKINGRANGE_GLOBAL] =
140 { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
141 [OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
142 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
143 [OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
144 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
145 [OPAL_MBRCONTROL] =
146 { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
147 [OPAL_MBR] =
148 { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
149 [OPAL_AUTHORITY_TABLE] =
150 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
151 [OPAL_C_PIN_TABLE] =
152 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
153 [OPAL_LOCKING_INFO_TABLE] =
154 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
155 [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
156 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
157
158 /* C_PIN_TABLE object ID's */
159
David Kozub1e815b32019-02-14 01:15:54 +0100160 [OPAL_C_PIN_MSID] =
Scott Bauer455a7b22017-02-03 12:50:31 -0700161 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
162 [OPAL_C_PIN_SID] =
163 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
164 [OPAL_C_PIN_ADMIN1] =
165 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
166
167 /* half UID's (only first 4 bytes used) */
168
169 [OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
170 { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
171 [OPAL_HALF_UID_BOOLEAN_ACE] =
172 { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
173
174 /* special value for omitted optional parameter */
175 [OPAL_UID_HEXFF] =
176 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
177};
178
179/*
180 * TCG Storage SSC Methods.
181 * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
182 * Section: 6.3 Assigned UIDs
183 */
Jonas Rabenstein1b6b75b2019-02-14 01:15:55 +0100184static const u8 opalmethod[][OPAL_METHOD_LENGTH] = {
Scott Bauer455a7b22017-02-03 12:50:31 -0700185 [OPAL_PROPERTIES] =
186 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
187 [OPAL_STARTSESSION] =
188 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
189 [OPAL_REVERT] =
190 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
191 [OPAL_ACTIVATE] =
192 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
193 [OPAL_EGET] =
194 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
195 [OPAL_ESET] =
196 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
197 [OPAL_NEXT] =
198 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
199 [OPAL_EAUTHENTICATE] =
200 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
201 [OPAL_GETACL] =
202 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
203 [OPAL_GENKEY] =
204 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
205 [OPAL_REVERTSP] =
206 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
207 [OPAL_GET] =
208 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
209 [OPAL_SET] =
210 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
211 [OPAL_AUTHENTICATE] =
212 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
213 [OPAL_RANDOM] =
214 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
215 [OPAL_ERASE] =
216 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
217};
218
Scott Bauer455a7b22017-02-03 12:50:31 -0700219static int end_opal_session_error(struct opal_dev *dev);
220
221struct opal_suspend_data {
222 struct opal_lock_unlock unlk;
223 u8 lr;
224 struct list_head node;
225};
226
227/*
228 * Derived from:
229 * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
230 * Section: 5.1.5 Method Status Codes
231 */
232static const char * const opal_errors[] = {
233 "Success",
234 "Not Authorized",
235 "Unknown Error",
236 "SP Busy",
237 "SP Failed",
238 "SP Disabled",
239 "SP Frozen",
240 "No Sessions Available",
241 "Uniqueness Conflict",
242 "Insufficient Space",
243 "Insufficient Rows",
244 "Invalid Function",
245 "Invalid Parameter",
246 "Invalid Reference",
247 "Unknown Error",
248 "TPER Malfunction",
249 "Transaction Failure",
250 "Response Overflow",
251 "Authority Locked Out",
252};
253
254static const char *opal_error_to_human(int error)
255{
256 if (error == 0x3f)
257 return "Failed";
258
259 if (error >= ARRAY_SIZE(opal_errors) || error < 0)
260 return "Unknown Error";
261
262 return opal_errors[error];
263}
264
265static void print_buffer(const u8 *ptr, u32 length)
266{
267#ifdef DEBUG
268 print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
269 pr_debug("\n");
270#endif
271}
272
273static bool check_tper(const void *data)
274{
275 const struct d0_tper_features *tper = data;
276 u8 flags = tper->supported_features;
277
278 if (!(flags & TPER_SYNC_SUPPORTED)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600279 pr_debug("TPer sync not supported. flags = %d\n",
280 tper->supported_features);
Scott Bauer455a7b22017-02-03 12:50:31 -0700281 return false;
282 }
283
284 return true;
285}
286
Scott Bauerdbec491b2017-09-01 08:53:35 -0600287static bool check_mbrenabled(const void *data)
288{
289 const struct d0_locking_features *lfeat = data;
290 u8 sup_feat = lfeat->supported_features;
291
292 return !!(sup_feat & MBR_ENABLED_MASK);
293}
294
Scott Bauer455a7b22017-02-03 12:50:31 -0700295static bool check_sum(const void *data)
296{
297 const struct d0_single_user_mode *sum = data;
298 u32 nlo = be32_to_cpu(sum->num_locking_objects);
299
300 if (nlo == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600301 pr_debug("Need at least one locking object.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700302 return false;
303 }
304
305 pr_debug("Number of locking objects: %d\n", nlo);
306
307 return true;
308}
309
310static u16 get_comid_v100(const void *data)
311{
312 const struct d0_opal_v100 *v100 = data;
313
314 return be16_to_cpu(v100->baseComID);
315}
316
317static u16 get_comid_v200(const void *data)
318{
319 const struct d0_opal_v200 *v200 = data;
320
321 return be16_to_cpu(v200->baseComID);
322}
323
324static int opal_send_cmd(struct opal_dev *dev)
325{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100326 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700327 dev->cmd, IO_BUFFER_LENGTH,
328 true);
329}
330
331static int opal_recv_cmd(struct opal_dev *dev)
332{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100333 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700334 dev->resp, IO_BUFFER_LENGTH,
335 false);
336}
337
338static int opal_recv_check(struct opal_dev *dev)
339{
340 size_t buflen = IO_BUFFER_LENGTH;
341 void *buffer = dev->resp;
342 struct opal_header *hdr = buffer;
343 int ret;
344
345 do {
346 pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
347 hdr->cp.outstandingData,
348 hdr->cp.minTransfer);
349
350 if (hdr->cp.outstandingData == 0 ||
351 hdr->cp.minTransfer != 0)
352 return 0;
353
354 memset(buffer, 0, buflen);
355 ret = opal_recv_cmd(dev);
356 } while (!ret);
357
358 return ret;
359}
360
361static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
362{
363 int ret;
364
365 ret = opal_send_cmd(dev);
366 if (ret)
367 return ret;
368 ret = opal_recv_cmd(dev);
369 if (ret)
370 return ret;
371 ret = opal_recv_check(dev);
372 if (ret)
373 return ret;
374 return cont(dev);
375}
376
377static void check_geometry(struct opal_dev *dev, const void *data)
378{
379 const struct d0_geometry_features *geo = data;
380
381 dev->align = geo->alignment_granularity;
382 dev->lowest_lba = geo->lowest_aligned_lba;
383}
384
385static int next(struct opal_dev *dev)
386{
Jon Derrickeed64952017-02-22 07:55:13 -0700387 const struct opal_step *step;
388 int state = 0, error = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700389
390 do {
Jon Derrickeed64952017-02-22 07:55:13 -0700391 step = &dev->steps[state];
392 if (!step->fn)
Scott Bauer455a7b22017-02-03 12:50:31 -0700393 break;
394
Jon Derrickeed64952017-02-22 07:55:13 -0700395 error = step->fn(dev, step->data);
Scott Bauer455a7b22017-02-03 12:50:31 -0700396 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600397 pr_debug("Error on step function: %d with error %d: %s\n",
398 state, error,
399 opal_error_to_human(error));
Scott Bauer455a7b22017-02-03 12:50:31 -0700400
401 /* For each OPAL command we do a discovery0 then we
402 * start some sort of session.
403 * If we haven't passed state 1 then there was an error
404 * on discovery0 or during the attempt to start a
405 * session. Therefore we shouldn't attempt to terminate
406 * a session, as one has not yet been created.
407 */
Scott Bauer2d190202017-02-22 10:15:08 -0700408 if (state > 1) {
409 end_opal_session_error(dev);
410 return error;
411 }
412
Scott Bauer455a7b22017-02-03 12:50:31 -0700413 }
Jon Derrickeed64952017-02-22 07:55:13 -0700414 state++;
Scott Bauer455a7b22017-02-03 12:50:31 -0700415 } while (!error);
416
417 return error;
418}
419
420static int opal_discovery0_end(struct opal_dev *dev)
421{
422 bool found_com_id = false, supported = true, single_user = false;
423 const struct d0_header *hdr = (struct d0_header *)dev->resp;
424 const u8 *epos = dev->resp, *cpos = dev->resp;
425 u16 comid = 0;
Jon Derrick77039b92017-02-21 11:59:15 -0700426 u32 hlen = be32_to_cpu(hdr->length);
Scott Bauer455a7b22017-02-03 12:50:31 -0700427
Jon Derrick77039b92017-02-21 11:59:15 -0700428 print_buffer(dev->resp, hlen);
Scott Bauerdbec491b2017-09-01 08:53:35 -0600429 dev->mbr_enabled = false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700430
Jon Derrick77039b92017-02-21 11:59:15 -0700431 if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600432 pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
433 sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
Jon Derrick77039b92017-02-21 11:59:15 -0700434 return -EFAULT;
435 }
436
437 epos += hlen; /* end of buffer */
Scott Bauer455a7b22017-02-03 12:50:31 -0700438 cpos += sizeof(*hdr); /* current position on buffer */
439
440 while (cpos < epos && supported) {
441 const struct d0_features *body =
442 (const struct d0_features *)cpos;
443
444 switch (be16_to_cpu(body->code)) {
445 case FC_TPER:
446 supported = check_tper(body->features);
447 break;
448 case FC_SINGLEUSER:
449 single_user = check_sum(body->features);
450 break;
451 case FC_GEOMETRY:
452 check_geometry(dev, body);
453 break;
454 case FC_LOCKING:
Scott Bauerdbec491b2017-09-01 08:53:35 -0600455 dev->mbr_enabled = check_mbrenabled(body->features);
456 break;
Scott Bauer455a7b22017-02-03 12:50:31 -0700457 case FC_ENTERPRISE:
458 case FC_DATASTORE:
459 /* some ignored properties */
460 pr_debug("Found OPAL feature description: %d\n",
461 be16_to_cpu(body->code));
462 break;
463 case FC_OPALV100:
464 comid = get_comid_v100(body->features);
465 found_com_id = true;
466 break;
467 case FC_OPALV200:
468 comid = get_comid_v200(body->features);
469 found_com_id = true;
470 break;
471 case 0xbfff ... 0xffff:
472 /* vendor specific, just ignore */
473 break;
474 default:
475 pr_debug("OPAL Unknown feature: %d\n",
476 be16_to_cpu(body->code));
477
478 }
479 cpos += body->length + 4;
480 }
481
482 if (!supported) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100483 pr_debug("This device is not Opal enabled. Not Supported!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700484 return -EOPNOTSUPP;
485 }
486
487 if (!single_user)
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100488 pr_debug("Device doesn't support single user mode\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700489
490
491 if (!found_com_id) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100492 pr_debug("Could not find OPAL comid for device. Returning early\n");
Ingo Molnared7158b2018-02-22 10:54:55 +0100493 return -EOPNOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -0700494 }
495
496 dev->comid = comid;
497
498 return 0;
499}
500
Jon Derrickeed64952017-02-22 07:55:13 -0700501static int opal_discovery0(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -0700502{
503 int ret;
504
505 memset(dev->resp, 0, IO_BUFFER_LENGTH);
506 dev->comid = OPAL_DISCOVERY_COMID;
507 ret = opal_recv_cmd(dev);
508 if (ret)
509 return ret;
510 return opal_discovery0_end(dev);
511}
512
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100513static bool can_add(int *err, struct opal_dev *cmd, size_t len)
Scott Bauer455a7b22017-02-03 12:50:31 -0700514{
515 if (*err)
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100516 return false;
517
518 if (len > IO_BUFFER_LENGTH || cmd->pos > IO_BUFFER_LENGTH - len) {
519 pr_debug("Error adding %zu bytes: end of buffer.\n", len);
Scott Bauer455a7b22017-02-03 12:50:31 -0700520 *err = -ERANGE;
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100521 return false;
Scott Bauer455a7b22017-02-03 12:50:31 -0700522 }
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100523
524 return true;
525}
526
527static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
528{
529 if (!can_add(err, cmd, 1))
530 return;
Scott Bauer455a7b22017-02-03 12:50:31 -0700531 cmd->cmd[cmd->pos++] = tok;
532}
533
534static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
535 bool has_sign, int len)
536{
537 u8 atom;
538 int err = 0;
539
540 atom = SHORT_ATOM_ID;
541 atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
542 atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
543 atom |= len & SHORT_ATOM_LEN_MASK;
544
545 add_token_u8(&err, cmd, atom);
546}
547
548static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
549 bool has_sign, int len)
550{
551 u8 header0;
552
553 header0 = MEDIUM_ATOM_ID;
554 header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
555 header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
556 header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
557 cmd->cmd[cmd->pos++] = header0;
558 cmd->cmd[cmd->pos++] = len;
559}
560
561static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
562{
Scott Bauer455a7b22017-02-03 12:50:31 -0700563 size_t len;
564 int msb;
Scott Bauer455a7b22017-02-03 12:50:31 -0700565
566 if (!(number & ~TINY_ATOM_DATA_MASK)) {
567 add_token_u8(err, cmd, number);
568 return;
569 }
570
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100571 msb = fls64(number);
572 len = DIV_ROUND_UP(msb, 8);
Scott Bauer455a7b22017-02-03 12:50:31 -0700573
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100574 if (!can_add(err, cmd, len + 1)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600575 pr_debug("Error adding u64: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700576 return;
577 }
578 add_short_atom_header(cmd, false, false, len);
Jonas Rabenstein5f990d32018-03-07 17:55:56 +0100579 while (len--)
580 add_token_u8(err, cmd, number >> (len * 8));
Scott Bauer455a7b22017-02-03 12:50:31 -0700581}
582
583static void add_token_bytestring(int *err, struct opal_dev *cmd,
584 const u8 *bytestring, size_t len)
585{
586 size_t header_len = 1;
587 bool is_short_atom = true;
588
589 if (*err)
590 return;
591
592 if (len & ~SHORT_ATOM_LEN_MASK) {
593 header_len = 2;
594 is_short_atom = false;
595 }
596
Jonas Rabensteine2821a52019-02-14 01:15:56 +0100597 if (!can_add(err, cmd, header_len + len)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600598 pr_debug("Error adding bytestring: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700599 return;
600 }
601
602 if (is_short_atom)
603 add_short_atom_header(cmd, true, false, len);
604 else
605 add_medium_atom_header(cmd, true, false, len);
606
607 memcpy(&cmd->cmd[cmd->pos], bytestring, len);
608 cmd->pos += len;
609
610}
611
612static int build_locking_range(u8 *buffer, size_t length, u8 lr)
613{
614 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600615 pr_debug("Can't build locking range. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700616 return -ERANGE;
617 }
618
619 memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
620
621 if (lr == 0)
622 return 0;
623 buffer[5] = LOCKING_RANGE_NON_GLOBAL;
624 buffer[7] = lr;
625
626 return 0;
627}
628
629static int build_locking_user(u8 *buffer, size_t length, u8 lr)
630{
631 if (length > OPAL_UID_LENGTH) {
David Kozub1e815b32019-02-14 01:15:54 +0100632 pr_debug("Can't build locking range user. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700633 return -ERANGE;
634 }
635
636 memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
637
638 buffer[7] = lr + 1;
639
640 return 0;
641}
642
643static void set_comid(struct opal_dev *cmd, u16 comid)
644{
645 struct opal_header *hdr = (struct opal_header *)cmd->cmd;
646
647 hdr->cp.extendedComID[0] = comid >> 8;
648 hdr->cp.extendedComID[1] = comid;
649 hdr->cp.extendedComID[2] = 0;
650 hdr->cp.extendedComID[3] = 0;
651}
652
653static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
654{
655 struct opal_header *hdr;
656 int err = 0;
657
658 add_token_u8(&err, cmd, OPAL_ENDOFDATA);
659 add_token_u8(&err, cmd, OPAL_STARTLIST);
660 add_token_u8(&err, cmd, 0);
661 add_token_u8(&err, cmd, 0);
662 add_token_u8(&err, cmd, 0);
663 add_token_u8(&err, cmd, OPAL_ENDLIST);
664
665 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600666 pr_debug("Error finalizing command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700667 return -EFAULT;
668 }
669
670 hdr = (struct opal_header *) cmd->cmd;
671
672 hdr->pkt.tsn = cpu_to_be32(tsn);
673 hdr->pkt.hsn = cpu_to_be32(hsn);
674
675 hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
676 while (cmd->pos % 4) {
677 if (cmd->pos >= IO_BUFFER_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600678 pr_debug("Error: Buffer overrun\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700679 return -ERANGE;
680 }
681 cmd->cmd[cmd->pos++] = 0;
682 }
683 hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
684 sizeof(hdr->pkt));
685 hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
686
687 return 0;
688}
689
Jon Derrickcccb9242017-02-21 11:59:14 -0700690static const struct opal_resp_tok *response_get_token(
691 const struct parsed_resp *resp,
692 int n)
Scott Bauer455a7b22017-02-03 12:50:31 -0700693{
694 const struct opal_resp_tok *tok;
695
696 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600697 pr_debug("Token number doesn't exist: %d, resp: %d\n",
698 n, resp->num);
Jon Derrickcccb9242017-02-21 11:59:14 -0700699 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700700 }
701
702 tok = &resp->toks[n];
703 if (tok->len == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600704 pr_debug("Token length must be non-zero\n");
Jon Derrickcccb9242017-02-21 11:59:14 -0700705 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700706 }
707
Jon Derrickcccb9242017-02-21 11:59:14 -0700708 return tok;
Scott Bauer455a7b22017-02-03 12:50:31 -0700709}
710
Jon Derrickaedb6e22017-02-21 11:59:13 -0700711static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
712 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700713{
714 tok->pos = pos;
715 tok->len = 1;
716 tok->width = OPAL_WIDTH_TINY;
717
718 if (pos[0] & TINY_ATOM_SIGNED) {
719 tok->type = OPAL_DTA_TOKENID_SINT;
720 } else {
721 tok->type = OPAL_DTA_TOKENID_UINT;
722 tok->stored.u = pos[0] & 0x3f;
723 }
724
725 return tok->len;
726}
727
Jon Derrickaedb6e22017-02-21 11:59:13 -0700728static ssize_t response_parse_short(struct opal_resp_tok *tok,
729 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700730{
731 tok->pos = pos;
732 tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
733 tok->width = OPAL_WIDTH_SHORT;
734
735 if (pos[0] & SHORT_ATOM_BYTESTRING) {
736 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
737 } else if (pos[0] & SHORT_ATOM_SIGNED) {
738 tok->type = OPAL_DTA_TOKENID_SINT;
739 } else {
740 u64 u_integer = 0;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700741 ssize_t i, b = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700742
743 tok->type = OPAL_DTA_TOKENID_UINT;
744 if (tok->len > 9) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600745 pr_debug("uint64 with more than 8 bytes\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700746 return -EINVAL;
747 }
748 for (i = tok->len - 1; i > 0; i--) {
749 u_integer |= ((u64)pos[i] << (8 * b));
750 b++;
751 }
752 tok->stored.u = u_integer;
753 }
754
755 return tok->len;
756}
757
Jon Derrickaedb6e22017-02-21 11:59:13 -0700758static ssize_t response_parse_medium(struct opal_resp_tok *tok,
759 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700760{
761 tok->pos = pos;
762 tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
763 tok->width = OPAL_WIDTH_MEDIUM;
764
765 if (pos[0] & MEDIUM_ATOM_BYTESTRING)
766 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
767 else if (pos[0] & MEDIUM_ATOM_SIGNED)
768 tok->type = OPAL_DTA_TOKENID_SINT;
769 else
770 tok->type = OPAL_DTA_TOKENID_UINT;
771
772 return tok->len;
773}
774
Jon Derrickaedb6e22017-02-21 11:59:13 -0700775static ssize_t response_parse_long(struct opal_resp_tok *tok,
776 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700777{
778 tok->pos = pos;
779 tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
780 tok->width = OPAL_WIDTH_LONG;
781
782 if (pos[0] & LONG_ATOM_BYTESTRING)
783 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
784 else if (pos[0] & LONG_ATOM_SIGNED)
785 tok->type = OPAL_DTA_TOKENID_SINT;
786 else
787 tok->type = OPAL_DTA_TOKENID_UINT;
788
789 return tok->len;
790}
791
Jon Derrickaedb6e22017-02-21 11:59:13 -0700792static ssize_t response_parse_token(struct opal_resp_tok *tok,
793 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700794{
795 tok->pos = pos;
796 tok->len = 1;
797 tok->type = OPAL_DTA_TOKENID_TOKEN;
798 tok->width = OPAL_WIDTH_TOKEN;
799
800 return tok->len;
801}
802
803static int response_parse(const u8 *buf, size_t length,
804 struct parsed_resp *resp)
805{
806 const struct opal_header *hdr;
807 struct opal_resp_tok *iter;
808 int num_entries = 0;
809 int total;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700810 ssize_t token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700811 const u8 *pos;
Jon Derrick77039b92017-02-21 11:59:15 -0700812 u32 clen, plen, slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700813
814 if (!buf)
815 return -EFAULT;
816
817 if (!resp)
818 return -EFAULT;
819
820 hdr = (struct opal_header *)buf;
821 pos = buf;
822 pos += sizeof(*hdr);
823
Jon Derrick77039b92017-02-21 11:59:15 -0700824 clen = be32_to_cpu(hdr->cp.length);
825 plen = be32_to_cpu(hdr->pkt.length);
826 slen = be32_to_cpu(hdr->subpkt.length);
827 pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
828 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700829
Jon Derrick77039b92017-02-21 11:59:15 -0700830 if (clen == 0 || plen == 0 || slen == 0 ||
831 slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600832 pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
833 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700834 print_buffer(pos, sizeof(*hdr));
835 return -EINVAL;
836 }
837
838 if (pos > buf + length)
839 return -EFAULT;
840
841 iter = resp->toks;
Jon Derrick77039b92017-02-21 11:59:15 -0700842 total = slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700843 print_buffer(pos, total);
844 while (total > 0) {
845 if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
846 token_length = response_parse_tiny(iter, pos);
847 else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
848 token_length = response_parse_short(iter, pos);
849 else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
850 token_length = response_parse_medium(iter, pos);
851 else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
852 token_length = response_parse_long(iter, pos);
853 else /* TOKEN */
854 token_length = response_parse_token(iter, pos);
855
Jon Derrickaedb6e22017-02-21 11:59:13 -0700856 if (token_length < 0)
857 return token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700858
859 pos += token_length;
860 total -= token_length;
861 iter++;
862 num_entries++;
863 }
864
865 if (num_entries == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600866 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700867 return -EINVAL;
868 }
869 resp->num = num_entries;
870
871 return 0;
872}
873
874static size_t response_get_string(const struct parsed_resp *resp, int n,
875 const char **store)
876{
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100877 u8 skip;
878 const struct opal_resp_tok *token;
879
Scott Bauer455a7b22017-02-03 12:50:31 -0700880 *store = NULL;
881 if (!resp) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600882 pr_debug("Response is NULL\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700883 return 0;
884 }
885
Dan Carpenterce042c12018-06-20 13:41:51 +0300886 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600887 pr_debug("Response has %d tokens. Can't access %d\n",
888 resp->num, n);
Scott Bauer455a7b22017-02-03 12:50:31 -0700889 return 0;
890 }
891
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100892 token = &resp->toks[n];
893 if (token->type != OPAL_DTA_TOKENID_BYTESTRING) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600894 pr_debug("Token is not a byte string!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700895 return 0;
896 }
897
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100898 switch (token->width) {
899 case OPAL_WIDTH_TINY:
900 case OPAL_WIDTH_SHORT:
901 skip = 1;
902 break;
903 case OPAL_WIDTH_MEDIUM:
904 skip = 2;
905 break;
906 case OPAL_WIDTH_LONG:
907 skip = 4;
908 break;
909 default:
910 pr_debug("Token has invalid width!\n");
911 return 0;
912 }
913
914 *store = token->pos + skip;
915 return token->len - skip;
Scott Bauer455a7b22017-02-03 12:50:31 -0700916}
917
918static u64 response_get_u64(const struct parsed_resp *resp, int n)
919{
920 if (!resp) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600921 pr_debug("Response is NULL\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700922 return 0;
923 }
924
Dan Carpenterce042c12018-06-20 13:41:51 +0300925 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600926 pr_debug("Response has %d tokens. Can't access %d\n",
927 resp->num, n);
Scott Bauer455a7b22017-02-03 12:50:31 -0700928 return 0;
929 }
930
931 if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600932 pr_debug("Token is not unsigned it: %d\n",
933 resp->toks[n].type);
Scott Bauer455a7b22017-02-03 12:50:31 -0700934 return 0;
935 }
936
937 if (!(resp->toks[n].width == OPAL_WIDTH_TINY ||
938 resp->toks[n].width == OPAL_WIDTH_SHORT)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600939 pr_debug("Atom is not short or tiny: %d\n",
940 resp->toks[n].width);
Scott Bauer455a7b22017-02-03 12:50:31 -0700941 return 0;
942 }
943
944 return resp->toks[n].stored.u;
945}
946
Jon Derrickcccb9242017-02-21 11:59:14 -0700947static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
948{
949 if (IS_ERR(token) ||
950 token->type != OPAL_DTA_TOKENID_TOKEN ||
951 token->pos[0] != match)
952 return false;
953 return true;
954}
955
Scott Bauer455a7b22017-02-03 12:50:31 -0700956static u8 response_status(const struct parsed_resp *resp)
957{
Jon Derrickcccb9242017-02-21 11:59:14 -0700958 const struct opal_resp_tok *tok;
959
960 tok = response_get_token(resp, 0);
961 if (response_token_matches(tok, OPAL_ENDOFSESSION))
Scott Bauer455a7b22017-02-03 12:50:31 -0700962 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700963
964 if (resp->num < 5)
965 return DTAERROR_NO_METHOD_STATUS;
966
Jon Derrickcccb9242017-02-21 11:59:14 -0700967 tok = response_get_token(resp, resp->num - 5);
968 if (!response_token_matches(tok, OPAL_STARTLIST))
969 return DTAERROR_NO_METHOD_STATUS;
970
971 tok = response_get_token(resp, resp->num - 1);
972 if (!response_token_matches(tok, OPAL_ENDLIST))
Scott Bauer455a7b22017-02-03 12:50:31 -0700973 return DTAERROR_NO_METHOD_STATUS;
974
975 return response_get_u64(resp, resp->num - 4);
976}
977
978/* Parses and checks for errors */
979static int parse_and_check_status(struct opal_dev *dev)
980{
981 int error;
982
983 print_buffer(dev->cmd, dev->pos);
984
985 error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
986 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600987 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700988 return error;
989 }
990
991 return response_status(&dev->parsed);
992}
993
994static void clear_opal_cmd(struct opal_dev *dev)
995{
996 dev->pos = sizeof(struct opal_header);
997 memset(dev->cmd, 0, IO_BUFFER_LENGTH);
998}
999
1000static int start_opal_session_cont(struct opal_dev *dev)
1001{
1002 u32 hsn, tsn;
1003 int error = 0;
1004
1005 error = parse_and_check_status(dev);
1006 if (error)
1007 return error;
1008
1009 hsn = response_get_u64(&dev->parsed, 4);
1010 tsn = response_get_u64(&dev->parsed, 5);
1011
1012 if (hsn == 0 && tsn == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001013 pr_debug("Couldn't authenticate session\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001014 return -EPERM;
1015 }
1016
1017 dev->hsn = hsn;
1018 dev->tsn = tsn;
1019 return 0;
1020}
1021
1022static void add_suspend_info(struct opal_dev *dev,
1023 struct opal_suspend_data *sus)
1024{
1025 struct opal_suspend_data *iter;
1026
1027 list_for_each_entry(iter, &dev->unlk_lst, node) {
1028 if (iter->lr == sus->lr) {
1029 list_del(&iter->node);
1030 kfree(iter);
1031 break;
1032 }
1033 }
1034 list_add_tail(&sus->node, &dev->unlk_lst);
1035}
1036
1037static int end_session_cont(struct opal_dev *dev)
1038{
1039 dev->hsn = 0;
1040 dev->tsn = 0;
1041 return parse_and_check_status(dev);
1042}
1043
1044static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1045{
1046 int ret;
1047
1048 ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1049 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001050 pr_debug("Error finalizing command buffer: %d\n", ret);
Scott Bauer455a7b22017-02-03 12:50:31 -07001051 return ret;
1052 }
1053
1054 print_buffer(dev->cmd, dev->pos);
1055
1056 return opal_send_recv(dev, cont);
1057}
1058
Jon Derrickeed64952017-02-22 07:55:13 -07001059static int gen_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001060{
Scott Bauer455a7b22017-02-03 12:50:31 -07001061 u8 uid[OPAL_UID_LENGTH];
1062 int err = 0;
1063
1064 clear_opal_cmd(dev);
1065 set_comid(dev, dev->comid);
1066
1067 memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
Scott Bauer455a7b22017-02-03 12:50:31 -07001068 kfree(dev->prev_data);
1069 dev->prev_data = NULL;
1070
1071 add_token_u8(&err, dev, OPAL_CALL);
1072 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1073 add_token_bytestring(&err, dev, opalmethod[OPAL_GENKEY],
1074 OPAL_UID_LENGTH);
1075 add_token_u8(&err, dev, OPAL_STARTLIST);
1076 add_token_u8(&err, dev, OPAL_ENDLIST);
1077
1078 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001079 pr_debug("Error building gen key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001080 return err;
1081
1082 }
1083 return finalize_and_send(dev, parse_and_check_status);
1084}
1085
1086static int get_active_key_cont(struct opal_dev *dev)
1087{
1088 const char *activekey;
1089 size_t keylen;
1090 int error = 0;
1091
1092 error = parse_and_check_status(dev);
1093 if (error)
1094 return error;
1095 keylen = response_get_string(&dev->parsed, 4, &activekey);
1096 if (!activekey) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001097 pr_debug("%s: Couldn't extract the Activekey from the response\n",
1098 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001099 return OPAL_INVAL_PARAM;
1100 }
1101 dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1102
1103 if (!dev->prev_data)
1104 return -ENOMEM;
1105
1106 dev->prev_d_len = keylen;
1107
1108 return 0;
1109}
1110
Jon Derrickeed64952017-02-22 07:55:13 -07001111static int get_active_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001112{
1113 u8 uid[OPAL_UID_LENGTH];
1114 int err = 0;
Jon Derrickeed64952017-02-22 07:55:13 -07001115 u8 *lr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001116
1117 clear_opal_cmd(dev);
1118 set_comid(dev, dev->comid);
Scott Bauer455a7b22017-02-03 12:50:31 -07001119
1120 err = build_locking_range(uid, sizeof(uid), *lr);
1121 if (err)
1122 return err;
1123
1124 err = 0;
1125 add_token_u8(&err, dev, OPAL_CALL);
1126 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1127 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1128 add_token_u8(&err, dev, OPAL_STARTLIST);
1129 add_token_u8(&err, dev, OPAL_STARTLIST);
1130 add_token_u8(&err, dev, OPAL_STARTNAME);
1131 add_token_u8(&err, dev, 3); /* startCloumn */
1132 add_token_u8(&err, dev, 10); /* ActiveKey */
1133 add_token_u8(&err, dev, OPAL_ENDNAME);
1134 add_token_u8(&err, dev, OPAL_STARTNAME);
1135 add_token_u8(&err, dev, 4); /* endColumn */
1136 add_token_u8(&err, dev, 10); /* ActiveKey */
1137 add_token_u8(&err, dev, OPAL_ENDNAME);
1138 add_token_u8(&err, dev, OPAL_ENDLIST);
1139 add_token_u8(&err, dev, OPAL_ENDLIST);
1140 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001141 pr_debug("Error building get active key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001142 return err;
1143 }
1144
1145 return finalize_and_send(dev, get_active_key_cont);
1146}
1147
1148static int generic_lr_enable_disable(struct opal_dev *dev,
1149 u8 *uid, bool rle, bool wle,
1150 bool rl, bool wl)
1151{
1152 int err = 0;
1153
1154 add_token_u8(&err, dev, OPAL_CALL);
1155 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1156 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1157
1158 add_token_u8(&err, dev, OPAL_STARTLIST);
1159 add_token_u8(&err, dev, OPAL_STARTNAME);
1160 add_token_u8(&err, dev, OPAL_VALUES);
1161 add_token_u8(&err, dev, OPAL_STARTLIST);
1162
1163 add_token_u8(&err, dev, OPAL_STARTNAME);
1164 add_token_u8(&err, dev, 5); /* ReadLockEnabled */
1165 add_token_u8(&err, dev, rle);
1166 add_token_u8(&err, dev, OPAL_ENDNAME);
1167
1168 add_token_u8(&err, dev, OPAL_STARTNAME);
1169 add_token_u8(&err, dev, 6); /* WriteLockEnabled */
1170 add_token_u8(&err, dev, wle);
1171 add_token_u8(&err, dev, OPAL_ENDNAME);
1172
1173 add_token_u8(&err, dev, OPAL_STARTNAME);
1174 add_token_u8(&err, dev, OPAL_READLOCKED);
1175 add_token_u8(&err, dev, rl);
1176 add_token_u8(&err, dev, OPAL_ENDNAME);
1177
1178 add_token_u8(&err, dev, OPAL_STARTNAME);
1179 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1180 add_token_u8(&err, dev, wl);
1181 add_token_u8(&err, dev, OPAL_ENDNAME);
1182
1183 add_token_u8(&err, dev, OPAL_ENDLIST);
1184 add_token_u8(&err, dev, OPAL_ENDNAME);
1185 add_token_u8(&err, dev, OPAL_ENDLIST);
1186 return err;
1187}
1188
1189static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1190 struct opal_user_lr_setup *setup)
1191{
1192 int err;
1193
1194 err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1195 0, 0);
1196 if (err)
Scott Bauer591c59d2017-04-07 13:58:50 -06001197 pr_debug("Failed to create enable global lr command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001198 return err;
1199}
1200
Jon Derrickeed64952017-02-22 07:55:13 -07001201static int setup_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001202{
1203 u8 uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001204 struct opal_user_lr_setup *setup = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001205 u8 lr;
1206 int err = 0;
1207
1208 clear_opal_cmd(dev);
1209 set_comid(dev, dev->comid);
1210
Scott Bauer455a7b22017-02-03 12:50:31 -07001211 lr = setup->session.opal_key.lr;
1212 err = build_locking_range(uid, sizeof(uid), lr);
1213 if (err)
1214 return err;
1215
1216 if (lr == 0)
1217 err = enable_global_lr(dev, uid, setup);
1218 else {
1219 add_token_u8(&err, dev, OPAL_CALL);
1220 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1221 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1222 OPAL_UID_LENGTH);
1223
1224 add_token_u8(&err, dev, OPAL_STARTLIST);
1225 add_token_u8(&err, dev, OPAL_STARTNAME);
1226 add_token_u8(&err, dev, OPAL_VALUES);
1227 add_token_u8(&err, dev, OPAL_STARTLIST);
1228
1229 add_token_u8(&err, dev, OPAL_STARTNAME);
1230 add_token_u8(&err, dev, 3); /* Ranges Start */
1231 add_token_u64(&err, dev, setup->range_start);
1232 add_token_u8(&err, dev, OPAL_ENDNAME);
1233
1234 add_token_u8(&err, dev, OPAL_STARTNAME);
1235 add_token_u8(&err, dev, 4); /* Ranges length */
1236 add_token_u64(&err, dev, setup->range_length);
1237 add_token_u8(&err, dev, OPAL_ENDNAME);
1238
1239 add_token_u8(&err, dev, OPAL_STARTNAME);
1240 add_token_u8(&err, dev, 5); /*ReadLockEnabled */
1241 add_token_u64(&err, dev, !!setup->RLE);
1242 add_token_u8(&err, dev, OPAL_ENDNAME);
1243
1244 add_token_u8(&err, dev, OPAL_STARTNAME);
1245 add_token_u8(&err, dev, 6); /*WriteLockEnabled*/
1246 add_token_u64(&err, dev, !!setup->WLE);
1247 add_token_u8(&err, dev, OPAL_ENDNAME);
1248
1249 add_token_u8(&err, dev, OPAL_ENDLIST);
1250 add_token_u8(&err, dev, OPAL_ENDNAME);
1251 add_token_u8(&err, dev, OPAL_ENDLIST);
1252
1253 }
1254 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001255 pr_debug("Error building Setup Locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001256 return err;
1257
1258 }
1259
1260 return finalize_and_send(dev, parse_and_check_status);
1261}
1262
1263static int start_generic_opal_session(struct opal_dev *dev,
1264 enum opal_uid auth,
1265 enum opal_uid sp_type,
1266 const char *key,
1267 u8 key_len)
1268{
1269 u32 hsn;
1270 int err = 0;
1271
Scott Bauer591c59d2017-04-07 13:58:50 -06001272 if (key == NULL && auth != OPAL_ANYBODY_UID)
Scott Bauer455a7b22017-02-03 12:50:31 -07001273 return OPAL_INVAL_PARAM;
Scott Bauer455a7b22017-02-03 12:50:31 -07001274
1275 clear_opal_cmd(dev);
1276
1277 set_comid(dev, dev->comid);
1278 hsn = GENERIC_HOST_SESSION_NUM;
1279
1280 add_token_u8(&err, dev, OPAL_CALL);
1281 add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
1282 OPAL_UID_LENGTH);
1283 add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
1284 OPAL_UID_LENGTH);
1285 add_token_u8(&err, dev, OPAL_STARTLIST);
1286 add_token_u64(&err, dev, hsn);
1287 add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1288 add_token_u8(&err, dev, 1);
1289
1290 switch (auth) {
1291 case OPAL_ANYBODY_UID:
1292 add_token_u8(&err, dev, OPAL_ENDLIST);
1293 break;
1294 case OPAL_ADMIN1_UID:
1295 case OPAL_SID_UID:
1296 add_token_u8(&err, dev, OPAL_STARTNAME);
1297 add_token_u8(&err, dev, 0); /* HostChallenge */
1298 add_token_bytestring(&err, dev, key, key_len);
1299 add_token_u8(&err, dev, OPAL_ENDNAME);
1300 add_token_u8(&err, dev, OPAL_STARTNAME);
1301 add_token_u8(&err, dev, 3); /* HostSignAuth */
1302 add_token_bytestring(&err, dev, opaluid[auth],
1303 OPAL_UID_LENGTH);
1304 add_token_u8(&err, dev, OPAL_ENDNAME);
1305 add_token_u8(&err, dev, OPAL_ENDLIST);
1306 break;
1307 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001308 pr_debug("Cannot start Admin SP session with auth %d\n", auth);
Scott Bauer455a7b22017-02-03 12:50:31 -07001309 return OPAL_INVAL_PARAM;
1310 }
1311
1312 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001313 pr_debug("Error building start adminsp session command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001314 return err;
1315 }
1316
1317 return finalize_and_send(dev, start_opal_session_cont);
1318}
1319
Jon Derrickeed64952017-02-22 07:55:13 -07001320static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001321{
1322 return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1323 OPAL_ADMINSP_UID, NULL, 0);
1324}
1325
Jon Derrickeed64952017-02-22 07:55:13 -07001326static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001327{
1328 int ret;
1329 const u8 *key = dev->prev_data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001330
1331 if (!key) {
Jon Derrickeed64952017-02-22 07:55:13 -07001332 const struct opal_key *okey = data;
David Kozub1e815b32019-02-14 01:15:54 +01001333
Scott Bauer455a7b22017-02-03 12:50:31 -07001334 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1335 OPAL_ADMINSP_UID,
1336 okey->key,
1337 okey->key_len);
1338 } else {
1339 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1340 OPAL_ADMINSP_UID,
1341 key, dev->prev_d_len);
1342 kfree(key);
1343 dev->prev_data = NULL;
1344 }
1345 return ret;
1346}
1347
Jon Derrickeed64952017-02-22 07:55:13 -07001348static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001349{
Jon Derrickeed64952017-02-22 07:55:13 -07001350 struct opal_key *key = data;
David Kozub1e815b32019-02-14 01:15:54 +01001351
Scott Bauer455a7b22017-02-03 12:50:31 -07001352 return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1353 OPAL_LOCKINGSP_UID,
1354 key->key, key->key_len);
1355}
1356
Jon Derrickeed64952017-02-22 07:55:13 -07001357static int start_auth_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001358{
Jon Derrickeed64952017-02-22 07:55:13 -07001359 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001360 u8 lk_ul_user[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001361 size_t keylen = session->opal_key.key_len;
Scott Bauer455a7b22017-02-03 12:50:31 -07001362 int err = 0;
1363
Scott Bauer455a7b22017-02-03 12:50:31 -07001364 u8 *key = session->opal_key.key;
1365 u32 hsn = GENERIC_HOST_SESSION_NUM;
1366
1367 clear_opal_cmd(dev);
1368 set_comid(dev, dev->comid);
1369
1370 if (session->sum) {
1371 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1372 session->opal_key.lr);
1373 if (err)
1374 return err;
1375
1376 } else if (session->who != OPAL_ADMIN1 && !session->sum) {
1377 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1378 session->who - 1);
1379 if (err)
1380 return err;
1381 } else
1382 memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1383
1384 add_token_u8(&err, dev, OPAL_CALL);
1385 add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
1386 OPAL_UID_LENGTH);
1387 add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
1388 OPAL_UID_LENGTH);
1389
1390 add_token_u8(&err, dev, OPAL_STARTLIST);
1391 add_token_u64(&err, dev, hsn);
1392 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1393 OPAL_UID_LENGTH);
1394 add_token_u8(&err, dev, 1);
1395 add_token_u8(&err, dev, OPAL_STARTNAME);
1396 add_token_u8(&err, dev, 0);
1397 add_token_bytestring(&err, dev, key, keylen);
1398 add_token_u8(&err, dev, OPAL_ENDNAME);
1399 add_token_u8(&err, dev, OPAL_STARTNAME);
1400 add_token_u8(&err, dev, 3);
1401 add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1402 add_token_u8(&err, dev, OPAL_ENDNAME);
1403 add_token_u8(&err, dev, OPAL_ENDLIST);
1404
1405 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001406 pr_debug("Error building STARTSESSION command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001407 return err;
1408 }
1409
1410 return finalize_and_send(dev, start_opal_session_cont);
1411}
1412
Jon Derrickeed64952017-02-22 07:55:13 -07001413static int revert_tper(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001414{
1415 int err = 0;
1416
1417 clear_opal_cmd(dev);
1418 set_comid(dev, dev->comid);
1419
1420 add_token_u8(&err, dev, OPAL_CALL);
1421 add_token_bytestring(&err, dev, opaluid[OPAL_ADMINSP_UID],
1422 OPAL_UID_LENGTH);
1423 add_token_bytestring(&err, dev, opalmethod[OPAL_REVERT],
1424 OPAL_UID_LENGTH);
1425 add_token_u8(&err, dev, OPAL_STARTLIST);
1426 add_token_u8(&err, dev, OPAL_ENDLIST);
1427 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001428 pr_debug("Error building REVERT TPER command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001429 return err;
1430 }
1431
1432 return finalize_and_send(dev, parse_and_check_status);
1433}
1434
Jon Derrickeed64952017-02-22 07:55:13 -07001435static int internal_activate_user(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001436{
Jon Derrickeed64952017-02-22 07:55:13 -07001437 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001438 u8 uid[OPAL_UID_LENGTH];
1439 int err = 0;
1440
1441 clear_opal_cmd(dev);
1442 set_comid(dev, dev->comid);
1443
1444 memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1445 uid[7] = session->who;
1446
1447 add_token_u8(&err, dev, OPAL_CALL);
1448 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1449 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1450 add_token_u8(&err, dev, OPAL_STARTLIST);
1451 add_token_u8(&err, dev, OPAL_STARTNAME);
1452 add_token_u8(&err, dev, OPAL_VALUES);
1453 add_token_u8(&err, dev, OPAL_STARTLIST);
1454 add_token_u8(&err, dev, OPAL_STARTNAME);
1455 add_token_u8(&err, dev, 5); /* Enabled */
1456 add_token_u8(&err, dev, OPAL_TRUE);
1457 add_token_u8(&err, dev, OPAL_ENDNAME);
1458 add_token_u8(&err, dev, OPAL_ENDLIST);
1459 add_token_u8(&err, dev, OPAL_ENDNAME);
1460 add_token_u8(&err, dev, OPAL_ENDLIST);
1461
1462 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001463 pr_debug("Error building Activate UserN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001464 return err;
1465 }
1466
1467 return finalize_and_send(dev, parse_and_check_status);
1468}
1469
Jon Derrickeed64952017-02-22 07:55:13 -07001470static int erase_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001471{
Jon Derrickeed64952017-02-22 07:55:13 -07001472 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001473 u8 uid[OPAL_UID_LENGTH];
1474 int err = 0;
1475
1476 clear_opal_cmd(dev);
1477 set_comid(dev, dev->comid);
Scott Bauer455a7b22017-02-03 12:50:31 -07001478
1479 if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1480 return -ERANGE;
1481
1482 add_token_u8(&err, dev, OPAL_CALL);
1483 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1484 add_token_bytestring(&err, dev, opalmethod[OPAL_ERASE],
1485 OPAL_UID_LENGTH);
1486 add_token_u8(&err, dev, OPAL_STARTLIST);
1487 add_token_u8(&err, dev, OPAL_ENDLIST);
1488
1489 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001490 pr_debug("Error building Erase Locking Range Command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001491 return err;
1492 }
1493 return finalize_and_send(dev, parse_and_check_status);
1494}
1495
Jon Derrickeed64952017-02-22 07:55:13 -07001496static int set_mbr_done(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001497{
Jon Derrickeed64952017-02-22 07:55:13 -07001498 u8 *mbr_done_tf = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001499 int err = 0;
1500
1501 clear_opal_cmd(dev);
1502 set_comid(dev, dev->comid);
1503
1504 add_token_u8(&err, dev, OPAL_CALL);
1505 add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL],
1506 OPAL_UID_LENGTH);
1507 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1508 add_token_u8(&err, dev, OPAL_STARTLIST);
1509 add_token_u8(&err, dev, OPAL_STARTNAME);
1510 add_token_u8(&err, dev, OPAL_VALUES);
1511 add_token_u8(&err, dev, OPAL_STARTLIST);
1512 add_token_u8(&err, dev, OPAL_STARTNAME);
1513 add_token_u8(&err, dev, 2); /* Done */
Jon Derrickeed64952017-02-22 07:55:13 -07001514 add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
Scott Bauer455a7b22017-02-03 12:50:31 -07001515 add_token_u8(&err, dev, OPAL_ENDNAME);
1516 add_token_u8(&err, dev, OPAL_ENDLIST);
1517 add_token_u8(&err, dev, OPAL_ENDNAME);
1518 add_token_u8(&err, dev, OPAL_ENDLIST);
1519
1520 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001521 pr_debug("Error Building set MBR Done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001522 return err;
1523 }
1524
1525 return finalize_and_send(dev, parse_and_check_status);
1526}
1527
Jon Derrickeed64952017-02-22 07:55:13 -07001528static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001529{
Jon Derrickeed64952017-02-22 07:55:13 -07001530 u8 *mbr_en_dis = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001531 int err = 0;
1532
1533 clear_opal_cmd(dev);
1534 set_comid(dev, dev->comid);
1535
1536 add_token_u8(&err, dev, OPAL_CALL);
1537 add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL],
1538 OPAL_UID_LENGTH);
1539 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1540 add_token_u8(&err, dev, OPAL_STARTLIST);
1541 add_token_u8(&err, dev, OPAL_STARTNAME);
1542 add_token_u8(&err, dev, OPAL_VALUES);
1543 add_token_u8(&err, dev, OPAL_STARTLIST);
1544 add_token_u8(&err, dev, OPAL_STARTNAME);
1545 add_token_u8(&err, dev, 1);
Jon Derrickeed64952017-02-22 07:55:13 -07001546 add_token_u8(&err, dev, *mbr_en_dis);
Scott Bauer455a7b22017-02-03 12:50:31 -07001547 add_token_u8(&err, dev, OPAL_ENDNAME);
1548 add_token_u8(&err, dev, OPAL_ENDLIST);
1549 add_token_u8(&err, dev, OPAL_ENDNAME);
1550 add_token_u8(&err, dev, OPAL_ENDLIST);
1551
1552 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001553 pr_debug("Error Building set MBR done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001554 return err;
1555 }
1556
1557 return finalize_and_send(dev, parse_and_check_status);
1558}
1559
1560static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1561 struct opal_dev *dev)
1562{
1563 int err = 0;
1564
1565 clear_opal_cmd(dev);
1566 set_comid(dev, dev->comid);
1567
1568 add_token_u8(&err, dev, OPAL_CALL);
1569 add_token_bytestring(&err, dev, cpin_uid, OPAL_UID_LENGTH);
1570 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1571 OPAL_UID_LENGTH);
1572 add_token_u8(&err, dev, OPAL_STARTLIST);
1573 add_token_u8(&err, dev, OPAL_STARTNAME);
1574 add_token_u8(&err, dev, OPAL_VALUES);
1575 add_token_u8(&err, dev, OPAL_STARTLIST);
1576 add_token_u8(&err, dev, OPAL_STARTNAME);
1577 add_token_u8(&err, dev, 3); /* PIN */
1578 add_token_bytestring(&err, dev, key, key_len);
1579 add_token_u8(&err, dev, OPAL_ENDNAME);
1580 add_token_u8(&err, dev, OPAL_ENDLIST);
1581 add_token_u8(&err, dev, OPAL_ENDNAME);
1582 add_token_u8(&err, dev, OPAL_ENDLIST);
1583
1584 return err;
1585}
1586
Jon Derrickeed64952017-02-22 07:55:13 -07001587static int set_new_pw(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001588{
1589 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001590 struct opal_session_info *usr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001591
1592 memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1593
1594 if (usr->who != OPAL_ADMIN1) {
1595 cpin_uid[5] = 0x03;
1596 if (usr->sum)
1597 cpin_uid[7] = usr->opal_key.lr + 1;
1598 else
1599 cpin_uid[7] = usr->who;
1600 }
1601
1602 if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1603 cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001604 pr_debug("Error building set password command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001605 return -ERANGE;
1606 }
1607
1608 return finalize_and_send(dev, parse_and_check_status);
1609}
1610
Jon Derrickeed64952017-02-22 07:55:13 -07001611static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001612{
1613 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001614 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001615
1616 memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1617
1618 if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001619 pr_debug("Error building Set SID cpin\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001620 return -ERANGE;
1621 }
1622 return finalize_and_send(dev, parse_and_check_status);
1623}
1624
Jon Derrickeed64952017-02-22 07:55:13 -07001625static int add_user_to_lr(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001626{
1627 u8 lr_buffer[OPAL_UID_LENGTH];
1628 u8 user_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001629 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001630 int err = 0;
1631
1632 clear_opal_cmd(dev);
1633 set_comid(dev, dev->comid);
1634
Scott Bauer455a7b22017-02-03 12:50:31 -07001635 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1636 OPAL_UID_LENGTH);
1637
1638 if (lkul->l_state == OPAL_RW)
1639 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1640 OPAL_UID_LENGTH);
1641
1642 lr_buffer[7] = lkul->session.opal_key.lr;
1643
1644 memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1645
1646 user_uid[7] = lkul->session.who;
1647
1648 add_token_u8(&err, dev, OPAL_CALL);
1649 add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
1650 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1651 OPAL_UID_LENGTH);
1652
1653 add_token_u8(&err, dev, OPAL_STARTLIST);
1654 add_token_u8(&err, dev, OPAL_STARTNAME);
1655 add_token_u8(&err, dev, OPAL_VALUES);
1656
1657 add_token_u8(&err, dev, OPAL_STARTLIST);
1658 add_token_u8(&err, dev, OPAL_STARTNAME);
1659 add_token_u8(&err, dev, 3);
1660
1661 add_token_u8(&err, dev, OPAL_STARTLIST);
1662
1663
1664 add_token_u8(&err, dev, OPAL_STARTNAME);
1665 add_token_bytestring(&err, dev,
1666 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1667 OPAL_UID_LENGTH/2);
1668 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1669 add_token_u8(&err, dev, OPAL_ENDNAME);
1670
1671
1672 add_token_u8(&err, dev, OPAL_STARTNAME);
1673 add_token_bytestring(&err, dev,
1674 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1675 OPAL_UID_LENGTH/2);
1676 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1677 add_token_u8(&err, dev, OPAL_ENDNAME);
1678
1679
1680 add_token_u8(&err, dev, OPAL_STARTNAME);
1681 add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1682 OPAL_UID_LENGTH/2);
1683 add_token_u8(&err, dev, 1);
1684 add_token_u8(&err, dev, OPAL_ENDNAME);
1685
1686
1687 add_token_u8(&err, dev, OPAL_ENDLIST);
1688 add_token_u8(&err, dev, OPAL_ENDNAME);
1689 add_token_u8(&err, dev, OPAL_ENDLIST);
1690 add_token_u8(&err, dev, OPAL_ENDNAME);
1691 add_token_u8(&err, dev, OPAL_ENDLIST);
1692
1693 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001694 pr_debug("Error building add user to locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001695 return err;
1696 }
1697
1698 return finalize_and_send(dev, parse_and_check_status);
1699}
1700
Jon Derrickeed64952017-02-22 07:55:13 -07001701static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001702{
1703 u8 lr_buffer[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001704 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001705 u8 read_locked = 1, write_locked = 1;
1706 int err = 0;
1707
1708 clear_opal_cmd(dev);
1709 set_comid(dev, dev->comid);
1710
Scott Bauer455a7b22017-02-03 12:50:31 -07001711 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1712 lkul->session.opal_key.lr) < 0)
1713 return -ERANGE;
1714
1715 switch (lkul->l_state) {
1716 case OPAL_RO:
1717 read_locked = 0;
1718 write_locked = 1;
1719 break;
1720 case OPAL_RW:
1721 read_locked = 0;
1722 write_locked = 0;
1723 break;
1724 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001725 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001726 break;
1727 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001728 pr_debug("Tried to set an invalid locking state... returning to uland\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001729 return OPAL_INVAL_PARAM;
1730 }
1731
1732 add_token_u8(&err, dev, OPAL_CALL);
1733 add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
1734 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1735 add_token_u8(&err, dev, OPAL_STARTLIST);
1736 add_token_u8(&err, dev, OPAL_STARTNAME);
1737 add_token_u8(&err, dev, OPAL_VALUES);
1738 add_token_u8(&err, dev, OPAL_STARTLIST);
1739
1740 add_token_u8(&err, dev, OPAL_STARTNAME);
1741 add_token_u8(&err, dev, OPAL_READLOCKED);
1742 add_token_u8(&err, dev, read_locked);
1743 add_token_u8(&err, dev, OPAL_ENDNAME);
1744
1745 add_token_u8(&err, dev, OPAL_STARTNAME);
1746 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1747 add_token_u8(&err, dev, write_locked);
1748 add_token_u8(&err, dev, OPAL_ENDNAME);
1749
1750 add_token_u8(&err, dev, OPAL_ENDLIST);
1751 add_token_u8(&err, dev, OPAL_ENDNAME);
1752 add_token_u8(&err, dev, OPAL_ENDLIST);
1753
1754 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001755 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001756 return err;
1757 }
1758 return finalize_and_send(dev, parse_and_check_status);
1759}
1760
1761
Jon Derrickeed64952017-02-22 07:55:13 -07001762static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001763{
1764 u8 lr_buffer[OPAL_UID_LENGTH];
1765 u8 read_locked = 1, write_locked = 1;
Jon Derrickeed64952017-02-22 07:55:13 -07001766 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001767 int ret;
1768
1769 clear_opal_cmd(dev);
1770 set_comid(dev, dev->comid);
1771
Scott Bauer455a7b22017-02-03 12:50:31 -07001772 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1773 lkul->session.opal_key.lr) < 0)
1774 return -ERANGE;
1775
1776 switch (lkul->l_state) {
1777 case OPAL_RO:
1778 read_locked = 0;
1779 write_locked = 1;
1780 break;
1781 case OPAL_RW:
1782 read_locked = 0;
1783 write_locked = 0;
1784 break;
1785 case OPAL_LK:
David Kozub1e815b32019-02-14 01:15:54 +01001786 /* vars are initialized to locked */
Scott Bauer455a7b22017-02-03 12:50:31 -07001787 break;
1788 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001789 pr_debug("Tried to set an invalid locking state.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001790 return OPAL_INVAL_PARAM;
1791 }
1792 ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1793 read_locked, write_locked);
1794
1795 if (ret < 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001796 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001797 return ret;
1798 }
1799 return finalize_and_send(dev, parse_and_check_status);
1800}
1801
Jon Derrickeed64952017-02-22 07:55:13 -07001802static int activate_lsp(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001803{
Jon Derrickeed64952017-02-22 07:55:13 -07001804 struct opal_lr_act *opal_act = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001805 u8 user_lr[OPAL_UID_LENGTH];
1806 u8 uint_3 = 0x83;
1807 int err = 0, i;
1808
1809 clear_opal_cmd(dev);
1810 set_comid(dev, dev->comid);
1811
Scott Bauer455a7b22017-02-03 12:50:31 -07001812 add_token_u8(&err, dev, OPAL_CALL);
1813 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1814 OPAL_UID_LENGTH);
1815 add_token_bytestring(&err, dev, opalmethod[OPAL_ACTIVATE],
1816 OPAL_UID_LENGTH);
1817
1818
1819 if (opal_act->sum) {
1820 err = build_locking_range(user_lr, sizeof(user_lr),
1821 opal_act->lr[0]);
1822 if (err)
1823 return err;
1824
1825 add_token_u8(&err, dev, OPAL_STARTLIST);
1826 add_token_u8(&err, dev, OPAL_STARTNAME);
1827 add_token_u8(&err, dev, uint_3);
1828 add_token_u8(&err, dev, 6);
1829 add_token_u8(&err, dev, 0);
1830 add_token_u8(&err, dev, 0);
1831
1832 add_token_u8(&err, dev, OPAL_STARTLIST);
1833 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1834 for (i = 1; i < opal_act->num_lrs; i++) {
1835 user_lr[7] = opal_act->lr[i];
1836 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1837 }
1838 add_token_u8(&err, dev, OPAL_ENDLIST);
1839 add_token_u8(&err, dev, OPAL_ENDNAME);
1840 add_token_u8(&err, dev, OPAL_ENDLIST);
1841
1842 } else {
1843 add_token_u8(&err, dev, OPAL_STARTLIST);
1844 add_token_u8(&err, dev, OPAL_ENDLIST);
1845 }
1846
1847 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001848 pr_debug("Error building Activate LockingSP command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001849 return err;
1850 }
1851
1852 return finalize_and_send(dev, parse_and_check_status);
1853}
1854
1855static int get_lsp_lifecycle_cont(struct opal_dev *dev)
1856{
1857 u8 lc_status;
1858 int error = 0;
1859
1860 error = parse_and_check_status(dev);
1861 if (error)
1862 return error;
1863
1864 lc_status = response_get_u64(&dev->parsed, 4);
David Kozub1e815b32019-02-14 01:15:54 +01001865 /* 0x08 is Manufactured Inactive */
Scott Bauer455a7b22017-02-03 12:50:31 -07001866 /* 0x09 is Manufactured */
1867 if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001868 pr_debug("Couldn't determine the status of the Lifecycle state\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001869 return -ENODEV;
1870 }
1871
1872 return 0;
1873}
1874
1875/* Determine if we're in the Manufactured Inactive or Active state */
Jon Derrickeed64952017-02-22 07:55:13 -07001876static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001877{
1878 int err = 0;
1879
1880 clear_opal_cmd(dev);
1881 set_comid(dev, dev->comid);
1882
1883 add_token_u8(&err, dev, OPAL_CALL);
1884 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1885 OPAL_UID_LENGTH);
1886 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1887
1888 add_token_u8(&err, dev, OPAL_STARTLIST);
1889 add_token_u8(&err, dev, OPAL_STARTLIST);
1890
1891 add_token_u8(&err, dev, OPAL_STARTNAME);
1892 add_token_u8(&err, dev, 3); /* Start Column */
1893 add_token_u8(&err, dev, 6); /* Lifecycle Column */
1894 add_token_u8(&err, dev, OPAL_ENDNAME);
1895
1896 add_token_u8(&err, dev, OPAL_STARTNAME);
1897 add_token_u8(&err, dev, 4); /* End Column */
1898 add_token_u8(&err, dev, 6); /* Lifecycle Column */
1899 add_token_u8(&err, dev, OPAL_ENDNAME);
1900
1901 add_token_u8(&err, dev, OPAL_ENDLIST);
1902 add_token_u8(&err, dev, OPAL_ENDLIST);
1903
1904 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001905 pr_debug("Error Building GET Lifecycle Status command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001906 return err;
1907 }
1908
1909 return finalize_and_send(dev, get_lsp_lifecycle_cont);
1910}
1911
1912static int get_msid_cpin_pin_cont(struct opal_dev *dev)
1913{
1914 const char *msid_pin;
1915 size_t strlen;
1916 int error = 0;
1917
1918 error = parse_and_check_status(dev);
1919 if (error)
1920 return error;
1921
1922 strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1923 if (!msid_pin) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001924 pr_debug("%s: Couldn't extract PIN from response\n", __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001925 return OPAL_INVAL_PARAM;
1926 }
1927
1928 dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1929 if (!dev->prev_data)
1930 return -ENOMEM;
1931
1932 dev->prev_d_len = strlen;
1933
1934 return 0;
1935}
1936
Jon Derrickeed64952017-02-22 07:55:13 -07001937static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001938{
1939 int err = 0;
1940
1941 clear_opal_cmd(dev);
1942 set_comid(dev, dev->comid);
1943
Scott Bauer455a7b22017-02-03 12:50:31 -07001944 add_token_u8(&err, dev, OPAL_CALL);
1945 add_token_bytestring(&err, dev, opaluid[OPAL_C_PIN_MSID],
1946 OPAL_UID_LENGTH);
1947 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1948
1949 add_token_u8(&err, dev, OPAL_STARTLIST);
1950 add_token_u8(&err, dev, OPAL_STARTLIST);
1951
1952 add_token_u8(&err, dev, OPAL_STARTNAME);
1953 add_token_u8(&err, dev, 3); /* Start Column */
1954 add_token_u8(&err, dev, 3); /* PIN */
1955 add_token_u8(&err, dev, OPAL_ENDNAME);
1956
1957 add_token_u8(&err, dev, OPAL_STARTNAME);
1958 add_token_u8(&err, dev, 4); /* End Column */
1959 add_token_u8(&err, dev, 3); /* Lifecycle Column */
1960 add_token_u8(&err, dev, OPAL_ENDNAME);
1961
1962 add_token_u8(&err, dev, OPAL_ENDLIST);
1963 add_token_u8(&err, dev, OPAL_ENDLIST);
1964
1965 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001966 pr_debug("Error building Get MSID CPIN PIN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001967 return err;
1968 }
1969
1970 return finalize_and_send(dev, get_msid_cpin_pin_cont);
1971}
1972
Jon Derrickeed64952017-02-22 07:55:13 -07001973static int end_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001974{
1975 int err = 0;
1976
1977 clear_opal_cmd(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001978 set_comid(dev, dev->comid);
1979 add_token_u8(&err, dev, OPAL_ENDOFSESSION);
Scott Bauer455a7b22017-02-03 12:50:31 -07001980
Jon Derrickeed64952017-02-22 07:55:13 -07001981 if (err < 0)
1982 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001983 return finalize_and_send(dev, end_session_cont);
1984}
1985
1986static int end_opal_session_error(struct opal_dev *dev)
1987{
Jon Derrickeed64952017-02-22 07:55:13 -07001988 const struct opal_step error_end_session[] = {
1989 { end_opal_session, },
1990 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001991 };
Jon Derrickeed64952017-02-22 07:55:13 -07001992 dev->steps = error_end_session;
Scott Bauer455a7b22017-02-03 12:50:31 -07001993 return next(dev);
1994}
1995
1996static inline void setup_opal_dev(struct opal_dev *dev,
Jon Derrickeed64952017-02-22 07:55:13 -07001997 const struct opal_step *steps)
Scott Bauer455a7b22017-02-03 12:50:31 -07001998{
Jon Derrickeed64952017-02-22 07:55:13 -07001999 dev->steps = steps;
Scott Bauer455a7b22017-02-03 12:50:31 -07002000 dev->tsn = 0;
2001 dev->hsn = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -07002002 dev->prev_data = NULL;
2003}
2004
2005static int check_opal_support(struct opal_dev *dev)
2006{
Jon Derrickeed64952017-02-22 07:55:13 -07002007 const struct opal_step steps[] = {
2008 { opal_discovery0, },
2009 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002010 };
2011 int ret;
2012
2013 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002014 setup_opal_dev(dev, steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002015 ret = next(dev);
2016 dev->supported = !ret;
2017 mutex_unlock(&dev->dev_lock);
2018 return ret;
2019}
2020
Scott Bauer7d6d1572017-02-22 10:15:06 -07002021static void clean_opal_dev(struct opal_dev *dev)
2022{
2023
2024 struct opal_suspend_data *suspend, *next;
2025
2026 mutex_lock(&dev->dev_lock);
2027 list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
2028 list_del(&suspend->node);
2029 kfree(suspend);
2030 }
2031 mutex_unlock(&dev->dev_lock);
2032}
2033
2034void free_opal_dev(struct opal_dev *dev)
2035{
2036 if (!dev)
2037 return;
2038 clean_opal_dev(dev);
2039 kfree(dev);
2040}
2041EXPORT_SYMBOL(free_opal_dev);
2042
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002043struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
Scott Bauer455a7b22017-02-03 12:50:31 -07002044{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002045 struct opal_dev *dev;
2046
2047 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
2048 if (!dev)
2049 return NULL;
2050
2051 INIT_LIST_HEAD(&dev->unlk_lst);
2052 mutex_init(&dev->dev_lock);
2053 dev->data = data;
2054 dev->send_recv = send_recv;
2055 if (check_opal_support(dev) != 0) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +01002056 pr_debug("Opal is not supported on this device\n");
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002057 kfree(dev);
2058 return NULL;
2059 }
2060 return dev;
Scott Bauer455a7b22017-02-03 12:50:31 -07002061}
2062EXPORT_SYMBOL(init_opal_dev);
2063
2064static int opal_secure_erase_locking_range(struct opal_dev *dev,
2065 struct opal_session_info *opal_session)
2066{
Jon Derrickeed64952017-02-22 07:55:13 -07002067 const struct opal_step erase_steps[] = {
2068 { opal_discovery0, },
2069 { start_auth_opal_session, opal_session },
2070 { get_active_key, &opal_session->opal_key.lr },
2071 { gen_key, },
2072 { end_opal_session, },
2073 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002074 };
2075 int ret;
2076
2077 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002078 setup_opal_dev(dev, erase_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002079 ret = next(dev);
2080 mutex_unlock(&dev->dev_lock);
2081 return ret;
2082}
2083
2084static int opal_erase_locking_range(struct opal_dev *dev,
2085 struct opal_session_info *opal_session)
2086{
Jon Derrickeed64952017-02-22 07:55:13 -07002087 const struct opal_step erase_steps[] = {
2088 { opal_discovery0, },
2089 { start_auth_opal_session, opal_session },
2090 { erase_locking_range, opal_session },
2091 { end_opal_session, },
2092 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002093 };
2094 int ret;
2095
2096 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002097 setup_opal_dev(dev, erase_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002098 ret = next(dev);
2099 mutex_unlock(&dev->dev_lock);
2100 return ret;
2101}
2102
2103static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
2104 struct opal_mbr_data *opal_mbr)
2105{
David Kozub78bf4732019-02-14 01:15:53 +01002106 u8 enable_disable = opal_mbr->enable_disable == OPAL_MBR_ENABLE ?
2107 OPAL_TRUE : OPAL_FALSE;
2108
Jon Derrickeed64952017-02-22 07:55:13 -07002109 const struct opal_step mbr_steps[] = {
2110 { opal_discovery0, },
2111 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01002112 { set_mbr_done, &enable_disable },
Jon Derrickeed64952017-02-22 07:55:13 -07002113 { end_opal_session, },
2114 { start_admin1LSP_opal_session, &opal_mbr->key },
David Kozub78bf4732019-02-14 01:15:53 +01002115 { set_mbr_enable_disable, &enable_disable },
Jon Derrickeed64952017-02-22 07:55:13 -07002116 { end_opal_session, },
2117 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002118 };
2119 int ret;
2120
2121 if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
2122 opal_mbr->enable_disable != OPAL_MBR_DISABLE)
2123 return -EINVAL;
2124
2125 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002126 setup_opal_dev(dev, mbr_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002127 ret = next(dev);
2128 mutex_unlock(&dev->dev_lock);
2129 return ret;
2130}
2131
2132static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
2133{
2134 struct opal_suspend_data *suspend;
2135
2136 suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
2137 if (!suspend)
2138 return -ENOMEM;
2139
2140 suspend->unlk = *lk_unlk;
2141 suspend->lr = lk_unlk->session.opal_key.lr;
2142
2143 mutex_lock(&dev->dev_lock);
2144 setup_opal_dev(dev, NULL);
2145 add_suspend_info(dev, suspend);
2146 mutex_unlock(&dev->dev_lock);
2147 return 0;
2148}
2149
2150static int opal_add_user_to_lr(struct opal_dev *dev,
2151 struct opal_lock_unlock *lk_unlk)
2152{
Jon Derrickeed64952017-02-22 07:55:13 -07002153 const struct opal_step steps[] = {
2154 { opal_discovery0, },
2155 { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2156 { add_user_to_lr, lk_unlk },
2157 { end_opal_session, },
2158 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002159 };
2160 int ret;
2161
2162 if (lk_unlk->l_state != OPAL_RO &&
2163 lk_unlk->l_state != OPAL_RW) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002164 pr_debug("Locking state was not RO or RW\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07002165 return -EINVAL;
2166 }
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002167 if (lk_unlk->session.who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002168 lk_unlk->session.who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002169 pr_debug("Authority was not within the range of users: %d\n",
2170 lk_unlk->session.who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002171 return -EINVAL;
2172 }
2173 if (lk_unlk->session.sum) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002174 pr_debug("%s not supported in sum. Use setup locking range\n",
2175 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07002176 return -EINVAL;
2177 }
2178
2179 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002180 setup_opal_dev(dev, steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002181 ret = next(dev);
2182 mutex_unlock(&dev->dev_lock);
2183 return ret;
2184}
2185
2186static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal)
2187{
Jon Derrickeed64952017-02-22 07:55:13 -07002188 const struct opal_step revert_steps[] = {
2189 { opal_discovery0, },
2190 { start_SIDASP_opal_session, opal },
2191 { revert_tper, }, /* controller will terminate session */
2192 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002193 };
2194 int ret;
2195
2196 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002197 setup_opal_dev(dev, revert_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002198 ret = next(dev);
2199 mutex_unlock(&dev->dev_lock);
Scott Bauer7d6d1572017-02-22 10:15:06 -07002200
2201 /*
2202 * If we successfully reverted lets clean
2203 * any saved locking ranges.
2204 */
2205 if (!ret)
2206 clean_opal_dev(dev);
2207
Scott Bauer455a7b22017-02-03 12:50:31 -07002208 return ret;
2209}
2210
Jon Derrickeed64952017-02-22 07:55:13 -07002211static int __opal_lock_unlock(struct opal_dev *dev,
2212 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002213{
Jon Derrickeed64952017-02-22 07:55:13 -07002214 const struct opal_step unlock_steps[] = {
2215 { opal_discovery0, },
2216 { start_auth_opal_session, &lk_unlk->session },
2217 { lock_unlock_locking_range, lk_unlk },
2218 { end_opal_session, },
2219 { NULL, }
2220 };
2221 const struct opal_step unlock_sum_steps[] = {
2222 { opal_discovery0, },
2223 { start_auth_opal_session, &lk_unlk->session },
2224 { lock_unlock_locking_range_sum, lk_unlk },
2225 { end_opal_session, },
2226 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002227 };
2228
Jon Derrickeed64952017-02-22 07:55:13 -07002229 dev->steps = lk_unlk->session.sum ? unlock_sum_steps : unlock_steps;
Scott Bauer455a7b22017-02-03 12:50:31 -07002230 return next(dev);
2231}
2232
Scott Bauerdbec491b2017-09-01 08:53:35 -06002233static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2234{
David Kozub78bf4732019-02-14 01:15:53 +01002235 u8 mbr_done_tf = OPAL_TRUE;
David Kozub1e815b32019-02-14 01:15:54 +01002236 const struct opal_step mbrdone_step[] = {
Scott Bauerdbec491b2017-09-01 08:53:35 -06002237 { opal_discovery0, },
2238 { start_admin1LSP_opal_session, key },
2239 { set_mbr_done, &mbr_done_tf },
2240 { end_opal_session, },
2241 { NULL, }
2242 };
2243
2244 dev->steps = mbrdone_step;
2245 return next(dev);
2246}
2247
Jon Derrickeed64952017-02-22 07:55:13 -07002248static int opal_lock_unlock(struct opal_dev *dev,
2249 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002250{
Scott Bauer455a7b22017-02-03 12:50:31 -07002251 int ret;
2252
2253 if (lk_unlk->session.who < OPAL_ADMIN1 ||
2254 lk_unlk->session.who > OPAL_USER9)
2255 return -EINVAL;
2256
2257 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002258 ret = __opal_lock_unlock(dev, lk_unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002259 mutex_unlock(&dev->dev_lock);
2260 return ret;
2261}
2262
2263static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2264{
Jon Derrickeed64952017-02-22 07:55:13 -07002265 const struct opal_step owner_steps[] = {
2266 { opal_discovery0, },
2267 { start_anybodyASP_opal_session, },
2268 { get_msid_cpin_pin, },
2269 { end_opal_session, },
2270 { start_SIDASP_opal_session, opal },
2271 { set_sid_cpin_pin, opal },
2272 { end_opal_session, },
2273 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002274 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002275 int ret;
2276
2277 if (!dev)
2278 return -ENODEV;
2279
2280 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002281 setup_opal_dev(dev, owner_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002282 ret = next(dev);
2283 mutex_unlock(&dev->dev_lock);
2284 return ret;
2285}
2286
David Kozub1e815b32019-02-14 01:15:54 +01002287static int opal_activate_lsp(struct opal_dev *dev,
2288 struct opal_lr_act *opal_lr_act)
Scott Bauer455a7b22017-02-03 12:50:31 -07002289{
Jon Derrickeed64952017-02-22 07:55:13 -07002290 const struct opal_step active_steps[] = {
2291 { opal_discovery0, },
2292 { start_SIDASP_opal_session, &opal_lr_act->key },
2293 { get_lsp_lifecycle, },
2294 { activate_lsp, opal_lr_act },
2295 { end_opal_session, },
2296 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002297 };
2298 int ret;
2299
2300 if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2301 return -EINVAL;
2302
2303 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002304 setup_opal_dev(dev, active_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002305 ret = next(dev);
2306 mutex_unlock(&dev->dev_lock);
2307 return ret;
2308}
2309
2310static int opal_setup_locking_range(struct opal_dev *dev,
2311 struct opal_user_lr_setup *opal_lrs)
2312{
Jon Derrickeed64952017-02-22 07:55:13 -07002313 const struct opal_step lr_steps[] = {
2314 { opal_discovery0, },
2315 { start_auth_opal_session, &opal_lrs->session },
2316 { setup_locking_range, opal_lrs },
2317 { end_opal_session, },
2318 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002319 };
2320 int ret;
2321
2322 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002323 setup_opal_dev(dev, lr_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002324 ret = next(dev);
2325 mutex_unlock(&dev->dev_lock);
2326 return ret;
2327}
2328
2329static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2330{
Jon Derrickeed64952017-02-22 07:55:13 -07002331 const struct opal_step pw_steps[] = {
2332 { opal_discovery0, },
2333 { start_auth_opal_session, &opal_pw->session },
2334 { set_new_pw, &opal_pw->new_user_pw },
2335 { end_opal_session, },
2336 { NULL }
Scott Bauer455a7b22017-02-03 12:50:31 -07002337 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002338 int ret;
2339
2340 if (opal_pw->session.who < OPAL_ADMIN1 ||
2341 opal_pw->session.who > OPAL_USER9 ||
2342 opal_pw->new_user_pw.who < OPAL_ADMIN1 ||
2343 opal_pw->new_user_pw.who > OPAL_USER9)
2344 return -EINVAL;
2345
2346 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002347 setup_opal_dev(dev, pw_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002348 ret = next(dev);
2349 mutex_unlock(&dev->dev_lock);
2350 return ret;
2351}
2352
2353static int opal_activate_user(struct opal_dev *dev,
2354 struct opal_session_info *opal_session)
2355{
Jon Derrickeed64952017-02-22 07:55:13 -07002356 const struct opal_step act_steps[] = {
2357 { opal_discovery0, },
2358 { start_admin1LSP_opal_session, &opal_session->opal_key },
2359 { internal_activate_user, opal_session },
2360 { end_opal_session, },
2361 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002362 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002363 int ret;
2364
2365 /* We can't activate Admin1 it's active as manufactured */
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002366 if (opal_session->who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002367 opal_session->who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002368 pr_debug("Who was not a valid user: %d\n", opal_session->who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002369 return -EINVAL;
2370 }
2371
2372 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002373 setup_opal_dev(dev, act_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002374 ret = next(dev);
2375 mutex_unlock(&dev->dev_lock);
2376 return ret;
2377}
2378
2379bool opal_unlock_from_suspend(struct opal_dev *dev)
2380{
2381 struct opal_suspend_data *suspend;
Scott Bauer455a7b22017-02-03 12:50:31 -07002382 bool was_failure = false;
2383 int ret = 0;
2384
2385 if (!dev)
2386 return false;
2387 if (!dev->supported)
2388 return false;
2389
2390 mutex_lock(&dev->dev_lock);
2391 setup_opal_dev(dev, NULL);
Scott Bauer455a7b22017-02-03 12:50:31 -07002392
2393 list_for_each_entry(suspend, &dev->unlk_lst, node) {
Scott Bauer455a7b22017-02-03 12:50:31 -07002394 dev->tsn = 0;
2395 dev->hsn = 0;
2396
Jon Derrickeed64952017-02-22 07:55:13 -07002397 ret = __opal_lock_unlock(dev, &suspend->unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002398 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002399 pr_debug("Failed to unlock LR %hhu with sum %d\n",
2400 suspend->unlk.session.opal_key.lr,
2401 suspend->unlk.session.sum);
Scott Bauer455a7b22017-02-03 12:50:31 -07002402 was_failure = true;
2403 }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002404 if (dev->mbr_enabled) {
2405 ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
2406 if (ret)
2407 pr_debug("Failed to set MBR Done in S3 resume\n");
2408 }
Scott Bauer455a7b22017-02-03 12:50:31 -07002409 }
2410 mutex_unlock(&dev->dev_lock);
2411 return was_failure;
2412}
2413EXPORT_SYMBOL(opal_unlock_from_suspend);
2414
Scott Bauere225c202017-02-14 17:29:36 -07002415int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
Scott Bauer455a7b22017-02-03 12:50:31 -07002416{
Scott Bauere225c202017-02-14 17:29:36 -07002417 void *p;
2418 int ret = -ENOTTY;
Scott Bauer455a7b22017-02-03 12:50:31 -07002419
2420 if (!capable(CAP_SYS_ADMIN))
2421 return -EACCES;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002422 if (!dev)
2423 return -ENOTSUPP;
Scott Bauer591c59d2017-04-07 13:58:50 -06002424 if (!dev->supported)
Scott Bauer455a7b22017-02-03 12:50:31 -07002425 return -ENOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -07002426
Jon Derrickeed64952017-02-22 07:55:13 -07002427 p = memdup_user(arg, _IOC_SIZE(cmd));
Scott Bauere225c202017-02-14 17:29:36 -07002428 if (IS_ERR(p))
2429 return PTR_ERR(p);
2430
Scott Bauer455a7b22017-02-03 12:50:31 -07002431 switch (cmd) {
Scott Bauere225c202017-02-14 17:29:36 -07002432 case IOC_OPAL_SAVE:
2433 ret = opal_save(dev, p);
2434 break;
2435 case IOC_OPAL_LOCK_UNLOCK:
2436 ret = opal_lock_unlock(dev, p);
2437 break;
2438 case IOC_OPAL_TAKE_OWNERSHIP:
2439 ret = opal_take_ownership(dev, p);
2440 break;
2441 case IOC_OPAL_ACTIVATE_LSP:
2442 ret = opal_activate_lsp(dev, p);
2443 break;
2444 case IOC_OPAL_SET_PW:
2445 ret = opal_set_new_pw(dev, p);
2446 break;
2447 case IOC_OPAL_ACTIVATE_USR:
2448 ret = opal_activate_user(dev, p);
2449 break;
2450 case IOC_OPAL_REVERT_TPR:
2451 ret = opal_reverttper(dev, p);
2452 break;
2453 case IOC_OPAL_LR_SETUP:
2454 ret = opal_setup_locking_range(dev, p);
2455 break;
2456 case IOC_OPAL_ADD_USR_TO_LR:
2457 ret = opal_add_user_to_lr(dev, p);
2458 break;
2459 case IOC_OPAL_ENABLE_DISABLE_MBR:
2460 ret = opal_enable_disable_shadow_mbr(dev, p);
2461 break;
2462 case IOC_OPAL_ERASE_LR:
2463 ret = opal_erase_locking_range(dev, p);
2464 break;
2465 case IOC_OPAL_SECURE_ERASE_LR:
2466 ret = opal_secure_erase_locking_range(dev, p);
2467 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002468 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06002469 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002470 }
Scott Bauere225c202017-02-14 17:29:36 -07002471
2472 kfree(p);
2473 return ret;
Scott Bauer455a7b22017-02-03 12:50:31 -07002474}
2475EXPORT_SYMBOL_GPL(sed_ioctl);