1455a7b23SScott Bauer /* 2455a7b23SScott Bauer * Copyright © 2016 Intel Corporation 3455a7b23SScott Bauer * 4455a7b23SScott Bauer * Authors: 5455a7b23SScott Bauer * Scott Bauer <scott.bauer@intel.com> 6455a7b23SScott Bauer * Rafael Antognolli <rafael.antognolli@intel.com> 7455a7b23SScott Bauer * 8455a7b23SScott Bauer * This program is free software; you can redistribute it and/or modify it 9455a7b23SScott Bauer * under the terms and conditions of the GNU General Public License, 10455a7b23SScott Bauer * version 2, as published by the Free Software Foundation. 11455a7b23SScott Bauer * 12455a7b23SScott Bauer * This program is distributed in the hope it will be useful, but WITHOUT 13455a7b23SScott Bauer * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14455a7b23SScott Bauer * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15455a7b23SScott Bauer * more details. 16455a7b23SScott Bauer */ 17455a7b23SScott Bauer 18455a7b23SScott Bauer #define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt 19455a7b23SScott Bauer 20455a7b23SScott Bauer #include <linux/delay.h> 21455a7b23SScott Bauer #include <linux/device.h> 22455a7b23SScott Bauer #include <linux/kernel.h> 23455a7b23SScott Bauer #include <linux/list.h> 24455a7b23SScott Bauer #include <linux/genhd.h> 25455a7b23SScott Bauer #include <linux/slab.h> 26455a7b23SScott Bauer #include <linux/uaccess.h> 27455a7b23SScott Bauer #include <uapi/linux/sed-opal.h> 28455a7b23SScott Bauer #include <linux/sed-opal.h> 29455a7b23SScott Bauer #include <linux/string.h> 30455a7b23SScott Bauer #include <linux/kdev_t.h> 31455a7b23SScott Bauer 32455a7b23SScott Bauer #include "opal_proto.h" 33455a7b23SScott Bauer 344f1244c8SChristoph Hellwig #define IO_BUFFER_LENGTH 2048 354f1244c8SChristoph Hellwig #define MAX_TOKS 64 364f1244c8SChristoph Hellwig 37eed64951SJon Derrick struct opal_step { 38eed64951SJon Derrick int (*fn)(struct opal_dev *dev, void *data); 39eed64951SJon Derrick void *data; 40eed64951SJon Derrick }; 41eed64951SJon Derrick typedef int (cont_fn)(struct opal_dev *dev); 424f1244c8SChristoph Hellwig 434f1244c8SChristoph Hellwig enum opal_atom_width { 444f1244c8SChristoph Hellwig OPAL_WIDTH_TINY, 454f1244c8SChristoph Hellwig OPAL_WIDTH_SHORT, 464f1244c8SChristoph Hellwig OPAL_WIDTH_MEDIUM, 474f1244c8SChristoph Hellwig OPAL_WIDTH_LONG, 484f1244c8SChristoph Hellwig OPAL_WIDTH_TOKEN 494f1244c8SChristoph Hellwig }; 504f1244c8SChristoph Hellwig 514f1244c8SChristoph Hellwig /* 524f1244c8SChristoph Hellwig * On the parsed response, we don't store again the toks that are already 534f1244c8SChristoph Hellwig * stored in the response buffer. Instead, for each token, we just store a 544f1244c8SChristoph Hellwig * pointer to the position in the buffer where the token starts, and the size 554f1244c8SChristoph Hellwig * of the token in bytes. 564f1244c8SChristoph Hellwig */ 574f1244c8SChristoph Hellwig struct opal_resp_tok { 584f1244c8SChristoph Hellwig const u8 *pos; 594f1244c8SChristoph Hellwig size_t len; 604f1244c8SChristoph Hellwig enum opal_response_token type; 614f1244c8SChristoph Hellwig enum opal_atom_width width; 624f1244c8SChristoph Hellwig union { 634f1244c8SChristoph Hellwig u64 u; 644f1244c8SChristoph Hellwig s64 s; 654f1244c8SChristoph Hellwig } stored; 664f1244c8SChristoph Hellwig }; 674f1244c8SChristoph Hellwig 684f1244c8SChristoph Hellwig /* 694f1244c8SChristoph Hellwig * From the response header it's not possible to know how many tokens there are 704f1244c8SChristoph Hellwig * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later 714f1244c8SChristoph Hellwig * if we start dealing with messages that have more than that, we can increase 724f1244c8SChristoph Hellwig * this number. This is done to avoid having to make two passes through the 734f1244c8SChristoph Hellwig * response, the first one counting how many tokens we have and the second one 744f1244c8SChristoph Hellwig * actually storing the positions. 754f1244c8SChristoph Hellwig */ 764f1244c8SChristoph Hellwig struct parsed_resp { 774f1244c8SChristoph Hellwig int num; 784f1244c8SChristoph Hellwig struct opal_resp_tok toks[MAX_TOKS]; 794f1244c8SChristoph Hellwig }; 804f1244c8SChristoph Hellwig 814f1244c8SChristoph Hellwig struct opal_dev { 824f1244c8SChristoph Hellwig bool supported; 83dbec491bSScott Bauer bool mbr_enabled; 844f1244c8SChristoph Hellwig 854f1244c8SChristoph Hellwig void *data; 864f1244c8SChristoph Hellwig sec_send_recv *send_recv; 874f1244c8SChristoph Hellwig 88eed64951SJon Derrick const struct opal_step *steps; 894f1244c8SChristoph Hellwig struct mutex dev_lock; 904f1244c8SChristoph Hellwig u16 comid; 914f1244c8SChristoph Hellwig u32 hsn; 924f1244c8SChristoph Hellwig u32 tsn; 934f1244c8SChristoph Hellwig u64 align; 944f1244c8SChristoph Hellwig u64 lowest_lba; 954f1244c8SChristoph Hellwig 964f1244c8SChristoph Hellwig size_t pos; 974f1244c8SChristoph Hellwig u8 cmd[IO_BUFFER_LENGTH]; 984f1244c8SChristoph Hellwig u8 resp[IO_BUFFER_LENGTH]; 994f1244c8SChristoph Hellwig 1004f1244c8SChristoph Hellwig struct parsed_resp parsed; 1014f1244c8SChristoph Hellwig size_t prev_d_len; 1024f1244c8SChristoph Hellwig void *prev_data; 1034f1244c8SChristoph Hellwig 1044f1244c8SChristoph Hellwig struct list_head unlk_lst; 1054f1244c8SChristoph Hellwig }; 1064f1244c8SChristoph Hellwig 1074f1244c8SChristoph Hellwig 108455a7b23SScott Bauer static const u8 opaluid[][OPAL_UID_LENGTH] = { 109455a7b23SScott Bauer /* users */ 110455a7b23SScott Bauer [OPAL_SMUID_UID] = 111455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff }, 112455a7b23SScott Bauer [OPAL_THISSP_UID] = 113455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, 114455a7b23SScott Bauer [OPAL_ADMINSP_UID] = 115455a7b23SScott Bauer { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 }, 116455a7b23SScott Bauer [OPAL_LOCKINGSP_UID] = 117455a7b23SScott Bauer { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 }, 118455a7b23SScott Bauer [OPAL_ENTERPRISE_LOCKINGSP_UID] = 119455a7b23SScott Bauer { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 }, 120455a7b23SScott Bauer [OPAL_ANYBODY_UID] = 121455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 }, 122455a7b23SScott Bauer [OPAL_SID_UID] = 123455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 }, 124455a7b23SScott Bauer [OPAL_ADMIN1_UID] = 125455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 }, 126455a7b23SScott Bauer [OPAL_USER1_UID] = 127455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 }, 128455a7b23SScott Bauer [OPAL_USER2_UID] = 129455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 }, 130455a7b23SScott Bauer [OPAL_PSID_UID] = 131455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 }, 132455a7b23SScott Bauer [OPAL_ENTERPRISE_BANDMASTER0_UID] = 133455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 }, 134455a7b23SScott Bauer [OPAL_ENTERPRISE_ERASEMASTER_UID] = 135455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 }, 136455a7b23SScott Bauer 137455a7b23SScott Bauer /* tables */ 138455a7b23SScott Bauer 139455a7b23SScott Bauer [OPAL_LOCKINGRANGE_GLOBAL] = 140455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 }, 141455a7b23SScott Bauer [OPAL_LOCKINGRANGE_ACE_RDLOCKED] = 142455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 }, 143455a7b23SScott Bauer [OPAL_LOCKINGRANGE_ACE_WRLOCKED] = 144455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 }, 145455a7b23SScott Bauer [OPAL_MBRCONTROL] = 146455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 }, 147455a7b23SScott Bauer [OPAL_MBR] = 148455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 }, 149455a7b23SScott Bauer [OPAL_AUTHORITY_TABLE] = 150455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00}, 151455a7b23SScott Bauer [OPAL_C_PIN_TABLE] = 152455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00}, 153455a7b23SScott Bauer [OPAL_LOCKING_INFO_TABLE] = 154455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 }, 155455a7b23SScott Bauer [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] = 156455a7b23SScott Bauer { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 }, 157455a7b23SScott Bauer 158455a7b23SScott Bauer /* C_PIN_TABLE object ID's */ 159455a7b23SScott Bauer 160455a7b23SScott Bauer [OPAL_C_PIN_MSID] = 161455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02}, 162455a7b23SScott Bauer [OPAL_C_PIN_SID] = 163455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01}, 164455a7b23SScott Bauer [OPAL_C_PIN_ADMIN1] = 165455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01}, 166455a7b23SScott Bauer 167455a7b23SScott Bauer /* half UID's (only first 4 bytes used) */ 168455a7b23SScott Bauer 169455a7b23SScott Bauer [OPAL_HALF_UID_AUTHORITY_OBJ_REF] = 170455a7b23SScott Bauer { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff }, 171455a7b23SScott Bauer [OPAL_HALF_UID_BOOLEAN_ACE] = 172455a7b23SScott Bauer { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff }, 173455a7b23SScott Bauer 174455a7b23SScott Bauer /* special value for omitted optional parameter */ 175455a7b23SScott Bauer [OPAL_UID_HEXFF] = 176455a7b23SScott Bauer { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 177455a7b23SScott Bauer }; 178455a7b23SScott Bauer 179455a7b23SScott Bauer /* 180455a7b23SScott Bauer * TCG Storage SSC Methods. 181455a7b23SScott Bauer * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 182455a7b23SScott Bauer * Section: 6.3 Assigned UIDs 183455a7b23SScott Bauer */ 1841b6b75b0SJonas Rabenstein static const u8 opalmethod[][OPAL_METHOD_LENGTH] = { 185455a7b23SScott Bauer [OPAL_PROPERTIES] = 186455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 }, 187455a7b23SScott Bauer [OPAL_STARTSESSION] = 188455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 }, 189455a7b23SScott Bauer [OPAL_REVERT] = 190455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 }, 191455a7b23SScott Bauer [OPAL_ACTIVATE] = 192455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 }, 193455a7b23SScott Bauer [OPAL_EGET] = 194455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 }, 195455a7b23SScott Bauer [OPAL_ESET] = 196455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 }, 197455a7b23SScott Bauer [OPAL_NEXT] = 198455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 }, 199455a7b23SScott Bauer [OPAL_EAUTHENTICATE] = 200455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c }, 201455a7b23SScott Bauer [OPAL_GETACL] = 202455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d }, 203455a7b23SScott Bauer [OPAL_GENKEY] = 204455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 }, 205455a7b23SScott Bauer [OPAL_REVERTSP] = 206455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 }, 207455a7b23SScott Bauer [OPAL_GET] = 208455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 }, 209455a7b23SScott Bauer [OPAL_SET] = 210455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 }, 211455a7b23SScott Bauer [OPAL_AUTHENTICATE] = 212455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c }, 213455a7b23SScott Bauer [OPAL_RANDOM] = 214455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 }, 215455a7b23SScott Bauer [OPAL_ERASE] = 216455a7b23SScott Bauer { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 }, 217455a7b23SScott Bauer }; 218455a7b23SScott Bauer 219455a7b23SScott Bauer static int end_opal_session_error(struct opal_dev *dev); 220455a7b23SScott Bauer 221455a7b23SScott Bauer struct opal_suspend_data { 222455a7b23SScott Bauer struct opal_lock_unlock unlk; 223455a7b23SScott Bauer u8 lr; 224455a7b23SScott Bauer struct list_head node; 225455a7b23SScott Bauer }; 226455a7b23SScott Bauer 227455a7b23SScott Bauer /* 228455a7b23SScott Bauer * Derived from: 229455a7b23SScott Bauer * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 230455a7b23SScott Bauer * Section: 5.1.5 Method Status Codes 231455a7b23SScott Bauer */ 232455a7b23SScott Bauer static const char * const opal_errors[] = { 233455a7b23SScott Bauer "Success", 234455a7b23SScott Bauer "Not Authorized", 235455a7b23SScott Bauer "Unknown Error", 236455a7b23SScott Bauer "SP Busy", 237455a7b23SScott Bauer "SP Failed", 238455a7b23SScott Bauer "SP Disabled", 239455a7b23SScott Bauer "SP Frozen", 240455a7b23SScott Bauer "No Sessions Available", 241455a7b23SScott Bauer "Uniqueness Conflict", 242455a7b23SScott Bauer "Insufficient Space", 243455a7b23SScott Bauer "Insufficient Rows", 244455a7b23SScott Bauer "Invalid Function", 245455a7b23SScott Bauer "Invalid Parameter", 246455a7b23SScott Bauer "Invalid Reference", 247455a7b23SScott Bauer "Unknown Error", 248455a7b23SScott Bauer "TPER Malfunction", 249455a7b23SScott Bauer "Transaction Failure", 250455a7b23SScott Bauer "Response Overflow", 251455a7b23SScott Bauer "Authority Locked Out", 252455a7b23SScott Bauer }; 253455a7b23SScott Bauer 254455a7b23SScott Bauer static const char *opal_error_to_human(int error) 255455a7b23SScott Bauer { 256455a7b23SScott Bauer if (error == 0x3f) 257455a7b23SScott Bauer return "Failed"; 258455a7b23SScott Bauer 259455a7b23SScott Bauer if (error >= ARRAY_SIZE(opal_errors) || error < 0) 260455a7b23SScott Bauer return "Unknown Error"; 261455a7b23SScott Bauer 262455a7b23SScott Bauer return opal_errors[error]; 263455a7b23SScott Bauer } 264455a7b23SScott Bauer 265455a7b23SScott Bauer static void print_buffer(const u8 *ptr, u32 length) 266455a7b23SScott Bauer { 267455a7b23SScott Bauer #ifdef DEBUG 268455a7b23SScott Bauer print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length); 269455a7b23SScott Bauer pr_debug("\n"); 270455a7b23SScott Bauer #endif 271455a7b23SScott Bauer } 272455a7b23SScott Bauer 273455a7b23SScott Bauer static bool check_tper(const void *data) 274455a7b23SScott Bauer { 275455a7b23SScott Bauer const struct d0_tper_features *tper = data; 276455a7b23SScott Bauer u8 flags = tper->supported_features; 277455a7b23SScott Bauer 278455a7b23SScott Bauer if (!(flags & TPER_SYNC_SUPPORTED)) { 279591c59d1SScott Bauer pr_debug("TPer sync not supported. flags = %d\n", 280455a7b23SScott Bauer tper->supported_features); 281455a7b23SScott Bauer return false; 282455a7b23SScott Bauer } 283455a7b23SScott Bauer 284455a7b23SScott Bauer return true; 285455a7b23SScott Bauer } 286455a7b23SScott Bauer 287dbec491bSScott Bauer static bool check_mbrenabled(const void *data) 288dbec491bSScott Bauer { 289dbec491bSScott Bauer const struct d0_locking_features *lfeat = data; 290dbec491bSScott Bauer u8 sup_feat = lfeat->supported_features; 291dbec491bSScott Bauer 292dbec491bSScott Bauer return !!(sup_feat & MBR_ENABLED_MASK); 293dbec491bSScott Bauer } 294dbec491bSScott Bauer 295455a7b23SScott Bauer static bool check_sum(const void *data) 296455a7b23SScott Bauer { 297455a7b23SScott Bauer const struct d0_single_user_mode *sum = data; 298455a7b23SScott Bauer u32 nlo = be32_to_cpu(sum->num_locking_objects); 299455a7b23SScott Bauer 300455a7b23SScott Bauer if (nlo == 0) { 301591c59d1SScott Bauer pr_debug("Need at least one locking object.\n"); 302455a7b23SScott Bauer return false; 303455a7b23SScott Bauer } 304455a7b23SScott Bauer 305455a7b23SScott Bauer pr_debug("Number of locking objects: %d\n", nlo); 306455a7b23SScott Bauer 307455a7b23SScott Bauer return true; 308455a7b23SScott Bauer } 309455a7b23SScott Bauer 310455a7b23SScott Bauer static u16 get_comid_v100(const void *data) 311455a7b23SScott Bauer { 312455a7b23SScott Bauer const struct d0_opal_v100 *v100 = data; 313455a7b23SScott Bauer 314455a7b23SScott Bauer return be16_to_cpu(v100->baseComID); 315455a7b23SScott Bauer } 316455a7b23SScott Bauer 317455a7b23SScott Bauer static u16 get_comid_v200(const void *data) 318455a7b23SScott Bauer { 319455a7b23SScott Bauer const struct d0_opal_v200 *v200 = data; 320455a7b23SScott Bauer 321455a7b23SScott Bauer return be16_to_cpu(v200->baseComID); 322455a7b23SScott Bauer } 323455a7b23SScott Bauer 324455a7b23SScott Bauer static int opal_send_cmd(struct opal_dev *dev) 325455a7b23SScott Bauer { 3264f1244c8SChristoph Hellwig return dev->send_recv(dev->data, dev->comid, TCG_SECP_01, 327455a7b23SScott Bauer dev->cmd, IO_BUFFER_LENGTH, 328455a7b23SScott Bauer true); 329455a7b23SScott Bauer } 330455a7b23SScott Bauer 331455a7b23SScott Bauer static int opal_recv_cmd(struct opal_dev *dev) 332455a7b23SScott Bauer { 3334f1244c8SChristoph Hellwig return dev->send_recv(dev->data, dev->comid, TCG_SECP_01, 334455a7b23SScott Bauer dev->resp, IO_BUFFER_LENGTH, 335455a7b23SScott Bauer false); 336455a7b23SScott Bauer } 337455a7b23SScott Bauer 338455a7b23SScott Bauer static int opal_recv_check(struct opal_dev *dev) 339455a7b23SScott Bauer { 340455a7b23SScott Bauer size_t buflen = IO_BUFFER_LENGTH; 341455a7b23SScott Bauer void *buffer = dev->resp; 342455a7b23SScott Bauer struct opal_header *hdr = buffer; 343455a7b23SScott Bauer int ret; 344455a7b23SScott Bauer 345455a7b23SScott Bauer do { 346455a7b23SScott Bauer pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n", 347455a7b23SScott Bauer hdr->cp.outstandingData, 348455a7b23SScott Bauer hdr->cp.minTransfer); 349455a7b23SScott Bauer 350455a7b23SScott Bauer if (hdr->cp.outstandingData == 0 || 351455a7b23SScott Bauer hdr->cp.minTransfer != 0) 352455a7b23SScott Bauer return 0; 353455a7b23SScott Bauer 354455a7b23SScott Bauer memset(buffer, 0, buflen); 355455a7b23SScott Bauer ret = opal_recv_cmd(dev); 356455a7b23SScott Bauer } while (!ret); 357455a7b23SScott Bauer 358455a7b23SScott Bauer return ret; 359455a7b23SScott Bauer } 360455a7b23SScott Bauer 361455a7b23SScott Bauer static int opal_send_recv(struct opal_dev *dev, cont_fn *cont) 362455a7b23SScott Bauer { 363455a7b23SScott Bauer int ret; 364455a7b23SScott Bauer 365455a7b23SScott Bauer ret = opal_send_cmd(dev); 366455a7b23SScott Bauer if (ret) 367455a7b23SScott Bauer return ret; 368455a7b23SScott Bauer ret = opal_recv_cmd(dev); 369455a7b23SScott Bauer if (ret) 370455a7b23SScott Bauer return ret; 371455a7b23SScott Bauer ret = opal_recv_check(dev); 372455a7b23SScott Bauer if (ret) 373455a7b23SScott Bauer return ret; 374455a7b23SScott Bauer return cont(dev); 375455a7b23SScott Bauer } 376455a7b23SScott Bauer 377455a7b23SScott Bauer static void check_geometry(struct opal_dev *dev, const void *data) 378455a7b23SScott Bauer { 379455a7b23SScott Bauer const struct d0_geometry_features *geo = data; 380455a7b23SScott Bauer 381455a7b23SScott Bauer dev->align = geo->alignment_granularity; 382455a7b23SScott Bauer dev->lowest_lba = geo->lowest_aligned_lba; 383455a7b23SScott Bauer } 384455a7b23SScott Bauer 385455a7b23SScott Bauer static int next(struct opal_dev *dev) 386455a7b23SScott Bauer { 387eed64951SJon Derrick const struct opal_step *step; 388eed64951SJon Derrick int state = 0, error = 0; 389455a7b23SScott Bauer 390455a7b23SScott Bauer do { 391eed64951SJon Derrick step = &dev->steps[state]; 392eed64951SJon Derrick if (!step->fn) 393455a7b23SScott Bauer break; 394455a7b23SScott Bauer 395eed64951SJon Derrick error = step->fn(dev, step->data); 396455a7b23SScott Bauer if (error) { 397591c59d1SScott Bauer pr_debug("Error on step function: %d with error %d: %s\n", 398eed64951SJon Derrick state, error, 399455a7b23SScott Bauer opal_error_to_human(error)); 400455a7b23SScott Bauer 401455a7b23SScott Bauer /* For each OPAL command we do a discovery0 then we 402455a7b23SScott Bauer * start some sort of session. 403455a7b23SScott Bauer * If we haven't passed state 1 then there was an error 404455a7b23SScott Bauer * on discovery0 or during the attempt to start a 405455a7b23SScott Bauer * session. Therefore we shouldn't attempt to terminate 406455a7b23SScott Bauer * a session, as one has not yet been created. 407455a7b23SScott Bauer */ 4082d19020bSScott Bauer if (state > 1) { 4092d19020bSScott Bauer end_opal_session_error(dev); 4102d19020bSScott Bauer return error; 4112d19020bSScott Bauer } 4122d19020bSScott Bauer 413455a7b23SScott Bauer } 414eed64951SJon Derrick state++; 415455a7b23SScott Bauer } while (!error); 416455a7b23SScott Bauer 417455a7b23SScott Bauer return error; 418455a7b23SScott Bauer } 419455a7b23SScott Bauer 420455a7b23SScott Bauer static int opal_discovery0_end(struct opal_dev *dev) 421455a7b23SScott Bauer { 422455a7b23SScott Bauer bool found_com_id = false, supported = true, single_user = false; 423455a7b23SScott Bauer const struct d0_header *hdr = (struct d0_header *)dev->resp; 424455a7b23SScott Bauer const u8 *epos = dev->resp, *cpos = dev->resp; 425455a7b23SScott Bauer u16 comid = 0; 42677039b96SJon Derrick u32 hlen = be32_to_cpu(hdr->length); 427455a7b23SScott Bauer 42877039b96SJon Derrick print_buffer(dev->resp, hlen); 429dbec491bSScott Bauer dev->mbr_enabled = false; 430455a7b23SScott Bauer 43177039b96SJon Derrick if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) { 432591c59d1SScott Bauer pr_debug("Discovery length overflows buffer (%zu+%u)/%u\n", 43377039b96SJon Derrick sizeof(*hdr), hlen, IO_BUFFER_LENGTH); 43477039b96SJon Derrick return -EFAULT; 43577039b96SJon Derrick } 43677039b96SJon Derrick 43777039b96SJon Derrick epos += hlen; /* end of buffer */ 438455a7b23SScott Bauer cpos += sizeof(*hdr); /* current position on buffer */ 439455a7b23SScott Bauer 440455a7b23SScott Bauer while (cpos < epos && supported) { 441455a7b23SScott Bauer const struct d0_features *body = 442455a7b23SScott Bauer (const struct d0_features *)cpos; 443455a7b23SScott Bauer 444455a7b23SScott Bauer switch (be16_to_cpu(body->code)) { 445455a7b23SScott Bauer case FC_TPER: 446455a7b23SScott Bauer supported = check_tper(body->features); 447455a7b23SScott Bauer break; 448455a7b23SScott Bauer case FC_SINGLEUSER: 449455a7b23SScott Bauer single_user = check_sum(body->features); 450455a7b23SScott Bauer break; 451455a7b23SScott Bauer case FC_GEOMETRY: 452455a7b23SScott Bauer check_geometry(dev, body); 453455a7b23SScott Bauer break; 454455a7b23SScott Bauer case FC_LOCKING: 455dbec491bSScott Bauer dev->mbr_enabled = check_mbrenabled(body->features); 456dbec491bSScott Bauer break; 457455a7b23SScott Bauer case FC_ENTERPRISE: 458455a7b23SScott Bauer case FC_DATASTORE: 459455a7b23SScott Bauer /* some ignored properties */ 460455a7b23SScott Bauer pr_debug("Found OPAL feature description: %d\n", 461455a7b23SScott Bauer be16_to_cpu(body->code)); 462455a7b23SScott Bauer break; 463455a7b23SScott Bauer case FC_OPALV100: 464455a7b23SScott Bauer comid = get_comid_v100(body->features); 465455a7b23SScott Bauer found_com_id = true; 466455a7b23SScott Bauer break; 467455a7b23SScott Bauer case FC_OPALV200: 468455a7b23SScott Bauer comid = get_comid_v200(body->features); 469455a7b23SScott Bauer found_com_id = true; 470455a7b23SScott Bauer break; 471455a7b23SScott Bauer case 0xbfff ... 0xffff: 472455a7b23SScott Bauer /* vendor specific, just ignore */ 473455a7b23SScott Bauer break; 474455a7b23SScott Bauer default: 475455a7b23SScott Bauer pr_debug("OPAL Unknown feature: %d\n", 476455a7b23SScott Bauer be16_to_cpu(body->code)); 477455a7b23SScott Bauer 478455a7b23SScott Bauer } 479455a7b23SScott Bauer cpos += body->length + 4; 480455a7b23SScott Bauer } 481455a7b23SScott Bauer 482455a7b23SScott Bauer if (!supported) { 483f5b37b7cSChristoph Hellwig pr_debug("This device is not Opal enabled. Not Supported!\n"); 484455a7b23SScott Bauer return -EOPNOTSUPP; 485455a7b23SScott Bauer } 486455a7b23SScott Bauer 487455a7b23SScott Bauer if (!single_user) 488f5b37b7cSChristoph Hellwig pr_debug("Device doesn't support single user mode\n"); 489455a7b23SScott Bauer 490455a7b23SScott Bauer 491455a7b23SScott Bauer if (!found_com_id) { 492f5b37b7cSChristoph Hellwig pr_debug("Could not find OPAL comid for device. Returning early\n"); 493ed7158baSIngo Molnar return -EOPNOTSUPP; 494455a7b23SScott Bauer } 495455a7b23SScott Bauer 496455a7b23SScott Bauer dev->comid = comid; 497455a7b23SScott Bauer 498455a7b23SScott Bauer return 0; 499455a7b23SScott Bauer } 500455a7b23SScott Bauer 501eed64951SJon Derrick static int opal_discovery0(struct opal_dev *dev, void *data) 502455a7b23SScott Bauer { 503455a7b23SScott Bauer int ret; 504455a7b23SScott Bauer 505455a7b23SScott Bauer memset(dev->resp, 0, IO_BUFFER_LENGTH); 506455a7b23SScott Bauer dev->comid = OPAL_DISCOVERY_COMID; 507455a7b23SScott Bauer ret = opal_recv_cmd(dev); 508455a7b23SScott Bauer if (ret) 509455a7b23SScott Bauer return ret; 510455a7b23SScott Bauer return opal_discovery0_end(dev); 511455a7b23SScott Bauer } 512455a7b23SScott Bauer 513e2821a50SJonas Rabenstein static bool can_add(int *err, struct opal_dev *cmd, size_t len) 514455a7b23SScott Bauer { 515455a7b23SScott Bauer if (*err) 516e2821a50SJonas Rabenstein return false; 517e2821a50SJonas Rabenstein 518e2821a50SJonas Rabenstein if (len > IO_BUFFER_LENGTH || cmd->pos > IO_BUFFER_LENGTH - len) { 519e2821a50SJonas Rabenstein pr_debug("Error adding %zu bytes: end of buffer.\n", len); 520455a7b23SScott Bauer *err = -ERANGE; 521e2821a50SJonas Rabenstein return false; 522455a7b23SScott Bauer } 523e2821a50SJonas Rabenstein 524e2821a50SJonas Rabenstein return true; 525e2821a50SJonas Rabenstein } 526e2821a50SJonas Rabenstein 527e2821a50SJonas Rabenstein static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok) 528e2821a50SJonas Rabenstein { 529e2821a50SJonas Rabenstein if (!can_add(err, cmd, 1)) 530e2821a50SJonas Rabenstein return; 531455a7b23SScott Bauer cmd->cmd[cmd->pos++] = tok; 532455a7b23SScott Bauer } 533455a7b23SScott Bauer 534455a7b23SScott Bauer static void add_short_atom_header(struct opal_dev *cmd, bool bytestring, 535455a7b23SScott Bauer bool has_sign, int len) 536455a7b23SScott Bauer { 537455a7b23SScott Bauer u8 atom; 538455a7b23SScott Bauer int err = 0; 539455a7b23SScott Bauer 540455a7b23SScott Bauer atom = SHORT_ATOM_ID; 541455a7b23SScott Bauer atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0; 542455a7b23SScott Bauer atom |= has_sign ? SHORT_ATOM_SIGNED : 0; 543455a7b23SScott Bauer atom |= len & SHORT_ATOM_LEN_MASK; 544455a7b23SScott Bauer 545455a7b23SScott Bauer add_token_u8(&err, cmd, atom); 546455a7b23SScott Bauer } 547455a7b23SScott Bauer 548455a7b23SScott Bauer static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring, 549455a7b23SScott Bauer bool has_sign, int len) 550455a7b23SScott Bauer { 551455a7b23SScott Bauer u8 header0; 552455a7b23SScott Bauer 553455a7b23SScott Bauer header0 = MEDIUM_ATOM_ID; 554455a7b23SScott Bauer header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0; 555455a7b23SScott Bauer header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0; 556455a7b23SScott Bauer header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK; 557455a7b23SScott Bauer cmd->cmd[cmd->pos++] = header0; 558455a7b23SScott Bauer cmd->cmd[cmd->pos++] = len; 559455a7b23SScott Bauer } 560455a7b23SScott Bauer 561455a7b23SScott Bauer static void add_token_u64(int *err, struct opal_dev *cmd, u64 number) 562455a7b23SScott Bauer { 563455a7b23SScott Bauer size_t len; 564455a7b23SScott Bauer int msb; 565455a7b23SScott Bauer 566455a7b23SScott Bauer if (!(number & ~TINY_ATOM_DATA_MASK)) { 567455a7b23SScott Bauer add_token_u8(err, cmd, number); 568455a7b23SScott Bauer return; 569455a7b23SScott Bauer } 570455a7b23SScott Bauer 5715f990d31SJonas Rabenstein msb = fls64(number); 5725f990d31SJonas Rabenstein len = DIV_ROUND_UP(msb, 8); 573455a7b23SScott Bauer 574e2821a50SJonas Rabenstein if (!can_add(err, cmd, len + 1)) { 575591c59d1SScott Bauer pr_debug("Error adding u64: end of buffer.\n"); 576455a7b23SScott Bauer return; 577455a7b23SScott Bauer } 578455a7b23SScott Bauer add_short_atom_header(cmd, false, false, len); 5795f990d31SJonas Rabenstein while (len--) 5805f990d31SJonas Rabenstein add_token_u8(err, cmd, number >> (len * 8)); 581455a7b23SScott Bauer } 582455a7b23SScott Bauer 583455a7b23SScott Bauer static void add_token_bytestring(int *err, struct opal_dev *cmd, 584455a7b23SScott Bauer const u8 *bytestring, size_t len) 585455a7b23SScott Bauer { 586455a7b23SScott Bauer size_t header_len = 1; 587455a7b23SScott Bauer bool is_short_atom = true; 588455a7b23SScott Bauer 589455a7b23SScott Bauer if (*err) 590455a7b23SScott Bauer return; 591455a7b23SScott Bauer 592455a7b23SScott Bauer if (len & ~SHORT_ATOM_LEN_MASK) { 593455a7b23SScott Bauer header_len = 2; 594455a7b23SScott Bauer is_short_atom = false; 595455a7b23SScott Bauer } 596455a7b23SScott Bauer 597e2821a50SJonas Rabenstein if (!can_add(err, cmd, header_len + len)) { 598591c59d1SScott Bauer pr_debug("Error adding bytestring: end of buffer.\n"); 599455a7b23SScott Bauer return; 600455a7b23SScott Bauer } 601455a7b23SScott Bauer 602455a7b23SScott Bauer if (is_short_atom) 603455a7b23SScott Bauer add_short_atom_header(cmd, true, false, len); 604455a7b23SScott Bauer else 605455a7b23SScott Bauer add_medium_atom_header(cmd, true, false, len); 606455a7b23SScott Bauer 607455a7b23SScott Bauer memcpy(&cmd->cmd[cmd->pos], bytestring, len); 608455a7b23SScott Bauer cmd->pos += len; 609455a7b23SScott Bauer 610455a7b23SScott Bauer } 611455a7b23SScott Bauer 612455a7b23SScott Bauer static int build_locking_range(u8 *buffer, size_t length, u8 lr) 613455a7b23SScott Bauer { 614455a7b23SScott Bauer if (length > OPAL_UID_LENGTH) { 615591c59d1SScott Bauer pr_debug("Can't build locking range. Length OOB\n"); 616455a7b23SScott Bauer return -ERANGE; 617455a7b23SScott Bauer } 618455a7b23SScott Bauer 619455a7b23SScott Bauer memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH); 620455a7b23SScott Bauer 621455a7b23SScott Bauer if (lr == 0) 622455a7b23SScott Bauer return 0; 623455a7b23SScott Bauer buffer[5] = LOCKING_RANGE_NON_GLOBAL; 624455a7b23SScott Bauer buffer[7] = lr; 625455a7b23SScott Bauer 626455a7b23SScott Bauer return 0; 627455a7b23SScott Bauer } 628455a7b23SScott Bauer 629455a7b23SScott Bauer static int build_locking_user(u8 *buffer, size_t length, u8 lr) 630455a7b23SScott Bauer { 631455a7b23SScott Bauer if (length > OPAL_UID_LENGTH) { 6321e815b33SDavid Kozub pr_debug("Can't build locking range user. Length OOB\n"); 633455a7b23SScott Bauer return -ERANGE; 634455a7b23SScott Bauer } 635455a7b23SScott Bauer 636455a7b23SScott Bauer memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH); 637455a7b23SScott Bauer 638455a7b23SScott Bauer buffer[7] = lr + 1; 639455a7b23SScott Bauer 640455a7b23SScott Bauer return 0; 641455a7b23SScott Bauer } 642455a7b23SScott Bauer 643455a7b23SScott Bauer static void set_comid(struct opal_dev *cmd, u16 comid) 644455a7b23SScott Bauer { 645455a7b23SScott Bauer struct opal_header *hdr = (struct opal_header *)cmd->cmd; 646455a7b23SScott Bauer 647455a7b23SScott Bauer hdr->cp.extendedComID[0] = comid >> 8; 648455a7b23SScott Bauer hdr->cp.extendedComID[1] = comid; 649455a7b23SScott Bauer hdr->cp.extendedComID[2] = 0; 650455a7b23SScott Bauer hdr->cp.extendedComID[3] = 0; 651455a7b23SScott Bauer } 652455a7b23SScott Bauer 653455a7b23SScott Bauer static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn) 654455a7b23SScott Bauer { 655455a7b23SScott Bauer struct opal_header *hdr; 656455a7b23SScott Bauer int err = 0; 657455a7b23SScott Bauer 658*e8b29224SDavid Kozub /* close the parameter list opened from cmd_start */ 65978d584caSDavid Kozub add_token_u8(&err, cmd, OPAL_ENDLIST); 66078d584caSDavid Kozub 661455a7b23SScott Bauer add_token_u8(&err, cmd, OPAL_ENDOFDATA); 662455a7b23SScott Bauer add_token_u8(&err, cmd, OPAL_STARTLIST); 663455a7b23SScott Bauer add_token_u8(&err, cmd, 0); 664455a7b23SScott Bauer add_token_u8(&err, cmd, 0); 665455a7b23SScott Bauer add_token_u8(&err, cmd, 0); 666455a7b23SScott Bauer add_token_u8(&err, cmd, OPAL_ENDLIST); 667455a7b23SScott Bauer 668455a7b23SScott Bauer if (err) { 669591c59d1SScott Bauer pr_debug("Error finalizing command.\n"); 670455a7b23SScott Bauer return -EFAULT; 671455a7b23SScott Bauer } 672455a7b23SScott Bauer 673455a7b23SScott Bauer hdr = (struct opal_header *) cmd->cmd; 674455a7b23SScott Bauer 675455a7b23SScott Bauer hdr->pkt.tsn = cpu_to_be32(tsn); 676455a7b23SScott Bauer hdr->pkt.hsn = cpu_to_be32(hsn); 677455a7b23SScott Bauer 678455a7b23SScott Bauer hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr)); 679455a7b23SScott Bauer while (cmd->pos % 4) { 680455a7b23SScott Bauer if (cmd->pos >= IO_BUFFER_LENGTH) { 681591c59d1SScott Bauer pr_debug("Error: Buffer overrun\n"); 682455a7b23SScott Bauer return -ERANGE; 683455a7b23SScott Bauer } 684455a7b23SScott Bauer cmd->cmd[cmd->pos++] = 0; 685455a7b23SScott Bauer } 686455a7b23SScott Bauer hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) - 687455a7b23SScott Bauer sizeof(hdr->pkt)); 688455a7b23SScott Bauer hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp)); 689455a7b23SScott Bauer 690455a7b23SScott Bauer return 0; 691455a7b23SScott Bauer } 692455a7b23SScott Bauer 693cccb9241SJon Derrick static const struct opal_resp_tok *response_get_token( 694cccb9241SJon Derrick const struct parsed_resp *resp, 695455a7b23SScott Bauer int n) 696455a7b23SScott Bauer { 697455a7b23SScott Bauer const struct opal_resp_tok *tok; 698455a7b23SScott Bauer 699455a7b23SScott Bauer if (n >= resp->num) { 700591c59d1SScott Bauer pr_debug("Token number doesn't exist: %d, resp: %d\n", 701455a7b23SScott Bauer n, resp->num); 702cccb9241SJon Derrick return ERR_PTR(-EINVAL); 703455a7b23SScott Bauer } 704455a7b23SScott Bauer 705455a7b23SScott Bauer tok = &resp->toks[n]; 706455a7b23SScott Bauer if (tok->len == 0) { 707591c59d1SScott Bauer pr_debug("Token length must be non-zero\n"); 708cccb9241SJon Derrick return ERR_PTR(-EINVAL); 709455a7b23SScott Bauer } 710455a7b23SScott Bauer 711cccb9241SJon Derrick return tok; 712455a7b23SScott Bauer } 713455a7b23SScott Bauer 714aedb6e24SJon Derrick static ssize_t response_parse_tiny(struct opal_resp_tok *tok, 715455a7b23SScott Bauer const u8 *pos) 716455a7b23SScott Bauer { 717455a7b23SScott Bauer tok->pos = pos; 718455a7b23SScott Bauer tok->len = 1; 719455a7b23SScott Bauer tok->width = OPAL_WIDTH_TINY; 720455a7b23SScott Bauer 721455a7b23SScott Bauer if (pos[0] & TINY_ATOM_SIGNED) { 722455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_SINT; 723455a7b23SScott Bauer } else { 724455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_UINT; 725455a7b23SScott Bauer tok->stored.u = pos[0] & 0x3f; 726455a7b23SScott Bauer } 727455a7b23SScott Bauer 728455a7b23SScott Bauer return tok->len; 729455a7b23SScott Bauer } 730455a7b23SScott Bauer 731aedb6e24SJon Derrick static ssize_t response_parse_short(struct opal_resp_tok *tok, 732455a7b23SScott Bauer const u8 *pos) 733455a7b23SScott Bauer { 734455a7b23SScott Bauer tok->pos = pos; 735455a7b23SScott Bauer tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1; 736455a7b23SScott Bauer tok->width = OPAL_WIDTH_SHORT; 737455a7b23SScott Bauer 738455a7b23SScott Bauer if (pos[0] & SHORT_ATOM_BYTESTRING) { 739455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_BYTESTRING; 740455a7b23SScott Bauer } else if (pos[0] & SHORT_ATOM_SIGNED) { 741455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_SINT; 742455a7b23SScott Bauer } else { 743455a7b23SScott Bauer u64 u_integer = 0; 744aedb6e24SJon Derrick ssize_t i, b = 0; 745455a7b23SScott Bauer 746455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_UINT; 747455a7b23SScott Bauer if (tok->len > 9) { 748591c59d1SScott Bauer pr_debug("uint64 with more than 8 bytes\n"); 749455a7b23SScott Bauer return -EINVAL; 750455a7b23SScott Bauer } 751455a7b23SScott Bauer for (i = tok->len - 1; i > 0; i--) { 752455a7b23SScott Bauer u_integer |= ((u64)pos[i] << (8 * b)); 753455a7b23SScott Bauer b++; 754455a7b23SScott Bauer } 755455a7b23SScott Bauer tok->stored.u = u_integer; 756455a7b23SScott Bauer } 757455a7b23SScott Bauer 758455a7b23SScott Bauer return tok->len; 759455a7b23SScott Bauer } 760455a7b23SScott Bauer 761aedb6e24SJon Derrick static ssize_t response_parse_medium(struct opal_resp_tok *tok, 762455a7b23SScott Bauer const u8 *pos) 763455a7b23SScott Bauer { 764455a7b23SScott Bauer tok->pos = pos; 765455a7b23SScott Bauer tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2; 766455a7b23SScott Bauer tok->width = OPAL_WIDTH_MEDIUM; 767455a7b23SScott Bauer 768455a7b23SScott Bauer if (pos[0] & MEDIUM_ATOM_BYTESTRING) 769455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_BYTESTRING; 770455a7b23SScott Bauer else if (pos[0] & MEDIUM_ATOM_SIGNED) 771455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_SINT; 772455a7b23SScott Bauer else 773455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_UINT; 774455a7b23SScott Bauer 775455a7b23SScott Bauer return tok->len; 776455a7b23SScott Bauer } 777455a7b23SScott Bauer 778aedb6e24SJon Derrick static ssize_t response_parse_long(struct opal_resp_tok *tok, 779455a7b23SScott Bauer const u8 *pos) 780455a7b23SScott Bauer { 781455a7b23SScott Bauer tok->pos = pos; 782455a7b23SScott Bauer tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4; 783455a7b23SScott Bauer tok->width = OPAL_WIDTH_LONG; 784455a7b23SScott Bauer 785455a7b23SScott Bauer if (pos[0] & LONG_ATOM_BYTESTRING) 786455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_BYTESTRING; 787455a7b23SScott Bauer else if (pos[0] & LONG_ATOM_SIGNED) 788455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_SINT; 789455a7b23SScott Bauer else 790455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_UINT; 791455a7b23SScott Bauer 792455a7b23SScott Bauer return tok->len; 793455a7b23SScott Bauer } 794455a7b23SScott Bauer 795aedb6e24SJon Derrick static ssize_t response_parse_token(struct opal_resp_tok *tok, 796455a7b23SScott Bauer const u8 *pos) 797455a7b23SScott Bauer { 798455a7b23SScott Bauer tok->pos = pos; 799455a7b23SScott Bauer tok->len = 1; 800455a7b23SScott Bauer tok->type = OPAL_DTA_TOKENID_TOKEN; 801455a7b23SScott Bauer tok->width = OPAL_WIDTH_TOKEN; 802455a7b23SScott Bauer 803455a7b23SScott Bauer return tok->len; 804455a7b23SScott Bauer } 805455a7b23SScott Bauer 806455a7b23SScott Bauer static int response_parse(const u8 *buf, size_t length, 807455a7b23SScott Bauer struct parsed_resp *resp) 808455a7b23SScott Bauer { 809455a7b23SScott Bauer const struct opal_header *hdr; 810455a7b23SScott Bauer struct opal_resp_tok *iter; 811455a7b23SScott Bauer int num_entries = 0; 812455a7b23SScott Bauer int total; 813aedb6e24SJon Derrick ssize_t token_length; 814455a7b23SScott Bauer const u8 *pos; 81577039b96SJon Derrick u32 clen, plen, slen; 816455a7b23SScott Bauer 817455a7b23SScott Bauer if (!buf) 818455a7b23SScott Bauer return -EFAULT; 819455a7b23SScott Bauer 820455a7b23SScott Bauer if (!resp) 821455a7b23SScott Bauer return -EFAULT; 822455a7b23SScott Bauer 823455a7b23SScott Bauer hdr = (struct opal_header *)buf; 824455a7b23SScott Bauer pos = buf; 825455a7b23SScott Bauer pos += sizeof(*hdr); 826455a7b23SScott Bauer 82777039b96SJon Derrick clen = be32_to_cpu(hdr->cp.length); 82877039b96SJon Derrick plen = be32_to_cpu(hdr->pkt.length); 82977039b96SJon Derrick slen = be32_to_cpu(hdr->subpkt.length); 83077039b96SJon Derrick pr_debug("Response size: cp: %u, pkt: %u, subpkt: %u\n", 83177039b96SJon Derrick clen, plen, slen); 832455a7b23SScott Bauer 83377039b96SJon Derrick if (clen == 0 || plen == 0 || slen == 0 || 83477039b96SJon Derrick slen > IO_BUFFER_LENGTH - sizeof(*hdr)) { 835591c59d1SScott Bauer pr_debug("Bad header length. cp: %u, pkt: %u, subpkt: %u\n", 83677039b96SJon Derrick clen, plen, slen); 837455a7b23SScott Bauer print_buffer(pos, sizeof(*hdr)); 838455a7b23SScott Bauer return -EINVAL; 839455a7b23SScott Bauer } 840455a7b23SScott Bauer 841455a7b23SScott Bauer if (pos > buf + length) 842455a7b23SScott Bauer return -EFAULT; 843455a7b23SScott Bauer 844455a7b23SScott Bauer iter = resp->toks; 84577039b96SJon Derrick total = slen; 846455a7b23SScott Bauer print_buffer(pos, total); 847455a7b23SScott Bauer while (total > 0) { 848455a7b23SScott Bauer if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */ 849455a7b23SScott Bauer token_length = response_parse_tiny(iter, pos); 850455a7b23SScott Bauer else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */ 851455a7b23SScott Bauer token_length = response_parse_short(iter, pos); 852455a7b23SScott Bauer else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */ 853455a7b23SScott Bauer token_length = response_parse_medium(iter, pos); 854455a7b23SScott Bauer else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */ 855455a7b23SScott Bauer token_length = response_parse_long(iter, pos); 856455a7b23SScott Bauer else /* TOKEN */ 857455a7b23SScott Bauer token_length = response_parse_token(iter, pos); 858455a7b23SScott Bauer 859aedb6e24SJon Derrick if (token_length < 0) 860aedb6e24SJon Derrick return token_length; 861455a7b23SScott Bauer 862455a7b23SScott Bauer pos += token_length; 863455a7b23SScott Bauer total -= token_length; 864455a7b23SScott Bauer iter++; 865455a7b23SScott Bauer num_entries++; 866455a7b23SScott Bauer } 867455a7b23SScott Bauer 868455a7b23SScott Bauer if (num_entries == 0) { 869591c59d1SScott Bauer pr_debug("Couldn't parse response.\n"); 870455a7b23SScott Bauer return -EINVAL; 871455a7b23SScott Bauer } 872455a7b23SScott Bauer resp->num = num_entries; 873455a7b23SScott Bauer 874455a7b23SScott Bauer return 0; 875455a7b23SScott Bauer } 876455a7b23SScott Bauer 877455a7b23SScott Bauer static size_t response_get_string(const struct parsed_resp *resp, int n, 878455a7b23SScott Bauer const char **store) 879455a7b23SScott Bauer { 880d15e1175SJonas Rabenstein u8 skip; 881d15e1175SJonas Rabenstein const struct opal_resp_tok *token; 882d15e1175SJonas Rabenstein 883455a7b23SScott Bauer *store = NULL; 884455a7b23SScott Bauer if (!resp) { 885591c59d1SScott Bauer pr_debug("Response is NULL\n"); 886455a7b23SScott Bauer return 0; 887455a7b23SScott Bauer } 888455a7b23SScott Bauer 889ce042c18SDan Carpenter if (n >= resp->num) { 890591c59d1SScott Bauer pr_debug("Response has %d tokens. Can't access %d\n", 891455a7b23SScott Bauer resp->num, n); 892455a7b23SScott Bauer return 0; 893455a7b23SScott Bauer } 894455a7b23SScott Bauer 895d15e1175SJonas Rabenstein token = &resp->toks[n]; 896d15e1175SJonas Rabenstein if (token->type != OPAL_DTA_TOKENID_BYTESTRING) { 897591c59d1SScott Bauer pr_debug("Token is not a byte string!\n"); 898455a7b23SScott Bauer return 0; 899455a7b23SScott Bauer } 900455a7b23SScott Bauer 901d15e1175SJonas Rabenstein switch (token->width) { 902d15e1175SJonas Rabenstein case OPAL_WIDTH_TINY: 903d15e1175SJonas Rabenstein case OPAL_WIDTH_SHORT: 904d15e1175SJonas Rabenstein skip = 1; 905d15e1175SJonas Rabenstein break; 906d15e1175SJonas Rabenstein case OPAL_WIDTH_MEDIUM: 907d15e1175SJonas Rabenstein skip = 2; 908d15e1175SJonas Rabenstein break; 909d15e1175SJonas Rabenstein case OPAL_WIDTH_LONG: 910d15e1175SJonas Rabenstein skip = 4; 911d15e1175SJonas Rabenstein break; 912d15e1175SJonas Rabenstein default: 913d15e1175SJonas Rabenstein pr_debug("Token has invalid width!\n"); 914d15e1175SJonas Rabenstein return 0; 915d15e1175SJonas Rabenstein } 916d15e1175SJonas Rabenstein 917d15e1175SJonas Rabenstein *store = token->pos + skip; 918d15e1175SJonas Rabenstein return token->len - skip; 919455a7b23SScott Bauer } 920455a7b23SScott Bauer 921455a7b23SScott Bauer static u64 response_get_u64(const struct parsed_resp *resp, int n) 922455a7b23SScott Bauer { 923455a7b23SScott Bauer if (!resp) { 924591c59d1SScott Bauer pr_debug("Response is NULL\n"); 925455a7b23SScott Bauer return 0; 926455a7b23SScott Bauer } 927455a7b23SScott Bauer 928ce042c18SDan Carpenter if (n >= resp->num) { 929591c59d1SScott Bauer pr_debug("Response has %d tokens. Can't access %d\n", 930455a7b23SScott Bauer resp->num, n); 931455a7b23SScott Bauer return 0; 932455a7b23SScott Bauer } 933455a7b23SScott Bauer 934455a7b23SScott Bauer if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) { 935591c59d1SScott Bauer pr_debug("Token is not unsigned it: %d\n", 936455a7b23SScott Bauer resp->toks[n].type); 937455a7b23SScott Bauer return 0; 938455a7b23SScott Bauer } 939455a7b23SScott Bauer 940455a7b23SScott Bauer if (!(resp->toks[n].width == OPAL_WIDTH_TINY || 941455a7b23SScott Bauer resp->toks[n].width == OPAL_WIDTH_SHORT)) { 942591c59d1SScott Bauer pr_debug("Atom is not short or tiny: %d\n", 943455a7b23SScott Bauer resp->toks[n].width); 944455a7b23SScott Bauer return 0; 945455a7b23SScott Bauer } 946455a7b23SScott Bauer 947455a7b23SScott Bauer return resp->toks[n].stored.u; 948455a7b23SScott Bauer } 949455a7b23SScott Bauer 950cccb9241SJon Derrick static bool response_token_matches(const struct opal_resp_tok *token, u8 match) 951cccb9241SJon Derrick { 952cccb9241SJon Derrick if (IS_ERR(token) || 953cccb9241SJon Derrick token->type != OPAL_DTA_TOKENID_TOKEN || 954cccb9241SJon Derrick token->pos[0] != match) 955cccb9241SJon Derrick return false; 956cccb9241SJon Derrick return true; 957cccb9241SJon Derrick } 958cccb9241SJon Derrick 959455a7b23SScott Bauer static u8 response_status(const struct parsed_resp *resp) 960455a7b23SScott Bauer { 961cccb9241SJon Derrick const struct opal_resp_tok *tok; 962cccb9241SJon Derrick 963cccb9241SJon Derrick tok = response_get_token(resp, 0); 964cccb9241SJon Derrick if (response_token_matches(tok, OPAL_ENDOFSESSION)) 965455a7b23SScott Bauer return 0; 966455a7b23SScott Bauer 967455a7b23SScott Bauer if (resp->num < 5) 968455a7b23SScott Bauer return DTAERROR_NO_METHOD_STATUS; 969455a7b23SScott Bauer 970cccb9241SJon Derrick tok = response_get_token(resp, resp->num - 5); 971cccb9241SJon Derrick if (!response_token_matches(tok, OPAL_STARTLIST)) 972cccb9241SJon Derrick return DTAERROR_NO_METHOD_STATUS; 973cccb9241SJon Derrick 974cccb9241SJon Derrick tok = response_get_token(resp, resp->num - 1); 975cccb9241SJon Derrick if (!response_token_matches(tok, OPAL_ENDLIST)) 976455a7b23SScott Bauer return DTAERROR_NO_METHOD_STATUS; 977455a7b23SScott Bauer 978455a7b23SScott Bauer return response_get_u64(resp, resp->num - 4); 979455a7b23SScott Bauer } 980455a7b23SScott Bauer 981455a7b23SScott Bauer /* Parses and checks for errors */ 982455a7b23SScott Bauer static int parse_and_check_status(struct opal_dev *dev) 983455a7b23SScott Bauer { 984455a7b23SScott Bauer int error; 985455a7b23SScott Bauer 986455a7b23SScott Bauer print_buffer(dev->cmd, dev->pos); 987455a7b23SScott Bauer 988455a7b23SScott Bauer error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed); 989455a7b23SScott Bauer if (error) { 990591c59d1SScott Bauer pr_debug("Couldn't parse response.\n"); 991455a7b23SScott Bauer return error; 992455a7b23SScott Bauer } 993455a7b23SScott Bauer 994455a7b23SScott Bauer return response_status(&dev->parsed); 995455a7b23SScott Bauer } 996455a7b23SScott Bauer 997455a7b23SScott Bauer static void clear_opal_cmd(struct opal_dev *dev) 998455a7b23SScott Bauer { 999455a7b23SScott Bauer dev->pos = sizeof(struct opal_header); 1000455a7b23SScott Bauer memset(dev->cmd, 0, IO_BUFFER_LENGTH); 1001455a7b23SScott Bauer } 1002455a7b23SScott Bauer 1003*e8b29224SDavid Kozub static int cmd_start(struct opal_dev *dev, const u8 *uid, const u8 *method) 1004*e8b29224SDavid Kozub { 1005*e8b29224SDavid Kozub int err = 0; 1006*e8b29224SDavid Kozub 1007*e8b29224SDavid Kozub clear_opal_cmd(dev); 1008*e8b29224SDavid Kozub set_comid(dev, dev->comid); 1009*e8b29224SDavid Kozub 1010*e8b29224SDavid Kozub add_token_u8(&err, dev, OPAL_CALL); 1011*e8b29224SDavid Kozub add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH); 1012*e8b29224SDavid Kozub add_token_bytestring(&err, dev, method, OPAL_METHOD_LENGTH); 1013*e8b29224SDavid Kozub 1014*e8b29224SDavid Kozub /* 1015*e8b29224SDavid Kozub * Every method call is followed by its parameters enclosed within 1016*e8b29224SDavid Kozub * OPAL_STARTLIST and OPAL_ENDLIST tokens. We automatically open the 1017*e8b29224SDavid Kozub * parameter list here and close it later in cmd_finalize. 1018*e8b29224SDavid Kozub */ 1019*e8b29224SDavid Kozub add_token_u8(&err, dev, OPAL_STARTLIST); 1020*e8b29224SDavid Kozub 1021*e8b29224SDavid Kozub return err; 1022*e8b29224SDavid Kozub } 1023*e8b29224SDavid Kozub 1024455a7b23SScott Bauer static int start_opal_session_cont(struct opal_dev *dev) 1025455a7b23SScott Bauer { 1026455a7b23SScott Bauer u32 hsn, tsn; 1027455a7b23SScott Bauer int error = 0; 1028455a7b23SScott Bauer 1029455a7b23SScott Bauer error = parse_and_check_status(dev); 1030455a7b23SScott Bauer if (error) 1031455a7b23SScott Bauer return error; 1032455a7b23SScott Bauer 1033455a7b23SScott Bauer hsn = response_get_u64(&dev->parsed, 4); 1034455a7b23SScott Bauer tsn = response_get_u64(&dev->parsed, 5); 1035455a7b23SScott Bauer 1036455a7b23SScott Bauer if (hsn == 0 && tsn == 0) { 1037591c59d1SScott Bauer pr_debug("Couldn't authenticate session\n"); 1038455a7b23SScott Bauer return -EPERM; 1039455a7b23SScott Bauer } 1040455a7b23SScott Bauer 1041455a7b23SScott Bauer dev->hsn = hsn; 1042455a7b23SScott Bauer dev->tsn = tsn; 1043455a7b23SScott Bauer return 0; 1044455a7b23SScott Bauer } 1045455a7b23SScott Bauer 1046455a7b23SScott Bauer static void add_suspend_info(struct opal_dev *dev, 1047455a7b23SScott Bauer struct opal_suspend_data *sus) 1048455a7b23SScott Bauer { 1049455a7b23SScott Bauer struct opal_suspend_data *iter; 1050455a7b23SScott Bauer 1051455a7b23SScott Bauer list_for_each_entry(iter, &dev->unlk_lst, node) { 1052455a7b23SScott Bauer if (iter->lr == sus->lr) { 1053455a7b23SScott Bauer list_del(&iter->node); 1054455a7b23SScott Bauer kfree(iter); 1055455a7b23SScott Bauer break; 1056455a7b23SScott Bauer } 1057455a7b23SScott Bauer } 1058455a7b23SScott Bauer list_add_tail(&sus->node, &dev->unlk_lst); 1059455a7b23SScott Bauer } 1060455a7b23SScott Bauer 1061455a7b23SScott Bauer static int end_session_cont(struct opal_dev *dev) 1062455a7b23SScott Bauer { 1063455a7b23SScott Bauer dev->hsn = 0; 1064455a7b23SScott Bauer dev->tsn = 0; 1065455a7b23SScott Bauer return parse_and_check_status(dev); 1066455a7b23SScott Bauer } 1067455a7b23SScott Bauer 1068455a7b23SScott Bauer static int finalize_and_send(struct opal_dev *dev, cont_fn cont) 1069455a7b23SScott Bauer { 1070455a7b23SScott Bauer int ret; 1071455a7b23SScott Bauer 1072455a7b23SScott Bauer ret = cmd_finalize(dev, dev->hsn, dev->tsn); 1073455a7b23SScott Bauer if (ret) { 1074591c59d1SScott Bauer pr_debug("Error finalizing command buffer: %d\n", ret); 1075455a7b23SScott Bauer return ret; 1076455a7b23SScott Bauer } 1077455a7b23SScott Bauer 1078455a7b23SScott Bauer print_buffer(dev->cmd, dev->pos); 1079455a7b23SScott Bauer 1080455a7b23SScott Bauer return opal_send_recv(dev, cont); 1081455a7b23SScott Bauer } 1082455a7b23SScott Bauer 1083eed64951SJon Derrick static int gen_key(struct opal_dev *dev, void *data) 1084455a7b23SScott Bauer { 1085455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH]; 1086*e8b29224SDavid Kozub int err; 1087455a7b23SScott Bauer 1088455a7b23SScott Bauer memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len)); 1089455a7b23SScott Bauer kfree(dev->prev_data); 1090455a7b23SScott Bauer dev->prev_data = NULL; 1091455a7b23SScott Bauer 1092*e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_GENKEY]); 1093455a7b23SScott Bauer 1094455a7b23SScott Bauer if (err) { 1095591c59d1SScott Bauer pr_debug("Error building gen key command\n"); 1096455a7b23SScott Bauer return err; 1097455a7b23SScott Bauer 1098455a7b23SScott Bauer } 1099455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1100455a7b23SScott Bauer } 1101455a7b23SScott Bauer 1102455a7b23SScott Bauer static int get_active_key_cont(struct opal_dev *dev) 1103455a7b23SScott Bauer { 1104455a7b23SScott Bauer const char *activekey; 1105455a7b23SScott Bauer size_t keylen; 1106455a7b23SScott Bauer int error = 0; 1107455a7b23SScott Bauer 1108455a7b23SScott Bauer error = parse_and_check_status(dev); 1109455a7b23SScott Bauer if (error) 1110455a7b23SScott Bauer return error; 1111455a7b23SScott Bauer keylen = response_get_string(&dev->parsed, 4, &activekey); 1112455a7b23SScott Bauer if (!activekey) { 1113591c59d1SScott Bauer pr_debug("%s: Couldn't extract the Activekey from the response\n", 1114455a7b23SScott Bauer __func__); 1115455a7b23SScott Bauer return OPAL_INVAL_PARAM; 1116455a7b23SScott Bauer } 1117455a7b23SScott Bauer dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL); 1118455a7b23SScott Bauer 1119455a7b23SScott Bauer if (!dev->prev_data) 1120455a7b23SScott Bauer return -ENOMEM; 1121455a7b23SScott Bauer 1122455a7b23SScott Bauer dev->prev_d_len = keylen; 1123455a7b23SScott Bauer 1124455a7b23SScott Bauer return 0; 1125455a7b23SScott Bauer } 1126455a7b23SScott Bauer 1127eed64951SJon Derrick static int get_active_key(struct opal_dev *dev, void *data) 1128455a7b23SScott Bauer { 1129455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH]; 1130*e8b29224SDavid Kozub int err; 1131eed64951SJon Derrick u8 *lr = data; 1132455a7b23SScott Bauer 1133455a7b23SScott Bauer err = build_locking_range(uid, sizeof(uid), *lr); 1134455a7b23SScott Bauer if (err) 1135455a7b23SScott Bauer return err; 1136455a7b23SScott Bauer 1137*e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_GET]); 1138455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1139455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1140455a7b23SScott Bauer add_token_u8(&err, dev, 3); /* startCloumn */ 1141455a7b23SScott Bauer add_token_u8(&err, dev, 10); /* ActiveKey */ 1142455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1143455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1144455a7b23SScott Bauer add_token_u8(&err, dev, 4); /* endColumn */ 1145455a7b23SScott Bauer add_token_u8(&err, dev, 10); /* ActiveKey */ 1146455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1147455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1148455a7b23SScott Bauer if (err) { 1149591c59d1SScott Bauer pr_debug("Error building get active key command\n"); 1150455a7b23SScott Bauer return err; 1151455a7b23SScott Bauer } 1152455a7b23SScott Bauer 1153455a7b23SScott Bauer return finalize_and_send(dev, get_active_key_cont); 1154455a7b23SScott Bauer } 1155455a7b23SScott Bauer 1156455a7b23SScott Bauer static int generic_lr_enable_disable(struct opal_dev *dev, 1157455a7b23SScott Bauer u8 *uid, bool rle, bool wle, 1158455a7b23SScott Bauer bool rl, bool wl) 1159455a7b23SScott Bauer { 1160*e8b29224SDavid Kozub int err; 1161455a7b23SScott Bauer 1162*e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_SET]); 1163455a7b23SScott Bauer 1164455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1165455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES); 1166455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1167455a7b23SScott Bauer 1168455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1169455a7b23SScott Bauer add_token_u8(&err, dev, 5); /* ReadLockEnabled */ 1170455a7b23SScott Bauer add_token_u8(&err, dev, rle); 1171455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1172455a7b23SScott Bauer 1173455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1174455a7b23SScott Bauer add_token_u8(&err, dev, 6); /* WriteLockEnabled */ 1175455a7b23SScott Bauer add_token_u8(&err, dev, wle); 1176455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1177455a7b23SScott Bauer 1178455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1179455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_READLOCKED); 1180455a7b23SScott Bauer add_token_u8(&err, dev, rl); 1181455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1182455a7b23SScott Bauer 1183455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1184455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_WRITELOCKED); 1185455a7b23SScott Bauer add_token_u8(&err, dev, wl); 1186455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1187455a7b23SScott Bauer 1188455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1189455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1190455a7b23SScott Bauer return err; 1191455a7b23SScott Bauer } 1192455a7b23SScott Bauer 1193455a7b23SScott Bauer static inline int enable_global_lr(struct opal_dev *dev, u8 *uid, 1194455a7b23SScott Bauer struct opal_user_lr_setup *setup) 1195455a7b23SScott Bauer { 1196455a7b23SScott Bauer int err; 1197455a7b23SScott Bauer 1198455a7b23SScott Bauer err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE, 1199455a7b23SScott Bauer 0, 0); 1200455a7b23SScott Bauer if (err) 1201591c59d1SScott Bauer pr_debug("Failed to create enable global lr command\n"); 1202455a7b23SScott Bauer return err; 1203455a7b23SScott Bauer } 1204455a7b23SScott Bauer 1205eed64951SJon Derrick static int setup_locking_range(struct opal_dev *dev, void *data) 1206455a7b23SScott Bauer { 1207455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH]; 1208eed64951SJon Derrick struct opal_user_lr_setup *setup = data; 1209455a7b23SScott Bauer u8 lr; 1210*e8b29224SDavid Kozub int err; 1211455a7b23SScott Bauer 1212455a7b23SScott Bauer lr = setup->session.opal_key.lr; 1213455a7b23SScott Bauer err = build_locking_range(uid, sizeof(uid), lr); 1214455a7b23SScott Bauer if (err) 1215455a7b23SScott Bauer return err; 1216455a7b23SScott Bauer 1217455a7b23SScott Bauer if (lr == 0) 1218455a7b23SScott Bauer err = enable_global_lr(dev, uid, setup); 1219455a7b23SScott Bauer else { 1220*e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_SET]); 1221455a7b23SScott Bauer 1222455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1223455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES); 1224455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1225455a7b23SScott Bauer 1226455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1227455a7b23SScott Bauer add_token_u8(&err, dev, 3); /* Ranges Start */ 1228455a7b23SScott Bauer add_token_u64(&err, dev, setup->range_start); 1229455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1230455a7b23SScott Bauer 1231455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1232455a7b23SScott Bauer add_token_u8(&err, dev, 4); /* Ranges length */ 1233455a7b23SScott Bauer add_token_u64(&err, dev, setup->range_length); 1234455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1235455a7b23SScott Bauer 1236455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1237455a7b23SScott Bauer add_token_u8(&err, dev, 5); /*ReadLockEnabled */ 1238455a7b23SScott Bauer add_token_u64(&err, dev, !!setup->RLE); 1239455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1240455a7b23SScott Bauer 1241455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1242455a7b23SScott Bauer add_token_u8(&err, dev, 6); /*WriteLockEnabled*/ 1243455a7b23SScott Bauer add_token_u64(&err, dev, !!setup->WLE); 1244455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1245455a7b23SScott Bauer 1246455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1247455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1248455a7b23SScott Bauer } 1249455a7b23SScott Bauer if (err) { 1250591c59d1SScott Bauer pr_debug("Error building Setup Locking range command.\n"); 1251455a7b23SScott Bauer return err; 1252455a7b23SScott Bauer 1253455a7b23SScott Bauer } 1254455a7b23SScott Bauer 1255455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1256455a7b23SScott Bauer } 1257455a7b23SScott Bauer 1258455a7b23SScott Bauer static int start_generic_opal_session(struct opal_dev *dev, 1259455a7b23SScott Bauer enum opal_uid auth, 1260455a7b23SScott Bauer enum opal_uid sp_type, 1261455a7b23SScott Bauer const char *key, 1262455a7b23SScott Bauer u8 key_len) 1263455a7b23SScott Bauer { 1264455a7b23SScott Bauer u32 hsn; 1265*e8b29224SDavid Kozub int err; 1266455a7b23SScott Bauer 1267591c59d1SScott Bauer if (key == NULL && auth != OPAL_ANYBODY_UID) 1268455a7b23SScott Bauer return OPAL_INVAL_PARAM; 1269455a7b23SScott Bauer 1270455a7b23SScott Bauer hsn = GENERIC_HOST_SESSION_NUM; 1271*e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_SMUID_UID], 1272*e8b29224SDavid Kozub opalmethod[OPAL_STARTSESSION]); 1273455a7b23SScott Bauer 1274455a7b23SScott Bauer add_token_u64(&err, dev, hsn); 1275455a7b23SScott Bauer add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH); 1276455a7b23SScott Bauer add_token_u8(&err, dev, 1); 1277455a7b23SScott Bauer 1278455a7b23SScott Bauer switch (auth) { 1279455a7b23SScott Bauer case OPAL_ANYBODY_UID: 1280455a7b23SScott Bauer break; 1281455a7b23SScott Bauer case OPAL_ADMIN1_UID: 1282455a7b23SScott Bauer case OPAL_SID_UID: 1283455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1284455a7b23SScott Bauer add_token_u8(&err, dev, 0); /* HostChallenge */ 1285455a7b23SScott Bauer add_token_bytestring(&err, dev, key, key_len); 1286455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1287455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1288455a7b23SScott Bauer add_token_u8(&err, dev, 3); /* HostSignAuth */ 1289455a7b23SScott Bauer add_token_bytestring(&err, dev, opaluid[auth], 1290455a7b23SScott Bauer OPAL_UID_LENGTH); 1291455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1292455a7b23SScott Bauer break; 1293455a7b23SScott Bauer default: 1294591c59d1SScott Bauer pr_debug("Cannot start Admin SP session with auth %d\n", auth); 1295455a7b23SScott Bauer return OPAL_INVAL_PARAM; 1296455a7b23SScott Bauer } 1297455a7b23SScott Bauer 1298455a7b23SScott Bauer if (err) { 1299591c59d1SScott Bauer pr_debug("Error building start adminsp session command.\n"); 1300455a7b23SScott Bauer return err; 1301455a7b23SScott Bauer } 1302455a7b23SScott Bauer 1303455a7b23SScott Bauer return finalize_and_send(dev, start_opal_session_cont); 1304455a7b23SScott Bauer } 1305455a7b23SScott Bauer 1306eed64951SJon Derrick static int start_anybodyASP_opal_session(struct opal_dev *dev, void *data) 1307455a7b23SScott Bauer { 1308455a7b23SScott Bauer return start_generic_opal_session(dev, OPAL_ANYBODY_UID, 1309455a7b23SScott Bauer OPAL_ADMINSP_UID, NULL, 0); 1310455a7b23SScott Bauer } 1311455a7b23SScott Bauer 1312eed64951SJon Derrick static int start_SIDASP_opal_session(struct opal_dev *dev, void *data) 1313455a7b23SScott Bauer { 1314455a7b23SScott Bauer int ret; 1315455a7b23SScott Bauer const u8 *key = dev->prev_data; 1316455a7b23SScott Bauer 1317455a7b23SScott Bauer if (!key) { 1318eed64951SJon Derrick const struct opal_key *okey = data; 13191e815b33SDavid Kozub 1320455a7b23SScott Bauer ret = start_generic_opal_session(dev, OPAL_SID_UID, 1321455a7b23SScott Bauer OPAL_ADMINSP_UID, 1322455a7b23SScott Bauer okey->key, 1323455a7b23SScott Bauer okey->key_len); 1324455a7b23SScott Bauer } else { 1325455a7b23SScott Bauer ret = start_generic_opal_session(dev, OPAL_SID_UID, 1326455a7b23SScott Bauer OPAL_ADMINSP_UID, 1327455a7b23SScott Bauer key, dev->prev_d_len); 1328455a7b23SScott Bauer kfree(key); 1329455a7b23SScott Bauer dev->prev_data = NULL; 1330455a7b23SScott Bauer } 1331455a7b23SScott Bauer return ret; 1332455a7b23SScott Bauer } 1333455a7b23SScott Bauer 1334eed64951SJon Derrick static int start_admin1LSP_opal_session(struct opal_dev *dev, void *data) 1335455a7b23SScott Bauer { 1336eed64951SJon Derrick struct opal_key *key = data; 13371e815b33SDavid Kozub 1338455a7b23SScott Bauer return start_generic_opal_session(dev, OPAL_ADMIN1_UID, 1339455a7b23SScott Bauer OPAL_LOCKINGSP_UID, 1340455a7b23SScott Bauer key->key, key->key_len); 1341455a7b23SScott Bauer } 1342455a7b23SScott Bauer 1343eed64951SJon Derrick static int start_auth_opal_session(struct opal_dev *dev, void *data) 1344455a7b23SScott Bauer { 1345eed64951SJon Derrick struct opal_session_info *session = data; 1346455a7b23SScott Bauer u8 lk_ul_user[OPAL_UID_LENGTH]; 1347eed64951SJon Derrick size_t keylen = session->opal_key.key_len; 1348455a7b23SScott Bauer int err = 0; 1349455a7b23SScott Bauer 1350455a7b23SScott Bauer u8 *key = session->opal_key.key; 1351455a7b23SScott Bauer u32 hsn = GENERIC_HOST_SESSION_NUM; 1352455a7b23SScott Bauer 1353*e8b29224SDavid Kozub if (session->sum) 1354455a7b23SScott Bauer err = build_locking_user(lk_ul_user, sizeof(lk_ul_user), 1355455a7b23SScott Bauer session->opal_key.lr); 1356*e8b29224SDavid Kozub else if (session->who != OPAL_ADMIN1 && !session->sum) 1357455a7b23SScott Bauer err = build_locking_user(lk_ul_user, sizeof(lk_ul_user), 1358455a7b23SScott Bauer session->who - 1); 1359*e8b29224SDavid Kozub else 1360455a7b23SScott Bauer memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH); 1361455a7b23SScott Bauer 1362*e8b29224SDavid Kozub if (err) 1363*e8b29224SDavid Kozub return err; 1364455a7b23SScott Bauer 1365*e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_SMUID_UID], 1366*e8b29224SDavid Kozub opalmethod[OPAL_STARTSESSION]); 1367*e8b29224SDavid Kozub 1368455a7b23SScott Bauer add_token_u64(&err, dev, hsn); 1369455a7b23SScott Bauer add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID], 1370455a7b23SScott Bauer OPAL_UID_LENGTH); 1371455a7b23SScott Bauer add_token_u8(&err, dev, 1); 1372455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1373455a7b23SScott Bauer add_token_u8(&err, dev, 0); 1374455a7b23SScott Bauer add_token_bytestring(&err, dev, key, keylen); 1375455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1376455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1377455a7b23SScott Bauer add_token_u8(&err, dev, 3); 1378455a7b23SScott Bauer add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH); 1379455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1380455a7b23SScott Bauer 1381455a7b23SScott Bauer if (err) { 1382591c59d1SScott Bauer pr_debug("Error building STARTSESSION command.\n"); 1383455a7b23SScott Bauer return err; 1384455a7b23SScott Bauer } 1385455a7b23SScott Bauer 1386455a7b23SScott Bauer return finalize_and_send(dev, start_opal_session_cont); 1387455a7b23SScott Bauer } 1388455a7b23SScott Bauer 1389eed64951SJon Derrick static int revert_tper(struct opal_dev *dev, void *data) 1390455a7b23SScott Bauer { 1391*e8b29224SDavid Kozub int err; 1392455a7b23SScott Bauer 1393*e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_ADMINSP_UID], 1394*e8b29224SDavid Kozub opalmethod[OPAL_REVERT]); 1395455a7b23SScott Bauer if (err) { 1396591c59d1SScott Bauer pr_debug("Error building REVERT TPER command.\n"); 1397455a7b23SScott Bauer return err; 1398455a7b23SScott Bauer } 1399455a7b23SScott Bauer 1400455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1401455a7b23SScott Bauer } 1402455a7b23SScott Bauer 1403eed64951SJon Derrick static int internal_activate_user(struct opal_dev *dev, void *data) 1404455a7b23SScott Bauer { 1405eed64951SJon Derrick struct opal_session_info *session = data; 1406455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH]; 1407*e8b29224SDavid Kozub int err; 1408455a7b23SScott Bauer 1409455a7b23SScott Bauer memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH); 1410455a7b23SScott Bauer uid[7] = session->who; 1411455a7b23SScott Bauer 1412*e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_SET]); 1413455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1414455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES); 1415455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1416455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1417455a7b23SScott Bauer add_token_u8(&err, dev, 5); /* Enabled */ 1418455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_TRUE); 1419455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1420455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1421455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1422455a7b23SScott Bauer 1423455a7b23SScott Bauer if (err) { 1424591c59d1SScott Bauer pr_debug("Error building Activate UserN command.\n"); 1425455a7b23SScott Bauer return err; 1426455a7b23SScott Bauer } 1427455a7b23SScott Bauer 1428455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1429455a7b23SScott Bauer } 1430455a7b23SScott Bauer 1431eed64951SJon Derrick static int erase_locking_range(struct opal_dev *dev, void *data) 1432455a7b23SScott Bauer { 1433eed64951SJon Derrick struct opal_session_info *session = data; 1434455a7b23SScott Bauer u8 uid[OPAL_UID_LENGTH]; 1435*e8b29224SDavid Kozub int err; 1436455a7b23SScott Bauer 1437455a7b23SScott Bauer if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0) 1438455a7b23SScott Bauer return -ERANGE; 1439455a7b23SScott Bauer 1440*e8b29224SDavid Kozub err = cmd_start(dev, uid, opalmethod[OPAL_ERASE]); 1441455a7b23SScott Bauer 1442455a7b23SScott Bauer if (err) { 1443591c59d1SScott Bauer pr_debug("Error building Erase Locking Range Command.\n"); 1444455a7b23SScott Bauer return err; 1445455a7b23SScott Bauer } 1446455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1447455a7b23SScott Bauer } 1448455a7b23SScott Bauer 1449eed64951SJon Derrick static int set_mbr_done(struct opal_dev *dev, void *data) 1450455a7b23SScott Bauer { 1451eed64951SJon Derrick u8 *mbr_done_tf = data; 1452*e8b29224SDavid Kozub int err; 1453455a7b23SScott Bauer 1454*e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_MBRCONTROL], 1455*e8b29224SDavid Kozub opalmethod[OPAL_SET]); 1456455a7b23SScott Bauer 1457455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1458455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES); 1459455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1460455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1461455a7b23SScott Bauer add_token_u8(&err, dev, 2); /* Done */ 1462eed64951SJon Derrick add_token_u8(&err, dev, *mbr_done_tf); /* Done T or F */ 1463455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1464455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1465455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1466455a7b23SScott Bauer 1467455a7b23SScott Bauer if (err) { 1468591c59d1SScott Bauer pr_debug("Error Building set MBR Done command\n"); 1469455a7b23SScott Bauer return err; 1470455a7b23SScott Bauer } 1471455a7b23SScott Bauer 1472455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1473455a7b23SScott Bauer } 1474455a7b23SScott Bauer 1475eed64951SJon Derrick static int set_mbr_enable_disable(struct opal_dev *dev, void *data) 1476455a7b23SScott Bauer { 1477eed64951SJon Derrick u8 *mbr_en_dis = data; 1478*e8b29224SDavid Kozub int err; 1479455a7b23SScott Bauer 1480*e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_MBRCONTROL], 1481*e8b29224SDavid Kozub opalmethod[OPAL_SET]); 1482455a7b23SScott Bauer 1483455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1484455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES); 1485455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1486455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1487455a7b23SScott Bauer add_token_u8(&err, dev, 1); 1488eed64951SJon Derrick add_token_u8(&err, dev, *mbr_en_dis); 1489455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1490455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1491455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1492455a7b23SScott Bauer 1493455a7b23SScott Bauer if (err) { 1494591c59d1SScott Bauer pr_debug("Error Building set MBR done command\n"); 1495455a7b23SScott Bauer return err; 1496455a7b23SScott Bauer } 1497455a7b23SScott Bauer 1498455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1499455a7b23SScott Bauer } 1500455a7b23SScott Bauer 1501455a7b23SScott Bauer static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid, 1502455a7b23SScott Bauer struct opal_dev *dev) 1503455a7b23SScott Bauer { 1504*e8b29224SDavid Kozub int err; 1505455a7b23SScott Bauer 1506*e8b29224SDavid Kozub err = cmd_start(dev, cpin_uid, opalmethod[OPAL_SET]); 1507455a7b23SScott Bauer 1508455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1509455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES); 1510455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1511455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1512455a7b23SScott Bauer add_token_u8(&err, dev, 3); /* PIN */ 1513455a7b23SScott Bauer add_token_bytestring(&err, dev, key, key_len); 1514455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1515455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1516455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1517455a7b23SScott Bauer 1518455a7b23SScott Bauer return err; 1519455a7b23SScott Bauer } 1520455a7b23SScott Bauer 1521eed64951SJon Derrick static int set_new_pw(struct opal_dev *dev, void *data) 1522455a7b23SScott Bauer { 1523455a7b23SScott Bauer u8 cpin_uid[OPAL_UID_LENGTH]; 1524eed64951SJon Derrick struct opal_session_info *usr = data; 1525455a7b23SScott Bauer 1526455a7b23SScott Bauer memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH); 1527455a7b23SScott Bauer 1528455a7b23SScott Bauer if (usr->who != OPAL_ADMIN1) { 1529455a7b23SScott Bauer cpin_uid[5] = 0x03; 1530455a7b23SScott Bauer if (usr->sum) 1531455a7b23SScott Bauer cpin_uid[7] = usr->opal_key.lr + 1; 1532455a7b23SScott Bauer else 1533455a7b23SScott Bauer cpin_uid[7] = usr->who; 1534455a7b23SScott Bauer } 1535455a7b23SScott Bauer 1536455a7b23SScott Bauer if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len, 1537455a7b23SScott Bauer cpin_uid, dev)) { 1538591c59d1SScott Bauer pr_debug("Error building set password command.\n"); 1539455a7b23SScott Bauer return -ERANGE; 1540455a7b23SScott Bauer } 1541455a7b23SScott Bauer 1542455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1543455a7b23SScott Bauer } 1544455a7b23SScott Bauer 1545eed64951SJon Derrick static int set_sid_cpin_pin(struct opal_dev *dev, void *data) 1546455a7b23SScott Bauer { 1547455a7b23SScott Bauer u8 cpin_uid[OPAL_UID_LENGTH]; 1548eed64951SJon Derrick struct opal_key *key = data; 1549455a7b23SScott Bauer 1550455a7b23SScott Bauer memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH); 1551455a7b23SScott Bauer 1552455a7b23SScott Bauer if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) { 1553591c59d1SScott Bauer pr_debug("Error building Set SID cpin\n"); 1554455a7b23SScott Bauer return -ERANGE; 1555455a7b23SScott Bauer } 1556455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1557455a7b23SScott Bauer } 1558455a7b23SScott Bauer 1559eed64951SJon Derrick static int add_user_to_lr(struct opal_dev *dev, void *data) 1560455a7b23SScott Bauer { 1561455a7b23SScott Bauer u8 lr_buffer[OPAL_UID_LENGTH]; 1562455a7b23SScott Bauer u8 user_uid[OPAL_UID_LENGTH]; 1563eed64951SJon Derrick struct opal_lock_unlock *lkul = data; 1564*e8b29224SDavid Kozub int err; 1565455a7b23SScott Bauer 1566455a7b23SScott Bauer memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED], 1567455a7b23SScott Bauer OPAL_UID_LENGTH); 1568455a7b23SScott Bauer 1569455a7b23SScott Bauer if (lkul->l_state == OPAL_RW) 1570455a7b23SScott Bauer memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED], 1571455a7b23SScott Bauer OPAL_UID_LENGTH); 1572455a7b23SScott Bauer 1573455a7b23SScott Bauer lr_buffer[7] = lkul->session.opal_key.lr; 1574455a7b23SScott Bauer 1575455a7b23SScott Bauer memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH); 1576455a7b23SScott Bauer 1577455a7b23SScott Bauer user_uid[7] = lkul->session.who; 1578455a7b23SScott Bauer 1579*e8b29224SDavid Kozub err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]); 1580455a7b23SScott Bauer 1581455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1582455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES); 1583455a7b23SScott Bauer 1584455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1585455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1586455a7b23SScott Bauer add_token_u8(&err, dev, 3); 1587455a7b23SScott Bauer 1588455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1589455a7b23SScott Bauer 1590455a7b23SScott Bauer 1591455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1592455a7b23SScott Bauer add_token_bytestring(&err, dev, 1593455a7b23SScott Bauer opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF], 1594455a7b23SScott Bauer OPAL_UID_LENGTH/2); 1595455a7b23SScott Bauer add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH); 1596455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1597455a7b23SScott Bauer 1598455a7b23SScott Bauer 1599455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1600455a7b23SScott Bauer add_token_bytestring(&err, dev, 1601455a7b23SScott Bauer opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF], 1602455a7b23SScott Bauer OPAL_UID_LENGTH/2); 1603455a7b23SScott Bauer add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH); 1604455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1605455a7b23SScott Bauer 1606455a7b23SScott Bauer 1607455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1608455a7b23SScott Bauer add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE], 1609455a7b23SScott Bauer OPAL_UID_LENGTH/2); 1610455a7b23SScott Bauer add_token_u8(&err, dev, 1); 1611455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1612455a7b23SScott Bauer 1613455a7b23SScott Bauer 1614455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1615455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1616455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1617455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1618455a7b23SScott Bauer 1619455a7b23SScott Bauer if (err) { 1620591c59d1SScott Bauer pr_debug("Error building add user to locking range command.\n"); 1621455a7b23SScott Bauer return err; 1622455a7b23SScott Bauer } 1623455a7b23SScott Bauer 1624455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1625455a7b23SScott Bauer } 1626455a7b23SScott Bauer 1627eed64951SJon Derrick static int lock_unlock_locking_range(struct opal_dev *dev, void *data) 1628455a7b23SScott Bauer { 1629455a7b23SScott Bauer u8 lr_buffer[OPAL_UID_LENGTH]; 1630eed64951SJon Derrick struct opal_lock_unlock *lkul = data; 1631455a7b23SScott Bauer u8 read_locked = 1, write_locked = 1; 1632455a7b23SScott Bauer int err = 0; 1633455a7b23SScott Bauer 1634455a7b23SScott Bauer if (build_locking_range(lr_buffer, sizeof(lr_buffer), 1635455a7b23SScott Bauer lkul->session.opal_key.lr) < 0) 1636455a7b23SScott Bauer return -ERANGE; 1637455a7b23SScott Bauer 1638455a7b23SScott Bauer switch (lkul->l_state) { 1639455a7b23SScott Bauer case OPAL_RO: 1640455a7b23SScott Bauer read_locked = 0; 1641455a7b23SScott Bauer write_locked = 1; 1642455a7b23SScott Bauer break; 1643455a7b23SScott Bauer case OPAL_RW: 1644455a7b23SScott Bauer read_locked = 0; 1645455a7b23SScott Bauer write_locked = 0; 1646455a7b23SScott Bauer break; 1647455a7b23SScott Bauer case OPAL_LK: 16481e815b33SDavid Kozub /* vars are initialized to locked */ 1649455a7b23SScott Bauer break; 1650455a7b23SScott Bauer default: 1651591c59d1SScott Bauer pr_debug("Tried to set an invalid locking state... returning to uland\n"); 1652455a7b23SScott Bauer return OPAL_INVAL_PARAM; 1653455a7b23SScott Bauer } 1654455a7b23SScott Bauer 1655*e8b29224SDavid Kozub err = cmd_start(dev, lr_buffer, opalmethod[OPAL_SET]); 1656*e8b29224SDavid Kozub 1657455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1658455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_VALUES); 1659455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1660455a7b23SScott Bauer 1661455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1662455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_READLOCKED); 1663455a7b23SScott Bauer add_token_u8(&err, dev, read_locked); 1664455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1665455a7b23SScott Bauer 1666455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1667455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_WRITELOCKED); 1668455a7b23SScott Bauer add_token_u8(&err, dev, write_locked); 1669455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1670455a7b23SScott Bauer 1671455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1672455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1673455a7b23SScott Bauer 1674455a7b23SScott Bauer if (err) { 1675591c59d1SScott Bauer pr_debug("Error building SET command.\n"); 1676455a7b23SScott Bauer return err; 1677455a7b23SScott Bauer } 1678455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1679455a7b23SScott Bauer } 1680455a7b23SScott Bauer 1681455a7b23SScott Bauer 1682eed64951SJon Derrick static int lock_unlock_locking_range_sum(struct opal_dev *dev, void *data) 1683455a7b23SScott Bauer { 1684455a7b23SScott Bauer u8 lr_buffer[OPAL_UID_LENGTH]; 1685455a7b23SScott Bauer u8 read_locked = 1, write_locked = 1; 1686eed64951SJon Derrick struct opal_lock_unlock *lkul = data; 1687455a7b23SScott Bauer int ret; 1688455a7b23SScott Bauer 1689455a7b23SScott Bauer clear_opal_cmd(dev); 1690455a7b23SScott Bauer set_comid(dev, dev->comid); 1691455a7b23SScott Bauer 1692455a7b23SScott Bauer if (build_locking_range(lr_buffer, sizeof(lr_buffer), 1693455a7b23SScott Bauer lkul->session.opal_key.lr) < 0) 1694455a7b23SScott Bauer return -ERANGE; 1695455a7b23SScott Bauer 1696455a7b23SScott Bauer switch (lkul->l_state) { 1697455a7b23SScott Bauer case OPAL_RO: 1698455a7b23SScott Bauer read_locked = 0; 1699455a7b23SScott Bauer write_locked = 1; 1700455a7b23SScott Bauer break; 1701455a7b23SScott Bauer case OPAL_RW: 1702455a7b23SScott Bauer read_locked = 0; 1703455a7b23SScott Bauer write_locked = 0; 1704455a7b23SScott Bauer break; 1705455a7b23SScott Bauer case OPAL_LK: 17061e815b33SDavid Kozub /* vars are initialized to locked */ 1707455a7b23SScott Bauer break; 1708455a7b23SScott Bauer default: 1709591c59d1SScott Bauer pr_debug("Tried to set an invalid locking state.\n"); 1710455a7b23SScott Bauer return OPAL_INVAL_PARAM; 1711455a7b23SScott Bauer } 1712455a7b23SScott Bauer ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1, 1713455a7b23SScott Bauer read_locked, write_locked); 1714455a7b23SScott Bauer 1715455a7b23SScott Bauer if (ret < 0) { 1716591c59d1SScott Bauer pr_debug("Error building SET command.\n"); 1717455a7b23SScott Bauer return ret; 1718455a7b23SScott Bauer } 1719455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1720455a7b23SScott Bauer } 1721455a7b23SScott Bauer 1722eed64951SJon Derrick static int activate_lsp(struct opal_dev *dev, void *data) 1723455a7b23SScott Bauer { 1724eed64951SJon Derrick struct opal_lr_act *opal_act = data; 1725455a7b23SScott Bauer u8 user_lr[OPAL_UID_LENGTH]; 1726455a7b23SScott Bauer u8 uint_3 = 0x83; 1727*e8b29224SDavid Kozub int err, i; 1728455a7b23SScott Bauer 1729*e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID], 1730*e8b29224SDavid Kozub opalmethod[OPAL_ACTIVATE]); 1731455a7b23SScott Bauer 1732455a7b23SScott Bauer if (opal_act->sum) { 1733455a7b23SScott Bauer err = build_locking_range(user_lr, sizeof(user_lr), 1734455a7b23SScott Bauer opal_act->lr[0]); 1735455a7b23SScott Bauer if (err) 1736455a7b23SScott Bauer return err; 1737455a7b23SScott Bauer 1738455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1739455a7b23SScott Bauer add_token_u8(&err, dev, uint_3); 1740455a7b23SScott Bauer add_token_u8(&err, dev, 6); 1741455a7b23SScott Bauer add_token_u8(&err, dev, 0); 1742455a7b23SScott Bauer add_token_u8(&err, dev, 0); 1743455a7b23SScott Bauer 1744455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1745455a7b23SScott Bauer add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH); 1746455a7b23SScott Bauer for (i = 1; i < opal_act->num_lrs; i++) { 1747455a7b23SScott Bauer user_lr[7] = opal_act->lr[i]; 1748455a7b23SScott Bauer add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH); 1749455a7b23SScott Bauer } 1750455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1751455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1752455a7b23SScott Bauer } 1753455a7b23SScott Bauer 1754455a7b23SScott Bauer if (err) { 1755591c59d1SScott Bauer pr_debug("Error building Activate LockingSP command.\n"); 1756455a7b23SScott Bauer return err; 1757455a7b23SScott Bauer } 1758455a7b23SScott Bauer 1759455a7b23SScott Bauer return finalize_and_send(dev, parse_and_check_status); 1760455a7b23SScott Bauer } 1761455a7b23SScott Bauer 1762455a7b23SScott Bauer static int get_lsp_lifecycle_cont(struct opal_dev *dev) 1763455a7b23SScott Bauer { 1764455a7b23SScott Bauer u8 lc_status; 1765455a7b23SScott Bauer int error = 0; 1766455a7b23SScott Bauer 1767455a7b23SScott Bauer error = parse_and_check_status(dev); 1768455a7b23SScott Bauer if (error) 1769455a7b23SScott Bauer return error; 1770455a7b23SScott Bauer 1771455a7b23SScott Bauer lc_status = response_get_u64(&dev->parsed, 4); 17721e815b33SDavid Kozub /* 0x08 is Manufactured Inactive */ 1773455a7b23SScott Bauer /* 0x09 is Manufactured */ 1774455a7b23SScott Bauer if (lc_status != OPAL_MANUFACTURED_INACTIVE) { 1775591c59d1SScott Bauer pr_debug("Couldn't determine the status of the Lifecycle state\n"); 1776455a7b23SScott Bauer return -ENODEV; 1777455a7b23SScott Bauer } 1778455a7b23SScott Bauer 1779455a7b23SScott Bauer return 0; 1780455a7b23SScott Bauer } 1781455a7b23SScott Bauer 1782455a7b23SScott Bauer /* Determine if we're in the Manufactured Inactive or Active state */ 1783eed64951SJon Derrick static int get_lsp_lifecycle(struct opal_dev *dev, void *data) 1784455a7b23SScott Bauer { 1785*e8b29224SDavid Kozub int err; 1786455a7b23SScott Bauer 1787*e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_LOCKINGSP_UID], 1788*e8b29224SDavid Kozub opalmethod[OPAL_GET]); 1789455a7b23SScott Bauer 1790455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1791455a7b23SScott Bauer 1792455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1793455a7b23SScott Bauer add_token_u8(&err, dev, 3); /* Start Column */ 1794455a7b23SScott Bauer add_token_u8(&err, dev, 6); /* Lifecycle Column */ 1795455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1796455a7b23SScott Bauer 1797455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1798455a7b23SScott Bauer add_token_u8(&err, dev, 4); /* End Column */ 1799455a7b23SScott Bauer add_token_u8(&err, dev, 6); /* Lifecycle Column */ 1800455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1801455a7b23SScott Bauer 1802455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1803455a7b23SScott Bauer 1804455a7b23SScott Bauer if (err) { 1805591c59d1SScott Bauer pr_debug("Error Building GET Lifecycle Status command\n"); 1806455a7b23SScott Bauer return err; 1807455a7b23SScott Bauer } 1808455a7b23SScott Bauer 1809455a7b23SScott Bauer return finalize_and_send(dev, get_lsp_lifecycle_cont); 1810455a7b23SScott Bauer } 1811455a7b23SScott Bauer 1812455a7b23SScott Bauer static int get_msid_cpin_pin_cont(struct opal_dev *dev) 1813455a7b23SScott Bauer { 1814455a7b23SScott Bauer const char *msid_pin; 1815455a7b23SScott Bauer size_t strlen; 1816455a7b23SScott Bauer int error = 0; 1817455a7b23SScott Bauer 1818455a7b23SScott Bauer error = parse_and_check_status(dev); 1819455a7b23SScott Bauer if (error) 1820455a7b23SScott Bauer return error; 1821455a7b23SScott Bauer 1822455a7b23SScott Bauer strlen = response_get_string(&dev->parsed, 4, &msid_pin); 1823455a7b23SScott Bauer if (!msid_pin) { 1824591c59d1SScott Bauer pr_debug("%s: Couldn't extract PIN from response\n", __func__); 1825455a7b23SScott Bauer return OPAL_INVAL_PARAM; 1826455a7b23SScott Bauer } 1827455a7b23SScott Bauer 1828455a7b23SScott Bauer dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL); 1829455a7b23SScott Bauer if (!dev->prev_data) 1830455a7b23SScott Bauer return -ENOMEM; 1831455a7b23SScott Bauer 1832455a7b23SScott Bauer dev->prev_d_len = strlen; 1833455a7b23SScott Bauer 1834455a7b23SScott Bauer return 0; 1835455a7b23SScott Bauer } 1836455a7b23SScott Bauer 1837eed64951SJon Derrick static int get_msid_cpin_pin(struct opal_dev *dev, void *data) 1838455a7b23SScott Bauer { 1839*e8b29224SDavid Kozub int err; 1840455a7b23SScott Bauer 1841*e8b29224SDavid Kozub err = cmd_start(dev, opaluid[OPAL_C_PIN_MSID], 1842*e8b29224SDavid Kozub opalmethod[OPAL_GET]); 1843455a7b23SScott Bauer 1844455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTLIST); 1845455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1846455a7b23SScott Bauer add_token_u8(&err, dev, 3); /* Start Column */ 1847455a7b23SScott Bauer add_token_u8(&err, dev, 3); /* PIN */ 1848455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1849455a7b23SScott Bauer 1850455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_STARTNAME); 1851455a7b23SScott Bauer add_token_u8(&err, dev, 4); /* End Column */ 1852455a7b23SScott Bauer add_token_u8(&err, dev, 3); /* Lifecycle Column */ 1853455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDNAME); 1854455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDLIST); 1855455a7b23SScott Bauer 1856455a7b23SScott Bauer if (err) { 1857591c59d1SScott Bauer pr_debug("Error building Get MSID CPIN PIN command.\n"); 1858455a7b23SScott Bauer return err; 1859455a7b23SScott Bauer } 1860455a7b23SScott Bauer 1861455a7b23SScott Bauer return finalize_and_send(dev, get_msid_cpin_pin_cont); 1862455a7b23SScott Bauer } 1863455a7b23SScott Bauer 1864eed64951SJon Derrick static int end_opal_session(struct opal_dev *dev, void *data) 1865455a7b23SScott Bauer { 1866455a7b23SScott Bauer int err = 0; 1867455a7b23SScott Bauer 1868455a7b23SScott Bauer clear_opal_cmd(dev); 1869455a7b23SScott Bauer set_comid(dev, dev->comid); 1870455a7b23SScott Bauer add_token_u8(&err, dev, OPAL_ENDOFSESSION); 1871eed64951SJon Derrick 1872eed64951SJon Derrick if (err < 0) 1873455a7b23SScott Bauer return err; 1874455a7b23SScott Bauer return finalize_and_send(dev, end_session_cont); 1875455a7b23SScott Bauer } 1876455a7b23SScott Bauer 1877455a7b23SScott Bauer static int end_opal_session_error(struct opal_dev *dev) 1878455a7b23SScott Bauer { 1879eed64951SJon Derrick const struct opal_step error_end_session[] = { 1880eed64951SJon Derrick { end_opal_session, }, 1881eed64951SJon Derrick { NULL, } 1882455a7b23SScott Bauer }; 1883eed64951SJon Derrick dev->steps = error_end_session; 1884455a7b23SScott Bauer return next(dev); 1885455a7b23SScott Bauer } 1886455a7b23SScott Bauer 1887455a7b23SScott Bauer static inline void setup_opal_dev(struct opal_dev *dev, 1888eed64951SJon Derrick const struct opal_step *steps) 1889455a7b23SScott Bauer { 1890eed64951SJon Derrick dev->steps = steps; 1891455a7b23SScott Bauer dev->tsn = 0; 1892455a7b23SScott Bauer dev->hsn = 0; 1893455a7b23SScott Bauer dev->prev_data = NULL; 1894455a7b23SScott Bauer } 1895455a7b23SScott Bauer 1896455a7b23SScott Bauer static int check_opal_support(struct opal_dev *dev) 1897455a7b23SScott Bauer { 1898eed64951SJon Derrick const struct opal_step steps[] = { 1899eed64951SJon Derrick { opal_discovery0, }, 1900eed64951SJon Derrick { NULL, } 1901455a7b23SScott Bauer }; 1902455a7b23SScott Bauer int ret; 1903455a7b23SScott Bauer 1904455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 1905eed64951SJon Derrick setup_opal_dev(dev, steps); 1906455a7b23SScott Bauer ret = next(dev); 1907455a7b23SScott Bauer dev->supported = !ret; 1908455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 1909455a7b23SScott Bauer return ret; 1910455a7b23SScott Bauer } 1911455a7b23SScott Bauer 19127d6d1578SScott Bauer static void clean_opal_dev(struct opal_dev *dev) 19137d6d1578SScott Bauer { 19147d6d1578SScott Bauer 19157d6d1578SScott Bauer struct opal_suspend_data *suspend, *next; 19167d6d1578SScott Bauer 19177d6d1578SScott Bauer mutex_lock(&dev->dev_lock); 19187d6d1578SScott Bauer list_for_each_entry_safe(suspend, next, &dev->unlk_lst, node) { 19197d6d1578SScott Bauer list_del(&suspend->node); 19207d6d1578SScott Bauer kfree(suspend); 19217d6d1578SScott Bauer } 19227d6d1578SScott Bauer mutex_unlock(&dev->dev_lock); 19237d6d1578SScott Bauer } 19247d6d1578SScott Bauer 19257d6d1578SScott Bauer void free_opal_dev(struct opal_dev *dev) 19267d6d1578SScott Bauer { 19277d6d1578SScott Bauer if (!dev) 19287d6d1578SScott Bauer return; 19297d6d1578SScott Bauer clean_opal_dev(dev); 19307d6d1578SScott Bauer kfree(dev); 19317d6d1578SScott Bauer } 19327d6d1578SScott Bauer EXPORT_SYMBOL(free_opal_dev); 19337d6d1578SScott Bauer 19344f1244c8SChristoph Hellwig struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv) 1935455a7b23SScott Bauer { 19364f1244c8SChristoph Hellwig struct opal_dev *dev; 19374f1244c8SChristoph Hellwig 19384f1244c8SChristoph Hellwig dev = kmalloc(sizeof(*dev), GFP_KERNEL); 19394f1244c8SChristoph Hellwig if (!dev) 19404f1244c8SChristoph Hellwig return NULL; 19414f1244c8SChristoph Hellwig 19424f1244c8SChristoph Hellwig INIT_LIST_HEAD(&dev->unlk_lst); 19434f1244c8SChristoph Hellwig mutex_init(&dev->dev_lock); 19444f1244c8SChristoph Hellwig dev->data = data; 19454f1244c8SChristoph Hellwig dev->send_recv = send_recv; 19464f1244c8SChristoph Hellwig if (check_opal_support(dev) != 0) { 1947f5b37b7cSChristoph Hellwig pr_debug("Opal is not supported on this device\n"); 19484f1244c8SChristoph Hellwig kfree(dev); 19494f1244c8SChristoph Hellwig return NULL; 19504f1244c8SChristoph Hellwig } 19514f1244c8SChristoph Hellwig return dev; 1952455a7b23SScott Bauer } 1953455a7b23SScott Bauer EXPORT_SYMBOL(init_opal_dev); 1954455a7b23SScott Bauer 1955455a7b23SScott Bauer static int opal_secure_erase_locking_range(struct opal_dev *dev, 1956455a7b23SScott Bauer struct opal_session_info *opal_session) 1957455a7b23SScott Bauer { 1958eed64951SJon Derrick const struct opal_step erase_steps[] = { 1959eed64951SJon Derrick { opal_discovery0, }, 1960eed64951SJon Derrick { start_auth_opal_session, opal_session }, 1961eed64951SJon Derrick { get_active_key, &opal_session->opal_key.lr }, 1962eed64951SJon Derrick { gen_key, }, 1963eed64951SJon Derrick { end_opal_session, }, 1964eed64951SJon Derrick { NULL, } 1965455a7b23SScott Bauer }; 1966455a7b23SScott Bauer int ret; 1967455a7b23SScott Bauer 1968455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 1969eed64951SJon Derrick setup_opal_dev(dev, erase_steps); 1970455a7b23SScott Bauer ret = next(dev); 1971455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 1972455a7b23SScott Bauer return ret; 1973455a7b23SScott Bauer } 1974455a7b23SScott Bauer 1975455a7b23SScott Bauer static int opal_erase_locking_range(struct opal_dev *dev, 1976455a7b23SScott Bauer struct opal_session_info *opal_session) 1977455a7b23SScott Bauer { 1978eed64951SJon Derrick const struct opal_step erase_steps[] = { 1979eed64951SJon Derrick { opal_discovery0, }, 1980eed64951SJon Derrick { start_auth_opal_session, opal_session }, 1981eed64951SJon Derrick { erase_locking_range, opal_session }, 1982eed64951SJon Derrick { end_opal_session, }, 1983eed64951SJon Derrick { NULL, } 1984455a7b23SScott Bauer }; 1985455a7b23SScott Bauer int ret; 1986455a7b23SScott Bauer 1987455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 1988eed64951SJon Derrick setup_opal_dev(dev, erase_steps); 1989455a7b23SScott Bauer ret = next(dev); 1990455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 1991455a7b23SScott Bauer return ret; 1992455a7b23SScott Bauer } 1993455a7b23SScott Bauer 1994455a7b23SScott Bauer static int opal_enable_disable_shadow_mbr(struct opal_dev *dev, 1995455a7b23SScott Bauer struct opal_mbr_data *opal_mbr) 1996455a7b23SScott Bauer { 199778bf4735SDavid Kozub u8 enable_disable = opal_mbr->enable_disable == OPAL_MBR_ENABLE ? 199878bf4735SDavid Kozub OPAL_TRUE : OPAL_FALSE; 199978bf4735SDavid Kozub 2000eed64951SJon Derrick const struct opal_step mbr_steps[] = { 2001eed64951SJon Derrick { opal_discovery0, }, 2002eed64951SJon Derrick { start_admin1LSP_opal_session, &opal_mbr->key }, 200378bf4735SDavid Kozub { set_mbr_done, &enable_disable }, 2004eed64951SJon Derrick { end_opal_session, }, 2005eed64951SJon Derrick { start_admin1LSP_opal_session, &opal_mbr->key }, 200678bf4735SDavid Kozub { set_mbr_enable_disable, &enable_disable }, 2007eed64951SJon Derrick { end_opal_session, }, 2008eed64951SJon Derrick { NULL, } 2009455a7b23SScott Bauer }; 2010455a7b23SScott Bauer int ret; 2011455a7b23SScott Bauer 2012455a7b23SScott Bauer if (opal_mbr->enable_disable != OPAL_MBR_ENABLE && 2013455a7b23SScott Bauer opal_mbr->enable_disable != OPAL_MBR_DISABLE) 2014455a7b23SScott Bauer return -EINVAL; 2015455a7b23SScott Bauer 2016455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2017eed64951SJon Derrick setup_opal_dev(dev, mbr_steps); 2018455a7b23SScott Bauer ret = next(dev); 2019455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2020455a7b23SScott Bauer return ret; 2021455a7b23SScott Bauer } 2022455a7b23SScott Bauer 2023455a7b23SScott Bauer static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk) 2024455a7b23SScott Bauer { 2025455a7b23SScott Bauer struct opal_suspend_data *suspend; 2026455a7b23SScott Bauer 2027455a7b23SScott Bauer suspend = kzalloc(sizeof(*suspend), GFP_KERNEL); 2028455a7b23SScott Bauer if (!suspend) 2029455a7b23SScott Bauer return -ENOMEM; 2030455a7b23SScott Bauer 2031455a7b23SScott Bauer suspend->unlk = *lk_unlk; 2032455a7b23SScott Bauer suspend->lr = lk_unlk->session.opal_key.lr; 2033455a7b23SScott Bauer 2034455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2035455a7b23SScott Bauer setup_opal_dev(dev, NULL); 2036455a7b23SScott Bauer add_suspend_info(dev, suspend); 2037455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2038455a7b23SScott Bauer return 0; 2039455a7b23SScott Bauer } 2040455a7b23SScott Bauer 2041455a7b23SScott Bauer static int opal_add_user_to_lr(struct opal_dev *dev, 2042455a7b23SScott Bauer struct opal_lock_unlock *lk_unlk) 2043455a7b23SScott Bauer { 2044eed64951SJon Derrick const struct opal_step steps[] = { 2045eed64951SJon Derrick { opal_discovery0, }, 2046eed64951SJon Derrick { start_admin1LSP_opal_session, &lk_unlk->session.opal_key }, 2047eed64951SJon Derrick { add_user_to_lr, lk_unlk }, 2048eed64951SJon Derrick { end_opal_session, }, 2049eed64951SJon Derrick { NULL, } 2050455a7b23SScott Bauer }; 2051455a7b23SScott Bauer int ret; 2052455a7b23SScott Bauer 2053455a7b23SScott Bauer if (lk_unlk->l_state != OPAL_RO && 2054455a7b23SScott Bauer lk_unlk->l_state != OPAL_RW) { 2055591c59d1SScott Bauer pr_debug("Locking state was not RO or RW\n"); 2056455a7b23SScott Bauer return -EINVAL; 2057455a7b23SScott Bauer } 2058b0bfdfc2SJon Derrick if (lk_unlk->session.who < OPAL_USER1 || 2059455a7b23SScott Bauer lk_unlk->session.who > OPAL_USER9) { 2060591c59d1SScott Bauer pr_debug("Authority was not within the range of users: %d\n", 2061455a7b23SScott Bauer lk_unlk->session.who); 2062455a7b23SScott Bauer return -EINVAL; 2063455a7b23SScott Bauer } 2064455a7b23SScott Bauer if (lk_unlk->session.sum) { 2065591c59d1SScott Bauer pr_debug("%s not supported in sum. Use setup locking range\n", 2066455a7b23SScott Bauer __func__); 2067455a7b23SScott Bauer return -EINVAL; 2068455a7b23SScott Bauer } 2069455a7b23SScott Bauer 2070455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2071eed64951SJon Derrick setup_opal_dev(dev, steps); 2072455a7b23SScott Bauer ret = next(dev); 2073455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2074455a7b23SScott Bauer return ret; 2075455a7b23SScott Bauer } 2076455a7b23SScott Bauer 2077455a7b23SScott Bauer static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal) 2078455a7b23SScott Bauer { 2079eed64951SJon Derrick const struct opal_step revert_steps[] = { 2080eed64951SJon Derrick { opal_discovery0, }, 2081eed64951SJon Derrick { start_SIDASP_opal_session, opal }, 2082eed64951SJon Derrick { revert_tper, }, /* controller will terminate session */ 2083eed64951SJon Derrick { NULL, } 2084455a7b23SScott Bauer }; 2085455a7b23SScott Bauer int ret; 2086455a7b23SScott Bauer 2087455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2088eed64951SJon Derrick setup_opal_dev(dev, revert_steps); 2089455a7b23SScott Bauer ret = next(dev); 2090455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 20917d6d1578SScott Bauer 20927d6d1578SScott Bauer /* 20937d6d1578SScott Bauer * If we successfully reverted lets clean 20947d6d1578SScott Bauer * any saved locking ranges. 20957d6d1578SScott Bauer */ 20967d6d1578SScott Bauer if (!ret) 20977d6d1578SScott Bauer clean_opal_dev(dev); 20987d6d1578SScott Bauer 2099455a7b23SScott Bauer return ret; 2100455a7b23SScott Bauer } 2101455a7b23SScott Bauer 2102eed64951SJon Derrick static int __opal_lock_unlock(struct opal_dev *dev, 2103eed64951SJon Derrick struct opal_lock_unlock *lk_unlk) 2104455a7b23SScott Bauer { 2105eed64951SJon Derrick const struct opal_step unlock_steps[] = { 2106eed64951SJon Derrick { opal_discovery0, }, 2107eed64951SJon Derrick { start_auth_opal_session, &lk_unlk->session }, 2108eed64951SJon Derrick { lock_unlock_locking_range, lk_unlk }, 2109eed64951SJon Derrick { end_opal_session, }, 2110eed64951SJon Derrick { NULL, } 2111eed64951SJon Derrick }; 2112eed64951SJon Derrick const struct opal_step unlock_sum_steps[] = { 2113eed64951SJon Derrick { opal_discovery0, }, 2114eed64951SJon Derrick { start_auth_opal_session, &lk_unlk->session }, 2115eed64951SJon Derrick { lock_unlock_locking_range_sum, lk_unlk }, 2116eed64951SJon Derrick { end_opal_session, }, 2117eed64951SJon Derrick { NULL, } 2118455a7b23SScott Bauer }; 2119455a7b23SScott Bauer 2120eed64951SJon Derrick dev->steps = lk_unlk->session.sum ? unlock_sum_steps : unlock_steps; 2121455a7b23SScott Bauer return next(dev); 2122455a7b23SScott Bauer } 2123455a7b23SScott Bauer 2124dbec491bSScott Bauer static int __opal_set_mbr_done(struct opal_dev *dev, struct opal_key *key) 2125dbec491bSScott Bauer { 212678bf4735SDavid Kozub u8 mbr_done_tf = OPAL_TRUE; 2127dbec491bSScott Bauer const struct opal_step mbrdone_step[] = { 2128dbec491bSScott Bauer { opal_discovery0, }, 2129dbec491bSScott Bauer { start_admin1LSP_opal_session, key }, 2130dbec491bSScott Bauer { set_mbr_done, &mbr_done_tf }, 2131dbec491bSScott Bauer { end_opal_session, }, 2132dbec491bSScott Bauer { NULL, } 2133dbec491bSScott Bauer }; 2134dbec491bSScott Bauer 2135dbec491bSScott Bauer dev->steps = mbrdone_step; 2136dbec491bSScott Bauer return next(dev); 2137dbec491bSScott Bauer } 2138dbec491bSScott Bauer 2139eed64951SJon Derrick static int opal_lock_unlock(struct opal_dev *dev, 2140eed64951SJon Derrick struct opal_lock_unlock *lk_unlk) 2141455a7b23SScott Bauer { 2142455a7b23SScott Bauer int ret; 2143455a7b23SScott Bauer 2144455a7b23SScott Bauer if (lk_unlk->session.who < OPAL_ADMIN1 || 2145455a7b23SScott Bauer lk_unlk->session.who > OPAL_USER9) 2146455a7b23SScott Bauer return -EINVAL; 2147455a7b23SScott Bauer 2148455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2149eed64951SJon Derrick ret = __opal_lock_unlock(dev, lk_unlk); 2150455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2151455a7b23SScott Bauer return ret; 2152455a7b23SScott Bauer } 2153455a7b23SScott Bauer 2154455a7b23SScott Bauer static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal) 2155455a7b23SScott Bauer { 2156eed64951SJon Derrick const struct opal_step owner_steps[] = { 2157eed64951SJon Derrick { opal_discovery0, }, 2158eed64951SJon Derrick { start_anybodyASP_opal_session, }, 2159eed64951SJon Derrick { get_msid_cpin_pin, }, 2160eed64951SJon Derrick { end_opal_session, }, 2161eed64951SJon Derrick { start_SIDASP_opal_session, opal }, 2162eed64951SJon Derrick { set_sid_cpin_pin, opal }, 2163eed64951SJon Derrick { end_opal_session, }, 2164eed64951SJon Derrick { NULL, } 2165455a7b23SScott Bauer }; 2166455a7b23SScott Bauer int ret; 2167455a7b23SScott Bauer 2168455a7b23SScott Bauer if (!dev) 2169455a7b23SScott Bauer return -ENODEV; 2170455a7b23SScott Bauer 2171455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2172eed64951SJon Derrick setup_opal_dev(dev, owner_steps); 2173455a7b23SScott Bauer ret = next(dev); 2174455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2175455a7b23SScott Bauer return ret; 2176455a7b23SScott Bauer } 2177455a7b23SScott Bauer 21781e815b33SDavid Kozub static int opal_activate_lsp(struct opal_dev *dev, 21791e815b33SDavid Kozub struct opal_lr_act *opal_lr_act) 2180455a7b23SScott Bauer { 2181eed64951SJon Derrick const struct opal_step active_steps[] = { 2182eed64951SJon Derrick { opal_discovery0, }, 2183eed64951SJon Derrick { start_SIDASP_opal_session, &opal_lr_act->key }, 2184eed64951SJon Derrick { get_lsp_lifecycle, }, 2185eed64951SJon Derrick { activate_lsp, opal_lr_act }, 2186eed64951SJon Derrick { end_opal_session, }, 2187eed64951SJon Derrick { NULL, } 2188455a7b23SScott Bauer }; 2189455a7b23SScott Bauer int ret; 2190455a7b23SScott Bauer 2191455a7b23SScott Bauer if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS) 2192455a7b23SScott Bauer return -EINVAL; 2193455a7b23SScott Bauer 2194455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2195eed64951SJon Derrick setup_opal_dev(dev, active_steps); 2196455a7b23SScott Bauer ret = next(dev); 2197455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2198455a7b23SScott Bauer return ret; 2199455a7b23SScott Bauer } 2200455a7b23SScott Bauer 2201455a7b23SScott Bauer static int opal_setup_locking_range(struct opal_dev *dev, 2202455a7b23SScott Bauer struct opal_user_lr_setup *opal_lrs) 2203455a7b23SScott Bauer { 2204eed64951SJon Derrick const struct opal_step lr_steps[] = { 2205eed64951SJon Derrick { opal_discovery0, }, 2206eed64951SJon Derrick { start_auth_opal_session, &opal_lrs->session }, 2207eed64951SJon Derrick { setup_locking_range, opal_lrs }, 2208eed64951SJon Derrick { end_opal_session, }, 2209eed64951SJon Derrick { NULL, } 2210455a7b23SScott Bauer }; 2211455a7b23SScott Bauer int ret; 2212455a7b23SScott Bauer 2213455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2214eed64951SJon Derrick setup_opal_dev(dev, lr_steps); 2215455a7b23SScott Bauer ret = next(dev); 2216455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2217455a7b23SScott Bauer return ret; 2218455a7b23SScott Bauer } 2219455a7b23SScott Bauer 2220455a7b23SScott Bauer static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw) 2221455a7b23SScott Bauer { 2222eed64951SJon Derrick const struct opal_step pw_steps[] = { 2223eed64951SJon Derrick { opal_discovery0, }, 2224eed64951SJon Derrick { start_auth_opal_session, &opal_pw->session }, 2225eed64951SJon Derrick { set_new_pw, &opal_pw->new_user_pw }, 2226eed64951SJon Derrick { end_opal_session, }, 2227eed64951SJon Derrick { NULL } 2228455a7b23SScott Bauer }; 2229455a7b23SScott Bauer int ret; 2230455a7b23SScott Bauer 2231455a7b23SScott Bauer if (opal_pw->session.who < OPAL_ADMIN1 || 2232455a7b23SScott Bauer opal_pw->session.who > OPAL_USER9 || 2233455a7b23SScott Bauer opal_pw->new_user_pw.who < OPAL_ADMIN1 || 2234455a7b23SScott Bauer opal_pw->new_user_pw.who > OPAL_USER9) 2235455a7b23SScott Bauer return -EINVAL; 2236455a7b23SScott Bauer 2237455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2238eed64951SJon Derrick setup_opal_dev(dev, pw_steps); 2239455a7b23SScott Bauer ret = next(dev); 2240455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2241455a7b23SScott Bauer return ret; 2242455a7b23SScott Bauer } 2243455a7b23SScott Bauer 2244455a7b23SScott Bauer static int opal_activate_user(struct opal_dev *dev, 2245455a7b23SScott Bauer struct opal_session_info *opal_session) 2246455a7b23SScott Bauer { 2247eed64951SJon Derrick const struct opal_step act_steps[] = { 2248eed64951SJon Derrick { opal_discovery0, }, 2249eed64951SJon Derrick { start_admin1LSP_opal_session, &opal_session->opal_key }, 2250eed64951SJon Derrick { internal_activate_user, opal_session }, 2251eed64951SJon Derrick { end_opal_session, }, 2252eed64951SJon Derrick { NULL, } 2253455a7b23SScott Bauer }; 2254455a7b23SScott Bauer int ret; 2255455a7b23SScott Bauer 2256455a7b23SScott Bauer /* We can't activate Admin1 it's active as manufactured */ 2257b0bfdfc2SJon Derrick if (opal_session->who < OPAL_USER1 || 2258455a7b23SScott Bauer opal_session->who > OPAL_USER9) { 2259591c59d1SScott Bauer pr_debug("Who was not a valid user: %d\n", opal_session->who); 2260455a7b23SScott Bauer return -EINVAL; 2261455a7b23SScott Bauer } 2262455a7b23SScott Bauer 2263455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2264eed64951SJon Derrick setup_opal_dev(dev, act_steps); 2265455a7b23SScott Bauer ret = next(dev); 2266455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2267455a7b23SScott Bauer return ret; 2268455a7b23SScott Bauer } 2269455a7b23SScott Bauer 2270455a7b23SScott Bauer bool opal_unlock_from_suspend(struct opal_dev *dev) 2271455a7b23SScott Bauer { 2272455a7b23SScott Bauer struct opal_suspend_data *suspend; 2273455a7b23SScott Bauer bool was_failure = false; 2274455a7b23SScott Bauer int ret = 0; 2275455a7b23SScott Bauer 2276455a7b23SScott Bauer if (!dev) 2277455a7b23SScott Bauer return false; 2278455a7b23SScott Bauer if (!dev->supported) 2279455a7b23SScott Bauer return false; 2280455a7b23SScott Bauer 2281455a7b23SScott Bauer mutex_lock(&dev->dev_lock); 2282455a7b23SScott Bauer setup_opal_dev(dev, NULL); 2283455a7b23SScott Bauer 2284455a7b23SScott Bauer list_for_each_entry(suspend, &dev->unlk_lst, node) { 2285455a7b23SScott Bauer dev->tsn = 0; 2286455a7b23SScott Bauer dev->hsn = 0; 2287455a7b23SScott Bauer 2288eed64951SJon Derrick ret = __opal_lock_unlock(dev, &suspend->unlk); 2289455a7b23SScott Bauer if (ret) { 2290591c59d1SScott Bauer pr_debug("Failed to unlock LR %hhu with sum %d\n", 2291455a7b23SScott Bauer suspend->unlk.session.opal_key.lr, 2292455a7b23SScott Bauer suspend->unlk.session.sum); 2293455a7b23SScott Bauer was_failure = true; 2294455a7b23SScott Bauer } 2295dbec491bSScott Bauer if (dev->mbr_enabled) { 2296dbec491bSScott Bauer ret = __opal_set_mbr_done(dev, &suspend->unlk.session.opal_key); 2297dbec491bSScott Bauer if (ret) 2298dbec491bSScott Bauer pr_debug("Failed to set MBR Done in S3 resume\n"); 2299dbec491bSScott Bauer } 2300455a7b23SScott Bauer } 2301455a7b23SScott Bauer mutex_unlock(&dev->dev_lock); 2302455a7b23SScott Bauer return was_failure; 2303455a7b23SScott Bauer } 2304455a7b23SScott Bauer EXPORT_SYMBOL(opal_unlock_from_suspend); 2305455a7b23SScott Bauer 2306e225c20eSScott Bauer int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg) 2307455a7b23SScott Bauer { 2308e225c20eSScott Bauer void *p; 2309e225c20eSScott Bauer int ret = -ENOTTY; 2310455a7b23SScott Bauer 2311455a7b23SScott Bauer if (!capable(CAP_SYS_ADMIN)) 2312455a7b23SScott Bauer return -EACCES; 23134f1244c8SChristoph Hellwig if (!dev) 23144f1244c8SChristoph Hellwig return -ENOTSUPP; 2315591c59d1SScott Bauer if (!dev->supported) 2316455a7b23SScott Bauer return -ENOTSUPP; 2317455a7b23SScott Bauer 2318e225c20eSScott Bauer p = memdup_user(arg, _IOC_SIZE(cmd)); 2319e225c20eSScott Bauer if (IS_ERR(p)) 2320e225c20eSScott Bauer return PTR_ERR(p); 2321e225c20eSScott Bauer 2322455a7b23SScott Bauer switch (cmd) { 2323e225c20eSScott Bauer case IOC_OPAL_SAVE: 2324e225c20eSScott Bauer ret = opal_save(dev, p); 2325e225c20eSScott Bauer break; 2326e225c20eSScott Bauer case IOC_OPAL_LOCK_UNLOCK: 2327e225c20eSScott Bauer ret = opal_lock_unlock(dev, p); 2328e225c20eSScott Bauer break; 2329e225c20eSScott Bauer case IOC_OPAL_TAKE_OWNERSHIP: 2330e225c20eSScott Bauer ret = opal_take_ownership(dev, p); 2331e225c20eSScott Bauer break; 2332e225c20eSScott Bauer case IOC_OPAL_ACTIVATE_LSP: 2333e225c20eSScott Bauer ret = opal_activate_lsp(dev, p); 2334e225c20eSScott Bauer break; 2335e225c20eSScott Bauer case IOC_OPAL_SET_PW: 2336e225c20eSScott Bauer ret = opal_set_new_pw(dev, p); 2337e225c20eSScott Bauer break; 2338e225c20eSScott Bauer case IOC_OPAL_ACTIVATE_USR: 2339e225c20eSScott Bauer ret = opal_activate_user(dev, p); 2340e225c20eSScott Bauer break; 2341e225c20eSScott Bauer case IOC_OPAL_REVERT_TPR: 2342e225c20eSScott Bauer ret = opal_reverttper(dev, p); 2343e225c20eSScott Bauer break; 2344e225c20eSScott Bauer case IOC_OPAL_LR_SETUP: 2345e225c20eSScott Bauer ret = opal_setup_locking_range(dev, p); 2346e225c20eSScott Bauer break; 2347e225c20eSScott Bauer case IOC_OPAL_ADD_USR_TO_LR: 2348e225c20eSScott Bauer ret = opal_add_user_to_lr(dev, p); 2349e225c20eSScott Bauer break; 2350e225c20eSScott Bauer case IOC_OPAL_ENABLE_DISABLE_MBR: 2351e225c20eSScott Bauer ret = opal_enable_disable_shadow_mbr(dev, p); 2352e225c20eSScott Bauer break; 2353e225c20eSScott Bauer case IOC_OPAL_ERASE_LR: 2354e225c20eSScott Bauer ret = opal_erase_locking_range(dev, p); 2355e225c20eSScott Bauer break; 2356e225c20eSScott Bauer case IOC_OPAL_SECURE_ERASE_LR: 2357e225c20eSScott Bauer ret = opal_secure_erase_locking_range(dev, p); 2358e225c20eSScott Bauer break; 2359455a7b23SScott Bauer default: 2360591c59d1SScott Bauer break; 2361455a7b23SScott Bauer } 2362e225c20eSScott Bauer 2363e225c20eSScott Bauer kfree(p); 2364e225c20eSScott Bauer return ret; 2365455a7b23SScott Bauer } 2366455a7b23SScott Bauer EXPORT_SYMBOL_GPL(sed_ioctl); 2367