blob: 36842bfa572ea7dc5ad2d0e00e39e77070b30457 [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
160 [OPAL_C_PIN_MSID] =
161 { 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 */
184static const u8 opalmethod[][OPAL_UID_LENGTH] = {
185 [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");
Scott Bauer455a7b22017-02-03 12:50:31 -0700493 return -EOPNOTSUPP;;
494 }
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
513static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
514{
515 if (*err)
516 return;
517 if (cmd->pos >= IO_BUFFER_LENGTH - 1) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600518 pr_debug("Error adding u8: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700519 *err = -ERANGE;
520 return;
521 }
522 cmd->cmd[cmd->pos++] = tok;
523}
524
525static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
526 bool has_sign, int len)
527{
528 u8 atom;
529 int err = 0;
530
531 atom = SHORT_ATOM_ID;
532 atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
533 atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
534 atom |= len & SHORT_ATOM_LEN_MASK;
535
536 add_token_u8(&err, cmd, atom);
537}
538
539static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
540 bool has_sign, int len)
541{
542 u8 header0;
543
544 header0 = MEDIUM_ATOM_ID;
545 header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
546 header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
547 header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
548 cmd->cmd[cmd->pos++] = header0;
549 cmd->cmd[cmd->pos++] = len;
550}
551
552static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
553{
554
555 size_t len;
556 int msb;
557 u8 n;
558
559 if (!(number & ~TINY_ATOM_DATA_MASK)) {
560 add_token_u8(err, cmd, number);
561 return;
562 }
563
564 msb = fls(number);
565 len = DIV_ROUND_UP(msb, 4);
566
567 if (cmd->pos >= IO_BUFFER_LENGTH - len - 1) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600568 pr_debug("Error adding u64: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700569 *err = -ERANGE;
570 return;
571 }
572 add_short_atom_header(cmd, false, false, len);
573 while (len--) {
574 n = number >> (len * 8);
575 add_token_u8(err, cmd, n);
576 }
577}
578
579static void add_token_bytestring(int *err, struct opal_dev *cmd,
580 const u8 *bytestring, size_t len)
581{
582 size_t header_len = 1;
583 bool is_short_atom = true;
584
585 if (*err)
586 return;
587
588 if (len & ~SHORT_ATOM_LEN_MASK) {
589 header_len = 2;
590 is_short_atom = false;
591 }
592
593 if (len >= IO_BUFFER_LENGTH - cmd->pos - header_len) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600594 pr_debug("Error adding bytestring: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700595 *err = -ERANGE;
596 return;
597 }
598
599 if (is_short_atom)
600 add_short_atom_header(cmd, true, false, len);
601 else
602 add_medium_atom_header(cmd, true, false, len);
603
604 memcpy(&cmd->cmd[cmd->pos], bytestring, len);
605 cmd->pos += len;
606
607}
608
609static int build_locking_range(u8 *buffer, size_t length, u8 lr)
610{
611 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600612 pr_debug("Can't build locking range. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700613 return -ERANGE;
614 }
615
616 memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
617
618 if (lr == 0)
619 return 0;
620 buffer[5] = LOCKING_RANGE_NON_GLOBAL;
621 buffer[7] = lr;
622
623 return 0;
624}
625
626static int build_locking_user(u8 *buffer, size_t length, u8 lr)
627{
628 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600629 pr_debug("Can't build locking range user, Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700630 return -ERANGE;
631 }
632
633 memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
634
635 buffer[7] = lr + 1;
636
637 return 0;
638}
639
640static void set_comid(struct opal_dev *cmd, u16 comid)
641{
642 struct opal_header *hdr = (struct opal_header *)cmd->cmd;
643
644 hdr->cp.extendedComID[0] = comid >> 8;
645 hdr->cp.extendedComID[1] = comid;
646 hdr->cp.extendedComID[2] = 0;
647 hdr->cp.extendedComID[3] = 0;
648}
649
650static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
651{
652 struct opal_header *hdr;
653 int err = 0;
654
655 add_token_u8(&err, cmd, OPAL_ENDOFDATA);
656 add_token_u8(&err, cmd, OPAL_STARTLIST);
657 add_token_u8(&err, cmd, 0);
658 add_token_u8(&err, cmd, 0);
659 add_token_u8(&err, cmd, 0);
660 add_token_u8(&err, cmd, OPAL_ENDLIST);
661
662 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600663 pr_debug("Error finalizing command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700664 return -EFAULT;
665 }
666
667 hdr = (struct opal_header *) cmd->cmd;
668
669 hdr->pkt.tsn = cpu_to_be32(tsn);
670 hdr->pkt.hsn = cpu_to_be32(hsn);
671
672 hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
673 while (cmd->pos % 4) {
674 if (cmd->pos >= IO_BUFFER_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600675 pr_debug("Error: Buffer overrun\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700676 return -ERANGE;
677 }
678 cmd->cmd[cmd->pos++] = 0;
679 }
680 hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
681 sizeof(hdr->pkt));
682 hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
683
684 return 0;
685}
686
Jon Derrickcccb9242017-02-21 11:59:14 -0700687static const struct opal_resp_tok *response_get_token(
688 const struct parsed_resp *resp,
689 int n)
Scott Bauer455a7b22017-02-03 12:50:31 -0700690{
691 const struct opal_resp_tok *tok;
692
693 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600694 pr_debug("Token number doesn't exist: %d, resp: %d\n",
695 n, resp->num);
Jon Derrickcccb9242017-02-21 11:59:14 -0700696 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700697 }
698
699 tok = &resp->toks[n];
700 if (tok->len == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600701 pr_debug("Token length must be non-zero\n");
Jon Derrickcccb9242017-02-21 11:59:14 -0700702 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700703 }
704
Jon Derrickcccb9242017-02-21 11:59:14 -0700705 return tok;
Scott Bauer455a7b22017-02-03 12:50:31 -0700706}
707
Jon Derrickaedb6e22017-02-21 11:59:13 -0700708static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
709 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700710{
711 tok->pos = pos;
712 tok->len = 1;
713 tok->width = OPAL_WIDTH_TINY;
714
715 if (pos[0] & TINY_ATOM_SIGNED) {
716 tok->type = OPAL_DTA_TOKENID_SINT;
717 } else {
718 tok->type = OPAL_DTA_TOKENID_UINT;
719 tok->stored.u = pos[0] & 0x3f;
720 }
721
722 return tok->len;
723}
724
Jon Derrickaedb6e22017-02-21 11:59:13 -0700725static ssize_t response_parse_short(struct opal_resp_tok *tok,
726 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700727{
728 tok->pos = pos;
729 tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
730 tok->width = OPAL_WIDTH_SHORT;
731
732 if (pos[0] & SHORT_ATOM_BYTESTRING) {
733 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
734 } else if (pos[0] & SHORT_ATOM_SIGNED) {
735 tok->type = OPAL_DTA_TOKENID_SINT;
736 } else {
737 u64 u_integer = 0;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700738 ssize_t i, b = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700739
740 tok->type = OPAL_DTA_TOKENID_UINT;
741 if (tok->len > 9) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600742 pr_debug("uint64 with more than 8 bytes\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700743 return -EINVAL;
744 }
745 for (i = tok->len - 1; i > 0; i--) {
746 u_integer |= ((u64)pos[i] << (8 * b));
747 b++;
748 }
749 tok->stored.u = u_integer;
750 }
751
752 return tok->len;
753}
754
Jon Derrickaedb6e22017-02-21 11:59:13 -0700755static ssize_t response_parse_medium(struct opal_resp_tok *tok,
756 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700757{
758 tok->pos = pos;
759 tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
760 tok->width = OPAL_WIDTH_MEDIUM;
761
762 if (pos[0] & MEDIUM_ATOM_BYTESTRING)
763 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
764 else if (pos[0] & MEDIUM_ATOM_SIGNED)
765 tok->type = OPAL_DTA_TOKENID_SINT;
766 else
767 tok->type = OPAL_DTA_TOKENID_UINT;
768
769 return tok->len;
770}
771
Jon Derrickaedb6e22017-02-21 11:59:13 -0700772static ssize_t response_parse_long(struct opal_resp_tok *tok,
773 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700774{
775 tok->pos = pos;
776 tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
777 tok->width = OPAL_WIDTH_LONG;
778
779 if (pos[0] & LONG_ATOM_BYTESTRING)
780 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
781 else if (pos[0] & LONG_ATOM_SIGNED)
782 tok->type = OPAL_DTA_TOKENID_SINT;
783 else
784 tok->type = OPAL_DTA_TOKENID_UINT;
785
786 return tok->len;
787}
788
Jon Derrickaedb6e22017-02-21 11:59:13 -0700789static ssize_t response_parse_token(struct opal_resp_tok *tok,
790 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700791{
792 tok->pos = pos;
793 tok->len = 1;
794 tok->type = OPAL_DTA_TOKENID_TOKEN;
795 tok->width = OPAL_WIDTH_TOKEN;
796
797 return tok->len;
798}
799
800static int response_parse(const u8 *buf, size_t length,
801 struct parsed_resp *resp)
802{
803 const struct opal_header *hdr;
804 struct opal_resp_tok *iter;
805 int num_entries = 0;
806 int total;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700807 ssize_t token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700808 const u8 *pos;
Jon Derrick77039b92017-02-21 11:59:15 -0700809 u32 clen, plen, slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700810
811 if (!buf)
812 return -EFAULT;
813
814 if (!resp)
815 return -EFAULT;
816
817 hdr = (struct opal_header *)buf;
818 pos = buf;
819 pos += sizeof(*hdr);
820
Jon Derrick77039b92017-02-21 11:59:15 -0700821 clen = be32_to_cpu(hdr->cp.length);
822 plen = be32_to_cpu(hdr->pkt.length);
823 slen = be32_to_cpu(hdr->subpkt.length);
824 pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
825 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700826
Jon Derrick77039b92017-02-21 11:59:15 -0700827 if (clen == 0 || plen == 0 || slen == 0 ||
828 slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600829 pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
830 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700831 print_buffer(pos, sizeof(*hdr));
832 return -EINVAL;
833 }
834
835 if (pos > buf + length)
836 return -EFAULT;
837
838 iter = resp->toks;
Jon Derrick77039b92017-02-21 11:59:15 -0700839 total = slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700840 print_buffer(pos, total);
841 while (total > 0) {
842 if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
843 token_length = response_parse_tiny(iter, pos);
844 else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
845 token_length = response_parse_short(iter, pos);
846 else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
847 token_length = response_parse_medium(iter, pos);
848 else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
849 token_length = response_parse_long(iter, pos);
850 else /* TOKEN */
851 token_length = response_parse_token(iter, pos);
852
Jon Derrickaedb6e22017-02-21 11:59:13 -0700853 if (token_length < 0)
854 return token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700855
856 pos += token_length;
857 total -= token_length;
858 iter++;
859 num_entries++;
860 }
861
862 if (num_entries == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600863 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700864 return -EINVAL;
865 }
866 resp->num = num_entries;
867
868 return 0;
869}
870
871static size_t response_get_string(const struct parsed_resp *resp, int n,
872 const char **store)
873{
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100874 u8 skip;
875 const struct opal_resp_tok *token;
876
Scott Bauer455a7b22017-02-03 12:50:31 -0700877 *store = NULL;
878 if (!resp) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600879 pr_debug("Response is NULL\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700880 return 0;
881 }
882
883 if (n > resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600884 pr_debug("Response has %d tokens. Can't access %d\n",
885 resp->num, n);
Scott Bauer455a7b22017-02-03 12:50:31 -0700886 return 0;
887 }
888
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100889 token = &resp->toks[n];
890 if (token->type != OPAL_DTA_TOKENID_BYTESTRING) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600891 pr_debug("Token is not a byte string!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700892 return 0;
893 }
894
Jonas Rabensteind15e11752018-03-01 14:26:37 +0100895 switch (token->width) {
896 case OPAL_WIDTH_TINY:
897 case OPAL_WIDTH_SHORT:
898 skip = 1;
899 break;
900 case OPAL_WIDTH_MEDIUM:
901 skip = 2;
902 break;
903 case OPAL_WIDTH_LONG:
904 skip = 4;
905 break;
906 default:
907 pr_debug("Token has invalid width!\n");
908 return 0;
909 }
910
911 *store = token->pos + skip;
912 return token->len - skip;
Scott Bauer455a7b22017-02-03 12:50:31 -0700913}
914
915static u64 response_get_u64(const struct parsed_resp *resp, int n)
916{
917 if (!resp) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600918 pr_debug("Response is NULL\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700919 return 0;
920 }
921
922 if (n > resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600923 pr_debug("Response has %d tokens. Can't access %d\n",
924 resp->num, n);
Scott Bauer455a7b22017-02-03 12:50:31 -0700925 return 0;
926 }
927
928 if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600929 pr_debug("Token is not unsigned it: %d\n",
930 resp->toks[n].type);
Scott Bauer455a7b22017-02-03 12:50:31 -0700931 return 0;
932 }
933
934 if (!(resp->toks[n].width == OPAL_WIDTH_TINY ||
935 resp->toks[n].width == OPAL_WIDTH_SHORT)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600936 pr_debug("Atom is not short or tiny: %d\n",
937 resp->toks[n].width);
Scott Bauer455a7b22017-02-03 12:50:31 -0700938 return 0;
939 }
940
941 return resp->toks[n].stored.u;
942}
943
Jon Derrickcccb9242017-02-21 11:59:14 -0700944static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
945{
946 if (IS_ERR(token) ||
947 token->type != OPAL_DTA_TOKENID_TOKEN ||
948 token->pos[0] != match)
949 return false;
950 return true;
951}
952
Scott Bauer455a7b22017-02-03 12:50:31 -0700953static u8 response_status(const struct parsed_resp *resp)
954{
Jon Derrickcccb9242017-02-21 11:59:14 -0700955 const struct opal_resp_tok *tok;
956
957 tok = response_get_token(resp, 0);
958 if (response_token_matches(tok, OPAL_ENDOFSESSION))
Scott Bauer455a7b22017-02-03 12:50:31 -0700959 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700960
961 if (resp->num < 5)
962 return DTAERROR_NO_METHOD_STATUS;
963
Jon Derrickcccb9242017-02-21 11:59:14 -0700964 tok = response_get_token(resp, resp->num - 5);
965 if (!response_token_matches(tok, OPAL_STARTLIST))
966 return DTAERROR_NO_METHOD_STATUS;
967
968 tok = response_get_token(resp, resp->num - 1);
969 if (!response_token_matches(tok, OPAL_ENDLIST))
Scott Bauer455a7b22017-02-03 12:50:31 -0700970 return DTAERROR_NO_METHOD_STATUS;
971
972 return response_get_u64(resp, resp->num - 4);
973}
974
975/* Parses and checks for errors */
976static int parse_and_check_status(struct opal_dev *dev)
977{
978 int error;
979
980 print_buffer(dev->cmd, dev->pos);
981
982 error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
983 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600984 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700985 return error;
986 }
987
988 return response_status(&dev->parsed);
989}
990
991static void clear_opal_cmd(struct opal_dev *dev)
992{
993 dev->pos = sizeof(struct opal_header);
994 memset(dev->cmd, 0, IO_BUFFER_LENGTH);
995}
996
997static int start_opal_session_cont(struct opal_dev *dev)
998{
999 u32 hsn, tsn;
1000 int error = 0;
1001
1002 error = parse_and_check_status(dev);
1003 if (error)
1004 return error;
1005
1006 hsn = response_get_u64(&dev->parsed, 4);
1007 tsn = response_get_u64(&dev->parsed, 5);
1008
1009 if (hsn == 0 && tsn == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001010 pr_debug("Couldn't authenticate session\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001011 return -EPERM;
1012 }
1013
1014 dev->hsn = hsn;
1015 dev->tsn = tsn;
1016 return 0;
1017}
1018
1019static void add_suspend_info(struct opal_dev *dev,
1020 struct opal_suspend_data *sus)
1021{
1022 struct opal_suspend_data *iter;
1023
1024 list_for_each_entry(iter, &dev->unlk_lst, node) {
1025 if (iter->lr == sus->lr) {
1026 list_del(&iter->node);
1027 kfree(iter);
1028 break;
1029 }
1030 }
1031 list_add_tail(&sus->node, &dev->unlk_lst);
1032}
1033
1034static int end_session_cont(struct opal_dev *dev)
1035{
1036 dev->hsn = 0;
1037 dev->tsn = 0;
1038 return parse_and_check_status(dev);
1039}
1040
1041static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1042{
1043 int ret;
1044
1045 ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1046 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001047 pr_debug("Error finalizing command buffer: %d\n", ret);
Scott Bauer455a7b22017-02-03 12:50:31 -07001048 return ret;
1049 }
1050
1051 print_buffer(dev->cmd, dev->pos);
1052
1053 return opal_send_recv(dev, cont);
1054}
1055
Jon Derrickeed64952017-02-22 07:55:13 -07001056static int gen_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001057{
Scott Bauer455a7b22017-02-03 12:50:31 -07001058 u8 uid[OPAL_UID_LENGTH];
1059 int err = 0;
1060
1061 clear_opal_cmd(dev);
1062 set_comid(dev, dev->comid);
1063
1064 memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
Scott Bauer455a7b22017-02-03 12:50:31 -07001065 kfree(dev->prev_data);
1066 dev->prev_data = NULL;
1067
1068 add_token_u8(&err, dev, OPAL_CALL);
1069 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1070 add_token_bytestring(&err, dev, opalmethod[OPAL_GENKEY],
1071 OPAL_UID_LENGTH);
1072 add_token_u8(&err, dev, OPAL_STARTLIST);
1073 add_token_u8(&err, dev, OPAL_ENDLIST);
1074
1075 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001076 pr_debug("Error building gen key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001077 return err;
1078
1079 }
1080 return finalize_and_send(dev, parse_and_check_status);
1081}
1082
1083static int get_active_key_cont(struct opal_dev *dev)
1084{
1085 const char *activekey;
1086 size_t keylen;
1087 int error = 0;
1088
1089 error = parse_and_check_status(dev);
1090 if (error)
1091 return error;
1092 keylen = response_get_string(&dev->parsed, 4, &activekey);
1093 if (!activekey) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001094 pr_debug("%s: Couldn't extract the Activekey from the response\n",
1095 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001096 return OPAL_INVAL_PARAM;
1097 }
1098 dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1099
1100 if (!dev->prev_data)
1101 return -ENOMEM;
1102
1103 dev->prev_d_len = keylen;
1104
1105 return 0;
1106}
1107
Jon Derrickeed64952017-02-22 07:55:13 -07001108static int get_active_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001109{
1110 u8 uid[OPAL_UID_LENGTH];
1111 int err = 0;
Jon Derrickeed64952017-02-22 07:55:13 -07001112 u8 *lr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001113
1114 clear_opal_cmd(dev);
1115 set_comid(dev, dev->comid);
Scott Bauer455a7b22017-02-03 12:50:31 -07001116
1117 err = build_locking_range(uid, sizeof(uid), *lr);
1118 if (err)
1119 return err;
1120
1121 err = 0;
1122 add_token_u8(&err, dev, OPAL_CALL);
1123 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1124 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1125 add_token_u8(&err, dev, OPAL_STARTLIST);
1126 add_token_u8(&err, dev, OPAL_STARTLIST);
1127 add_token_u8(&err, dev, OPAL_STARTNAME);
1128 add_token_u8(&err, dev, 3); /* startCloumn */
1129 add_token_u8(&err, dev, 10); /* ActiveKey */
1130 add_token_u8(&err, dev, OPAL_ENDNAME);
1131 add_token_u8(&err, dev, OPAL_STARTNAME);
1132 add_token_u8(&err, dev, 4); /* endColumn */
1133 add_token_u8(&err, dev, 10); /* ActiveKey */
1134 add_token_u8(&err, dev, OPAL_ENDNAME);
1135 add_token_u8(&err, dev, OPAL_ENDLIST);
1136 add_token_u8(&err, dev, OPAL_ENDLIST);
1137 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001138 pr_debug("Error building get active key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001139 return err;
1140 }
1141
1142 return finalize_and_send(dev, get_active_key_cont);
1143}
1144
1145static int generic_lr_enable_disable(struct opal_dev *dev,
1146 u8 *uid, bool rle, bool wle,
1147 bool rl, bool wl)
1148{
1149 int err = 0;
1150
1151 add_token_u8(&err, dev, OPAL_CALL);
1152 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1153 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1154
1155 add_token_u8(&err, dev, OPAL_STARTLIST);
1156 add_token_u8(&err, dev, OPAL_STARTNAME);
1157 add_token_u8(&err, dev, OPAL_VALUES);
1158 add_token_u8(&err, dev, OPAL_STARTLIST);
1159
1160 add_token_u8(&err, dev, OPAL_STARTNAME);
1161 add_token_u8(&err, dev, 5); /* ReadLockEnabled */
1162 add_token_u8(&err, dev, rle);
1163 add_token_u8(&err, dev, OPAL_ENDNAME);
1164
1165 add_token_u8(&err, dev, OPAL_STARTNAME);
1166 add_token_u8(&err, dev, 6); /* WriteLockEnabled */
1167 add_token_u8(&err, dev, wle);
1168 add_token_u8(&err, dev, OPAL_ENDNAME);
1169
1170 add_token_u8(&err, dev, OPAL_STARTNAME);
1171 add_token_u8(&err, dev, OPAL_READLOCKED);
1172 add_token_u8(&err, dev, rl);
1173 add_token_u8(&err, dev, OPAL_ENDNAME);
1174
1175 add_token_u8(&err, dev, OPAL_STARTNAME);
1176 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1177 add_token_u8(&err, dev, wl);
1178 add_token_u8(&err, dev, OPAL_ENDNAME);
1179
1180 add_token_u8(&err, dev, OPAL_ENDLIST);
1181 add_token_u8(&err, dev, OPAL_ENDNAME);
1182 add_token_u8(&err, dev, OPAL_ENDLIST);
1183 return err;
1184}
1185
1186static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1187 struct opal_user_lr_setup *setup)
1188{
1189 int err;
1190
1191 err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1192 0, 0);
1193 if (err)
Scott Bauer591c59d2017-04-07 13:58:50 -06001194 pr_debug("Failed to create enable global lr command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001195 return err;
1196}
1197
Jon Derrickeed64952017-02-22 07:55:13 -07001198static int setup_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001199{
1200 u8 uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001201 struct opal_user_lr_setup *setup = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001202 u8 lr;
1203 int err = 0;
1204
1205 clear_opal_cmd(dev);
1206 set_comid(dev, dev->comid);
1207
Scott Bauer455a7b22017-02-03 12:50:31 -07001208 lr = setup->session.opal_key.lr;
1209 err = build_locking_range(uid, sizeof(uid), lr);
1210 if (err)
1211 return err;
1212
1213 if (lr == 0)
1214 err = enable_global_lr(dev, uid, setup);
1215 else {
1216 add_token_u8(&err, dev, OPAL_CALL);
1217 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1218 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1219 OPAL_UID_LENGTH);
1220
1221 add_token_u8(&err, dev, OPAL_STARTLIST);
1222 add_token_u8(&err, dev, OPAL_STARTNAME);
1223 add_token_u8(&err, dev, OPAL_VALUES);
1224 add_token_u8(&err, dev, OPAL_STARTLIST);
1225
1226 add_token_u8(&err, dev, OPAL_STARTNAME);
1227 add_token_u8(&err, dev, 3); /* Ranges Start */
1228 add_token_u64(&err, dev, setup->range_start);
1229 add_token_u8(&err, dev, OPAL_ENDNAME);
1230
1231 add_token_u8(&err, dev, OPAL_STARTNAME);
1232 add_token_u8(&err, dev, 4); /* Ranges length */
1233 add_token_u64(&err, dev, setup->range_length);
1234 add_token_u8(&err, dev, OPAL_ENDNAME);
1235
1236 add_token_u8(&err, dev, OPAL_STARTNAME);
1237 add_token_u8(&err, dev, 5); /*ReadLockEnabled */
1238 add_token_u64(&err, dev, !!setup->RLE);
1239 add_token_u8(&err, dev, OPAL_ENDNAME);
1240
1241 add_token_u8(&err, dev, OPAL_STARTNAME);
1242 add_token_u8(&err, dev, 6); /*WriteLockEnabled*/
1243 add_token_u64(&err, dev, !!setup->WLE);
1244 add_token_u8(&err, dev, OPAL_ENDNAME);
1245
1246 add_token_u8(&err, dev, OPAL_ENDLIST);
1247 add_token_u8(&err, dev, OPAL_ENDNAME);
1248 add_token_u8(&err, dev, OPAL_ENDLIST);
1249
1250 }
1251 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001252 pr_debug("Error building Setup Locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001253 return err;
1254
1255 }
1256
1257 return finalize_and_send(dev, parse_and_check_status);
1258}
1259
1260static int start_generic_opal_session(struct opal_dev *dev,
1261 enum opal_uid auth,
1262 enum opal_uid sp_type,
1263 const char *key,
1264 u8 key_len)
1265{
1266 u32 hsn;
1267 int err = 0;
1268
Scott Bauer591c59d2017-04-07 13:58:50 -06001269 if (key == NULL && auth != OPAL_ANYBODY_UID)
Scott Bauer455a7b22017-02-03 12:50:31 -07001270 return OPAL_INVAL_PARAM;
Scott Bauer455a7b22017-02-03 12:50:31 -07001271
1272 clear_opal_cmd(dev);
1273
1274 set_comid(dev, dev->comid);
1275 hsn = GENERIC_HOST_SESSION_NUM;
1276
1277 add_token_u8(&err, dev, OPAL_CALL);
1278 add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
1279 OPAL_UID_LENGTH);
1280 add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
1281 OPAL_UID_LENGTH);
1282 add_token_u8(&err, dev, OPAL_STARTLIST);
1283 add_token_u64(&err, dev, hsn);
1284 add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1285 add_token_u8(&err, dev, 1);
1286
1287 switch (auth) {
1288 case OPAL_ANYBODY_UID:
1289 add_token_u8(&err, dev, OPAL_ENDLIST);
1290 break;
1291 case OPAL_ADMIN1_UID:
1292 case OPAL_SID_UID:
1293 add_token_u8(&err, dev, OPAL_STARTNAME);
1294 add_token_u8(&err, dev, 0); /* HostChallenge */
1295 add_token_bytestring(&err, dev, key, key_len);
1296 add_token_u8(&err, dev, OPAL_ENDNAME);
1297 add_token_u8(&err, dev, OPAL_STARTNAME);
1298 add_token_u8(&err, dev, 3); /* HostSignAuth */
1299 add_token_bytestring(&err, dev, opaluid[auth],
1300 OPAL_UID_LENGTH);
1301 add_token_u8(&err, dev, OPAL_ENDNAME);
1302 add_token_u8(&err, dev, OPAL_ENDLIST);
1303 break;
1304 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001305 pr_debug("Cannot start Admin SP session with auth %d\n", auth);
Scott Bauer455a7b22017-02-03 12:50:31 -07001306 return OPAL_INVAL_PARAM;
1307 }
1308
1309 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001310 pr_debug("Error building start adminsp session command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001311 return err;
1312 }
1313
1314 return finalize_and_send(dev, start_opal_session_cont);
1315}
1316
Jon Derrickeed64952017-02-22 07:55:13 -07001317static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001318{
1319 return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1320 OPAL_ADMINSP_UID, NULL, 0);
1321}
1322
Jon Derrickeed64952017-02-22 07:55:13 -07001323static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001324{
1325 int ret;
1326 const u8 *key = dev->prev_data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001327
1328 if (!key) {
Jon Derrickeed64952017-02-22 07:55:13 -07001329 const struct opal_key *okey = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001330 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1331 OPAL_ADMINSP_UID,
1332 okey->key,
1333 okey->key_len);
1334 } else {
1335 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1336 OPAL_ADMINSP_UID,
1337 key, dev->prev_d_len);
1338 kfree(key);
1339 dev->prev_data = NULL;
1340 }
1341 return ret;
1342}
1343
Jon Derrickeed64952017-02-22 07:55:13 -07001344static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001345{
Jon Derrickeed64952017-02-22 07:55:13 -07001346 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001347 return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1348 OPAL_LOCKINGSP_UID,
1349 key->key, key->key_len);
1350}
1351
Jon Derrickeed64952017-02-22 07:55:13 -07001352static int start_auth_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001353{
Jon Derrickeed64952017-02-22 07:55:13 -07001354 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001355 u8 lk_ul_user[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001356 size_t keylen = session->opal_key.key_len;
Scott Bauer455a7b22017-02-03 12:50:31 -07001357 int err = 0;
1358
Scott Bauer455a7b22017-02-03 12:50:31 -07001359 u8 *key = session->opal_key.key;
1360 u32 hsn = GENERIC_HOST_SESSION_NUM;
1361
1362 clear_opal_cmd(dev);
1363 set_comid(dev, dev->comid);
1364
1365 if (session->sum) {
1366 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1367 session->opal_key.lr);
1368 if (err)
1369 return err;
1370
1371 } else if (session->who != OPAL_ADMIN1 && !session->sum) {
1372 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1373 session->who - 1);
1374 if (err)
1375 return err;
1376 } else
1377 memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1378
1379 add_token_u8(&err, dev, OPAL_CALL);
1380 add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
1381 OPAL_UID_LENGTH);
1382 add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
1383 OPAL_UID_LENGTH);
1384
1385 add_token_u8(&err, dev, OPAL_STARTLIST);
1386 add_token_u64(&err, dev, hsn);
1387 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1388 OPAL_UID_LENGTH);
1389 add_token_u8(&err, dev, 1);
1390 add_token_u8(&err, dev, OPAL_STARTNAME);
1391 add_token_u8(&err, dev, 0);
1392 add_token_bytestring(&err, dev, key, keylen);
1393 add_token_u8(&err, dev, OPAL_ENDNAME);
1394 add_token_u8(&err, dev, OPAL_STARTNAME);
1395 add_token_u8(&err, dev, 3);
1396 add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1397 add_token_u8(&err, dev, OPAL_ENDNAME);
1398 add_token_u8(&err, dev, OPAL_ENDLIST);
1399
1400 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001401 pr_debug("Error building STARTSESSION command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001402 return err;
1403 }
1404
1405 return finalize_and_send(dev, start_opal_session_cont);
1406}
1407
Jon Derrickeed64952017-02-22 07:55:13 -07001408static int revert_tper(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001409{
1410 int err = 0;
1411
1412 clear_opal_cmd(dev);
1413 set_comid(dev, dev->comid);
1414
1415 add_token_u8(&err, dev, OPAL_CALL);
1416 add_token_bytestring(&err, dev, opaluid[OPAL_ADMINSP_UID],
1417 OPAL_UID_LENGTH);
1418 add_token_bytestring(&err, dev, opalmethod[OPAL_REVERT],
1419 OPAL_UID_LENGTH);
1420 add_token_u8(&err, dev, OPAL_STARTLIST);
1421 add_token_u8(&err, dev, OPAL_ENDLIST);
1422 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001423 pr_debug("Error building REVERT TPER command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001424 return err;
1425 }
1426
1427 return finalize_and_send(dev, parse_and_check_status);
1428}
1429
Jon Derrickeed64952017-02-22 07:55:13 -07001430static int internal_activate_user(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001431{
Jon Derrickeed64952017-02-22 07:55:13 -07001432 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001433 u8 uid[OPAL_UID_LENGTH];
1434 int err = 0;
1435
1436 clear_opal_cmd(dev);
1437 set_comid(dev, dev->comid);
1438
1439 memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1440 uid[7] = session->who;
1441
1442 add_token_u8(&err, dev, OPAL_CALL);
1443 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1444 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1445 add_token_u8(&err, dev, OPAL_STARTLIST);
1446 add_token_u8(&err, dev, OPAL_STARTNAME);
1447 add_token_u8(&err, dev, OPAL_VALUES);
1448 add_token_u8(&err, dev, OPAL_STARTLIST);
1449 add_token_u8(&err, dev, OPAL_STARTNAME);
1450 add_token_u8(&err, dev, 5); /* Enabled */
1451 add_token_u8(&err, dev, OPAL_TRUE);
1452 add_token_u8(&err, dev, OPAL_ENDNAME);
1453 add_token_u8(&err, dev, OPAL_ENDLIST);
1454 add_token_u8(&err, dev, OPAL_ENDNAME);
1455 add_token_u8(&err, dev, OPAL_ENDLIST);
1456
1457 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001458 pr_debug("Error building Activate UserN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001459 return err;
1460 }
1461
1462 return finalize_and_send(dev, parse_and_check_status);
1463}
1464
Jon Derrickeed64952017-02-22 07:55:13 -07001465static int erase_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001466{
Jon Derrickeed64952017-02-22 07:55:13 -07001467 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001468 u8 uid[OPAL_UID_LENGTH];
1469 int err = 0;
1470
1471 clear_opal_cmd(dev);
1472 set_comid(dev, dev->comid);
Scott Bauer455a7b22017-02-03 12:50:31 -07001473
1474 if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1475 return -ERANGE;
1476
1477 add_token_u8(&err, dev, OPAL_CALL);
1478 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1479 add_token_bytestring(&err, dev, opalmethod[OPAL_ERASE],
1480 OPAL_UID_LENGTH);
1481 add_token_u8(&err, dev, OPAL_STARTLIST);
1482 add_token_u8(&err, dev, OPAL_ENDLIST);
1483
1484 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001485 pr_debug("Error building Erase Locking Range Command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001486 return err;
1487 }
1488 return finalize_and_send(dev, parse_and_check_status);
1489}
1490
Jon Derrickeed64952017-02-22 07:55:13 -07001491static int set_mbr_done(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001492{
Jon Derrickeed64952017-02-22 07:55:13 -07001493 u8 *mbr_done_tf = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001494 int err = 0;
1495
1496 clear_opal_cmd(dev);
1497 set_comid(dev, dev->comid);
1498
1499 add_token_u8(&err, dev, OPAL_CALL);
1500 add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL],
1501 OPAL_UID_LENGTH);
1502 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1503 add_token_u8(&err, dev, OPAL_STARTLIST);
1504 add_token_u8(&err, dev, OPAL_STARTNAME);
1505 add_token_u8(&err, dev, OPAL_VALUES);
1506 add_token_u8(&err, dev, OPAL_STARTLIST);
1507 add_token_u8(&err, dev, OPAL_STARTNAME);
1508 add_token_u8(&err, dev, 2); /* Done */
Jon Derrickeed64952017-02-22 07:55:13 -07001509 add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
Scott Bauer455a7b22017-02-03 12:50:31 -07001510 add_token_u8(&err, dev, OPAL_ENDNAME);
1511 add_token_u8(&err, dev, OPAL_ENDLIST);
1512 add_token_u8(&err, dev, OPAL_ENDNAME);
1513 add_token_u8(&err, dev, OPAL_ENDLIST);
1514
1515 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001516 pr_debug("Error Building set MBR Done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001517 return err;
1518 }
1519
1520 return finalize_and_send(dev, parse_and_check_status);
1521}
1522
Jon Derrickeed64952017-02-22 07:55:13 -07001523static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001524{
Jon Derrickeed64952017-02-22 07:55:13 -07001525 u8 *mbr_en_dis = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001526 int err = 0;
1527
1528 clear_opal_cmd(dev);
1529 set_comid(dev, dev->comid);
1530
1531 add_token_u8(&err, dev, OPAL_CALL);
1532 add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL],
1533 OPAL_UID_LENGTH);
1534 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1535 add_token_u8(&err, dev, OPAL_STARTLIST);
1536 add_token_u8(&err, dev, OPAL_STARTNAME);
1537 add_token_u8(&err, dev, OPAL_VALUES);
1538 add_token_u8(&err, dev, OPAL_STARTLIST);
1539 add_token_u8(&err, dev, OPAL_STARTNAME);
1540 add_token_u8(&err, dev, 1);
Jon Derrickeed64952017-02-22 07:55:13 -07001541 add_token_u8(&err, dev, *mbr_en_dis);
Scott Bauer455a7b22017-02-03 12:50:31 -07001542 add_token_u8(&err, dev, OPAL_ENDNAME);
1543 add_token_u8(&err, dev, OPAL_ENDLIST);
1544 add_token_u8(&err, dev, OPAL_ENDNAME);
1545 add_token_u8(&err, dev, OPAL_ENDLIST);
1546
1547 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001548 pr_debug("Error Building set MBR done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001549 return err;
1550 }
1551
1552 return finalize_and_send(dev, parse_and_check_status);
1553}
1554
1555static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1556 struct opal_dev *dev)
1557{
1558 int err = 0;
1559
1560 clear_opal_cmd(dev);
1561 set_comid(dev, dev->comid);
1562
1563 add_token_u8(&err, dev, OPAL_CALL);
1564 add_token_bytestring(&err, dev, cpin_uid, OPAL_UID_LENGTH);
1565 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1566 OPAL_UID_LENGTH);
1567 add_token_u8(&err, dev, OPAL_STARTLIST);
1568 add_token_u8(&err, dev, OPAL_STARTNAME);
1569 add_token_u8(&err, dev, OPAL_VALUES);
1570 add_token_u8(&err, dev, OPAL_STARTLIST);
1571 add_token_u8(&err, dev, OPAL_STARTNAME);
1572 add_token_u8(&err, dev, 3); /* PIN */
1573 add_token_bytestring(&err, dev, key, key_len);
1574 add_token_u8(&err, dev, OPAL_ENDNAME);
1575 add_token_u8(&err, dev, OPAL_ENDLIST);
1576 add_token_u8(&err, dev, OPAL_ENDNAME);
1577 add_token_u8(&err, dev, OPAL_ENDLIST);
1578
1579 return err;
1580}
1581
Jon Derrickeed64952017-02-22 07:55:13 -07001582static int set_new_pw(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001583{
1584 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001585 struct opal_session_info *usr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001586
1587 memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1588
1589 if (usr->who != OPAL_ADMIN1) {
1590 cpin_uid[5] = 0x03;
1591 if (usr->sum)
1592 cpin_uid[7] = usr->opal_key.lr + 1;
1593 else
1594 cpin_uid[7] = usr->who;
1595 }
1596
1597 if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1598 cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001599 pr_debug("Error building set password command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001600 return -ERANGE;
1601 }
1602
1603 return finalize_and_send(dev, parse_and_check_status);
1604}
1605
Jon Derrickeed64952017-02-22 07:55:13 -07001606static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001607{
1608 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001609 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001610
1611 memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1612
1613 if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001614 pr_debug("Error building Set SID cpin\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001615 return -ERANGE;
1616 }
1617 return finalize_and_send(dev, parse_and_check_status);
1618}
1619
Jon Derrickeed64952017-02-22 07:55:13 -07001620static int add_user_to_lr(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001621{
1622 u8 lr_buffer[OPAL_UID_LENGTH];
1623 u8 user_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001624 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001625 int err = 0;
1626
1627 clear_opal_cmd(dev);
1628 set_comid(dev, dev->comid);
1629
Scott Bauer455a7b22017-02-03 12:50:31 -07001630 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1631 OPAL_UID_LENGTH);
1632
1633 if (lkul->l_state == OPAL_RW)
1634 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1635 OPAL_UID_LENGTH);
1636
1637 lr_buffer[7] = lkul->session.opal_key.lr;
1638
1639 memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1640
1641 user_uid[7] = lkul->session.who;
1642
1643 add_token_u8(&err, dev, OPAL_CALL);
1644 add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
1645 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1646 OPAL_UID_LENGTH);
1647
1648 add_token_u8(&err, dev, OPAL_STARTLIST);
1649 add_token_u8(&err, dev, OPAL_STARTNAME);
1650 add_token_u8(&err, dev, OPAL_VALUES);
1651
1652 add_token_u8(&err, dev, OPAL_STARTLIST);
1653 add_token_u8(&err, dev, OPAL_STARTNAME);
1654 add_token_u8(&err, dev, 3);
1655
1656 add_token_u8(&err, dev, OPAL_STARTLIST);
1657
1658
1659 add_token_u8(&err, dev, OPAL_STARTNAME);
1660 add_token_bytestring(&err, dev,
1661 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1662 OPAL_UID_LENGTH/2);
1663 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1664 add_token_u8(&err, dev, OPAL_ENDNAME);
1665
1666
1667 add_token_u8(&err, dev, OPAL_STARTNAME);
1668 add_token_bytestring(&err, dev,
1669 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1670 OPAL_UID_LENGTH/2);
1671 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1672 add_token_u8(&err, dev, OPAL_ENDNAME);
1673
1674
1675 add_token_u8(&err, dev, OPAL_STARTNAME);
1676 add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1677 OPAL_UID_LENGTH/2);
1678 add_token_u8(&err, dev, 1);
1679 add_token_u8(&err, dev, OPAL_ENDNAME);
1680
1681
1682 add_token_u8(&err, dev, OPAL_ENDLIST);
1683 add_token_u8(&err, dev, OPAL_ENDNAME);
1684 add_token_u8(&err, dev, OPAL_ENDLIST);
1685 add_token_u8(&err, dev, OPAL_ENDNAME);
1686 add_token_u8(&err, dev, OPAL_ENDLIST);
1687
1688 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001689 pr_debug("Error building add user to locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001690 return err;
1691 }
1692
1693 return finalize_and_send(dev, parse_and_check_status);
1694}
1695
Jon Derrickeed64952017-02-22 07:55:13 -07001696static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001697{
1698 u8 lr_buffer[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001699 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001700 u8 read_locked = 1, write_locked = 1;
1701 int err = 0;
1702
1703 clear_opal_cmd(dev);
1704 set_comid(dev, dev->comid);
1705
Scott Bauer455a7b22017-02-03 12:50:31 -07001706 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1707 lkul->session.opal_key.lr) < 0)
1708 return -ERANGE;
1709
1710 switch (lkul->l_state) {
1711 case OPAL_RO:
1712 read_locked = 0;
1713 write_locked = 1;
1714 break;
1715 case OPAL_RW:
1716 read_locked = 0;
1717 write_locked = 0;
1718 break;
1719 case OPAL_LK:
1720 /* vars are initalized to locked */
1721 break;
1722 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001723 pr_debug("Tried to set an invalid locking state... returning to uland\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001724 return OPAL_INVAL_PARAM;
1725 }
1726
1727 add_token_u8(&err, dev, OPAL_CALL);
1728 add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
1729 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1730 add_token_u8(&err, dev, OPAL_STARTLIST);
1731 add_token_u8(&err, dev, OPAL_STARTNAME);
1732 add_token_u8(&err, dev, OPAL_VALUES);
1733 add_token_u8(&err, dev, OPAL_STARTLIST);
1734
1735 add_token_u8(&err, dev, OPAL_STARTNAME);
1736 add_token_u8(&err, dev, OPAL_READLOCKED);
1737 add_token_u8(&err, dev, read_locked);
1738 add_token_u8(&err, dev, OPAL_ENDNAME);
1739
1740 add_token_u8(&err, dev, OPAL_STARTNAME);
1741 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1742 add_token_u8(&err, dev, write_locked);
1743 add_token_u8(&err, dev, OPAL_ENDNAME);
1744
1745 add_token_u8(&err, dev, OPAL_ENDLIST);
1746 add_token_u8(&err, dev, OPAL_ENDNAME);
1747 add_token_u8(&err, dev, OPAL_ENDLIST);
1748
1749 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001750 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001751 return err;
1752 }
1753 return finalize_and_send(dev, parse_and_check_status);
1754}
1755
1756
Jon Derrickeed64952017-02-22 07:55:13 -07001757static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001758{
1759 u8 lr_buffer[OPAL_UID_LENGTH];
1760 u8 read_locked = 1, write_locked = 1;
Jon Derrickeed64952017-02-22 07:55:13 -07001761 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001762 int ret;
1763
1764 clear_opal_cmd(dev);
1765 set_comid(dev, dev->comid);
1766
Scott Bauer455a7b22017-02-03 12:50:31 -07001767 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1768 lkul->session.opal_key.lr) < 0)
1769 return -ERANGE;
1770
1771 switch (lkul->l_state) {
1772 case OPAL_RO:
1773 read_locked = 0;
1774 write_locked = 1;
1775 break;
1776 case OPAL_RW:
1777 read_locked = 0;
1778 write_locked = 0;
1779 break;
1780 case OPAL_LK:
1781 /* vars are initalized to locked */
1782 break;
1783 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001784 pr_debug("Tried to set an invalid locking state.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001785 return OPAL_INVAL_PARAM;
1786 }
1787 ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1788 read_locked, write_locked);
1789
1790 if (ret < 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001791 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001792 return ret;
1793 }
1794 return finalize_and_send(dev, parse_and_check_status);
1795}
1796
Jon Derrickeed64952017-02-22 07:55:13 -07001797static int activate_lsp(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001798{
Jon Derrickeed64952017-02-22 07:55:13 -07001799 struct opal_lr_act *opal_act = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001800 u8 user_lr[OPAL_UID_LENGTH];
1801 u8 uint_3 = 0x83;
1802 int err = 0, i;
1803
1804 clear_opal_cmd(dev);
1805 set_comid(dev, dev->comid);
1806
Scott Bauer455a7b22017-02-03 12:50:31 -07001807 add_token_u8(&err, dev, OPAL_CALL);
1808 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1809 OPAL_UID_LENGTH);
1810 add_token_bytestring(&err, dev, opalmethod[OPAL_ACTIVATE],
1811 OPAL_UID_LENGTH);
1812
1813
1814 if (opal_act->sum) {
1815 err = build_locking_range(user_lr, sizeof(user_lr),
1816 opal_act->lr[0]);
1817 if (err)
1818 return err;
1819
1820 add_token_u8(&err, dev, OPAL_STARTLIST);
1821 add_token_u8(&err, dev, OPAL_STARTNAME);
1822 add_token_u8(&err, dev, uint_3);
1823 add_token_u8(&err, dev, 6);
1824 add_token_u8(&err, dev, 0);
1825 add_token_u8(&err, dev, 0);
1826
1827 add_token_u8(&err, dev, OPAL_STARTLIST);
1828 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1829 for (i = 1; i < opal_act->num_lrs; i++) {
1830 user_lr[7] = opal_act->lr[i];
1831 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1832 }
1833 add_token_u8(&err, dev, OPAL_ENDLIST);
1834 add_token_u8(&err, dev, OPAL_ENDNAME);
1835 add_token_u8(&err, dev, OPAL_ENDLIST);
1836
1837 } else {
1838 add_token_u8(&err, dev, OPAL_STARTLIST);
1839 add_token_u8(&err, dev, OPAL_ENDLIST);
1840 }
1841
1842 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001843 pr_debug("Error building Activate LockingSP command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001844 return err;
1845 }
1846
1847 return finalize_and_send(dev, parse_and_check_status);
1848}
1849
1850static int get_lsp_lifecycle_cont(struct opal_dev *dev)
1851{
1852 u8 lc_status;
1853 int error = 0;
1854
1855 error = parse_and_check_status(dev);
1856 if (error)
1857 return error;
1858
1859 lc_status = response_get_u64(&dev->parsed, 4);
1860 /* 0x08 is Manufacured Inactive */
1861 /* 0x09 is Manufactured */
1862 if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001863 pr_debug("Couldn't determine the status of the Lifecycle state\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001864 return -ENODEV;
1865 }
1866
1867 return 0;
1868}
1869
1870/* Determine if we're in the Manufactured Inactive or Active state */
Jon Derrickeed64952017-02-22 07:55:13 -07001871static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001872{
1873 int err = 0;
1874
1875 clear_opal_cmd(dev);
1876 set_comid(dev, dev->comid);
1877
1878 add_token_u8(&err, dev, OPAL_CALL);
1879 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1880 OPAL_UID_LENGTH);
1881 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1882
1883 add_token_u8(&err, dev, OPAL_STARTLIST);
1884 add_token_u8(&err, dev, OPAL_STARTLIST);
1885
1886 add_token_u8(&err, dev, OPAL_STARTNAME);
1887 add_token_u8(&err, dev, 3); /* Start Column */
1888 add_token_u8(&err, dev, 6); /* Lifecycle Column */
1889 add_token_u8(&err, dev, OPAL_ENDNAME);
1890
1891 add_token_u8(&err, dev, OPAL_STARTNAME);
1892 add_token_u8(&err, dev, 4); /* End 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_ENDLIST);
1897 add_token_u8(&err, dev, OPAL_ENDLIST);
1898
1899 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001900 pr_debug("Error Building GET Lifecycle Status command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001901 return err;
1902 }
1903
1904 return finalize_and_send(dev, get_lsp_lifecycle_cont);
1905}
1906
1907static int get_msid_cpin_pin_cont(struct opal_dev *dev)
1908{
1909 const char *msid_pin;
1910 size_t strlen;
1911 int error = 0;
1912
1913 error = parse_and_check_status(dev);
1914 if (error)
1915 return error;
1916
1917 strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1918 if (!msid_pin) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001919 pr_debug("%s: Couldn't extract PIN from response\n", __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001920 return OPAL_INVAL_PARAM;
1921 }
1922
1923 dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1924 if (!dev->prev_data)
1925 return -ENOMEM;
1926
1927 dev->prev_d_len = strlen;
1928
1929 return 0;
1930}
1931
Jon Derrickeed64952017-02-22 07:55:13 -07001932static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001933{
1934 int err = 0;
1935
1936 clear_opal_cmd(dev);
1937 set_comid(dev, dev->comid);
1938
Scott Bauer455a7b22017-02-03 12:50:31 -07001939 add_token_u8(&err, dev, OPAL_CALL);
1940 add_token_bytestring(&err, dev, opaluid[OPAL_C_PIN_MSID],
1941 OPAL_UID_LENGTH);
1942 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1943
1944 add_token_u8(&err, dev, OPAL_STARTLIST);
1945 add_token_u8(&err, dev, OPAL_STARTLIST);
1946
1947 add_token_u8(&err, dev, OPAL_STARTNAME);
1948 add_token_u8(&err, dev, 3); /* Start Column */
1949 add_token_u8(&err, dev, 3); /* PIN */
1950 add_token_u8(&err, dev, OPAL_ENDNAME);
1951
1952 add_token_u8(&err, dev, OPAL_STARTNAME);
1953 add_token_u8(&err, dev, 4); /* End Column */
1954 add_token_u8(&err, dev, 3); /* Lifecycle Column */
1955 add_token_u8(&err, dev, OPAL_ENDNAME);
1956
1957 add_token_u8(&err, dev, OPAL_ENDLIST);
1958 add_token_u8(&err, dev, OPAL_ENDLIST);
1959
1960 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001961 pr_debug("Error building Get MSID CPIN PIN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001962 return err;
1963 }
1964
1965 return finalize_and_send(dev, get_msid_cpin_pin_cont);
1966}
1967
Jon Derrickeed64952017-02-22 07:55:13 -07001968static int end_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001969{
1970 int err = 0;
1971
1972 clear_opal_cmd(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001973 set_comid(dev, dev->comid);
1974 add_token_u8(&err, dev, OPAL_ENDOFSESSION);
Scott Bauer455a7b22017-02-03 12:50:31 -07001975
Jon Derrickeed64952017-02-22 07:55:13 -07001976 if (err < 0)
1977 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001978 return finalize_and_send(dev, end_session_cont);
1979}
1980
1981static int end_opal_session_error(struct opal_dev *dev)
1982{
Jon Derrickeed64952017-02-22 07:55:13 -07001983 const struct opal_step error_end_session[] = {
1984 { end_opal_session, },
1985 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001986 };
Jon Derrickeed64952017-02-22 07:55:13 -07001987 dev->steps = error_end_session;
Scott Bauer455a7b22017-02-03 12:50:31 -07001988 return next(dev);
1989}
1990
1991static inline void setup_opal_dev(struct opal_dev *dev,
Jon Derrickeed64952017-02-22 07:55:13 -07001992 const struct opal_step *steps)
Scott Bauer455a7b22017-02-03 12:50:31 -07001993{
Jon Derrickeed64952017-02-22 07:55:13 -07001994 dev->steps = steps;
Scott Bauer455a7b22017-02-03 12:50:31 -07001995 dev->tsn = 0;
1996 dev->hsn = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -07001997 dev->prev_data = NULL;
1998}
1999
2000static int check_opal_support(struct opal_dev *dev)
2001{
Jon Derrickeed64952017-02-22 07:55:13 -07002002 const struct opal_step steps[] = {
2003 { opal_discovery0, },
2004 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002005 };
2006 int ret;
2007
2008 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002009 setup_opal_dev(dev, steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002010 ret = next(dev);
2011 dev->supported = !ret;
2012 mutex_unlock(&dev->dev_lock);
2013 return ret;
2014}
2015
Scott Bauer7d6d1572017-02-22 10:15:06 -07002016static void clean_opal_dev(struct opal_dev *dev)
2017{
2018
2019 struct opal_suspend_data *suspend, *next;
2020
2021 mutex_lock(&dev->dev_lock);
2022 list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
2023 list_del(&suspend->node);
2024 kfree(suspend);
2025 }
2026 mutex_unlock(&dev->dev_lock);
2027}
2028
2029void free_opal_dev(struct opal_dev *dev)
2030{
2031 if (!dev)
2032 return;
2033 clean_opal_dev(dev);
2034 kfree(dev);
2035}
2036EXPORT_SYMBOL(free_opal_dev);
2037
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002038struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
Scott Bauer455a7b22017-02-03 12:50:31 -07002039{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002040 struct opal_dev *dev;
2041
2042 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
2043 if (!dev)
2044 return NULL;
2045
2046 INIT_LIST_HEAD(&dev->unlk_lst);
2047 mutex_init(&dev->dev_lock);
2048 dev->data = data;
2049 dev->send_recv = send_recv;
2050 if (check_opal_support(dev) != 0) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +01002051 pr_debug("Opal is not supported on this device\n");
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002052 kfree(dev);
2053 return NULL;
2054 }
2055 return dev;
Scott Bauer455a7b22017-02-03 12:50:31 -07002056}
2057EXPORT_SYMBOL(init_opal_dev);
2058
2059static int opal_secure_erase_locking_range(struct opal_dev *dev,
2060 struct opal_session_info *opal_session)
2061{
Jon Derrickeed64952017-02-22 07:55:13 -07002062 const struct opal_step erase_steps[] = {
2063 { opal_discovery0, },
2064 { start_auth_opal_session, opal_session },
2065 { get_active_key, &opal_session->opal_key.lr },
2066 { gen_key, },
2067 { end_opal_session, },
2068 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002069 };
2070 int ret;
2071
2072 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002073 setup_opal_dev(dev, erase_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002074 ret = next(dev);
2075 mutex_unlock(&dev->dev_lock);
2076 return ret;
2077}
2078
2079static int opal_erase_locking_range(struct opal_dev *dev,
2080 struct opal_session_info *opal_session)
2081{
Jon Derrickeed64952017-02-22 07:55:13 -07002082 const struct opal_step erase_steps[] = {
2083 { opal_discovery0, },
2084 { start_auth_opal_session, opal_session },
2085 { erase_locking_range, opal_session },
2086 { end_opal_session, },
2087 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002088 };
2089 int ret;
2090
2091 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002092 setup_opal_dev(dev, erase_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002093 ret = next(dev);
2094 mutex_unlock(&dev->dev_lock);
2095 return ret;
2096}
2097
2098static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
2099 struct opal_mbr_data *opal_mbr)
2100{
Jon Derrickeed64952017-02-22 07:55:13 -07002101 const struct opal_step mbr_steps[] = {
2102 { opal_discovery0, },
2103 { start_admin1LSP_opal_session, &opal_mbr->key },
2104 { set_mbr_done, &opal_mbr->enable_disable },
2105 { end_opal_session, },
2106 { start_admin1LSP_opal_session, &opal_mbr->key },
2107 { set_mbr_enable_disable, &opal_mbr->enable_disable },
2108 { end_opal_session, },
2109 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002110 };
2111 int ret;
2112
2113 if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
2114 opal_mbr->enable_disable != OPAL_MBR_DISABLE)
2115 return -EINVAL;
2116
2117 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002118 setup_opal_dev(dev, mbr_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002119 ret = next(dev);
2120 mutex_unlock(&dev->dev_lock);
2121 return ret;
2122}
2123
2124static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
2125{
2126 struct opal_suspend_data *suspend;
2127
2128 suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
2129 if (!suspend)
2130 return -ENOMEM;
2131
2132 suspend->unlk = *lk_unlk;
2133 suspend->lr = lk_unlk->session.opal_key.lr;
2134
2135 mutex_lock(&dev->dev_lock);
2136 setup_opal_dev(dev, NULL);
2137 add_suspend_info(dev, suspend);
2138 mutex_unlock(&dev->dev_lock);
2139 return 0;
2140}
2141
2142static int opal_add_user_to_lr(struct opal_dev *dev,
2143 struct opal_lock_unlock *lk_unlk)
2144{
Jon Derrickeed64952017-02-22 07:55:13 -07002145 const struct opal_step steps[] = {
2146 { opal_discovery0, },
2147 { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2148 { add_user_to_lr, lk_unlk },
2149 { end_opal_session, },
2150 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002151 };
2152 int ret;
2153
2154 if (lk_unlk->l_state != OPAL_RO &&
2155 lk_unlk->l_state != OPAL_RW) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002156 pr_debug("Locking state was not RO or RW\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07002157 return -EINVAL;
2158 }
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002159 if (lk_unlk->session.who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002160 lk_unlk->session.who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002161 pr_debug("Authority was not within the range of users: %d\n",
2162 lk_unlk->session.who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002163 return -EINVAL;
2164 }
2165 if (lk_unlk->session.sum) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002166 pr_debug("%s not supported in sum. Use setup locking range\n",
2167 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07002168 return -EINVAL;
2169 }
2170
2171 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002172 setup_opal_dev(dev, steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002173 ret = next(dev);
2174 mutex_unlock(&dev->dev_lock);
2175 return ret;
2176}
2177
2178static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal)
2179{
Jon Derrickeed64952017-02-22 07:55:13 -07002180 const struct opal_step revert_steps[] = {
2181 { opal_discovery0, },
2182 { start_SIDASP_opal_session, opal },
2183 { revert_tper, }, /* controller will terminate session */
2184 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002185 };
2186 int ret;
2187
2188 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002189 setup_opal_dev(dev, revert_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002190 ret = next(dev);
2191 mutex_unlock(&dev->dev_lock);
Scott Bauer7d6d1572017-02-22 10:15:06 -07002192
2193 /*
2194 * If we successfully reverted lets clean
2195 * any saved locking ranges.
2196 */
2197 if (!ret)
2198 clean_opal_dev(dev);
2199
Scott Bauer455a7b22017-02-03 12:50:31 -07002200 return ret;
2201}
2202
Jon Derrickeed64952017-02-22 07:55:13 -07002203static int __opal_lock_unlock(struct opal_dev *dev,
2204 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002205{
Jon Derrickeed64952017-02-22 07:55:13 -07002206 const struct opal_step unlock_steps[] = {
2207 { opal_discovery0, },
2208 { start_auth_opal_session, &lk_unlk->session },
2209 { lock_unlock_locking_range, lk_unlk },
2210 { end_opal_session, },
2211 { NULL, }
2212 };
2213 const struct opal_step unlock_sum_steps[] = {
2214 { opal_discovery0, },
2215 { start_auth_opal_session, &lk_unlk->session },
2216 { lock_unlock_locking_range_sum, lk_unlk },
2217 { end_opal_session, },
2218 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002219 };
2220
Jon Derrickeed64952017-02-22 07:55:13 -07002221 dev->steps = lk_unlk->session.sum ? unlock_sum_steps : unlock_steps;
Scott Bauer455a7b22017-02-03 12:50:31 -07002222 return next(dev);
2223}
2224
Scott Bauerdbec491b2017-09-01 08:53:35 -06002225static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2226{
2227 u8 mbr_done_tf = 1;
2228 const struct opal_step mbrdone_step [] = {
2229 { opal_discovery0, },
2230 { start_admin1LSP_opal_session, key },
2231 { set_mbr_done, &mbr_done_tf },
2232 { end_opal_session, },
2233 { NULL, }
2234 };
2235
2236 dev->steps = mbrdone_step;
2237 return next(dev);
2238}
2239
Jon Derrickeed64952017-02-22 07:55:13 -07002240static int opal_lock_unlock(struct opal_dev *dev,
2241 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002242{
Scott Bauer455a7b22017-02-03 12:50:31 -07002243 int ret;
2244
2245 if (lk_unlk->session.who < OPAL_ADMIN1 ||
2246 lk_unlk->session.who > OPAL_USER9)
2247 return -EINVAL;
2248
2249 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002250 ret = __opal_lock_unlock(dev, lk_unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002251 mutex_unlock(&dev->dev_lock);
2252 return ret;
2253}
2254
2255static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2256{
Jon Derrickeed64952017-02-22 07:55:13 -07002257 const struct opal_step owner_steps[] = {
2258 { opal_discovery0, },
2259 { start_anybodyASP_opal_session, },
2260 { get_msid_cpin_pin, },
2261 { end_opal_session, },
2262 { start_SIDASP_opal_session, opal },
2263 { set_sid_cpin_pin, opal },
2264 { end_opal_session, },
2265 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002266 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002267 int ret;
2268
2269 if (!dev)
2270 return -ENODEV;
2271
2272 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002273 setup_opal_dev(dev, owner_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002274 ret = next(dev);
2275 mutex_unlock(&dev->dev_lock);
2276 return ret;
2277}
2278
2279static int opal_activate_lsp(struct opal_dev *dev, struct opal_lr_act *opal_lr_act)
2280{
Jon Derrickeed64952017-02-22 07:55:13 -07002281 const struct opal_step active_steps[] = {
2282 { opal_discovery0, },
2283 { start_SIDASP_opal_session, &opal_lr_act->key },
2284 { get_lsp_lifecycle, },
2285 { activate_lsp, opal_lr_act },
2286 { end_opal_session, },
2287 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002288 };
2289 int ret;
2290
2291 if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2292 return -EINVAL;
2293
2294 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002295 setup_opal_dev(dev, active_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002296 ret = next(dev);
2297 mutex_unlock(&dev->dev_lock);
2298 return ret;
2299}
2300
2301static int opal_setup_locking_range(struct opal_dev *dev,
2302 struct opal_user_lr_setup *opal_lrs)
2303{
Jon Derrickeed64952017-02-22 07:55:13 -07002304 const struct opal_step lr_steps[] = {
2305 { opal_discovery0, },
2306 { start_auth_opal_session, &opal_lrs->session },
2307 { setup_locking_range, opal_lrs },
2308 { end_opal_session, },
2309 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002310 };
2311 int ret;
2312
2313 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002314 setup_opal_dev(dev, lr_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002315 ret = next(dev);
2316 mutex_unlock(&dev->dev_lock);
2317 return ret;
2318}
2319
2320static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2321{
Jon Derrickeed64952017-02-22 07:55:13 -07002322 const struct opal_step pw_steps[] = {
2323 { opal_discovery0, },
2324 { start_auth_opal_session, &opal_pw->session },
2325 { set_new_pw, &opal_pw->new_user_pw },
2326 { end_opal_session, },
2327 { NULL }
Scott Bauer455a7b22017-02-03 12:50:31 -07002328 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002329 int ret;
2330
2331 if (opal_pw->session.who < OPAL_ADMIN1 ||
2332 opal_pw->session.who > OPAL_USER9 ||
2333 opal_pw->new_user_pw.who < OPAL_ADMIN1 ||
2334 opal_pw->new_user_pw.who > OPAL_USER9)
2335 return -EINVAL;
2336
2337 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002338 setup_opal_dev(dev, pw_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002339 ret = next(dev);
2340 mutex_unlock(&dev->dev_lock);
2341 return ret;
2342}
2343
2344static int opal_activate_user(struct opal_dev *dev,
2345 struct opal_session_info *opal_session)
2346{
Jon Derrickeed64952017-02-22 07:55:13 -07002347 const struct opal_step act_steps[] = {
2348 { opal_discovery0, },
2349 { start_admin1LSP_opal_session, &opal_session->opal_key },
2350 { internal_activate_user, opal_session },
2351 { end_opal_session, },
2352 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002353 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002354 int ret;
2355
2356 /* We can't activate Admin1 it's active as manufactured */
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002357 if (opal_session->who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002358 opal_session->who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002359 pr_debug("Who was not a valid user: %d\n", opal_session->who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002360 return -EINVAL;
2361 }
2362
2363 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002364 setup_opal_dev(dev, act_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002365 ret = next(dev);
2366 mutex_unlock(&dev->dev_lock);
2367 return ret;
2368}
2369
2370bool opal_unlock_from_suspend(struct opal_dev *dev)
2371{
2372 struct opal_suspend_data *suspend;
Scott Bauer455a7b22017-02-03 12:50:31 -07002373 bool was_failure = false;
2374 int ret = 0;
2375
2376 if (!dev)
2377 return false;
2378 if (!dev->supported)
2379 return false;
2380
2381 mutex_lock(&dev->dev_lock);
2382 setup_opal_dev(dev, NULL);
Scott Bauer455a7b22017-02-03 12:50:31 -07002383
2384 list_for_each_entry(suspend, &dev->unlk_lst, node) {
Scott Bauer455a7b22017-02-03 12:50:31 -07002385 dev->tsn = 0;
2386 dev->hsn = 0;
2387
Jon Derrickeed64952017-02-22 07:55:13 -07002388 ret = __opal_lock_unlock(dev, &suspend->unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002389 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002390 pr_debug("Failed to unlock LR %hhu with sum %d\n",
2391 suspend->unlk.session.opal_key.lr,
2392 suspend->unlk.session.sum);
Scott Bauer455a7b22017-02-03 12:50:31 -07002393 was_failure = true;
2394 }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002395 if (dev->mbr_enabled) {
2396 ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
2397 if (ret)
2398 pr_debug("Failed to set MBR Done in S3 resume\n");
2399 }
Scott Bauer455a7b22017-02-03 12:50:31 -07002400 }
2401 mutex_unlock(&dev->dev_lock);
2402 return was_failure;
2403}
2404EXPORT_SYMBOL(opal_unlock_from_suspend);
2405
Scott Bauere225c202017-02-14 17:29:36 -07002406int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
Scott Bauer455a7b22017-02-03 12:50:31 -07002407{
Scott Bauere225c202017-02-14 17:29:36 -07002408 void *p;
2409 int ret = -ENOTTY;
Scott Bauer455a7b22017-02-03 12:50:31 -07002410
2411 if (!capable(CAP_SYS_ADMIN))
2412 return -EACCES;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002413 if (!dev)
2414 return -ENOTSUPP;
Scott Bauer591c59d2017-04-07 13:58:50 -06002415 if (!dev->supported)
Scott Bauer455a7b22017-02-03 12:50:31 -07002416 return -ENOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -07002417
Jon Derrickeed64952017-02-22 07:55:13 -07002418 p = memdup_user(arg, _IOC_SIZE(cmd));
Scott Bauere225c202017-02-14 17:29:36 -07002419 if (IS_ERR(p))
2420 return PTR_ERR(p);
2421
Scott Bauer455a7b22017-02-03 12:50:31 -07002422 switch (cmd) {
Scott Bauere225c202017-02-14 17:29:36 -07002423 case IOC_OPAL_SAVE:
2424 ret = opal_save(dev, p);
2425 break;
2426 case IOC_OPAL_LOCK_UNLOCK:
2427 ret = opal_lock_unlock(dev, p);
2428 break;
2429 case IOC_OPAL_TAKE_OWNERSHIP:
2430 ret = opal_take_ownership(dev, p);
2431 break;
2432 case IOC_OPAL_ACTIVATE_LSP:
2433 ret = opal_activate_lsp(dev, p);
2434 break;
2435 case IOC_OPAL_SET_PW:
2436 ret = opal_set_new_pw(dev, p);
2437 break;
2438 case IOC_OPAL_ACTIVATE_USR:
2439 ret = opal_activate_user(dev, p);
2440 break;
2441 case IOC_OPAL_REVERT_TPR:
2442 ret = opal_reverttper(dev, p);
2443 break;
2444 case IOC_OPAL_LR_SETUP:
2445 ret = opal_setup_locking_range(dev, p);
2446 break;
2447 case IOC_OPAL_ADD_USR_TO_LR:
2448 ret = opal_add_user_to_lr(dev, p);
2449 break;
2450 case IOC_OPAL_ENABLE_DISABLE_MBR:
2451 ret = opal_enable_disable_shadow_mbr(dev, p);
2452 break;
2453 case IOC_OPAL_ERASE_LR:
2454 ret = opal_erase_locking_range(dev, p);
2455 break;
2456 case IOC_OPAL_SECURE_ERASE_LR:
2457 ret = opal_secure_erase_locking_range(dev, p);
2458 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002459 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06002460 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002461 }
Scott Bauere225c202017-02-14 17:29:36 -07002462
2463 kfree(p);
2464 return ret;
Scott Bauer455a7b22017-02-03 12:50:31 -07002465}
2466EXPORT_SYMBOL_GPL(sed_ioctl);