blob: 9b30ae5ab843b0508494cae08a78ae831c67e58b [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;
83
84 void *data;
85 sec_send_recv *send_recv;
86
Jon Derrickeed64952017-02-22 07:55:13 -070087 const struct opal_step *steps;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +010088 struct mutex dev_lock;
89 u16 comid;
90 u32 hsn;
91 u32 tsn;
92 u64 align;
93 u64 lowest_lba;
94
95 size_t pos;
96 u8 cmd[IO_BUFFER_LENGTH];
97 u8 resp[IO_BUFFER_LENGTH];
98
99 struct parsed_resp parsed;
100 size_t prev_d_len;
101 void *prev_data;
102
103 struct list_head unlk_lst;
104};
105
106
Scott Bauer455a7b22017-02-03 12:50:31 -0700107static const u8 opaluid[][OPAL_UID_LENGTH] = {
108 /* users */
109 [OPAL_SMUID_UID] =
110 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
111 [OPAL_THISSP_UID] =
112 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
113 [OPAL_ADMINSP_UID] =
114 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
115 [OPAL_LOCKINGSP_UID] =
116 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
117 [OPAL_ENTERPRISE_LOCKINGSP_UID] =
118 { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
119 [OPAL_ANYBODY_UID] =
120 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
121 [OPAL_SID_UID] =
122 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
123 [OPAL_ADMIN1_UID] =
124 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
125 [OPAL_USER1_UID] =
126 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
127 [OPAL_USER2_UID] =
128 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
129 [OPAL_PSID_UID] =
130 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
131 [OPAL_ENTERPRISE_BANDMASTER0_UID] =
132 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
133 [OPAL_ENTERPRISE_ERASEMASTER_UID] =
134 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
135
136 /* tables */
137
138 [OPAL_LOCKINGRANGE_GLOBAL] =
139 { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
140 [OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
141 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
142 [OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
143 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
144 [OPAL_MBRCONTROL] =
145 { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
146 [OPAL_MBR] =
147 { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
148 [OPAL_AUTHORITY_TABLE] =
149 { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
150 [OPAL_C_PIN_TABLE] =
151 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
152 [OPAL_LOCKING_INFO_TABLE] =
153 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
154 [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
155 { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
156
157 /* C_PIN_TABLE object ID's */
158
159 [OPAL_C_PIN_MSID] =
160 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
161 [OPAL_C_PIN_SID] =
162 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
163 [OPAL_C_PIN_ADMIN1] =
164 { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
165
166 /* half UID's (only first 4 bytes used) */
167
168 [OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
169 { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
170 [OPAL_HALF_UID_BOOLEAN_ACE] =
171 { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
172
173 /* special value for omitted optional parameter */
174 [OPAL_UID_HEXFF] =
175 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
176};
177
178/*
179 * TCG Storage SSC Methods.
180 * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
181 * Section: 6.3 Assigned UIDs
182 */
183static const u8 opalmethod[][OPAL_UID_LENGTH] = {
184 [OPAL_PROPERTIES] =
185 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
186 [OPAL_STARTSESSION] =
187 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
188 [OPAL_REVERT] =
189 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
190 [OPAL_ACTIVATE] =
191 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
192 [OPAL_EGET] =
193 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
194 [OPAL_ESET] =
195 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
196 [OPAL_NEXT] =
197 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
198 [OPAL_EAUTHENTICATE] =
199 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
200 [OPAL_GETACL] =
201 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
202 [OPAL_GENKEY] =
203 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
204 [OPAL_REVERTSP] =
205 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
206 [OPAL_GET] =
207 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
208 [OPAL_SET] =
209 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
210 [OPAL_AUTHENTICATE] =
211 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
212 [OPAL_RANDOM] =
213 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
214 [OPAL_ERASE] =
215 { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
216};
217
Scott Bauer455a7b22017-02-03 12:50:31 -0700218static int end_opal_session_error(struct opal_dev *dev);
219
220struct opal_suspend_data {
221 struct opal_lock_unlock unlk;
222 u8 lr;
223 struct list_head node;
224};
225
226/*
227 * Derived from:
228 * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
229 * Section: 5.1.5 Method Status Codes
230 */
231static const char * const opal_errors[] = {
232 "Success",
233 "Not Authorized",
234 "Unknown Error",
235 "SP Busy",
236 "SP Failed",
237 "SP Disabled",
238 "SP Frozen",
239 "No Sessions Available",
240 "Uniqueness Conflict",
241 "Insufficient Space",
242 "Insufficient Rows",
243 "Invalid Function",
244 "Invalid Parameter",
245 "Invalid Reference",
246 "Unknown Error",
247 "TPER Malfunction",
248 "Transaction Failure",
249 "Response Overflow",
250 "Authority Locked Out",
251};
252
253static const char *opal_error_to_human(int error)
254{
255 if (error == 0x3f)
256 return "Failed";
257
258 if (error >= ARRAY_SIZE(opal_errors) || error < 0)
259 return "Unknown Error";
260
261 return opal_errors[error];
262}
263
264static void print_buffer(const u8 *ptr, u32 length)
265{
266#ifdef DEBUG
267 print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
268 pr_debug("\n");
269#endif
270}
271
272static bool check_tper(const void *data)
273{
274 const struct d0_tper_features *tper = data;
275 u8 flags = tper->supported_features;
276
277 if (!(flags & TPER_SYNC_SUPPORTED)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600278 pr_debug("TPer sync not supported. flags = %d\n",
279 tper->supported_features);
Scott Bauer455a7b22017-02-03 12:50:31 -0700280 return false;
281 }
282
283 return true;
284}
285
286static bool check_sum(const void *data)
287{
288 const struct d0_single_user_mode *sum = data;
289 u32 nlo = be32_to_cpu(sum->num_locking_objects);
290
291 if (nlo == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600292 pr_debug("Need at least one locking object.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700293 return false;
294 }
295
296 pr_debug("Number of locking objects: %d\n", nlo);
297
298 return true;
299}
300
301static u16 get_comid_v100(const void *data)
302{
303 const struct d0_opal_v100 *v100 = data;
304
305 return be16_to_cpu(v100->baseComID);
306}
307
308static u16 get_comid_v200(const void *data)
309{
310 const struct d0_opal_v200 *v200 = data;
311
312 return be16_to_cpu(v200->baseComID);
313}
314
315static int opal_send_cmd(struct opal_dev *dev)
316{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100317 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700318 dev->cmd, IO_BUFFER_LENGTH,
319 true);
320}
321
322static int opal_recv_cmd(struct opal_dev *dev)
323{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +0100324 return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
Scott Bauer455a7b22017-02-03 12:50:31 -0700325 dev->resp, IO_BUFFER_LENGTH,
326 false);
327}
328
329static int opal_recv_check(struct opal_dev *dev)
330{
331 size_t buflen = IO_BUFFER_LENGTH;
332 void *buffer = dev->resp;
333 struct opal_header *hdr = buffer;
334 int ret;
335
336 do {
337 pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
338 hdr->cp.outstandingData,
339 hdr->cp.minTransfer);
340
341 if (hdr->cp.outstandingData == 0 ||
342 hdr->cp.minTransfer != 0)
343 return 0;
344
345 memset(buffer, 0, buflen);
346 ret = opal_recv_cmd(dev);
347 } while (!ret);
348
349 return ret;
350}
351
352static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
353{
354 int ret;
355
356 ret = opal_send_cmd(dev);
357 if (ret)
358 return ret;
359 ret = opal_recv_cmd(dev);
360 if (ret)
361 return ret;
362 ret = opal_recv_check(dev);
363 if (ret)
364 return ret;
365 return cont(dev);
366}
367
368static void check_geometry(struct opal_dev *dev, const void *data)
369{
370 const struct d0_geometry_features *geo = data;
371
372 dev->align = geo->alignment_granularity;
373 dev->lowest_lba = geo->lowest_aligned_lba;
374}
375
376static int next(struct opal_dev *dev)
377{
Jon Derrickeed64952017-02-22 07:55:13 -0700378 const struct opal_step *step;
379 int state = 0, error = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700380
381 do {
Jon Derrickeed64952017-02-22 07:55:13 -0700382 step = &dev->steps[state];
383 if (!step->fn)
Scott Bauer455a7b22017-02-03 12:50:31 -0700384 break;
385
Jon Derrickeed64952017-02-22 07:55:13 -0700386 error = step->fn(dev, step->data);
Scott Bauer455a7b22017-02-03 12:50:31 -0700387 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600388 pr_debug("Error on step function: %d with error %d: %s\n",
389 state, error,
390 opal_error_to_human(error));
Scott Bauer455a7b22017-02-03 12:50:31 -0700391
392 /* For each OPAL command we do a discovery0 then we
393 * start some sort of session.
394 * If we haven't passed state 1 then there was an error
395 * on discovery0 or during the attempt to start a
396 * session. Therefore we shouldn't attempt to terminate
397 * a session, as one has not yet been created.
398 */
Scott Bauer2d190202017-02-22 10:15:08 -0700399 if (state > 1) {
400 end_opal_session_error(dev);
401 return error;
402 }
403
Scott Bauer455a7b22017-02-03 12:50:31 -0700404 }
Jon Derrickeed64952017-02-22 07:55:13 -0700405 state++;
Scott Bauer455a7b22017-02-03 12:50:31 -0700406 } while (!error);
407
408 return error;
409}
410
411static int opal_discovery0_end(struct opal_dev *dev)
412{
413 bool found_com_id = false, supported = true, single_user = false;
414 const struct d0_header *hdr = (struct d0_header *)dev->resp;
415 const u8 *epos = dev->resp, *cpos = dev->resp;
416 u16 comid = 0;
Jon Derrick77039b92017-02-21 11:59:15 -0700417 u32 hlen = be32_to_cpu(hdr->length);
Scott Bauer455a7b22017-02-03 12:50:31 -0700418
Jon Derrick77039b92017-02-21 11:59:15 -0700419 print_buffer(dev->resp, hlen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700420
Jon Derrick77039b92017-02-21 11:59:15 -0700421 if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600422 pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
423 sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
Jon Derrick77039b92017-02-21 11:59:15 -0700424 return -EFAULT;
425 }
426
427 epos += hlen; /* end of buffer */
Scott Bauer455a7b22017-02-03 12:50:31 -0700428 cpos += sizeof(*hdr); /* current position on buffer */
429
430 while (cpos < epos && supported) {
431 const struct d0_features *body =
432 (const struct d0_features *)cpos;
433
434 switch (be16_to_cpu(body->code)) {
435 case FC_TPER:
436 supported = check_tper(body->features);
437 break;
438 case FC_SINGLEUSER:
439 single_user = check_sum(body->features);
440 break;
441 case FC_GEOMETRY:
442 check_geometry(dev, body);
443 break;
444 case FC_LOCKING:
445 case FC_ENTERPRISE:
446 case FC_DATASTORE:
447 /* some ignored properties */
448 pr_debug("Found OPAL feature description: %d\n",
449 be16_to_cpu(body->code));
450 break;
451 case FC_OPALV100:
452 comid = get_comid_v100(body->features);
453 found_com_id = true;
454 break;
455 case FC_OPALV200:
456 comid = get_comid_v200(body->features);
457 found_com_id = true;
458 break;
459 case 0xbfff ... 0xffff:
460 /* vendor specific, just ignore */
461 break;
462 default:
463 pr_debug("OPAL Unknown feature: %d\n",
464 be16_to_cpu(body->code));
465
466 }
467 cpos += body->length + 4;
468 }
469
470 if (!supported) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100471 pr_debug("This device is not Opal enabled. Not Supported!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700472 return -EOPNOTSUPP;
473 }
474
475 if (!single_user)
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100476 pr_debug("Device doesn't support single user mode\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700477
478
479 if (!found_com_id) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +0100480 pr_debug("Could not find OPAL comid for device. Returning early\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700481 return -EOPNOTSUPP;;
482 }
483
484 dev->comid = comid;
485
486 return 0;
487}
488
Jon Derrickeed64952017-02-22 07:55:13 -0700489static int opal_discovery0(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -0700490{
491 int ret;
492
493 memset(dev->resp, 0, IO_BUFFER_LENGTH);
494 dev->comid = OPAL_DISCOVERY_COMID;
495 ret = opal_recv_cmd(dev);
496 if (ret)
497 return ret;
498 return opal_discovery0_end(dev);
499}
500
501static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
502{
503 if (*err)
504 return;
505 if (cmd->pos >= IO_BUFFER_LENGTH - 1) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600506 pr_debug("Error adding u8: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700507 *err = -ERANGE;
508 return;
509 }
510 cmd->cmd[cmd->pos++] = tok;
511}
512
513static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
514 bool has_sign, int len)
515{
516 u8 atom;
517 int err = 0;
518
519 atom = SHORT_ATOM_ID;
520 atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
521 atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
522 atom |= len & SHORT_ATOM_LEN_MASK;
523
524 add_token_u8(&err, cmd, atom);
525}
526
527static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
528 bool has_sign, int len)
529{
530 u8 header0;
531
532 header0 = MEDIUM_ATOM_ID;
533 header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
534 header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
535 header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
536 cmd->cmd[cmd->pos++] = header0;
537 cmd->cmd[cmd->pos++] = len;
538}
539
540static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
541{
542
543 size_t len;
544 int msb;
545 u8 n;
546
547 if (!(number & ~TINY_ATOM_DATA_MASK)) {
548 add_token_u8(err, cmd, number);
549 return;
550 }
551
552 msb = fls(number);
553 len = DIV_ROUND_UP(msb, 4);
554
555 if (cmd->pos >= IO_BUFFER_LENGTH - len - 1) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600556 pr_debug("Error adding u64: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700557 *err = -ERANGE;
558 return;
559 }
560 add_short_atom_header(cmd, false, false, len);
561 while (len--) {
562 n = number >> (len * 8);
563 add_token_u8(err, cmd, n);
564 }
565}
566
567static void add_token_bytestring(int *err, struct opal_dev *cmd,
568 const u8 *bytestring, size_t len)
569{
570 size_t header_len = 1;
571 bool is_short_atom = true;
572
573 if (*err)
574 return;
575
576 if (len & ~SHORT_ATOM_LEN_MASK) {
577 header_len = 2;
578 is_short_atom = false;
579 }
580
581 if (len >= IO_BUFFER_LENGTH - cmd->pos - header_len) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600582 pr_debug("Error adding bytestring: end of buffer.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700583 *err = -ERANGE;
584 return;
585 }
586
587 if (is_short_atom)
588 add_short_atom_header(cmd, true, false, len);
589 else
590 add_medium_atom_header(cmd, true, false, len);
591
592 memcpy(&cmd->cmd[cmd->pos], bytestring, len);
593 cmd->pos += len;
594
595}
596
597static int build_locking_range(u8 *buffer, size_t length, u8 lr)
598{
599 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600600 pr_debug("Can't build locking range. Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700601 return -ERANGE;
602 }
603
604 memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
605
606 if (lr == 0)
607 return 0;
608 buffer[5] = LOCKING_RANGE_NON_GLOBAL;
609 buffer[7] = lr;
610
611 return 0;
612}
613
614static int build_locking_user(u8 *buffer, size_t length, u8 lr)
615{
616 if (length > OPAL_UID_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600617 pr_debug("Can't build locking range user, Length OOB\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700618 return -ERANGE;
619 }
620
621 memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
622
623 buffer[7] = lr + 1;
624
625 return 0;
626}
627
628static void set_comid(struct opal_dev *cmd, u16 comid)
629{
630 struct opal_header *hdr = (struct opal_header *)cmd->cmd;
631
632 hdr->cp.extendedComID[0] = comid >> 8;
633 hdr->cp.extendedComID[1] = comid;
634 hdr->cp.extendedComID[2] = 0;
635 hdr->cp.extendedComID[3] = 0;
636}
637
638static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
639{
640 struct opal_header *hdr;
641 int err = 0;
642
643 add_token_u8(&err, cmd, OPAL_ENDOFDATA);
644 add_token_u8(&err, cmd, OPAL_STARTLIST);
645 add_token_u8(&err, cmd, 0);
646 add_token_u8(&err, cmd, 0);
647 add_token_u8(&err, cmd, 0);
648 add_token_u8(&err, cmd, OPAL_ENDLIST);
649
650 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600651 pr_debug("Error finalizing command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700652 return -EFAULT;
653 }
654
655 hdr = (struct opal_header *) cmd->cmd;
656
657 hdr->pkt.tsn = cpu_to_be32(tsn);
658 hdr->pkt.hsn = cpu_to_be32(hsn);
659
660 hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
661 while (cmd->pos % 4) {
662 if (cmd->pos >= IO_BUFFER_LENGTH) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600663 pr_debug("Error: Buffer overrun\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700664 return -ERANGE;
665 }
666 cmd->cmd[cmd->pos++] = 0;
667 }
668 hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
669 sizeof(hdr->pkt));
670 hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
671
672 return 0;
673}
674
Jon Derrickcccb9242017-02-21 11:59:14 -0700675static const struct opal_resp_tok *response_get_token(
676 const struct parsed_resp *resp,
677 int n)
Scott Bauer455a7b22017-02-03 12:50:31 -0700678{
679 const struct opal_resp_tok *tok;
680
681 if (n >= resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600682 pr_debug("Token number doesn't exist: %d, resp: %d\n",
683 n, resp->num);
Jon Derrickcccb9242017-02-21 11:59:14 -0700684 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700685 }
686
687 tok = &resp->toks[n];
688 if (tok->len == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600689 pr_debug("Token length must be non-zero\n");
Jon Derrickcccb9242017-02-21 11:59:14 -0700690 return ERR_PTR(-EINVAL);
Scott Bauer455a7b22017-02-03 12:50:31 -0700691 }
692
Jon Derrickcccb9242017-02-21 11:59:14 -0700693 return tok;
Scott Bauer455a7b22017-02-03 12:50:31 -0700694}
695
Jon Derrickaedb6e22017-02-21 11:59:13 -0700696static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
697 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700698{
699 tok->pos = pos;
700 tok->len = 1;
701 tok->width = OPAL_WIDTH_TINY;
702
703 if (pos[0] & TINY_ATOM_SIGNED) {
704 tok->type = OPAL_DTA_TOKENID_SINT;
705 } else {
706 tok->type = OPAL_DTA_TOKENID_UINT;
707 tok->stored.u = pos[0] & 0x3f;
708 }
709
710 return tok->len;
711}
712
Jon Derrickaedb6e22017-02-21 11:59:13 -0700713static ssize_t response_parse_short(struct opal_resp_tok *tok,
714 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700715{
716 tok->pos = pos;
717 tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
718 tok->width = OPAL_WIDTH_SHORT;
719
720 if (pos[0] & SHORT_ATOM_BYTESTRING) {
721 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
722 } else if (pos[0] & SHORT_ATOM_SIGNED) {
723 tok->type = OPAL_DTA_TOKENID_SINT;
724 } else {
725 u64 u_integer = 0;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700726 ssize_t i, b = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700727
728 tok->type = OPAL_DTA_TOKENID_UINT;
729 if (tok->len > 9) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600730 pr_debug("uint64 with more than 8 bytes\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700731 return -EINVAL;
732 }
733 for (i = tok->len - 1; i > 0; i--) {
734 u_integer |= ((u64)pos[i] << (8 * b));
735 b++;
736 }
737 tok->stored.u = u_integer;
738 }
739
740 return tok->len;
741}
742
Jon Derrickaedb6e22017-02-21 11:59:13 -0700743static ssize_t response_parse_medium(struct opal_resp_tok *tok,
744 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700745{
746 tok->pos = pos;
747 tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
748 tok->width = OPAL_WIDTH_MEDIUM;
749
750 if (pos[0] & MEDIUM_ATOM_BYTESTRING)
751 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
752 else if (pos[0] & MEDIUM_ATOM_SIGNED)
753 tok->type = OPAL_DTA_TOKENID_SINT;
754 else
755 tok->type = OPAL_DTA_TOKENID_UINT;
756
757 return tok->len;
758}
759
Jon Derrickaedb6e22017-02-21 11:59:13 -0700760static ssize_t response_parse_long(struct opal_resp_tok *tok,
761 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700762{
763 tok->pos = pos;
764 tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
765 tok->width = OPAL_WIDTH_LONG;
766
767 if (pos[0] & LONG_ATOM_BYTESTRING)
768 tok->type = OPAL_DTA_TOKENID_BYTESTRING;
769 else if (pos[0] & LONG_ATOM_SIGNED)
770 tok->type = OPAL_DTA_TOKENID_SINT;
771 else
772 tok->type = OPAL_DTA_TOKENID_UINT;
773
774 return tok->len;
775}
776
Jon Derrickaedb6e22017-02-21 11:59:13 -0700777static ssize_t response_parse_token(struct opal_resp_tok *tok,
778 const u8 *pos)
Scott Bauer455a7b22017-02-03 12:50:31 -0700779{
780 tok->pos = pos;
781 tok->len = 1;
782 tok->type = OPAL_DTA_TOKENID_TOKEN;
783 tok->width = OPAL_WIDTH_TOKEN;
784
785 return tok->len;
786}
787
788static int response_parse(const u8 *buf, size_t length,
789 struct parsed_resp *resp)
790{
791 const struct opal_header *hdr;
792 struct opal_resp_tok *iter;
793 int num_entries = 0;
794 int total;
Jon Derrickaedb6e22017-02-21 11:59:13 -0700795 ssize_t token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700796 const u8 *pos;
Jon Derrick77039b92017-02-21 11:59:15 -0700797 u32 clen, plen, slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700798
799 if (!buf)
800 return -EFAULT;
801
802 if (!resp)
803 return -EFAULT;
804
805 hdr = (struct opal_header *)buf;
806 pos = buf;
807 pos += sizeof(*hdr);
808
Jon Derrick77039b92017-02-21 11:59:15 -0700809 clen = be32_to_cpu(hdr->cp.length);
810 plen = be32_to_cpu(hdr->pkt.length);
811 slen = be32_to_cpu(hdr->subpkt.length);
812 pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
813 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700814
Jon Derrick77039b92017-02-21 11:59:15 -0700815 if (clen == 0 || plen == 0 || slen == 0 ||
816 slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600817 pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
818 clen, plen, slen);
Scott Bauer455a7b22017-02-03 12:50:31 -0700819 print_buffer(pos, sizeof(*hdr));
820 return -EINVAL;
821 }
822
823 if (pos > buf + length)
824 return -EFAULT;
825
826 iter = resp->toks;
Jon Derrick77039b92017-02-21 11:59:15 -0700827 total = slen;
Scott Bauer455a7b22017-02-03 12:50:31 -0700828 print_buffer(pos, total);
829 while (total > 0) {
830 if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
831 token_length = response_parse_tiny(iter, pos);
832 else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
833 token_length = response_parse_short(iter, pos);
834 else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
835 token_length = response_parse_medium(iter, pos);
836 else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
837 token_length = response_parse_long(iter, pos);
838 else /* TOKEN */
839 token_length = response_parse_token(iter, pos);
840
Jon Derrickaedb6e22017-02-21 11:59:13 -0700841 if (token_length < 0)
842 return token_length;
Scott Bauer455a7b22017-02-03 12:50:31 -0700843
844 pos += token_length;
845 total -= token_length;
846 iter++;
847 num_entries++;
848 }
849
850 if (num_entries == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600851 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700852 return -EINVAL;
853 }
854 resp->num = num_entries;
855
856 return 0;
857}
858
859static size_t response_get_string(const struct parsed_resp *resp, int n,
860 const char **store)
861{
862 *store = NULL;
863 if (!resp) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600864 pr_debug("Response is NULL\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700865 return 0;
866 }
867
868 if (n > resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600869 pr_debug("Response has %d tokens. Can't access %d\n",
870 resp->num, n);
Scott Bauer455a7b22017-02-03 12:50:31 -0700871 return 0;
872 }
873
874 if (resp->toks[n].type != OPAL_DTA_TOKENID_BYTESTRING) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600875 pr_debug("Token is not a byte string!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700876 return 0;
877 }
878
879 *store = resp->toks[n].pos + 1;
880 return resp->toks[n].len - 1;
881}
882
883static u64 response_get_u64(const struct parsed_resp *resp, int n)
884{
885 if (!resp) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600886 pr_debug("Response is NULL\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700887 return 0;
888 }
889
890 if (n > resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600891 pr_debug("Response has %d tokens. Can't access %d\n",
892 resp->num, n);
Scott Bauer455a7b22017-02-03 12:50:31 -0700893 return 0;
894 }
895
896 if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600897 pr_debug("Token is not unsigned it: %d\n",
898 resp->toks[n].type);
Scott Bauer455a7b22017-02-03 12:50:31 -0700899 return 0;
900 }
901
902 if (!(resp->toks[n].width == OPAL_WIDTH_TINY ||
903 resp->toks[n].width == OPAL_WIDTH_SHORT)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600904 pr_debug("Atom is not short or tiny: %d\n",
905 resp->toks[n].width);
Scott Bauer455a7b22017-02-03 12:50:31 -0700906 return 0;
907 }
908
909 return resp->toks[n].stored.u;
910}
911
Jon Derrickcccb9242017-02-21 11:59:14 -0700912static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
913{
914 if (IS_ERR(token) ||
915 token->type != OPAL_DTA_TOKENID_TOKEN ||
916 token->pos[0] != match)
917 return false;
918 return true;
919}
920
Scott Bauer455a7b22017-02-03 12:50:31 -0700921static u8 response_status(const struct parsed_resp *resp)
922{
Jon Derrickcccb9242017-02-21 11:59:14 -0700923 const struct opal_resp_tok *tok;
924
925 tok = response_get_token(resp, 0);
926 if (response_token_matches(tok, OPAL_ENDOFSESSION))
Scott Bauer455a7b22017-02-03 12:50:31 -0700927 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700928
929 if (resp->num < 5)
930 return DTAERROR_NO_METHOD_STATUS;
931
Jon Derrickcccb9242017-02-21 11:59:14 -0700932 tok = response_get_token(resp, resp->num - 5);
933 if (!response_token_matches(tok, OPAL_STARTLIST))
934 return DTAERROR_NO_METHOD_STATUS;
935
936 tok = response_get_token(resp, resp->num - 1);
937 if (!response_token_matches(tok, OPAL_ENDLIST))
Scott Bauer455a7b22017-02-03 12:50:31 -0700938 return DTAERROR_NO_METHOD_STATUS;
939
940 return response_get_u64(resp, resp->num - 4);
941}
942
943/* Parses and checks for errors */
944static int parse_and_check_status(struct opal_dev *dev)
945{
946 int error;
947
948 print_buffer(dev->cmd, dev->pos);
949
950 error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
951 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600952 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700953 return error;
954 }
955
956 return response_status(&dev->parsed);
957}
958
959static void clear_opal_cmd(struct opal_dev *dev)
960{
961 dev->pos = sizeof(struct opal_header);
962 memset(dev->cmd, 0, IO_BUFFER_LENGTH);
963}
964
965static int start_opal_session_cont(struct opal_dev *dev)
966{
967 u32 hsn, tsn;
968 int error = 0;
969
970 error = parse_and_check_status(dev);
971 if (error)
972 return error;
973
974 hsn = response_get_u64(&dev->parsed, 4);
975 tsn = response_get_u64(&dev->parsed, 5);
976
977 if (hsn == 0 && tsn == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600978 pr_debug("Couldn't authenticate session\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700979 return -EPERM;
980 }
981
982 dev->hsn = hsn;
983 dev->tsn = tsn;
984 return 0;
985}
986
987static void add_suspend_info(struct opal_dev *dev,
988 struct opal_suspend_data *sus)
989{
990 struct opal_suspend_data *iter;
991
992 list_for_each_entry(iter, &dev->unlk_lst, node) {
993 if (iter->lr == sus->lr) {
994 list_del(&iter->node);
995 kfree(iter);
996 break;
997 }
998 }
999 list_add_tail(&sus->node, &dev->unlk_lst);
1000}
1001
1002static int end_session_cont(struct opal_dev *dev)
1003{
1004 dev->hsn = 0;
1005 dev->tsn = 0;
1006 return parse_and_check_status(dev);
1007}
1008
1009static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1010{
1011 int ret;
1012
1013 ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1014 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001015 pr_debug("Error finalizing command buffer: %d\n", ret);
Scott Bauer455a7b22017-02-03 12:50:31 -07001016 return ret;
1017 }
1018
1019 print_buffer(dev->cmd, dev->pos);
1020
1021 return opal_send_recv(dev, cont);
1022}
1023
Jon Derrickeed64952017-02-22 07:55:13 -07001024static int gen_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001025{
Scott Bauer455a7b22017-02-03 12:50:31 -07001026 u8 uid[OPAL_UID_LENGTH];
1027 int err = 0;
1028
1029 clear_opal_cmd(dev);
1030 set_comid(dev, dev->comid);
1031
1032 memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
Scott Bauer455a7b22017-02-03 12:50:31 -07001033 kfree(dev->prev_data);
1034 dev->prev_data = NULL;
1035
1036 add_token_u8(&err, dev, OPAL_CALL);
1037 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1038 add_token_bytestring(&err, dev, opalmethod[OPAL_GENKEY],
1039 OPAL_UID_LENGTH);
1040 add_token_u8(&err, dev, OPAL_STARTLIST);
1041 add_token_u8(&err, dev, OPAL_ENDLIST);
1042
1043 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001044 pr_debug("Error building gen key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001045 return err;
1046
1047 }
1048 return finalize_and_send(dev, parse_and_check_status);
1049}
1050
1051static int get_active_key_cont(struct opal_dev *dev)
1052{
1053 const char *activekey;
1054 size_t keylen;
1055 int error = 0;
1056
1057 error = parse_and_check_status(dev);
1058 if (error)
1059 return error;
1060 keylen = response_get_string(&dev->parsed, 4, &activekey);
1061 if (!activekey) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001062 pr_debug("%s: Couldn't extract the Activekey from the response\n",
1063 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001064 return OPAL_INVAL_PARAM;
1065 }
1066 dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1067
1068 if (!dev->prev_data)
1069 return -ENOMEM;
1070
1071 dev->prev_d_len = keylen;
1072
1073 return 0;
1074}
1075
Jon Derrickeed64952017-02-22 07:55:13 -07001076static int get_active_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001077{
1078 u8 uid[OPAL_UID_LENGTH];
1079 int err = 0;
Jon Derrickeed64952017-02-22 07:55:13 -07001080 u8 *lr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001081
1082 clear_opal_cmd(dev);
1083 set_comid(dev, dev->comid);
Scott Bauer455a7b22017-02-03 12:50:31 -07001084
1085 err = build_locking_range(uid, sizeof(uid), *lr);
1086 if (err)
1087 return err;
1088
1089 err = 0;
1090 add_token_u8(&err, dev, OPAL_CALL);
1091 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1092 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1093 add_token_u8(&err, dev, OPAL_STARTLIST);
1094 add_token_u8(&err, dev, OPAL_STARTLIST);
1095 add_token_u8(&err, dev, OPAL_STARTNAME);
1096 add_token_u8(&err, dev, 3); /* startCloumn */
1097 add_token_u8(&err, dev, 10); /* ActiveKey */
1098 add_token_u8(&err, dev, OPAL_ENDNAME);
1099 add_token_u8(&err, dev, OPAL_STARTNAME);
1100 add_token_u8(&err, dev, 4); /* endColumn */
1101 add_token_u8(&err, dev, 10); /* ActiveKey */
1102 add_token_u8(&err, dev, OPAL_ENDNAME);
1103 add_token_u8(&err, dev, OPAL_ENDLIST);
1104 add_token_u8(&err, dev, OPAL_ENDLIST);
1105 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001106 pr_debug("Error building get active key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001107 return err;
1108 }
1109
1110 return finalize_and_send(dev, get_active_key_cont);
1111}
1112
1113static int generic_lr_enable_disable(struct opal_dev *dev,
1114 u8 *uid, bool rle, bool wle,
1115 bool rl, bool wl)
1116{
1117 int err = 0;
1118
1119 add_token_u8(&err, dev, OPAL_CALL);
1120 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1121 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1122
1123 add_token_u8(&err, dev, OPAL_STARTLIST);
1124 add_token_u8(&err, dev, OPAL_STARTNAME);
1125 add_token_u8(&err, dev, OPAL_VALUES);
1126 add_token_u8(&err, dev, OPAL_STARTLIST);
1127
1128 add_token_u8(&err, dev, OPAL_STARTNAME);
1129 add_token_u8(&err, dev, 5); /* ReadLockEnabled */
1130 add_token_u8(&err, dev, rle);
1131 add_token_u8(&err, dev, OPAL_ENDNAME);
1132
1133 add_token_u8(&err, dev, OPAL_STARTNAME);
1134 add_token_u8(&err, dev, 6); /* WriteLockEnabled */
1135 add_token_u8(&err, dev, wle);
1136 add_token_u8(&err, dev, OPAL_ENDNAME);
1137
1138 add_token_u8(&err, dev, OPAL_STARTNAME);
1139 add_token_u8(&err, dev, OPAL_READLOCKED);
1140 add_token_u8(&err, dev, rl);
1141 add_token_u8(&err, dev, OPAL_ENDNAME);
1142
1143 add_token_u8(&err, dev, OPAL_STARTNAME);
1144 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1145 add_token_u8(&err, dev, wl);
1146 add_token_u8(&err, dev, OPAL_ENDNAME);
1147
1148 add_token_u8(&err, dev, OPAL_ENDLIST);
1149 add_token_u8(&err, dev, OPAL_ENDNAME);
1150 add_token_u8(&err, dev, OPAL_ENDLIST);
1151 return err;
1152}
1153
1154static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1155 struct opal_user_lr_setup *setup)
1156{
1157 int err;
1158
1159 err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1160 0, 0);
1161 if (err)
Scott Bauer591c59d2017-04-07 13:58:50 -06001162 pr_debug("Failed to create enable global lr command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001163 return err;
1164}
1165
Jon Derrickeed64952017-02-22 07:55:13 -07001166static int setup_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001167{
1168 u8 uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001169 struct opal_user_lr_setup *setup = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001170 u8 lr;
1171 int err = 0;
1172
1173 clear_opal_cmd(dev);
1174 set_comid(dev, dev->comid);
1175
Scott Bauer455a7b22017-02-03 12:50:31 -07001176 lr = setup->session.opal_key.lr;
1177 err = build_locking_range(uid, sizeof(uid), lr);
1178 if (err)
1179 return err;
1180
1181 if (lr == 0)
1182 err = enable_global_lr(dev, uid, setup);
1183 else {
1184 add_token_u8(&err, dev, OPAL_CALL);
1185 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1186 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1187 OPAL_UID_LENGTH);
1188
1189 add_token_u8(&err, dev, OPAL_STARTLIST);
1190 add_token_u8(&err, dev, OPAL_STARTNAME);
1191 add_token_u8(&err, dev, OPAL_VALUES);
1192 add_token_u8(&err, dev, OPAL_STARTLIST);
1193
1194 add_token_u8(&err, dev, OPAL_STARTNAME);
1195 add_token_u8(&err, dev, 3); /* Ranges Start */
1196 add_token_u64(&err, dev, setup->range_start);
1197 add_token_u8(&err, dev, OPAL_ENDNAME);
1198
1199 add_token_u8(&err, dev, OPAL_STARTNAME);
1200 add_token_u8(&err, dev, 4); /* Ranges length */
1201 add_token_u64(&err, dev, setup->range_length);
1202 add_token_u8(&err, dev, OPAL_ENDNAME);
1203
1204 add_token_u8(&err, dev, OPAL_STARTNAME);
1205 add_token_u8(&err, dev, 5); /*ReadLockEnabled */
1206 add_token_u64(&err, dev, !!setup->RLE);
1207 add_token_u8(&err, dev, OPAL_ENDNAME);
1208
1209 add_token_u8(&err, dev, OPAL_STARTNAME);
1210 add_token_u8(&err, dev, 6); /*WriteLockEnabled*/
1211 add_token_u64(&err, dev, !!setup->WLE);
1212 add_token_u8(&err, dev, OPAL_ENDNAME);
1213
1214 add_token_u8(&err, dev, OPAL_ENDLIST);
1215 add_token_u8(&err, dev, OPAL_ENDNAME);
1216 add_token_u8(&err, dev, OPAL_ENDLIST);
1217
1218 }
1219 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001220 pr_debug("Error building Setup Locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001221 return err;
1222
1223 }
1224
1225 return finalize_and_send(dev, parse_and_check_status);
1226}
1227
1228static int start_generic_opal_session(struct opal_dev *dev,
1229 enum opal_uid auth,
1230 enum opal_uid sp_type,
1231 const char *key,
1232 u8 key_len)
1233{
1234 u32 hsn;
1235 int err = 0;
1236
Scott Bauer591c59d2017-04-07 13:58:50 -06001237 if (key == NULL && auth != OPAL_ANYBODY_UID)
Scott Bauer455a7b22017-02-03 12:50:31 -07001238 return OPAL_INVAL_PARAM;
Scott Bauer455a7b22017-02-03 12:50:31 -07001239
1240 clear_opal_cmd(dev);
1241
1242 set_comid(dev, dev->comid);
1243 hsn = GENERIC_HOST_SESSION_NUM;
1244
1245 add_token_u8(&err, dev, OPAL_CALL);
1246 add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
1247 OPAL_UID_LENGTH);
1248 add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
1249 OPAL_UID_LENGTH);
1250 add_token_u8(&err, dev, OPAL_STARTLIST);
1251 add_token_u64(&err, dev, hsn);
1252 add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1253 add_token_u8(&err, dev, 1);
1254
1255 switch (auth) {
1256 case OPAL_ANYBODY_UID:
1257 add_token_u8(&err, dev, OPAL_ENDLIST);
1258 break;
1259 case OPAL_ADMIN1_UID:
1260 case OPAL_SID_UID:
1261 add_token_u8(&err, dev, OPAL_STARTNAME);
1262 add_token_u8(&err, dev, 0); /* HostChallenge */
1263 add_token_bytestring(&err, dev, key, key_len);
1264 add_token_u8(&err, dev, OPAL_ENDNAME);
1265 add_token_u8(&err, dev, OPAL_STARTNAME);
1266 add_token_u8(&err, dev, 3); /* HostSignAuth */
1267 add_token_bytestring(&err, dev, opaluid[auth],
1268 OPAL_UID_LENGTH);
1269 add_token_u8(&err, dev, OPAL_ENDNAME);
1270 add_token_u8(&err, dev, OPAL_ENDLIST);
1271 break;
1272 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001273 pr_debug("Cannot start Admin SP session with auth %d\n", auth);
Scott Bauer455a7b22017-02-03 12:50:31 -07001274 return OPAL_INVAL_PARAM;
1275 }
1276
1277 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001278 pr_debug("Error building start adminsp session command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001279 return err;
1280 }
1281
1282 return finalize_and_send(dev, start_opal_session_cont);
1283}
1284
Jon Derrickeed64952017-02-22 07:55:13 -07001285static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001286{
1287 return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1288 OPAL_ADMINSP_UID, NULL, 0);
1289}
1290
Jon Derrickeed64952017-02-22 07:55:13 -07001291static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001292{
1293 int ret;
1294 const u8 *key = dev->prev_data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001295
1296 if (!key) {
Jon Derrickeed64952017-02-22 07:55:13 -07001297 const struct opal_key *okey = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001298 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1299 OPAL_ADMINSP_UID,
1300 okey->key,
1301 okey->key_len);
1302 } else {
1303 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1304 OPAL_ADMINSP_UID,
1305 key, dev->prev_d_len);
1306 kfree(key);
1307 dev->prev_data = NULL;
1308 }
1309 return ret;
1310}
1311
Jon Derrickeed64952017-02-22 07:55:13 -07001312static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001313{
Jon Derrickeed64952017-02-22 07:55:13 -07001314 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001315 return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1316 OPAL_LOCKINGSP_UID,
1317 key->key, key->key_len);
1318}
1319
Jon Derrickeed64952017-02-22 07:55:13 -07001320static int start_auth_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001321{
Jon Derrickeed64952017-02-22 07:55:13 -07001322 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001323 u8 lk_ul_user[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001324 size_t keylen = session->opal_key.key_len;
Scott Bauer455a7b22017-02-03 12:50:31 -07001325 int err = 0;
1326
Scott Bauer455a7b22017-02-03 12:50:31 -07001327 u8 *key = session->opal_key.key;
1328 u32 hsn = GENERIC_HOST_SESSION_NUM;
1329
1330 clear_opal_cmd(dev);
1331 set_comid(dev, dev->comid);
1332
1333 if (session->sum) {
1334 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1335 session->opal_key.lr);
1336 if (err)
1337 return err;
1338
1339 } else if (session->who != OPAL_ADMIN1 && !session->sum) {
1340 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1341 session->who - 1);
1342 if (err)
1343 return err;
1344 } else
1345 memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1346
1347 add_token_u8(&err, dev, OPAL_CALL);
1348 add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
1349 OPAL_UID_LENGTH);
1350 add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
1351 OPAL_UID_LENGTH);
1352
1353 add_token_u8(&err, dev, OPAL_STARTLIST);
1354 add_token_u64(&err, dev, hsn);
1355 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1356 OPAL_UID_LENGTH);
1357 add_token_u8(&err, dev, 1);
1358 add_token_u8(&err, dev, OPAL_STARTNAME);
1359 add_token_u8(&err, dev, 0);
1360 add_token_bytestring(&err, dev, key, keylen);
1361 add_token_u8(&err, dev, OPAL_ENDNAME);
1362 add_token_u8(&err, dev, OPAL_STARTNAME);
1363 add_token_u8(&err, dev, 3);
1364 add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1365 add_token_u8(&err, dev, OPAL_ENDNAME);
1366 add_token_u8(&err, dev, OPAL_ENDLIST);
1367
1368 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001369 pr_debug("Error building STARTSESSION command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001370 return err;
1371 }
1372
1373 return finalize_and_send(dev, start_opal_session_cont);
1374}
1375
Jon Derrickeed64952017-02-22 07:55:13 -07001376static int revert_tper(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001377{
1378 int err = 0;
1379
1380 clear_opal_cmd(dev);
1381 set_comid(dev, dev->comid);
1382
1383 add_token_u8(&err, dev, OPAL_CALL);
1384 add_token_bytestring(&err, dev, opaluid[OPAL_ADMINSP_UID],
1385 OPAL_UID_LENGTH);
1386 add_token_bytestring(&err, dev, opalmethod[OPAL_REVERT],
1387 OPAL_UID_LENGTH);
1388 add_token_u8(&err, dev, OPAL_STARTLIST);
1389 add_token_u8(&err, dev, OPAL_ENDLIST);
1390 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001391 pr_debug("Error building REVERT TPER command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001392 return err;
1393 }
1394
1395 return finalize_and_send(dev, parse_and_check_status);
1396}
1397
Jon Derrickeed64952017-02-22 07:55:13 -07001398static int internal_activate_user(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001399{
Jon Derrickeed64952017-02-22 07:55:13 -07001400 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001401 u8 uid[OPAL_UID_LENGTH];
1402 int err = 0;
1403
1404 clear_opal_cmd(dev);
1405 set_comid(dev, dev->comid);
1406
1407 memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1408 uid[7] = session->who;
1409
1410 add_token_u8(&err, dev, OPAL_CALL);
1411 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1412 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1413 add_token_u8(&err, dev, OPAL_STARTLIST);
1414 add_token_u8(&err, dev, OPAL_STARTNAME);
1415 add_token_u8(&err, dev, OPAL_VALUES);
1416 add_token_u8(&err, dev, OPAL_STARTLIST);
1417 add_token_u8(&err, dev, OPAL_STARTNAME);
1418 add_token_u8(&err, dev, 5); /* Enabled */
1419 add_token_u8(&err, dev, OPAL_TRUE);
1420 add_token_u8(&err, dev, OPAL_ENDNAME);
1421 add_token_u8(&err, dev, OPAL_ENDLIST);
1422 add_token_u8(&err, dev, OPAL_ENDNAME);
1423 add_token_u8(&err, dev, OPAL_ENDLIST);
1424
1425 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001426 pr_debug("Error building Activate UserN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001427 return err;
1428 }
1429
1430 return finalize_and_send(dev, parse_and_check_status);
1431}
1432
Jon Derrickeed64952017-02-22 07:55:13 -07001433static int erase_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001434{
Jon Derrickeed64952017-02-22 07:55:13 -07001435 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001436 u8 uid[OPAL_UID_LENGTH];
1437 int err = 0;
1438
1439 clear_opal_cmd(dev);
1440 set_comid(dev, dev->comid);
Scott Bauer455a7b22017-02-03 12:50:31 -07001441
1442 if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1443 return -ERANGE;
1444
1445 add_token_u8(&err, dev, OPAL_CALL);
1446 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1447 add_token_bytestring(&err, dev, opalmethod[OPAL_ERASE],
1448 OPAL_UID_LENGTH);
1449 add_token_u8(&err, dev, OPAL_STARTLIST);
1450 add_token_u8(&err, dev, OPAL_ENDLIST);
1451
1452 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001453 pr_debug("Error building Erase Locking Range Command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001454 return err;
1455 }
1456 return finalize_and_send(dev, parse_and_check_status);
1457}
1458
Jon Derrickeed64952017-02-22 07:55:13 -07001459static int set_mbr_done(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001460{
Jon Derrickeed64952017-02-22 07:55:13 -07001461 u8 *mbr_done_tf = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001462 int err = 0;
1463
1464 clear_opal_cmd(dev);
1465 set_comid(dev, dev->comid);
1466
1467 add_token_u8(&err, dev, OPAL_CALL);
1468 add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL],
1469 OPAL_UID_LENGTH);
1470 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1471 add_token_u8(&err, dev, OPAL_STARTLIST);
1472 add_token_u8(&err, dev, OPAL_STARTNAME);
1473 add_token_u8(&err, dev, OPAL_VALUES);
1474 add_token_u8(&err, dev, OPAL_STARTLIST);
1475 add_token_u8(&err, dev, OPAL_STARTNAME);
1476 add_token_u8(&err, dev, 2); /* Done */
Jon Derrickeed64952017-02-22 07:55:13 -07001477 add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
Scott Bauer455a7b22017-02-03 12:50:31 -07001478 add_token_u8(&err, dev, OPAL_ENDNAME);
1479 add_token_u8(&err, dev, OPAL_ENDLIST);
1480 add_token_u8(&err, dev, OPAL_ENDNAME);
1481 add_token_u8(&err, dev, OPAL_ENDLIST);
1482
1483 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001484 pr_debug("Error Building set MBR Done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001485 return err;
1486 }
1487
1488 return finalize_and_send(dev, parse_and_check_status);
1489}
1490
Jon Derrickeed64952017-02-22 07:55:13 -07001491static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001492{
Jon Derrickeed64952017-02-22 07:55:13 -07001493 u8 *mbr_en_dis = 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, 1);
Jon Derrickeed64952017-02-22 07:55:13 -07001509 add_token_u8(&err, dev, *mbr_en_dis);
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
1523static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1524 struct opal_dev *dev)
1525{
1526 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, cpin_uid, OPAL_UID_LENGTH);
1533 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1534 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, 3); /* PIN */
1541 add_token_bytestring(&err, dev, key, key_len);
1542 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 return err;
1548}
1549
Jon Derrickeed64952017-02-22 07:55:13 -07001550static int set_new_pw(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001551{
1552 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001553 struct opal_session_info *usr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001554
1555 memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1556
1557 if (usr->who != OPAL_ADMIN1) {
1558 cpin_uid[5] = 0x03;
1559 if (usr->sum)
1560 cpin_uid[7] = usr->opal_key.lr + 1;
1561 else
1562 cpin_uid[7] = usr->who;
1563 }
1564
1565 if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1566 cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001567 pr_debug("Error building set password command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001568 return -ERANGE;
1569 }
1570
1571 return finalize_and_send(dev, parse_and_check_status);
1572}
1573
Jon Derrickeed64952017-02-22 07:55:13 -07001574static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001575{
1576 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001577 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001578
1579 memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1580
1581 if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001582 pr_debug("Error building Set SID cpin\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001583 return -ERANGE;
1584 }
1585 return finalize_and_send(dev, parse_and_check_status);
1586}
1587
Jon Derrickeed64952017-02-22 07:55:13 -07001588static int add_user_to_lr(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001589{
1590 u8 lr_buffer[OPAL_UID_LENGTH];
1591 u8 user_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001592 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001593 int err = 0;
1594
1595 clear_opal_cmd(dev);
1596 set_comid(dev, dev->comid);
1597
Scott Bauer455a7b22017-02-03 12:50:31 -07001598 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1599 OPAL_UID_LENGTH);
1600
1601 if (lkul->l_state == OPAL_RW)
1602 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1603 OPAL_UID_LENGTH);
1604
1605 lr_buffer[7] = lkul->session.opal_key.lr;
1606
1607 memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1608
1609 user_uid[7] = lkul->session.who;
1610
1611 add_token_u8(&err, dev, OPAL_CALL);
1612 add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
1613 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1614 OPAL_UID_LENGTH);
1615
1616 add_token_u8(&err, dev, OPAL_STARTLIST);
1617 add_token_u8(&err, dev, OPAL_STARTNAME);
1618 add_token_u8(&err, dev, OPAL_VALUES);
1619
1620 add_token_u8(&err, dev, OPAL_STARTLIST);
1621 add_token_u8(&err, dev, OPAL_STARTNAME);
1622 add_token_u8(&err, dev, 3);
1623
1624 add_token_u8(&err, dev, OPAL_STARTLIST);
1625
1626
1627 add_token_u8(&err, dev, OPAL_STARTNAME);
1628 add_token_bytestring(&err, dev,
1629 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1630 OPAL_UID_LENGTH/2);
1631 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1632 add_token_u8(&err, dev, OPAL_ENDNAME);
1633
1634
1635 add_token_u8(&err, dev, OPAL_STARTNAME);
1636 add_token_bytestring(&err, dev,
1637 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1638 OPAL_UID_LENGTH/2);
1639 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1640 add_token_u8(&err, dev, OPAL_ENDNAME);
1641
1642
1643 add_token_u8(&err, dev, OPAL_STARTNAME);
1644 add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1645 OPAL_UID_LENGTH/2);
1646 add_token_u8(&err, dev, 1);
1647 add_token_u8(&err, dev, OPAL_ENDNAME);
1648
1649
1650 add_token_u8(&err, dev, OPAL_ENDLIST);
1651 add_token_u8(&err, dev, OPAL_ENDNAME);
1652 add_token_u8(&err, dev, OPAL_ENDLIST);
1653 add_token_u8(&err, dev, OPAL_ENDNAME);
1654 add_token_u8(&err, dev, OPAL_ENDLIST);
1655
1656 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001657 pr_debug("Error building add user to locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001658 return err;
1659 }
1660
1661 return finalize_and_send(dev, parse_and_check_status);
1662}
1663
Jon Derrickeed64952017-02-22 07:55:13 -07001664static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001665{
1666 u8 lr_buffer[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001667 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001668 u8 read_locked = 1, write_locked = 1;
1669 int err = 0;
1670
1671 clear_opal_cmd(dev);
1672 set_comid(dev, dev->comid);
1673
Scott Bauer455a7b22017-02-03 12:50:31 -07001674 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1675 lkul->session.opal_key.lr) < 0)
1676 return -ERANGE;
1677
1678 switch (lkul->l_state) {
1679 case OPAL_RO:
1680 read_locked = 0;
1681 write_locked = 1;
1682 break;
1683 case OPAL_RW:
1684 read_locked = 0;
1685 write_locked = 0;
1686 break;
1687 case OPAL_LK:
1688 /* vars are initalized to locked */
1689 break;
1690 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001691 pr_debug("Tried to set an invalid locking state... returning to uland\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001692 return OPAL_INVAL_PARAM;
1693 }
1694
1695 add_token_u8(&err, dev, OPAL_CALL);
1696 add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
1697 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1698 add_token_u8(&err, dev, OPAL_STARTLIST);
1699 add_token_u8(&err, dev, OPAL_STARTNAME);
1700 add_token_u8(&err, dev, OPAL_VALUES);
1701 add_token_u8(&err, dev, OPAL_STARTLIST);
1702
1703 add_token_u8(&err, dev, OPAL_STARTNAME);
1704 add_token_u8(&err, dev, OPAL_READLOCKED);
1705 add_token_u8(&err, dev, read_locked);
1706 add_token_u8(&err, dev, OPAL_ENDNAME);
1707
1708 add_token_u8(&err, dev, OPAL_STARTNAME);
1709 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1710 add_token_u8(&err, dev, write_locked);
1711 add_token_u8(&err, dev, OPAL_ENDNAME);
1712
1713 add_token_u8(&err, dev, OPAL_ENDLIST);
1714 add_token_u8(&err, dev, OPAL_ENDNAME);
1715 add_token_u8(&err, dev, OPAL_ENDLIST);
1716
1717 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001718 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001719 return err;
1720 }
1721 return finalize_and_send(dev, parse_and_check_status);
1722}
1723
1724
Jon Derrickeed64952017-02-22 07:55:13 -07001725static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001726{
1727 u8 lr_buffer[OPAL_UID_LENGTH];
1728 u8 read_locked = 1, write_locked = 1;
Jon Derrickeed64952017-02-22 07:55:13 -07001729 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001730 int ret;
1731
1732 clear_opal_cmd(dev);
1733 set_comid(dev, dev->comid);
1734
Scott Bauer455a7b22017-02-03 12:50:31 -07001735 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1736 lkul->session.opal_key.lr) < 0)
1737 return -ERANGE;
1738
1739 switch (lkul->l_state) {
1740 case OPAL_RO:
1741 read_locked = 0;
1742 write_locked = 1;
1743 break;
1744 case OPAL_RW:
1745 read_locked = 0;
1746 write_locked = 0;
1747 break;
1748 case OPAL_LK:
1749 /* vars are initalized to locked */
1750 break;
1751 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001752 pr_debug("Tried to set an invalid locking state.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001753 return OPAL_INVAL_PARAM;
1754 }
1755 ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1756 read_locked, write_locked);
1757
1758 if (ret < 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001759 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001760 return ret;
1761 }
1762 return finalize_and_send(dev, parse_and_check_status);
1763}
1764
Jon Derrickeed64952017-02-22 07:55:13 -07001765static int activate_lsp(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001766{
Jon Derrickeed64952017-02-22 07:55:13 -07001767 struct opal_lr_act *opal_act = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001768 u8 user_lr[OPAL_UID_LENGTH];
1769 u8 uint_3 = 0x83;
1770 int err = 0, i;
1771
1772 clear_opal_cmd(dev);
1773 set_comid(dev, dev->comid);
1774
Scott Bauer455a7b22017-02-03 12:50:31 -07001775 add_token_u8(&err, dev, OPAL_CALL);
1776 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1777 OPAL_UID_LENGTH);
1778 add_token_bytestring(&err, dev, opalmethod[OPAL_ACTIVATE],
1779 OPAL_UID_LENGTH);
1780
1781
1782 if (opal_act->sum) {
1783 err = build_locking_range(user_lr, sizeof(user_lr),
1784 opal_act->lr[0]);
1785 if (err)
1786 return err;
1787
1788 add_token_u8(&err, dev, OPAL_STARTLIST);
1789 add_token_u8(&err, dev, OPAL_STARTNAME);
1790 add_token_u8(&err, dev, uint_3);
1791 add_token_u8(&err, dev, 6);
1792 add_token_u8(&err, dev, 0);
1793 add_token_u8(&err, dev, 0);
1794
1795 add_token_u8(&err, dev, OPAL_STARTLIST);
1796 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1797 for (i = 1; i < opal_act->num_lrs; i++) {
1798 user_lr[7] = opal_act->lr[i];
1799 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1800 }
1801 add_token_u8(&err, dev, OPAL_ENDLIST);
1802 add_token_u8(&err, dev, OPAL_ENDNAME);
1803 add_token_u8(&err, dev, OPAL_ENDLIST);
1804
1805 } else {
1806 add_token_u8(&err, dev, OPAL_STARTLIST);
1807 add_token_u8(&err, dev, OPAL_ENDLIST);
1808 }
1809
1810 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001811 pr_debug("Error building Activate LockingSP command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001812 return err;
1813 }
1814
1815 return finalize_and_send(dev, parse_and_check_status);
1816}
1817
1818static int get_lsp_lifecycle_cont(struct opal_dev *dev)
1819{
1820 u8 lc_status;
1821 int error = 0;
1822
1823 error = parse_and_check_status(dev);
1824 if (error)
1825 return error;
1826
1827 lc_status = response_get_u64(&dev->parsed, 4);
1828 /* 0x08 is Manufacured Inactive */
1829 /* 0x09 is Manufactured */
1830 if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001831 pr_debug("Couldn't determine the status of the Lifecycle state\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001832 return -ENODEV;
1833 }
1834
1835 return 0;
1836}
1837
1838/* Determine if we're in the Manufactured Inactive or Active state */
Jon Derrickeed64952017-02-22 07:55:13 -07001839static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001840{
1841 int err = 0;
1842
1843 clear_opal_cmd(dev);
1844 set_comid(dev, dev->comid);
1845
1846 add_token_u8(&err, dev, OPAL_CALL);
1847 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1848 OPAL_UID_LENGTH);
1849 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1850
1851 add_token_u8(&err, dev, OPAL_STARTLIST);
1852 add_token_u8(&err, dev, OPAL_STARTLIST);
1853
1854 add_token_u8(&err, dev, OPAL_STARTNAME);
1855 add_token_u8(&err, dev, 3); /* Start Column */
1856 add_token_u8(&err, dev, 6); /* Lifecycle Column */
1857 add_token_u8(&err, dev, OPAL_ENDNAME);
1858
1859 add_token_u8(&err, dev, OPAL_STARTNAME);
1860 add_token_u8(&err, dev, 4); /* End Column */
1861 add_token_u8(&err, dev, 6); /* Lifecycle Column */
1862 add_token_u8(&err, dev, OPAL_ENDNAME);
1863
1864 add_token_u8(&err, dev, OPAL_ENDLIST);
1865 add_token_u8(&err, dev, OPAL_ENDLIST);
1866
1867 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001868 pr_debug("Error Building GET Lifecycle Status command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001869 return err;
1870 }
1871
1872 return finalize_and_send(dev, get_lsp_lifecycle_cont);
1873}
1874
1875static int get_msid_cpin_pin_cont(struct opal_dev *dev)
1876{
1877 const char *msid_pin;
1878 size_t strlen;
1879 int error = 0;
1880
1881 error = parse_and_check_status(dev);
1882 if (error)
1883 return error;
1884
1885 strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1886 if (!msid_pin) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001887 pr_debug("%s: Couldn't extract PIN from response\n", __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001888 return OPAL_INVAL_PARAM;
1889 }
1890
1891 dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1892 if (!dev->prev_data)
1893 return -ENOMEM;
1894
1895 dev->prev_d_len = strlen;
1896
1897 return 0;
1898}
1899
Jon Derrickeed64952017-02-22 07:55:13 -07001900static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001901{
1902 int err = 0;
1903
1904 clear_opal_cmd(dev);
1905 set_comid(dev, dev->comid);
1906
Scott Bauer455a7b22017-02-03 12:50:31 -07001907 add_token_u8(&err, dev, OPAL_CALL);
1908 add_token_bytestring(&err, dev, opaluid[OPAL_C_PIN_MSID],
1909 OPAL_UID_LENGTH);
1910 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1911
1912 add_token_u8(&err, dev, OPAL_STARTLIST);
1913 add_token_u8(&err, dev, OPAL_STARTLIST);
1914
1915 add_token_u8(&err, dev, OPAL_STARTNAME);
1916 add_token_u8(&err, dev, 3); /* Start Column */
1917 add_token_u8(&err, dev, 3); /* PIN */
1918 add_token_u8(&err, dev, OPAL_ENDNAME);
1919
1920 add_token_u8(&err, dev, OPAL_STARTNAME);
1921 add_token_u8(&err, dev, 4); /* End Column */
1922 add_token_u8(&err, dev, 3); /* Lifecycle Column */
1923 add_token_u8(&err, dev, OPAL_ENDNAME);
1924
1925 add_token_u8(&err, dev, OPAL_ENDLIST);
1926 add_token_u8(&err, dev, OPAL_ENDLIST);
1927
1928 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001929 pr_debug("Error building Get MSID CPIN PIN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001930 return err;
1931 }
1932
1933 return finalize_and_send(dev, get_msid_cpin_pin_cont);
1934}
1935
Jon Derrickeed64952017-02-22 07:55:13 -07001936static int end_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001937{
1938 int err = 0;
1939
1940 clear_opal_cmd(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001941 set_comid(dev, dev->comid);
1942 add_token_u8(&err, dev, OPAL_ENDOFSESSION);
Scott Bauer455a7b22017-02-03 12:50:31 -07001943
Jon Derrickeed64952017-02-22 07:55:13 -07001944 if (err < 0)
1945 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001946 return finalize_and_send(dev, end_session_cont);
1947}
1948
1949static int end_opal_session_error(struct opal_dev *dev)
1950{
Jon Derrickeed64952017-02-22 07:55:13 -07001951 const struct opal_step error_end_session[] = {
1952 { end_opal_session, },
1953 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001954 };
Jon Derrickeed64952017-02-22 07:55:13 -07001955 dev->steps = error_end_session;
Scott Bauer455a7b22017-02-03 12:50:31 -07001956 return next(dev);
1957}
1958
1959static inline void setup_opal_dev(struct opal_dev *dev,
Jon Derrickeed64952017-02-22 07:55:13 -07001960 const struct opal_step *steps)
Scott Bauer455a7b22017-02-03 12:50:31 -07001961{
Jon Derrickeed64952017-02-22 07:55:13 -07001962 dev->steps = steps;
Scott Bauer455a7b22017-02-03 12:50:31 -07001963 dev->tsn = 0;
1964 dev->hsn = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -07001965 dev->prev_data = NULL;
1966}
1967
1968static int check_opal_support(struct opal_dev *dev)
1969{
Jon Derrickeed64952017-02-22 07:55:13 -07001970 const struct opal_step steps[] = {
1971 { opal_discovery0, },
1972 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001973 };
1974 int ret;
1975
1976 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07001977 setup_opal_dev(dev, steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07001978 ret = next(dev);
1979 dev->supported = !ret;
1980 mutex_unlock(&dev->dev_lock);
1981 return ret;
1982}
1983
Scott Bauer7d6d1572017-02-22 10:15:06 -07001984static void clean_opal_dev(struct opal_dev *dev)
1985{
1986
1987 struct opal_suspend_data *suspend, *next;
1988
1989 mutex_lock(&dev->dev_lock);
1990 list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
1991 list_del(&suspend->node);
1992 kfree(suspend);
1993 }
1994 mutex_unlock(&dev->dev_lock);
1995}
1996
1997void free_opal_dev(struct opal_dev *dev)
1998{
1999 if (!dev)
2000 return;
2001 clean_opal_dev(dev);
2002 kfree(dev);
2003}
2004EXPORT_SYMBOL(free_opal_dev);
2005
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002006struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
Scott Bauer455a7b22017-02-03 12:50:31 -07002007{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002008 struct opal_dev *dev;
2009
2010 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
2011 if (!dev)
2012 return NULL;
2013
2014 INIT_LIST_HEAD(&dev->unlk_lst);
2015 mutex_init(&dev->dev_lock);
2016 dev->data = data;
2017 dev->send_recv = send_recv;
2018 if (check_opal_support(dev) != 0) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +01002019 pr_debug("Opal is not supported on this device\n");
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002020 kfree(dev);
2021 return NULL;
2022 }
2023 return dev;
Scott Bauer455a7b22017-02-03 12:50:31 -07002024}
2025EXPORT_SYMBOL(init_opal_dev);
2026
2027static int opal_secure_erase_locking_range(struct opal_dev *dev,
2028 struct opal_session_info *opal_session)
2029{
Jon Derrickeed64952017-02-22 07:55:13 -07002030 const struct opal_step erase_steps[] = {
2031 { opal_discovery0, },
2032 { start_auth_opal_session, opal_session },
2033 { get_active_key, &opal_session->opal_key.lr },
2034 { gen_key, },
2035 { end_opal_session, },
2036 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002037 };
2038 int ret;
2039
2040 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002041 setup_opal_dev(dev, erase_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002042 ret = next(dev);
2043 mutex_unlock(&dev->dev_lock);
2044 return ret;
2045}
2046
2047static int opal_erase_locking_range(struct opal_dev *dev,
2048 struct opal_session_info *opal_session)
2049{
Jon Derrickeed64952017-02-22 07:55:13 -07002050 const struct opal_step erase_steps[] = {
2051 { opal_discovery0, },
2052 { start_auth_opal_session, opal_session },
2053 { erase_locking_range, opal_session },
2054 { end_opal_session, },
2055 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002056 };
2057 int ret;
2058
2059 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002060 setup_opal_dev(dev, erase_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002061 ret = next(dev);
2062 mutex_unlock(&dev->dev_lock);
2063 return ret;
2064}
2065
2066static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
2067 struct opal_mbr_data *opal_mbr)
2068{
Jon Derrickeed64952017-02-22 07:55:13 -07002069 const struct opal_step mbr_steps[] = {
2070 { opal_discovery0, },
2071 { start_admin1LSP_opal_session, &opal_mbr->key },
2072 { set_mbr_done, &opal_mbr->enable_disable },
2073 { end_opal_session, },
2074 { start_admin1LSP_opal_session, &opal_mbr->key },
2075 { set_mbr_enable_disable, &opal_mbr->enable_disable },
2076 { end_opal_session, },
2077 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002078 };
2079 int ret;
2080
2081 if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
2082 opal_mbr->enable_disable != OPAL_MBR_DISABLE)
2083 return -EINVAL;
2084
2085 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002086 setup_opal_dev(dev, mbr_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002087 ret = next(dev);
2088 mutex_unlock(&dev->dev_lock);
2089 return ret;
2090}
2091
2092static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
2093{
2094 struct opal_suspend_data *suspend;
2095
2096 suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
2097 if (!suspend)
2098 return -ENOMEM;
2099
2100 suspend->unlk = *lk_unlk;
2101 suspend->lr = lk_unlk->session.opal_key.lr;
2102
2103 mutex_lock(&dev->dev_lock);
2104 setup_opal_dev(dev, NULL);
2105 add_suspend_info(dev, suspend);
2106 mutex_unlock(&dev->dev_lock);
2107 return 0;
2108}
2109
2110static int opal_add_user_to_lr(struct opal_dev *dev,
2111 struct opal_lock_unlock *lk_unlk)
2112{
Jon Derrickeed64952017-02-22 07:55:13 -07002113 const struct opal_step steps[] = {
2114 { opal_discovery0, },
2115 { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2116 { add_user_to_lr, lk_unlk },
2117 { end_opal_session, },
2118 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002119 };
2120 int ret;
2121
2122 if (lk_unlk->l_state != OPAL_RO &&
2123 lk_unlk->l_state != OPAL_RW) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002124 pr_debug("Locking state was not RO or RW\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07002125 return -EINVAL;
2126 }
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002127 if (lk_unlk->session.who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002128 lk_unlk->session.who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002129 pr_debug("Authority was not within the range of users: %d\n",
2130 lk_unlk->session.who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002131 return -EINVAL;
2132 }
2133 if (lk_unlk->session.sum) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002134 pr_debug("%s not supported in sum. Use setup locking range\n",
2135 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07002136 return -EINVAL;
2137 }
2138
2139 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002140 setup_opal_dev(dev, steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002141 ret = next(dev);
2142 mutex_unlock(&dev->dev_lock);
2143 return ret;
2144}
2145
2146static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal)
2147{
Jon Derrickeed64952017-02-22 07:55:13 -07002148 const struct opal_step revert_steps[] = {
2149 { opal_discovery0, },
2150 { start_SIDASP_opal_session, opal },
2151 { revert_tper, }, /* controller will terminate session */
2152 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002153 };
2154 int ret;
2155
2156 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002157 setup_opal_dev(dev, revert_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002158 ret = next(dev);
2159 mutex_unlock(&dev->dev_lock);
Scott Bauer7d6d1572017-02-22 10:15:06 -07002160
2161 /*
2162 * If we successfully reverted lets clean
2163 * any saved locking ranges.
2164 */
2165 if (!ret)
2166 clean_opal_dev(dev);
2167
Scott Bauer455a7b22017-02-03 12:50:31 -07002168 return ret;
2169}
2170
Jon Derrickeed64952017-02-22 07:55:13 -07002171static int __opal_lock_unlock(struct opal_dev *dev,
2172 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002173{
Jon Derrickeed64952017-02-22 07:55:13 -07002174 const struct opal_step unlock_steps[] = {
2175 { opal_discovery0, },
2176 { start_auth_opal_session, &lk_unlk->session },
2177 { lock_unlock_locking_range, lk_unlk },
2178 { end_opal_session, },
2179 { NULL, }
2180 };
2181 const struct opal_step unlock_sum_steps[] = {
2182 { opal_discovery0, },
2183 { start_auth_opal_session, &lk_unlk->session },
2184 { lock_unlock_locking_range_sum, lk_unlk },
2185 { end_opal_session, },
2186 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002187 };
2188
Jon Derrickeed64952017-02-22 07:55:13 -07002189 dev->steps = lk_unlk->session.sum ? unlock_sum_steps : unlock_steps;
Scott Bauer455a7b22017-02-03 12:50:31 -07002190 return next(dev);
2191}
2192
Jon Derrickeed64952017-02-22 07:55:13 -07002193static int opal_lock_unlock(struct opal_dev *dev,
2194 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002195{
Scott Bauer455a7b22017-02-03 12:50:31 -07002196 int ret;
2197
2198 if (lk_unlk->session.who < OPAL_ADMIN1 ||
2199 lk_unlk->session.who > OPAL_USER9)
2200 return -EINVAL;
2201
2202 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002203 ret = __opal_lock_unlock(dev, lk_unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002204 mutex_unlock(&dev->dev_lock);
2205 return ret;
2206}
2207
2208static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2209{
Jon Derrickeed64952017-02-22 07:55:13 -07002210 const struct opal_step owner_steps[] = {
2211 { opal_discovery0, },
2212 { start_anybodyASP_opal_session, },
2213 { get_msid_cpin_pin, },
2214 { end_opal_session, },
2215 { start_SIDASP_opal_session, opal },
2216 { set_sid_cpin_pin, opal },
2217 { end_opal_session, },
2218 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002219 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002220 int ret;
2221
2222 if (!dev)
2223 return -ENODEV;
2224
2225 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002226 setup_opal_dev(dev, owner_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002227 ret = next(dev);
2228 mutex_unlock(&dev->dev_lock);
2229 return ret;
2230}
2231
2232static int opal_activate_lsp(struct opal_dev *dev, struct opal_lr_act *opal_lr_act)
2233{
Jon Derrickeed64952017-02-22 07:55:13 -07002234 const struct opal_step active_steps[] = {
2235 { opal_discovery0, },
2236 { start_SIDASP_opal_session, &opal_lr_act->key },
2237 { get_lsp_lifecycle, },
2238 { activate_lsp, opal_lr_act },
2239 { end_opal_session, },
2240 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002241 };
2242 int ret;
2243
2244 if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2245 return -EINVAL;
2246
2247 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002248 setup_opal_dev(dev, active_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002249 ret = next(dev);
2250 mutex_unlock(&dev->dev_lock);
2251 return ret;
2252}
2253
2254static int opal_setup_locking_range(struct opal_dev *dev,
2255 struct opal_user_lr_setup *opal_lrs)
2256{
Jon Derrickeed64952017-02-22 07:55:13 -07002257 const struct opal_step lr_steps[] = {
2258 { opal_discovery0, },
2259 { start_auth_opal_session, &opal_lrs->session },
2260 { setup_locking_range, opal_lrs },
2261 { end_opal_session, },
2262 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002263 };
2264 int ret;
2265
2266 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002267 setup_opal_dev(dev, lr_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002268 ret = next(dev);
2269 mutex_unlock(&dev->dev_lock);
2270 return ret;
2271}
2272
2273static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2274{
Jon Derrickeed64952017-02-22 07:55:13 -07002275 const struct opal_step pw_steps[] = {
2276 { opal_discovery0, },
2277 { start_auth_opal_session, &opal_pw->session },
2278 { set_new_pw, &opal_pw->new_user_pw },
2279 { end_opal_session, },
2280 { NULL }
Scott Bauer455a7b22017-02-03 12:50:31 -07002281 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002282 int ret;
2283
2284 if (opal_pw->session.who < OPAL_ADMIN1 ||
2285 opal_pw->session.who > OPAL_USER9 ||
2286 opal_pw->new_user_pw.who < OPAL_ADMIN1 ||
2287 opal_pw->new_user_pw.who > OPAL_USER9)
2288 return -EINVAL;
2289
2290 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002291 setup_opal_dev(dev, pw_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002292 ret = next(dev);
2293 mutex_unlock(&dev->dev_lock);
2294 return ret;
2295}
2296
2297static int opal_activate_user(struct opal_dev *dev,
2298 struct opal_session_info *opal_session)
2299{
Jon Derrickeed64952017-02-22 07:55:13 -07002300 const struct opal_step act_steps[] = {
2301 { opal_discovery0, },
2302 { start_admin1LSP_opal_session, &opal_session->opal_key },
2303 { internal_activate_user, opal_session },
2304 { end_opal_session, },
2305 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002306 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002307 int ret;
2308
2309 /* We can't activate Admin1 it's active as manufactured */
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002310 if (opal_session->who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002311 opal_session->who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002312 pr_debug("Who was not a valid user: %d\n", opal_session->who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002313 return -EINVAL;
2314 }
2315
2316 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002317 setup_opal_dev(dev, act_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002318 ret = next(dev);
2319 mutex_unlock(&dev->dev_lock);
2320 return ret;
2321}
2322
2323bool opal_unlock_from_suspend(struct opal_dev *dev)
2324{
2325 struct opal_suspend_data *suspend;
Scott Bauer455a7b22017-02-03 12:50:31 -07002326 bool was_failure = false;
2327 int ret = 0;
2328
2329 if (!dev)
2330 return false;
2331 if (!dev->supported)
2332 return false;
2333
2334 mutex_lock(&dev->dev_lock);
2335 setup_opal_dev(dev, NULL);
Scott Bauer455a7b22017-02-03 12:50:31 -07002336
2337 list_for_each_entry(suspend, &dev->unlk_lst, node) {
Scott Bauer455a7b22017-02-03 12:50:31 -07002338 dev->tsn = 0;
2339 dev->hsn = 0;
2340
Jon Derrickeed64952017-02-22 07:55:13 -07002341 ret = __opal_lock_unlock(dev, &suspend->unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002342 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002343 pr_debug("Failed to unlock LR %hhu with sum %d\n",
2344 suspend->unlk.session.opal_key.lr,
2345 suspend->unlk.session.sum);
Scott Bauer455a7b22017-02-03 12:50:31 -07002346 was_failure = true;
2347 }
2348 }
2349 mutex_unlock(&dev->dev_lock);
2350 return was_failure;
2351}
2352EXPORT_SYMBOL(opal_unlock_from_suspend);
2353
Scott Bauere225c202017-02-14 17:29:36 -07002354int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
Scott Bauer455a7b22017-02-03 12:50:31 -07002355{
Scott Bauere225c202017-02-14 17:29:36 -07002356 void *p;
2357 int ret = -ENOTTY;
Scott Bauer455a7b22017-02-03 12:50:31 -07002358
2359 if (!capable(CAP_SYS_ADMIN))
2360 return -EACCES;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002361 if (!dev)
2362 return -ENOTSUPP;
Scott Bauer591c59d2017-04-07 13:58:50 -06002363 if (!dev->supported)
Scott Bauer455a7b22017-02-03 12:50:31 -07002364 return -ENOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -07002365
Jon Derrickeed64952017-02-22 07:55:13 -07002366 p = memdup_user(arg, _IOC_SIZE(cmd));
Scott Bauere225c202017-02-14 17:29:36 -07002367 if (IS_ERR(p))
2368 return PTR_ERR(p);
2369
Scott Bauer455a7b22017-02-03 12:50:31 -07002370 switch (cmd) {
Scott Bauere225c202017-02-14 17:29:36 -07002371 case IOC_OPAL_SAVE:
2372 ret = opal_save(dev, p);
2373 break;
2374 case IOC_OPAL_LOCK_UNLOCK:
2375 ret = opal_lock_unlock(dev, p);
2376 break;
2377 case IOC_OPAL_TAKE_OWNERSHIP:
2378 ret = opal_take_ownership(dev, p);
2379 break;
2380 case IOC_OPAL_ACTIVATE_LSP:
2381 ret = opal_activate_lsp(dev, p);
2382 break;
2383 case IOC_OPAL_SET_PW:
2384 ret = opal_set_new_pw(dev, p);
2385 break;
2386 case IOC_OPAL_ACTIVATE_USR:
2387 ret = opal_activate_user(dev, p);
2388 break;
2389 case IOC_OPAL_REVERT_TPR:
2390 ret = opal_reverttper(dev, p);
2391 break;
2392 case IOC_OPAL_LR_SETUP:
2393 ret = opal_setup_locking_range(dev, p);
2394 break;
2395 case IOC_OPAL_ADD_USR_TO_LR:
2396 ret = opal_add_user_to_lr(dev, p);
2397 break;
2398 case IOC_OPAL_ENABLE_DISABLE_MBR:
2399 ret = opal_enable_disable_shadow_mbr(dev, p);
2400 break;
2401 case IOC_OPAL_ERASE_LR:
2402 ret = opal_erase_locking_range(dev, p);
2403 break;
2404 case IOC_OPAL_SECURE_ERASE_LR:
2405 ret = opal_secure_erase_locking_range(dev, p);
2406 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002407 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06002408 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002409 }
Scott Bauere225c202017-02-14 17:29:36 -07002410
2411 kfree(p);
2412 return ret;
Scott Bauer455a7b22017-02-03 12:50:31 -07002413}
2414EXPORT_SYMBOL_GPL(sed_ioctl);