diff options
-rw-r--r-- | MAINTAINERS | 11 | ||||
-rw-r--r-- | block/Kconfig | 7 | ||||
-rw-r--r-- | block/Makefile | 1 | ||||
-rw-r--r-- | block/opal_proto.h | 429 | ||||
-rw-r--r-- | block/sed-opal.c | 2448 | ||||
-rw-r--r-- | include/linux/sed-opal.h | 178 |
6 files changed, 3074 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index f481713fe44c..f96181c927be 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -11075,6 +11075,17 @@ L: linux-mmc@vger.kernel.org | |||
11075 | S: Maintained | 11075 | S: Maintained |
11076 | F: drivers/mmc/host/sdhci-spear.c | 11076 | F: drivers/mmc/host/sdhci-spear.c |
11077 | 11077 | ||
11078 | SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER | ||
11079 | M: Scott Bauer <scott.bauer@intel.com> | ||
11080 | M: Jonathan Derrick <jonathan.derrick@intel.com> | ||
11081 | M: Rafael Antognolli <rafael.antognolli@intel.com> | ||
11082 | L: linux-nvme@lists.infradead.org | ||
11083 | S: Supported | ||
11084 | F: block/sed* | ||
11085 | F: block/opal_proto.h | ||
11086 | F: include/linux/sed* | ||
11087 | F: include/uapi/linux/sed* | ||
11088 | |||
11078 | SECURITY SUBSYSTEM | 11089 | SECURITY SUBSYSTEM |
11079 | M: James Morris <james.l.morris@oracle.com> | 11090 | M: James Morris <james.l.morris@oracle.com> |
11080 | M: "Serge E. Hallyn" <serge@hallyn.com> | 11091 | M: "Serge E. Hallyn" <serge@hallyn.com> |
diff --git a/block/Kconfig b/block/Kconfig index 7f659b23850c..1aef809affae 100644 --- a/block/Kconfig +++ b/block/Kconfig | |||
@@ -159,6 +159,13 @@ config BLK_DEBUG_FS | |||
159 | Unless you are building a kernel for a tiny system, you should | 159 | Unless you are building a kernel for a tiny system, you should |
160 | say Y here. | 160 | say Y here. |
161 | 161 | ||
162 | config BLK_SED_OPAL | ||
163 | bool "Logic for interfacing with Opal enabled SEDs" | ||
164 | ---help--- | ||
165 | Builds Logic for interfacing with Opal enabled controllers. | ||
166 | Enabling this option enables users to setup/unlock/lock | ||
167 | Locking ranges for SED devices using the Opal protocol. | ||
168 | |||
162 | menu "Partition Types" | 169 | menu "Partition Types" |
163 | 170 | ||
164 | source "block/partitions/Kconfig" | 171 | source "block/partitions/Kconfig" |
diff --git a/block/Makefile b/block/Makefile index 317165f8708c..6ba1b1bc9529 100644 --- a/block/Makefile +++ b/block/Makefile | |||
@@ -27,3 +27,4 @@ obj-$(CONFIG_BLK_MQ_PCI) += blk-mq-pci.o | |||
27 | obj-$(CONFIG_BLK_DEV_ZONED) += blk-zoned.o | 27 | obj-$(CONFIG_BLK_DEV_ZONED) += blk-zoned.o |
28 | obj-$(CONFIG_BLK_WBT) += blk-wbt.o | 28 | obj-$(CONFIG_BLK_WBT) += blk-wbt.o |
29 | obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o | 29 | obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o |
30 | obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o | ||
diff --git a/block/opal_proto.h b/block/opal_proto.h new file mode 100644 index 000000000000..af9abc56c157 --- /dev/null +++ b/block/opal_proto.h | |||
@@ -0,0 +1,429 @@ | |||
1 | /* | ||
2 | * Copyright © 2016 Intel Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Rafael Antognolli <rafael.antognolli@intel.com> | ||
6 | * Scott Bauer <scott.bauer@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | */ | ||
17 | #include <linux/types.h> | ||
18 | |||
19 | #ifndef _OPAL_PROTO_H | ||
20 | #define _OPAL_PROTO_H | ||
21 | |||
22 | #define DTAERROR_NO_METHOD_STATUS 0x89 | ||
23 | #define GENERIC_HOST_SESSION_NUM 0x41 | ||
24 | |||
25 | #define TPER_SYNC_SUPPORTED 0x01 | ||
26 | |||
27 | #define TINY_ATOM_DATA_MASK 0x3F | ||
28 | #define TINY_ATOM_SIGNED 0x40 | ||
29 | |||
30 | #define SHORT_ATOM_ID 0x80 | ||
31 | #define SHORT_ATOM_BYTESTRING 0x20 | ||
32 | #define SHORT_ATOM_SIGNED 0x10 | ||
33 | #define SHORT_ATOM_LEN_MASK 0xF | ||
34 | |||
35 | #define MEDIUM_ATOM_ID 0xC0 | ||
36 | #define MEDIUM_ATOM_BYTESTRING 0x10 | ||
37 | #define MEDIUM_ATOM_SIGNED 0x8 | ||
38 | #define MEDIUM_ATOM_LEN_MASK 0x7 | ||
39 | |||
40 | #define LONG_ATOM_ID 0xe0 | ||
41 | #define LONG_ATOM_BYTESTRING 0x2 | ||
42 | #define LONG_ATOM_SIGNED 0x1 | ||
43 | |||
44 | /* Derived from TCG Core spec 2.01 Section: | ||
45 | * 3.2.2.1 | ||
46 | * Data Type | ||
47 | */ | ||
48 | #define TINY_ATOM_BYTE 0x7F | ||
49 | #define SHORT_ATOM_BYTE 0xBF | ||
50 | #define MEDIUM_ATOM_BYTE 0xDF | ||
51 | #define LONG_ATOM_BYTE 0xE3 | ||
52 | |||
53 | #define OPAL_INVAL_PARAM 12 | ||
54 | #define OPAL_MANUFACTURED_INACTIVE 0x08 | ||
55 | #define OPAL_DISCOVERY_COMID 0x0001 | ||
56 | |||
57 | #define LOCKING_RANGE_NON_GLOBAL 0x03 | ||
58 | /* | ||
59 | * User IDs used in the TCG storage SSCs | ||
60 | * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 | ||
61 | * Section: 6.3 Assigned UIDs | ||
62 | */ | ||
63 | #define OPAL_UID_LENGTH 8 | ||
64 | #define OPAL_METHOD_LENGTH 8 | ||
65 | #define OPAL_MSID_KEYLEN 15 | ||
66 | #define OPAL_UID_LENGTH_HALF 4 | ||
67 | |||
68 | /* Enum to index OPALUID array */ | ||
69 | enum opal_uid { | ||
70 | /* users */ | ||
71 | OPAL_SMUID_UID, | ||
72 | OPAL_THISSP_UID, | ||
73 | OPAL_ADMINSP_UID, | ||
74 | OPAL_LOCKINGSP_UID, | ||
75 | OPAL_ENTERPRISE_LOCKINGSP_UID, | ||
76 | OPAL_ANYBODY_UID, | ||
77 | OPAL_SID_UID, | ||
78 | OPAL_ADMIN1_UID, | ||
79 | OPAL_USER1_UID, | ||
80 | OPAL_USER2_UID, | ||
81 | OPAL_PSID_UID, | ||
82 | OPAL_ENTERPRISE_BANDMASTER0_UID, | ||
83 | OPAL_ENTERPRISE_ERASEMASTER_UID, | ||
84 | /* tables */ | ||
85 | OPAL_LOCKINGRANGE_GLOBAL, | ||
86 | OPAL_LOCKINGRANGE_ACE_RDLOCKED, | ||
87 | OPAL_LOCKINGRANGE_ACE_WRLOCKED, | ||
88 | OPAL_MBRCONTROL, | ||
89 | OPAL_MBR, | ||
90 | OPAL_AUTHORITY_TABLE, | ||
91 | OPAL_C_PIN_TABLE, | ||
92 | OPAL_LOCKING_INFO_TABLE, | ||
93 | OPAL_ENTERPRISE_LOCKING_INFO_TABLE, | ||
94 | /* C_PIN_TABLE object ID's */ | ||
95 | OPAL_C_PIN_MSID, | ||
96 | OPAL_C_PIN_SID, | ||
97 | OPAL_C_PIN_ADMIN1, | ||
98 | /* half UID's (only first 4 bytes used) */ | ||
99 | OPAL_HALF_UID_AUTHORITY_OBJ_REF, | ||
100 | OPAL_HALF_UID_BOOLEAN_ACE, | ||
101 | /* omitted optional parameter */ | ||
102 | OPAL_UID_HEXFF, | ||
103 | }; | ||
104 | |||
105 | #define OPAL_METHOD_LENGTH 8 | ||
106 | |||
107 | /* Enum for indexing the OPALMETHOD array */ | ||
108 | enum opal_method { | ||
109 | OPAL_PROPERTIES, | ||
110 | OPAL_STARTSESSION, | ||
111 | OPAL_REVERT, | ||
112 | OPAL_ACTIVATE, | ||
113 | OPAL_EGET, | ||
114 | OPAL_ESET, | ||
115 | OPAL_NEXT, | ||
116 | OPAL_EAUTHENTICATE, | ||
117 | OPAL_GETACL, | ||
118 | OPAL_GENKEY, | ||
119 | OPAL_REVERTSP, | ||
120 | OPAL_GET, | ||
121 | OPAL_SET, | ||
122 | OPAL_AUTHENTICATE, | ||
123 | OPAL_RANDOM, | ||
124 | OPAL_ERASE, | ||
125 | }; | ||
126 | |||
127 | enum opal_token { | ||
128 | /* Boolean */ | ||
129 | OPAL_TRUE = 0x01, | ||
130 | OPAL_FALSE = 0x00, | ||
131 | OPAL_BOOLEAN_EXPR = 0x03, | ||
132 | /* cellblocks */ | ||
133 | OPAL_TABLE = 0x00, | ||
134 | OPAL_STARTROW = 0x01, | ||
135 | OPAL_ENDROW = 0x02, | ||
136 | OPAL_STARTCOLUMN = 0x03, | ||
137 | OPAL_ENDCOLUMN = 0x04, | ||
138 | OPAL_VALUES = 0x01, | ||
139 | /* authority table */ | ||
140 | OPAL_PIN = 0x03, | ||
141 | /* locking tokens */ | ||
142 | OPAL_RANGESTART = 0x03, | ||
143 | OPAL_RANGELENGTH = 0x04, | ||
144 | OPAL_READLOCKENABLED = 0x05, | ||
145 | OPAL_WRITELOCKENABLED = 0x06, | ||
146 | OPAL_READLOCKED = 0x07, | ||
147 | OPAL_WRITELOCKED = 0x08, | ||
148 | OPAL_ACTIVEKEY = 0x0A, | ||
149 | /* locking info table */ | ||
150 | OPAL_MAXRANGES = 0x04, | ||
151 | /* mbr control */ | ||
152 | OPAL_MBRENABLE = 0x01, | ||
153 | OPAL_MBRDONE = 0x02, | ||
154 | /* properties */ | ||
155 | OPAL_HOSTPROPERTIES = 0x00, | ||
156 | /* atoms */ | ||
157 | OPAL_STARTLIST = 0xf0, | ||
158 | OPAL_ENDLIST = 0xf1, | ||
159 | OPAL_STARTNAME = 0xf2, | ||
160 | OPAL_ENDNAME = 0xf3, | ||
161 | OPAL_CALL = 0xf8, | ||
162 | OPAL_ENDOFDATA = 0xf9, | ||
163 | OPAL_ENDOFSESSION = 0xfa, | ||
164 | OPAL_STARTTRANSACTON = 0xfb, | ||
165 | OPAL_ENDTRANSACTON = 0xfC, | ||
166 | OPAL_EMPTYATOM = 0xff, | ||
167 | OPAL_WHERE = 0x00, | ||
168 | }; | ||
169 | |||
170 | /* Locking state for a locking range */ | ||
171 | enum opal_lockingstate { | ||
172 | OPAL_LOCKING_READWRITE = 0x01, | ||
173 | OPAL_LOCKING_READONLY = 0x02, | ||
174 | OPAL_LOCKING_LOCKED = 0x03, | ||
175 | }; | ||
176 | |||
177 | /* Packets derived from: | ||
178 | * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 | ||
179 | * Secion: 3.2.3 ComPackets, Packets & Subpackets | ||
180 | */ | ||
181 | |||
182 | /* Comm Packet (header) for transmissions. */ | ||
183 | struct opal_compacket { | ||
184 | __be32 reserved0; | ||
185 | u8 extendedComID[4]; | ||
186 | __be32 outstandingData; | ||
187 | __be32 minTransfer; | ||
188 | __be32 length; | ||
189 | }; | ||
190 | |||
191 | /* Packet structure. */ | ||
192 | struct opal_packet { | ||
193 | __be32 tsn; | ||
194 | __be32 hsn; | ||
195 | __be32 seq_number; | ||
196 | __be16 reserved0; | ||
197 | __be16 ack_type; | ||
198 | __be32 acknowledgment; | ||
199 | __be32 length; | ||
200 | }; | ||
201 | |||
202 | /* Data sub packet header */ | ||
203 | struct opal_data_subpacket { | ||
204 | u8 reserved0[6]; | ||
205 | __be16 kind; | ||
206 | __be32 length; | ||
207 | }; | ||
208 | |||
209 | /* header of a response */ | ||
210 | struct opal_header { | ||
211 | struct opal_compacket cp; | ||
212 | struct opal_packet pkt; | ||
213 | struct opal_data_subpacket subpkt; | ||
214 | }; | ||
215 | |||
216 | #define FC_TPER 0x0001 | ||
217 | #define FC_LOCKING 0x0002 | ||
218 | #define FC_GEOMETRY 0x0003 | ||
219 | #define FC_ENTERPRISE 0x0100 | ||
220 | #define FC_DATASTORE 0x0202 | ||
221 | #define FC_SINGLEUSER 0x0201 | ||
222 | #define FC_OPALV100 0x0200 | ||
223 | #define FC_OPALV200 0x0203 | ||
224 | |||
225 | /* | ||
226 | * The Discovery 0 Header. As defined in | ||
227 | * Opal SSC Documentation | ||
228 | * Section: 3.3.5 Capability Discovery | ||
229 | */ | ||
230 | struct d0_header { | ||
231 | __be32 length; /* the length of the header 48 in 2.00.100 */ | ||
232 | __be32 revision; /**< revision of the header 1 in 2.00.100 */ | ||
233 | __be32 reserved01; | ||
234 | __be32 reserved02; | ||
235 | /* | ||
236 | * the remainder of the structure is vendor specific and will not be | ||
237 | * addressed now | ||
238 | */ | ||
239 | u8 ignored[32]; | ||
240 | }; | ||
241 | |||
242 | /* | ||
243 | * TPer Feature Descriptor. Contains flags indicating support for the | ||
244 | * TPer features described in the OPAL specification. The names match the | ||
245 | * OPAL terminology | ||
246 | * | ||
247 | * code == 0x001 in 2.00.100 | ||
248 | */ | ||
249 | struct d0_tper_features { | ||
250 | /* | ||
251 | * supported_features bits: | ||
252 | * bit 7: reserved | ||
253 | * bit 6: com ID management | ||
254 | * bit 5: reserved | ||
255 | * bit 4: streaming support | ||
256 | * bit 3: buffer management | ||
257 | * bit 2: ACK/NACK | ||
258 | * bit 1: async | ||
259 | * bit 0: sync | ||
260 | */ | ||
261 | u8 supported_features; | ||
262 | /* | ||
263 | * bytes 5 through 15 are reserved, but we represent the first 3 as | ||
264 | * u8 to keep the other two 32bits integers aligned. | ||
265 | */ | ||
266 | u8 reserved01[3]; | ||
267 | __be32 reserved02; | ||
268 | __be32 reserved03; | ||
269 | }; | ||
270 | |||
271 | /* | ||
272 | * Locking Feature Descriptor. Contains flags indicating support for the | ||
273 | * locking features described in the OPAL specification. The names match the | ||
274 | * OPAL terminology | ||
275 | * | ||
276 | * code == 0x0002 in 2.00.100 | ||
277 | */ | ||
278 | struct d0_locking_features { | ||
279 | /* | ||
280 | * supported_features bits: | ||
281 | * bits 6-7: reserved | ||
282 | * bit 5: MBR done | ||
283 | * bit 4: MBR enabled | ||
284 | * bit 3: media encryption | ||
285 | * bit 2: locked | ||
286 | * bit 1: locking enabled | ||
287 | * bit 0: locking supported | ||
288 | */ | ||
289 | u8 supported_features; | ||
290 | /* | ||
291 | * bytes 5 through 15 are reserved, but we represent the first 3 as | ||
292 | * u8 to keep the other two 32bits integers aligned. | ||
293 | */ | ||
294 | u8 reserved01[3]; | ||
295 | __be32 reserved02; | ||
296 | __be32 reserved03; | ||
297 | }; | ||
298 | |||
299 | /* | ||
300 | * Geometry Feature Descriptor. Contains flags indicating support for the | ||
301 | * geometry features described in the OPAL specification. The names match the | ||
302 | * OPAL terminology | ||
303 | * | ||
304 | * code == 0x0003 in 2.00.100 | ||
305 | */ | ||
306 | struct d0_geometry_features { | ||
307 | /* | ||
308 | * skip 32 bits from header, needed to align the struct to 64 bits. | ||
309 | */ | ||
310 | u8 header[4]; | ||
311 | /* | ||
312 | * reserved01: | ||
313 | * bits 1-6: reserved | ||
314 | * bit 0: align | ||
315 | */ | ||
316 | u8 reserved01; | ||
317 | u8 reserved02[7]; | ||
318 | __be32 logical_block_size; | ||
319 | __be64 alignment_granularity; | ||
320 | __be64 lowest_aligned_lba; | ||
321 | }; | ||
322 | |||
323 | /* | ||
324 | * Enterprise SSC Feature | ||
325 | * | ||
326 | * code == 0x0100 | ||
327 | */ | ||
328 | struct d0_enterprise_ssc { | ||
329 | __be16 baseComID; | ||
330 | __be16 numComIDs; | ||
331 | /* range_crossing: | ||
332 | * bits 1-6: reserved | ||
333 | * bit 0: range crossing | ||
334 | */ | ||
335 | u8 range_crossing; | ||
336 | u8 reserved01; | ||
337 | __be16 reserved02; | ||
338 | __be32 reserved03; | ||
339 | __be32 reserved04; | ||
340 | }; | ||
341 | |||
342 | /* | ||
343 | * Opal V1 feature | ||
344 | * | ||
345 | * code == 0x0200 | ||
346 | */ | ||
347 | struct d0_opal_v100 { | ||
348 | __be16 baseComID; | ||
349 | __be16 numComIDs; | ||
350 | }; | ||
351 | |||
352 | /* | ||
353 | * Single User Mode feature | ||
354 | * | ||
355 | * code == 0x0201 | ||
356 | */ | ||
357 | struct d0_single_user_mode { | ||
358 | __be32 num_locking_objects; | ||
359 | /* reserved01: | ||
360 | * bit 0: any | ||
361 | * bit 1: all | ||
362 | * bit 2: policy | ||
363 | * bits 3-7: reserved | ||
364 | */ | ||
365 | u8 reserved01; | ||
366 | u8 reserved02; | ||
367 | __be16 reserved03; | ||
368 | __be32 reserved04; | ||
369 | }; | ||
370 | |||
371 | /* | ||
372 | * Additonal Datastores feature | ||
373 | * | ||
374 | * code == 0x0202 | ||
375 | */ | ||
376 | struct d0_datastore_table { | ||
377 | __be16 reserved01; | ||
378 | __be16 max_tables; | ||
379 | __be32 max_size_tables; | ||
380 | __be32 table_size_alignment; | ||
381 | }; | ||
382 | |||
383 | /* | ||
384 | * OPAL 2.0 feature | ||
385 | * | ||
386 | * code == 0x0203 | ||
387 | */ | ||
388 | struct d0_opal_v200 { | ||
389 | __be16 baseComID; | ||
390 | __be16 numComIDs; | ||
391 | /* range_crossing: | ||
392 | * bits 1-6: reserved | ||
393 | * bit 0: range crossing | ||
394 | */ | ||
395 | u8 range_crossing; | ||
396 | /* num_locking_admin_auth: | ||
397 | * not aligned to 16 bits, so use two u8. | ||
398 | * stored in big endian: | ||
399 | * 0: MSB | ||
400 | * 1: LSB | ||
401 | */ | ||
402 | u8 num_locking_admin_auth[2]; | ||
403 | /* num_locking_user_auth: | ||
404 | * not aligned to 16 bits, so use two u8. | ||
405 | * stored in big endian: | ||
406 | * 0: MSB | ||
407 | * 1: LSB | ||
408 | */ | ||
409 | u8 num_locking_user_auth[2]; | ||
410 | u8 initialPIN; | ||
411 | u8 revertedPIN; | ||
412 | u8 reserved01; | ||
413 | __be32 reserved02; | ||
414 | }; | ||
415 | |||
416 | /* Union of features used to parse the discovery 0 response */ | ||
417 | struct d0_features { | ||
418 | __be16 code; | ||
419 | /* | ||
420 | * r_version bits: | ||
421 | * bits 4-7: version | ||
422 | * bits 0-3: reserved | ||
423 | */ | ||
424 | u8 r_version; | ||
425 | u8 length; | ||
426 | u8 features[]; | ||
427 | }; | ||
428 | |||
429 | #endif /* _OPAL_PROTO_H */ | ||
diff --git a/block/sed-opal.c b/block/sed-opal.c new file mode 100644 index 000000000000..bf1406e5159b --- /dev/null +++ b/block/sed-opal.c | |||
@@ -0,0 +1,2448 @@ | |||
1 | /* | ||
2 | * Copyright © 2016 Intel Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Scott Bauer <scott.bauer@intel.com> | ||
6 | * Rafael Antognolli <rafael.antognolli@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | */ | ||
17 | |||
18 | #define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/genhd.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/uaccess.h> | ||
27 | #include <uapi/linux/sed-opal.h> | ||
28 | #include <linux/sed-opal.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/kdev_t.h> | ||
31 | |||
32 | #include "opal_proto.h" | ||
33 | |||
34 | static const u8 opaluid[][OPAL_UID_LENGTH] = { | ||
35 | /* users */ | ||
36 | [OPAL_SMUID_UID] = | ||
37 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff }, | ||
38 | [OPAL_THISSP_UID] = | ||
39 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, | ||
40 | [OPAL_ADMINSP_UID] = | ||
41 | { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 }, | ||
42 | [OPAL_LOCKINGSP_UID] = | ||
43 | { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 }, | ||
44 | [OPAL_ENTERPRISE_LOCKINGSP_UID] = | ||
45 | { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 }, | ||
46 | [OPAL_ANYBODY_UID] = | ||
47 | { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 }, | ||
48 | [OPAL_SID_UID] = | ||
49 | { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 }, | ||
50 | [OPAL_ADMIN1_UID] = | ||
51 | { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 }, | ||
52 | [OPAL_USER1_UID] = | ||
53 | { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 }, | ||
54 | [OPAL_USER2_UID] = | ||
55 | { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 }, | ||
56 | [OPAL_PSID_UID] = | ||
57 | { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 }, | ||
58 | [OPAL_ENTERPRISE_BANDMASTER0_UID] = | ||
59 | { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 }, | ||
60 | [OPAL_ENTERPRISE_ERASEMASTER_UID] = | ||
61 | { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 }, | ||
62 | |||
63 | /* tables */ | ||
64 | |||
65 | [OPAL_LOCKINGRANGE_GLOBAL] = | ||
66 | { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 }, | ||
67 | [OPAL_LOCKINGRANGE_ACE_RDLOCKED] = | ||
68 | { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 }, | ||
69 | [OPAL_LOCKINGRANGE_ACE_WRLOCKED] = | ||
70 | { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 }, | ||
71 | [OPAL_MBRCONTROL] = | ||
72 | { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 }, | ||
73 | [OPAL_MBR] = | ||
74 | { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 }, | ||
75 | [OPAL_AUTHORITY_TABLE] = | ||
76 | { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00}, | ||
77 | [OPAL_C_PIN_TABLE] = | ||
78 | { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00}, | ||
79 | [OPAL_LOCKING_INFO_TABLE] = | ||
80 | { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 }, | ||
81 | [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] = | ||
82 | { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 }, | ||
83 | |||
84 | /* C_PIN_TABLE object ID's */ | ||
85 | |||
86 | [OPAL_C_PIN_MSID] = | ||
87 | { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02}, | ||
88 | [OPAL_C_PIN_SID] = | ||
89 | { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01}, | ||
90 | [OPAL_C_PIN_ADMIN1] = | ||
91 | { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01}, | ||
92 | |||
93 | /* half UID's (only first 4 bytes used) */ | ||
94 | |||
95 | [OPAL_HALF_UID_AUTHORITY_OBJ_REF] = | ||
96 | { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff }, | ||
97 | [OPAL_HALF_UID_BOOLEAN_ACE] = | ||
98 | { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff }, | ||
99 | |||
100 | /* special value for omitted optional parameter */ | ||
101 | [OPAL_UID_HEXFF] = | ||
102 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, | ||
103 | }; | ||
104 | |||
105 | /* | ||
106 | * TCG Storage SSC Methods. | ||
107 | * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 | ||
108 | * Section: 6.3 Assigned UIDs | ||
109 | */ | ||
110 | static const u8 opalmethod[][OPAL_UID_LENGTH] = { | ||
111 | [OPAL_PROPERTIES] = | ||
112 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 }, | ||
113 | [OPAL_STARTSESSION] = | ||
114 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 }, | ||
115 | [OPAL_REVERT] = | ||
116 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 }, | ||
117 | [OPAL_ACTIVATE] = | ||
118 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 }, | ||
119 | [OPAL_EGET] = | ||
120 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 }, | ||
121 | [OPAL_ESET] = | ||
122 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 }, | ||
123 | [OPAL_NEXT] = | ||
124 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 }, | ||
125 | [OPAL_EAUTHENTICATE] = | ||
126 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c }, | ||
127 | [OPAL_GETACL] = | ||
128 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d }, | ||
129 | [OPAL_GENKEY] = | ||
130 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 }, | ||
131 | [OPAL_REVERTSP] = | ||
132 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 }, | ||
133 | [OPAL_GET] = | ||
134 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 }, | ||
135 | [OPAL_SET] = | ||
136 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 }, | ||
137 | [OPAL_AUTHENTICATE] = | ||
138 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c }, | ||
139 | [OPAL_RANDOM] = | ||
140 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 }, | ||
141 | [OPAL_ERASE] = | ||
142 | { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 }, | ||
143 | }; | ||
144 | |||
145 | typedef int (cont_fn)(struct opal_dev *dev); | ||
146 | |||
147 | static int end_opal_session_error(struct opal_dev *dev); | ||
148 | |||
149 | struct opal_suspend_data { | ||
150 | struct opal_lock_unlock unlk; | ||
151 | u8 lr; | ||
152 | struct list_head node; | ||
153 | }; | ||
154 | |||
155 | /* | ||
156 | * Derived from: | ||
157 | * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 | ||
158 | * Section: 5.1.5 Method Status Codes | ||
159 | */ | ||
160 | static const char * const opal_errors[] = { | ||
161 | "Success", | ||
162 | "Not Authorized", | ||
163 | "Unknown Error", | ||
164 | "SP Busy", | ||
165 | "SP Failed", | ||
166 | "SP Disabled", | ||
167 | "SP Frozen", | ||
168 | "No Sessions Available", | ||
169 | "Uniqueness Conflict", | ||
170 | "Insufficient Space", | ||
171 | "Insufficient Rows", | ||
172 | "Invalid Function", | ||
173 | "Invalid Parameter", | ||
174 | "Invalid Reference", | ||
175 | "Unknown Error", | ||
176 | "TPER Malfunction", | ||
177 | "Transaction Failure", | ||
178 | "Response Overflow", | ||
179 | "Authority Locked Out", | ||
180 | }; | ||
181 | |||
182 | static const char *opal_error_to_human(int error) | ||
183 | { | ||
184 | if (error == 0x3f) | ||
185 | return "Failed"; | ||
186 | |||
187 | if (error >= ARRAY_SIZE(opal_errors) || error < 0) | ||
188 | return "Unknown Error"; | ||
189 | |||
190 | return opal_errors[error]; | ||
191 | } | ||
192 | |||
193 | static void print_buffer(const u8 *ptr, u32 length) | ||
194 | { | ||
195 | #ifdef DEBUG | ||
196 | print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length); | ||
197 | pr_debug("\n"); | ||
198 | #endif | ||
199 | } | ||
200 | |||
201 | static bool check_tper(const void *data) | ||
202 | { | ||
203 | const struct d0_tper_features *tper = data; | ||
204 | u8 flags = tper->supported_features; | ||
205 | |||
206 | if (!(flags & TPER_SYNC_SUPPORTED)) { | ||
207 | pr_err("TPer sync not supported. flags = %d\n", | ||
208 | tper->supported_features); | ||
209 | return false; | ||
210 | } | ||
211 | |||
212 | return true; | ||
213 | } | ||
214 | |||
215 | static bool check_sum(const void *data) | ||
216 | { | ||
217 | const struct d0_single_user_mode *sum = data; | ||
218 | u32 nlo = be32_to_cpu(sum->num_locking_objects); | ||
219 | |||
220 | if (nlo == 0) { | ||
221 | pr_err("Need at least one locking object.\n"); | ||
222 | return false; | ||
223 | } | ||
224 | |||
225 | pr_debug("Number of locking objects: %d\n", nlo); | ||
226 | |||
227 | return true; | ||
228 | } | ||
229 | |||
230 | static u16 get_comid_v100(const void *data) | ||
231 | { | ||
232 | const struct d0_opal_v100 *v100 = data; | ||
233 | |||
234 | return be16_to_cpu(v100->baseComID); | ||
235 | } | ||
236 | |||
237 | static u16 get_comid_v200(const void *data) | ||
238 | { | ||
239 | const struct d0_opal_v200 *v200 = data; | ||
240 | |||
241 | return be16_to_cpu(v200->baseComID); | ||
242 | } | ||
243 | |||
244 | static int opal_send_cmd(struct opal_dev *dev) | ||
245 | { | ||
246 | return dev->send_recv(dev, dev->comid, TCG_SECP_01, | ||
247 | dev->cmd, IO_BUFFER_LENGTH, | ||
248 | true); | ||
249 | } | ||
250 | |||
251 | static int opal_recv_cmd(struct opal_dev *dev) | ||
252 | { | ||
253 | return dev->send_recv(dev, dev->comid, TCG_SECP_01, | ||
254 | dev->resp, IO_BUFFER_LENGTH, | ||
255 | false); | ||
256 | } | ||
257 | |||
258 | static int opal_recv_check(struct opal_dev *dev) | ||
259 | { | ||
260 | size_t buflen = IO_BUFFER_LENGTH; | ||
261 | void *buffer = dev->resp; | ||
262 | struct opal_header *hdr = buffer; | ||
263 | int ret; | ||
264 | |||
265 | do { | ||
266 | pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n", | ||
267 | hdr->cp.outstandingData, | ||
268 | hdr->cp.minTransfer); | ||
269 | |||
270 | if (hdr->cp.outstandingData == 0 || | ||
271 | hdr->cp.minTransfer != 0) | ||
272 | return 0; | ||
273 | |||
274 | memset(buffer, 0, buflen); | ||
275 | ret = opal_recv_cmd(dev); | ||
276 | } while (!ret); | ||
277 | |||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | static int opal_send_recv(struct opal_dev *dev, cont_fn *cont) | ||
282 | { | ||
283 | int ret; | ||
284 | |||
285 | ret = opal_send_cmd(dev); | ||
286 | if (ret) | ||
287 | return ret; | ||
288 | ret = opal_recv_cmd(dev); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | ret = opal_recv_check(dev); | ||
292 | if (ret) | ||
293 | return ret; | ||
294 | return cont(dev); | ||
295 | } | ||
296 | |||
297 | static void check_geometry(struct opal_dev *dev, const void *data) | ||
298 | { | ||
299 | const struct d0_geometry_features *geo = data; | ||
300 | |||
301 | dev->align = geo->alignment_granularity; | ||
302 | dev->lowest_lba = geo->lowest_aligned_lba; | ||
303 | } | ||
304 | |||
305 | static int next(struct opal_dev *dev) | ||
306 | { | ||
307 | opal_step func; | ||
308 | int error = 0; | ||
309 | |||
310 | do { | ||
311 | func = dev->funcs[dev->state]; | ||
312 | if (!func) | ||
313 | break; | ||
314 | |||
315 | error = func(dev); | ||
316 | if (error) { | ||
317 | pr_err("Error on step function: %d with error %d: %s\n", | ||
318 | dev->state, error, | ||
319 | opal_error_to_human(error)); | ||
320 | |||
321 | /* For each OPAL command we do a discovery0 then we | ||
322 | * start some sort of session. | ||
323 | * If we haven't passed state 1 then there was an error | ||
324 | * on discovery0 or during the attempt to start a | ||
325 | * session. Therefore we shouldn't attempt to terminate | ||
326 | * a session, as one has not yet been created. | ||
327 | */ | ||
328 | if (dev->state > 1) | ||
329 | return end_opal_session_error(dev); | ||
330 | } | ||
331 | dev->state++; | ||
332 | } while (!error); | ||
333 | |||
334 | return error; | ||
335 | } | ||
336 | |||
337 | static int opal_discovery0_end(struct opal_dev *dev) | ||
338 | { | ||
339 | bool found_com_id = false, supported = true, single_user = false; | ||
340 | const struct d0_header *hdr = (struct d0_header *)dev->resp; | ||
341 | const u8 *epos = dev->resp, *cpos = dev->resp; | ||
342 | u16 comid = 0; | ||
343 | |||
344 | print_buffer(dev->resp, be32_to_cpu(hdr->length)); | ||
345 | |||
346 | epos += be32_to_cpu(hdr->length); /* end of buffer */ | ||
347 | cpos += sizeof(*hdr); /* current position on buffer */ | ||
348 | |||
349 | while (cpos < epos && supported) { | ||
350 | const struct d0_features *body = | ||
351 | (const struct d0_features *)cpos; | ||
352 | |||
353 | switch (be16_to_cpu(body->code)) { | ||
354 | case FC_TPER: | ||
355 | supported = check_tper(body->features); | ||
356 | break; | ||
357 | case FC_SINGLEUSER: | ||
358 | single_user = check_sum(body->features); | ||
359 | break; | ||
360 | case FC_GEOMETRY: | ||
361 | check_geometry(dev, body); | ||
362 | break; | ||
363 | case FC_LOCKING: | ||
364 | case FC_ENTERPRISE: | ||
365 | case FC_DATASTORE: | ||
366 | /* some ignored properties */ | ||
367 | pr_debug("Found OPAL feature description: %d\n", | ||
368 | be16_to_cpu(body->code)); | ||
369 | break; | ||
370 | case FC_OPALV100: | ||
371 | comid = get_comid_v100(body->features); | ||
372 | found_com_id = true; | ||
373 | break; | ||
374 | case FC_OPALV200: | ||
375 | comid = get_comid_v200(body->features); | ||
376 | found_com_id = true; | ||
377 | break; | ||
378 | case 0xbfff ... 0xffff: | ||
379 | /* vendor specific, just ignore */ | ||
380 | break; | ||
381 | default: | ||
382 | pr_debug("OPAL Unknown feature: %d\n", | ||
383 | be16_to_cpu(body->code)); | ||
384 | |||
385 | } | ||
386 | cpos += body->length + 4; | ||
387 | } | ||
388 | |||
389 | if (!supported) { | ||
390 | pr_err("This device is not Opal enabled. Not Supported!\n"); | ||
391 | return -EOPNOTSUPP; | ||
392 | } | ||
393 | |||
394 | if (!single_user) | ||
395 | pr_warn("Device doesn't support single user mode\n"); | ||
396 | |||
397 | |||
398 | if (!found_com_id) { | ||
399 | pr_warn("Could not find OPAL comid for device. Returning early\n"); | ||
400 | return -EOPNOTSUPP;; | ||
401 | } | ||
402 | |||
403 | dev->comid = comid; | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int opal_discovery0(struct opal_dev *dev) | ||
409 | { | ||
410 | int ret; | ||
411 | |||
412 | memset(dev->resp, 0, IO_BUFFER_LENGTH); | ||
413 | dev->comid = OPAL_DISCOVERY_COMID; | ||
414 | ret = opal_recv_cmd(dev); | ||
415 | if (ret) | ||
416 | return ret; | ||
417 | return opal_discovery0_end(dev); | ||
418 | } | ||
419 | |||
420 | static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok) | ||
421 | { | ||
422 | if (*err) | ||
423 | return; | ||
424 | if (cmd->pos >= IO_BUFFER_LENGTH - 1) { | ||
425 | pr_err("Error adding u8: end of buffer.\n"); | ||
426 | *err = -ERANGE; | ||
427 | return; | ||
428 | } | ||
429 | cmd->cmd[cmd->pos++] = tok; | ||
430 | } | ||
431 | |||
432 | static void add_short_atom_header(struct opal_dev *cmd, bool bytestring, | ||
433 | bool has_sign, int len) | ||
434 | { | ||
435 | u8 atom; | ||
436 | int err = 0; | ||
437 | |||
438 | atom = SHORT_ATOM_ID; | ||
439 | atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0; | ||
440 | atom |= has_sign ? SHORT_ATOM_SIGNED : 0; | ||
441 | atom |= len & SHORT_ATOM_LEN_MASK; | ||
442 | |||
443 | add_token_u8(&err, cmd, atom); | ||
444 | } | ||
445 | |||
446 | static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring, | ||
447 | bool has_sign, int len) | ||
448 | { | ||
449 | u8 header0; | ||
450 | |||
451 | header0 = MEDIUM_ATOM_ID; | ||
452 | header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0; | ||
453 | header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0; | ||
454 | header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK; | ||
455 | cmd->cmd[cmd->pos++] = header0; | ||
456 | cmd->cmd[cmd->pos++] = len; | ||
457 | } | ||
458 | |||
459 | static void add_token_u64(int *err, struct opal_dev *cmd, u64 number) | ||
460 | { | ||
461 | |||
462 | size_t len; | ||
463 | int msb; | ||
464 | u8 n; | ||
465 | |||
466 | if (!(number & ~TINY_ATOM_DATA_MASK)) { | ||
467 | add_token_u8(err, cmd, number); | ||
468 | return; | ||
469 | } | ||
470 | |||
471 | msb = fls(number); | ||
472 | len = DIV_ROUND_UP(msb, 4); | ||
473 | |||
474 | if (cmd->pos >= IO_BUFFER_LENGTH - len - 1) { | ||
475 | pr_err("Error adding u64: end of buffer.\n"); | ||
476 | *err = -ERANGE; | ||
477 | return; | ||
478 | } | ||
479 | add_short_atom_header(cmd, false, false, len); | ||
480 | while (len--) { | ||
481 | n = number >> (len * 8); | ||
482 | add_token_u8(err, cmd, n); | ||
483 | } | ||
484 | } | ||
485 | |||
486 | static void add_token_bytestring(int *err, struct opal_dev *cmd, | ||
487 | const u8 *bytestring, size_t len) | ||
488 | { | ||
489 | size_t header_len = 1; | ||
490 | bool is_short_atom = true; | ||
491 | |||
492 | if (*err) | ||
493 | return; | ||
494 | |||
495 | if (len & ~SHORT_ATOM_LEN_MASK) { | ||
496 | header_len = 2; | ||
497 | is_short_atom = false; | ||
498 | } | ||
499 | |||
500 | if (len >= IO_BUFFER_LENGTH - cmd->pos - header_len) { | ||
501 | pr_err("Error adding bytestring: end of buffer.\n"); | ||
502 | *err = -ERANGE; | ||
503 | return; | ||
504 | } | ||
505 | |||
506 | if (is_short_atom) | ||
507 | add_short_atom_header(cmd, true, false, len); | ||
508 | else | ||
509 | add_medium_atom_header(cmd, true, false, len); | ||
510 | |||
511 | memcpy(&cmd->cmd[cmd->pos], bytestring, len); | ||
512 | cmd->pos += len; | ||
513 | |||
514 | } | ||
515 | |||
516 | static int build_locking_range(u8 *buffer, size_t length, u8 lr) | ||
517 | { | ||
518 | if (length > OPAL_UID_LENGTH) { | ||
519 | pr_err("Can't build locking range. Length OOB\n"); | ||
520 | return -ERANGE; | ||
521 | } | ||
522 | |||
523 | memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH); | ||
524 | |||
525 | if (lr == 0) | ||
526 | return 0; | ||
527 | buffer[5] = LOCKING_RANGE_NON_GLOBAL; | ||
528 | buffer[7] = lr; | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int build_locking_user(u8 *buffer, size_t length, u8 lr) | ||
534 | { | ||
535 | if (length > OPAL_UID_LENGTH) { | ||
536 | pr_err("Can't build locking range user, Length OOB\n"); | ||
537 | return -ERANGE; | ||
538 | } | ||
539 | |||
540 | memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH); | ||
541 | |||
542 | buffer[7] = lr + 1; | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static void set_comid(struct opal_dev *cmd, u16 comid) | ||
548 | { | ||
549 | struct opal_header *hdr = (struct opal_header *)cmd->cmd; | ||
550 | |||
551 | hdr->cp.extendedComID[0] = comid >> 8; | ||
552 | hdr->cp.extendedComID[1] = comid; | ||
553 | hdr->cp.extendedComID[2] = 0; | ||
554 | hdr->cp.extendedComID[3] = 0; | ||
555 | } | ||
556 | |||
557 | static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn) | ||
558 | { | ||
559 | struct opal_header *hdr; | ||
560 | int err = 0; | ||
561 | |||
562 | add_token_u8(&err, cmd, OPAL_ENDOFDATA); | ||
563 | add_token_u8(&err, cmd, OPAL_STARTLIST); | ||
564 | add_token_u8(&err, cmd, 0); | ||
565 | add_token_u8(&err, cmd, 0); | ||
566 | add_token_u8(&err, cmd, 0); | ||
567 | add_token_u8(&err, cmd, OPAL_ENDLIST); | ||
568 | |||
569 | if (err) { | ||
570 | pr_err("Error finalizing command.\n"); | ||
571 | return -EFAULT; | ||
572 | } | ||
573 | |||
574 | hdr = (struct opal_header *) cmd->cmd; | ||
575 | |||
576 | hdr->pkt.tsn = cpu_to_be32(tsn); | ||
577 | hdr->pkt.hsn = cpu_to_be32(hsn); | ||
578 | |||
579 | hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr)); | ||
580 | while (cmd->pos % 4) { | ||
581 | if (cmd->pos >= IO_BUFFER_LENGTH) { | ||
582 | pr_err("Error: Buffer overrun\n"); | ||
583 | return -ERANGE; | ||
584 | } | ||
585 | cmd->cmd[cmd->pos++] = 0; | ||
586 | } | ||
587 | hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) - | ||
588 | sizeof(hdr->pkt)); | ||
589 | hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp)); | ||
590 | |||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | static enum opal_response_token token_type(const struct parsed_resp *resp, | ||
595 | int n) | ||
596 | { | ||
597 | const struct opal_resp_tok *tok; | ||
598 | |||
599 | if (n >= resp->num) { | ||
600 | pr_err("Token number doesn't exist: %d, resp: %d\n", | ||
601 | n, resp->num); | ||
602 | return OPAL_DTA_TOKENID_INVALID; | ||
603 | } | ||
604 | |||
605 | tok = &resp->toks[n]; | ||
606 | if (tok->len == 0) { | ||
607 | pr_err("Token length must be non-zero\n"); | ||
608 | return OPAL_DTA_TOKENID_INVALID; | ||
609 | } | ||
610 | |||
611 | return tok->type; | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * This function returns 0 in case of invalid token. One should call | ||
616 | * token_type() first to find out if the token is valid or not. | ||
617 | */ | ||
618 | static enum opal_token response_get_token(const struct parsed_resp *resp, | ||
619 | int n) | ||
620 | { | ||
621 | const struct opal_resp_tok *tok; | ||
622 | |||
623 | if (n >= resp->num) { | ||
624 | pr_err("Token number doesn't exist: %d, resp: %d\n", | ||
625 | n, resp->num); | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | tok = &resp->toks[n]; | ||
630 | if (tok->len == 0) { | ||
631 | pr_err("Token length must be non-zero\n"); | ||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | return tok->pos[0]; | ||
636 | } | ||
637 | |||
638 | static size_t response_parse_tiny(struct opal_resp_tok *tok, | ||
639 | const u8 *pos) | ||
640 | { | ||
641 | tok->pos = pos; | ||
642 | tok->len = 1; | ||
643 | tok->width = OPAL_WIDTH_TINY; | ||
644 | |||
645 | if (pos[0] & TINY_ATOM_SIGNED) { | ||
646 | tok->type = OPAL_DTA_TOKENID_SINT; | ||
647 | } else { | ||
648 | tok->type = OPAL_DTA_TOKENID_UINT; | ||
649 | tok->stored.u = pos[0] & 0x3f; | ||
650 | } | ||
651 | |||
652 | return tok->len; | ||
653 | } | ||
654 | |||
655 | static size_t response_parse_short(struct opal_resp_tok *tok, | ||
656 | const u8 *pos) | ||
657 | { | ||
658 | tok->pos = pos; | ||
659 | tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1; | ||
660 | tok->width = OPAL_WIDTH_SHORT; | ||
661 | |||
662 | if (pos[0] & SHORT_ATOM_BYTESTRING) { | ||
663 | tok->type = OPAL_DTA_TOKENID_BYTESTRING; | ||
664 | } else if (pos[0] & SHORT_ATOM_SIGNED) { | ||
665 | tok->type = OPAL_DTA_TOKENID_SINT; | ||
666 | } else { | ||
667 | u64 u_integer = 0; | ||
668 | int i, b = 0; | ||
669 | |||
670 | tok->type = OPAL_DTA_TOKENID_UINT; | ||
671 | if (tok->len > 9) { | ||
672 | pr_warn("uint64 with more than 8 bytes\n"); | ||
673 | return -EINVAL; | ||
674 | } | ||
675 | for (i = tok->len - 1; i > 0; i--) { | ||
676 | u_integer |= ((u64)pos[i] << (8 * b)); | ||
677 | b++; | ||
678 | } | ||
679 | tok->stored.u = u_integer; | ||
680 | } | ||
681 | |||
682 | return tok->len; | ||
683 | } | ||
684 | |||
685 | static size_t response_parse_medium(struct opal_resp_tok *tok, | ||
686 | const u8 *pos) | ||
687 | { | ||
688 | tok->pos = pos; | ||
689 | tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2; | ||
690 | tok->width = OPAL_WIDTH_MEDIUM; | ||
691 | |||
692 | if (pos[0] & MEDIUM_ATOM_BYTESTRING) | ||
693 | tok->type = OPAL_DTA_TOKENID_BYTESTRING; | ||
694 | else if (pos[0] & MEDIUM_ATOM_SIGNED) | ||
695 | tok->type = OPAL_DTA_TOKENID_SINT; | ||
696 | else | ||
697 | tok->type = OPAL_DTA_TOKENID_UINT; | ||
698 | |||
699 | return tok->len; | ||
700 | } | ||
701 | |||
702 | static size_t response_parse_long(struct opal_resp_tok *tok, | ||
703 | const u8 *pos) | ||
704 | { | ||
705 | tok->pos = pos; | ||
706 | tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4; | ||
707 | tok->width = OPAL_WIDTH_LONG; | ||
708 | |||
709 | if (pos[0] & LONG_ATOM_BYTESTRING) | ||
710 | tok->type = OPAL_DTA_TOKENID_BYTESTRING; | ||
711 | else if (pos[0] & LONG_ATOM_SIGNED) | ||
712 | tok->type = OPAL_DTA_TOKENID_SINT; | ||
713 | else | ||
714 | tok->type = OPAL_DTA_TOKENID_UINT; | ||
715 | |||
716 | return tok->len; | ||
717 | } | ||
718 | |||
719 | static size_t response_parse_token(struct opal_resp_tok *tok, | ||
720 | const u8 *pos) | ||
721 | { | ||
722 | tok->pos = pos; | ||
723 | tok->len = 1; | ||
724 | tok->type = OPAL_DTA_TOKENID_TOKEN; | ||
725 | tok->width = OPAL_WIDTH_TOKEN; | ||
726 | |||
727 | return tok->len; | ||
728 | } | ||
729 | |||
730 | static int response_parse(const u8 *buf, size_t length, | ||
731 | struct parsed_resp *resp) | ||
732 | { | ||
733 | const struct opal_header *hdr; | ||
734 | struct opal_resp_tok *iter; | ||
735 | int num_entries = 0; | ||
736 | int total; | ||
737 | size_t token_length; | ||
738 | const u8 *pos; | ||
739 | |||
740 | if (!buf) | ||
741 | return -EFAULT; | ||
742 | |||
743 | if (!resp) | ||
744 | return -EFAULT; | ||
745 | |||
746 | hdr = (struct opal_header *)buf; | ||
747 | pos = buf; | ||
748 | pos += sizeof(*hdr); | ||
749 | |||
750 | pr_debug("Response size: cp: %d, pkt: %d, subpkt: %d\n", | ||
751 | be32_to_cpu(hdr->cp.length), | ||
752 | be32_to_cpu(hdr->pkt.length), | ||
753 | be32_to_cpu(hdr->subpkt.length)); | ||
754 | |||
755 | if (hdr->cp.length == 0 || hdr->pkt.length == 0 || | ||
756 | hdr->subpkt.length == 0) { | ||
757 | pr_err("Bad header length. cp: %d, pkt: %d, subpkt: %d\n", | ||
758 | be32_to_cpu(hdr->cp.length), | ||
759 | be32_to_cpu(hdr->pkt.length), | ||
760 | be32_to_cpu(hdr->subpkt.length)); | ||
761 | print_buffer(pos, sizeof(*hdr)); | ||
762 | return -EINVAL; | ||
763 | } | ||
764 | |||
765 | if (pos > buf + length) | ||
766 | return -EFAULT; | ||
767 | |||
768 | iter = resp->toks; | ||
769 | total = be32_to_cpu(hdr->subpkt.length); | ||
770 | print_buffer(pos, total); | ||
771 | while (total > 0) { | ||
772 | if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */ | ||
773 | token_length = response_parse_tiny(iter, pos); | ||
774 | else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */ | ||
775 | token_length = response_parse_short(iter, pos); | ||
776 | else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */ | ||
777 | token_length = response_parse_medium(iter, pos); | ||
778 | else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */ | ||
779 | token_length = response_parse_long(iter, pos); | ||
780 | else /* TOKEN */ | ||
781 | token_length = response_parse_token(iter, pos); | ||
782 | |||
783 | if (token_length == -EINVAL) | ||
784 | return -EINVAL; | ||
785 | |||
786 | pos += token_length; | ||
787 | total -= token_length; | ||
788 | iter++; | ||
789 | num_entries++; | ||
790 | } | ||
791 | |||
792 | if (num_entries == 0) { | ||
793 | pr_err("Couldn't parse response.\n"); | ||
794 | return -EINVAL; | ||
795 | } | ||
796 | resp->num = num_entries; | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | static size_t response_get_string(const struct parsed_resp *resp, int n, | ||
802 | const char **store) | ||
803 | { | ||
804 | *store = NULL; | ||
805 | if (!resp) { | ||
806 | pr_err("Response is NULL\n"); | ||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | if (n > resp->num) { | ||
811 | pr_err("Response has %d tokens. Can't access %d\n", | ||
812 | resp->num, n); | ||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | if (resp->toks[n].type != OPAL_DTA_TOKENID_BYTESTRING) { | ||
817 | pr_err("Token is not a byte string!\n"); | ||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | *store = resp->toks[n].pos + 1; | ||
822 | return resp->toks[n].len - 1; | ||
823 | } | ||
824 | |||
825 | static u64 response_get_u64(const struct parsed_resp *resp, int n) | ||
826 | { | ||
827 | if (!resp) { | ||
828 | pr_err("Response is NULL\n"); | ||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | if (n > resp->num) { | ||
833 | pr_err("Response has %d tokens. Can't access %d\n", | ||
834 | resp->num, n); | ||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) { | ||
839 | pr_err("Token is not unsigned it: %d\n", | ||
840 | resp->toks[n].type); | ||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | if (!(resp->toks[n].width == OPAL_WIDTH_TINY || | ||
845 | resp->toks[n].width == OPAL_WIDTH_SHORT)) { | ||
846 | pr_err("Atom is not short or tiny: %d\n", | ||
847 | resp->toks[n].width); | ||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | return resp->toks[n].stored.u; | ||
852 | } | ||
853 | |||
854 | static u8 response_status(const struct parsed_resp *resp) | ||
855 | { | ||
856 | if (token_type(resp, 0) == OPAL_DTA_TOKENID_TOKEN && | ||
857 | response_get_token(resp, 0) == OPAL_ENDOFSESSION) { | ||
858 | return 0; | ||
859 | } | ||
860 | |||
861 | if (resp->num < 5) | ||
862 | return DTAERROR_NO_METHOD_STATUS; | ||
863 | |||
864 | if (token_type(resp, resp->num - 1) != OPAL_DTA_TOKENID_TOKEN || | ||
865 | token_type(resp, resp->num - 5) != OPAL_DTA_TOKENID_TOKEN || | ||
866 | response_get_token(resp, resp->num - 1) != OPAL_ENDLIST || | ||
867 | response_get_token(resp, resp->num - 5) != OPAL_STARTLIST) | ||
868 | return DTAERROR_NO_METHOD_STATUS; | ||
869 | |||
870 | return response_get_u64(resp, resp->num - 4); | ||
871 | } | ||
872 | |||
873 | /* Parses and checks for errors */ | ||
874 | static int parse_and_check_status(struct opal_dev *dev) | ||
875 | { | ||
876 | int error; | ||
877 | |||
878 | print_buffer(dev->cmd, dev->pos); | ||
879 | |||
880 | error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed); | ||
881 | if (error) { | ||
882 | pr_err("Couldn't parse response.\n"); | ||
883 | return error; | ||
884 | } | ||
885 | |||
886 | return response_status(&dev->parsed); | ||
887 | } | ||
888 | |||
889 | static void clear_opal_cmd(struct opal_dev *dev) | ||
890 | { | ||
891 | dev->pos = sizeof(struct opal_header); | ||
892 | memset(dev->cmd, 0, IO_BUFFER_LENGTH); | ||
893 | } | ||
894 | |||
895 | static int start_opal_session_cont(struct opal_dev *dev) | ||
896 | { | ||
897 | u32 hsn, tsn; | ||
898 | int error = 0; | ||
899 | |||
900 | error = parse_and_check_status(dev); | ||
901 | if (error) | ||
902 | return error; | ||
903 | |||
904 | hsn = response_get_u64(&dev->parsed, 4); | ||
905 | tsn = response_get_u64(&dev->parsed, 5); | ||
906 | |||
907 | if (hsn == 0 && tsn == 0) { | ||
908 | pr_err("Couldn't authenticate session\n"); | ||
909 | return -EPERM; | ||
910 | } | ||
911 | |||
912 | dev->hsn = hsn; | ||
913 | dev->tsn = tsn; | ||
914 | return 0; | ||
915 | } | ||
916 | |||
917 | static void add_suspend_info(struct opal_dev *dev, | ||
918 | struct opal_suspend_data *sus) | ||
919 | { | ||
920 | struct opal_suspend_data *iter; | ||
921 | |||
922 | list_for_each_entry(iter, &dev->unlk_lst, node) { | ||
923 | if (iter->lr == sus->lr) { | ||
924 | list_del(&iter->node); | ||
925 | kfree(iter); | ||
926 | break; | ||
927 | } | ||
928 | } | ||
929 | list_add_tail(&sus->node, &dev->unlk_lst); | ||
930 | } | ||
931 | |||
932 | static int end_session_cont(struct opal_dev *dev) | ||
933 | { | ||
934 | dev->hsn = 0; | ||
935 | dev->tsn = 0; | ||
936 | return parse_and_check_status(dev); | ||
937 | } | ||
938 | |||
939 | static int finalize_and_send(struct opal_dev *dev, cont_fn cont) | ||
940 | { | ||
941 | int ret; | ||
942 | |||
943 | ret = cmd_finalize(dev, dev->hsn, dev->tsn); | ||
944 | if (ret) { | ||
945 | pr_err("Error finalizing command buffer: %d\n", ret); | ||
946 | return ret; | ||
947 | } | ||
948 | |||
949 | print_buffer(dev->cmd, dev->pos); | ||
950 | |||
951 | return opal_send_recv(dev, cont); | ||
952 | } | ||
953 | |||
954 | static int gen_key(struct opal_dev *dev) | ||
955 | { | ||
956 | const u8 *method; | ||
957 | u8 uid[OPAL_UID_LENGTH]; | ||
958 | int err = 0; | ||
959 | |||
960 | clear_opal_cmd(dev); | ||
961 | set_comid(dev, dev->comid); | ||
962 | |||
963 | memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len)); | ||
964 | method = opalmethod[OPAL_GENKEY]; | ||
965 | kfree(dev->prev_data); | ||
966 | dev->prev_data = NULL; | ||
967 | |||
968 | add_token_u8(&err, dev, OPAL_CALL); | ||
969 | add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH); | ||
970 | add_token_bytestring(&err, dev, opalmethod[OPAL_GENKEY], | ||
971 | OPAL_UID_LENGTH); | ||
972 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
973 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
974 | |||
975 | if (err) { | ||
976 | pr_err("Error building gen key command\n"); | ||
977 | return err; | ||
978 | |||
979 | } | ||
980 | return finalize_and_send(dev, parse_and_check_status); | ||
981 | } | ||
982 | |||
983 | static int get_active_key_cont(struct opal_dev *dev) | ||
984 | { | ||
985 | const char *activekey; | ||
986 | size_t keylen; | ||
987 | int error = 0; | ||
988 | |||
989 | error = parse_and_check_status(dev); | ||
990 | if (error) | ||
991 | return error; | ||
992 | keylen = response_get_string(&dev->parsed, 4, &activekey); | ||
993 | if (!activekey) { | ||
994 | pr_err("%s: Couldn't extract the Activekey from the response\n", | ||
995 | __func__); | ||
996 | return OPAL_INVAL_PARAM; | ||
997 | } | ||
998 | dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL); | ||
999 | |||
1000 | if (!dev->prev_data) | ||
1001 | return -ENOMEM; | ||
1002 | |||
1003 | dev->prev_d_len = keylen; | ||
1004 | |||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | static int get_active_key(struct opal_dev *dev) | ||
1009 | { | ||
1010 | u8 uid[OPAL_UID_LENGTH]; | ||
1011 | int err = 0; | ||
1012 | u8 *lr; | ||
1013 | |||
1014 | clear_opal_cmd(dev); | ||
1015 | set_comid(dev, dev->comid); | ||
1016 | lr = dev->func_data[dev->state]; | ||
1017 | |||
1018 | err = build_locking_range(uid, sizeof(uid), *lr); | ||
1019 | if (err) | ||
1020 | return err; | ||
1021 | |||
1022 | err = 0; | ||
1023 | add_token_u8(&err, dev, OPAL_CALL); | ||
1024 | add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH); | ||
1025 | add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH); | ||
1026 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1027 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1028 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1029 | add_token_u8(&err, dev, 3); /* startCloumn */ | ||
1030 | add_token_u8(&err, dev, 10); /* ActiveKey */ | ||
1031 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1032 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1033 | add_token_u8(&err, dev, 4); /* endColumn */ | ||
1034 | add_token_u8(&err, dev, 10); /* ActiveKey */ | ||
1035 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1036 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1037 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1038 | if (err) { | ||
1039 | pr_err("Error building get active key command\n"); | ||
1040 | return err; | ||
1041 | } | ||
1042 | |||
1043 | return finalize_and_send(dev, get_active_key_cont); | ||
1044 | } | ||
1045 | |||
1046 | static int generic_lr_enable_disable(struct opal_dev *dev, | ||
1047 | u8 *uid, bool rle, bool wle, | ||
1048 | bool rl, bool wl) | ||
1049 | { | ||
1050 | int err = 0; | ||
1051 | |||
1052 | add_token_u8(&err, dev, OPAL_CALL); | ||
1053 | add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH); | ||
1054 | add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH); | ||
1055 | |||
1056 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1057 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1058 | add_token_u8(&err, dev, OPAL_VALUES); | ||
1059 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1060 | |||
1061 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1062 | add_token_u8(&err, dev, 5); /* ReadLockEnabled */ | ||
1063 | add_token_u8(&err, dev, rle); | ||
1064 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1065 | |||
1066 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1067 | add_token_u8(&err, dev, 6); /* WriteLockEnabled */ | ||
1068 | add_token_u8(&err, dev, wle); | ||
1069 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1070 | |||
1071 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1072 | add_token_u8(&err, dev, OPAL_READLOCKED); | ||
1073 | add_token_u8(&err, dev, rl); | ||
1074 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1075 | |||
1076 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1077 | add_token_u8(&err, dev, OPAL_WRITELOCKED); | ||
1078 | add_token_u8(&err, dev, wl); | ||
1079 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1080 | |||
1081 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1082 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1083 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1084 | return err; | ||
1085 | } | ||
1086 | |||
1087 | static inline int enable_global_lr(struct opal_dev *dev, u8 *uid, | ||
1088 | struct opal_user_lr_setup *setup) | ||
1089 | { | ||
1090 | int err; | ||
1091 | |||
1092 | err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE, | ||
1093 | 0, 0); | ||
1094 | if (err) | ||
1095 | pr_err("Failed to create enable global lr command\n"); | ||
1096 | return err; | ||
1097 | } | ||
1098 | |||
1099 | static int setup_locking_range(struct opal_dev *dev) | ||
1100 | { | ||
1101 | u8 uid[OPAL_UID_LENGTH]; | ||
1102 | struct opal_user_lr_setup *setup; | ||
1103 | u8 lr; | ||
1104 | int err = 0; | ||
1105 | |||
1106 | clear_opal_cmd(dev); | ||
1107 | set_comid(dev, dev->comid); | ||
1108 | |||
1109 | setup = dev->func_data[dev->state]; | ||
1110 | lr = setup->session.opal_key.lr; | ||
1111 | err = build_locking_range(uid, sizeof(uid), lr); | ||
1112 | if (err) | ||
1113 | return err; | ||
1114 | |||
1115 | if (lr == 0) | ||
1116 | err = enable_global_lr(dev, uid, setup); | ||
1117 | else { | ||
1118 | add_token_u8(&err, dev, OPAL_CALL); | ||
1119 | add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH); | ||
1120 | add_token_bytestring(&err, dev, opalmethod[OPAL_SET], | ||
1121 | OPAL_UID_LENGTH); | ||
1122 | |||
1123 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1124 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1125 | add_token_u8(&err, dev, OPAL_VALUES); | ||
1126 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1127 | |||
1128 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1129 | add_token_u8(&err, dev, 3); /* Ranges Start */ | ||
1130 | add_token_u64(&err, dev, setup->range_start); | ||
1131 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1132 | |||
1133 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1134 | add_token_u8(&err, dev, 4); /* Ranges length */ | ||
1135 | add_token_u64(&err, dev, setup->range_length); | ||
1136 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1137 | |||
1138 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1139 | add_token_u8(&err, dev, 5); /*ReadLockEnabled */ | ||
1140 | add_token_u64(&err, dev, !!setup->RLE); | ||
1141 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1142 | |||
1143 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1144 | add_token_u8(&err, dev, 6); /*WriteLockEnabled*/ | ||
1145 | add_token_u64(&err, dev, !!setup->WLE); | ||
1146 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1147 | |||
1148 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1149 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1150 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1151 | |||
1152 | } | ||
1153 | if (err) { | ||
1154 | pr_err("Error building Setup Locking range command.\n"); | ||
1155 | return err; | ||
1156 | |||
1157 | } | ||
1158 | |||
1159 | return finalize_and_send(dev, parse_and_check_status); | ||
1160 | } | ||
1161 | |||
1162 | static int start_generic_opal_session(struct opal_dev *dev, | ||
1163 | enum opal_uid auth, | ||
1164 | enum opal_uid sp_type, | ||
1165 | const char *key, | ||
1166 | u8 key_len) | ||
1167 | { | ||
1168 | u32 hsn; | ||
1169 | int err = 0; | ||
1170 | |||
1171 | if (key == NULL && auth != OPAL_ANYBODY_UID) { | ||
1172 | pr_err("%s: Attempted to open ADMIN_SP Session without a Host" \ | ||
1173 | "Challenge, and not as the Anybody UID\n", __func__); | ||
1174 | return OPAL_INVAL_PARAM; | ||
1175 | } | ||
1176 | |||
1177 | clear_opal_cmd(dev); | ||
1178 | |||
1179 | set_comid(dev, dev->comid); | ||
1180 | hsn = GENERIC_HOST_SESSION_NUM; | ||
1181 | |||
1182 | add_token_u8(&err, dev, OPAL_CALL); | ||
1183 | add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID], | ||
1184 | OPAL_UID_LENGTH); | ||
1185 | add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION], | ||
1186 | OPAL_UID_LENGTH); | ||
1187 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1188 | add_token_u64(&err, dev, hsn); | ||
1189 | add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH); | ||
1190 | add_token_u8(&err, dev, 1); | ||
1191 | |||
1192 | switch (auth) { | ||
1193 | case OPAL_ANYBODY_UID: | ||
1194 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1195 | break; | ||
1196 | case OPAL_ADMIN1_UID: | ||
1197 | case OPAL_SID_UID: | ||
1198 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1199 | add_token_u8(&err, dev, 0); /* HostChallenge */ | ||
1200 | add_token_bytestring(&err, dev, key, key_len); | ||
1201 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1202 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1203 | add_token_u8(&err, dev, 3); /* HostSignAuth */ | ||
1204 | add_token_bytestring(&err, dev, opaluid[auth], | ||
1205 | OPAL_UID_LENGTH); | ||
1206 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1207 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1208 | break; | ||
1209 | default: | ||
1210 | pr_err("Cannot start Admin SP session with auth %d\n", auth); | ||
1211 | return OPAL_INVAL_PARAM; | ||
1212 | } | ||
1213 | |||
1214 | if (err) { | ||
1215 | pr_err("Error building start adminsp session command.\n"); | ||
1216 | return err; | ||
1217 | } | ||
1218 | |||
1219 | return finalize_and_send(dev, start_opal_session_cont); | ||
1220 | } | ||
1221 | |||
1222 | static int start_anybodyASP_opal_session(struct opal_dev *dev) | ||
1223 | { | ||
1224 | return start_generic_opal_session(dev, OPAL_ANYBODY_UID, | ||
1225 | OPAL_ADMINSP_UID, NULL, 0); | ||
1226 | } | ||
1227 | |||
1228 | static int start_SIDASP_opal_session(struct opal_dev *dev) | ||
1229 | { | ||
1230 | int ret; | ||
1231 | const u8 *key = dev->prev_data; | ||
1232 | struct opal_key *okey; | ||
1233 | |||
1234 | if (!key) { | ||
1235 | okey = dev->func_data[dev->state]; | ||
1236 | ret = start_generic_opal_session(dev, OPAL_SID_UID, | ||
1237 | OPAL_ADMINSP_UID, | ||
1238 | okey->key, | ||
1239 | okey->key_len); | ||
1240 | } else { | ||
1241 | ret = start_generic_opal_session(dev, OPAL_SID_UID, | ||
1242 | OPAL_ADMINSP_UID, | ||
1243 | key, dev->prev_d_len); | ||
1244 | kfree(key); | ||
1245 | dev->prev_data = NULL; | ||
1246 | } | ||
1247 | return ret; | ||
1248 | } | ||
1249 | |||
1250 | static inline int start_admin1LSP_opal_session(struct opal_dev *dev) | ||
1251 | { | ||
1252 | struct opal_key *key = dev->func_data[dev->state]; | ||
1253 | |||
1254 | return start_generic_opal_session(dev, OPAL_ADMIN1_UID, | ||
1255 | OPAL_LOCKINGSP_UID, | ||
1256 | key->key, key->key_len); | ||
1257 | } | ||
1258 | |||
1259 | static int start_auth_opal_session(struct opal_dev *dev) | ||
1260 | { | ||
1261 | u8 lk_ul_user[OPAL_UID_LENGTH]; | ||
1262 | int err = 0; | ||
1263 | |||
1264 | struct opal_session_info *session = dev->func_data[dev->state]; | ||
1265 | size_t keylen = session->opal_key.key_len; | ||
1266 | u8 *key = session->opal_key.key; | ||
1267 | u32 hsn = GENERIC_HOST_SESSION_NUM; | ||
1268 | |||
1269 | clear_opal_cmd(dev); | ||
1270 | set_comid(dev, dev->comid); | ||
1271 | |||
1272 | if (session->sum) { | ||
1273 | err = build_locking_user(lk_ul_user, sizeof(lk_ul_user), | ||
1274 | session->opal_key.lr); | ||
1275 | if (err) | ||
1276 | return err; | ||
1277 | |||
1278 | } else if (session->who != OPAL_ADMIN1 && !session->sum) { | ||
1279 | err = build_locking_user(lk_ul_user, sizeof(lk_ul_user), | ||
1280 | session->who - 1); | ||
1281 | if (err) | ||
1282 | return err; | ||
1283 | } else | ||
1284 | memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH); | ||
1285 | |||
1286 | add_token_u8(&err, dev, OPAL_CALL); | ||
1287 | add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID], | ||
1288 | OPAL_UID_LENGTH); | ||
1289 | add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION], | ||
1290 | OPAL_UID_LENGTH); | ||
1291 | |||
1292 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1293 | add_token_u64(&err, dev, hsn); | ||
1294 | add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID], | ||
1295 | OPAL_UID_LENGTH); | ||
1296 | add_token_u8(&err, dev, 1); | ||
1297 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1298 | add_token_u8(&err, dev, 0); | ||
1299 | add_token_bytestring(&err, dev, key, keylen); | ||
1300 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1301 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1302 | add_token_u8(&err, dev, 3); | ||
1303 | add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH); | ||
1304 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1305 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1306 | |||
1307 | if (err) { | ||
1308 | pr_err("Error building STARTSESSION command.\n"); | ||
1309 | return err; | ||
1310 | } | ||
1311 | |||
1312 | return finalize_and_send(dev, start_opal_session_cont); | ||
1313 | } | ||
1314 | |||
1315 | static int revert_tper(struct opal_dev *dev) | ||
1316 | { | ||
1317 | int err = 0; | ||
1318 | |||
1319 | clear_opal_cmd(dev); | ||
1320 | set_comid(dev, dev->comid); | ||
1321 | |||
1322 | add_token_u8(&err, dev, OPAL_CALL); | ||
1323 | add_token_bytestring(&err, dev, opaluid[OPAL_ADMINSP_UID], | ||
1324 | OPAL_UID_LENGTH); | ||
1325 | add_token_bytestring(&err, dev, opalmethod[OPAL_REVERT], | ||
1326 | OPAL_UID_LENGTH); | ||
1327 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1328 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1329 | if (err) { | ||
1330 | pr_err("Error building REVERT TPER command.\n"); | ||
1331 | return err; | ||
1332 | } | ||
1333 | |||
1334 | return finalize_and_send(dev, parse_and_check_status); | ||
1335 | } | ||
1336 | |||
1337 | static int internal_activate_user(struct opal_dev *dev) | ||
1338 | { | ||
1339 | struct opal_session_info *session = dev->func_data[dev->state]; | ||
1340 | u8 uid[OPAL_UID_LENGTH]; | ||
1341 | int err = 0; | ||
1342 | |||
1343 | clear_opal_cmd(dev); | ||
1344 | set_comid(dev, dev->comid); | ||
1345 | |||
1346 | memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH); | ||
1347 | uid[7] = session->who; | ||
1348 | |||
1349 | add_token_u8(&err, dev, OPAL_CALL); | ||
1350 | add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH); | ||
1351 | add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH); | ||
1352 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1353 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1354 | add_token_u8(&err, dev, OPAL_VALUES); | ||
1355 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1356 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1357 | add_token_u8(&err, dev, 5); /* Enabled */ | ||
1358 | add_token_u8(&err, dev, OPAL_TRUE); | ||
1359 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1360 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1361 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1362 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1363 | |||
1364 | if (err) { | ||
1365 | pr_err("Error building Activate UserN command.\n"); | ||
1366 | return err; | ||
1367 | } | ||
1368 | |||
1369 | return finalize_and_send(dev, parse_and_check_status); | ||
1370 | } | ||
1371 | |||
1372 | static int erase_locking_range(struct opal_dev *dev) | ||
1373 | { | ||
1374 | struct opal_session_info *session; | ||
1375 | u8 uid[OPAL_UID_LENGTH]; | ||
1376 | int err = 0; | ||
1377 | |||
1378 | clear_opal_cmd(dev); | ||
1379 | set_comid(dev, dev->comid); | ||
1380 | session = dev->func_data[dev->state]; | ||
1381 | |||
1382 | if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0) | ||
1383 | return -ERANGE; | ||
1384 | |||
1385 | add_token_u8(&err, dev, OPAL_CALL); | ||
1386 | add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH); | ||
1387 | add_token_bytestring(&err, dev, opalmethod[OPAL_ERASE], | ||
1388 | OPAL_UID_LENGTH); | ||
1389 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1390 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1391 | |||
1392 | if (err) { | ||
1393 | pr_err("Error building Erase Locking Range Command.\n"); | ||
1394 | return err; | ||
1395 | } | ||
1396 | return finalize_and_send(dev, parse_and_check_status); | ||
1397 | } | ||
1398 | |||
1399 | static int set_mbr_done(struct opal_dev *dev) | ||
1400 | { | ||
1401 | u8 mbr_done_tf = *(u8 *)dev->func_data[dev->state]; | ||
1402 | int err = 0; | ||
1403 | |||
1404 | clear_opal_cmd(dev); | ||
1405 | set_comid(dev, dev->comid); | ||
1406 | |||
1407 | add_token_u8(&err, dev, OPAL_CALL); | ||
1408 | add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL], | ||
1409 | OPAL_UID_LENGTH); | ||
1410 | add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH); | ||
1411 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1412 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1413 | add_token_u8(&err, dev, OPAL_VALUES); | ||
1414 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1415 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1416 | add_token_u8(&err, dev, 2); /* Done */ | ||
1417 | add_token_u8(&err, dev, mbr_done_tf); /* Done T or F */ | ||
1418 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1419 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1420 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1421 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1422 | |||
1423 | if (err) { | ||
1424 | pr_err("Error Building set MBR Done command\n"); | ||
1425 | return err; | ||
1426 | } | ||
1427 | |||
1428 | return finalize_and_send(dev, parse_and_check_status); | ||
1429 | } | ||
1430 | |||
1431 | static int set_mbr_enable_disable(struct opal_dev *dev) | ||
1432 | { | ||
1433 | u8 mbr_en_dis = *(u8 *)dev->func_data[dev->state]; | ||
1434 | int err = 0; | ||
1435 | |||
1436 | clear_opal_cmd(dev); | ||
1437 | set_comid(dev, dev->comid); | ||
1438 | |||
1439 | add_token_u8(&err, dev, OPAL_CALL); | ||
1440 | add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL], | ||
1441 | OPAL_UID_LENGTH); | ||
1442 | add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH); | ||
1443 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1444 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1445 | add_token_u8(&err, dev, OPAL_VALUES); | ||
1446 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1447 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1448 | add_token_u8(&err, dev, 1); | ||
1449 | add_token_u8(&err, dev, mbr_en_dis); | ||
1450 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1451 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1452 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1453 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1454 | |||
1455 | if (err) { | ||
1456 | pr_err("Error Building set MBR done command\n"); | ||
1457 | return err; | ||
1458 | } | ||
1459 | |||
1460 | return finalize_and_send(dev, parse_and_check_status); | ||
1461 | } | ||
1462 | |||
1463 | static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid, | ||
1464 | struct opal_dev *dev) | ||
1465 | { | ||
1466 | int err = 0; | ||
1467 | |||
1468 | clear_opal_cmd(dev); | ||
1469 | set_comid(dev, dev->comid); | ||
1470 | |||
1471 | add_token_u8(&err, dev, OPAL_CALL); | ||
1472 | add_token_bytestring(&err, dev, cpin_uid, OPAL_UID_LENGTH); | ||
1473 | add_token_bytestring(&err, dev, opalmethod[OPAL_SET], | ||
1474 | OPAL_UID_LENGTH); | ||
1475 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1476 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1477 | add_token_u8(&err, dev, OPAL_VALUES); | ||
1478 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1479 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1480 | add_token_u8(&err, dev, 3); /* PIN */ | ||
1481 | add_token_bytestring(&err, dev, key, key_len); | ||
1482 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1483 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1484 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1485 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1486 | |||
1487 | return err; | ||
1488 | } | ||
1489 | |||
1490 | static int set_new_pw(struct opal_dev *dev) | ||
1491 | { | ||
1492 | u8 cpin_uid[OPAL_UID_LENGTH]; | ||
1493 | struct opal_session_info *usr = dev->func_data[dev->state]; | ||
1494 | |||
1495 | |||
1496 | memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH); | ||
1497 | |||
1498 | if (usr->who != OPAL_ADMIN1) { | ||
1499 | cpin_uid[5] = 0x03; | ||
1500 | if (usr->sum) | ||
1501 | cpin_uid[7] = usr->opal_key.lr + 1; | ||
1502 | else | ||
1503 | cpin_uid[7] = usr->who; | ||
1504 | } | ||
1505 | |||
1506 | if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len, | ||
1507 | cpin_uid, dev)) { | ||
1508 | pr_err("Error building set password command.\n"); | ||
1509 | return -ERANGE; | ||
1510 | } | ||
1511 | |||
1512 | return finalize_and_send(dev, parse_and_check_status); | ||
1513 | } | ||
1514 | |||
1515 | static int set_sid_cpin_pin(struct opal_dev *dev) | ||
1516 | { | ||
1517 | u8 cpin_uid[OPAL_UID_LENGTH]; | ||
1518 | struct opal_key *key = dev->func_data[dev->state]; | ||
1519 | |||
1520 | memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH); | ||
1521 | |||
1522 | if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) { | ||
1523 | pr_err("Error building Set SID cpin\n"); | ||
1524 | return -ERANGE; | ||
1525 | } | ||
1526 | return finalize_and_send(dev, parse_and_check_status); | ||
1527 | } | ||
1528 | |||
1529 | static int add_user_to_lr(struct opal_dev *dev) | ||
1530 | { | ||
1531 | u8 lr_buffer[OPAL_UID_LENGTH]; | ||
1532 | u8 user_uid[OPAL_UID_LENGTH]; | ||
1533 | struct opal_lock_unlock *lkul; | ||
1534 | int err = 0; | ||
1535 | |||
1536 | clear_opal_cmd(dev); | ||
1537 | set_comid(dev, dev->comid); | ||
1538 | |||
1539 | lkul = dev->func_data[dev->state]; | ||
1540 | |||
1541 | memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED], | ||
1542 | OPAL_UID_LENGTH); | ||
1543 | |||
1544 | if (lkul->l_state == OPAL_RW) | ||
1545 | memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED], | ||
1546 | OPAL_UID_LENGTH); | ||
1547 | |||
1548 | lr_buffer[7] = lkul->session.opal_key.lr; | ||
1549 | |||
1550 | memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH); | ||
1551 | |||
1552 | user_uid[7] = lkul->session.who; | ||
1553 | |||
1554 | add_token_u8(&err, dev, OPAL_CALL); | ||
1555 | add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH); | ||
1556 | add_token_bytestring(&err, dev, opalmethod[OPAL_SET], | ||
1557 | OPAL_UID_LENGTH); | ||
1558 | |||
1559 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1560 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1561 | add_token_u8(&err, dev, OPAL_VALUES); | ||
1562 | |||
1563 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1564 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1565 | add_token_u8(&err, dev, 3); | ||
1566 | |||
1567 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1568 | |||
1569 | |||
1570 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1571 | add_token_bytestring(&err, dev, | ||
1572 | opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF], | ||
1573 | OPAL_UID_LENGTH/2); | ||
1574 | add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH); | ||
1575 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1576 | |||
1577 | |||
1578 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1579 | add_token_bytestring(&err, dev, | ||
1580 | opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF], | ||
1581 | OPAL_UID_LENGTH/2); | ||
1582 | add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH); | ||
1583 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1584 | |||
1585 | |||
1586 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1587 | add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE], | ||
1588 | OPAL_UID_LENGTH/2); | ||
1589 | add_token_u8(&err, dev, 1); | ||
1590 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1591 | |||
1592 | |||
1593 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1594 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1595 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1596 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1597 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1598 | |||
1599 | if (err) { | ||
1600 | pr_err("Error building add user to locking range command.\n"); | ||
1601 | return err; | ||
1602 | } | ||
1603 | |||
1604 | return finalize_and_send(dev, parse_and_check_status); | ||
1605 | } | ||
1606 | |||
1607 | static int lock_unlock_locking_range(struct opal_dev *dev) | ||
1608 | { | ||
1609 | u8 lr_buffer[OPAL_UID_LENGTH]; | ||
1610 | const u8 *method; | ||
1611 | struct opal_lock_unlock *lkul; | ||
1612 | u8 read_locked = 1, write_locked = 1; | ||
1613 | int err = 0; | ||
1614 | |||
1615 | clear_opal_cmd(dev); | ||
1616 | set_comid(dev, dev->comid); | ||
1617 | |||
1618 | method = opalmethod[OPAL_SET]; | ||
1619 | lkul = dev->func_data[dev->state]; | ||
1620 | if (build_locking_range(lr_buffer, sizeof(lr_buffer), | ||
1621 | lkul->session.opal_key.lr) < 0) | ||
1622 | return -ERANGE; | ||
1623 | |||
1624 | switch (lkul->l_state) { | ||
1625 | case OPAL_RO: | ||
1626 | read_locked = 0; | ||
1627 | write_locked = 1; | ||
1628 | break; | ||
1629 | case OPAL_RW: | ||
1630 | read_locked = 0; | ||
1631 | write_locked = 0; | ||
1632 | break; | ||
1633 | case OPAL_LK: | ||
1634 | /* vars are initalized to locked */ | ||
1635 | break; | ||
1636 | default: | ||
1637 | pr_err("Tried to set an invalid locking state... returning to uland\n"); | ||
1638 | return OPAL_INVAL_PARAM; | ||
1639 | } | ||
1640 | |||
1641 | add_token_u8(&err, dev, OPAL_CALL); | ||
1642 | add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH); | ||
1643 | add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH); | ||
1644 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1645 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1646 | add_token_u8(&err, dev, OPAL_VALUES); | ||
1647 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1648 | |||
1649 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1650 | add_token_u8(&err, dev, OPAL_READLOCKED); | ||
1651 | add_token_u8(&err, dev, read_locked); | ||
1652 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1653 | |||
1654 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1655 | add_token_u8(&err, dev, OPAL_WRITELOCKED); | ||
1656 | add_token_u8(&err, dev, write_locked); | ||
1657 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1658 | |||
1659 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1660 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1661 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1662 | |||
1663 | if (err) { | ||
1664 | pr_err("Error building SET command.\n"); | ||
1665 | return err; | ||
1666 | } | ||
1667 | return finalize_and_send(dev, parse_and_check_status); | ||
1668 | } | ||
1669 | |||
1670 | |||
1671 | static int lock_unlock_locking_range_sum(struct opal_dev *dev) | ||
1672 | { | ||
1673 | u8 lr_buffer[OPAL_UID_LENGTH]; | ||
1674 | u8 read_locked = 1, write_locked = 1; | ||
1675 | const u8 *method; | ||
1676 | struct opal_lock_unlock *lkul; | ||
1677 | int ret; | ||
1678 | |||
1679 | clear_opal_cmd(dev); | ||
1680 | set_comid(dev, dev->comid); | ||
1681 | |||
1682 | method = opalmethod[OPAL_SET]; | ||
1683 | lkul = dev->func_data[dev->state]; | ||
1684 | if (build_locking_range(lr_buffer, sizeof(lr_buffer), | ||
1685 | lkul->session.opal_key.lr) < 0) | ||
1686 | return -ERANGE; | ||
1687 | |||
1688 | switch (lkul->l_state) { | ||
1689 | case OPAL_RO: | ||
1690 | read_locked = 0; | ||
1691 | write_locked = 1; | ||
1692 | break; | ||
1693 | case OPAL_RW: | ||
1694 | read_locked = 0; | ||
1695 | write_locked = 0; | ||
1696 | break; | ||
1697 | case OPAL_LK: | ||
1698 | /* vars are initalized to locked */ | ||
1699 | break; | ||
1700 | default: | ||
1701 | pr_err("Tried to set an invalid locking state.\n"); | ||
1702 | return OPAL_INVAL_PARAM; | ||
1703 | } | ||
1704 | ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1, | ||
1705 | read_locked, write_locked); | ||
1706 | |||
1707 | if (ret < 0) { | ||
1708 | pr_err("Error building SET command.\n"); | ||
1709 | return ret; | ||
1710 | } | ||
1711 | return finalize_and_send(dev, parse_and_check_status); | ||
1712 | } | ||
1713 | |||
1714 | static int activate_lsp(struct opal_dev *dev) | ||
1715 | { | ||
1716 | struct opal_lr_act *opal_act; | ||
1717 | u8 user_lr[OPAL_UID_LENGTH]; | ||
1718 | u8 uint_3 = 0x83; | ||
1719 | int err = 0, i; | ||
1720 | |||
1721 | clear_opal_cmd(dev); | ||
1722 | set_comid(dev, dev->comid); | ||
1723 | |||
1724 | opal_act = dev->func_data[dev->state]; | ||
1725 | |||
1726 | add_token_u8(&err, dev, OPAL_CALL); | ||
1727 | add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID], | ||
1728 | OPAL_UID_LENGTH); | ||
1729 | add_token_bytestring(&err, dev, opalmethod[OPAL_ACTIVATE], | ||
1730 | OPAL_UID_LENGTH); | ||
1731 | |||
1732 | |||
1733 | if (opal_act->sum) { | ||
1734 | err = build_locking_range(user_lr, sizeof(user_lr), | ||
1735 | opal_act->lr[0]); | ||
1736 | if (err) | ||
1737 | return err; | ||
1738 | |||
1739 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1740 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1741 | add_token_u8(&err, dev, uint_3); | ||
1742 | add_token_u8(&err, dev, 6); | ||
1743 | add_token_u8(&err, dev, 0); | ||
1744 | add_token_u8(&err, dev, 0); | ||
1745 | |||
1746 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1747 | add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH); | ||
1748 | for (i = 1; i < opal_act->num_lrs; i++) { | ||
1749 | user_lr[7] = opal_act->lr[i]; | ||
1750 | add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH); | ||
1751 | } | ||
1752 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1753 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1754 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1755 | |||
1756 | } else { | ||
1757 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1758 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1759 | } | ||
1760 | |||
1761 | if (err) { | ||
1762 | pr_err("Error building Activate LockingSP command.\n"); | ||
1763 | return err; | ||
1764 | } | ||
1765 | |||
1766 | return finalize_and_send(dev, parse_and_check_status); | ||
1767 | } | ||
1768 | |||
1769 | static int get_lsp_lifecycle_cont(struct opal_dev *dev) | ||
1770 | { | ||
1771 | u8 lc_status; | ||
1772 | int error = 0; | ||
1773 | |||
1774 | error = parse_and_check_status(dev); | ||
1775 | if (error) | ||
1776 | return error; | ||
1777 | |||
1778 | lc_status = response_get_u64(&dev->parsed, 4); | ||
1779 | /* 0x08 is Manufacured Inactive */ | ||
1780 | /* 0x09 is Manufactured */ | ||
1781 | if (lc_status != OPAL_MANUFACTURED_INACTIVE) { | ||
1782 | pr_err("Couldn't determine the status of the Lifcycle state\n"); | ||
1783 | return -ENODEV; | ||
1784 | } | ||
1785 | |||
1786 | return 0; | ||
1787 | } | ||
1788 | |||
1789 | /* Determine if we're in the Manufactured Inactive or Active state */ | ||
1790 | static int get_lsp_lifecycle(struct opal_dev *dev) | ||
1791 | { | ||
1792 | int err = 0; | ||
1793 | |||
1794 | clear_opal_cmd(dev); | ||
1795 | set_comid(dev, dev->comid); | ||
1796 | |||
1797 | add_token_u8(&err, dev, OPAL_CALL); | ||
1798 | add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID], | ||
1799 | OPAL_UID_LENGTH); | ||
1800 | add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH); | ||
1801 | |||
1802 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1803 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1804 | |||
1805 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1806 | add_token_u8(&err, dev, 3); /* Start Column */ | ||
1807 | add_token_u8(&err, dev, 6); /* Lifecycle Column */ | ||
1808 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1809 | |||
1810 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1811 | add_token_u8(&err, dev, 4); /* End Column */ | ||
1812 | add_token_u8(&err, dev, 6); /* Lifecycle Column */ | ||
1813 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1814 | |||
1815 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1816 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1817 | |||
1818 | if (err) { | ||
1819 | pr_err("Error Building GET Lifecycle Status command\n"); | ||
1820 | return err; | ||
1821 | } | ||
1822 | |||
1823 | return finalize_and_send(dev, get_lsp_lifecycle_cont); | ||
1824 | } | ||
1825 | |||
1826 | static int get_msid_cpin_pin_cont(struct opal_dev *dev) | ||
1827 | { | ||
1828 | const char *msid_pin; | ||
1829 | size_t strlen; | ||
1830 | int error = 0; | ||
1831 | |||
1832 | error = parse_and_check_status(dev); | ||
1833 | if (error) | ||
1834 | return error; | ||
1835 | |||
1836 | strlen = response_get_string(&dev->parsed, 4, &msid_pin); | ||
1837 | if (!msid_pin) { | ||
1838 | pr_err("%s: Couldn't extract PIN from response\n", __func__); | ||
1839 | return OPAL_INVAL_PARAM; | ||
1840 | } | ||
1841 | |||
1842 | dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL); | ||
1843 | if (!dev->prev_data) | ||
1844 | return -ENOMEM; | ||
1845 | |||
1846 | dev->prev_d_len = strlen; | ||
1847 | |||
1848 | return 0; | ||
1849 | } | ||
1850 | |||
1851 | static int get_msid_cpin_pin(struct opal_dev *dev) | ||
1852 | { | ||
1853 | int err = 0; | ||
1854 | |||
1855 | clear_opal_cmd(dev); | ||
1856 | set_comid(dev, dev->comid); | ||
1857 | |||
1858 | |||
1859 | add_token_u8(&err, dev, OPAL_CALL); | ||
1860 | add_token_bytestring(&err, dev, opaluid[OPAL_C_PIN_MSID], | ||
1861 | OPAL_UID_LENGTH); | ||
1862 | add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH); | ||
1863 | |||
1864 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1865 | add_token_u8(&err, dev, OPAL_STARTLIST); | ||
1866 | |||
1867 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1868 | add_token_u8(&err, dev, 3); /* Start Column */ | ||
1869 | add_token_u8(&err, dev, 3); /* PIN */ | ||
1870 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1871 | |||
1872 | add_token_u8(&err, dev, OPAL_STARTNAME); | ||
1873 | add_token_u8(&err, dev, 4); /* End Column */ | ||
1874 | add_token_u8(&err, dev, 3); /* Lifecycle Column */ | ||
1875 | add_token_u8(&err, dev, OPAL_ENDNAME); | ||
1876 | |||
1877 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1878 | add_token_u8(&err, dev, OPAL_ENDLIST); | ||
1879 | |||
1880 | if (err) { | ||
1881 | pr_err("Error building Get MSID CPIN PIN command.\n"); | ||
1882 | return err; | ||
1883 | } | ||
1884 | |||
1885 | return finalize_and_send(dev, get_msid_cpin_pin_cont); | ||
1886 | } | ||
1887 | |||
1888 | static int build_end_opal_session(struct opal_dev *dev) | ||
1889 | { | ||
1890 | int err = 0; | ||
1891 | |||
1892 | clear_opal_cmd(dev); | ||
1893 | |||
1894 | set_comid(dev, dev->comid); | ||
1895 | add_token_u8(&err, dev, OPAL_ENDOFSESSION); | ||
1896 | return err; | ||
1897 | } | ||
1898 | |||
1899 | static int end_opal_session(struct opal_dev *dev) | ||
1900 | { | ||
1901 | int ret = build_end_opal_session(dev); | ||
1902 | |||
1903 | if (ret < 0) | ||
1904 | return ret; | ||
1905 | return finalize_and_send(dev, end_session_cont); | ||
1906 | } | ||
1907 | |||
1908 | static int end_opal_session_error(struct opal_dev *dev) | ||
1909 | { | ||
1910 | const opal_step error_end_session[] = { | ||
1911 | end_opal_session, | ||
1912 | NULL, | ||
1913 | }; | ||
1914 | dev->funcs = error_end_session; | ||
1915 | dev->state = 0; | ||
1916 | return next(dev); | ||
1917 | } | ||
1918 | |||
1919 | static inline void setup_opal_dev(struct opal_dev *dev, | ||
1920 | const opal_step *funcs) | ||
1921 | { | ||
1922 | dev->state = 0; | ||
1923 | dev->funcs = funcs; | ||
1924 | dev->tsn = 0; | ||
1925 | dev->hsn = 0; | ||
1926 | dev->func_data = NULL; | ||
1927 | dev->prev_data = NULL; | ||
1928 | } | ||
1929 | |||
1930 | static int check_opal_support(struct opal_dev *dev) | ||
1931 | { | ||
1932 | static const opal_step funcs[] = { | ||
1933 | opal_discovery0, | ||
1934 | NULL | ||
1935 | }; | ||
1936 | int ret; | ||
1937 | |||
1938 | mutex_lock(&dev->dev_lock); | ||
1939 | setup_opal_dev(dev, funcs); | ||
1940 | ret = next(dev); | ||
1941 | dev->supported = !ret; | ||
1942 | mutex_unlock(&dev->dev_lock); | ||
1943 | return ret; | ||
1944 | } | ||
1945 | |||
1946 | void init_opal_dev(struct opal_dev *opal_dev, sec_send_recv *send_recv) | ||
1947 | { | ||
1948 | if (opal_dev->initialized) | ||
1949 | return; | ||
1950 | INIT_LIST_HEAD(&opal_dev->unlk_lst); | ||
1951 | mutex_init(&opal_dev->dev_lock); | ||
1952 | opal_dev->send_recv = send_recv; | ||
1953 | if (check_opal_support(opal_dev) < 0) | ||
1954 | pr_warn("Opal is not supported on this device\n"); | ||
1955 | opal_dev->initialized = true; | ||
1956 | } | ||
1957 | EXPORT_SYMBOL(init_opal_dev); | ||
1958 | |||
1959 | static int opal_secure_erase_locking_range(struct opal_dev *dev, | ||
1960 | struct opal_session_info *opal_session) | ||
1961 | { | ||
1962 | void *data[3] = { NULL }; | ||
1963 | static const opal_step erase_funcs[] = { | ||
1964 | opal_discovery0, | ||
1965 | start_auth_opal_session, | ||
1966 | get_active_key, | ||
1967 | gen_key, | ||
1968 | end_opal_session, | ||
1969 | NULL, | ||
1970 | }; | ||
1971 | int ret; | ||
1972 | |||
1973 | mutex_lock(&dev->dev_lock); | ||
1974 | setup_opal_dev(dev, erase_funcs); | ||
1975 | |||
1976 | dev->func_data = data; | ||
1977 | dev->func_data[1] = opal_session; | ||
1978 | dev->func_data[2] = &opal_session->opal_key.lr; | ||
1979 | |||
1980 | ret = next(dev); | ||
1981 | mutex_unlock(&dev->dev_lock); | ||
1982 | return ret; | ||
1983 | } | ||
1984 | |||
1985 | static int opal_erase_locking_range(struct opal_dev *dev, | ||
1986 | struct opal_session_info *opal_session) | ||
1987 | { | ||
1988 | void *data[3] = { NULL }; | ||
1989 | static const opal_step erase_funcs[] = { | ||
1990 | opal_discovery0, | ||
1991 | start_auth_opal_session, | ||
1992 | erase_locking_range, | ||
1993 | end_opal_session, | ||
1994 | NULL, | ||
1995 | }; | ||
1996 | int ret; | ||
1997 | |||
1998 | mutex_lock(&dev->dev_lock); | ||
1999 | setup_opal_dev(dev, erase_funcs); | ||
2000 | |||
2001 | dev->func_data = data; | ||
2002 | dev->func_data[1] = opal_session; | ||
2003 | dev->func_data[2] = opal_session; | ||
2004 | |||
2005 | ret = next(dev); | ||
2006 | mutex_unlock(&dev->dev_lock); | ||
2007 | return ret; | ||
2008 | } | ||
2009 | |||
2010 | static int opal_enable_disable_shadow_mbr(struct opal_dev *dev, | ||
2011 | struct opal_mbr_data *opal_mbr) | ||
2012 | { | ||
2013 | void *func_data[6] = { NULL }; | ||
2014 | static const opal_step mbr_funcs[] = { | ||
2015 | opal_discovery0, | ||
2016 | start_admin1LSP_opal_session, | ||
2017 | set_mbr_done, | ||
2018 | end_opal_session, | ||
2019 | start_admin1LSP_opal_session, | ||
2020 | set_mbr_enable_disable, | ||
2021 | end_opal_session, | ||
2022 | NULL, | ||
2023 | }; | ||
2024 | int ret; | ||
2025 | |||
2026 | if (opal_mbr->enable_disable != OPAL_MBR_ENABLE && | ||
2027 | opal_mbr->enable_disable != OPAL_MBR_DISABLE) | ||
2028 | return -EINVAL; | ||
2029 | |||
2030 | mutex_lock(&dev->dev_lock); | ||
2031 | setup_opal_dev(dev, mbr_funcs); | ||
2032 | dev->func_data = func_data; | ||
2033 | dev->func_data[1] = &opal_mbr->key; | ||
2034 | dev->func_data[2] = &opal_mbr->enable_disable; | ||
2035 | dev->func_data[4] = &opal_mbr->key; | ||
2036 | dev->func_data[5] = &opal_mbr->enable_disable; | ||
2037 | ret = next(dev); | ||
2038 | mutex_unlock(&dev->dev_lock); | ||
2039 | return ret; | ||
2040 | } | ||
2041 | |||
2042 | static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk) | ||
2043 | { | ||
2044 | struct opal_suspend_data *suspend; | ||
2045 | |||
2046 | suspend = kzalloc(sizeof(*suspend), GFP_KERNEL); | ||
2047 | if (!suspend) | ||
2048 | return -ENOMEM; | ||
2049 | |||
2050 | suspend->unlk = *lk_unlk; | ||
2051 | suspend->lr = lk_unlk->session.opal_key.lr; | ||
2052 | |||
2053 | mutex_lock(&dev->dev_lock); | ||
2054 | setup_opal_dev(dev, NULL); | ||
2055 | add_suspend_info(dev, suspend); | ||
2056 | mutex_unlock(&dev->dev_lock); | ||
2057 | return 0; | ||
2058 | } | ||
2059 | |||
2060 | static int opal_add_user_to_lr(struct opal_dev *dev, | ||
2061 | struct opal_lock_unlock *lk_unlk) | ||
2062 | { | ||
2063 | void *func_data[3] = { NULL }; | ||
2064 | static const opal_step funcs[] = { | ||
2065 | opal_discovery0, | ||
2066 | start_admin1LSP_opal_session, | ||
2067 | add_user_to_lr, | ||
2068 | end_opal_session, | ||
2069 | NULL | ||
2070 | }; | ||
2071 | int ret; | ||
2072 | |||
2073 | if (lk_unlk->l_state != OPAL_RO && | ||
2074 | lk_unlk->l_state != OPAL_RW) { | ||
2075 | pr_err("Locking state was not RO or RW\n"); | ||
2076 | return -EINVAL; | ||
2077 | } | ||
2078 | if (lk_unlk->session.who < OPAL_USER1 && | ||
2079 | lk_unlk->session.who > OPAL_USER9) { | ||
2080 | pr_err("Authority was not within the range of users: %d\n", | ||
2081 | lk_unlk->session.who); | ||
2082 | return -EINVAL; | ||
2083 | } | ||
2084 | if (lk_unlk->session.sum) { | ||
2085 | pr_err("%s not supported in sum. Use setup locking range\n", | ||
2086 | __func__); | ||
2087 | return -EINVAL; | ||
2088 | } | ||
2089 | |||
2090 | mutex_lock(&dev->dev_lock); | ||
2091 | setup_opal_dev(dev, funcs); | ||
2092 | dev->func_data = func_data; | ||
2093 | dev->func_data[1] = &lk_unlk->session.opal_key; | ||
2094 | dev->func_data[2] = lk_unlk; | ||
2095 | ret = next(dev); | ||
2096 | mutex_unlock(&dev->dev_lock); | ||
2097 | return ret; | ||
2098 | } | ||
2099 | |||
2100 | static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal) | ||
2101 | { | ||
2102 | void *data[2] = { NULL }; | ||
2103 | static const opal_step revert_funcs[] = { | ||
2104 | opal_discovery0, | ||
2105 | start_SIDASP_opal_session, | ||
2106 | revert_tper, /* controller will terminate session */ | ||
2107 | NULL, | ||
2108 | }; | ||
2109 | int ret; | ||
2110 | |||
2111 | mutex_lock(&dev->dev_lock); | ||
2112 | setup_opal_dev(dev, revert_funcs); | ||
2113 | dev->func_data = data; | ||
2114 | dev->func_data[1] = opal; | ||
2115 | ret = next(dev); | ||
2116 | mutex_unlock(&dev->dev_lock); | ||
2117 | return ret; | ||
2118 | } | ||
2119 | |||
2120 | static int __opal_lock_unlock_sum(struct opal_dev *dev) | ||
2121 | { | ||
2122 | static const opal_step ulk_funcs_sum[] = { | ||
2123 | opal_discovery0, | ||
2124 | start_auth_opal_session, | ||
2125 | lock_unlock_locking_range_sum, | ||
2126 | end_opal_session, | ||
2127 | NULL | ||
2128 | }; | ||
2129 | |||
2130 | dev->funcs = ulk_funcs_sum; | ||
2131 | return next(dev); | ||
2132 | } | ||
2133 | |||
2134 | static int __opal_lock_unlock(struct opal_dev *dev) | ||
2135 | { | ||
2136 | static const opal_step _unlock_funcs[] = { | ||
2137 | opal_discovery0, | ||
2138 | start_auth_opal_session, | ||
2139 | lock_unlock_locking_range, | ||
2140 | end_opal_session, | ||
2141 | NULL | ||
2142 | }; | ||
2143 | |||
2144 | dev->funcs = _unlock_funcs; | ||
2145 | return next(dev); | ||
2146 | } | ||
2147 | |||
2148 | static int opal_lock_unlock(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk) | ||
2149 | { | ||
2150 | void *func_data[3] = { NULL }; | ||
2151 | int ret; | ||
2152 | |||
2153 | if (lk_unlk->session.who < OPAL_ADMIN1 || | ||
2154 | lk_unlk->session.who > OPAL_USER9) | ||
2155 | return -EINVAL; | ||
2156 | |||
2157 | mutex_lock(&dev->dev_lock); | ||
2158 | setup_opal_dev(dev, NULL); | ||
2159 | dev->func_data = func_data; | ||
2160 | dev->func_data[1] = &lk_unlk->session; | ||
2161 | dev->func_data[2] = lk_unlk; | ||
2162 | |||
2163 | if (lk_unlk->session.sum) | ||
2164 | ret = __opal_lock_unlock_sum(dev); | ||
2165 | else | ||
2166 | ret = __opal_lock_unlock(dev); | ||
2167 | |||
2168 | mutex_unlock(&dev->dev_lock); | ||
2169 | return ret; | ||
2170 | } | ||
2171 | |||
2172 | static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal) | ||
2173 | { | ||
2174 | static const opal_step owner_funcs[] = { | ||
2175 | opal_discovery0, | ||
2176 | start_anybodyASP_opal_session, | ||
2177 | get_msid_cpin_pin, | ||
2178 | end_opal_session, | ||
2179 | start_SIDASP_opal_session, | ||
2180 | set_sid_cpin_pin, | ||
2181 | end_opal_session, | ||
2182 | NULL | ||
2183 | }; | ||
2184 | void *data[6] = { NULL }; | ||
2185 | int ret; | ||
2186 | |||
2187 | if (!dev) | ||
2188 | return -ENODEV; | ||
2189 | |||
2190 | mutex_lock(&dev->dev_lock); | ||
2191 | setup_opal_dev(dev, owner_funcs); | ||
2192 | dev->func_data = data; | ||
2193 | dev->func_data[4] = opal; | ||
2194 | dev->func_data[5] = opal; | ||
2195 | ret = next(dev); | ||
2196 | mutex_unlock(&dev->dev_lock); | ||
2197 | return ret; | ||
2198 | } | ||
2199 | |||
2200 | static int opal_activate_lsp(struct opal_dev *dev, struct opal_lr_act *opal_lr_act) | ||
2201 | { | ||
2202 | void *data[4] = { NULL }; | ||
2203 | static const opal_step active_funcs[] = { | ||
2204 | opal_discovery0, | ||
2205 | start_SIDASP_opal_session, /* Open session as SID auth */ | ||
2206 | get_lsp_lifecycle, | ||
2207 | activate_lsp, | ||
2208 | end_opal_session, | ||
2209 | NULL | ||
2210 | }; | ||
2211 | int ret; | ||
2212 | |||
2213 | if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS) | ||
2214 | return -EINVAL; | ||
2215 | |||
2216 | mutex_lock(&dev->dev_lock); | ||
2217 | setup_opal_dev(dev, active_funcs); | ||
2218 | dev->func_data = data; | ||
2219 | dev->func_data[1] = &opal_lr_act->key; | ||
2220 | dev->func_data[3] = opal_lr_act; | ||
2221 | ret = next(dev); | ||
2222 | mutex_unlock(&dev->dev_lock); | ||
2223 | return ret; | ||
2224 | } | ||
2225 | |||
2226 | static int opal_setup_locking_range(struct opal_dev *dev, | ||
2227 | struct opal_user_lr_setup *opal_lrs) | ||
2228 | { | ||
2229 | void *data[3] = { NULL }; | ||
2230 | static const opal_step lr_funcs[] = { | ||
2231 | opal_discovery0, | ||
2232 | start_auth_opal_session, | ||
2233 | setup_locking_range, | ||
2234 | end_opal_session, | ||
2235 | NULL, | ||
2236 | }; | ||
2237 | int ret; | ||
2238 | |||
2239 | mutex_lock(&dev->dev_lock); | ||
2240 | setup_opal_dev(dev, lr_funcs); | ||
2241 | dev->func_data = data; | ||
2242 | dev->func_data[1] = &opal_lrs->session; | ||
2243 | dev->func_data[2] = opal_lrs; | ||
2244 | ret = next(dev); | ||
2245 | mutex_unlock(&dev->dev_lock); | ||
2246 | return ret; | ||
2247 | } | ||
2248 | |||
2249 | static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw) | ||
2250 | { | ||
2251 | static const opal_step pw_funcs[] = { | ||
2252 | opal_discovery0, | ||
2253 | start_auth_opal_session, | ||
2254 | set_new_pw, | ||
2255 | end_opal_session, | ||
2256 | NULL | ||
2257 | }; | ||
2258 | void *data[3] = { NULL }; | ||
2259 | int ret; | ||
2260 | |||
2261 | if (opal_pw->session.who < OPAL_ADMIN1 || | ||
2262 | opal_pw->session.who > OPAL_USER9 || | ||
2263 | opal_pw->new_user_pw.who < OPAL_ADMIN1 || | ||
2264 | opal_pw->new_user_pw.who > OPAL_USER9) | ||
2265 | return -EINVAL; | ||
2266 | |||
2267 | mutex_lock(&dev->dev_lock); | ||
2268 | setup_opal_dev(dev, pw_funcs); | ||
2269 | dev->func_data = data; | ||
2270 | dev->func_data[1] = (void *) &opal_pw->session; | ||
2271 | dev->func_data[2] = (void *) &opal_pw->new_user_pw; | ||
2272 | |||
2273 | ret = next(dev); | ||
2274 | mutex_unlock(&dev->dev_lock); | ||
2275 | return ret; | ||
2276 | } | ||
2277 | |||
2278 | static int opal_activate_user(struct opal_dev *dev, | ||
2279 | struct opal_session_info *opal_session) | ||
2280 | { | ||
2281 | static const opal_step act_funcs[] = { | ||
2282 | opal_discovery0, | ||
2283 | start_admin1LSP_opal_session, | ||
2284 | internal_activate_user, | ||
2285 | end_opal_session, | ||
2286 | NULL | ||
2287 | }; | ||
2288 | void *data[3] = { NULL }; | ||
2289 | int ret; | ||
2290 | |||
2291 | /* We can't activate Admin1 it's active as manufactured */ | ||
2292 | if (opal_session->who < OPAL_USER1 && | ||
2293 | opal_session->who > OPAL_USER9) { | ||
2294 | pr_err("Who was not a valid user: %d\n", opal_session->who); | ||
2295 | return -EINVAL; | ||
2296 | } | ||
2297 | |||
2298 | mutex_lock(&dev->dev_lock); | ||
2299 | setup_opal_dev(dev, act_funcs); | ||
2300 | dev->func_data = data; | ||
2301 | dev->func_data[1] = &opal_session->opal_key; | ||
2302 | dev->func_data[2] = opal_session; | ||
2303 | ret = next(dev); | ||
2304 | mutex_unlock(&dev->dev_lock); | ||
2305 | return ret; | ||
2306 | } | ||
2307 | |||
2308 | bool opal_unlock_from_suspend(struct opal_dev *dev) | ||
2309 | { | ||
2310 | struct opal_suspend_data *suspend; | ||
2311 | void *func_data[3] = { NULL }; | ||
2312 | bool was_failure = false; | ||
2313 | int ret = 0; | ||
2314 | |||
2315 | if (!dev) | ||
2316 | return false; | ||
2317 | if (!dev->supported) | ||
2318 | return false; | ||
2319 | |||
2320 | mutex_lock(&dev->dev_lock); | ||
2321 | setup_opal_dev(dev, NULL); | ||
2322 | dev->func_data = func_data; | ||
2323 | |||
2324 | list_for_each_entry(suspend, &dev->unlk_lst, node) { | ||
2325 | dev->state = 0; | ||
2326 | dev->func_data[1] = &suspend->unlk.session; | ||
2327 | dev->func_data[2] = &suspend->unlk; | ||
2328 | dev->tsn = 0; | ||
2329 | dev->hsn = 0; | ||
2330 | |||
2331 | if (suspend->unlk.session.sum) | ||
2332 | ret = __opal_lock_unlock_sum(dev); | ||
2333 | else | ||
2334 | ret = __opal_lock_unlock(dev); | ||
2335 | if (ret) { | ||
2336 | pr_warn("Failed to unlock LR %hhu with sum %d\n", | ||
2337 | suspend->unlk.session.opal_key.lr, | ||
2338 | suspend->unlk.session.sum); | ||
2339 | was_failure = true; | ||
2340 | } | ||
2341 | } | ||
2342 | mutex_unlock(&dev->dev_lock); | ||
2343 | return was_failure; | ||
2344 | } | ||
2345 | EXPORT_SYMBOL(opal_unlock_from_suspend); | ||
2346 | |||
2347 | int sed_ioctl(struct opal_dev *dev, unsigned int cmd, unsigned long ptr) | ||
2348 | { | ||
2349 | void __user *arg = (void __user *)ptr; | ||
2350 | |||
2351 | if (!capable(CAP_SYS_ADMIN)) | ||
2352 | return -EACCES; | ||
2353 | if (!dev->supported) { | ||
2354 | pr_err("Not supported\n"); | ||
2355 | return -ENOTSUPP; | ||
2356 | } | ||
2357 | |||
2358 | switch (cmd) { | ||
2359 | case IOC_OPAL_SAVE: { | ||
2360 | struct opal_lock_unlock lk_unlk; | ||
2361 | |||
2362 | if (copy_from_user(&lk_unlk, arg, sizeof(lk_unlk))) | ||
2363 | return -EFAULT; | ||
2364 | return opal_save(dev, &lk_unlk); | ||
2365 | } | ||
2366 | case IOC_OPAL_LOCK_UNLOCK: { | ||
2367 | struct opal_lock_unlock lk_unlk; | ||
2368 | |||
2369 | if (copy_from_user(&lk_unlk, arg, sizeof(lk_unlk))) | ||
2370 | return -EFAULT; | ||
2371 | return opal_lock_unlock(dev, &lk_unlk); | ||
2372 | } | ||
2373 | case IOC_OPAL_TAKE_OWNERSHIP: { | ||
2374 | struct opal_key opal_key; | ||
2375 | |||
2376 | if (copy_from_user(&opal_key, arg, sizeof(opal_key))) | ||
2377 | return -EFAULT; | ||
2378 | return opal_take_ownership(dev, &opal_key); | ||
2379 | } | ||
2380 | case IOC_OPAL_ACTIVATE_LSP: { | ||
2381 | struct opal_lr_act opal_lr_act; | ||
2382 | |||
2383 | if (copy_from_user(&opal_lr_act, arg, sizeof(opal_lr_act))) | ||
2384 | return -EFAULT; | ||
2385 | return opal_activate_lsp(dev, &opal_lr_act); | ||
2386 | } | ||
2387 | case IOC_OPAL_SET_PW: { | ||
2388 | struct opal_new_pw opal_pw; | ||
2389 | |||
2390 | if (copy_from_user(&opal_pw, arg, sizeof(opal_pw))) | ||
2391 | return -EFAULT; | ||
2392 | return opal_set_new_pw(dev, &opal_pw); | ||
2393 | } | ||
2394 | case IOC_OPAL_ACTIVATE_USR: { | ||
2395 | struct opal_session_info session; | ||
2396 | |||
2397 | if (copy_from_user(&session, arg, sizeof(session))) | ||
2398 | return -EFAULT; | ||
2399 | return opal_activate_user(dev, &session); | ||
2400 | } | ||
2401 | case IOC_OPAL_REVERT_TPR: { | ||
2402 | struct opal_key opal_key; | ||
2403 | |||
2404 | if (copy_from_user(&opal_key, arg, sizeof(opal_key))) | ||
2405 | return -EFAULT; | ||
2406 | return opal_reverttper(dev, &opal_key); | ||
2407 | } | ||
2408 | case IOC_OPAL_LR_SETUP: { | ||
2409 | struct opal_user_lr_setup lrs; | ||
2410 | |||
2411 | if (copy_from_user(&lrs, arg, sizeof(lrs))) | ||
2412 | return -EFAULT; | ||
2413 | return opal_setup_locking_range(dev, &lrs); | ||
2414 | } | ||
2415 | case IOC_OPAL_ADD_USR_TO_LR: { | ||
2416 | struct opal_lock_unlock lk_unlk; | ||
2417 | |||
2418 | if (copy_from_user(&lk_unlk, arg, sizeof(lk_unlk))) | ||
2419 | return -EFAULT; | ||
2420 | return opal_add_user_to_lr(dev, &lk_unlk); | ||
2421 | } | ||
2422 | case IOC_OPAL_ENABLE_DISABLE_MBR: { | ||
2423 | struct opal_mbr_data mbr; | ||
2424 | |||
2425 | if (copy_from_user(&mbr, arg, sizeof(mbr))) | ||
2426 | return -EFAULT; | ||
2427 | return opal_enable_disable_shadow_mbr(dev, &mbr); | ||
2428 | } | ||
2429 | case IOC_OPAL_ERASE_LR: { | ||
2430 | struct opal_session_info session; | ||
2431 | |||
2432 | if (copy_from_user(&session, arg, sizeof(session))) | ||
2433 | return -EFAULT; | ||
2434 | return opal_erase_locking_range(dev, &session); | ||
2435 | } | ||
2436 | case IOC_OPAL_SECURE_ERASE_LR: { | ||
2437 | struct opal_session_info session; | ||
2438 | |||
2439 | if (copy_from_user(&session, arg, sizeof(session))) | ||
2440 | return -EFAULT; | ||
2441 | return opal_secure_erase_locking_range(dev, &session); | ||
2442 | } | ||
2443 | default: | ||
2444 | pr_warn("No such Opal Ioctl %u\n", cmd); | ||
2445 | } | ||
2446 | return -ENOTTY; | ||
2447 | } | ||
2448 | EXPORT_SYMBOL_GPL(sed_ioctl); | ||
diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h new file mode 100644 index 000000000000..af1a85eae193 --- /dev/null +++ b/include/linux/sed-opal.h | |||
@@ -0,0 +1,178 @@ | |||
1 | /* | ||
2 | * Copyright © 2016 Intel Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Rafael Antognolli <rafael.antognolli@intel.com> | ||
6 | * Scott Bauer <scott.bauer@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | */ | ||
17 | |||
18 | #ifndef LINUX_OPAL_H | ||
19 | #define LINUX_OPAL_H | ||
20 | |||
21 | #include <uapi/linux/sed-opal.h> | ||
22 | #include <linux/kernel.h> | ||
23 | |||
24 | /* | ||
25 | * These constant values come from: | ||
26 | * SPC-4 section | ||
27 | * 6.30 SECURITY PROTOCOL IN command / table 265. | ||
28 | */ | ||
29 | enum { | ||
30 | TCG_SECP_00 = 0, | ||
31 | TCG_SECP_01, | ||
32 | }; | ||
33 | struct opal_dev; | ||
34 | |||
35 | #define IO_BUFFER_LENGTH 2048 | ||
36 | #define MAX_TOKS 64 | ||
37 | |||
38 | typedef int (*opal_step)(struct opal_dev *dev); | ||
39 | typedef int (sec_send_recv)(struct opal_dev *ctx, u16 spsp, u8 secp, | ||
40 | void *buffer, size_t len, bool send); | ||
41 | |||
42 | |||
43 | enum opal_atom_width { | ||
44 | OPAL_WIDTH_TINY, | ||
45 | OPAL_WIDTH_SHORT, | ||
46 | OPAL_WIDTH_MEDIUM, | ||
47 | OPAL_WIDTH_LONG, | ||
48 | OPAL_WIDTH_TOKEN | ||
49 | }; | ||
50 | |||
51 | /* | ||
52 | * Token defs derived from: | ||
53 | * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 | ||
54 | * 3.2.2 Data Stream Encoding | ||
55 | */ | ||
56 | enum opal_response_token { | ||
57 | OPAL_DTA_TOKENID_BYTESTRING = 0xe0, | ||
58 | OPAL_DTA_TOKENID_SINT = 0xe1, | ||
59 | OPAL_DTA_TOKENID_UINT = 0xe2, | ||
60 | OPAL_DTA_TOKENID_TOKEN = 0xe3, /* actual token is returned */ | ||
61 | OPAL_DTA_TOKENID_INVALID = 0X0 | ||
62 | }; | ||
63 | |||
64 | /* | ||
65 | * On the parsed response, we don't store again the toks that are already | ||
66 | * stored in the response buffer. Instead, for each token, we just store a | ||
67 | * pointer to the position in the buffer where the token starts, and the size | ||
68 | * of the token in bytes. | ||
69 | */ | ||
70 | struct opal_resp_tok { | ||
71 | const u8 *pos; | ||
72 | size_t len; | ||
73 | enum opal_response_token type; | ||
74 | enum opal_atom_width width; | ||
75 | union { | ||
76 | u64 u; | ||
77 | s64 s; | ||
78 | } stored; | ||
79 | }; | ||
80 | |||
81 | /* | ||
82 | * From the response header it's not possible to know how many tokens there are | ||
83 | * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later | ||
84 | * if we start dealing with messages that have more than that, we can increase | ||
85 | * this number. This is done to avoid having to make two passes through the | ||
86 | * response, the first one counting how many tokens we have and the second one | ||
87 | * actually storing the positions. | ||
88 | */ | ||
89 | struct parsed_resp { | ||
90 | int num; | ||
91 | struct opal_resp_tok toks[MAX_TOKS]; | ||
92 | }; | ||
93 | |||
94 | /** | ||
95 | * struct opal_dev - The structure representing a OPAL enabled SED. | ||
96 | * @supported: Whether or not OPAL is supported on this controller. | ||
97 | * @send_recv: The combined sec_send/sec_recv function pointer. | ||
98 | * @opal_step: A series of opal methods that are necessary to complete a command. | ||
99 | * @func_data: An array of parameters for the opal methods above. | ||
100 | * @state: Describes the current opal_step we're working on. | ||
101 | * @dev_lock: Locks the entire opal_dev structure. | ||
102 | * @parsed: Parsed response from controller. | ||
103 | * @prev_data: Data returned from a method to the controller. | ||
104 | * @unlk_lst: A list of Locking ranges to unlock on this device during a resume. | ||
105 | */ | ||
106 | struct opal_dev { | ||
107 | bool initialized; | ||
108 | bool supported; | ||
109 | sec_send_recv *send_recv; | ||
110 | |||
111 | const opal_step *funcs; | ||
112 | void **func_data; | ||
113 | int state; | ||
114 | struct mutex dev_lock; | ||
115 | u16 comid; | ||
116 | u32 hsn; | ||
117 | u32 tsn; | ||
118 | u64 align; | ||
119 | u64 lowest_lba; | ||
120 | |||
121 | size_t pos; | ||
122 | u8 cmd[IO_BUFFER_LENGTH]; | ||
123 | u8 resp[IO_BUFFER_LENGTH]; | ||
124 | |||
125 | struct parsed_resp parsed; | ||
126 | size_t prev_d_len; | ||
127 | void *prev_data; | ||
128 | |||
129 | struct list_head unlk_lst; | ||
130 | }; | ||
131 | |||
132 | #ifdef CONFIG_BLK_SED_OPAL | ||
133 | bool opal_unlock_from_suspend(struct opal_dev *dev); | ||
134 | void init_opal_dev(struct opal_dev *opal_dev, sec_send_recv *send_recv); | ||
135 | int sed_ioctl(struct opal_dev *dev, unsigned int cmd, unsigned long ptr); | ||
136 | |||
137 | static inline bool is_sed_ioctl(unsigned int cmd) | ||
138 | { | ||
139 | switch (cmd) { | ||
140 | case IOC_OPAL_SAVE: | ||
141 | case IOC_OPAL_LOCK_UNLOCK: | ||
142 | case IOC_OPAL_TAKE_OWNERSHIP: | ||
143 | case IOC_OPAL_ACTIVATE_LSP: | ||
144 | case IOC_OPAL_SET_PW: | ||
145 | case IOC_OPAL_ACTIVATE_USR: | ||
146 | case IOC_OPAL_REVERT_TPR: | ||
147 | case IOC_OPAL_LR_SETUP: | ||
148 | case IOC_OPAL_ADD_USR_TO_LR: | ||
149 | case IOC_OPAL_ENABLE_DISABLE_MBR: | ||
150 | case IOC_OPAL_ERASE_LR: | ||
151 | case IOC_OPAL_SECURE_ERASE_LR: | ||
152 | return true; | ||
153 | } | ||
154 | return false; | ||
155 | } | ||
156 | #else | ||
157 | static inline bool is_sed_ioctl(unsigned int cmd) | ||
158 | { | ||
159 | return false; | ||
160 | } | ||
161 | |||
162 | static inline int sed_ioctl(struct opal_dev *dev, unsigned int cmd, | ||
163 | unsigned long ptr) | ||
164 | { | ||
165 | return 0; | ||
166 | } | ||
167 | static inline bool opal_unlock_from_suspend(struct opal_dev *dev) | ||
168 | { | ||
169 | return false; | ||
170 | } | ||
171 | static inline void init_opal_dev(struct opal_dev *opal_dev, | ||
172 | sec_send_recv *send_recv) | ||
173 | { | ||
174 | opal_dev->supported = false; | ||
175 | opal_dev->initialized = true; | ||
176 | } | ||
177 | #endif /* CONFIG_BLK_SED_OPAL */ | ||
178 | #endif /* LINUX_OPAL_H */ | ||