blob: 9ed51d0c6b1d171fc2eab785ef854b64f93721fe [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{
874 *store = NULL;
875 if (!resp) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600876 pr_debug("Response is NULL\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700877 return 0;
878 }
879
880 if (n > resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600881 pr_debug("Response has %d tokens. Can't access %d\n",
882 resp->num, n);
Scott Bauer455a7b22017-02-03 12:50:31 -0700883 return 0;
884 }
885
886 if (resp->toks[n].type != OPAL_DTA_TOKENID_BYTESTRING) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600887 pr_debug("Token is not a byte string!\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700888 return 0;
889 }
890
891 *store = resp->toks[n].pos + 1;
892 return resp->toks[n].len - 1;
893}
894
895static u64 response_get_u64(const struct parsed_resp *resp, int n)
896{
897 if (!resp) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600898 pr_debug("Response is NULL\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700899 return 0;
900 }
901
902 if (n > resp->num) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600903 pr_debug("Response has %d tokens. Can't access %d\n",
904 resp->num, n);
Scott Bauer455a7b22017-02-03 12:50:31 -0700905 return 0;
906 }
907
908 if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600909 pr_debug("Token is not unsigned it: %d\n",
910 resp->toks[n].type);
Scott Bauer455a7b22017-02-03 12:50:31 -0700911 return 0;
912 }
913
914 if (!(resp->toks[n].width == OPAL_WIDTH_TINY ||
915 resp->toks[n].width == OPAL_WIDTH_SHORT)) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600916 pr_debug("Atom is not short or tiny: %d\n",
917 resp->toks[n].width);
Scott Bauer455a7b22017-02-03 12:50:31 -0700918 return 0;
919 }
920
921 return resp->toks[n].stored.u;
922}
923
Jon Derrickcccb9242017-02-21 11:59:14 -0700924static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
925{
926 if (IS_ERR(token) ||
927 token->type != OPAL_DTA_TOKENID_TOKEN ||
928 token->pos[0] != match)
929 return false;
930 return true;
931}
932
Scott Bauer455a7b22017-02-03 12:50:31 -0700933static u8 response_status(const struct parsed_resp *resp)
934{
Jon Derrickcccb9242017-02-21 11:59:14 -0700935 const struct opal_resp_tok *tok;
936
937 tok = response_get_token(resp, 0);
938 if (response_token_matches(tok, OPAL_ENDOFSESSION))
Scott Bauer455a7b22017-02-03 12:50:31 -0700939 return 0;
Scott Bauer455a7b22017-02-03 12:50:31 -0700940
941 if (resp->num < 5)
942 return DTAERROR_NO_METHOD_STATUS;
943
Jon Derrickcccb9242017-02-21 11:59:14 -0700944 tok = response_get_token(resp, resp->num - 5);
945 if (!response_token_matches(tok, OPAL_STARTLIST))
946 return DTAERROR_NO_METHOD_STATUS;
947
948 tok = response_get_token(resp, resp->num - 1);
949 if (!response_token_matches(tok, OPAL_ENDLIST))
Scott Bauer455a7b22017-02-03 12:50:31 -0700950 return DTAERROR_NO_METHOD_STATUS;
951
952 return response_get_u64(resp, resp->num - 4);
953}
954
955/* Parses and checks for errors */
956static int parse_and_check_status(struct opal_dev *dev)
957{
958 int error;
959
960 print_buffer(dev->cmd, dev->pos);
961
962 error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
963 if (error) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600964 pr_debug("Couldn't parse response.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700965 return error;
966 }
967
968 return response_status(&dev->parsed);
969}
970
971static void clear_opal_cmd(struct opal_dev *dev)
972{
973 dev->pos = sizeof(struct opal_header);
974 memset(dev->cmd, 0, IO_BUFFER_LENGTH);
975}
976
977static int start_opal_session_cont(struct opal_dev *dev)
978{
979 u32 hsn, tsn;
980 int error = 0;
981
982 error = parse_and_check_status(dev);
983 if (error)
984 return error;
985
986 hsn = response_get_u64(&dev->parsed, 4);
987 tsn = response_get_u64(&dev->parsed, 5);
988
989 if (hsn == 0 && tsn == 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -0600990 pr_debug("Couldn't authenticate session\n");
Scott Bauer455a7b22017-02-03 12:50:31 -0700991 return -EPERM;
992 }
993
994 dev->hsn = hsn;
995 dev->tsn = tsn;
996 return 0;
997}
998
999static void add_suspend_info(struct opal_dev *dev,
1000 struct opal_suspend_data *sus)
1001{
1002 struct opal_suspend_data *iter;
1003
1004 list_for_each_entry(iter, &dev->unlk_lst, node) {
1005 if (iter->lr == sus->lr) {
1006 list_del(&iter->node);
1007 kfree(iter);
1008 break;
1009 }
1010 }
1011 list_add_tail(&sus->node, &dev->unlk_lst);
1012}
1013
1014static int end_session_cont(struct opal_dev *dev)
1015{
1016 dev->hsn = 0;
1017 dev->tsn = 0;
1018 return parse_and_check_status(dev);
1019}
1020
1021static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1022{
1023 int ret;
1024
1025 ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1026 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001027 pr_debug("Error finalizing command buffer: %d\n", ret);
Scott Bauer455a7b22017-02-03 12:50:31 -07001028 return ret;
1029 }
1030
1031 print_buffer(dev->cmd, dev->pos);
1032
1033 return opal_send_recv(dev, cont);
1034}
1035
Jon Derrickeed64952017-02-22 07:55:13 -07001036static int gen_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001037{
Scott Bauer455a7b22017-02-03 12:50:31 -07001038 u8 uid[OPAL_UID_LENGTH];
1039 int err = 0;
1040
1041 clear_opal_cmd(dev);
1042 set_comid(dev, dev->comid);
1043
1044 memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
Scott Bauer455a7b22017-02-03 12:50:31 -07001045 kfree(dev->prev_data);
1046 dev->prev_data = NULL;
1047
1048 add_token_u8(&err, dev, OPAL_CALL);
1049 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1050 add_token_bytestring(&err, dev, opalmethod[OPAL_GENKEY],
1051 OPAL_UID_LENGTH);
1052 add_token_u8(&err, dev, OPAL_STARTLIST);
1053 add_token_u8(&err, dev, OPAL_ENDLIST);
1054
1055 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001056 pr_debug("Error building gen key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001057 return err;
1058
1059 }
1060 return finalize_and_send(dev, parse_and_check_status);
1061}
1062
1063static int get_active_key_cont(struct opal_dev *dev)
1064{
1065 const char *activekey;
1066 size_t keylen;
1067 int error = 0;
1068
1069 error = parse_and_check_status(dev);
1070 if (error)
1071 return error;
1072 keylen = response_get_string(&dev->parsed, 4, &activekey);
1073 if (!activekey) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001074 pr_debug("%s: Couldn't extract the Activekey from the response\n",
1075 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001076 return OPAL_INVAL_PARAM;
1077 }
1078 dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1079
1080 if (!dev->prev_data)
1081 return -ENOMEM;
1082
1083 dev->prev_d_len = keylen;
1084
1085 return 0;
1086}
1087
Jon Derrickeed64952017-02-22 07:55:13 -07001088static int get_active_key(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001089{
1090 u8 uid[OPAL_UID_LENGTH];
1091 int err = 0;
Jon Derrickeed64952017-02-22 07:55:13 -07001092 u8 *lr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001093
1094 clear_opal_cmd(dev);
1095 set_comid(dev, dev->comid);
Scott Bauer455a7b22017-02-03 12:50:31 -07001096
1097 err = build_locking_range(uid, sizeof(uid), *lr);
1098 if (err)
1099 return err;
1100
1101 err = 0;
1102 add_token_u8(&err, dev, OPAL_CALL);
1103 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1104 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1105 add_token_u8(&err, dev, OPAL_STARTLIST);
1106 add_token_u8(&err, dev, OPAL_STARTLIST);
1107 add_token_u8(&err, dev, OPAL_STARTNAME);
1108 add_token_u8(&err, dev, 3); /* startCloumn */
1109 add_token_u8(&err, dev, 10); /* ActiveKey */
1110 add_token_u8(&err, dev, OPAL_ENDNAME);
1111 add_token_u8(&err, dev, OPAL_STARTNAME);
1112 add_token_u8(&err, dev, 4); /* endColumn */
1113 add_token_u8(&err, dev, 10); /* ActiveKey */
1114 add_token_u8(&err, dev, OPAL_ENDNAME);
1115 add_token_u8(&err, dev, OPAL_ENDLIST);
1116 add_token_u8(&err, dev, OPAL_ENDLIST);
1117 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001118 pr_debug("Error building get active key command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001119 return err;
1120 }
1121
1122 return finalize_and_send(dev, get_active_key_cont);
1123}
1124
1125static int generic_lr_enable_disable(struct opal_dev *dev,
1126 u8 *uid, bool rle, bool wle,
1127 bool rl, bool wl)
1128{
1129 int err = 0;
1130
1131 add_token_u8(&err, dev, OPAL_CALL);
1132 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1133 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1134
1135 add_token_u8(&err, dev, OPAL_STARTLIST);
1136 add_token_u8(&err, dev, OPAL_STARTNAME);
1137 add_token_u8(&err, dev, OPAL_VALUES);
1138 add_token_u8(&err, dev, OPAL_STARTLIST);
1139
1140 add_token_u8(&err, dev, OPAL_STARTNAME);
1141 add_token_u8(&err, dev, 5); /* ReadLockEnabled */
1142 add_token_u8(&err, dev, rle);
1143 add_token_u8(&err, dev, OPAL_ENDNAME);
1144
1145 add_token_u8(&err, dev, OPAL_STARTNAME);
1146 add_token_u8(&err, dev, 6); /* WriteLockEnabled */
1147 add_token_u8(&err, dev, wle);
1148 add_token_u8(&err, dev, OPAL_ENDNAME);
1149
1150 add_token_u8(&err, dev, OPAL_STARTNAME);
1151 add_token_u8(&err, dev, OPAL_READLOCKED);
1152 add_token_u8(&err, dev, rl);
1153 add_token_u8(&err, dev, OPAL_ENDNAME);
1154
1155 add_token_u8(&err, dev, OPAL_STARTNAME);
1156 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1157 add_token_u8(&err, dev, wl);
1158 add_token_u8(&err, dev, OPAL_ENDNAME);
1159
1160 add_token_u8(&err, dev, OPAL_ENDLIST);
1161 add_token_u8(&err, dev, OPAL_ENDNAME);
1162 add_token_u8(&err, dev, OPAL_ENDLIST);
1163 return err;
1164}
1165
1166static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1167 struct opal_user_lr_setup *setup)
1168{
1169 int err;
1170
1171 err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1172 0, 0);
1173 if (err)
Scott Bauer591c59d2017-04-07 13:58:50 -06001174 pr_debug("Failed to create enable global lr command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001175 return err;
1176}
1177
Jon Derrickeed64952017-02-22 07:55:13 -07001178static int setup_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001179{
1180 u8 uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001181 struct opal_user_lr_setup *setup = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001182 u8 lr;
1183 int err = 0;
1184
1185 clear_opal_cmd(dev);
1186 set_comid(dev, dev->comid);
1187
Scott Bauer455a7b22017-02-03 12:50:31 -07001188 lr = setup->session.opal_key.lr;
1189 err = build_locking_range(uid, sizeof(uid), lr);
1190 if (err)
1191 return err;
1192
1193 if (lr == 0)
1194 err = enable_global_lr(dev, uid, setup);
1195 else {
1196 add_token_u8(&err, dev, OPAL_CALL);
1197 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1198 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1199 OPAL_UID_LENGTH);
1200
1201 add_token_u8(&err, dev, OPAL_STARTLIST);
1202 add_token_u8(&err, dev, OPAL_STARTNAME);
1203 add_token_u8(&err, dev, OPAL_VALUES);
1204 add_token_u8(&err, dev, OPAL_STARTLIST);
1205
1206 add_token_u8(&err, dev, OPAL_STARTNAME);
1207 add_token_u8(&err, dev, 3); /* Ranges Start */
1208 add_token_u64(&err, dev, setup->range_start);
1209 add_token_u8(&err, dev, OPAL_ENDNAME);
1210
1211 add_token_u8(&err, dev, OPAL_STARTNAME);
1212 add_token_u8(&err, dev, 4); /* Ranges length */
1213 add_token_u64(&err, dev, setup->range_length);
1214 add_token_u8(&err, dev, OPAL_ENDNAME);
1215
1216 add_token_u8(&err, dev, OPAL_STARTNAME);
1217 add_token_u8(&err, dev, 5); /*ReadLockEnabled */
1218 add_token_u64(&err, dev, !!setup->RLE);
1219 add_token_u8(&err, dev, OPAL_ENDNAME);
1220
1221 add_token_u8(&err, dev, OPAL_STARTNAME);
1222 add_token_u8(&err, dev, 6); /*WriteLockEnabled*/
1223 add_token_u64(&err, dev, !!setup->WLE);
1224 add_token_u8(&err, dev, OPAL_ENDNAME);
1225
1226 add_token_u8(&err, dev, OPAL_ENDLIST);
1227 add_token_u8(&err, dev, OPAL_ENDNAME);
1228 add_token_u8(&err, dev, OPAL_ENDLIST);
1229
1230 }
1231 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001232 pr_debug("Error building Setup Locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001233 return err;
1234
1235 }
1236
1237 return finalize_and_send(dev, parse_and_check_status);
1238}
1239
1240static int start_generic_opal_session(struct opal_dev *dev,
1241 enum opal_uid auth,
1242 enum opal_uid sp_type,
1243 const char *key,
1244 u8 key_len)
1245{
1246 u32 hsn;
1247 int err = 0;
1248
Scott Bauer591c59d2017-04-07 13:58:50 -06001249 if (key == NULL && auth != OPAL_ANYBODY_UID)
Scott Bauer455a7b22017-02-03 12:50:31 -07001250 return OPAL_INVAL_PARAM;
Scott Bauer455a7b22017-02-03 12:50:31 -07001251
1252 clear_opal_cmd(dev);
1253
1254 set_comid(dev, dev->comid);
1255 hsn = GENERIC_HOST_SESSION_NUM;
1256
1257 add_token_u8(&err, dev, OPAL_CALL);
1258 add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
1259 OPAL_UID_LENGTH);
1260 add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
1261 OPAL_UID_LENGTH);
1262 add_token_u8(&err, dev, OPAL_STARTLIST);
1263 add_token_u64(&err, dev, hsn);
1264 add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1265 add_token_u8(&err, dev, 1);
1266
1267 switch (auth) {
1268 case OPAL_ANYBODY_UID:
1269 add_token_u8(&err, dev, OPAL_ENDLIST);
1270 break;
1271 case OPAL_ADMIN1_UID:
1272 case OPAL_SID_UID:
1273 add_token_u8(&err, dev, OPAL_STARTNAME);
1274 add_token_u8(&err, dev, 0); /* HostChallenge */
1275 add_token_bytestring(&err, dev, key, key_len);
1276 add_token_u8(&err, dev, OPAL_ENDNAME);
1277 add_token_u8(&err, dev, OPAL_STARTNAME);
1278 add_token_u8(&err, dev, 3); /* HostSignAuth */
1279 add_token_bytestring(&err, dev, opaluid[auth],
1280 OPAL_UID_LENGTH);
1281 add_token_u8(&err, dev, OPAL_ENDNAME);
1282 add_token_u8(&err, dev, OPAL_ENDLIST);
1283 break;
1284 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001285 pr_debug("Cannot start Admin SP session with auth %d\n", auth);
Scott Bauer455a7b22017-02-03 12:50:31 -07001286 return OPAL_INVAL_PARAM;
1287 }
1288
1289 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001290 pr_debug("Error building start adminsp session command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001291 return err;
1292 }
1293
1294 return finalize_and_send(dev, start_opal_session_cont);
1295}
1296
Jon Derrickeed64952017-02-22 07:55:13 -07001297static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001298{
1299 return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1300 OPAL_ADMINSP_UID, NULL, 0);
1301}
1302
Jon Derrickeed64952017-02-22 07:55:13 -07001303static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001304{
1305 int ret;
1306 const u8 *key = dev->prev_data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001307
1308 if (!key) {
Jon Derrickeed64952017-02-22 07:55:13 -07001309 const struct opal_key *okey = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001310 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1311 OPAL_ADMINSP_UID,
1312 okey->key,
1313 okey->key_len);
1314 } else {
1315 ret = start_generic_opal_session(dev, OPAL_SID_UID,
1316 OPAL_ADMINSP_UID,
1317 key, dev->prev_d_len);
1318 kfree(key);
1319 dev->prev_data = NULL;
1320 }
1321 return ret;
1322}
1323
Jon Derrickeed64952017-02-22 07:55:13 -07001324static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001325{
Jon Derrickeed64952017-02-22 07:55:13 -07001326 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001327 return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1328 OPAL_LOCKINGSP_UID,
1329 key->key, key->key_len);
1330}
1331
Jon Derrickeed64952017-02-22 07:55:13 -07001332static int start_auth_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001333{
Jon Derrickeed64952017-02-22 07:55:13 -07001334 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001335 u8 lk_ul_user[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001336 size_t keylen = session->opal_key.key_len;
Scott Bauer455a7b22017-02-03 12:50:31 -07001337 int err = 0;
1338
Scott Bauer455a7b22017-02-03 12:50:31 -07001339 u8 *key = session->opal_key.key;
1340 u32 hsn = GENERIC_HOST_SESSION_NUM;
1341
1342 clear_opal_cmd(dev);
1343 set_comid(dev, dev->comid);
1344
1345 if (session->sum) {
1346 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1347 session->opal_key.lr);
1348 if (err)
1349 return err;
1350
1351 } else if (session->who != OPAL_ADMIN1 && !session->sum) {
1352 err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1353 session->who - 1);
1354 if (err)
1355 return err;
1356 } else
1357 memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1358
1359 add_token_u8(&err, dev, OPAL_CALL);
1360 add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
1361 OPAL_UID_LENGTH);
1362 add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
1363 OPAL_UID_LENGTH);
1364
1365 add_token_u8(&err, dev, OPAL_STARTLIST);
1366 add_token_u64(&err, dev, hsn);
1367 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1368 OPAL_UID_LENGTH);
1369 add_token_u8(&err, dev, 1);
1370 add_token_u8(&err, dev, OPAL_STARTNAME);
1371 add_token_u8(&err, dev, 0);
1372 add_token_bytestring(&err, dev, key, keylen);
1373 add_token_u8(&err, dev, OPAL_ENDNAME);
1374 add_token_u8(&err, dev, OPAL_STARTNAME);
1375 add_token_u8(&err, dev, 3);
1376 add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1377 add_token_u8(&err, dev, OPAL_ENDNAME);
1378 add_token_u8(&err, dev, OPAL_ENDLIST);
1379
1380 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001381 pr_debug("Error building STARTSESSION command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001382 return err;
1383 }
1384
1385 return finalize_and_send(dev, start_opal_session_cont);
1386}
1387
Jon Derrickeed64952017-02-22 07:55:13 -07001388static int revert_tper(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001389{
1390 int err = 0;
1391
1392 clear_opal_cmd(dev);
1393 set_comid(dev, dev->comid);
1394
1395 add_token_u8(&err, dev, OPAL_CALL);
1396 add_token_bytestring(&err, dev, opaluid[OPAL_ADMINSP_UID],
1397 OPAL_UID_LENGTH);
1398 add_token_bytestring(&err, dev, opalmethod[OPAL_REVERT],
1399 OPAL_UID_LENGTH);
1400 add_token_u8(&err, dev, OPAL_STARTLIST);
1401 add_token_u8(&err, dev, OPAL_ENDLIST);
1402 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001403 pr_debug("Error building REVERT TPER command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001404 return err;
1405 }
1406
1407 return finalize_and_send(dev, parse_and_check_status);
1408}
1409
Jon Derrickeed64952017-02-22 07:55:13 -07001410static int internal_activate_user(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001411{
Jon Derrickeed64952017-02-22 07:55:13 -07001412 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001413 u8 uid[OPAL_UID_LENGTH];
1414 int err = 0;
1415
1416 clear_opal_cmd(dev);
1417 set_comid(dev, dev->comid);
1418
1419 memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1420 uid[7] = session->who;
1421
1422 add_token_u8(&err, dev, OPAL_CALL);
1423 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1424 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1425 add_token_u8(&err, dev, OPAL_STARTLIST);
1426 add_token_u8(&err, dev, OPAL_STARTNAME);
1427 add_token_u8(&err, dev, OPAL_VALUES);
1428 add_token_u8(&err, dev, OPAL_STARTLIST);
1429 add_token_u8(&err, dev, OPAL_STARTNAME);
1430 add_token_u8(&err, dev, 5); /* Enabled */
1431 add_token_u8(&err, dev, OPAL_TRUE);
1432 add_token_u8(&err, dev, OPAL_ENDNAME);
1433 add_token_u8(&err, dev, OPAL_ENDLIST);
1434 add_token_u8(&err, dev, OPAL_ENDNAME);
1435 add_token_u8(&err, dev, OPAL_ENDLIST);
1436
1437 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001438 pr_debug("Error building Activate UserN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001439 return err;
1440 }
1441
1442 return finalize_and_send(dev, parse_and_check_status);
1443}
1444
Jon Derrickeed64952017-02-22 07:55:13 -07001445static int erase_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001446{
Jon Derrickeed64952017-02-22 07:55:13 -07001447 struct opal_session_info *session = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001448 u8 uid[OPAL_UID_LENGTH];
1449 int err = 0;
1450
1451 clear_opal_cmd(dev);
1452 set_comid(dev, dev->comid);
Scott Bauer455a7b22017-02-03 12:50:31 -07001453
1454 if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1455 return -ERANGE;
1456
1457 add_token_u8(&err, dev, OPAL_CALL);
1458 add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1459 add_token_bytestring(&err, dev, opalmethod[OPAL_ERASE],
1460 OPAL_UID_LENGTH);
1461 add_token_u8(&err, dev, OPAL_STARTLIST);
1462 add_token_u8(&err, dev, OPAL_ENDLIST);
1463
1464 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001465 pr_debug("Error building Erase Locking Range Command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001466 return err;
1467 }
1468 return finalize_and_send(dev, parse_and_check_status);
1469}
1470
Jon Derrickeed64952017-02-22 07:55:13 -07001471static int set_mbr_done(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001472{
Jon Derrickeed64952017-02-22 07:55:13 -07001473 u8 *mbr_done_tf = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001474 int err = 0;
1475
1476 clear_opal_cmd(dev);
1477 set_comid(dev, dev->comid);
1478
1479 add_token_u8(&err, dev, OPAL_CALL);
1480 add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL],
1481 OPAL_UID_LENGTH);
1482 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1483 add_token_u8(&err, dev, OPAL_STARTLIST);
1484 add_token_u8(&err, dev, OPAL_STARTNAME);
1485 add_token_u8(&err, dev, OPAL_VALUES);
1486 add_token_u8(&err, dev, OPAL_STARTLIST);
1487 add_token_u8(&err, dev, OPAL_STARTNAME);
1488 add_token_u8(&err, dev, 2); /* Done */
Jon Derrickeed64952017-02-22 07:55:13 -07001489 add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
Scott Bauer455a7b22017-02-03 12:50:31 -07001490 add_token_u8(&err, dev, OPAL_ENDNAME);
1491 add_token_u8(&err, dev, OPAL_ENDLIST);
1492 add_token_u8(&err, dev, OPAL_ENDNAME);
1493 add_token_u8(&err, dev, OPAL_ENDLIST);
1494
1495 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001496 pr_debug("Error Building set MBR Done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001497 return err;
1498 }
1499
1500 return finalize_and_send(dev, parse_and_check_status);
1501}
1502
Jon Derrickeed64952017-02-22 07:55:13 -07001503static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001504{
Jon Derrickeed64952017-02-22 07:55:13 -07001505 u8 *mbr_en_dis = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001506 int err = 0;
1507
1508 clear_opal_cmd(dev);
1509 set_comid(dev, dev->comid);
1510
1511 add_token_u8(&err, dev, OPAL_CALL);
1512 add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL],
1513 OPAL_UID_LENGTH);
1514 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1515 add_token_u8(&err, dev, OPAL_STARTLIST);
1516 add_token_u8(&err, dev, OPAL_STARTNAME);
1517 add_token_u8(&err, dev, OPAL_VALUES);
1518 add_token_u8(&err, dev, OPAL_STARTLIST);
1519 add_token_u8(&err, dev, OPAL_STARTNAME);
1520 add_token_u8(&err, dev, 1);
Jon Derrickeed64952017-02-22 07:55:13 -07001521 add_token_u8(&err, dev, *mbr_en_dis);
Scott Bauer455a7b22017-02-03 12:50:31 -07001522 add_token_u8(&err, dev, OPAL_ENDNAME);
1523 add_token_u8(&err, dev, OPAL_ENDLIST);
1524 add_token_u8(&err, dev, OPAL_ENDNAME);
1525 add_token_u8(&err, dev, OPAL_ENDLIST);
1526
1527 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001528 pr_debug("Error Building set MBR done command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001529 return err;
1530 }
1531
1532 return finalize_and_send(dev, parse_and_check_status);
1533}
1534
1535static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1536 struct opal_dev *dev)
1537{
1538 int err = 0;
1539
1540 clear_opal_cmd(dev);
1541 set_comid(dev, dev->comid);
1542
1543 add_token_u8(&err, dev, OPAL_CALL);
1544 add_token_bytestring(&err, dev, cpin_uid, OPAL_UID_LENGTH);
1545 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1546 OPAL_UID_LENGTH);
1547 add_token_u8(&err, dev, OPAL_STARTLIST);
1548 add_token_u8(&err, dev, OPAL_STARTNAME);
1549 add_token_u8(&err, dev, OPAL_VALUES);
1550 add_token_u8(&err, dev, OPAL_STARTLIST);
1551 add_token_u8(&err, dev, OPAL_STARTNAME);
1552 add_token_u8(&err, dev, 3); /* PIN */
1553 add_token_bytestring(&err, dev, key, key_len);
1554 add_token_u8(&err, dev, OPAL_ENDNAME);
1555 add_token_u8(&err, dev, OPAL_ENDLIST);
1556 add_token_u8(&err, dev, OPAL_ENDNAME);
1557 add_token_u8(&err, dev, OPAL_ENDLIST);
1558
1559 return err;
1560}
1561
Jon Derrickeed64952017-02-22 07:55:13 -07001562static int set_new_pw(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001563{
1564 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001565 struct opal_session_info *usr = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001566
1567 memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
1568
1569 if (usr->who != OPAL_ADMIN1) {
1570 cpin_uid[5] = 0x03;
1571 if (usr->sum)
1572 cpin_uid[7] = usr->opal_key.lr + 1;
1573 else
1574 cpin_uid[7] = usr->who;
1575 }
1576
1577 if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
1578 cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001579 pr_debug("Error building set password command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001580 return -ERANGE;
1581 }
1582
1583 return finalize_and_send(dev, parse_and_check_status);
1584}
1585
Jon Derrickeed64952017-02-22 07:55:13 -07001586static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001587{
1588 u8 cpin_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001589 struct opal_key *key = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001590
1591 memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
1592
1593 if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001594 pr_debug("Error building Set SID cpin\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001595 return -ERANGE;
1596 }
1597 return finalize_and_send(dev, parse_and_check_status);
1598}
1599
Jon Derrickeed64952017-02-22 07:55:13 -07001600static int add_user_to_lr(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001601{
1602 u8 lr_buffer[OPAL_UID_LENGTH];
1603 u8 user_uid[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001604 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001605 int err = 0;
1606
1607 clear_opal_cmd(dev);
1608 set_comid(dev, dev->comid);
1609
Scott Bauer455a7b22017-02-03 12:50:31 -07001610 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
1611 OPAL_UID_LENGTH);
1612
1613 if (lkul->l_state == OPAL_RW)
1614 memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
1615 OPAL_UID_LENGTH);
1616
1617 lr_buffer[7] = lkul->session.opal_key.lr;
1618
1619 memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1620
1621 user_uid[7] = lkul->session.who;
1622
1623 add_token_u8(&err, dev, OPAL_CALL);
1624 add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
1625 add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
1626 OPAL_UID_LENGTH);
1627
1628 add_token_u8(&err, dev, OPAL_STARTLIST);
1629 add_token_u8(&err, dev, OPAL_STARTNAME);
1630 add_token_u8(&err, dev, OPAL_VALUES);
1631
1632 add_token_u8(&err, dev, OPAL_STARTLIST);
1633 add_token_u8(&err, dev, OPAL_STARTNAME);
1634 add_token_u8(&err, dev, 3);
1635
1636 add_token_u8(&err, dev, OPAL_STARTLIST);
1637
1638
1639 add_token_u8(&err, dev, OPAL_STARTNAME);
1640 add_token_bytestring(&err, dev,
1641 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1642 OPAL_UID_LENGTH/2);
1643 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1644 add_token_u8(&err, dev, OPAL_ENDNAME);
1645
1646
1647 add_token_u8(&err, dev, OPAL_STARTNAME);
1648 add_token_bytestring(&err, dev,
1649 opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
1650 OPAL_UID_LENGTH/2);
1651 add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
1652 add_token_u8(&err, dev, OPAL_ENDNAME);
1653
1654
1655 add_token_u8(&err, dev, OPAL_STARTNAME);
1656 add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
1657 OPAL_UID_LENGTH/2);
1658 add_token_u8(&err, dev, 1);
1659 add_token_u8(&err, dev, OPAL_ENDNAME);
1660
1661
1662 add_token_u8(&err, dev, OPAL_ENDLIST);
1663 add_token_u8(&err, dev, OPAL_ENDNAME);
1664 add_token_u8(&err, dev, OPAL_ENDLIST);
1665 add_token_u8(&err, dev, OPAL_ENDNAME);
1666 add_token_u8(&err, dev, OPAL_ENDLIST);
1667
1668 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001669 pr_debug("Error building add user to locking range command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001670 return err;
1671 }
1672
1673 return finalize_and_send(dev, parse_and_check_status);
1674}
1675
Jon Derrickeed64952017-02-22 07:55:13 -07001676static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001677{
1678 u8 lr_buffer[OPAL_UID_LENGTH];
Jon Derrickeed64952017-02-22 07:55:13 -07001679 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001680 u8 read_locked = 1, write_locked = 1;
1681 int err = 0;
1682
1683 clear_opal_cmd(dev);
1684 set_comid(dev, dev->comid);
1685
Scott Bauer455a7b22017-02-03 12:50:31 -07001686 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1687 lkul->session.opal_key.lr) < 0)
1688 return -ERANGE;
1689
1690 switch (lkul->l_state) {
1691 case OPAL_RO:
1692 read_locked = 0;
1693 write_locked = 1;
1694 break;
1695 case OPAL_RW:
1696 read_locked = 0;
1697 write_locked = 0;
1698 break;
1699 case OPAL_LK:
1700 /* vars are initalized to locked */
1701 break;
1702 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001703 pr_debug("Tried to set an invalid locking state... returning to uland\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001704 return OPAL_INVAL_PARAM;
1705 }
1706
1707 add_token_u8(&err, dev, OPAL_CALL);
1708 add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
1709 add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
1710 add_token_u8(&err, dev, OPAL_STARTLIST);
1711 add_token_u8(&err, dev, OPAL_STARTNAME);
1712 add_token_u8(&err, dev, OPAL_VALUES);
1713 add_token_u8(&err, dev, OPAL_STARTLIST);
1714
1715 add_token_u8(&err, dev, OPAL_STARTNAME);
1716 add_token_u8(&err, dev, OPAL_READLOCKED);
1717 add_token_u8(&err, dev, read_locked);
1718 add_token_u8(&err, dev, OPAL_ENDNAME);
1719
1720 add_token_u8(&err, dev, OPAL_STARTNAME);
1721 add_token_u8(&err, dev, OPAL_WRITELOCKED);
1722 add_token_u8(&err, dev, write_locked);
1723 add_token_u8(&err, dev, OPAL_ENDNAME);
1724
1725 add_token_u8(&err, dev, OPAL_ENDLIST);
1726 add_token_u8(&err, dev, OPAL_ENDNAME);
1727 add_token_u8(&err, dev, OPAL_ENDLIST);
1728
1729 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001730 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001731 return err;
1732 }
1733 return finalize_and_send(dev, parse_and_check_status);
1734}
1735
1736
Jon Derrickeed64952017-02-22 07:55:13 -07001737static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001738{
1739 u8 lr_buffer[OPAL_UID_LENGTH];
1740 u8 read_locked = 1, write_locked = 1;
Jon Derrickeed64952017-02-22 07:55:13 -07001741 struct opal_lock_unlock *lkul = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001742 int ret;
1743
1744 clear_opal_cmd(dev);
1745 set_comid(dev, dev->comid);
1746
Scott Bauer455a7b22017-02-03 12:50:31 -07001747 if (build_locking_range(lr_buffer, sizeof(lr_buffer),
1748 lkul->session.opal_key.lr) < 0)
1749 return -ERANGE;
1750
1751 switch (lkul->l_state) {
1752 case OPAL_RO:
1753 read_locked = 0;
1754 write_locked = 1;
1755 break;
1756 case OPAL_RW:
1757 read_locked = 0;
1758 write_locked = 0;
1759 break;
1760 case OPAL_LK:
1761 /* vars are initalized to locked */
1762 break;
1763 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06001764 pr_debug("Tried to set an invalid locking state.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001765 return OPAL_INVAL_PARAM;
1766 }
1767 ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
1768 read_locked, write_locked);
1769
1770 if (ret < 0) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001771 pr_debug("Error building SET command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001772 return ret;
1773 }
1774 return finalize_and_send(dev, parse_and_check_status);
1775}
1776
Jon Derrickeed64952017-02-22 07:55:13 -07001777static int activate_lsp(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001778{
Jon Derrickeed64952017-02-22 07:55:13 -07001779 struct opal_lr_act *opal_act = data;
Scott Bauer455a7b22017-02-03 12:50:31 -07001780 u8 user_lr[OPAL_UID_LENGTH];
1781 u8 uint_3 = 0x83;
1782 int err = 0, i;
1783
1784 clear_opal_cmd(dev);
1785 set_comid(dev, dev->comid);
1786
Scott Bauer455a7b22017-02-03 12:50:31 -07001787 add_token_u8(&err, dev, OPAL_CALL);
1788 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1789 OPAL_UID_LENGTH);
1790 add_token_bytestring(&err, dev, opalmethod[OPAL_ACTIVATE],
1791 OPAL_UID_LENGTH);
1792
1793
1794 if (opal_act->sum) {
1795 err = build_locking_range(user_lr, sizeof(user_lr),
1796 opal_act->lr[0]);
1797 if (err)
1798 return err;
1799
1800 add_token_u8(&err, dev, OPAL_STARTLIST);
1801 add_token_u8(&err, dev, OPAL_STARTNAME);
1802 add_token_u8(&err, dev, uint_3);
1803 add_token_u8(&err, dev, 6);
1804 add_token_u8(&err, dev, 0);
1805 add_token_u8(&err, dev, 0);
1806
1807 add_token_u8(&err, dev, OPAL_STARTLIST);
1808 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1809 for (i = 1; i < opal_act->num_lrs; i++) {
1810 user_lr[7] = opal_act->lr[i];
1811 add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
1812 }
1813 add_token_u8(&err, dev, OPAL_ENDLIST);
1814 add_token_u8(&err, dev, OPAL_ENDNAME);
1815 add_token_u8(&err, dev, OPAL_ENDLIST);
1816
1817 } else {
1818 add_token_u8(&err, dev, OPAL_STARTLIST);
1819 add_token_u8(&err, dev, OPAL_ENDLIST);
1820 }
1821
1822 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001823 pr_debug("Error building Activate LockingSP command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001824 return err;
1825 }
1826
1827 return finalize_and_send(dev, parse_and_check_status);
1828}
1829
1830static int get_lsp_lifecycle_cont(struct opal_dev *dev)
1831{
1832 u8 lc_status;
1833 int error = 0;
1834
1835 error = parse_and_check_status(dev);
1836 if (error)
1837 return error;
1838
1839 lc_status = response_get_u64(&dev->parsed, 4);
1840 /* 0x08 is Manufacured Inactive */
1841 /* 0x09 is Manufactured */
1842 if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001843 pr_debug("Couldn't determine the status of the Lifecycle state\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001844 return -ENODEV;
1845 }
1846
1847 return 0;
1848}
1849
1850/* Determine if we're in the Manufactured Inactive or Active state */
Jon Derrickeed64952017-02-22 07:55:13 -07001851static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001852{
1853 int err = 0;
1854
1855 clear_opal_cmd(dev);
1856 set_comid(dev, dev->comid);
1857
1858 add_token_u8(&err, dev, OPAL_CALL);
1859 add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1860 OPAL_UID_LENGTH);
1861 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1862
1863 add_token_u8(&err, dev, OPAL_STARTLIST);
1864 add_token_u8(&err, dev, OPAL_STARTLIST);
1865
1866 add_token_u8(&err, dev, OPAL_STARTNAME);
1867 add_token_u8(&err, dev, 3); /* Start Column */
1868 add_token_u8(&err, dev, 6); /* Lifecycle Column */
1869 add_token_u8(&err, dev, OPAL_ENDNAME);
1870
1871 add_token_u8(&err, dev, OPAL_STARTNAME);
1872 add_token_u8(&err, dev, 4); /* End Column */
1873 add_token_u8(&err, dev, 6); /* Lifecycle Column */
1874 add_token_u8(&err, dev, OPAL_ENDNAME);
1875
1876 add_token_u8(&err, dev, OPAL_ENDLIST);
1877 add_token_u8(&err, dev, OPAL_ENDLIST);
1878
1879 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001880 pr_debug("Error Building GET Lifecycle Status command\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001881 return err;
1882 }
1883
1884 return finalize_and_send(dev, get_lsp_lifecycle_cont);
1885}
1886
1887static int get_msid_cpin_pin_cont(struct opal_dev *dev)
1888{
1889 const char *msid_pin;
1890 size_t strlen;
1891 int error = 0;
1892
1893 error = parse_and_check_status(dev);
1894 if (error)
1895 return error;
1896
1897 strlen = response_get_string(&dev->parsed, 4, &msid_pin);
1898 if (!msid_pin) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001899 pr_debug("%s: Couldn't extract PIN from response\n", __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07001900 return OPAL_INVAL_PARAM;
1901 }
1902
1903 dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
1904 if (!dev->prev_data)
1905 return -ENOMEM;
1906
1907 dev->prev_d_len = strlen;
1908
1909 return 0;
1910}
1911
Jon Derrickeed64952017-02-22 07:55:13 -07001912static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001913{
1914 int err = 0;
1915
1916 clear_opal_cmd(dev);
1917 set_comid(dev, dev->comid);
1918
Scott Bauer455a7b22017-02-03 12:50:31 -07001919 add_token_u8(&err, dev, OPAL_CALL);
1920 add_token_bytestring(&err, dev, opaluid[OPAL_C_PIN_MSID],
1921 OPAL_UID_LENGTH);
1922 add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
1923
1924 add_token_u8(&err, dev, OPAL_STARTLIST);
1925 add_token_u8(&err, dev, OPAL_STARTLIST);
1926
1927 add_token_u8(&err, dev, OPAL_STARTNAME);
1928 add_token_u8(&err, dev, 3); /* Start Column */
1929 add_token_u8(&err, dev, 3); /* PIN */
1930 add_token_u8(&err, dev, OPAL_ENDNAME);
1931
1932 add_token_u8(&err, dev, OPAL_STARTNAME);
1933 add_token_u8(&err, dev, 4); /* End Column */
1934 add_token_u8(&err, dev, 3); /* Lifecycle Column */
1935 add_token_u8(&err, dev, OPAL_ENDNAME);
1936
1937 add_token_u8(&err, dev, OPAL_ENDLIST);
1938 add_token_u8(&err, dev, OPAL_ENDLIST);
1939
1940 if (err) {
Scott Bauer591c59d2017-04-07 13:58:50 -06001941 pr_debug("Error building Get MSID CPIN PIN command.\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07001942 return err;
1943 }
1944
1945 return finalize_and_send(dev, get_msid_cpin_pin_cont);
1946}
1947
Jon Derrickeed64952017-02-22 07:55:13 -07001948static int end_opal_session(struct opal_dev *dev, void *data)
Scott Bauer455a7b22017-02-03 12:50:31 -07001949{
1950 int err = 0;
1951
1952 clear_opal_cmd(dev);
Scott Bauer455a7b22017-02-03 12:50:31 -07001953 set_comid(dev, dev->comid);
1954 add_token_u8(&err, dev, OPAL_ENDOFSESSION);
Scott Bauer455a7b22017-02-03 12:50:31 -07001955
Jon Derrickeed64952017-02-22 07:55:13 -07001956 if (err < 0)
1957 return err;
Scott Bauer455a7b22017-02-03 12:50:31 -07001958 return finalize_and_send(dev, end_session_cont);
1959}
1960
1961static int end_opal_session_error(struct opal_dev *dev)
1962{
Jon Derrickeed64952017-02-22 07:55:13 -07001963 const struct opal_step error_end_session[] = {
1964 { end_opal_session, },
1965 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001966 };
Jon Derrickeed64952017-02-22 07:55:13 -07001967 dev->steps = error_end_session;
Scott Bauer455a7b22017-02-03 12:50:31 -07001968 return next(dev);
1969}
1970
1971static inline void setup_opal_dev(struct opal_dev *dev,
Jon Derrickeed64952017-02-22 07:55:13 -07001972 const struct opal_step *steps)
Scott Bauer455a7b22017-02-03 12:50:31 -07001973{
Jon Derrickeed64952017-02-22 07:55:13 -07001974 dev->steps = steps;
Scott Bauer455a7b22017-02-03 12:50:31 -07001975 dev->tsn = 0;
1976 dev->hsn = 0;
Scott Bauer455a7b22017-02-03 12:50:31 -07001977 dev->prev_data = NULL;
1978}
1979
1980static int check_opal_support(struct opal_dev *dev)
1981{
Jon Derrickeed64952017-02-22 07:55:13 -07001982 const struct opal_step steps[] = {
1983 { opal_discovery0, },
1984 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07001985 };
1986 int ret;
1987
1988 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07001989 setup_opal_dev(dev, steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07001990 ret = next(dev);
1991 dev->supported = !ret;
1992 mutex_unlock(&dev->dev_lock);
1993 return ret;
1994}
1995
Scott Bauer7d6d1572017-02-22 10:15:06 -07001996static void clean_opal_dev(struct opal_dev *dev)
1997{
1998
1999 struct opal_suspend_data *suspend, *next;
2000
2001 mutex_lock(&dev->dev_lock);
2002 list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
2003 list_del(&suspend->node);
2004 kfree(suspend);
2005 }
2006 mutex_unlock(&dev->dev_lock);
2007}
2008
2009void free_opal_dev(struct opal_dev *dev)
2010{
2011 if (!dev)
2012 return;
2013 clean_opal_dev(dev);
2014 kfree(dev);
2015}
2016EXPORT_SYMBOL(free_opal_dev);
2017
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002018struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
Scott Bauer455a7b22017-02-03 12:50:31 -07002019{
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002020 struct opal_dev *dev;
2021
2022 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
2023 if (!dev)
2024 return NULL;
2025
2026 INIT_LIST_HEAD(&dev->unlk_lst);
2027 mutex_init(&dev->dev_lock);
2028 dev->data = data;
2029 dev->send_recv = send_recv;
2030 if (check_opal_support(dev) != 0) {
Christoph Hellwigf5b37b72017-02-17 13:59:38 +01002031 pr_debug("Opal is not supported on this device\n");
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002032 kfree(dev);
2033 return NULL;
2034 }
2035 return dev;
Scott Bauer455a7b22017-02-03 12:50:31 -07002036}
2037EXPORT_SYMBOL(init_opal_dev);
2038
2039static int opal_secure_erase_locking_range(struct opal_dev *dev,
2040 struct opal_session_info *opal_session)
2041{
Jon Derrickeed64952017-02-22 07:55:13 -07002042 const struct opal_step erase_steps[] = {
2043 { opal_discovery0, },
2044 { start_auth_opal_session, opal_session },
2045 { get_active_key, &opal_session->opal_key.lr },
2046 { gen_key, },
2047 { end_opal_session, },
2048 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002049 };
2050 int ret;
2051
2052 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002053 setup_opal_dev(dev, erase_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002054 ret = next(dev);
2055 mutex_unlock(&dev->dev_lock);
2056 return ret;
2057}
2058
2059static int opal_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 { erase_locking_range, opal_session },
2066 { end_opal_session, },
2067 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002068 };
2069 int ret;
2070
2071 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002072 setup_opal_dev(dev, erase_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002073 ret = next(dev);
2074 mutex_unlock(&dev->dev_lock);
2075 return ret;
2076}
2077
2078static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
2079 struct opal_mbr_data *opal_mbr)
2080{
Jon Derrickeed64952017-02-22 07:55:13 -07002081 const struct opal_step mbr_steps[] = {
2082 { opal_discovery0, },
2083 { start_admin1LSP_opal_session, &opal_mbr->key },
2084 { set_mbr_done, &opal_mbr->enable_disable },
2085 { end_opal_session, },
2086 { start_admin1LSP_opal_session, &opal_mbr->key },
2087 { set_mbr_enable_disable, &opal_mbr->enable_disable },
2088 { end_opal_session, },
2089 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002090 };
2091 int ret;
2092
2093 if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
2094 opal_mbr->enable_disable != OPAL_MBR_DISABLE)
2095 return -EINVAL;
2096
2097 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002098 setup_opal_dev(dev, mbr_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002099 ret = next(dev);
2100 mutex_unlock(&dev->dev_lock);
2101 return ret;
2102}
2103
2104static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
2105{
2106 struct opal_suspend_data *suspend;
2107
2108 suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
2109 if (!suspend)
2110 return -ENOMEM;
2111
2112 suspend->unlk = *lk_unlk;
2113 suspend->lr = lk_unlk->session.opal_key.lr;
2114
2115 mutex_lock(&dev->dev_lock);
2116 setup_opal_dev(dev, NULL);
2117 add_suspend_info(dev, suspend);
2118 mutex_unlock(&dev->dev_lock);
2119 return 0;
2120}
2121
2122static int opal_add_user_to_lr(struct opal_dev *dev,
2123 struct opal_lock_unlock *lk_unlk)
2124{
Jon Derrickeed64952017-02-22 07:55:13 -07002125 const struct opal_step steps[] = {
2126 { opal_discovery0, },
2127 { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2128 { add_user_to_lr, lk_unlk },
2129 { end_opal_session, },
2130 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002131 };
2132 int ret;
2133
2134 if (lk_unlk->l_state != OPAL_RO &&
2135 lk_unlk->l_state != OPAL_RW) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002136 pr_debug("Locking state was not RO or RW\n");
Scott Bauer455a7b22017-02-03 12:50:31 -07002137 return -EINVAL;
2138 }
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002139 if (lk_unlk->session.who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002140 lk_unlk->session.who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002141 pr_debug("Authority was not within the range of users: %d\n",
2142 lk_unlk->session.who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002143 return -EINVAL;
2144 }
2145 if (lk_unlk->session.sum) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002146 pr_debug("%s not supported in sum. Use setup locking range\n",
2147 __func__);
Scott Bauer455a7b22017-02-03 12:50:31 -07002148 return -EINVAL;
2149 }
2150
2151 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002152 setup_opal_dev(dev, steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002153 ret = next(dev);
2154 mutex_unlock(&dev->dev_lock);
2155 return ret;
2156}
2157
2158static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal)
2159{
Jon Derrickeed64952017-02-22 07:55:13 -07002160 const struct opal_step revert_steps[] = {
2161 { opal_discovery0, },
2162 { start_SIDASP_opal_session, opal },
2163 { revert_tper, }, /* controller will terminate session */
2164 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002165 };
2166 int ret;
2167
2168 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002169 setup_opal_dev(dev, revert_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002170 ret = next(dev);
2171 mutex_unlock(&dev->dev_lock);
Scott Bauer7d6d1572017-02-22 10:15:06 -07002172
2173 /*
2174 * If we successfully reverted lets clean
2175 * any saved locking ranges.
2176 */
2177 if (!ret)
2178 clean_opal_dev(dev);
2179
Scott Bauer455a7b22017-02-03 12:50:31 -07002180 return ret;
2181}
2182
Jon Derrickeed64952017-02-22 07:55:13 -07002183static int __opal_lock_unlock(struct opal_dev *dev,
2184 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002185{
Jon Derrickeed64952017-02-22 07:55:13 -07002186 const struct opal_step unlock_steps[] = {
2187 { opal_discovery0, },
2188 { start_auth_opal_session, &lk_unlk->session },
2189 { lock_unlock_locking_range, lk_unlk },
2190 { end_opal_session, },
2191 { NULL, }
2192 };
2193 const struct opal_step unlock_sum_steps[] = {
2194 { opal_discovery0, },
2195 { start_auth_opal_session, &lk_unlk->session },
2196 { lock_unlock_locking_range_sum, lk_unlk },
2197 { end_opal_session, },
2198 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002199 };
2200
Jon Derrickeed64952017-02-22 07:55:13 -07002201 dev->steps = lk_unlk->session.sum ? unlock_sum_steps : unlock_steps;
Scott Bauer455a7b22017-02-03 12:50:31 -07002202 return next(dev);
2203}
2204
Scott Bauerdbec491b2017-09-01 08:53:35 -06002205static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2206{
2207 u8 mbr_done_tf = 1;
2208 const struct opal_step mbrdone_step [] = {
2209 { opal_discovery0, },
2210 { start_admin1LSP_opal_session, key },
2211 { set_mbr_done, &mbr_done_tf },
2212 { end_opal_session, },
2213 { NULL, }
2214 };
2215
2216 dev->steps = mbrdone_step;
2217 return next(dev);
2218}
2219
Jon Derrickeed64952017-02-22 07:55:13 -07002220static int opal_lock_unlock(struct opal_dev *dev,
2221 struct opal_lock_unlock *lk_unlk)
Scott Bauer455a7b22017-02-03 12:50:31 -07002222{
Scott Bauer455a7b22017-02-03 12:50:31 -07002223 int ret;
2224
2225 if (lk_unlk->session.who < OPAL_ADMIN1 ||
2226 lk_unlk->session.who > OPAL_USER9)
2227 return -EINVAL;
2228
2229 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002230 ret = __opal_lock_unlock(dev, lk_unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002231 mutex_unlock(&dev->dev_lock);
2232 return ret;
2233}
2234
2235static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2236{
Jon Derrickeed64952017-02-22 07:55:13 -07002237 const struct opal_step owner_steps[] = {
2238 { opal_discovery0, },
2239 { start_anybodyASP_opal_session, },
2240 { get_msid_cpin_pin, },
2241 { end_opal_session, },
2242 { start_SIDASP_opal_session, opal },
2243 { set_sid_cpin_pin, opal },
2244 { end_opal_session, },
2245 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002246 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002247 int ret;
2248
2249 if (!dev)
2250 return -ENODEV;
2251
2252 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002253 setup_opal_dev(dev, owner_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002254 ret = next(dev);
2255 mutex_unlock(&dev->dev_lock);
2256 return ret;
2257}
2258
2259static int opal_activate_lsp(struct opal_dev *dev, struct opal_lr_act *opal_lr_act)
2260{
Jon Derrickeed64952017-02-22 07:55:13 -07002261 const struct opal_step active_steps[] = {
2262 { opal_discovery0, },
2263 { start_SIDASP_opal_session, &opal_lr_act->key },
2264 { get_lsp_lifecycle, },
2265 { activate_lsp, opal_lr_act },
2266 { end_opal_session, },
2267 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002268 };
2269 int ret;
2270
2271 if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2272 return -EINVAL;
2273
2274 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002275 setup_opal_dev(dev, active_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002276 ret = next(dev);
2277 mutex_unlock(&dev->dev_lock);
2278 return ret;
2279}
2280
2281static int opal_setup_locking_range(struct opal_dev *dev,
2282 struct opal_user_lr_setup *opal_lrs)
2283{
Jon Derrickeed64952017-02-22 07:55:13 -07002284 const struct opal_step lr_steps[] = {
2285 { opal_discovery0, },
2286 { start_auth_opal_session, &opal_lrs->session },
2287 { setup_locking_range, opal_lrs },
2288 { end_opal_session, },
2289 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002290 };
2291 int ret;
2292
2293 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002294 setup_opal_dev(dev, lr_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002295 ret = next(dev);
2296 mutex_unlock(&dev->dev_lock);
2297 return ret;
2298}
2299
2300static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
2301{
Jon Derrickeed64952017-02-22 07:55:13 -07002302 const struct opal_step pw_steps[] = {
2303 { opal_discovery0, },
2304 { start_auth_opal_session, &opal_pw->session },
2305 { set_new_pw, &opal_pw->new_user_pw },
2306 { end_opal_session, },
2307 { NULL }
Scott Bauer455a7b22017-02-03 12:50:31 -07002308 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002309 int ret;
2310
2311 if (opal_pw->session.who < OPAL_ADMIN1 ||
2312 opal_pw->session.who > OPAL_USER9 ||
2313 opal_pw->new_user_pw.who < OPAL_ADMIN1 ||
2314 opal_pw->new_user_pw.who > OPAL_USER9)
2315 return -EINVAL;
2316
2317 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002318 setup_opal_dev(dev, pw_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002319 ret = next(dev);
2320 mutex_unlock(&dev->dev_lock);
2321 return ret;
2322}
2323
2324static int opal_activate_user(struct opal_dev *dev,
2325 struct opal_session_info *opal_session)
2326{
Jon Derrickeed64952017-02-22 07:55:13 -07002327 const struct opal_step act_steps[] = {
2328 { opal_discovery0, },
2329 { start_admin1LSP_opal_session, &opal_session->opal_key },
2330 { internal_activate_user, opal_session },
2331 { end_opal_session, },
2332 { NULL, }
Scott Bauer455a7b22017-02-03 12:50:31 -07002333 };
Scott Bauer455a7b22017-02-03 12:50:31 -07002334 int ret;
2335
2336 /* We can't activate Admin1 it's active as manufactured */
Jon Derrickb0bfdfc2017-03-06 08:41:04 -07002337 if (opal_session->who < OPAL_USER1 ||
Scott Bauer455a7b22017-02-03 12:50:31 -07002338 opal_session->who > OPAL_USER9) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002339 pr_debug("Who was not a valid user: %d\n", opal_session->who);
Scott Bauer455a7b22017-02-03 12:50:31 -07002340 return -EINVAL;
2341 }
2342
2343 mutex_lock(&dev->dev_lock);
Jon Derrickeed64952017-02-22 07:55:13 -07002344 setup_opal_dev(dev, act_steps);
Scott Bauer455a7b22017-02-03 12:50:31 -07002345 ret = next(dev);
2346 mutex_unlock(&dev->dev_lock);
2347 return ret;
2348}
2349
2350bool opal_unlock_from_suspend(struct opal_dev *dev)
2351{
2352 struct opal_suspend_data *suspend;
Scott Bauer455a7b22017-02-03 12:50:31 -07002353 bool was_failure = false;
2354 int ret = 0;
2355
2356 if (!dev)
2357 return false;
2358 if (!dev->supported)
2359 return false;
2360
2361 mutex_lock(&dev->dev_lock);
2362 setup_opal_dev(dev, NULL);
Scott Bauer455a7b22017-02-03 12:50:31 -07002363
2364 list_for_each_entry(suspend, &dev->unlk_lst, node) {
Scott Bauer455a7b22017-02-03 12:50:31 -07002365 dev->tsn = 0;
2366 dev->hsn = 0;
2367
Jon Derrickeed64952017-02-22 07:55:13 -07002368 ret = __opal_lock_unlock(dev, &suspend->unlk);
Scott Bauer455a7b22017-02-03 12:50:31 -07002369 if (ret) {
Scott Bauer591c59d2017-04-07 13:58:50 -06002370 pr_debug("Failed to unlock LR %hhu with sum %d\n",
2371 suspend->unlk.session.opal_key.lr,
2372 suspend->unlk.session.sum);
Scott Bauer455a7b22017-02-03 12:50:31 -07002373 was_failure = true;
2374 }
Scott Bauerdbec491b2017-09-01 08:53:35 -06002375 if (dev->mbr_enabled) {
2376 ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
2377 if (ret)
2378 pr_debug("Failed to set MBR Done in S3 resume\n");
2379 }
Scott Bauer455a7b22017-02-03 12:50:31 -07002380 }
2381 mutex_unlock(&dev->dev_lock);
2382 return was_failure;
2383}
2384EXPORT_SYMBOL(opal_unlock_from_suspend);
2385
Scott Bauere225c202017-02-14 17:29:36 -07002386int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
Scott Bauer455a7b22017-02-03 12:50:31 -07002387{
Scott Bauere225c202017-02-14 17:29:36 -07002388 void *p;
2389 int ret = -ENOTTY;
Scott Bauer455a7b22017-02-03 12:50:31 -07002390
2391 if (!capable(CAP_SYS_ADMIN))
2392 return -EACCES;
Christoph Hellwig4f1244c2017-02-17 13:59:39 +01002393 if (!dev)
2394 return -ENOTSUPP;
Scott Bauer591c59d2017-04-07 13:58:50 -06002395 if (!dev->supported)
Scott Bauer455a7b22017-02-03 12:50:31 -07002396 return -ENOTSUPP;
Scott Bauer455a7b22017-02-03 12:50:31 -07002397
Jon Derrickeed64952017-02-22 07:55:13 -07002398 p = memdup_user(arg, _IOC_SIZE(cmd));
Scott Bauere225c202017-02-14 17:29:36 -07002399 if (IS_ERR(p))
2400 return PTR_ERR(p);
2401
Scott Bauer455a7b22017-02-03 12:50:31 -07002402 switch (cmd) {
Scott Bauere225c202017-02-14 17:29:36 -07002403 case IOC_OPAL_SAVE:
2404 ret = opal_save(dev, p);
2405 break;
2406 case IOC_OPAL_LOCK_UNLOCK:
2407 ret = opal_lock_unlock(dev, p);
2408 break;
2409 case IOC_OPAL_TAKE_OWNERSHIP:
2410 ret = opal_take_ownership(dev, p);
2411 break;
2412 case IOC_OPAL_ACTIVATE_LSP:
2413 ret = opal_activate_lsp(dev, p);
2414 break;
2415 case IOC_OPAL_SET_PW:
2416 ret = opal_set_new_pw(dev, p);
2417 break;
2418 case IOC_OPAL_ACTIVATE_USR:
2419 ret = opal_activate_user(dev, p);
2420 break;
2421 case IOC_OPAL_REVERT_TPR:
2422 ret = opal_reverttper(dev, p);
2423 break;
2424 case IOC_OPAL_LR_SETUP:
2425 ret = opal_setup_locking_range(dev, p);
2426 break;
2427 case IOC_OPAL_ADD_USR_TO_LR:
2428 ret = opal_add_user_to_lr(dev, p);
2429 break;
2430 case IOC_OPAL_ENABLE_DISABLE_MBR:
2431 ret = opal_enable_disable_shadow_mbr(dev, p);
2432 break;
2433 case IOC_OPAL_ERASE_LR:
2434 ret = opal_erase_locking_range(dev, p);
2435 break;
2436 case IOC_OPAL_SECURE_ERASE_LR:
2437 ret = opal_secure_erase_locking_range(dev, p);
2438 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002439 default:
Scott Bauer591c59d2017-04-07 13:58:50 -06002440 break;
Scott Bauer455a7b22017-02-03 12:50:31 -07002441 }
Scott Bauere225c202017-02-14 17:29:36 -07002442
2443 kfree(p);
2444 return ret;
Scott Bauer455a7b22017-02-03 12:50:31 -07002445}
2446EXPORT_SYMBOL_GPL(sed_ioctl);