18c16567dSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
2455a7b23SScott Bauer /*
3455a7b23SScott Bauer * Copyright © 2016 Intel Corporation
4455a7b23SScott Bauer *
5455a7b23SScott Bauer * Authors:
6455a7b23SScott Bauer * Scott Bauer <scott.bauer@intel.com>
7455a7b23SScott Bauer * Rafael Antognolli <rafael.antognolli@intel.com>
8455a7b23SScott Bauer */
9455a7b23SScott Bauer
10455a7b23SScott Bauer #define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt
11455a7b23SScott Bauer
12455a7b23SScott Bauer #include <linux/delay.h>
13455a7b23SScott Bauer #include <linux/device.h>
14455a7b23SScott Bauer #include <linux/kernel.h>
15455a7b23SScott Bauer #include <linux/list.h>
16322cbb50SChristoph Hellwig #include <linux/blkdev.h>
17455a7b23SScott Bauer #include <linux/slab.h>
18455a7b23SScott Bauer #include <linux/uaccess.h>
19455a7b23SScott Bauer #include <uapi/linux/sed-opal.h>
20455a7b23SScott Bauer #include <linux/sed-opal.h>
21455a7b23SScott Bauer #include <linux/string.h>
22455a7b23SScott Bauer #include <linux/kdev_t.h>
233bfeb612SGreg Joyce #include <linux/key.h>
243bfeb612SGreg Joyce #include <linux/key-type.h>
253bfeb612SGreg Joyce #include <keys/user-type.h>
26455a7b23SScott Bauer
27455a7b23SScott Bauer #include "opal_proto.h"
28455a7b23SScott Bauer
294f1244c8SChristoph Hellwig #define IO_BUFFER_LENGTH 2048
304f1244c8SChristoph Hellwig #define MAX_TOKS 64
314f1244c8SChristoph Hellwig
32a9b25b4cSJonas Rabenstein /* Number of bytes needed by cmd_finalize. */
33a9b25b4cSJonas Rabenstein #define CMD_FINALIZE_BYTES_NEEDED 7
34a9b25b4cSJonas Rabenstein
353bfeb612SGreg Joyce static struct key *sed_opal_keyring;
363bfeb612SGreg Joyce
37eed64951SJon Derrick struct opal_step {
38eed64951SJon Derrick int (*fn)(struct opal_dev *dev, void *data);
39eed64951SJon Derrick void *data;
40eed64951SJon Derrick };
41eed64951SJon Derrick typedef int (cont_fn)(struct opal_dev *dev);
424f1244c8SChristoph Hellwig
434f1244c8SChristoph Hellwig enum opal_atom_width {
444f1244c8SChristoph Hellwig OPAL_WIDTH_TINY,
454f1244c8SChristoph Hellwig OPAL_WIDTH_SHORT,
464f1244c8SChristoph Hellwig OPAL_WIDTH_MEDIUM,
474f1244c8SChristoph Hellwig OPAL_WIDTH_LONG,
484f1244c8SChristoph Hellwig OPAL_WIDTH_TOKEN
494f1244c8SChristoph Hellwig };
504f1244c8SChristoph Hellwig
514f1244c8SChristoph Hellwig /*
524f1244c8SChristoph Hellwig * On the parsed response, we don't store again the toks that are already
534f1244c8SChristoph Hellwig * stored in the response buffer. Instead, for each token, we just store a
544f1244c8SChristoph Hellwig * pointer to the position in the buffer where the token starts, and the size
554f1244c8SChristoph Hellwig * of the token in bytes.
564f1244c8SChristoph Hellwig */
574f1244c8SChristoph Hellwig struct opal_resp_tok {
584f1244c8SChristoph Hellwig const u8 *pos;
594f1244c8SChristoph Hellwig size_t len;
604f1244c8SChristoph Hellwig enum opal_response_token type;
614f1244c8SChristoph Hellwig enum opal_atom_width width;
624f1244c8SChristoph Hellwig union {
634f1244c8SChristoph Hellwig u64 u;
644f1244c8SChristoph Hellwig s64 s;
654f1244c8SChristoph Hellwig } stored;
664f1244c8SChristoph Hellwig };
674f1244c8SChristoph Hellwig
684f1244c8SChristoph Hellwig /*
694f1244c8SChristoph Hellwig * From the response header it's not possible to know how many tokens there are
704f1244c8SChristoph Hellwig * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
714f1244c8SChristoph Hellwig * if we start dealing with messages that have more than that, we can increase
724f1244c8SChristoph Hellwig * this number. This is done to avoid having to make two passes through the
734f1244c8SChristoph Hellwig * response, the first one counting how many tokens we have and the second one
744f1244c8SChristoph Hellwig * actually storing the positions.
754f1244c8SChristoph Hellwig */
764f1244c8SChristoph Hellwig struct parsed_resp {
774f1244c8SChristoph Hellwig int num;
784f1244c8SChristoph Hellwig struct opal_resp_tok toks[MAX_TOKS];
794f1244c8SChristoph Hellwig };
804f1244c8SChristoph Hellwig
814f1244c8SChristoph Hellwig struct opal_dev {
82c6ea7060Sdougmill@linux.vnet.ibm.com u32 flags;
834f1244c8SChristoph Hellwig
844f1244c8SChristoph Hellwig void *data;
854f1244c8SChristoph Hellwig sec_send_recv *send_recv;
864f1244c8SChristoph Hellwig
874f1244c8SChristoph Hellwig struct mutex dev_lock;
884f1244c8SChristoph Hellwig u16 comid;
894f1244c8SChristoph Hellwig u32 hsn;
904f1244c8SChristoph Hellwig u32 tsn;
919e05a259SOndrej Kozina u64 align; /* alignment granularity */
924f1244c8SChristoph Hellwig u64 lowest_lba;
939e05a259SOndrej Kozina u32 logical_block_size;
949e05a259SOndrej Kozina u8 align_required; /* ALIGN: 0 or 1 */
954f1244c8SChristoph Hellwig
964f1244c8SChristoph Hellwig size_t pos;
97f829230dSSerge Semin u8 *cmd;
98f829230dSSerge Semin u8 *resp;
994f1244c8SChristoph Hellwig
1004f1244c8SChristoph Hellwig struct parsed_resp parsed;
1014f1244c8SChristoph Hellwig size_t prev_d_len;
1024f1244c8SChristoph Hellwig void *prev_data;
1034f1244c8SChristoph Hellwig
1044f1244c8SChristoph Hellwig struct list_head unlk_lst;
1054f1244c8SChristoph Hellwig };
1064f1244c8SChristoph Hellwig
1074f1244c8SChristoph Hellwig
108455a7b23SScott Bauer static const u8 opaluid[][OPAL_UID_LENGTH] = {
109455a7b23SScott Bauer /* users */
110455a7b23SScott Bauer [OPAL_SMUID_UID] =
111455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
112455a7b23SScott Bauer [OPAL_THISSP_UID] =
113455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
114455a7b23SScott Bauer [OPAL_ADMINSP_UID] =
115455a7b23SScott Bauer { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
116455a7b23SScott Bauer [OPAL_LOCKINGSP_UID] =
117455a7b23SScott Bauer { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
118455a7b23SScott Bauer [OPAL_ENTERPRISE_LOCKINGSP_UID] =
119455a7b23SScott Bauer { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
120455a7b23SScott Bauer [OPAL_ANYBODY_UID] =
121455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
122455a7b23SScott Bauer [OPAL_SID_UID] =
123455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
124455a7b23SScott Bauer [OPAL_ADMIN1_UID] =
125455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
126455a7b23SScott Bauer [OPAL_USER1_UID] =
127455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
128455a7b23SScott Bauer [OPAL_USER2_UID] =
129455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
130455a7b23SScott Bauer [OPAL_PSID_UID] =
131455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
132455a7b23SScott Bauer [OPAL_ENTERPRISE_BANDMASTER0_UID] =
133455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
134455a7b23SScott Bauer [OPAL_ENTERPRISE_ERASEMASTER_UID] =
135455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
136455a7b23SScott Bauer
137455a7b23SScott Bauer /* tables */
138dc301025SRandy Dunlap [OPAL_TABLE_TABLE] =
139ff91064eSJonas Rabenstein { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 },
140455a7b23SScott Bauer [OPAL_LOCKINGRANGE_GLOBAL] =
141455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
1428be19a02SOndrej Kozina [OPAL_LOCKINGRANGE_ACE_START_TO_KEY] =
1438be19a02SOndrej Kozina { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xD0, 0x01 },
144455a7b23SScott Bauer [OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
145455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
146455a7b23SScott Bauer [OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
147455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
148455a7b23SScott Bauer [OPAL_MBRCONTROL] =
149455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
150455a7b23SScott Bauer [OPAL_MBR] =
151455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
152455a7b23SScott Bauer [OPAL_AUTHORITY_TABLE] =
153455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
154455a7b23SScott Bauer [OPAL_C_PIN_TABLE] =
155455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
156455a7b23SScott Bauer [OPAL_LOCKING_INFO_TABLE] =
157455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
158455a7b23SScott Bauer [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
159455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
16062c441c6SRevanth Rajashekar [OPAL_DATASTORE] =
16162c441c6SRevanth Rajashekar { 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00 },
162455a7b23SScott Bauer
163455a7b23SScott Bauer /* C_PIN_TABLE object ID's */
164455a7b23SScott Bauer [OPAL_C_PIN_MSID] =
165455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
166455a7b23SScott Bauer [OPAL_C_PIN_SID] =
167455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
168455a7b23SScott Bauer [OPAL_C_PIN_ADMIN1] =
169455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
170455a7b23SScott Bauer
171455a7b23SScott Bauer /* half UID's (only first 4 bytes used) */
172455a7b23SScott Bauer [OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
173455a7b23SScott Bauer { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
174455a7b23SScott Bauer [OPAL_HALF_UID_BOOLEAN_ACE] =
175455a7b23SScott Bauer { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
176455a7b23SScott Bauer
177455a7b23SScott Bauer /* special value for omitted optional parameter */
178455a7b23SScott Bauer [OPAL_UID_HEXFF] =
179455a7b23SScott Bauer { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
180455a7b23SScott Bauer };
181455a7b23SScott Bauer
182455a7b23SScott Bauer /*
183455a7b23SScott Bauer * TCG Storage SSC Methods.
184455a7b23SScott Bauer * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
185455a7b23SScott Bauer * Section: 6.3 Assigned UIDs
186455a7b23SScott Bauer */
1871b6b75b0SJonas Rabenstein static const u8 opalmethod[][OPAL_METHOD_LENGTH] = {
188455a7b23SScott Bauer [OPAL_PROPERTIES] =
189455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
190455a7b23SScott Bauer [OPAL_STARTSESSION] =
191455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
192455a7b23SScott Bauer [OPAL_REVERT] =
193455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
194455a7b23SScott Bauer [OPAL_ACTIVATE] =
195455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
196455a7b23SScott Bauer [OPAL_EGET] =
197455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
198455a7b23SScott Bauer [OPAL_ESET] =
199455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
200455a7b23SScott Bauer [OPAL_NEXT] =
201455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
202455a7b23SScott Bauer [OPAL_EAUTHENTICATE] =
203455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
204455a7b23SScott Bauer [OPAL_GETACL] =
205455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
206455a7b23SScott Bauer [OPAL_GENKEY] =
207455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
208455a7b23SScott Bauer [OPAL_REVERTSP] =
209455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
210455a7b23SScott Bauer [OPAL_GET] =
211455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
212455a7b23SScott Bauer [OPAL_SET] =
213455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
214455a7b23SScott Bauer [OPAL_AUTHENTICATE] =
215455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
216455a7b23SScott Bauer [OPAL_RANDOM] =
217455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
218455a7b23SScott Bauer [OPAL_ERASE] =
219455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
220455a7b23SScott Bauer };
221455a7b23SScott Bauer
222455a7b23SScott Bauer static int end_opal_session_error(struct opal_dev *dev);
2230af2648eSDavid Kozub static int opal_discovery0_step(struct opal_dev *dev);
224455a7b23SScott Bauer
225455a7b23SScott Bauer struct opal_suspend_data {
226455a7b23SScott Bauer struct opal_lock_unlock unlk;
227455a7b23SScott Bauer u8 lr;
228455a7b23SScott Bauer struct list_head node;
229455a7b23SScott Bauer };
230455a7b23SScott Bauer
231455a7b23SScott Bauer /*
232455a7b23SScott Bauer * Derived from:
233455a7b23SScott Bauer * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
234455a7b23SScott Bauer * Section: 5.1.5 Method Status Codes
235455a7b23SScott Bauer */
236455a7b23SScott Bauer static const char * const opal_errors[] = {
237455a7b23SScott Bauer "Success",
238455a7b23SScott Bauer "Not Authorized",
239455a7b23SScott Bauer "Unknown Error",
240455a7b23SScott Bauer "SP Busy",
241455a7b23SScott Bauer "SP Failed",
242455a7b23SScott Bauer "SP Disabled",
243455a7b23SScott Bauer "SP Frozen",
244455a7b23SScott Bauer "No Sessions Available",
245455a7b23SScott Bauer "Uniqueness Conflict",
246455a7b23SScott Bauer "Insufficient Space",
247455a7b23SScott Bauer "Insufficient Rows",
248455a7b23SScott Bauer "Invalid Function",
249455a7b23SScott Bauer "Invalid Parameter",
250455a7b23SScott Bauer "Invalid Reference",
251455a7b23SScott Bauer "Unknown Error",
252455a7b23SScott Bauer "TPER Malfunction",
253455a7b23SScott Bauer "Transaction Failure",
254455a7b23SScott Bauer "Response Overflow",
255455a7b23SScott Bauer "Authority Locked Out",
256455a7b23SScott Bauer };
257455a7b23SScott Bauer
opal_error_to_human(int error)258455a7b23SScott Bauer static const char *opal_error_to_human(int error)
259455a7b23SScott Bauer {
260455a7b23SScott Bauer if (error == 0x3f)
261455a7b23SScott Bauer return "Failed";
262455a7b23SScott Bauer
263455a7b23SScott Bauer if (error >= ARRAY_SIZE(opal_errors) || error < 0)
264455a7b23SScott Bauer return "Unknown Error";
265455a7b23SScott Bauer
266455a7b23SScott Bauer return opal_errors[error];
267455a7b23SScott Bauer }
268455a7b23SScott Bauer
print_buffer(const u8 * ptr,u32 length)269455a7b23SScott Bauer static void print_buffer(const u8 *ptr, u32 length)
270455a7b23SScott Bauer {
271455a7b23SScott Bauer #ifdef DEBUG
272455a7b23SScott Bauer print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
273455a7b23SScott Bauer pr_debug("\n");
274455a7b23SScott Bauer #endif
275455a7b23SScott Bauer }
276455a7b23SScott Bauer
2773bfeb612SGreg Joyce /*
2783bfeb612SGreg Joyce * Allocate/update a SED Opal key and add it to the SED Opal keyring.
2793bfeb612SGreg Joyce */
update_sed_opal_key(const char * desc,u_char * key_data,int keylen)2803bfeb612SGreg Joyce static int update_sed_opal_key(const char *desc, u_char *key_data, int keylen)
2813bfeb612SGreg Joyce {
2823bfeb612SGreg Joyce key_ref_t kr;
2833bfeb612SGreg Joyce
2843bfeb612SGreg Joyce if (!sed_opal_keyring)
2853bfeb612SGreg Joyce return -ENOKEY;
2863bfeb612SGreg Joyce
2873bfeb612SGreg Joyce kr = key_create_or_update(make_key_ref(sed_opal_keyring, true), "user",
2883bfeb612SGreg Joyce desc, (const void *)key_data, keylen,
2893bfeb612SGreg Joyce KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_WRITE,
2903bfeb612SGreg Joyce KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN |
2913bfeb612SGreg Joyce KEY_ALLOC_BYPASS_RESTRICTION);
2923bfeb612SGreg Joyce if (IS_ERR(kr)) {
2933bfeb612SGreg Joyce pr_err("Error adding SED key (%ld)\n", PTR_ERR(kr));
2943bfeb612SGreg Joyce return PTR_ERR(kr);
2953bfeb612SGreg Joyce }
2963bfeb612SGreg Joyce
2973bfeb612SGreg Joyce return 0;
2983bfeb612SGreg Joyce }
2993bfeb612SGreg Joyce
3003bfeb612SGreg Joyce /*
3013bfeb612SGreg Joyce * Read a SED Opal key from the SED Opal keyring.
3023bfeb612SGreg Joyce */
read_sed_opal_key(const char * key_name,u_char * buffer,int buflen)3033bfeb612SGreg Joyce static int read_sed_opal_key(const char *key_name, u_char *buffer, int buflen)
3043bfeb612SGreg Joyce {
3053bfeb612SGreg Joyce int ret;
3063bfeb612SGreg Joyce key_ref_t kref;
3073bfeb612SGreg Joyce struct key *key;
3083bfeb612SGreg Joyce
3093bfeb612SGreg Joyce if (!sed_opal_keyring)
3103bfeb612SGreg Joyce return -ENOKEY;
3113bfeb612SGreg Joyce
3123bfeb612SGreg Joyce kref = keyring_search(make_key_ref(sed_opal_keyring, true),
3133bfeb612SGreg Joyce &key_type_user, key_name, true);
3143bfeb612SGreg Joyce
3153bfeb612SGreg Joyce if (IS_ERR(kref))
316*6b715545SSu Hui return PTR_ERR(kref);
3173bfeb612SGreg Joyce
3183bfeb612SGreg Joyce key = key_ref_to_ptr(kref);
3193bfeb612SGreg Joyce down_read(&key->sem);
3203bfeb612SGreg Joyce ret = key_validate(key);
3213bfeb612SGreg Joyce if (ret == 0) {
3223bfeb612SGreg Joyce if (buflen > key->datalen)
3233bfeb612SGreg Joyce buflen = key->datalen;
3243bfeb612SGreg Joyce
3253bfeb612SGreg Joyce ret = key->type->read(key, (char *)buffer, buflen);
3263bfeb612SGreg Joyce }
3273bfeb612SGreg Joyce up_read(&key->sem);
3283bfeb612SGreg Joyce
3293bfeb612SGreg Joyce key_ref_put(kref);
3303bfeb612SGreg Joyce
3313bfeb612SGreg Joyce return ret;
3323bfeb612SGreg Joyce }
3333bfeb612SGreg Joyce
opal_get_key(struct opal_dev * dev,struct opal_key * key)3343bfeb612SGreg Joyce static int opal_get_key(struct opal_dev *dev, struct opal_key *key)
3353bfeb612SGreg Joyce {
3363bfeb612SGreg Joyce int ret = 0;
3373bfeb612SGreg Joyce
3383bfeb612SGreg Joyce switch (key->key_type) {
3393bfeb612SGreg Joyce case OPAL_INCLUDED:
3403bfeb612SGreg Joyce /* the key is ready to use */
3413bfeb612SGreg Joyce break;
3423bfeb612SGreg Joyce case OPAL_KEYRING:
3433bfeb612SGreg Joyce /* the key is in the keyring */
3443bfeb612SGreg Joyce ret = read_sed_opal_key(OPAL_AUTH_KEY, key->key, OPAL_KEY_MAX);
3453bfeb612SGreg Joyce if (ret > 0) {
3463bfeb612SGreg Joyce if (ret > U8_MAX) {
3473bfeb612SGreg Joyce ret = -ENOSPC;
3483bfeb612SGreg Joyce goto error;
3493bfeb612SGreg Joyce }
3503bfeb612SGreg Joyce key->key_len = ret;
3513bfeb612SGreg Joyce key->key_type = OPAL_INCLUDED;
3523bfeb612SGreg Joyce }
3533bfeb612SGreg Joyce break;
3543bfeb612SGreg Joyce default:
3553bfeb612SGreg Joyce ret = -EINVAL;
3563bfeb612SGreg Joyce break;
3573bfeb612SGreg Joyce }
3583bfeb612SGreg Joyce if (ret < 0)
3593bfeb612SGreg Joyce goto error;
3603bfeb612SGreg Joyce
3613bfeb612SGreg Joyce /* must have a PEK by now or it's an error */
3623bfeb612SGreg Joyce if (key->key_type != OPAL_INCLUDED || key->key_len == 0) {
3633bfeb612SGreg Joyce ret = -EINVAL;
3643bfeb612SGreg Joyce goto error;
3653bfeb612SGreg Joyce }
3663bfeb612SGreg Joyce return 0;
3673bfeb612SGreg Joyce error:
3683bfeb612SGreg Joyce pr_debug("Error getting password: %d\n", ret);
3693bfeb612SGreg Joyce return ret;
3703bfeb612SGreg Joyce }
3713bfeb612SGreg Joyce
check_tper(const void * data)372455a7b23SScott Bauer static bool check_tper(const void *data)
373455a7b23SScott Bauer {
374455a7b23SScott Bauer const struct d0_tper_features *tper = data;
375455a7b23SScott Bauer u8 flags = tper->supported_features;
376455a7b23SScott Bauer
377455a7b23SScott Bauer if (!(flags & TPER_SYNC_SUPPORTED)) {
378591c59d1SScott Bauer pr_debug("TPer sync not supported. flags = %d\n",
379455a7b23SScott Bauer tper->supported_features);
380455a7b23SScott Bauer return false;
381455a7b23SScott Bauer }
382455a7b23SScott Bauer
383455a7b23SScott Bauer return true;
384455a7b23SScott Bauer }
385455a7b23SScott Bauer
check_lcksuppt(const void * data)386c6ea7060Sdougmill@linux.vnet.ibm.com static bool check_lcksuppt(const void *data)
387c6ea7060Sdougmill@linux.vnet.ibm.com {
388c6ea7060Sdougmill@linux.vnet.ibm.com const struct d0_locking_features *lfeat = data;
389c6ea7060Sdougmill@linux.vnet.ibm.com u8 sup_feat = lfeat->supported_features;
390c6ea7060Sdougmill@linux.vnet.ibm.com
391c6ea7060Sdougmill@linux.vnet.ibm.com return !!(sup_feat & LOCKING_SUPPORTED_MASK);
392c6ea7060Sdougmill@linux.vnet.ibm.com }
393c6ea7060Sdougmill@linux.vnet.ibm.com
check_lckenabled(const void * data)394c6ea7060Sdougmill@linux.vnet.ibm.com static bool check_lckenabled(const void *data)
395c6ea7060Sdougmill@linux.vnet.ibm.com {
396c6ea7060Sdougmill@linux.vnet.ibm.com const struct d0_locking_features *lfeat = data;
397c6ea7060Sdougmill@linux.vnet.ibm.com u8 sup_feat = lfeat->supported_features;
398c6ea7060Sdougmill@linux.vnet.ibm.com
399c6ea7060Sdougmill@linux.vnet.ibm.com return !!(sup_feat & LOCKING_ENABLED_MASK);
400c6ea7060Sdougmill@linux.vnet.ibm.com }
401c6ea7060Sdougmill@linux.vnet.ibm.com
check_locked(const void * data)402c6ea7060Sdougmill@linux.vnet.ibm.com static bool check_locked(const void *data)
403c6ea7060Sdougmill@linux.vnet.ibm.com {
404c6ea7060Sdougmill@linux.vnet.ibm.com const struct d0_locking_features *lfeat = data;
405c6ea7060Sdougmill@linux.vnet.ibm.com u8 sup_feat = lfeat->supported_features;
406c6ea7060Sdougmill@linux.vnet.ibm.com
407c6ea7060Sdougmill@linux.vnet.ibm.com return !!(sup_feat & LOCKED_MASK);
408c6ea7060Sdougmill@linux.vnet.ibm.com }
409c6ea7060Sdougmill@linux.vnet.ibm.com
check_mbrenabled(const void * data)410dbec491bSScott Bauer static bool check_mbrenabled(const void *data)
411dbec491bSScott Bauer {
412dbec491bSScott Bauer const struct d0_locking_features *lfeat = data;
413dbec491bSScott Bauer u8 sup_feat = lfeat->supported_features;
414dbec491bSScott Bauer
415dbec491bSScott Bauer return !!(sup_feat & MBR_ENABLED_MASK);
416dbec491bSScott Bauer }
417dbec491bSScott Bauer
check_mbrdone(const void * data)418c6ea7060Sdougmill@linux.vnet.ibm.com static bool check_mbrdone(const void *data)
419c6ea7060Sdougmill@linux.vnet.ibm.com {
420c6ea7060Sdougmill@linux.vnet.ibm.com const struct d0_locking_features *lfeat = data;
421c6ea7060Sdougmill@linux.vnet.ibm.com u8 sup_feat = lfeat->supported_features;
422c6ea7060Sdougmill@linux.vnet.ibm.com
423c6ea7060Sdougmill@linux.vnet.ibm.com return !!(sup_feat & MBR_DONE_MASK);
424c6ea7060Sdougmill@linux.vnet.ibm.com }
425c6ea7060Sdougmill@linux.vnet.ibm.com
check_sum(const void * data)426455a7b23SScott Bauer static bool check_sum(const void *data)
427455a7b23SScott Bauer {
428455a7b23SScott Bauer const struct d0_single_user_mode *sum = data;
429455a7b23SScott Bauer u32 nlo = be32_to_cpu(sum->num_locking_objects);
430455a7b23SScott Bauer
431455a7b23SScott Bauer if (nlo == 0) {
432591c59d1SScott Bauer pr_debug("Need at least one locking object.\n");
433455a7b23SScott Bauer return false;
434455a7b23SScott Bauer }
435455a7b23SScott Bauer
436455a7b23SScott Bauer pr_debug("Number of locking objects: %d\n", nlo);
437455a7b23SScott Bauer
438455a7b23SScott Bauer return true;
439455a7b23SScott Bauer }
440455a7b23SScott Bauer
get_comid_v100(const void * data)441455a7b23SScott Bauer static u16 get_comid_v100(const void *data)
442455a7b23SScott Bauer {
443455a7b23SScott Bauer const struct d0_opal_v100 *v100 = data;
444455a7b23SScott Bauer
445455a7b23SScott Bauer return be16_to_cpu(v100->baseComID);
446455a7b23SScott Bauer }
447455a7b23SScott Bauer
get_comid_v200(const void * data)448455a7b23SScott Bauer static u16 get_comid_v200(const void *data)
449455a7b23SScott Bauer {
450455a7b23SScott Bauer const struct d0_opal_v200 *v200 = data;
451455a7b23SScott Bauer
452455a7b23SScott Bauer return be16_to_cpu(v200->baseComID);
453455a7b23SScott Bauer }
454455a7b23SScott Bauer
opal_send_cmd(struct opal_dev * dev)455455a7b23SScott Bauer static int opal_send_cmd(struct opal_dev *dev)
456455a7b23SScott Bauer {
4574f1244c8SChristoph Hellwig return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
458455a7b23SScott Bauer dev->cmd, IO_BUFFER_LENGTH,
459455a7b23SScott Bauer true);
460455a7b23SScott Bauer }
461455a7b23SScott Bauer
opal_recv_cmd(struct opal_dev * dev)462455a7b23SScott Bauer static int opal_recv_cmd(struct opal_dev *dev)
463455a7b23SScott Bauer {
4644f1244c8SChristoph Hellwig return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
465455a7b23SScott Bauer dev->resp, IO_BUFFER_LENGTH,
466455a7b23SScott Bauer false);
467455a7b23SScott Bauer }
468455a7b23SScott Bauer
opal_recv_check(struct opal_dev * dev)469455a7b23SScott Bauer static int opal_recv_check(struct opal_dev *dev)
470455a7b23SScott Bauer {
471455a7b23SScott Bauer size_t buflen = IO_BUFFER_LENGTH;
472455a7b23SScott Bauer void *buffer = dev->resp;
473455a7b23SScott Bauer struct opal_header *hdr = buffer;
474455a7b23SScott Bauer int ret;
475455a7b23SScott Bauer
476455a7b23SScott Bauer do {
477455a7b23SScott Bauer pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
478455a7b23SScott Bauer hdr->cp.outstandingData,
479455a7b23SScott Bauer hdr->cp.minTransfer);
480455a7b23SScott Bauer
481455a7b23SScott Bauer if (hdr->cp.outstandingData == 0 ||
482455a7b23SScott Bauer hdr->cp.minTransfer != 0)
483455a7b23SScott Bauer return 0;
484455a7b23SScott Bauer
485455a7b23SScott Bauer memset(buffer, 0, buflen);
486455a7b23SScott Bauer ret = opal_recv_cmd(dev);
487455a7b23SScott Bauer } while (!ret);
488455a7b23SScott Bauer
489455a7b23SScott Bauer return ret;
490455a7b23SScott Bauer }
491455a7b23SScott Bauer
opal_send_recv(struct opal_dev * dev,cont_fn * cont)492455a7b23SScott Bauer static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
493455a7b23SScott Bauer {
494455a7b23SScott Bauer int ret;
495455a7b23SScott Bauer
496455a7b23SScott Bauer ret = opal_send_cmd(dev);
497455a7b23SScott Bauer if (ret)
498455a7b23SScott Bauer return ret;
499455a7b23SScott Bauer ret = opal_recv_cmd(dev);
500455a7b23SScott Bauer if (ret)
501455a7b23SScott Bauer return ret;
502455a7b23SScott Bauer ret = opal_recv_check(dev);
503455a7b23SScott Bauer if (ret)
504455a7b23SScott Bauer return ret;
505455a7b23SScott Bauer return cont(dev);
506455a7b23SScott Bauer }
507455a7b23SScott Bauer
check_geometry(struct opal_dev * dev,const void * data)508455a7b23SScott Bauer static void check_geometry(struct opal_dev *dev, const void *data)
509455a7b23SScott Bauer {
510455a7b23SScott Bauer const struct d0_geometry_features *geo = data;
511455a7b23SScott Bauer
512a9eb49c9SRandy Dunlap dev->align = be64_to_cpu(geo->alignment_granularity);
513a9eb49c9SRandy Dunlap dev->lowest_lba = be64_to_cpu(geo->lowest_aligned_lba);
5149e05a259SOndrej Kozina dev->logical_block_size = be32_to_cpu(geo->logical_block_size);
5159e05a259SOndrej Kozina dev->align_required = geo->reserved01 & 1;
516455a7b23SScott Bauer }
517455a7b23SScott Bauer
execute_step(struct opal_dev * dev,const struct opal_step * step,size_t stepIndex)5180af2648eSDavid Kozub static int execute_step(struct opal_dev *dev,
5190af2648eSDavid Kozub const struct opal_step *step, size_t stepIndex)
5200af2648eSDavid Kozub {
5210af2648eSDavid Kozub int error = step->fn(dev, step->data);
5220af2648eSDavid Kozub
5230af2648eSDavid Kozub if (error) {
5240af2648eSDavid Kozub pr_debug("Step %zu (%pS) failed with error %d: %s\n",
5250af2648eSDavid Kozub stepIndex, step->fn, error,
5260af2648eSDavid Kozub opal_error_to_human(error));
5270af2648eSDavid Kozub }
5280af2648eSDavid Kozub
5290af2648eSDavid Kozub return error;
5300af2648eSDavid Kozub }
5310af2648eSDavid Kozub
execute_steps(struct opal_dev * dev,const struct opal_step * steps,size_t n_steps)532a80f36ccSDavid Kozub static int execute_steps(struct opal_dev *dev,
533a80f36ccSDavid Kozub const struct opal_step *steps, size_t n_steps)
534455a7b23SScott Bauer {
5350af2648eSDavid Kozub size_t state = 0;
5360af2648eSDavid Kozub int error;
5370af2648eSDavid Kozub
5380af2648eSDavid Kozub /* first do a discovery0 */
5390af2648eSDavid Kozub error = opal_discovery0_step(dev);
5400af2648eSDavid Kozub if (error)
5410af2648eSDavid Kozub return error;
542455a7b23SScott Bauer
5433db87236SDavid Kozub for (state = 0; state < n_steps; state++) {
5440af2648eSDavid Kozub error = execute_step(dev, &steps[state], state);
5453db87236SDavid Kozub if (error)
5463db87236SDavid Kozub goto out_error;
5473db87236SDavid Kozub }
548455a7b23SScott Bauer
5493db87236SDavid Kozub return 0;
5503db87236SDavid Kozub
5513db87236SDavid Kozub out_error:
5523db87236SDavid Kozub /*
5530af2648eSDavid Kozub * For each OPAL command the first step in steps starts some sort of
5540af2648eSDavid Kozub * session. If an error occurred in the initial discovery0 or if an
5550af2648eSDavid Kozub * error occurred in the first step (and thus stopping the loop with
5560af2648eSDavid Kozub * state == 0) then there was an error before or during the attempt to
5570af2648eSDavid Kozub * start a session. Therefore we shouldn't attempt to terminate a
5580af2648eSDavid Kozub * session, as one has not yet been created.
559455a7b23SScott Bauer */
5600af2648eSDavid Kozub if (state > 0)
5612d19020bSScott Bauer end_opal_session_error(dev);
562455a7b23SScott Bauer
563455a7b23SScott Bauer return error;
564455a7b23SScott Bauer }
565455a7b23SScott Bauer
opal_discovery0_end(struct opal_dev * dev,void * data)5669fb10726SGreg Joyce static int opal_discovery0_end(struct opal_dev *dev, void *data)
567455a7b23SScott Bauer {
5689fb10726SGreg Joyce struct opal_discovery *discv_out = data; /* may be NULL */
5699fb10726SGreg Joyce u8 __user *buf_out;
5709fb10726SGreg Joyce u64 len_out;
571455a7b23SScott Bauer bool found_com_id = false, supported = true, single_user = false;
572455a7b23SScott Bauer const struct d0_header *hdr = (struct d0_header *)dev->resp;
573455a7b23SScott Bauer const u8 *epos = dev->resp, *cpos = dev->resp;
574455a7b23SScott Bauer u16 comid = 0;
57577039b96SJon Derrick u32 hlen = be32_to_cpu(hdr->length);
576455a7b23SScott Bauer
57777039b96SJon Derrick print_buffer(dev->resp, hlen);
578c6ea7060Sdougmill@linux.vnet.ibm.com dev->flags &= OPAL_FL_SUPPORTED;
579455a7b23SScott Bauer
58077039b96SJon Derrick if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
581591c59d1SScott Bauer pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n",
58277039b96SJon Derrick sizeof(*hdr), hlen, IO_BUFFER_LENGTH);
58377039b96SJon Derrick return -EFAULT;
58477039b96SJon Derrick }
58577039b96SJon Derrick
5869fb10726SGreg Joyce if (discv_out) {
5879fb10726SGreg Joyce buf_out = (u8 __user *)(uintptr_t)discv_out->data;
5889fb10726SGreg Joyce len_out = min_t(u64, discv_out->size, hlen);
5899fb10726SGreg Joyce if (buf_out && copy_to_user(buf_out, dev->resp, len_out))
5909fb10726SGreg Joyce return -EFAULT;
5919fb10726SGreg Joyce
5929fb10726SGreg Joyce discv_out->size = hlen; /* actual size of data */
5939fb10726SGreg Joyce }
5949fb10726SGreg Joyce
59577039b96SJon Derrick epos += hlen; /* end of buffer */
596455a7b23SScott Bauer cpos += sizeof(*hdr); /* current position on buffer */
597455a7b23SScott Bauer
598455a7b23SScott Bauer while (cpos < epos && supported) {
599455a7b23SScott Bauer const struct d0_features *body =
600455a7b23SScott Bauer (const struct d0_features *)cpos;
601455a7b23SScott Bauer
602455a7b23SScott Bauer switch (be16_to_cpu(body->code)) {
603455a7b23SScott Bauer case FC_TPER:
604455a7b23SScott Bauer supported = check_tper(body->features);
605455a7b23SScott Bauer break;
606455a7b23SScott Bauer case FC_SINGLEUSER:
607455a7b23SScott Bauer single_user = check_sum(body->features);
6089ec041eaSLuca Boccassi if (single_user)
6099ec041eaSLuca Boccassi dev->flags |= OPAL_FL_SUM_SUPPORTED;
610455a7b23SScott Bauer break;
611455a7b23SScott Bauer case FC_GEOMETRY:
612455a7b23SScott Bauer check_geometry(dev, body);
613455a7b23SScott Bauer break;
614455a7b23SScott Bauer case FC_LOCKING:
615c6ea7060Sdougmill@linux.vnet.ibm.com if (check_lcksuppt(body->features))
616c6ea7060Sdougmill@linux.vnet.ibm.com dev->flags |= OPAL_FL_LOCKING_SUPPORTED;
617c6ea7060Sdougmill@linux.vnet.ibm.com if (check_lckenabled(body->features))
618c6ea7060Sdougmill@linux.vnet.ibm.com dev->flags |= OPAL_FL_LOCKING_ENABLED;
619c6ea7060Sdougmill@linux.vnet.ibm.com if (check_locked(body->features))
620c6ea7060Sdougmill@linux.vnet.ibm.com dev->flags |= OPAL_FL_LOCKED;
621c6ea7060Sdougmill@linux.vnet.ibm.com if (check_mbrenabled(body->features))
622c6ea7060Sdougmill@linux.vnet.ibm.com dev->flags |= OPAL_FL_MBR_ENABLED;
623c6ea7060Sdougmill@linux.vnet.ibm.com if (check_mbrdone(body->features))
624c6ea7060Sdougmill@linux.vnet.ibm.com dev->flags |= OPAL_FL_MBR_DONE;
625dbec491bSScott Bauer break;
626455a7b23SScott Bauer case FC_ENTERPRISE:
627455a7b23SScott Bauer case FC_DATASTORE:
628455a7b23SScott Bauer /* some ignored properties */
629455a7b23SScott Bauer pr_debug("Found OPAL feature description: %d\n",
630455a7b23SScott Bauer be16_to_cpu(body->code));
631455a7b23SScott Bauer break;
632455a7b23SScott Bauer case FC_OPALV100:
633455a7b23SScott Bauer comid = get_comid_v100(body->features);
634455a7b23SScott Bauer found_com_id = true;
635455a7b23SScott Bauer break;
636455a7b23SScott Bauer case FC_OPALV200:
637455a7b23SScott Bauer comid = get_comid_v200(body->features);
638455a7b23SScott Bauer found_com_id = true;
639455a7b23SScott Bauer break;
640455a7b23SScott Bauer case 0xbfff ... 0xffff:
641455a7b23SScott Bauer /* vendor specific, just ignore */
642455a7b23SScott Bauer break;
643455a7b23SScott Bauer default:
644455a7b23SScott Bauer pr_debug("OPAL Unknown feature: %d\n",
645455a7b23SScott Bauer be16_to_cpu(body->code));
646455a7b23SScott Bauer
647455a7b23SScott Bauer }
648455a7b23SScott Bauer cpos += body->length + 4;
649455a7b23SScott Bauer }
650455a7b23SScott Bauer
651455a7b23SScott Bauer if (!supported) {
652f5b37b7cSChristoph Hellwig pr_debug("This device is not Opal enabled. Not Supported!\n");
653455a7b23SScott Bauer return -EOPNOTSUPP;
654455a7b23SScott Bauer }
655455a7b23SScott Bauer
656455a7b23SScott Bauer if (!single_user)
657f5b37b7cSChristoph Hellwig pr_debug("Device doesn't support single user mode\n");
658455a7b23SScott Bauer
659455a7b23SScott Bauer
660455a7b23SScott Bauer if (!found_com_id) {
661f5b37b7cSChristoph Hellwig pr_debug("Could not find OPAL comid for device. Returning early\n");
662ed7158baSIngo Molnar return -EOPNOTSUPP;
663455a7b23SScott Bauer }
664455a7b23SScott Bauer
665455a7b23SScott Bauer dev->comid = comid;
666455a7b23SScott Bauer
667455a7b23SScott Bauer return 0;
668455a7b23SScott Bauer }
669455a7b23SScott Bauer
opal_discovery0(struct opal_dev * dev,void * data)670eed64951SJon Derrick static int opal_discovery0(struct opal_dev *dev, void *data)
671455a7b23SScott Bauer {
672455a7b23SScott Bauer int ret;
673455a7b23SScott Bauer
674455a7b23SScott Bauer memset(dev->resp, 0, IO_BUFFER_LENGTH);
675455a7b23SScott Bauer dev->comid = OPAL_DISCOVERY_COMID;
676455a7b23SScott Bauer ret = opal_recv_cmd(dev);
677455a7b23SScott Bauer if (ret)
678455a7b23SScott Bauer return ret;
6795cc23ed7SRevanth Rajashekar
6809fb10726SGreg Joyce return opal_discovery0_end(dev, data);
681455a7b23SScott Bauer }
682455a7b23SScott Bauer
opal_discovery0_step(struct opal_dev * dev)6830af2648eSDavid Kozub static int opal_discovery0_step(struct opal_dev *dev)
6840af2648eSDavid Kozub {
6850af2648eSDavid Kozub const struct opal_step discovery0_step = {
6869fb10726SGreg Joyce opal_discovery0, NULL
6870af2648eSDavid Kozub };
6885cc23ed7SRevanth Rajashekar
6890af2648eSDavid Kozub return execute_step(dev, &discovery0_step, 0);
6900af2648eSDavid Kozub }
6910af2648eSDavid Kozub
remaining_size(struct opal_dev * cmd)692a9b25b4cSJonas Rabenstein static size_t remaining_size(struct opal_dev *cmd)
693a9b25b4cSJonas Rabenstein {
694a9b25b4cSJonas Rabenstein return IO_BUFFER_LENGTH - cmd->pos;
695a9b25b4cSJonas Rabenstein }
696a9b25b4cSJonas Rabenstein
can_add(int * err,struct opal_dev * cmd,size_t len)697e2821a50SJonas Rabenstein static bool can_add(int *err, struct opal_dev *cmd, size_t len)
698455a7b23SScott Bauer {
699455a7b23SScott Bauer if (*err)
700e2821a50SJonas Rabenstein return false;
701e2821a50SJonas Rabenstein
702a9b25b4cSJonas Rabenstein if (remaining_size(cmd) < len) {
703e2821a50SJonas Rabenstein pr_debug("Error adding %zu bytes: end of buffer.\n", len);
704455a7b23SScott Bauer *err = -ERANGE;
705e2821a50SJonas Rabenstein return false;
706455a7b23SScott Bauer }
707e2821a50SJonas Rabenstein
708e2821a50SJonas Rabenstein return true;
709e2821a50SJonas Rabenstein }
710e2821a50SJonas Rabenstein
add_token_u8(int * err,struct opal_dev * cmd,u8 tok)711e2821a50SJonas Rabenstein static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
712e2821a50SJonas Rabenstein {
713e2821a50SJonas Rabenstein if (!can_add(err, cmd, 1))
714e2821a50SJonas Rabenstein return;
7155cc23ed7SRevanth Rajashekar
716455a7b23SScott Bauer cmd->cmd[cmd->pos++] = tok;
717455a7b23SScott Bauer }
718455a7b23SScott Bauer
add_short_atom_header(struct opal_dev * cmd,bool bytestring,bool has_sign,int len)719455a7b23SScott Bauer static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
720455a7b23SScott Bauer bool has_sign, int len)
721455a7b23SScott Bauer {
722455a7b23SScott Bauer u8 atom;
723455a7b23SScott Bauer int err = 0;
724455a7b23SScott Bauer
725455a7b23SScott Bauer atom = SHORT_ATOM_ID;
726455a7b23SScott Bauer atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
727455a7b23SScott Bauer atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
728455a7b23SScott Bauer atom |= len & SHORT_ATOM_LEN_MASK;
729455a7b23SScott Bauer
730455a7b23SScott Bauer add_token_u8(&err, cmd, atom);
731455a7b23SScott Bauer }
732455a7b23SScott Bauer
add_medium_atom_header(struct opal_dev * cmd,bool bytestring,bool has_sign,int len)733455a7b23SScott Bauer static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
734455a7b23SScott Bauer bool has_sign, int len)
735455a7b23SScott Bauer {
736455a7b23SScott Bauer u8 header0;
737455a7b23SScott Bauer
738455a7b23SScott Bauer header0 = MEDIUM_ATOM_ID;
739455a7b23SScott Bauer header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
740455a7b23SScott Bauer header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
741455a7b23SScott Bauer header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
7425cc23ed7SRevanth Rajashekar
743455a7b23SScott Bauer cmd->cmd[cmd->pos++] = header0;
744455a7b23SScott Bauer cmd->cmd[cmd->pos++] = len;
745455a7b23SScott Bauer }
746455a7b23SScott Bauer
add_token_u64(int * err,struct opal_dev * cmd,u64 number)747455a7b23SScott Bauer static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
748455a7b23SScott Bauer {
749455a7b23SScott Bauer size_t len;
750455a7b23SScott Bauer int msb;
751455a7b23SScott Bauer
752455a7b23SScott Bauer if (!(number & ~TINY_ATOM_DATA_MASK)) {
753455a7b23SScott Bauer add_token_u8(err, cmd, number);
754455a7b23SScott Bauer return;
755455a7b23SScott Bauer }
756455a7b23SScott Bauer
7575f990d31SJonas Rabenstein msb = fls64(number);
7585f990d31SJonas Rabenstein len = DIV_ROUND_UP(msb, 8);
759455a7b23SScott Bauer
760e2821a50SJonas Rabenstein if (!can_add(err, cmd, len + 1)) {
761591c59d1SScott Bauer pr_debug("Error adding u64: end of buffer.\n");
762455a7b23SScott Bauer return;
763455a7b23SScott Bauer }
764455a7b23SScott Bauer add_short_atom_header(cmd, false, false, len);
7655f990d31SJonas Rabenstein while (len--)
7665f990d31SJonas Rabenstein add_token_u8(err, cmd, number >> (len * 8));
767455a7b23SScott Bauer }
768455a7b23SScott Bauer
add_bytestring_header(int * err,struct opal_dev * cmd,size_t len)76928559959SJonas Rabenstein static u8 *add_bytestring_header(int *err, struct opal_dev *cmd, size_t len)
770455a7b23SScott Bauer {
771455a7b23SScott Bauer size_t header_len = 1;
772455a7b23SScott Bauer bool is_short_atom = true;
773455a7b23SScott Bauer
774455a7b23SScott Bauer if (len & ~SHORT_ATOM_LEN_MASK) {
775455a7b23SScott Bauer header_len = 2;
776455a7b23SScott Bauer is_short_atom = false;
777455a7b23SScott Bauer }
778455a7b23SScott Bauer
779e2821a50SJonas Rabenstein if (!can_add(err, cmd, header_len + len)) {
780591c59d1SScott Bauer pr_debug("Error adding bytestring: end of buffer.\n");
78128559959SJonas Rabenstein return NULL;
782455a7b23SScott Bauer }
783455a7b23SScott Bauer
784455a7b23SScott Bauer if (is_short_atom)
785455a7b23SScott Bauer add_short_atom_header(cmd, true, false, len);
786455a7b23SScott Bauer else
787455a7b23SScott Bauer add_medium_atom_header(cmd, true, false, len);
788455a7b23SScott Bauer
78928559959SJonas Rabenstein return &cmd->cmd[cmd->pos];
79028559959SJonas Rabenstein }
791455a7b23SScott Bauer
add_token_bytestring(int * err,struct opal_dev * cmd,const u8 * bytestring,size_t len)79228559959SJonas Rabenstein static void add_token_bytestring(int *err, struct opal_dev *cmd,
79328559959SJonas Rabenstein const u8 *bytestring, size_t len)
79428559959SJonas Rabenstein {
79528559959SJonas Rabenstein u8 *start;
79628559959SJonas Rabenstein
79728559959SJonas Rabenstein start = add_bytestring_header(err, cmd, len);
79828559959SJonas Rabenstein if (!start)
79928559959SJonas Rabenstein return;
80028559959SJonas Rabenstein memcpy(start, bytestring, len);
80128559959SJonas Rabenstein cmd->pos += len;
802455a7b23SScott Bauer }
803455a7b23SScott Bauer
build_locking_range(u8 * buffer,size_t length,u8 lr)804455a7b23SScott Bauer static int build_locking_range(u8 *buffer, size_t length, u8 lr)
805455a7b23SScott Bauer {
806455a7b23SScott Bauer if (length > OPAL_UID_LENGTH) {
807591c59d1SScott Bauer pr_debug("Can't build locking range. Length OOB\n");
808455a7b23SScott Bauer return -ERANGE;
809455a7b23SScott Bauer }
810455a7b23SScott Bauer
811455a7b23SScott Bauer memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
812455a7b23SScott Bauer
813455a7b23SScott Bauer if (lr == 0)
814455a7b23SScott Bauer return 0;
8155cc23ed7SRevanth Rajashekar
816455a7b23SScott Bauer buffer[5] = LOCKING_RANGE_NON_GLOBAL;
817455a7b23SScott Bauer buffer[7] = lr;
818455a7b23SScott Bauer
819455a7b23SScott Bauer return 0;
820455a7b23SScott Bauer }
821455a7b23SScott Bauer
build_locking_user(u8 * buffer,size_t length,u8 lr)822455a7b23SScott Bauer static int build_locking_user(u8 *buffer, size_t length, u8 lr)
823455a7b23SScott Bauer {
824455a7b23SScott Bauer if (length > OPAL_UID_LENGTH) {
8251e815b33SDavid Kozub pr_debug("Can't build locking range user. Length OOB\n");
826455a7b23SScott Bauer return -ERANGE;
827455a7b23SScott Bauer }
828455a7b23SScott Bauer
829455a7b23SScott Bauer memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
830455a7b23SScott Bauer
831455a7b23SScott Bauer buffer[7] = lr + 1;
832455a7b23SScott Bauer
833455a7b23SScott Bauer return 0;
834455a7b23SScott Bauer }
835455a7b23SScott Bauer
set_comid(struct opal_dev * cmd,u16 comid)836455a7b23SScott Bauer static void set_comid(struct opal_dev *cmd, u16 comid)
837455a7b23SScott Bauer {
838455a7b23SScott Bauer struct opal_header *hdr = (struct opal_header *)cmd->cmd;
839455a7b23SScott Bauer
840455a7b23SScott Bauer hdr->cp.extendedComID[0] = comid >> 8;
841455a7b23SScott Bauer hdr->cp.extendedComID[1] = comid;
842455a7b23SScott Bauer hdr->cp.extendedComID[2] = 0;
843455a7b23SScott Bauer hdr->cp.extendedComID[3] = 0;
844455a7b23SScott Bauer }
845455a7b23SScott Bauer
cmd_finalize(struct opal_dev * cmd,u32 hsn,u32 tsn)846455a7b23SScott Bauer static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
847455a7b23SScott Bauer {
848455a7b23SScott Bauer struct opal_header *hdr;
849455a7b23SScott Bauer int err = 0;
850455a7b23SScott Bauer
851a9b25b4cSJonas Rabenstein /*
852a9b25b4cSJonas Rabenstein * Close the parameter list opened from cmd_start.
853a9b25b4cSJonas Rabenstein * The number of bytes added must be equal to
854a9b25b4cSJonas Rabenstein * CMD_FINALIZE_BYTES_NEEDED.
855a9b25b4cSJonas Rabenstein */
85678d584caSDavid Kozub add_token_u8(&err, cmd, OPAL_ENDLIST);
85778d584caSDavid Kozub
858455a7b23SScott Bauer add_token_u8(&err, cmd, OPAL_ENDOFDATA);
859455a7b23SScott Bauer add_token_u8(&err, cmd, OPAL_STARTLIST);
860455a7b23SScott Bauer add_token_u8(&err, cmd, 0);
861455a7b23SScott Bauer add_token_u8(&err, cmd, 0);
862455a7b23SScott Bauer add_token_u8(&err, cmd, 0);
863455a7b23SScott Bauer add_token_u8(&err, cmd, OPAL_ENDLIST);
864455a7b23SScott Bauer
865455a7b23SScott Bauer if (err) {
866591c59d1SScott Bauer pr_debug("Error finalizing command.\n");
867455a7b23SScott Bauer return -EFAULT;
868455a7b23SScott Bauer }
869455a7b23SScott Bauer
870455a7b23SScott Bauer hdr = (struct opal_header *) cmd->cmd;
871455a7b23SScott Bauer
872455a7b23SScott Bauer hdr->pkt.tsn = cpu_to_be32(tsn);
873455a7b23SScott Bauer hdr->pkt.hsn = cpu_to_be32(hsn);
874455a7b23SScott Bauer
875455a7b23SScott Bauer hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
876455a7b23SScott Bauer while (cmd->pos % 4) {
877455a7b23SScott Bauer if (cmd->pos >= IO_BUFFER_LENGTH) {
878591c59d1SScott Bauer pr_debug("Error: Buffer overrun\n");
879455a7b23SScott Bauer return -ERANGE;
880455a7b23SScott Bauer }
881455a7b23SScott Bauer cmd->cmd[cmd->pos++] = 0;
882455a7b23SScott Bauer }
883455a7b23SScott Bauer hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
884455a7b23SScott Bauer sizeof(hdr->pkt));
885455a7b23SScott Bauer hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
886455a7b23SScott Bauer
887455a7b23SScott Bauer return 0;
888455a7b23SScott Bauer }
889455a7b23SScott Bauer
response_get_token(const struct parsed_resp * resp,int n)890cccb9241SJon Derrick static const struct opal_resp_tok *response_get_token(
891cccb9241SJon Derrick const struct parsed_resp *resp,
892455a7b23SScott Bauer int n)
893455a7b23SScott Bauer {
894455a7b23SScott Bauer const struct opal_resp_tok *tok;
895455a7b23SScott Bauer
8967d9b62aeSDavid Kozub if (!resp) {
8977d9b62aeSDavid Kozub pr_debug("Response is NULL\n");
8987d9b62aeSDavid Kozub return ERR_PTR(-EINVAL);
8997d9b62aeSDavid Kozub }
9007d9b62aeSDavid Kozub
901455a7b23SScott Bauer if (n >= resp->num) {
902591c59d1SScott Bauer pr_debug("Token number doesn't exist: %d, resp: %d\n",
903455a7b23SScott Bauer n, resp->num);
904cccb9241SJon Derrick return ERR_PTR(-EINVAL);
905455a7b23SScott Bauer }
906455a7b23SScott Bauer
907455a7b23SScott Bauer tok = &resp->toks[n];
908455a7b23SScott Bauer if (tok->len == 0) {
909591c59d1SScott Bauer pr_debug("Token length must be non-zero\n");
910cccb9241SJon Derrick return ERR_PTR(-EINVAL);
911455a7b23SScott Bauer }
912455a7b23SScott Bauer
913cccb9241SJon Derrick return tok;
914455a7b23SScott Bauer }
915455a7b23SScott Bauer
response_parse_tiny(struct opal_resp_tok * tok,const u8 * pos)916aedb6e24SJon Derrick static ssize_t response_parse_tiny(struct opal_resp_tok *tok,
917455a7b23SScott Bauer const u8 *pos)
918455a7b23SScott Bauer {
919455a7b23SScott Bauer tok->pos = pos;
920455a7b23SScott Bauer tok->len = 1;
921455a7b23SScott Bauer tok->width = OPAL_WIDTH_TINY;
922455a7b23SScott Bauer
923455a7b23SScott Bauer if (pos[0] & TINY_ATOM_SIGNED) {
924455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_SINT;
925455a7b23SScott Bauer } else {
926455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_UINT;
927455a7b23SScott Bauer tok->stored.u = pos[0] & 0x3f;
928455a7b23SScott Bauer }
929455a7b23SScott Bauer
930455a7b23SScott Bauer return tok->len;
931455a7b23SScott Bauer }
932455a7b23SScott Bauer
response_parse_short(struct opal_resp_tok * tok,const u8 * pos)933aedb6e24SJon Derrick static ssize_t response_parse_short(struct opal_resp_tok *tok,
934455a7b23SScott Bauer const u8 *pos)
935455a7b23SScott Bauer {
936455a7b23SScott Bauer tok->pos = pos;
937455a7b23SScott Bauer tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
938455a7b23SScott Bauer tok->width = OPAL_WIDTH_SHORT;
939455a7b23SScott Bauer
940455a7b23SScott Bauer if (pos[0] & SHORT_ATOM_BYTESTRING) {
941455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_BYTESTRING;
942455a7b23SScott Bauer } else if (pos[0] & SHORT_ATOM_SIGNED) {
943455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_SINT;
944455a7b23SScott Bauer } else {
945455a7b23SScott Bauer u64 u_integer = 0;
946aedb6e24SJon Derrick ssize_t i, b = 0;
947455a7b23SScott Bauer
948455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_UINT;
949455a7b23SScott Bauer if (tok->len > 9) {
950591c59d1SScott Bauer pr_debug("uint64 with more than 8 bytes\n");
951455a7b23SScott Bauer return -EINVAL;
952455a7b23SScott Bauer }
953455a7b23SScott Bauer for (i = tok->len - 1; i > 0; i--) {
954455a7b23SScott Bauer u_integer |= ((u64)pos[i] << (8 * b));
955455a7b23SScott Bauer b++;
956455a7b23SScott Bauer }
957455a7b23SScott Bauer tok->stored.u = u_integer;
958455a7b23SScott Bauer }
959455a7b23SScott Bauer
960455a7b23SScott Bauer return tok->len;
961455a7b23SScott Bauer }
962455a7b23SScott Bauer
response_parse_medium(struct opal_resp_tok * tok,const u8 * pos)963aedb6e24SJon Derrick static ssize_t response_parse_medium(struct opal_resp_tok *tok,
964455a7b23SScott Bauer const u8 *pos)
965455a7b23SScott Bauer {
966455a7b23SScott Bauer tok->pos = pos;
967455a7b23SScott Bauer tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
968455a7b23SScott Bauer tok->width = OPAL_WIDTH_MEDIUM;
969455a7b23SScott Bauer
970455a7b23SScott Bauer if (pos[0] & MEDIUM_ATOM_BYTESTRING)
971455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_BYTESTRING;
972455a7b23SScott Bauer else if (pos[0] & MEDIUM_ATOM_SIGNED)
973455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_SINT;
974455a7b23SScott Bauer else
975455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_UINT;
976455a7b23SScott Bauer
977455a7b23SScott Bauer return tok->len;
978455a7b23SScott Bauer }
979455a7b23SScott Bauer
response_parse_long(struct opal_resp_tok * tok,const u8 * pos)980aedb6e24SJon Derrick static ssize_t response_parse_long(struct opal_resp_tok *tok,
981455a7b23SScott Bauer const u8 *pos)
982455a7b23SScott Bauer {
983455a7b23SScott Bauer tok->pos = pos;
984455a7b23SScott Bauer tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
985455a7b23SScott Bauer tok->width = OPAL_WIDTH_LONG;
986455a7b23SScott Bauer
987455a7b23SScott Bauer if (pos[0] & LONG_ATOM_BYTESTRING)
988455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_BYTESTRING;
989455a7b23SScott Bauer else if (pos[0] & LONG_ATOM_SIGNED)
990455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_SINT;
991455a7b23SScott Bauer else
992455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_UINT;
993455a7b23SScott Bauer
994455a7b23SScott Bauer return tok->len;
995455a7b23SScott Bauer }
996455a7b23SScott Bauer
response_parse_token(struct opal_resp_tok * tok,const u8 * pos)997aedb6e24SJon Derrick static ssize_t response_parse_token(struct opal_resp_tok *tok,
998455a7b23SScott Bauer const u8 *pos)
999455a7b23SScott Bauer {
1000455a7b23SScott Bauer tok->pos = pos;
1001455a7b23SScott Bauer tok->len = 1;
1002455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_TOKEN;
1003455a7b23SScott Bauer tok->width = OPAL_WIDTH_TOKEN;
1004455a7b23SScott Bauer
1005455a7b23SScott Bauer return tok->len;
1006455a7b23SScott Bauer }
1007455a7b23SScott Bauer
response_parse(const u8 * buf,size_t length,struct parsed_resp * resp)1008455a7b23SScott Bauer static int response_parse(const u8 *buf, size_t length,
1009455a7b23SScott Bauer struct parsed_resp *resp)
1010455a7b23SScott Bauer {
1011455a7b23SScott Bauer const struct opal_header *hdr;
1012455a7b23SScott Bauer struct opal_resp_tok *iter;
1013455a7b23SScott Bauer int num_entries = 0;
1014455a7b23SScott Bauer int total;
1015aedb6e24SJon Derrick ssize_t token_length;
1016455a7b23SScott Bauer const u8 *pos;
101777039b96SJon Derrick u32 clen, plen, slen;
1018455a7b23SScott Bauer
1019455a7b23SScott Bauer if (!buf)
1020455a7b23SScott Bauer return -EFAULT;
1021455a7b23SScott Bauer
1022455a7b23SScott Bauer if (!resp)
1023455a7b23SScott Bauer return -EFAULT;
1024455a7b23SScott Bauer
1025455a7b23SScott Bauer hdr = (struct opal_header *)buf;
1026455a7b23SScott Bauer pos = buf;
1027455a7b23SScott Bauer pos += sizeof(*hdr);
1028455a7b23SScott Bauer
102977039b96SJon Derrick clen = be32_to_cpu(hdr->cp.length);
103077039b96SJon Derrick plen = be32_to_cpu(hdr->pkt.length);
103177039b96SJon Derrick slen = be32_to_cpu(hdr->subpkt.length);
103277039b96SJon Derrick pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n",
103377039b96SJon Derrick clen, plen, slen);
1034455a7b23SScott Bauer
103577039b96SJon Derrick if (clen == 0 || plen == 0 || slen == 0 ||
103677039b96SJon Derrick slen > IO_BUFFER_LENGTH - sizeof(*hdr)) {
1037591c59d1SScott Bauer pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n",
103877039b96SJon Derrick clen, plen, slen);
1039455a7b23SScott Bauer print_buffer(pos, sizeof(*hdr));
1040455a7b23SScott Bauer return -EINVAL;
1041455a7b23SScott Bauer }
1042455a7b23SScott Bauer
1043455a7b23SScott Bauer if (pos > buf + length)
1044455a7b23SScott Bauer return -EFAULT;
1045455a7b23SScott Bauer
1046455a7b23SScott Bauer iter = resp->toks;
104777039b96SJon Derrick total = slen;
1048455a7b23SScott Bauer print_buffer(pos, total);
1049455a7b23SScott Bauer while (total > 0) {
1050455a7b23SScott Bauer if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
1051455a7b23SScott Bauer token_length = response_parse_tiny(iter, pos);
1052455a7b23SScott Bauer else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
1053455a7b23SScott Bauer token_length = response_parse_short(iter, pos);
1054455a7b23SScott Bauer else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
1055455a7b23SScott Bauer token_length = response_parse_medium(iter, pos);
1056455a7b23SScott Bauer else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
1057455a7b23SScott Bauer token_length = response_parse_long(iter, pos);
1058031b6233SGreg Joyce else if (pos[0] == EMPTY_ATOM_BYTE) /* empty atom */
1059031b6233SGreg Joyce token_length = 1;
1060455a7b23SScott Bauer else /* TOKEN */
1061455a7b23SScott Bauer token_length = response_parse_token(iter, pos);
1062455a7b23SScott Bauer
1063aedb6e24SJon Derrick if (token_length < 0)
1064aedb6e24SJon Derrick return token_length;
1065455a7b23SScott Bauer
1066031b6233SGreg Joyce if (pos[0] != EMPTY_ATOM_BYTE)
1067031b6233SGreg Joyce num_entries++;
1068031b6233SGreg Joyce
1069455a7b23SScott Bauer pos += token_length;
1070455a7b23SScott Bauer total -= token_length;
1071455a7b23SScott Bauer iter++;
1072455a7b23SScott Bauer }
1073455a7b23SScott Bauer
1074455a7b23SScott Bauer resp->num = num_entries;
1075455a7b23SScott Bauer
1076455a7b23SScott Bauer return 0;
1077455a7b23SScott Bauer }
1078455a7b23SScott Bauer
response_get_string(const struct parsed_resp * resp,int n,const char ** store)1079455a7b23SScott Bauer static size_t response_get_string(const struct parsed_resp *resp, int n,
1080455a7b23SScott Bauer const char **store)
1081455a7b23SScott Bauer {
1082d15e1175SJonas Rabenstein u8 skip;
1083b68f09ecSDavid Kozub const struct opal_resp_tok *tok;
1084d15e1175SJonas Rabenstein
1085455a7b23SScott Bauer *store = NULL;
1086b68f09ecSDavid Kozub tok = response_get_token(resp, n);
1087b68f09ecSDavid Kozub if (IS_ERR(tok))
1088455a7b23SScott Bauer return 0;
1089455a7b23SScott Bauer
1090b68f09ecSDavid Kozub if (tok->type != OPAL_DTA_TOKENID_BYTESTRING) {
1091591c59d1SScott Bauer pr_debug("Token is not a byte string!\n");
1092455a7b23SScott Bauer return 0;
1093455a7b23SScott Bauer }
1094455a7b23SScott Bauer
1095b68f09ecSDavid Kozub switch (tok->width) {
1096d15e1175SJonas Rabenstein case OPAL_WIDTH_TINY:
1097d15e1175SJonas Rabenstein case OPAL_WIDTH_SHORT:
1098d15e1175SJonas Rabenstein skip = 1;
1099d15e1175SJonas Rabenstein break;
1100d15e1175SJonas Rabenstein case OPAL_WIDTH_MEDIUM:
1101d15e1175SJonas Rabenstein skip = 2;
1102d15e1175SJonas Rabenstein break;
1103d15e1175SJonas Rabenstein case OPAL_WIDTH_LONG:
1104d15e1175SJonas Rabenstein skip = 4;
1105d15e1175SJonas Rabenstein break;
1106d15e1175SJonas Rabenstein default:
1107d15e1175SJonas Rabenstein pr_debug("Token has invalid width!\n");
1108d15e1175SJonas Rabenstein return 0;
1109d15e1175SJonas Rabenstein }
1110d15e1175SJonas Rabenstein
1111b68f09ecSDavid Kozub *store = tok->pos + skip;
11125cc23ed7SRevanth Rajashekar
1113b68f09ecSDavid Kozub return tok->len - skip;
1114455a7b23SScott Bauer }
1115455a7b23SScott Bauer
response_get_u64(const struct parsed_resp * resp,int n)1116455a7b23SScott Bauer static u64 response_get_u64(const struct parsed_resp *resp, int n)
1117455a7b23SScott Bauer {
1118b68f09ecSDavid Kozub const struct opal_resp_tok *tok;
1119b68f09ecSDavid Kozub
1120b68f09ecSDavid Kozub tok = response_get_token(resp, n);
1121b68f09ecSDavid Kozub if (IS_ERR(tok))
1122b68f09ecSDavid Kozub return 0;
1123b68f09ecSDavid Kozub
1124b68f09ecSDavid Kozub if (tok->type != OPAL_DTA_TOKENID_UINT) {
1125b68f09ecSDavid Kozub pr_debug("Token is not unsigned int: %d\n", tok->type);
1126455a7b23SScott Bauer return 0;
1127455a7b23SScott Bauer }
1128455a7b23SScott Bauer
1129b68f09ecSDavid Kozub if (tok->width != OPAL_WIDTH_TINY && tok->width != OPAL_WIDTH_SHORT) {
1130b68f09ecSDavid Kozub pr_debug("Atom is not short or tiny: %d\n", tok->width);
1131455a7b23SScott Bauer return 0;
1132455a7b23SScott Bauer }
1133455a7b23SScott Bauer
1134b68f09ecSDavid Kozub return tok->stored.u;
1135455a7b23SScott Bauer }
1136455a7b23SScott Bauer
response_token_matches(const struct opal_resp_tok * token,u8 match)1137cccb9241SJon Derrick static bool response_token_matches(const struct opal_resp_tok *token, u8 match)
1138cccb9241SJon Derrick {
1139cccb9241SJon Derrick if (IS_ERR(token) ||
1140cccb9241SJon Derrick token->type != OPAL_DTA_TOKENID_TOKEN ||
1141cccb9241SJon Derrick token->pos[0] != match)
1142cccb9241SJon Derrick return false;
1143cccb9241SJon Derrick return true;
1144cccb9241SJon Derrick }
1145cccb9241SJon Derrick
response_status(const struct parsed_resp * resp)1146455a7b23SScott Bauer static u8 response_status(const struct parsed_resp *resp)
1147455a7b23SScott Bauer {
1148cccb9241SJon Derrick const struct opal_resp_tok *tok;
1149cccb9241SJon Derrick
1150cccb9241SJon Derrick tok = response_get_token(resp, 0);
1151cccb9241SJon Derrick if (response_token_matches(tok, OPAL_ENDOFSESSION))
1152455a7b23SScott Bauer return 0;
1153455a7b23SScott Bauer
1154455a7b23SScott Bauer if (resp->num < 5)
1155455a7b23SScott Bauer return DTAERROR_NO_METHOD_STATUS;
1156455a7b23SScott Bauer
1157cccb9241SJon Derrick tok = response_get_token(resp, resp->num - 5);
1158cccb9241SJon Derrick if (!response_token_matches(tok, OPAL_STARTLIST))
1159cccb9241SJon Derrick return DTAERROR_NO_METHOD_STATUS;
1160cccb9241SJon Derrick
1161cccb9241SJon Derrick tok = response_get_token(resp, resp->num - 1);
1162cccb9241SJon Derrick if (!response_token_matches(tok, OPAL_ENDLIST))
1163455a7b23SScott Bauer return DTAERROR_NO_METHOD_STATUS;
1164455a7b23SScott Bauer
1165455a7b23SScott Bauer return response_get_u64(resp, resp->num - 4);
1166455a7b23SScott Bauer }
1167455a7b23SScott Bauer
1168455a7b23SScott Bauer /* Parses and checks for errors */
parse_and_check_status(struct opal_dev * dev)1169455a7b23SScott Bauer static int parse_and_check_status(struct opal_dev *dev)
1170455a7b23SScott Bauer {
1171455a7b23SScott Bauer int error;
1172455a7b23SScott Bauer
1173455a7b23SScott Bauer print_buffer(dev->cmd, dev->pos);
1174455a7b23SScott Bauer
1175455a7b23SScott Bauer error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
1176455a7b23SScott Bauer if (error) {
1177591c59d1SScott Bauer pr_debug("Couldn't parse response.\n");
1178455a7b23SScott Bauer return error;
1179455a7b23SScott Bauer }
1180455a7b23SScott Bauer
1181455a7b23SScott Bauer return response_status(&dev->parsed);
1182455a7b23SScott Bauer }
1183455a7b23SScott Bauer
clear_opal_cmd(struct opal_dev * dev)1184455a7b23SScott Bauer static void clear_opal_cmd(struct opal_dev *dev)
1185455a7b23SScott Bauer {
1186455a7b23SScott Bauer dev->pos = sizeof(struct opal_header);
1187455a7b23SScott Bauer memset(dev->cmd, 0, IO_BUFFER_LENGTH);
1188455a7b23SScott Bauer }
1189455a7b23SScott Bauer
cmd_start(struct opal_dev * dev,const u8 * uid,const u8 * method)1190e8b29224SDavid Kozub static int cmd_start(struct opal_dev *dev, const u8 *uid, const u8 *method)
1191e8b29224SDavid Kozub {
1192e8b29224SDavid Kozub int err = 0;
1193e8b29224SDavid Kozub
1194e8b29224SDavid Kozub clear_opal_cmd(dev);
1195e8b29224SDavid Kozub set_comid(dev, dev->comid);
1196e8b29224SDavid Kozub
1197e8b29224SDavid Kozub add_token_u8(&err, dev, OPAL_CALL);
1198e8b29224SDavid Kozub add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
1199e8b29224SDavid Kozub add_token_bytestring(&err, dev, method, OPAL_METHOD_LENGTH);
1200e8b29224SDavid Kozub
1201e8b29224SDavid Kozub /*
1202e8b29224SDavid Kozub * Every method call is followed by its parameters enclosed within
1203e8b29224SDavid Kozub * OPAL_STARTLIST and OPAL_ENDLIST tokens. We automatically open the
1204e8b29224SDavid Kozub * parameter list here and close it later in cmd_finalize.
1205e8b29224SDavid Kozub */
1206e8b29224SDavid Kozub add_token_u8(&err, dev, OPAL_STARTLIST);
1207e8b29224SDavid Kozub
1208e8b29224SDavid Kozub return err;
1209e8b29224SDavid Kozub }
1210e8b29224SDavid Kozub
start_opal_session_cont(struct opal_dev * dev)1211455a7b23SScott Bauer static int start_opal_session_cont(struct opal_dev *dev)
1212455a7b23SScott Bauer {
1213455a7b23SScott Bauer u32 hsn, tsn;
1214455a7b23SScott Bauer int error = 0;
1215455a7b23SScott Bauer
1216455a7b23SScott Bauer error = parse_and_check_status(dev);
1217455a7b23SScott Bauer if (error)
1218455a7b23SScott Bauer return error;
1219455a7b23SScott Bauer
1220455a7b23SScott Bauer hsn = response_get_u64(&dev->parsed, 4);
1221455a7b23SScott Bauer tsn = response_get_u64(&dev->parsed, 5);
1222455a7b23SScott Bauer
122388d6041dSRevanth Rajashekar if (hsn != GENERIC_HOST_SESSION_NUM || tsn < FIRST_TPER_SESSION_NUM) {
1224591c59d1SScott Bauer pr_debug("Couldn't authenticate session\n");
1225455a7b23SScott Bauer return -EPERM;
1226455a7b23SScott Bauer }
1227455a7b23SScott Bauer
1228455a7b23SScott Bauer dev->hsn = hsn;
1229455a7b23SScott Bauer dev->tsn = tsn;
12305cc23ed7SRevanth Rajashekar
1231455a7b23SScott Bauer return 0;
1232455a7b23SScott Bauer }
1233455a7b23SScott Bauer
add_suspend_info(struct opal_dev * dev,struct opal_suspend_data * sus)1234455a7b23SScott Bauer static void add_suspend_info(struct opal_dev *dev,
1235455a7b23SScott Bauer struct opal_suspend_data *sus)
1236455a7b23SScott Bauer {
1237455a7b23SScott Bauer struct opal_suspend_data *iter;
1238455a7b23SScott Bauer
1239455a7b23SScott Bauer list_for_each_entry(iter, &dev->unlk_lst, node) {
1240455a7b23SScott Bauer if (iter->lr == sus->lr) {
1241455a7b23SScott Bauer list_del(&iter->node);
1242455a7b23SScott Bauer kfree(iter);
1243455a7b23SScott Bauer break;
1244455a7b23SScott Bauer }
1245455a7b23SScott Bauer }
1246455a7b23SScott Bauer list_add_tail(&sus->node, &dev->unlk_lst);
1247455a7b23SScott Bauer }
1248455a7b23SScott Bauer
end_session_cont(struct opal_dev * dev)1249455a7b23SScott Bauer static int end_session_cont(struct opal_dev *dev)
1250455a7b23SScott Bauer {
1251455a7b23SScott Bauer dev->hsn = 0;
1252455a7b23SScott Bauer dev->tsn = 0;
12535cc23ed7SRevanth Rajashekar
1254455a7b23SScott Bauer return parse_and_check_status(dev);
1255455a7b23SScott Bauer }
1256455a7b23SScott Bauer
finalize_and_send(struct opal_dev * dev,cont_fn cont)1257455a7b23SScott Bauer static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
1258455a7b23SScott Bauer {
1259455a7b23SScott Bauer int ret;
1260455a7b23SScott Bauer
1261455a7b23SScott Bauer ret = cmd_finalize(dev, dev->hsn, dev->tsn);
1262455a7b23SScott Bauer if (ret) {
1263591c59d1SScott Bauer pr_debug("Error finalizing command buffer: %d\n", ret);
1264455a7b23SScott Bauer return ret;
1265455a7b23SScott Bauer }
1266455a7b23SScott Bauer
1267455a7b23SScott Bauer print_buffer(dev->cmd, dev->pos);
1268455a7b23SScott Bauer
1269455a7b23SScott Bauer return opal_send_recv(dev, cont);
1270455a7b23SScott Bauer }
1271455a7b23SScott Bauer
generic_get_columns(struct opal_dev * dev,const u8 * table,u64 start_column,u64 end_column)1272baf82b67SOndrej Kozina static int generic_get_columns(struct opal_dev *dev, const u8 *table,
1273baf82b67SOndrej Kozina u64 start_column, u64 end_column)
12743fff234bSDavid Kozub {
12753fff234bSDavid Kozub int err;
12763fff234bSDavid Kozub
12773fff234bSDavid Kozub err = cmd_start(dev, table, opalmethod[OPAL_GET]);
12783fff234bSDavid Kozub
12793fff234bSDavid Kozub add_token_u8(&err, dev, OPAL_STARTLIST);
12803fff234bSDavid Kozub
12813fff234bSDavid Kozub add_token_u8(&err, dev, OPAL_STARTNAME);
12823fff234bSDavid Kozub add_token_u8(&err, dev, OPAL_STARTCOLUMN);
1283baf82b67SOndrej Kozina add_token_u64(&err, dev, start_column);
12843fff234bSDavid Kozub add_token_u8(&err, dev, OPAL_ENDNAME);
12853fff234bSDavid Kozub
12863fff234bSDavid Kozub add_token_u8(&err, dev, OPAL_STARTNAME);
12873fff234bSDavid Kozub add_token_u8(&err, dev, OPAL_ENDCOLUMN);
1288baf82b67SOndrej Kozina add_token_u64(&err, dev, end_column);
12893fff234bSDavid Kozub add_token_u8(&err, dev, OPAL_ENDNAME);
12903fff234bSDavid Kozub
12913fff234bSDavid Kozub add_token_u8(&err, dev, OPAL_ENDLIST);
12923fff234bSDavid Kozub
12933fff234bSDavid Kozub if (err)
12943fff234bSDavid Kozub return err;
12953fff234bSDavid Kozub
12963fff234bSDavid Kozub return finalize_and_send(dev, parse_and_check_status);
12973fff234bSDavid Kozub }
12983fff234bSDavid Kozub
1299ff91064eSJonas Rabenstein /*
1300baf82b67SOndrej Kozina * request @column from table @table on device @dev. On success, the column
1301baf82b67SOndrej Kozina * data will be available in dev->resp->tok[4]
1302baf82b67SOndrej Kozina */
generic_get_column(struct opal_dev * dev,const u8 * table,u64 column)1303baf82b67SOndrej Kozina static int generic_get_column(struct opal_dev *dev, const u8 *table,
1304baf82b67SOndrej Kozina u64 column)
1305baf82b67SOndrej Kozina {
1306baf82b67SOndrej Kozina return generic_get_columns(dev, table, column, column);
1307baf82b67SOndrej Kozina }
1308baf82b67SOndrej Kozina
1309baf82b67SOndrej Kozina /*
1310ff91064eSJonas Rabenstein * see TCG SAS 5.3.2.3 for a description of the available columns
1311ff91064eSJonas Rabenstein *
1312ff91064eSJonas Rabenstein * the result is provided in dev->resp->tok[4]
1313ff91064eSJonas Rabenstein */
generic_get_table_info(struct opal_dev * dev,const u8 * table_uid,u64 column)13143495ea1bSRevanth Rajashekar static int generic_get_table_info(struct opal_dev *dev, const u8 *table_uid,
1315ff91064eSJonas Rabenstein u64 column)
1316ff91064eSJonas Rabenstein {
1317ff91064eSJonas Rabenstein u8 uid[OPAL_UID_LENGTH];
13183495ea1bSRevanth Rajashekar const unsigned int half = OPAL_UID_LENGTH_HALF;
1319ff91064eSJonas Rabenstein
1320ff91064eSJonas Rabenstein /* sed-opal UIDs can be split in two halves:
1321ff91064eSJonas Rabenstein * first: actual table index
1322ff91064eSJonas Rabenstein * second: relative index in the table
1323ff91064eSJonas Rabenstein * so we have to get the first half of the OPAL_TABLE_TABLE and use the
1324ff91064eSJonas Rabenstein * first part of the target table as relative index into that table
1325ff91064eSJonas Rabenstein */
1326ff91064eSJonas Rabenstein memcpy(uid, opaluid[OPAL_TABLE_TABLE], half);
13273495ea1bSRevanth Rajashekar memcpy(uid + half, table_uid, half);
1328ff91064eSJonas Rabenstein
1329ff91064eSJonas Rabenstein return generic_get_column(dev, uid, column);
1330ff91064eSJonas Rabenstein }
1331ff91064eSJonas Rabenstein
gen_key(struct opal_dev * dev,void * data)1332eed64951SJon Derrick static int gen_key(struct opal_dev *dev, void *data)
1333455a7b23SScott Bauer {
1334455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH];
1335e8b29224SDavid Kozub int err;
1336455a7b23SScott Bauer
1337455a7b23SScott Bauer memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
1338455a7b23SScott Bauer kfree(dev->prev_data);
1339455a7b23SScott Bauer dev->prev_data = NULL;
1340455a7b23SScott Bauer
1341e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_GENKEY]);
1342455a7b23SScott Bauer
1343455a7b23SScott Bauer if (err) {
1344591c59d1SScott Bauer pr_debug("Error building gen key command\n");
1345455a7b23SScott Bauer return err;
1346455a7b23SScott Bauer
1347455a7b23SScott Bauer }
13485cc23ed7SRevanth Rajashekar
1349455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
1350455a7b23SScott Bauer }
1351455a7b23SScott Bauer
get_active_key_cont(struct opal_dev * dev)1352455a7b23SScott Bauer static int get_active_key_cont(struct opal_dev *dev)
1353455a7b23SScott Bauer {
1354455a7b23SScott Bauer const char *activekey;
1355455a7b23SScott Bauer size_t keylen;
1356455a7b23SScott Bauer int error = 0;
1357455a7b23SScott Bauer
1358455a7b23SScott Bauer error = parse_and_check_status(dev);
1359455a7b23SScott Bauer if (error)
1360455a7b23SScott Bauer return error;
13615cc23ed7SRevanth Rajashekar
1362455a7b23SScott Bauer keylen = response_get_string(&dev->parsed, 4, &activekey);
1363455a7b23SScott Bauer if (!activekey) {
1364591c59d1SScott Bauer pr_debug("%s: Couldn't extract the Activekey from the response\n",
1365455a7b23SScott Bauer __func__);
1366455a7b23SScott Bauer return OPAL_INVAL_PARAM;
1367455a7b23SScott Bauer }
13685cc23ed7SRevanth Rajashekar
1369455a7b23SScott Bauer dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
1370455a7b23SScott Bauer
1371455a7b23SScott Bauer if (!dev->prev_data)
1372455a7b23SScott Bauer return -ENOMEM;
1373455a7b23SScott Bauer
1374455a7b23SScott Bauer dev->prev_d_len = keylen;
1375455a7b23SScott Bauer
1376455a7b23SScott Bauer return 0;
1377455a7b23SScott Bauer }
1378455a7b23SScott Bauer
get_active_key(struct opal_dev * dev,void * data)1379eed64951SJon Derrick static int get_active_key(struct opal_dev *dev, void *data)
1380455a7b23SScott Bauer {
1381455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH];
1382e8b29224SDavid Kozub int err;
1383eed64951SJon Derrick u8 *lr = data;
1384455a7b23SScott Bauer
1385455a7b23SScott Bauer err = build_locking_range(uid, sizeof(uid), *lr);
1386455a7b23SScott Bauer if (err)
1387455a7b23SScott Bauer return err;
1388455a7b23SScott Bauer
13893fff234bSDavid Kozub err = generic_get_column(dev, uid, OPAL_ACTIVEKEY);
13903fff234bSDavid Kozub if (err)
1391455a7b23SScott Bauer return err;
1392455a7b23SScott Bauer
13933fff234bSDavid Kozub return get_active_key_cont(dev);
1394455a7b23SScott Bauer }
1395455a7b23SScott Bauer
generic_table_write_data(struct opal_dev * dev,const u64 data,u64 offset,u64 size,const u8 * uid)13963495ea1bSRevanth Rajashekar static int generic_table_write_data(struct opal_dev *dev, const u64 data,
13973495ea1bSRevanth Rajashekar u64 offset, u64 size, const u8 *uid)
13983495ea1bSRevanth Rajashekar {
13993495ea1bSRevanth Rajashekar const u8 __user *src = (u8 __user *)(uintptr_t)data;
14003495ea1bSRevanth Rajashekar u8 *dst;
14013495ea1bSRevanth Rajashekar u64 len;
14023495ea1bSRevanth Rajashekar size_t off = 0;
14033495ea1bSRevanth Rajashekar int err;
14043495ea1bSRevanth Rajashekar
14053495ea1bSRevanth Rajashekar /* do we fit in the available space? */
14063495ea1bSRevanth Rajashekar err = generic_get_table_info(dev, uid, OPAL_TABLE_ROWS);
14073495ea1bSRevanth Rajashekar if (err) {
14083495ea1bSRevanth Rajashekar pr_debug("Couldn't get the table size\n");
14093495ea1bSRevanth Rajashekar return err;
14103495ea1bSRevanth Rajashekar }
14113495ea1bSRevanth Rajashekar
14123495ea1bSRevanth Rajashekar len = response_get_u64(&dev->parsed, 4);
14133495ea1bSRevanth Rajashekar if (size > len || offset > len - size) {
14143495ea1bSRevanth Rajashekar pr_debug("Does not fit in the table (%llu vs. %llu)\n",
14153495ea1bSRevanth Rajashekar offset + size, len);
14163495ea1bSRevanth Rajashekar return -ENOSPC;
14173495ea1bSRevanth Rajashekar }
14183495ea1bSRevanth Rajashekar
14193495ea1bSRevanth Rajashekar /* do the actual transmission(s) */
14203495ea1bSRevanth Rajashekar while (off < size) {
14213495ea1bSRevanth Rajashekar err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
14223495ea1bSRevanth Rajashekar add_token_u8(&err, dev, OPAL_STARTNAME);
14233495ea1bSRevanth Rajashekar add_token_u8(&err, dev, OPAL_WHERE);
14243495ea1bSRevanth Rajashekar add_token_u64(&err, dev, offset + off);
14253495ea1bSRevanth Rajashekar add_token_u8(&err, dev, OPAL_ENDNAME);
14263495ea1bSRevanth Rajashekar
14273495ea1bSRevanth Rajashekar add_token_u8(&err, dev, OPAL_STARTNAME);
14283495ea1bSRevanth Rajashekar add_token_u8(&err, dev, OPAL_VALUES);
14293495ea1bSRevanth Rajashekar
14303495ea1bSRevanth Rajashekar /*
14313495ea1bSRevanth Rajashekar * The bytestring header is either 1 or 2 bytes, so assume 2.
14323495ea1bSRevanth Rajashekar * There also needs to be enough space to accommodate the
14333495ea1bSRevanth Rajashekar * trailing OPAL_ENDNAME (1 byte) and tokens added by
14343495ea1bSRevanth Rajashekar * cmd_finalize.
14353495ea1bSRevanth Rajashekar */
14363495ea1bSRevanth Rajashekar len = min(remaining_size(dev) - (2+1+CMD_FINALIZE_BYTES_NEEDED),
14373495ea1bSRevanth Rajashekar (size_t)(size - off));
14383495ea1bSRevanth Rajashekar pr_debug("Write bytes %zu+%llu/%llu\n", off, len, size);
14393495ea1bSRevanth Rajashekar
14403495ea1bSRevanth Rajashekar dst = add_bytestring_header(&err, dev, len);
14413495ea1bSRevanth Rajashekar if (!dst)
14423495ea1bSRevanth Rajashekar break;
14433495ea1bSRevanth Rajashekar
14443495ea1bSRevanth Rajashekar if (copy_from_user(dst, src + off, len)) {
14453495ea1bSRevanth Rajashekar err = -EFAULT;
14463495ea1bSRevanth Rajashekar break;
14473495ea1bSRevanth Rajashekar }
14483495ea1bSRevanth Rajashekar
14493495ea1bSRevanth Rajashekar dev->pos += len;
14503495ea1bSRevanth Rajashekar
14513495ea1bSRevanth Rajashekar add_token_u8(&err, dev, OPAL_ENDNAME);
14523495ea1bSRevanth Rajashekar if (err)
14533495ea1bSRevanth Rajashekar break;
14543495ea1bSRevanth Rajashekar
14553495ea1bSRevanth Rajashekar err = finalize_and_send(dev, parse_and_check_status);
14563495ea1bSRevanth Rajashekar if (err)
14573495ea1bSRevanth Rajashekar break;
14583495ea1bSRevanth Rajashekar
14593495ea1bSRevanth Rajashekar off += len;
14603495ea1bSRevanth Rajashekar }
14613495ea1bSRevanth Rajashekar
14623495ea1bSRevanth Rajashekar return err;
14633495ea1bSRevanth Rajashekar }
14643495ea1bSRevanth Rajashekar
generic_lr_enable_disable(struct opal_dev * dev,u8 * uid,bool rle,bool wle,bool rl,bool wl)1465455a7b23SScott Bauer static int generic_lr_enable_disable(struct opal_dev *dev,
1466455a7b23SScott Bauer u8 *uid, bool rle, bool wle,
1467455a7b23SScott Bauer bool rl, bool wl)
1468455a7b23SScott Bauer {
1469e8b29224SDavid Kozub int err;
1470455a7b23SScott Bauer
1471e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
1472455a7b23SScott Bauer
1473455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1474455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES);
1475455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
1476455a7b23SScott Bauer
1477455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1478372be408SDavid Kozub add_token_u8(&err, dev, OPAL_READLOCKENABLED);
1479455a7b23SScott Bauer add_token_u8(&err, dev, rle);
1480455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1481455a7b23SScott Bauer
1482455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1483372be408SDavid Kozub add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
1484455a7b23SScott Bauer add_token_u8(&err, dev, wle);
1485455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1486455a7b23SScott Bauer
1487455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1488455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_READLOCKED);
1489455a7b23SScott Bauer add_token_u8(&err, dev, rl);
1490455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1491455a7b23SScott Bauer
1492455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1493455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_WRITELOCKED);
1494455a7b23SScott Bauer add_token_u8(&err, dev, wl);
1495455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1496455a7b23SScott Bauer
1497455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
1498455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
14995cc23ed7SRevanth Rajashekar
1500455a7b23SScott Bauer return err;
1501455a7b23SScott Bauer }
1502455a7b23SScott Bauer
enable_global_lr(struct opal_dev * dev,u8 * uid,struct opal_user_lr_setup * setup)1503455a7b23SScott Bauer static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
1504455a7b23SScott Bauer struct opal_user_lr_setup *setup)
1505455a7b23SScott Bauer {
1506455a7b23SScott Bauer int err;
1507455a7b23SScott Bauer
1508455a7b23SScott Bauer err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
1509455a7b23SScott Bauer 0, 0);
1510455a7b23SScott Bauer if (err)
1511591c59d1SScott Bauer pr_debug("Failed to create enable global lr command\n");
15125cc23ed7SRevanth Rajashekar
1513455a7b23SScott Bauer return err;
1514455a7b23SScott Bauer }
1515455a7b23SScott Bauer
setup_locking_range(struct opal_dev * dev,void * data)1516eed64951SJon Derrick static int setup_locking_range(struct opal_dev *dev, void *data)
1517455a7b23SScott Bauer {
1518455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH];
1519eed64951SJon Derrick struct opal_user_lr_setup *setup = data;
1520455a7b23SScott Bauer u8 lr;
1521e8b29224SDavid Kozub int err;
1522455a7b23SScott Bauer
1523455a7b23SScott Bauer lr = setup->session.opal_key.lr;
1524455a7b23SScott Bauer err = build_locking_range(uid, sizeof(uid), lr);
1525455a7b23SScott Bauer if (err)
1526455a7b23SScott Bauer return err;
1527455a7b23SScott Bauer
1528455a7b23SScott Bauer if (lr == 0)
1529455a7b23SScott Bauer err = enable_global_lr(dev, uid, setup);
1530455a7b23SScott Bauer else {
1531e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
1532455a7b23SScott Bauer
1533455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1534455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES);
1535455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
1536455a7b23SScott Bauer
1537455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1538372be408SDavid Kozub add_token_u8(&err, dev, OPAL_RANGESTART);
1539455a7b23SScott Bauer add_token_u64(&err, dev, setup->range_start);
1540455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1541455a7b23SScott Bauer
1542455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1543372be408SDavid Kozub add_token_u8(&err, dev, OPAL_RANGELENGTH);
1544455a7b23SScott Bauer add_token_u64(&err, dev, setup->range_length);
1545455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1546455a7b23SScott Bauer
1547455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1548372be408SDavid Kozub add_token_u8(&err, dev, OPAL_READLOCKENABLED);
1549455a7b23SScott Bauer add_token_u64(&err, dev, !!setup->RLE);
1550455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1551455a7b23SScott Bauer
1552455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1553372be408SDavid Kozub add_token_u8(&err, dev, OPAL_WRITELOCKENABLED);
1554455a7b23SScott Bauer add_token_u64(&err, dev, !!setup->WLE);
1555455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1556455a7b23SScott Bauer
1557455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
1558455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1559455a7b23SScott Bauer }
1560455a7b23SScott Bauer if (err) {
1561591c59d1SScott Bauer pr_debug("Error building Setup Locking range command.\n");
1562455a7b23SScott Bauer return err;
1563455a7b23SScott Bauer }
1564455a7b23SScott Bauer
1565455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
1566455a7b23SScott Bauer }
1567455a7b23SScott Bauer
response_get_column(const struct parsed_resp * resp,int * iter,u8 column,u64 * value)15684c4dd04eSOndrej Kozina static int response_get_column(const struct parsed_resp *resp,
15694c4dd04eSOndrej Kozina int *iter,
15704c4dd04eSOndrej Kozina u8 column,
15714c4dd04eSOndrej Kozina u64 *value)
15724c4dd04eSOndrej Kozina {
15734c4dd04eSOndrej Kozina const struct opal_resp_tok *tok;
15744c4dd04eSOndrej Kozina int n = *iter;
15754c4dd04eSOndrej Kozina u64 val;
15764c4dd04eSOndrej Kozina
15774c4dd04eSOndrej Kozina tok = response_get_token(resp, n);
15784c4dd04eSOndrej Kozina if (IS_ERR(tok))
15794c4dd04eSOndrej Kozina return PTR_ERR(tok);
15804c4dd04eSOndrej Kozina
15814c4dd04eSOndrej Kozina if (!response_token_matches(tok, OPAL_STARTNAME)) {
15824c4dd04eSOndrej Kozina pr_debug("Unexpected response token type %d.\n", n);
15834c4dd04eSOndrej Kozina return OPAL_INVAL_PARAM;
15844c4dd04eSOndrej Kozina }
15854c4dd04eSOndrej Kozina n++;
15864c4dd04eSOndrej Kozina
15874c4dd04eSOndrej Kozina if (response_get_u64(resp, n) != column) {
15884c4dd04eSOndrej Kozina pr_debug("Token %d does not match expected column %u.\n",
15894c4dd04eSOndrej Kozina n, column);
15904c4dd04eSOndrej Kozina return OPAL_INVAL_PARAM;
15914c4dd04eSOndrej Kozina }
15924c4dd04eSOndrej Kozina n++;
15934c4dd04eSOndrej Kozina
15944c4dd04eSOndrej Kozina val = response_get_u64(resp, n);
15954c4dd04eSOndrej Kozina n++;
15964c4dd04eSOndrej Kozina
15974c4dd04eSOndrej Kozina tok = response_get_token(resp, n);
15984c4dd04eSOndrej Kozina if (IS_ERR(tok))
15994c4dd04eSOndrej Kozina return PTR_ERR(tok);
16004c4dd04eSOndrej Kozina
16014c4dd04eSOndrej Kozina if (!response_token_matches(tok, OPAL_ENDNAME)) {
16024c4dd04eSOndrej Kozina pr_debug("Unexpected response token type %d.\n", n);
16034c4dd04eSOndrej Kozina return OPAL_INVAL_PARAM;
16044c4dd04eSOndrej Kozina }
16054c4dd04eSOndrej Kozina n++;
16064c4dd04eSOndrej Kozina
16074c4dd04eSOndrej Kozina *value = val;
16084c4dd04eSOndrej Kozina *iter = n;
16094c4dd04eSOndrej Kozina
16104c4dd04eSOndrej Kozina return 0;
16114c4dd04eSOndrej Kozina }
16124c4dd04eSOndrej Kozina
locking_range_status(struct opal_dev * dev,void * data)16134c4dd04eSOndrej Kozina static int locking_range_status(struct opal_dev *dev, void *data)
16144c4dd04eSOndrej Kozina {
16154c4dd04eSOndrej Kozina u8 lr_buffer[OPAL_UID_LENGTH];
16164c4dd04eSOndrej Kozina u64 resp;
16174c4dd04eSOndrej Kozina bool rlocked, wlocked;
16184c4dd04eSOndrej Kozina int err, tok_n = 2;
16194c4dd04eSOndrej Kozina struct opal_lr_status *lrst = data;
16204c4dd04eSOndrej Kozina
16214c4dd04eSOndrej Kozina err = build_locking_range(lr_buffer, sizeof(lr_buffer),
16224c4dd04eSOndrej Kozina lrst->session.opal_key.lr);
16234c4dd04eSOndrej Kozina if (err)
16244c4dd04eSOndrej Kozina return err;
16254c4dd04eSOndrej Kozina
16264c4dd04eSOndrej Kozina err = generic_get_columns(dev, lr_buffer, OPAL_RANGESTART,
16274c4dd04eSOndrej Kozina OPAL_WRITELOCKED);
16284c4dd04eSOndrej Kozina if (err) {
16294c4dd04eSOndrej Kozina pr_debug("Couldn't get lr %u table columns %d to %d.\n",
16304c4dd04eSOndrej Kozina lrst->session.opal_key.lr, OPAL_RANGESTART,
16314c4dd04eSOndrej Kozina OPAL_WRITELOCKED);
16324c4dd04eSOndrej Kozina return err;
16334c4dd04eSOndrej Kozina }
16344c4dd04eSOndrej Kozina
16354c4dd04eSOndrej Kozina /* range start */
16364c4dd04eSOndrej Kozina err = response_get_column(&dev->parsed, &tok_n, OPAL_RANGESTART,
16374c4dd04eSOndrej Kozina &lrst->range_start);
16384c4dd04eSOndrej Kozina if (err)
16394c4dd04eSOndrej Kozina return err;
16404c4dd04eSOndrej Kozina
16414c4dd04eSOndrej Kozina /* range length */
16424c4dd04eSOndrej Kozina err = response_get_column(&dev->parsed, &tok_n, OPAL_RANGELENGTH,
16434c4dd04eSOndrej Kozina &lrst->range_length);
16444c4dd04eSOndrej Kozina if (err)
16454c4dd04eSOndrej Kozina return err;
16464c4dd04eSOndrej Kozina
16474c4dd04eSOndrej Kozina /* RLE */
16484c4dd04eSOndrej Kozina err = response_get_column(&dev->parsed, &tok_n, OPAL_READLOCKENABLED,
16494c4dd04eSOndrej Kozina &resp);
16504c4dd04eSOndrej Kozina if (err)
16514c4dd04eSOndrej Kozina return err;
16524c4dd04eSOndrej Kozina
16534c4dd04eSOndrej Kozina lrst->RLE = !!resp;
16544c4dd04eSOndrej Kozina
16554c4dd04eSOndrej Kozina /* WLE */
16564c4dd04eSOndrej Kozina err = response_get_column(&dev->parsed, &tok_n, OPAL_WRITELOCKENABLED,
16574c4dd04eSOndrej Kozina &resp);
16584c4dd04eSOndrej Kozina if (err)
16594c4dd04eSOndrej Kozina return err;
16604c4dd04eSOndrej Kozina
16614c4dd04eSOndrej Kozina lrst->WLE = !!resp;
16624c4dd04eSOndrej Kozina
16634c4dd04eSOndrej Kozina /* read locked */
16644c4dd04eSOndrej Kozina err = response_get_column(&dev->parsed, &tok_n, OPAL_READLOCKED, &resp);
16654c4dd04eSOndrej Kozina if (err)
16664c4dd04eSOndrej Kozina return err;
16674c4dd04eSOndrej Kozina
16684c4dd04eSOndrej Kozina rlocked = !!resp;
16694c4dd04eSOndrej Kozina
16704c4dd04eSOndrej Kozina /* write locked */
16714c4dd04eSOndrej Kozina err = response_get_column(&dev->parsed, &tok_n, OPAL_WRITELOCKED, &resp);
16724c4dd04eSOndrej Kozina if (err)
16734c4dd04eSOndrej Kozina return err;
16744c4dd04eSOndrej Kozina
16754c4dd04eSOndrej Kozina wlocked = !!resp;
16764c4dd04eSOndrej Kozina
16774c4dd04eSOndrej Kozina /* opal_lock_state can not map 'read locked' only state. */
16784c4dd04eSOndrej Kozina lrst->l_state = OPAL_RW;
16794c4dd04eSOndrej Kozina if (rlocked && wlocked)
16804c4dd04eSOndrej Kozina lrst->l_state = OPAL_LK;
16814c4dd04eSOndrej Kozina else if (wlocked)
16824c4dd04eSOndrej Kozina lrst->l_state = OPAL_RO;
16834c4dd04eSOndrej Kozina else if (rlocked) {
16844c4dd04eSOndrej Kozina pr_debug("Can not report read locked only state.\n");
16854c4dd04eSOndrej Kozina return -EINVAL;
16864c4dd04eSOndrej Kozina }
16874c4dd04eSOndrej Kozina
16884c4dd04eSOndrej Kozina return 0;
16894c4dd04eSOndrej Kozina }
16904c4dd04eSOndrej Kozina
start_generic_opal_session(struct opal_dev * dev,enum opal_uid auth,enum opal_uid sp_type,const char * key,u8 key_len)1691455a7b23SScott Bauer static int start_generic_opal_session(struct opal_dev *dev,
1692455a7b23SScott Bauer enum opal_uid auth,
1693455a7b23SScott Bauer enum opal_uid sp_type,
1694455a7b23SScott Bauer const char *key,
1695455a7b23SScott Bauer u8 key_len)
1696455a7b23SScott Bauer {
1697455a7b23SScott Bauer u32 hsn;
1698e8b29224SDavid Kozub int err;
1699455a7b23SScott Bauer
1700591c59d1SScott Bauer if (key == NULL && auth != OPAL_ANYBODY_UID)
1701455a7b23SScott Bauer return OPAL_INVAL_PARAM;
1702455a7b23SScott Bauer
1703455a7b23SScott Bauer hsn = GENERIC_HOST_SESSION_NUM;
1704e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1705e8b29224SDavid Kozub opalmethod[OPAL_STARTSESSION]);
1706455a7b23SScott Bauer
1707455a7b23SScott Bauer add_token_u64(&err, dev, hsn);
1708455a7b23SScott Bauer add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
1709455a7b23SScott Bauer add_token_u8(&err, dev, 1);
1710455a7b23SScott Bauer
1711455a7b23SScott Bauer switch (auth) {
1712455a7b23SScott Bauer case OPAL_ANYBODY_UID:
1713455a7b23SScott Bauer break;
1714455a7b23SScott Bauer case OPAL_ADMIN1_UID:
1715455a7b23SScott Bauer case OPAL_SID_UID:
17165e4c7cf6SRevanth Rajashekar case OPAL_PSID_UID:
1717455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1718455a7b23SScott Bauer add_token_u8(&err, dev, 0); /* HostChallenge */
1719455a7b23SScott Bauer add_token_bytestring(&err, dev, key, key_len);
1720455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1721455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1722455a7b23SScott Bauer add_token_u8(&err, dev, 3); /* HostSignAuth */
1723455a7b23SScott Bauer add_token_bytestring(&err, dev, opaluid[auth],
1724455a7b23SScott Bauer OPAL_UID_LENGTH);
1725455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1726455a7b23SScott Bauer break;
1727455a7b23SScott Bauer default:
1728591c59d1SScott Bauer pr_debug("Cannot start Admin SP session with auth %d\n", auth);
1729455a7b23SScott Bauer return OPAL_INVAL_PARAM;
1730455a7b23SScott Bauer }
1731455a7b23SScott Bauer
1732455a7b23SScott Bauer if (err) {
1733591c59d1SScott Bauer pr_debug("Error building start adminsp session command.\n");
1734455a7b23SScott Bauer return err;
1735455a7b23SScott Bauer }
1736455a7b23SScott Bauer
1737455a7b23SScott Bauer return finalize_and_send(dev, start_opal_session_cont);
1738455a7b23SScott Bauer }
1739455a7b23SScott Bauer
start_anybodyASP_opal_session(struct opal_dev * dev,void * data)1740eed64951SJon Derrick static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data)
1741455a7b23SScott Bauer {
1742455a7b23SScott Bauer return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
1743455a7b23SScott Bauer OPAL_ADMINSP_UID, NULL, 0);
1744455a7b23SScott Bauer }
1745455a7b23SScott Bauer
start_SIDASP_opal_session(struct opal_dev * dev,void * data)1746eed64951SJon Derrick static int start_SIDASP_opal_session(struct opal_dev *dev, void *data)
1747455a7b23SScott Bauer {
1748455a7b23SScott Bauer int ret;
1749455a7b23SScott Bauer const u8 *key = dev->prev_data;
1750455a7b23SScott Bauer
1751455a7b23SScott Bauer if (!key) {
1752eed64951SJon Derrick const struct opal_key *okey = data;
17531e815b33SDavid Kozub
1754455a7b23SScott Bauer ret = start_generic_opal_session(dev, OPAL_SID_UID,
1755455a7b23SScott Bauer OPAL_ADMINSP_UID,
1756455a7b23SScott Bauer okey->key,
1757455a7b23SScott Bauer okey->key_len);
1758455a7b23SScott Bauer } else {
1759455a7b23SScott Bauer ret = start_generic_opal_session(dev, OPAL_SID_UID,
1760455a7b23SScott Bauer OPAL_ADMINSP_UID,
1761455a7b23SScott Bauer key, dev->prev_d_len);
1762455a7b23SScott Bauer kfree(key);
1763455a7b23SScott Bauer dev->prev_data = NULL;
1764455a7b23SScott Bauer }
17655cc23ed7SRevanth Rajashekar
1766455a7b23SScott Bauer return ret;
1767455a7b23SScott Bauer }
1768455a7b23SScott Bauer
start_admin1LSP_opal_session(struct opal_dev * dev,void * data)1769eed64951SJon Derrick static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data)
1770455a7b23SScott Bauer {
1771eed64951SJon Derrick struct opal_key *key = data;
17721e815b33SDavid Kozub
1773455a7b23SScott Bauer return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
1774455a7b23SScott Bauer OPAL_LOCKINGSP_UID,
1775455a7b23SScott Bauer key->key, key->key_len);
1776455a7b23SScott Bauer }
1777455a7b23SScott Bauer
start_PSID_opal_session(struct opal_dev * dev,void * data)17785e4c7cf6SRevanth Rajashekar static int start_PSID_opal_session(struct opal_dev *dev, void *data)
17795e4c7cf6SRevanth Rajashekar {
17805e4c7cf6SRevanth Rajashekar const struct opal_key *okey = data;
17815e4c7cf6SRevanth Rajashekar
17825e4c7cf6SRevanth Rajashekar return start_generic_opal_session(dev, OPAL_PSID_UID,
17835e4c7cf6SRevanth Rajashekar OPAL_ADMINSP_UID,
17845e4c7cf6SRevanth Rajashekar okey->key,
17855e4c7cf6SRevanth Rajashekar okey->key_len);
17865e4c7cf6SRevanth Rajashekar }
17875e4c7cf6SRevanth Rajashekar
start_auth_opal_session(struct opal_dev * dev,void * data)1788eed64951SJon Derrick static int start_auth_opal_session(struct opal_dev *dev, void *data)
1789455a7b23SScott Bauer {
1790eed64951SJon Derrick struct opal_session_info *session = data;
1791455a7b23SScott Bauer u8 lk_ul_user[OPAL_UID_LENGTH];
1792eed64951SJon Derrick size_t keylen = session->opal_key.key_len;
1793455a7b23SScott Bauer int err = 0;
1794455a7b23SScott Bauer
1795455a7b23SScott Bauer u8 *key = session->opal_key.key;
1796455a7b23SScott Bauer u32 hsn = GENERIC_HOST_SESSION_NUM;
1797455a7b23SScott Bauer
1798e8b29224SDavid Kozub if (session->sum)
1799455a7b23SScott Bauer err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1800455a7b23SScott Bauer session->opal_key.lr);
1801e8b29224SDavid Kozub else if (session->who != OPAL_ADMIN1 && !session->sum)
1802455a7b23SScott Bauer err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
1803455a7b23SScott Bauer session->who - 1);
1804e8b29224SDavid Kozub else
1805455a7b23SScott Bauer memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
1806455a7b23SScott Bauer
1807e8b29224SDavid Kozub if (err)
1808e8b29224SDavid Kozub return err;
1809455a7b23SScott Bauer
1810e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_SMUID_UID],
1811e8b29224SDavid Kozub opalmethod[OPAL_STARTSESSION]);
1812e8b29224SDavid Kozub
1813455a7b23SScott Bauer add_token_u64(&err, dev, hsn);
1814455a7b23SScott Bauer add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
1815455a7b23SScott Bauer OPAL_UID_LENGTH);
1816455a7b23SScott Bauer add_token_u8(&err, dev, 1);
1817455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1818455a7b23SScott Bauer add_token_u8(&err, dev, 0);
1819455a7b23SScott Bauer add_token_bytestring(&err, dev, key, keylen);
1820455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1821455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1822455a7b23SScott Bauer add_token_u8(&err, dev, 3);
1823455a7b23SScott Bauer add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
1824455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1825455a7b23SScott Bauer
1826455a7b23SScott Bauer if (err) {
1827591c59d1SScott Bauer pr_debug("Error building STARTSESSION command.\n");
1828455a7b23SScott Bauer return err;
1829455a7b23SScott Bauer }
1830455a7b23SScott Bauer
1831455a7b23SScott Bauer return finalize_and_send(dev, start_opal_session_cont);
1832455a7b23SScott Bauer }
1833455a7b23SScott Bauer
revert_tper(struct opal_dev * dev,void * data)1834eed64951SJon Derrick static int revert_tper(struct opal_dev *dev, void *data)
1835455a7b23SScott Bauer {
1836e8b29224SDavid Kozub int err;
1837455a7b23SScott Bauer
1838e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_ADMINSP_UID],
1839e8b29224SDavid Kozub opalmethod[OPAL_REVERT]);
1840455a7b23SScott Bauer if (err) {
1841591c59d1SScott Bauer pr_debug("Error building REVERT TPER command.\n");
1842455a7b23SScott Bauer return err;
1843455a7b23SScott Bauer }
1844455a7b23SScott Bauer
1845455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
1846455a7b23SScott Bauer }
1847455a7b23SScott Bauer
internal_activate_user(struct opal_dev * dev,void * data)1848eed64951SJon Derrick static int internal_activate_user(struct opal_dev *dev, void *data)
1849455a7b23SScott Bauer {
1850eed64951SJon Derrick struct opal_session_info *session = data;
1851455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH];
1852e8b29224SDavid Kozub int err;
1853455a7b23SScott Bauer
1854455a7b23SScott Bauer memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
1855455a7b23SScott Bauer uid[7] = session->who;
1856455a7b23SScott Bauer
1857e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_SET]);
1858455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1859455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES);
1860455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
1861455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1862455a7b23SScott Bauer add_token_u8(&err, dev, 5); /* Enabled */
1863455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_TRUE);
1864455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1865455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
1866455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1867455a7b23SScott Bauer
1868455a7b23SScott Bauer if (err) {
1869591c59d1SScott Bauer pr_debug("Error building Activate UserN command.\n");
1870455a7b23SScott Bauer return err;
1871455a7b23SScott Bauer }
1872455a7b23SScott Bauer
1873455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
1874455a7b23SScott Bauer }
1875455a7b23SScott Bauer
revert_lsp(struct opal_dev * dev,void * data)18765c82efc1SGreg Joyce static int revert_lsp(struct opal_dev *dev, void *data)
18775c82efc1SGreg Joyce {
18785c82efc1SGreg Joyce struct opal_revert_lsp *rev = data;
18795c82efc1SGreg Joyce int err;
18805c82efc1SGreg Joyce
18815c82efc1SGreg Joyce err = cmd_start(dev, opaluid[OPAL_THISSP_UID],
18825c82efc1SGreg Joyce opalmethod[OPAL_REVERTSP]);
18835c82efc1SGreg Joyce add_token_u8(&err, dev, OPAL_STARTNAME);
18845c82efc1SGreg Joyce add_token_u64(&err, dev, OPAL_KEEP_GLOBAL_RANGE_KEY);
18855c82efc1SGreg Joyce add_token_u8(&err, dev, (rev->options & OPAL_PRESERVE) ?
18865c82efc1SGreg Joyce OPAL_TRUE : OPAL_FALSE);
18875c82efc1SGreg Joyce add_token_u8(&err, dev, OPAL_ENDNAME);
18885c82efc1SGreg Joyce if (err) {
18895c82efc1SGreg Joyce pr_debug("Error building REVERT SP command.\n");
18905c82efc1SGreg Joyce return err;
18915c82efc1SGreg Joyce }
18925c82efc1SGreg Joyce
18935c82efc1SGreg Joyce return finalize_and_send(dev, parse_and_check_status);
18945c82efc1SGreg Joyce }
18955c82efc1SGreg Joyce
erase_locking_range(struct opal_dev * dev,void * data)1896eed64951SJon Derrick static int erase_locking_range(struct opal_dev *dev, void *data)
1897455a7b23SScott Bauer {
1898eed64951SJon Derrick struct opal_session_info *session = data;
1899455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH];
1900e8b29224SDavid Kozub int err;
1901455a7b23SScott Bauer
1902455a7b23SScott Bauer if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
1903455a7b23SScott Bauer return -ERANGE;
1904455a7b23SScott Bauer
1905e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_ERASE]);
1906455a7b23SScott Bauer
1907455a7b23SScott Bauer if (err) {
1908591c59d1SScott Bauer pr_debug("Error building Erase Locking Range Command.\n");
1909455a7b23SScott Bauer return err;
1910455a7b23SScott Bauer }
19115cc23ed7SRevanth Rajashekar
1912455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
1913455a7b23SScott Bauer }
1914455a7b23SScott Bauer
set_mbr_done(struct opal_dev * dev,void * data)1915eed64951SJon Derrick static int set_mbr_done(struct opal_dev *dev, void *data)
1916455a7b23SScott Bauer {
1917eed64951SJon Derrick u8 *mbr_done_tf = data;
1918e8b29224SDavid Kozub int err;
1919455a7b23SScott Bauer
1920e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1921e8b29224SDavid Kozub opalmethod[OPAL_SET]);
1922455a7b23SScott Bauer
1923455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1924455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES);
1925455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
1926455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1927372be408SDavid Kozub add_token_u8(&err, dev, OPAL_MBRDONE);
1928eed64951SJon Derrick add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */
1929455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1930455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
1931455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1932455a7b23SScott Bauer
1933455a7b23SScott Bauer if (err) {
1934591c59d1SScott Bauer pr_debug("Error Building set MBR Done command\n");
1935455a7b23SScott Bauer return err;
1936455a7b23SScott Bauer }
1937455a7b23SScott Bauer
1938455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
1939455a7b23SScott Bauer }
1940455a7b23SScott Bauer
set_mbr_enable_disable(struct opal_dev * dev,void * data)1941eed64951SJon Derrick static int set_mbr_enable_disable(struct opal_dev *dev, void *data)
1942455a7b23SScott Bauer {
1943eed64951SJon Derrick u8 *mbr_en_dis = data;
1944e8b29224SDavid Kozub int err;
1945455a7b23SScott Bauer
1946e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_MBRCONTROL],
1947e8b29224SDavid Kozub opalmethod[OPAL_SET]);
1948455a7b23SScott Bauer
1949455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1950455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES);
1951455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
1952455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1953372be408SDavid Kozub add_token_u8(&err, dev, OPAL_MBRENABLE);
1954eed64951SJon Derrick add_token_u8(&err, dev, *mbr_en_dis);
1955455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1956455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
1957455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1958455a7b23SScott Bauer
1959455a7b23SScott Bauer if (err) {
1960591c59d1SScott Bauer pr_debug("Error Building set MBR done command\n");
1961455a7b23SScott Bauer return err;
1962455a7b23SScott Bauer }
1963455a7b23SScott Bauer
1964455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
1965455a7b23SScott Bauer }
1966455a7b23SScott Bauer
write_shadow_mbr(struct opal_dev * dev,void * data)1967a9b25b4cSJonas Rabenstein static int write_shadow_mbr(struct opal_dev *dev, void *data)
1968a9b25b4cSJonas Rabenstein {
1969a9b25b4cSJonas Rabenstein struct opal_shadow_mbr *shadow = data;
1970a9b25b4cSJonas Rabenstein
19713495ea1bSRevanth Rajashekar return generic_table_write_data(dev, shadow->data, shadow->offset,
19723495ea1bSRevanth Rajashekar shadow->size, opaluid[OPAL_MBR]);
1973a9b25b4cSJonas Rabenstein }
1974a9b25b4cSJonas Rabenstein
generic_pw_cmd(u8 * key,size_t key_len,u8 * cpin_uid,struct opal_dev * dev)1975455a7b23SScott Bauer static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
1976455a7b23SScott Bauer struct opal_dev *dev)
1977455a7b23SScott Bauer {
1978e8b29224SDavid Kozub int err;
1979455a7b23SScott Bauer
1980e8b29224SDavid Kozub err = cmd_start(dev, cpin_uid, opalmethod[OPAL_SET]);
1981455a7b23SScott Bauer
1982455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1983455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES);
1984455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
1985455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
1986372be408SDavid Kozub add_token_u8(&err, dev, OPAL_PIN);
1987455a7b23SScott Bauer add_token_bytestring(&err, dev, key, key_len);
1988455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1989455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
1990455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
1991455a7b23SScott Bauer
1992455a7b23SScott Bauer return err;
1993455a7b23SScott Bauer }
1994455a7b23SScott Bauer
set_new_pw(struct opal_dev * dev,void * data)1995eed64951SJon Derrick static int set_new_pw(struct opal_dev *dev, void *data)
1996455a7b23SScott Bauer {
1997455a7b23SScott Bauer u8 cpin_uid[OPAL_UID_LENGTH];
1998eed64951SJon Derrick struct opal_session_info *usr = data;
1999455a7b23SScott Bauer
2000455a7b23SScott Bauer memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
2001455a7b23SScott Bauer
2002455a7b23SScott Bauer if (usr->who != OPAL_ADMIN1) {
2003455a7b23SScott Bauer cpin_uid[5] = 0x03;
2004455a7b23SScott Bauer if (usr->sum)
2005455a7b23SScott Bauer cpin_uid[7] = usr->opal_key.lr + 1;
2006455a7b23SScott Bauer else
2007455a7b23SScott Bauer cpin_uid[7] = usr->who;
2008455a7b23SScott Bauer }
2009455a7b23SScott Bauer
2010455a7b23SScott Bauer if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
2011455a7b23SScott Bauer cpin_uid, dev)) {
2012591c59d1SScott Bauer pr_debug("Error building set password command.\n");
2013455a7b23SScott Bauer return -ERANGE;
2014455a7b23SScott Bauer }
2015455a7b23SScott Bauer
2016455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
2017455a7b23SScott Bauer }
2018455a7b23SScott Bauer
set_sid_cpin_pin(struct opal_dev * dev,void * data)2019eed64951SJon Derrick static int set_sid_cpin_pin(struct opal_dev *dev, void *data)
2020455a7b23SScott Bauer {
2021455a7b23SScott Bauer u8 cpin_uid[OPAL_UID_LENGTH];
2022eed64951SJon Derrick struct opal_key *key = data;
2023455a7b23SScott Bauer
2024455a7b23SScott Bauer memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
2025455a7b23SScott Bauer
2026455a7b23SScott Bauer if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
2027591c59d1SScott Bauer pr_debug("Error building Set SID cpin\n");
2028455a7b23SScott Bauer return -ERANGE;
2029455a7b23SScott Bauer }
2030455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
2031455a7b23SScott Bauer }
2032455a7b23SScott Bauer
add_authority_object_ref(int * err,struct opal_dev * dev,const u8 * uid,size_t uid_len)2033175b6544SOndrej Kozina static void add_authority_object_ref(int *err,
2034175b6544SOndrej Kozina struct opal_dev *dev,
2035175b6544SOndrej Kozina const u8 *uid,
2036175b6544SOndrej Kozina size_t uid_len)
2037175b6544SOndrej Kozina {
2038175b6544SOndrej Kozina add_token_u8(err, dev, OPAL_STARTNAME);
2039175b6544SOndrej Kozina add_token_bytestring(err, dev,
2040175b6544SOndrej Kozina opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
2041175b6544SOndrej Kozina OPAL_UID_LENGTH/2);
2042175b6544SOndrej Kozina add_token_bytestring(err, dev, uid, uid_len);
2043175b6544SOndrej Kozina add_token_u8(err, dev, OPAL_ENDNAME);
2044175b6544SOndrej Kozina }
2045175b6544SOndrej Kozina
add_boolean_object_ref(int * err,struct opal_dev * dev,u8 boolean_op)2046175b6544SOndrej Kozina static void add_boolean_object_ref(int *err,
2047175b6544SOndrej Kozina struct opal_dev *dev,
2048175b6544SOndrej Kozina u8 boolean_op)
2049175b6544SOndrej Kozina {
2050175b6544SOndrej Kozina add_token_u8(err, dev, OPAL_STARTNAME);
2051175b6544SOndrej Kozina add_token_bytestring(err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
2052175b6544SOndrej Kozina OPAL_UID_LENGTH/2);
2053175b6544SOndrej Kozina add_token_u8(err, dev, boolean_op);
2054175b6544SOndrej Kozina add_token_u8(err, dev, OPAL_ENDNAME);
2055175b6544SOndrej Kozina }
2056175b6544SOndrej Kozina
set_lr_boolean_ace(struct opal_dev * dev,unsigned int opal_uid,u8 lr,const u8 * users,size_t users_len)2057175b6544SOndrej Kozina static int set_lr_boolean_ace(struct opal_dev *dev,
2058175b6544SOndrej Kozina unsigned int opal_uid,
2059175b6544SOndrej Kozina u8 lr,
2060175b6544SOndrej Kozina const u8 *users,
2061175b6544SOndrej Kozina size_t users_len)
2062455a7b23SScott Bauer {
2063455a7b23SScott Bauer u8 lr_buffer[OPAL_UID_LENGTH];
2064455a7b23SScott Bauer u8 user_uid[OPAL_UID_LENGTH];
2065175b6544SOndrej Kozina u8 u;
2066e8b29224SDavid Kozub int err;
2067455a7b23SScott Bauer
2068175b6544SOndrej Kozina memcpy(lr_buffer, opaluid[opal_uid], OPAL_UID_LENGTH);
2069175b6544SOndrej Kozina lr_buffer[7] = lr;
2070455a7b23SScott Bauer
2071e8b29224SDavid Kozub err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
2072455a7b23SScott Bauer
2073455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
2074455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES);
2075455a7b23SScott Bauer
2076455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
2077455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
2078455a7b23SScott Bauer add_token_u8(&err, dev, 3);
2079455a7b23SScott Bauer
2080455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
2081455a7b23SScott Bauer
2082175b6544SOndrej Kozina for (u = 0; u < users_len; u++) {
2083175b6544SOndrej Kozina if (users[u] == OPAL_ADMIN1)
2084175b6544SOndrej Kozina memcpy(user_uid, opaluid[OPAL_ADMIN1_UID],
2085175b6544SOndrej Kozina OPAL_UID_LENGTH);
2086175b6544SOndrej Kozina else {
2087175b6544SOndrej Kozina memcpy(user_uid, opaluid[OPAL_USER1_UID],
2088175b6544SOndrej Kozina OPAL_UID_LENGTH);
2089175b6544SOndrej Kozina user_uid[7] = users[u];
2090175b6544SOndrej Kozina }
2091455a7b23SScott Bauer
2092175b6544SOndrej Kozina add_authority_object_ref(&err, dev, user_uid, sizeof(user_uid));
2093175b6544SOndrej Kozina
2094175b6544SOndrej Kozina /*
2095175b6544SOndrej Kozina * Add boolean operator in postfix only with
2096175b6544SOndrej Kozina * two or more authorities being added in ACE
2097175b6544SOndrej Kozina * expresion.
2098175b6544SOndrej Kozina * */
2099175b6544SOndrej Kozina if (u > 0)
2100175b6544SOndrej Kozina add_boolean_object_ref(&err, dev, OPAL_BOOLEAN_OR);
2101175b6544SOndrej Kozina }
2102455a7b23SScott Bauer
2103455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
2104455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
2105455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
2106455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
2107455a7b23SScott Bauer
2108175b6544SOndrej Kozina return err;
2109175b6544SOndrej Kozina }
2110175b6544SOndrej Kozina
add_user_to_lr(struct opal_dev * dev,void * data)2111175b6544SOndrej Kozina static int add_user_to_lr(struct opal_dev *dev, void *data)
2112175b6544SOndrej Kozina {
2113175b6544SOndrej Kozina int err;
2114175b6544SOndrej Kozina struct opal_lock_unlock *lkul = data;
2115175b6544SOndrej Kozina const u8 users[] = {
2116175b6544SOndrej Kozina lkul->session.who
2117175b6544SOndrej Kozina };
2118175b6544SOndrej Kozina
2119175b6544SOndrej Kozina err = set_lr_boolean_ace(dev,
2120175b6544SOndrej Kozina lkul->l_state == OPAL_RW ?
2121175b6544SOndrej Kozina OPAL_LOCKINGRANGE_ACE_WRLOCKED :
2122175b6544SOndrej Kozina OPAL_LOCKINGRANGE_ACE_RDLOCKED,
2123175b6544SOndrej Kozina lkul->session.opal_key.lr, users,
2124175b6544SOndrej Kozina ARRAY_SIZE(users));
2125455a7b23SScott Bauer if (err) {
2126591c59d1SScott Bauer pr_debug("Error building add user to locking range command.\n");
2127455a7b23SScott Bauer return err;
2128455a7b23SScott Bauer }
2129455a7b23SScott Bauer
2130455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
2131455a7b23SScott Bauer }
2132455a7b23SScott Bauer
add_user_to_lr_ace(struct opal_dev * dev,void * data)21338be19a02SOndrej Kozina static int add_user_to_lr_ace(struct opal_dev *dev, void *data)
21348be19a02SOndrej Kozina {
21358be19a02SOndrej Kozina int err;
21368be19a02SOndrej Kozina struct opal_lock_unlock *lkul = data;
21378be19a02SOndrej Kozina const u8 users[] = {
21388be19a02SOndrej Kozina OPAL_ADMIN1,
21398be19a02SOndrej Kozina lkul->session.who
21408be19a02SOndrej Kozina };
21418be19a02SOndrej Kozina
21428be19a02SOndrej Kozina err = set_lr_boolean_ace(dev, OPAL_LOCKINGRANGE_ACE_START_TO_KEY,
21438be19a02SOndrej Kozina lkul->session.opal_key.lr, users,
21448be19a02SOndrej Kozina ARRAY_SIZE(users));
21458be19a02SOndrej Kozina
21468be19a02SOndrej Kozina if (err) {
21478be19a02SOndrej Kozina pr_debug("Error building add user to locking ranges ACEs.\n");
21488be19a02SOndrej Kozina return err;
21498be19a02SOndrej Kozina }
21508be19a02SOndrej Kozina
21518be19a02SOndrej Kozina return finalize_and_send(dev, parse_and_check_status);
21528be19a02SOndrej Kozina }
21538be19a02SOndrej Kozina
lock_unlock_locking_range(struct opal_dev * dev,void * data)2154eed64951SJon Derrick static int lock_unlock_locking_range(struct opal_dev *dev, void *data)
2155455a7b23SScott Bauer {
2156455a7b23SScott Bauer u8 lr_buffer[OPAL_UID_LENGTH];
2157eed64951SJon Derrick struct opal_lock_unlock *lkul = data;
2158455a7b23SScott Bauer u8 read_locked = 1, write_locked = 1;
2159455a7b23SScott Bauer int err = 0;
2160455a7b23SScott Bauer
2161455a7b23SScott Bauer if (build_locking_range(lr_buffer, sizeof(lr_buffer),
2162455a7b23SScott Bauer lkul->session.opal_key.lr) < 0)
2163455a7b23SScott Bauer return -ERANGE;
2164455a7b23SScott Bauer
2165455a7b23SScott Bauer switch (lkul->l_state) {
2166455a7b23SScott Bauer case OPAL_RO:
2167455a7b23SScott Bauer read_locked = 0;
2168455a7b23SScott Bauer write_locked = 1;
2169455a7b23SScott Bauer break;
2170455a7b23SScott Bauer case OPAL_RW:
2171455a7b23SScott Bauer read_locked = 0;
2172455a7b23SScott Bauer write_locked = 0;
2173455a7b23SScott Bauer break;
2174455a7b23SScott Bauer case OPAL_LK:
21751e815b33SDavid Kozub /* vars are initialized to locked */
2176455a7b23SScott Bauer break;
2177455a7b23SScott Bauer default:
2178591c59d1SScott Bauer pr_debug("Tried to set an invalid locking state... returning to uland\n");
2179455a7b23SScott Bauer return OPAL_INVAL_PARAM;
2180455a7b23SScott Bauer }
2181455a7b23SScott Bauer
2182e8b29224SDavid Kozub err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]);
2183e8b29224SDavid Kozub
2184455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
2185455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES);
2186455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
2187455a7b23SScott Bauer
2188455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
2189455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_READLOCKED);
2190455a7b23SScott Bauer add_token_u8(&err, dev, read_locked);
2191455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
2192455a7b23SScott Bauer
2193455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
2194455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_WRITELOCKED);
2195455a7b23SScott Bauer add_token_u8(&err, dev, write_locked);
2196455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
2197455a7b23SScott Bauer
2198455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
2199455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
2200455a7b23SScott Bauer
2201455a7b23SScott Bauer if (err) {
2202591c59d1SScott Bauer pr_debug("Error building SET command.\n");
2203455a7b23SScott Bauer return err;
2204455a7b23SScott Bauer }
22055cc23ed7SRevanth Rajashekar
2206455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
2207455a7b23SScott Bauer }
2208455a7b23SScott Bauer
2209455a7b23SScott Bauer
lock_unlock_locking_range_sum(struct opal_dev * dev,void * data)2210eed64951SJon Derrick static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data)
2211455a7b23SScott Bauer {
2212455a7b23SScott Bauer u8 lr_buffer[OPAL_UID_LENGTH];
2213455a7b23SScott Bauer u8 read_locked = 1, write_locked = 1;
2214eed64951SJon Derrick struct opal_lock_unlock *lkul = data;
2215455a7b23SScott Bauer int ret;
2216455a7b23SScott Bauer
2217455a7b23SScott Bauer clear_opal_cmd(dev);
2218455a7b23SScott Bauer set_comid(dev, dev->comid);
2219455a7b23SScott Bauer
2220455a7b23SScott Bauer if (build_locking_range(lr_buffer, sizeof(lr_buffer),
2221455a7b23SScott Bauer lkul->session.opal_key.lr) < 0)
2222455a7b23SScott Bauer return -ERANGE;
2223455a7b23SScott Bauer
2224455a7b23SScott Bauer switch (lkul->l_state) {
2225455a7b23SScott Bauer case OPAL_RO:
2226455a7b23SScott Bauer read_locked = 0;
2227455a7b23SScott Bauer write_locked = 1;
2228455a7b23SScott Bauer break;
2229455a7b23SScott Bauer case OPAL_RW:
2230455a7b23SScott Bauer read_locked = 0;
2231455a7b23SScott Bauer write_locked = 0;
2232455a7b23SScott Bauer break;
2233455a7b23SScott Bauer case OPAL_LK:
22341e815b33SDavid Kozub /* vars are initialized to locked */
2235455a7b23SScott Bauer break;
2236455a7b23SScott Bauer default:
2237591c59d1SScott Bauer pr_debug("Tried to set an invalid locking state.\n");
2238455a7b23SScott Bauer return OPAL_INVAL_PARAM;
2239455a7b23SScott Bauer }
2240455a7b23SScott Bauer ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
2241455a7b23SScott Bauer read_locked, write_locked);
2242455a7b23SScott Bauer
2243455a7b23SScott Bauer if (ret < 0) {
2244591c59d1SScott Bauer pr_debug("Error building SET command.\n");
2245455a7b23SScott Bauer return ret;
2246455a7b23SScott Bauer }
22475cc23ed7SRevanth Rajashekar
2248455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
2249455a7b23SScott Bauer }
2250455a7b23SScott Bauer
activate_lsp(struct opal_dev * dev,void * data)2251eed64951SJon Derrick static int activate_lsp(struct opal_dev *dev, void *data)
2252455a7b23SScott Bauer {
2253eed64951SJon Derrick struct opal_lr_act *opal_act = data;
2254455a7b23SScott Bauer u8 user_lr[OPAL_UID_LENGTH];
2255e8b29224SDavid Kozub int err, i;
2256455a7b23SScott Bauer
2257e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID],
2258e8b29224SDavid Kozub opalmethod[OPAL_ACTIVATE]);
2259455a7b23SScott Bauer
2260455a7b23SScott Bauer if (opal_act->sum) {
2261455a7b23SScott Bauer err = build_locking_range(user_lr, sizeof(user_lr),
2262455a7b23SScott Bauer opal_act->lr[0]);
2263455a7b23SScott Bauer if (err)
2264455a7b23SScott Bauer return err;
2265455a7b23SScott Bauer
2266455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME);
2267c6da429eSRevanth Rajashekar add_token_u64(&err, dev, OPAL_SUM_SET_LIST);
2268455a7b23SScott Bauer
2269455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST);
2270455a7b23SScott Bauer add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
2271455a7b23SScott Bauer for (i = 1; i < opal_act->num_lrs; i++) {
2272455a7b23SScott Bauer user_lr[7] = opal_act->lr[i];
2273455a7b23SScott Bauer add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
2274455a7b23SScott Bauer }
2275455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST);
2276455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME);
2277455a7b23SScott Bauer }
2278455a7b23SScott Bauer
2279455a7b23SScott Bauer if (err) {
2280591c59d1SScott Bauer pr_debug("Error building Activate LockingSP command.\n");
2281455a7b23SScott Bauer return err;
2282455a7b23SScott Bauer }
2283455a7b23SScott Bauer
2284455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status);
2285455a7b23SScott Bauer }
2286455a7b23SScott Bauer
22873fff234bSDavid Kozub /* Determine if we're in the Manufactured Inactive or Active state */
get_lsp_lifecycle(struct opal_dev * dev,void * data)22883fff234bSDavid Kozub static int get_lsp_lifecycle(struct opal_dev *dev, void *data)
2289455a7b23SScott Bauer {
2290455a7b23SScott Bauer u8 lc_status;
22913fff234bSDavid Kozub int err;
2292455a7b23SScott Bauer
22933fff234bSDavid Kozub err = generic_get_column(dev, opaluid[OPAL_LOCKINGSP_UID],
22943fff234bSDavid Kozub OPAL_LIFECYCLE);
22953fff234bSDavid Kozub if (err)
22963fff234bSDavid Kozub return err;
2297455a7b23SScott Bauer
2298455a7b23SScott Bauer lc_status = response_get_u64(&dev->parsed, 4);
22991e815b33SDavid Kozub /* 0x08 is Manufactured Inactive */
2300455a7b23SScott Bauer /* 0x09 is Manufactured */
2301455a7b23SScott Bauer if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
2302591c59d1SScott Bauer pr_debug("Couldn't determine the status of the Lifecycle state\n");
2303455a7b23SScott Bauer return -ENODEV;
2304455a7b23SScott Bauer }
2305455a7b23SScott Bauer
2306455a7b23SScott Bauer return 0;
2307455a7b23SScott Bauer }
2308455a7b23SScott Bauer
get_msid_cpin_pin(struct opal_dev * dev,void * data)23093fff234bSDavid Kozub static int get_msid_cpin_pin(struct opal_dev *dev, void *data)
2310455a7b23SScott Bauer {
2311455a7b23SScott Bauer const char *msid_pin;
2312455a7b23SScott Bauer size_t strlen;
23133fff234bSDavid Kozub int err;
2314455a7b23SScott Bauer
23153fff234bSDavid Kozub err = generic_get_column(dev, opaluid[OPAL_C_PIN_MSID], OPAL_PIN);
23163fff234bSDavid Kozub if (err)
23173fff234bSDavid Kozub return err;
2318455a7b23SScott Bauer
2319455a7b23SScott Bauer strlen = response_get_string(&dev->parsed, 4, &msid_pin);
2320455a7b23SScott Bauer if (!msid_pin) {
23213fff234bSDavid Kozub pr_debug("Couldn't extract MSID_CPIN from response\n");
2322455a7b23SScott Bauer return OPAL_INVAL_PARAM;
2323455a7b23SScott Bauer }
2324455a7b23SScott Bauer
2325455a7b23SScott Bauer dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
2326455a7b23SScott Bauer if (!dev->prev_data)
2327455a7b23SScott Bauer return -ENOMEM;
2328455a7b23SScott Bauer
2329455a7b23SScott Bauer dev->prev_d_len = strlen;
2330455a7b23SScott Bauer
2331455a7b23SScott Bauer return 0;
2332455a7b23SScott Bauer }
2333455a7b23SScott Bauer
write_table_data(struct opal_dev * dev,void * data)233451f421c8SRevanth Rajashekar static int write_table_data(struct opal_dev *dev, void *data)
233551f421c8SRevanth Rajashekar {
233651f421c8SRevanth Rajashekar struct opal_read_write_table *write_tbl = data;
233751f421c8SRevanth Rajashekar
233851f421c8SRevanth Rajashekar return generic_table_write_data(dev, write_tbl->data, write_tbl->offset,
233951f421c8SRevanth Rajashekar write_tbl->size, write_tbl->table_uid);
234051f421c8SRevanth Rajashekar }
234151f421c8SRevanth Rajashekar
read_table_data_cont(struct opal_dev * dev)234251f421c8SRevanth Rajashekar static int read_table_data_cont(struct opal_dev *dev)
234351f421c8SRevanth Rajashekar {
234451f421c8SRevanth Rajashekar int err;
234551f421c8SRevanth Rajashekar const char *data_read;
234651f421c8SRevanth Rajashekar
234751f421c8SRevanth Rajashekar err = parse_and_check_status(dev);
234851f421c8SRevanth Rajashekar if (err)
234951f421c8SRevanth Rajashekar return err;
235051f421c8SRevanth Rajashekar
235151f421c8SRevanth Rajashekar dev->prev_d_len = response_get_string(&dev->parsed, 1, &data_read);
235251f421c8SRevanth Rajashekar dev->prev_data = (void *)data_read;
235351f421c8SRevanth Rajashekar if (!dev->prev_data) {
235451f421c8SRevanth Rajashekar pr_debug("%s: Couldn't read data from the table.\n", __func__);
235551f421c8SRevanth Rajashekar return OPAL_INVAL_PARAM;
235651f421c8SRevanth Rajashekar }
235751f421c8SRevanth Rajashekar
235851f421c8SRevanth Rajashekar return 0;
235951f421c8SRevanth Rajashekar }
236051f421c8SRevanth Rajashekar
236151f421c8SRevanth Rajashekar /*
236251f421c8SRevanth Rajashekar * IO_BUFFER_LENGTH = 2048
236351f421c8SRevanth Rajashekar * sizeof(header) = 56
236451f421c8SRevanth Rajashekar * No. of Token Bytes in the Response = 11
236551f421c8SRevanth Rajashekar * MAX size of data that can be carried in response buffer
236651f421c8SRevanth Rajashekar * at a time is : 2048 - (56 + 11) = 1981 = 0x7BD.
236751f421c8SRevanth Rajashekar */
236851f421c8SRevanth Rajashekar #define OPAL_MAX_READ_TABLE (0x7BD)
236951f421c8SRevanth Rajashekar
read_table_data(struct opal_dev * dev,void * data)237051f421c8SRevanth Rajashekar static int read_table_data(struct opal_dev *dev, void *data)
237151f421c8SRevanth Rajashekar {
237251f421c8SRevanth Rajashekar struct opal_read_write_table *read_tbl = data;
237351f421c8SRevanth Rajashekar int err;
237451f421c8SRevanth Rajashekar size_t off = 0, max_read_size = OPAL_MAX_READ_TABLE;
237551f421c8SRevanth Rajashekar u64 table_len, len;
237651f421c8SRevanth Rajashekar u64 offset = read_tbl->offset, read_size = read_tbl->size - 1;
237751f421c8SRevanth Rajashekar u8 __user *dst;
237851f421c8SRevanth Rajashekar
237951f421c8SRevanth Rajashekar err = generic_get_table_info(dev, read_tbl->table_uid, OPAL_TABLE_ROWS);
238051f421c8SRevanth Rajashekar if (err) {
238151f421c8SRevanth Rajashekar pr_debug("Couldn't get the table size\n");
238251f421c8SRevanth Rajashekar return err;
238351f421c8SRevanth Rajashekar }
238451f421c8SRevanth Rajashekar
238551f421c8SRevanth Rajashekar table_len = response_get_u64(&dev->parsed, 4);
238651f421c8SRevanth Rajashekar
238751f421c8SRevanth Rajashekar /* Check if the user is trying to read from the table limits */
238851f421c8SRevanth Rajashekar if (read_size > table_len || offset > table_len - read_size) {
238951f421c8SRevanth Rajashekar pr_debug("Read size exceeds the Table size limits (%llu vs. %llu)\n",
239051f421c8SRevanth Rajashekar offset + read_size, table_len);
239151f421c8SRevanth Rajashekar return -EINVAL;
239251f421c8SRevanth Rajashekar }
239351f421c8SRevanth Rajashekar
239451f421c8SRevanth Rajashekar while (off < read_size) {
239551f421c8SRevanth Rajashekar err = cmd_start(dev, read_tbl->table_uid, opalmethod[OPAL_GET]);
239651f421c8SRevanth Rajashekar
239751f421c8SRevanth Rajashekar add_token_u8(&err, dev, OPAL_STARTLIST);
239851f421c8SRevanth Rajashekar add_token_u8(&err, dev, OPAL_STARTNAME);
239951f421c8SRevanth Rajashekar add_token_u8(&err, dev, OPAL_STARTROW);
240051f421c8SRevanth Rajashekar add_token_u64(&err, dev, offset + off); /* start row value */
240151f421c8SRevanth Rajashekar add_token_u8(&err, dev, OPAL_ENDNAME);
240251f421c8SRevanth Rajashekar
240351f421c8SRevanth Rajashekar add_token_u8(&err, dev, OPAL_STARTNAME);
240451f421c8SRevanth Rajashekar add_token_u8(&err, dev, OPAL_ENDROW);
240551f421c8SRevanth Rajashekar
240651f421c8SRevanth Rajashekar len = min(max_read_size, (size_t)(read_size - off));
240751f421c8SRevanth Rajashekar add_token_u64(&err, dev, offset + off + len); /* end row value
240851f421c8SRevanth Rajashekar */
240951f421c8SRevanth Rajashekar add_token_u8(&err, dev, OPAL_ENDNAME);
241051f421c8SRevanth Rajashekar add_token_u8(&err, dev, OPAL_ENDLIST);
241151f421c8SRevanth Rajashekar
241251f421c8SRevanth Rajashekar if (err) {
241351f421c8SRevanth Rajashekar pr_debug("Error building read table data command.\n");
241451f421c8SRevanth Rajashekar break;
241551f421c8SRevanth Rajashekar }
241651f421c8SRevanth Rajashekar
241751f421c8SRevanth Rajashekar err = finalize_and_send(dev, read_table_data_cont);
241851f421c8SRevanth Rajashekar if (err)
241951f421c8SRevanth Rajashekar break;
242051f421c8SRevanth Rajashekar
242151f421c8SRevanth Rajashekar /* len+1: This includes the NULL terminator at the end*/
242251f421c8SRevanth Rajashekar if (dev->prev_d_len > len + 1) {
242351f421c8SRevanth Rajashekar err = -EOVERFLOW;
242451f421c8SRevanth Rajashekar break;
242551f421c8SRevanth Rajashekar }
242651f421c8SRevanth Rajashekar
242751f421c8SRevanth Rajashekar dst = (u8 __user *)(uintptr_t)read_tbl->data;
242851f421c8SRevanth Rajashekar if (copy_to_user(dst + off, dev->prev_data, dev->prev_d_len)) {
242951f421c8SRevanth Rajashekar pr_debug("Error copying data to userspace\n");
243051f421c8SRevanth Rajashekar err = -EFAULT;
243151f421c8SRevanth Rajashekar break;
243251f421c8SRevanth Rajashekar }
243351f421c8SRevanth Rajashekar dev->prev_data = NULL;
243451f421c8SRevanth Rajashekar
243551f421c8SRevanth Rajashekar off += len;
243651f421c8SRevanth Rajashekar }
243751f421c8SRevanth Rajashekar
243851f421c8SRevanth Rajashekar return err;
243951f421c8SRevanth Rajashekar }
244051f421c8SRevanth Rajashekar
end_opal_session(struct opal_dev * dev,void * data)2441eed64951SJon Derrick static int end_opal_session(struct opal_dev *dev, void *data)
2442455a7b23SScott Bauer {
2443455a7b23SScott Bauer int err = 0;
2444455a7b23SScott Bauer
2445455a7b23SScott Bauer clear_opal_cmd(dev);
2446455a7b23SScott Bauer set_comid(dev, dev->comid);
2447455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDOFSESSION);
2448eed64951SJon Derrick
2449eed64951SJon Derrick if (err < 0)
2450455a7b23SScott Bauer return err;
24515cc23ed7SRevanth Rajashekar
2452455a7b23SScott Bauer return finalize_and_send(dev, end_session_cont);
2453455a7b23SScott Bauer }
2454455a7b23SScott Bauer
end_opal_session_error(struct opal_dev * dev)2455455a7b23SScott Bauer static int end_opal_session_error(struct opal_dev *dev)
2456455a7b23SScott Bauer {
24570af2648eSDavid Kozub const struct opal_step error_end_session = {
24580af2648eSDavid Kozub end_opal_session,
2459455a7b23SScott Bauer };
24605cc23ed7SRevanth Rajashekar
24610af2648eSDavid Kozub return execute_step(dev, &error_end_session, 0);
2462455a7b23SScott Bauer }
2463455a7b23SScott Bauer
setup_opal_dev(struct opal_dev * dev)24643db87236SDavid Kozub static inline void setup_opal_dev(struct opal_dev *dev)
2465455a7b23SScott Bauer {
2466455a7b23SScott Bauer dev->tsn = 0;
2467455a7b23SScott Bauer dev->hsn = 0;
2468455a7b23SScott Bauer dev->prev_data = NULL;
2469455a7b23SScott Bauer }
2470455a7b23SScott Bauer
check_opal_support(struct opal_dev * dev)2471455a7b23SScott Bauer static int check_opal_support(struct opal_dev *dev)
2472455a7b23SScott Bauer {
2473455a7b23SScott Bauer int ret;
2474455a7b23SScott Bauer
2475455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
24763db87236SDavid Kozub setup_opal_dev(dev);
24770af2648eSDavid Kozub ret = opal_discovery0_step(dev);
2478c6ea7060Sdougmill@linux.vnet.ibm.com if (!ret)
2479c6ea7060Sdougmill@linux.vnet.ibm.com dev->flags |= OPAL_FL_SUPPORTED;
2480455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
24815cc23ed7SRevanth Rajashekar
2482455a7b23SScott Bauer return ret;
2483455a7b23SScott Bauer }
2484455a7b23SScott Bauer
clean_opal_dev(struct opal_dev * dev)24857d6d1578SScott Bauer static void clean_opal_dev(struct opal_dev *dev)
24867d6d1578SScott Bauer {
24877d6d1578SScott Bauer
24887d6d1578SScott Bauer struct opal_suspend_data *suspend, *next;
24897d6d1578SScott Bauer
24907d6d1578SScott Bauer mutex_lock(&dev->dev_lock);
24917d6d1578SScott Bauer list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) {
24927d6d1578SScott Bauer list_del(&suspend->node);
24937d6d1578SScott Bauer kfree(suspend);
24947d6d1578SScott Bauer }
24957d6d1578SScott Bauer mutex_unlock(&dev->dev_lock);
24967d6d1578SScott Bauer }
24977d6d1578SScott Bauer
free_opal_dev(struct opal_dev * dev)24987d6d1578SScott Bauer void free_opal_dev(struct opal_dev *dev)
24997d6d1578SScott Bauer {
25007d6d1578SScott Bauer if (!dev)
25017d6d1578SScott Bauer return;
25025cc23ed7SRevanth Rajashekar
25037d6d1578SScott Bauer clean_opal_dev(dev);
2504f829230dSSerge Semin kfree(dev->resp);
2505f829230dSSerge Semin kfree(dev->cmd);
25067d6d1578SScott Bauer kfree(dev);
25077d6d1578SScott Bauer }
25087d6d1578SScott Bauer EXPORT_SYMBOL(free_opal_dev);
25097d6d1578SScott Bauer
init_opal_dev(void * data,sec_send_recv * send_recv)25104f1244c8SChristoph Hellwig struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
2511455a7b23SScott Bauer {
25124f1244c8SChristoph Hellwig struct opal_dev *dev;
25134f1244c8SChristoph Hellwig
25144f1244c8SChristoph Hellwig dev = kmalloc(sizeof(*dev), GFP_KERNEL);
25154f1244c8SChristoph Hellwig if (!dev)
25164f1244c8SChristoph Hellwig return NULL;
25174f1244c8SChristoph Hellwig
2518f829230dSSerge Semin /*
2519f829230dSSerge Semin * Presumably DMA-able buffers must be cache-aligned. Kmalloc makes
2520f829230dSSerge Semin * sure the allocated buffer is DMA-safe in that regard.
2521f829230dSSerge Semin */
2522f829230dSSerge Semin dev->cmd = kmalloc(IO_BUFFER_LENGTH, GFP_KERNEL);
2523f829230dSSerge Semin if (!dev->cmd)
2524f829230dSSerge Semin goto err_free_dev;
2525f829230dSSerge Semin
2526f829230dSSerge Semin dev->resp = kmalloc(IO_BUFFER_LENGTH, GFP_KERNEL);
2527f829230dSSerge Semin if (!dev->resp)
2528f829230dSSerge Semin goto err_free_cmd;
2529f829230dSSerge Semin
25304f1244c8SChristoph Hellwig INIT_LIST_HEAD(&dev->unlk_lst);
25314f1244c8SChristoph Hellwig mutex_init(&dev->dev_lock);
2532c6ea7060Sdougmill@linux.vnet.ibm.com dev->flags = 0;
25334f1244c8SChristoph Hellwig dev->data = data;
25344f1244c8SChristoph Hellwig dev->send_recv = send_recv;
25354f1244c8SChristoph Hellwig if (check_opal_support(dev) != 0) {
2536f5b37b7cSChristoph Hellwig pr_debug("Opal is not supported on this device\n");
2537f829230dSSerge Semin goto err_free_resp;
25384f1244c8SChristoph Hellwig }
25395cc23ed7SRevanth Rajashekar
25404f1244c8SChristoph Hellwig return dev;
2541f829230dSSerge Semin
2542f829230dSSerge Semin err_free_resp:
2543f829230dSSerge Semin kfree(dev->resp);
2544f829230dSSerge Semin
2545f829230dSSerge Semin err_free_cmd:
2546f829230dSSerge Semin kfree(dev->cmd);
2547f829230dSSerge Semin
2548f829230dSSerge Semin err_free_dev:
2549f829230dSSerge Semin kfree(dev);
2550f829230dSSerge Semin
2551f829230dSSerge Semin return NULL;
2552455a7b23SScott Bauer }
2553455a7b23SScott Bauer EXPORT_SYMBOL(init_opal_dev);
2554455a7b23SScott Bauer
opal_secure_erase_locking_range(struct opal_dev * dev,struct opal_session_info * opal_session)2555455a7b23SScott Bauer static int opal_secure_erase_locking_range(struct opal_dev *dev,
2556455a7b23SScott Bauer struct opal_session_info *opal_session)
2557455a7b23SScott Bauer {
2558eed64951SJon Derrick const struct opal_step erase_steps[] = {
2559eed64951SJon Derrick { start_auth_opal_session, opal_session },
2560eed64951SJon Derrick { get_active_key, &opal_session->opal_key.lr },
2561eed64951SJon Derrick { gen_key, },
25623db87236SDavid Kozub { end_opal_session, }
2563455a7b23SScott Bauer };
2564455a7b23SScott Bauer int ret;
2565455a7b23SScott Bauer
25663bfeb612SGreg Joyce ret = opal_get_key(dev, &opal_session->opal_key);
25673bfeb612SGreg Joyce if (ret)
25683bfeb612SGreg Joyce return ret;
2569455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
25703db87236SDavid Kozub setup_opal_dev(dev);
2571a80f36ccSDavid Kozub ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
2572455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
25735cc23ed7SRevanth Rajashekar
2574455a7b23SScott Bauer return ret;
2575455a7b23SScott Bauer }
2576455a7b23SScott Bauer
opal_get_discv(struct opal_dev * dev,struct opal_discovery * discv)25779fb10726SGreg Joyce static int opal_get_discv(struct opal_dev *dev, struct opal_discovery *discv)
25789fb10726SGreg Joyce {
25799fb10726SGreg Joyce const struct opal_step discovery0_step = {
25809fb10726SGreg Joyce opal_discovery0, discv
25819fb10726SGreg Joyce };
25829fb10726SGreg Joyce int ret = 0;
25839fb10726SGreg Joyce
25849fb10726SGreg Joyce mutex_lock(&dev->dev_lock);
25859fb10726SGreg Joyce setup_opal_dev(dev);
25869fb10726SGreg Joyce ret = execute_step(dev, &discovery0_step, 0);
25879fb10726SGreg Joyce mutex_unlock(&dev->dev_lock);
25889fb10726SGreg Joyce if (ret)
25899fb10726SGreg Joyce return ret;
25909fb10726SGreg Joyce return discv->size; /* modified to actual length of data */
25919fb10726SGreg Joyce }
25929fb10726SGreg Joyce
opal_revertlsp(struct opal_dev * dev,struct opal_revert_lsp * rev)25935c82efc1SGreg Joyce static int opal_revertlsp(struct opal_dev *dev, struct opal_revert_lsp *rev)
25945c82efc1SGreg Joyce {
25955c82efc1SGreg Joyce /* controller will terminate session */
25965c82efc1SGreg Joyce const struct opal_step steps[] = {
25975c82efc1SGreg Joyce { start_admin1LSP_opal_session, &rev->key },
25985c82efc1SGreg Joyce { revert_lsp, rev }
25995c82efc1SGreg Joyce };
26005c82efc1SGreg Joyce int ret;
26015c82efc1SGreg Joyce
26023bfeb612SGreg Joyce ret = opal_get_key(dev, &rev->key);
26033bfeb612SGreg Joyce if (ret)
26043bfeb612SGreg Joyce return ret;
26055c82efc1SGreg Joyce mutex_lock(&dev->dev_lock);
26065c82efc1SGreg Joyce setup_opal_dev(dev);
26075c82efc1SGreg Joyce ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
26085c82efc1SGreg Joyce mutex_unlock(&dev->dev_lock);
26095c82efc1SGreg Joyce
26105c82efc1SGreg Joyce return ret;
26115c82efc1SGreg Joyce }
26125c82efc1SGreg Joyce
opal_erase_locking_range(struct opal_dev * dev,struct opal_session_info * opal_session)2613455a7b23SScott Bauer static int opal_erase_locking_range(struct opal_dev *dev,
2614455a7b23SScott Bauer struct opal_session_info *opal_session)
2615455a7b23SScott Bauer {
2616eed64951SJon Derrick const struct opal_step erase_steps[] = {
2617eed64951SJon Derrick { start_auth_opal_session, opal_session },
2618eed64951SJon Derrick { erase_locking_range, opal_session },
26193db87236SDavid Kozub { end_opal_session, }
2620455a7b23SScott Bauer };
2621455a7b23SScott Bauer int ret;
2622455a7b23SScott Bauer
26233bfeb612SGreg Joyce ret = opal_get_key(dev, &opal_session->opal_key);
26243bfeb612SGreg Joyce if (ret)
26253bfeb612SGreg Joyce return ret;
2626455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
26273db87236SDavid Kozub setup_opal_dev(dev);
2628a80f36ccSDavid Kozub ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
2629455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
26305cc23ed7SRevanth Rajashekar
2631455a7b23SScott Bauer return ret;
2632455a7b23SScott Bauer }
2633455a7b23SScott Bauer
opal_enable_disable_shadow_mbr(struct opal_dev * dev,struct opal_mbr_data * opal_mbr)2634455a7b23SScott Bauer static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
2635455a7b23SScott Bauer struct opal_mbr_data *opal_mbr)
2636455a7b23SScott Bauer {
263778bf4735SDavid Kozub u8 enable_disable = opal_mbr->enable_disable == OPAL_MBR_ENABLE ?
263878bf4735SDavid Kozub OPAL_TRUE : OPAL_FALSE;
263978bf4735SDavid Kozub
2640eed64951SJon Derrick const struct opal_step mbr_steps[] = {
2641eed64951SJon Derrick { start_admin1LSP_opal_session, &opal_mbr->key },
264278bf4735SDavid Kozub { set_mbr_done, &enable_disable },
2643eed64951SJon Derrick { end_opal_session, },
2644eed64951SJon Derrick { start_admin1LSP_opal_session, &opal_mbr->key },
264578bf4735SDavid Kozub { set_mbr_enable_disable, &enable_disable },
26463db87236SDavid Kozub { end_opal_session, }
2647455a7b23SScott Bauer };
2648455a7b23SScott Bauer int ret;
2649455a7b23SScott Bauer
2650455a7b23SScott Bauer if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
2651455a7b23SScott Bauer opal_mbr->enable_disable != OPAL_MBR_DISABLE)
2652455a7b23SScott Bauer return -EINVAL;
2653455a7b23SScott Bauer
26543bfeb612SGreg Joyce ret = opal_get_key(dev, &opal_mbr->key);
26553bfeb612SGreg Joyce if (ret)
26563bfeb612SGreg Joyce return ret;
2657455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
26583db87236SDavid Kozub setup_opal_dev(dev);
2659a80f36ccSDavid Kozub ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
2660455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
26615cc23ed7SRevanth Rajashekar
2662455a7b23SScott Bauer return ret;
2663455a7b23SScott Bauer }
2664455a7b23SScott Bauer
opal_set_mbr_done(struct opal_dev * dev,struct opal_mbr_done * mbr_done)2665c9888443SJonas Rabenstein static int opal_set_mbr_done(struct opal_dev *dev,
2666c9888443SJonas Rabenstein struct opal_mbr_done *mbr_done)
2667c9888443SJonas Rabenstein {
2668c9888443SJonas Rabenstein u8 mbr_done_tf = mbr_done->done_flag == OPAL_MBR_DONE ?
2669c9888443SJonas Rabenstein OPAL_TRUE : OPAL_FALSE;
2670c9888443SJonas Rabenstein
2671c9888443SJonas Rabenstein const struct opal_step mbr_steps[] = {
2672c9888443SJonas Rabenstein { start_admin1LSP_opal_session, &mbr_done->key },
2673c9888443SJonas Rabenstein { set_mbr_done, &mbr_done_tf },
2674c9888443SJonas Rabenstein { end_opal_session, }
2675c9888443SJonas Rabenstein };
2676c9888443SJonas Rabenstein int ret;
2677c9888443SJonas Rabenstein
2678c9888443SJonas Rabenstein if (mbr_done->done_flag != OPAL_MBR_DONE &&
2679c9888443SJonas Rabenstein mbr_done->done_flag != OPAL_MBR_NOT_DONE)
2680c9888443SJonas Rabenstein return -EINVAL;
2681c9888443SJonas Rabenstein
26823bfeb612SGreg Joyce ret = opal_get_key(dev, &mbr_done->key);
26833bfeb612SGreg Joyce if (ret)
26843bfeb612SGreg Joyce return ret;
2685c9888443SJonas Rabenstein mutex_lock(&dev->dev_lock);
2686c9888443SJonas Rabenstein setup_opal_dev(dev);
2687c9888443SJonas Rabenstein ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
2688c9888443SJonas Rabenstein mutex_unlock(&dev->dev_lock);
26895cc23ed7SRevanth Rajashekar
2690c9888443SJonas Rabenstein return ret;
2691c9888443SJonas Rabenstein }
2692c9888443SJonas Rabenstein
opal_write_shadow_mbr(struct opal_dev * dev,struct opal_shadow_mbr * info)2693a9b25b4cSJonas Rabenstein static int opal_write_shadow_mbr(struct opal_dev *dev,
2694a9b25b4cSJonas Rabenstein struct opal_shadow_mbr *info)
2695a9b25b4cSJonas Rabenstein {
2696a9b25b4cSJonas Rabenstein const struct opal_step mbr_steps[] = {
2697a9b25b4cSJonas Rabenstein { start_admin1LSP_opal_session, &info->key },
2698a9b25b4cSJonas Rabenstein { write_shadow_mbr, info },
2699a9b25b4cSJonas Rabenstein { end_opal_session, }
2700a9b25b4cSJonas Rabenstein };
2701a9b25b4cSJonas Rabenstein int ret;
2702a9b25b4cSJonas Rabenstein
2703a9b25b4cSJonas Rabenstein if (info->size == 0)
2704a9b25b4cSJonas Rabenstein return 0;
2705a9b25b4cSJonas Rabenstein
27063bfeb612SGreg Joyce ret = opal_get_key(dev, &info->key);
27073bfeb612SGreg Joyce if (ret)
27083bfeb612SGreg Joyce return ret;
2709a9b25b4cSJonas Rabenstein mutex_lock(&dev->dev_lock);
2710a9b25b4cSJonas Rabenstein setup_opal_dev(dev);
2711a9b25b4cSJonas Rabenstein ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
2712a9b25b4cSJonas Rabenstein mutex_unlock(&dev->dev_lock);
27135cc23ed7SRevanth Rajashekar
2714a9b25b4cSJonas Rabenstein return ret;
2715a9b25b4cSJonas Rabenstein }
2716a9b25b4cSJonas Rabenstein
opal_save(struct opal_dev * dev,struct opal_lock_unlock * lk_unlk)2717455a7b23SScott Bauer static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
2718455a7b23SScott Bauer {
2719455a7b23SScott Bauer struct opal_suspend_data *suspend;
2720455a7b23SScott Bauer
2721455a7b23SScott Bauer suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
2722455a7b23SScott Bauer if (!suspend)
2723455a7b23SScott Bauer return -ENOMEM;
2724455a7b23SScott Bauer
2725455a7b23SScott Bauer suspend->unlk = *lk_unlk;
2726455a7b23SScott Bauer suspend->lr = lk_unlk->session.opal_key.lr;
2727455a7b23SScott Bauer
2728455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
27293db87236SDavid Kozub setup_opal_dev(dev);
2730455a7b23SScott Bauer add_suspend_info(dev, suspend);
2731455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
27325cc23ed7SRevanth Rajashekar
2733455a7b23SScott Bauer return 0;
2734455a7b23SScott Bauer }
2735455a7b23SScott Bauer
opal_add_user_to_lr(struct opal_dev * dev,struct opal_lock_unlock * lk_unlk)2736455a7b23SScott Bauer static int opal_add_user_to_lr(struct opal_dev *dev,
2737455a7b23SScott Bauer struct opal_lock_unlock *lk_unlk)
2738455a7b23SScott Bauer {
2739eed64951SJon Derrick const struct opal_step steps[] = {
2740eed64951SJon Derrick { start_admin1LSP_opal_session, &lk_unlk->session.opal_key },
2741eed64951SJon Derrick { add_user_to_lr, lk_unlk },
27428be19a02SOndrej Kozina { add_user_to_lr_ace, lk_unlk },
27433db87236SDavid Kozub { end_opal_session, }
2744455a7b23SScott Bauer };
2745455a7b23SScott Bauer int ret;
2746455a7b23SScott Bauer
2747455a7b23SScott Bauer if (lk_unlk->l_state != OPAL_RO &&
2748455a7b23SScott Bauer lk_unlk->l_state != OPAL_RW) {
2749591c59d1SScott Bauer pr_debug("Locking state was not RO or RW\n");
2750455a7b23SScott Bauer return -EINVAL;
2751455a7b23SScott Bauer }
27525cc23ed7SRevanth Rajashekar
2753b0bfdfc2SJon Derrick if (lk_unlk->session.who < OPAL_USER1 ||
2754455a7b23SScott Bauer lk_unlk->session.who > OPAL_USER9) {
2755591c59d1SScott Bauer pr_debug("Authority was not within the range of users: %d\n",
2756455a7b23SScott Bauer lk_unlk->session.who);
2757455a7b23SScott Bauer return -EINVAL;
2758455a7b23SScott Bauer }
27595cc23ed7SRevanth Rajashekar
2760455a7b23SScott Bauer if (lk_unlk->session.sum) {
2761591c59d1SScott Bauer pr_debug("%s not supported in sum. Use setup locking range\n",
2762455a7b23SScott Bauer __func__);
2763455a7b23SScott Bauer return -EINVAL;
2764455a7b23SScott Bauer }
2765455a7b23SScott Bauer
27663bfeb612SGreg Joyce ret = opal_get_key(dev, &lk_unlk->session.opal_key);
27673bfeb612SGreg Joyce if (ret)
27683bfeb612SGreg Joyce return ret;
2769455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
27703db87236SDavid Kozub setup_opal_dev(dev);
2771a80f36ccSDavid Kozub ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
2772455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
27735cc23ed7SRevanth Rajashekar
2774455a7b23SScott Bauer return ret;
2775455a7b23SScott Bauer }
2776455a7b23SScott Bauer
opal_reverttper(struct opal_dev * dev,struct opal_key * opal,bool psid)27775e4c7cf6SRevanth Rajashekar static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal, bool psid)
2778455a7b23SScott Bauer {
27795e4c7cf6SRevanth Rajashekar /* controller will terminate session */
2780eed64951SJon Derrick const struct opal_step revert_steps[] = {
2781eed64951SJon Derrick { start_SIDASP_opal_session, opal },
27825e4c7cf6SRevanth Rajashekar { revert_tper, }
2783455a7b23SScott Bauer };
27845e4c7cf6SRevanth Rajashekar const struct opal_step psid_revert_steps[] = {
27855e4c7cf6SRevanth Rajashekar { start_PSID_opal_session, opal },
27865e4c7cf6SRevanth Rajashekar { revert_tper, }
27875e4c7cf6SRevanth Rajashekar };
27885e4c7cf6SRevanth Rajashekar
2789455a7b23SScott Bauer int ret;
2790455a7b23SScott Bauer
27913bfeb612SGreg Joyce ret = opal_get_key(dev, opal);
27923bfeb612SGreg Joyce
27933bfeb612SGreg Joyce if (ret)
27943bfeb612SGreg Joyce return ret;
2795455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
27963db87236SDavid Kozub setup_opal_dev(dev);
27975e4c7cf6SRevanth Rajashekar if (psid)
27985e4c7cf6SRevanth Rajashekar ret = execute_steps(dev, psid_revert_steps,
27995e4c7cf6SRevanth Rajashekar ARRAY_SIZE(psid_revert_steps));
28005e4c7cf6SRevanth Rajashekar else
28015e4c7cf6SRevanth Rajashekar ret = execute_steps(dev, revert_steps,
28025e4c7cf6SRevanth Rajashekar ARRAY_SIZE(revert_steps));
2803455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
28047d6d1578SScott Bauer
28057d6d1578SScott Bauer /*
28067d6d1578SScott Bauer * If we successfully reverted lets clean
28077d6d1578SScott Bauer * any saved locking ranges.
28087d6d1578SScott Bauer */
28097d6d1578SScott Bauer if (!ret)
28107d6d1578SScott Bauer clean_opal_dev(dev);
28117d6d1578SScott Bauer
2812455a7b23SScott Bauer return ret;
2813455a7b23SScott Bauer }
2814455a7b23SScott Bauer
__opal_lock_unlock(struct opal_dev * dev,struct opal_lock_unlock * lk_unlk)2815eed64951SJon Derrick static int __opal_lock_unlock(struct opal_dev *dev,
2816eed64951SJon Derrick struct opal_lock_unlock *lk_unlk)
2817455a7b23SScott Bauer {
2818eed64951SJon Derrick const struct opal_step unlock_steps[] = {
2819eed64951SJon Derrick { start_auth_opal_session, &lk_unlk->session },
2820eed64951SJon Derrick { lock_unlock_locking_range, lk_unlk },
28213db87236SDavid Kozub { end_opal_session, }
2822eed64951SJon Derrick };
2823eed64951SJon Derrick const struct opal_step unlock_sum_steps[] = {
2824eed64951SJon Derrick { start_auth_opal_session, &lk_unlk->session },
2825eed64951SJon Derrick { lock_unlock_locking_range_sum, lk_unlk },
28263db87236SDavid Kozub { end_opal_session, }
2827455a7b23SScott Bauer };
2828455a7b23SScott Bauer
28293db87236SDavid Kozub if (lk_unlk->session.sum)
2830a80f36ccSDavid Kozub return execute_steps(dev, unlock_sum_steps,
28313db87236SDavid Kozub ARRAY_SIZE(unlock_sum_steps));
28323db87236SDavid Kozub else
2833a80f36ccSDavid Kozub return execute_steps(dev, unlock_steps,
2834a80f36ccSDavid Kozub ARRAY_SIZE(unlock_steps));
2835455a7b23SScott Bauer }
2836455a7b23SScott Bauer
__opal_set_mbr_done(struct opal_dev * dev,struct opal_key * key)2837dbec491bSScott Bauer static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key)
2838dbec491bSScott Bauer {
283978bf4735SDavid Kozub u8 mbr_done_tf = OPAL_TRUE;
2840dbec491bSScott Bauer const struct opal_step mbrdone_step[] = {
2841dbec491bSScott Bauer { start_admin1LSP_opal_session, key },
2842dbec491bSScott Bauer { set_mbr_done, &mbr_done_tf },
28433db87236SDavid Kozub { end_opal_session, }
2844dbec491bSScott Bauer };
2845dbec491bSScott Bauer
2846a80f36ccSDavid Kozub return execute_steps(dev, mbrdone_step, ARRAY_SIZE(mbrdone_step));
2847dbec491bSScott Bauer }
2848dbec491bSScott Bauer
opal_lock_check_for_saved_key(struct opal_dev * dev,struct opal_lock_unlock * lk_unlk)2849c1f480b2SLuca Boccassi static void opal_lock_check_for_saved_key(struct opal_dev *dev,
2850c1f480b2SLuca Boccassi struct opal_lock_unlock *lk_unlk)
2851c1f480b2SLuca Boccassi {
2852c1f480b2SLuca Boccassi struct opal_suspend_data *iter;
2853c1f480b2SLuca Boccassi
2854c1f480b2SLuca Boccassi if (lk_unlk->l_state != OPAL_LK ||
2855c1f480b2SLuca Boccassi lk_unlk->session.opal_key.key_len > 0)
2856c1f480b2SLuca Boccassi return;
2857c1f480b2SLuca Boccassi
2858c1f480b2SLuca Boccassi /*
2859c1f480b2SLuca Boccassi * Usually when closing a crypto device (eg: dm-crypt with LUKS) the
2860c1f480b2SLuca Boccassi * volume key is not required, as it requires root privileges anyway,
2861c1f480b2SLuca Boccassi * and root can deny access to a disk in many ways regardless.
2862c1f480b2SLuca Boccassi * Requiring the volume key to lock the device is a peculiarity of the
2863c1f480b2SLuca Boccassi * OPAL specification. Given we might already have saved the key if
2864c1f480b2SLuca Boccassi * the user requested it via the 'IOC_OPAL_SAVE' ioctl, we can use
2865c1f480b2SLuca Boccassi * that key to lock the device if no key was provided here, the
2866c1f480b2SLuca Boccassi * locking range matches and the appropriate flag was passed with
2867c1f480b2SLuca Boccassi * 'IOC_OPAL_SAVE'.
2868c1f480b2SLuca Boccassi * This allows integrating OPAL with tools and libraries that are used
2869c1f480b2SLuca Boccassi * to the common behaviour and do not ask for the volume key when
2870c1f480b2SLuca Boccassi * closing a device.
2871c1f480b2SLuca Boccassi */
2872c1f480b2SLuca Boccassi setup_opal_dev(dev);
2873c1f480b2SLuca Boccassi list_for_each_entry(iter, &dev->unlk_lst, node) {
2874c1f480b2SLuca Boccassi if ((iter->unlk.flags & OPAL_SAVE_FOR_LOCK) &&
2875c1f480b2SLuca Boccassi iter->lr == lk_unlk->session.opal_key.lr &&
2876c1f480b2SLuca Boccassi iter->unlk.session.opal_key.key_len > 0) {
2877c1f480b2SLuca Boccassi lk_unlk->session.opal_key.key_len =
2878c1f480b2SLuca Boccassi iter->unlk.session.opal_key.key_len;
2879c1f480b2SLuca Boccassi memcpy(lk_unlk->session.opal_key.key,
2880c1f480b2SLuca Boccassi iter->unlk.session.opal_key.key,
2881c1f480b2SLuca Boccassi iter->unlk.session.opal_key.key_len);
2882c1f480b2SLuca Boccassi break;
2883c1f480b2SLuca Boccassi }
2884c1f480b2SLuca Boccassi }
2885c1f480b2SLuca Boccassi }
2886c1f480b2SLuca Boccassi
opal_lock_unlock(struct opal_dev * dev,struct opal_lock_unlock * lk_unlk)2887eed64951SJon Derrick static int opal_lock_unlock(struct opal_dev *dev,
2888eed64951SJon Derrick struct opal_lock_unlock *lk_unlk)
2889455a7b23SScott Bauer {
2890455a7b23SScott Bauer int ret;
2891455a7b23SScott Bauer
289215ddffcbSRevanth Rajashekar if (lk_unlk->session.who > OPAL_USER9)
2893455a7b23SScott Bauer return -EINVAL;
2894455a7b23SScott Bauer
2895455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
2896c1f480b2SLuca Boccassi opal_lock_check_for_saved_key(dev, lk_unlk);
28974eaf0932SMilan Broz ret = opal_get_key(dev, &lk_unlk->session.opal_key);
28984eaf0932SMilan Broz if (!ret)
2899eed64951SJon Derrick ret = __opal_lock_unlock(dev, lk_unlk);
2900455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
29015cc23ed7SRevanth Rajashekar
2902455a7b23SScott Bauer return ret;
2903455a7b23SScott Bauer }
2904455a7b23SScott Bauer
opal_take_ownership(struct opal_dev * dev,struct opal_key * opal)2905455a7b23SScott Bauer static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
2906455a7b23SScott Bauer {
2907eed64951SJon Derrick const struct opal_step owner_steps[] = {
2908eed64951SJon Derrick { start_anybodyASP_opal_session, },
2909eed64951SJon Derrick { get_msid_cpin_pin, },
2910eed64951SJon Derrick { end_opal_session, },
2911eed64951SJon Derrick { start_SIDASP_opal_session, opal },
2912eed64951SJon Derrick { set_sid_cpin_pin, opal },
29133db87236SDavid Kozub { end_opal_session, }
2914455a7b23SScott Bauer };
2915455a7b23SScott Bauer int ret;
2916455a7b23SScott Bauer
2917455a7b23SScott Bauer if (!dev)
2918455a7b23SScott Bauer return -ENODEV;
2919455a7b23SScott Bauer
29203bfeb612SGreg Joyce ret = opal_get_key(dev, opal);
29213bfeb612SGreg Joyce if (ret)
29223bfeb612SGreg Joyce return ret;
2923455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
29243db87236SDavid Kozub setup_opal_dev(dev);
2925a80f36ccSDavid Kozub ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps));
2926455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
29275cc23ed7SRevanth Rajashekar
2928455a7b23SScott Bauer return ret;
2929455a7b23SScott Bauer }
2930455a7b23SScott Bauer
opal_activate_lsp(struct opal_dev * dev,struct opal_lr_act * opal_lr_act)29311e815b33SDavid Kozub static int opal_activate_lsp(struct opal_dev *dev,
29321e815b33SDavid Kozub struct opal_lr_act *opal_lr_act)
2933455a7b23SScott Bauer {
2934eed64951SJon Derrick const struct opal_step active_steps[] = {
2935eed64951SJon Derrick { start_SIDASP_opal_session, &opal_lr_act->key },
2936eed64951SJon Derrick { get_lsp_lifecycle, },
2937eed64951SJon Derrick { activate_lsp, opal_lr_act },
29383db87236SDavid Kozub { end_opal_session, }
2939455a7b23SScott Bauer };
2940455a7b23SScott Bauer int ret;
2941455a7b23SScott Bauer
2942455a7b23SScott Bauer if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
2943455a7b23SScott Bauer return -EINVAL;
2944455a7b23SScott Bauer
29453bfeb612SGreg Joyce ret = opal_get_key(dev, &opal_lr_act->key);
29463bfeb612SGreg Joyce if (ret)
29473bfeb612SGreg Joyce return ret;
2948455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
29493db87236SDavid Kozub setup_opal_dev(dev);
2950a80f36ccSDavid Kozub ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps));
2951455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
29525cc23ed7SRevanth Rajashekar
2953455a7b23SScott Bauer return ret;
2954455a7b23SScott Bauer }
2955455a7b23SScott Bauer
opal_setup_locking_range(struct opal_dev * dev,struct opal_user_lr_setup * opal_lrs)2956455a7b23SScott Bauer static int opal_setup_locking_range(struct opal_dev *dev,
2957455a7b23SScott Bauer struct opal_user_lr_setup *opal_lrs)
2958455a7b23SScott Bauer {
2959eed64951SJon Derrick const struct opal_step lr_steps[] = {
2960eed64951SJon Derrick { start_auth_opal_session, &opal_lrs->session },
2961eed64951SJon Derrick { setup_locking_range, opal_lrs },
29623db87236SDavid Kozub { end_opal_session, }
2963455a7b23SScott Bauer };
2964455a7b23SScott Bauer int ret;
2965455a7b23SScott Bauer
29663bfeb612SGreg Joyce ret = opal_get_key(dev, &opal_lrs->session.opal_key);
29673bfeb612SGreg Joyce if (ret)
29683bfeb612SGreg Joyce return ret;
2969455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
29703db87236SDavid Kozub setup_opal_dev(dev);
2971a80f36ccSDavid Kozub ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
2972455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
29735cc23ed7SRevanth Rajashekar
2974455a7b23SScott Bauer return ret;
2975455a7b23SScott Bauer }
2976455a7b23SScott Bauer
opal_locking_range_status(struct opal_dev * dev,struct opal_lr_status * opal_lrst,void __user * data)29774c4dd04eSOndrej Kozina static int opal_locking_range_status(struct opal_dev *dev,
29784c4dd04eSOndrej Kozina struct opal_lr_status *opal_lrst,
29794c4dd04eSOndrej Kozina void __user *data)
29804c4dd04eSOndrej Kozina {
29814c4dd04eSOndrej Kozina const struct opal_step lr_steps[] = {
29824c4dd04eSOndrej Kozina { start_auth_opal_session, &opal_lrst->session },
29834c4dd04eSOndrej Kozina { locking_range_status, opal_lrst },
29844c4dd04eSOndrej Kozina { end_opal_session, }
29854c4dd04eSOndrej Kozina };
29864c4dd04eSOndrej Kozina int ret;
29874c4dd04eSOndrej Kozina
29884c4dd04eSOndrej Kozina mutex_lock(&dev->dev_lock);
29894c4dd04eSOndrej Kozina setup_opal_dev(dev);
29904c4dd04eSOndrej Kozina ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
29914c4dd04eSOndrej Kozina mutex_unlock(&dev->dev_lock);
29924c4dd04eSOndrej Kozina
29934c4dd04eSOndrej Kozina /* skip session info when copying back to uspace */
29944c4dd04eSOndrej Kozina if (!ret && copy_to_user(data + offsetof(struct opal_lr_status, range_start),
29954c4dd04eSOndrej Kozina (void *)opal_lrst + offsetof(struct opal_lr_status, range_start),
29964c4dd04eSOndrej Kozina sizeof(*opal_lrst) - offsetof(struct opal_lr_status, range_start))) {
29974c4dd04eSOndrej Kozina pr_debug("Error copying status to userspace\n");
29984c4dd04eSOndrej Kozina return -EFAULT;
29994c4dd04eSOndrej Kozina }
30004c4dd04eSOndrej Kozina
30014c4dd04eSOndrej Kozina return ret;
30024c4dd04eSOndrej Kozina }
30034c4dd04eSOndrej Kozina
opal_set_new_pw(struct opal_dev * dev,struct opal_new_pw * opal_pw)3004455a7b23SScott Bauer static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
3005455a7b23SScott Bauer {
3006eed64951SJon Derrick const struct opal_step pw_steps[] = {
3007eed64951SJon Derrick { start_auth_opal_session, &opal_pw->session },
3008eed64951SJon Derrick { set_new_pw, &opal_pw->new_user_pw },
30093db87236SDavid Kozub { end_opal_session, }
3010455a7b23SScott Bauer };
3011455a7b23SScott Bauer int ret;
3012455a7b23SScott Bauer
301315ddffcbSRevanth Rajashekar if (opal_pw->session.who > OPAL_USER9 ||
3014455a7b23SScott Bauer opal_pw->new_user_pw.who > OPAL_USER9)
3015455a7b23SScott Bauer return -EINVAL;
3016455a7b23SScott Bauer
3017455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
30183db87236SDavid Kozub setup_opal_dev(dev);
3019a80f36ccSDavid Kozub ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
3020455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
30215cc23ed7SRevanth Rajashekar
30223bfeb612SGreg Joyce if (ret)
30233bfeb612SGreg Joyce return ret;
30243bfeb612SGreg Joyce
30253bfeb612SGreg Joyce /* update keyring with new password */
30263bfeb612SGreg Joyce ret = update_sed_opal_key(OPAL_AUTH_KEY,
30273bfeb612SGreg Joyce opal_pw->new_user_pw.opal_key.key,
30283bfeb612SGreg Joyce opal_pw->new_user_pw.opal_key.key_len);
30293bfeb612SGreg Joyce
3030455a7b23SScott Bauer return ret;
3031455a7b23SScott Bauer }
3032455a7b23SScott Bauer
opal_activate_user(struct opal_dev * dev,struct opal_session_info * opal_session)3033455a7b23SScott Bauer static int opal_activate_user(struct opal_dev *dev,
3034455a7b23SScott Bauer struct opal_session_info *opal_session)
3035455a7b23SScott Bauer {
3036eed64951SJon Derrick const struct opal_step act_steps[] = {
3037eed64951SJon Derrick { start_admin1LSP_opal_session, &opal_session->opal_key },
3038eed64951SJon Derrick { internal_activate_user, opal_session },
30393db87236SDavid Kozub { end_opal_session, }
3040455a7b23SScott Bauer };
3041455a7b23SScott Bauer int ret;
3042455a7b23SScott Bauer
3043455a7b23SScott Bauer /* We can't activate Admin1 it's active as manufactured */
3044b0bfdfc2SJon Derrick if (opal_session->who < OPAL_USER1 ||
3045455a7b23SScott Bauer opal_session->who > OPAL_USER9) {
3046591c59d1SScott Bauer pr_debug("Who was not a valid user: %d\n", opal_session->who);
3047455a7b23SScott Bauer return -EINVAL;
3048455a7b23SScott Bauer }
3049455a7b23SScott Bauer
30503bfeb612SGreg Joyce ret = opal_get_key(dev, &opal_session->opal_key);
30513bfeb612SGreg Joyce if (ret)
30523bfeb612SGreg Joyce return ret;
3053455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
30543db87236SDavid Kozub setup_opal_dev(dev);
3055a80f36ccSDavid Kozub ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps));
3056455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
30575cc23ed7SRevanth Rajashekar
3058455a7b23SScott Bauer return ret;
3059455a7b23SScott Bauer }
3060455a7b23SScott Bauer
opal_unlock_from_suspend(struct opal_dev * dev)3061455a7b23SScott Bauer bool opal_unlock_from_suspend(struct opal_dev *dev)
3062455a7b23SScott Bauer {
3063455a7b23SScott Bauer struct opal_suspend_data *suspend;
3064455a7b23SScott Bauer bool was_failure = false;
3065455a7b23SScott Bauer int ret = 0;
3066455a7b23SScott Bauer
3067455a7b23SScott Bauer if (!dev)
3068455a7b23SScott Bauer return false;
30695cc23ed7SRevanth Rajashekar
3070c6ea7060Sdougmill@linux.vnet.ibm.com if (!(dev->flags & OPAL_FL_SUPPORTED))
3071455a7b23SScott Bauer return false;
3072455a7b23SScott Bauer
3073455a7b23SScott Bauer mutex_lock(&dev->dev_lock);
30743db87236SDavid Kozub setup_opal_dev(dev);
3075455a7b23SScott Bauer
3076455a7b23SScott Bauer list_for_each_entry(suspend, &dev->unlk_lst, node) {
3077455a7b23SScott Bauer dev->tsn = 0;
3078455a7b23SScott Bauer dev->hsn = 0;
3079455a7b23SScott Bauer
3080eed64951SJon Derrick ret = __opal_lock_unlock(dev, &suspend->unlk);
3081455a7b23SScott Bauer if (ret) {
3082591c59d1SScott Bauer pr_debug("Failed to unlock LR %hhu with sum %d\n",
3083455a7b23SScott Bauer suspend->unlk.session.opal_key.lr,
3084455a7b23SScott Bauer suspend->unlk.session.sum);
3085455a7b23SScott Bauer was_failure = true;
3086455a7b23SScott Bauer }
30875cc23ed7SRevanth Rajashekar
3088c6ea7060Sdougmill@linux.vnet.ibm.com if (dev->flags & OPAL_FL_MBR_ENABLED) {
3089dbec491bSScott Bauer ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key);
3090dbec491bSScott Bauer if (ret)
3091dbec491bSScott Bauer pr_debug("Failed to set MBR Done in S3 resume\n");
3092dbec491bSScott Bauer }
3093455a7b23SScott Bauer }
3094455a7b23SScott Bauer mutex_unlock(&dev->dev_lock);
30955cc23ed7SRevanth Rajashekar
3096455a7b23SScott Bauer return was_failure;
3097455a7b23SScott Bauer }
3098455a7b23SScott Bauer EXPORT_SYMBOL(opal_unlock_from_suspend);
3099455a7b23SScott Bauer
opal_read_table(struct opal_dev * dev,struct opal_read_write_table * rw_tbl)310051f421c8SRevanth Rajashekar static int opal_read_table(struct opal_dev *dev,
310151f421c8SRevanth Rajashekar struct opal_read_write_table *rw_tbl)
310251f421c8SRevanth Rajashekar {
310351f421c8SRevanth Rajashekar const struct opal_step read_table_steps[] = {
310451f421c8SRevanth Rajashekar { start_admin1LSP_opal_session, &rw_tbl->key },
310551f421c8SRevanth Rajashekar { read_table_data, rw_tbl },
310651f421c8SRevanth Rajashekar { end_opal_session, }
310751f421c8SRevanth Rajashekar };
310851f421c8SRevanth Rajashekar int ret = 0;
310951f421c8SRevanth Rajashekar
311051f421c8SRevanth Rajashekar if (!rw_tbl->size)
311151f421c8SRevanth Rajashekar return ret;
311251f421c8SRevanth Rajashekar
311351f421c8SRevanth Rajashekar return execute_steps(dev, read_table_steps,
311451f421c8SRevanth Rajashekar ARRAY_SIZE(read_table_steps));
311551f421c8SRevanth Rajashekar }
311651f421c8SRevanth Rajashekar
opal_write_table(struct opal_dev * dev,struct opal_read_write_table * rw_tbl)311751f421c8SRevanth Rajashekar static int opal_write_table(struct opal_dev *dev,
311851f421c8SRevanth Rajashekar struct opal_read_write_table *rw_tbl)
311951f421c8SRevanth Rajashekar {
312051f421c8SRevanth Rajashekar const struct opal_step write_table_steps[] = {
312151f421c8SRevanth Rajashekar { start_admin1LSP_opal_session, &rw_tbl->key },
312251f421c8SRevanth Rajashekar { write_table_data, rw_tbl },
312351f421c8SRevanth Rajashekar { end_opal_session, }
312451f421c8SRevanth Rajashekar };
312551f421c8SRevanth Rajashekar int ret = 0;
312651f421c8SRevanth Rajashekar
312751f421c8SRevanth Rajashekar if (!rw_tbl->size)
312851f421c8SRevanth Rajashekar return ret;
312951f421c8SRevanth Rajashekar
313051f421c8SRevanth Rajashekar return execute_steps(dev, write_table_steps,
313151f421c8SRevanth Rajashekar ARRAY_SIZE(write_table_steps));
313251f421c8SRevanth Rajashekar }
313351f421c8SRevanth Rajashekar
opal_generic_read_write_table(struct opal_dev * dev,struct opal_read_write_table * rw_tbl)313451f421c8SRevanth Rajashekar static int opal_generic_read_write_table(struct opal_dev *dev,
313551f421c8SRevanth Rajashekar struct opal_read_write_table *rw_tbl)
313651f421c8SRevanth Rajashekar {
313751f421c8SRevanth Rajashekar int ret, bit_set;
313851f421c8SRevanth Rajashekar
31393bfeb612SGreg Joyce ret = opal_get_key(dev, &rw_tbl->key);
31403bfeb612SGreg Joyce if (ret)
31413bfeb612SGreg Joyce return ret;
314251f421c8SRevanth Rajashekar mutex_lock(&dev->dev_lock);
314351f421c8SRevanth Rajashekar setup_opal_dev(dev);
314451f421c8SRevanth Rajashekar
314551f421c8SRevanth Rajashekar bit_set = fls64(rw_tbl->flags) - 1;
314651f421c8SRevanth Rajashekar switch (bit_set) {
314751f421c8SRevanth Rajashekar case OPAL_READ_TABLE:
314851f421c8SRevanth Rajashekar ret = opal_read_table(dev, rw_tbl);
314951f421c8SRevanth Rajashekar break;
315051f421c8SRevanth Rajashekar case OPAL_WRITE_TABLE:
315151f421c8SRevanth Rajashekar ret = opal_write_table(dev, rw_tbl);
315251f421c8SRevanth Rajashekar break;
315351f421c8SRevanth Rajashekar default:
315451f421c8SRevanth Rajashekar pr_debug("Invalid bit set in the flag (%016llx).\n",
315551f421c8SRevanth Rajashekar rw_tbl->flags);
315651f421c8SRevanth Rajashekar ret = -EINVAL;
315751f421c8SRevanth Rajashekar break;
315851f421c8SRevanth Rajashekar }
315951f421c8SRevanth Rajashekar
316051f421c8SRevanth Rajashekar mutex_unlock(&dev->dev_lock);
316151f421c8SRevanth Rajashekar
316251f421c8SRevanth Rajashekar return ret;
316351f421c8SRevanth Rajashekar }
316451f421c8SRevanth Rajashekar
opal_get_status(struct opal_dev * dev,void __user * data)3165c6ea7060Sdougmill@linux.vnet.ibm.com static int opal_get_status(struct opal_dev *dev, void __user *data)
3166c6ea7060Sdougmill@linux.vnet.ibm.com {
3167c6ea7060Sdougmill@linux.vnet.ibm.com struct opal_status sts = {0};
3168c6ea7060Sdougmill@linux.vnet.ibm.com
3169c6ea7060Sdougmill@linux.vnet.ibm.com /*
3170c6ea7060Sdougmill@linux.vnet.ibm.com * check_opal_support() error is not fatal,
3171c6ea7060Sdougmill@linux.vnet.ibm.com * !dev->supported is a valid condition
3172c6ea7060Sdougmill@linux.vnet.ibm.com */
3173c6ea7060Sdougmill@linux.vnet.ibm.com if (!check_opal_support(dev))
3174c6ea7060Sdougmill@linux.vnet.ibm.com sts.flags = dev->flags;
3175c6ea7060Sdougmill@linux.vnet.ibm.com if (copy_to_user(data, &sts, sizeof(sts))) {
3176c6ea7060Sdougmill@linux.vnet.ibm.com pr_debug("Error copying status to userspace\n");
3177c6ea7060Sdougmill@linux.vnet.ibm.com return -EFAULT;
3178c6ea7060Sdougmill@linux.vnet.ibm.com }
3179c6ea7060Sdougmill@linux.vnet.ibm.com return 0;
3180c6ea7060Sdougmill@linux.vnet.ibm.com }
3181c6ea7060Sdougmill@linux.vnet.ibm.com
opal_get_geometry(struct opal_dev * dev,void __user * data)31829e05a259SOndrej Kozina static int opal_get_geometry(struct opal_dev *dev, void __user *data)
31839e05a259SOndrej Kozina {
31849e05a259SOndrej Kozina struct opal_geometry geo = {0};
31859e05a259SOndrej Kozina
31869e05a259SOndrej Kozina if (check_opal_support(dev))
31879e05a259SOndrej Kozina return -EINVAL;
31889e05a259SOndrej Kozina
31899e05a259SOndrej Kozina geo.align = dev->align_required;
31909e05a259SOndrej Kozina geo.logical_block_size = dev->logical_block_size;
31919e05a259SOndrej Kozina geo.alignment_granularity = dev->align;
31929e05a259SOndrej Kozina geo.lowest_aligned_lba = dev->lowest_lba;
31939e05a259SOndrej Kozina
31949e05a259SOndrej Kozina if (copy_to_user(data, &geo, sizeof(geo))) {
31959e05a259SOndrej Kozina pr_debug("Error copying geometry data to userspace\n");
31969e05a259SOndrej Kozina return -EFAULT;
31979e05a259SOndrej Kozina }
31989e05a259SOndrej Kozina
31999e05a259SOndrej Kozina return 0;
32009e05a259SOndrej Kozina }
32019e05a259SOndrej Kozina
sed_ioctl(struct opal_dev * dev,unsigned int cmd,void __user * arg)3202e225c20eSScott Bauer int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
3203455a7b23SScott Bauer {
3204e225c20eSScott Bauer void *p;
3205e225c20eSScott Bauer int ret = -ENOTTY;
3206455a7b23SScott Bauer
3207455a7b23SScott Bauer if (!capable(CAP_SYS_ADMIN))
3208455a7b23SScott Bauer return -EACCES;
32094f1244c8SChristoph Hellwig if (!dev)
32103bfeb612SGreg Joyce return -EOPNOTSUPP;
3211c6ea7060Sdougmill@linux.vnet.ibm.com if (!(dev->flags & OPAL_FL_SUPPORTED))
32123bfeb612SGreg Joyce return -EOPNOTSUPP;
3213455a7b23SScott Bauer
3214c6ea7060Sdougmill@linux.vnet.ibm.com if (cmd & IOC_IN) {
3215e225c20eSScott Bauer p = memdup_user(arg, _IOC_SIZE(cmd));
3216e225c20eSScott Bauer if (IS_ERR(p))
3217e225c20eSScott Bauer return PTR_ERR(p);
3218c6ea7060Sdougmill@linux.vnet.ibm.com }
3219e225c20eSScott Bauer
3220455a7b23SScott Bauer switch (cmd) {
3221e225c20eSScott Bauer case IOC_OPAL_SAVE:
3222e225c20eSScott Bauer ret = opal_save(dev, p);
3223e225c20eSScott Bauer break;
3224e225c20eSScott Bauer case IOC_OPAL_LOCK_UNLOCK:
3225e225c20eSScott Bauer ret = opal_lock_unlock(dev, p);
3226e225c20eSScott Bauer break;
3227e225c20eSScott Bauer case IOC_OPAL_TAKE_OWNERSHIP:
3228e225c20eSScott Bauer ret = opal_take_ownership(dev, p);
3229e225c20eSScott Bauer break;
3230e225c20eSScott Bauer case IOC_OPAL_ACTIVATE_LSP:
3231e225c20eSScott Bauer ret = opal_activate_lsp(dev, p);
3232e225c20eSScott Bauer break;
3233e225c20eSScott Bauer case IOC_OPAL_SET_PW:
3234e225c20eSScott Bauer ret = opal_set_new_pw(dev, p);
3235e225c20eSScott Bauer break;
3236e225c20eSScott Bauer case IOC_OPAL_ACTIVATE_USR:
3237e225c20eSScott Bauer ret = opal_activate_user(dev, p);
3238e225c20eSScott Bauer break;
3239e225c20eSScott Bauer case IOC_OPAL_REVERT_TPR:
32405e4c7cf6SRevanth Rajashekar ret = opal_reverttper(dev, p, false);
3241e225c20eSScott Bauer break;
3242e225c20eSScott Bauer case IOC_OPAL_LR_SETUP:
3243e225c20eSScott Bauer ret = opal_setup_locking_range(dev, p);
3244e225c20eSScott Bauer break;
3245e225c20eSScott Bauer case IOC_OPAL_ADD_USR_TO_LR:
3246e225c20eSScott Bauer ret = opal_add_user_to_lr(dev, p);
3247e225c20eSScott Bauer break;
3248e225c20eSScott Bauer case IOC_OPAL_ENABLE_DISABLE_MBR:
3249e225c20eSScott Bauer ret = opal_enable_disable_shadow_mbr(dev, p);
3250e225c20eSScott Bauer break;
3251c9888443SJonas Rabenstein case IOC_OPAL_MBR_DONE:
3252c9888443SJonas Rabenstein ret = opal_set_mbr_done(dev, p);
3253c9888443SJonas Rabenstein break;
3254a9b25b4cSJonas Rabenstein case IOC_OPAL_WRITE_SHADOW_MBR:
3255a9b25b4cSJonas Rabenstein ret = opal_write_shadow_mbr(dev, p);
3256a9b25b4cSJonas Rabenstein break;
3257e225c20eSScott Bauer case IOC_OPAL_ERASE_LR:
3258e225c20eSScott Bauer ret = opal_erase_locking_range(dev, p);
3259e225c20eSScott Bauer break;
3260e225c20eSScott Bauer case IOC_OPAL_SECURE_ERASE_LR:
3261e225c20eSScott Bauer ret = opal_secure_erase_locking_range(dev, p);
3262e225c20eSScott Bauer break;
32635e4c7cf6SRevanth Rajashekar case IOC_OPAL_PSID_REVERT_TPR:
32645e4c7cf6SRevanth Rajashekar ret = opal_reverttper(dev, p, true);
32655e4c7cf6SRevanth Rajashekar break;
326651f421c8SRevanth Rajashekar case IOC_OPAL_GENERIC_TABLE_RW:
326751f421c8SRevanth Rajashekar ret = opal_generic_read_write_table(dev, p);
326851f421c8SRevanth Rajashekar break;
3269c6ea7060Sdougmill@linux.vnet.ibm.com case IOC_OPAL_GET_STATUS:
3270c6ea7060Sdougmill@linux.vnet.ibm.com ret = opal_get_status(dev, arg);
3271c6ea7060Sdougmill@linux.vnet.ibm.com break;
32724c4dd04eSOndrej Kozina case IOC_OPAL_GET_LR_STATUS:
32734c4dd04eSOndrej Kozina ret = opal_locking_range_status(dev, p, arg);
32744c4dd04eSOndrej Kozina break;
32759e05a259SOndrej Kozina case IOC_OPAL_GET_GEOMETRY:
32769e05a259SOndrej Kozina ret = opal_get_geometry(dev, arg);
32779e05a259SOndrej Kozina break;
32785c82efc1SGreg Joyce case IOC_OPAL_REVERT_LSP:
32795c82efc1SGreg Joyce ret = opal_revertlsp(dev, p);
32805c82efc1SGreg Joyce break;
32819fb10726SGreg Joyce case IOC_OPAL_DISCOVERY:
32829fb10726SGreg Joyce ret = opal_get_discv(dev, p);
32839fb10726SGreg Joyce break;
32849fb10726SGreg Joyce
3285455a7b23SScott Bauer default:
3286591c59d1SScott Bauer break;
3287455a7b23SScott Bauer }
3288e225c20eSScott Bauer
3289c6ea7060Sdougmill@linux.vnet.ibm.com if (cmd & IOC_IN)
3290e225c20eSScott Bauer kfree(p);
3291e225c20eSScott Bauer return ret;
3292455a7b23SScott Bauer }
3293455a7b23SScott Bauer EXPORT_SYMBOL_GPL(sed_ioctl);
32943bfeb612SGreg Joyce
sed_opal_init(void)32953bfeb612SGreg Joyce static int __init sed_opal_init(void)
32963bfeb612SGreg Joyce {
32973bfeb612SGreg Joyce struct key *kr;
32983bfeb612SGreg Joyce
32993bfeb612SGreg Joyce kr = keyring_alloc(".sed_opal",
33003bfeb612SGreg Joyce GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
33013bfeb612SGreg Joyce (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW |
33023bfeb612SGreg Joyce KEY_USR_READ | KEY_USR_SEARCH | KEY_USR_WRITE,
33033bfeb612SGreg Joyce KEY_ALLOC_NOT_IN_QUOTA,
33043bfeb612SGreg Joyce NULL, NULL);
33053bfeb612SGreg Joyce if (IS_ERR(kr))
33063bfeb612SGreg Joyce return PTR_ERR(kr);
33073bfeb612SGreg Joyce
33083bfeb612SGreg Joyce sed_opal_keyring = kr;
33093bfeb612SGreg Joyce
33103bfeb612SGreg Joyce return 0;
33113bfeb612SGreg Joyce }
33123bfeb612SGreg Joyce late_initcall(sed_opal_init);
3313