// SPDX-License-Identifier: GPL-2.0/* * Copyright © 2016 Intel Corporation * * Authors: * Scott Bauer <scott.bauer@intel.com> * Rafael Antognolli <rafael.antognolli@intel.com> */ #define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt #include <linux/delay.h>#include <linux/device.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/blkdev.h>#include <linux/slab.h>#include <linux/uaccess.h>#include <uapi/linux/sed-opal.h>#include <linux/sed-opal.h>#include <linux/sed-opal-key.h>#include <linux/string.h>#include <linux/kdev_t.h>#include <linux/key.h>#include <linux/key-type.h>#include <keys/user-type.h> #include "opal_proto.h" #define IO_BUFFER_LENGTH 2048#define MAX_TOKS 64 /* Number of bytes needed by cmd_finalize. */#define CMD_FINALIZE_BYTES_NEEDED 7 static struct key *sed_opal_keyring; struct opal_step { int (*fn)(struct opal_dev *dev, void *data); void *data;};typedef int (cont_fn)(struct opal_dev *dev); enum opal_atom_width { OPAL_WIDTH_TINY, OPAL_WIDTH_SHORT, OPAL_WIDTH_MEDIUM, OPAL_WIDTH_LONG, OPAL_WIDTH_TOKEN}; /* * On the parsed response, we don't store again the toks that are already * stored in the response buffer. Instead, for each token, we just store a * pointer to the position in the buffer where the token starts, and the size * of the token in bytes. */struct opal_resp_tok { const u8 *pos; size_t len; enum opal_response_token type; enum opal_atom_width width; union { u64 u; s64 s; } stored;}; /* * From the response header it's not possible to know how many tokens there are * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later * if we start dealing with messages that have more than that, we can increase * this number. This is done to avoid having to make two passes through the * response, the first one counting how many tokens we have and the second one * actually storing the positions. */struct parsed_resp { int num; struct opal_resp_tok toks[MAX_TOKS];}; struct opal_dev { u32 flags; void *data; sec_send_recv *send_recv; struct mutex dev_lock; u16 comid; u32 hsn; u32 tsn; u64 align; /* alignment granularity */ u64 lowest_lba; u32 logical_block_size; u8 align_required; /* ALIGN: 0 or 1 */ size_t pos; u8 *cmd; u8 *resp; struct parsed_resp parsed; size_t prev_d_len; void *prev_data; struct list_head unlk_lst;}; static const u8 opaluid[][OPAL_UID_LENGTH] = { /* users */ [OPAL_SMUID_UID] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff }, [OPAL_THISSP_UID] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, [OPAL_ADMINSP_UID] = { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 }, [OPAL_LOCKINGSP_UID] = { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 }, [OPAL_ENTERPRISE_LOCKINGSP_UID] = { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 }, [OPAL_ANYBODY_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 }, [OPAL_SID_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 }, [OPAL_ADMIN1_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 }, [OPAL_USER1_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 }, [OPAL_USER2_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 }, [OPAL_PSID_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 }, [OPAL_ENTERPRISE_BANDMASTER0_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 }, [OPAL_ENTERPRISE_ERASEMASTER_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 }, /* tables */ [OPAL_TABLE_TABLE] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 }, [OPAL_LOCKINGRANGE_GLOBAL] = { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 }, [OPAL_LOCKINGRANGE_ACE_START_TO_KEY] = { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xD0, 0x01 }, [OPAL_LOCKINGRANGE_ACE_RDLOCKED] = { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 }, [OPAL_LOCKINGRANGE_ACE_WRLOCKED] = { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 }, [OPAL_MBRCONTROL] = { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 }, [OPAL_MBR] = { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 }, [OPAL_AUTHORITY_TABLE] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00}, [OPAL_C_PIN_TABLE] = { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00}, [OPAL_LOCKING_INFO_TABLE] = { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 }, [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] = { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 }, [OPAL_DATASTORE] = { 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00 }, [OPAL_LOCKING_TABLE] = { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00 }, /* C_PIN_TABLE object ID's */ [OPAL_C_PIN_MSID] = { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02}, [OPAL_C_PIN_SID] = { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01}, [OPAL_C_PIN_ADMIN1] = { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01}, /* half UID's (only first 4 bytes used) */ [OPAL_HALF_UID_AUTHORITY_OBJ_REF] = { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff }, [OPAL_HALF_UID_BOOLEAN_ACE] = { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff }, /* special value for omitted optional parameter */ [OPAL_UID_HEXFF] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},}; /* * TCG Storage SSC Methods. * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 * Section: 6.3 Assigned UIDs */static const u8 opalmethod[][OPAL_METHOD_LENGTH] = { [OPAL_PROPERTIES] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 }, [OPAL_STARTSESSION] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 }, [OPAL_REVERT] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 }, [OPAL_ACTIVATE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 }, [OPAL_EGET] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 }, [OPAL_ESET] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 }, [OPAL_NEXT] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 }, [OPAL_EAUTHENTICATE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c }, [OPAL_GETACL] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d }, [OPAL_GENKEY] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 }, [OPAL_REVERTSP] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 }, [OPAL_GET] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 }, [OPAL_SET] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 }, [OPAL_AUTHENTICATE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c }, [OPAL_RANDOM] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 }, [OPAL_ERASE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 }, [OPAL_REACTIVATE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x01 },}; static int end_opal_session_error(struct opal_dev *dev);static int opal_discovery0_step(struct opal_dev *dev); struct opal_suspend_data { struct opal_lock_unlock unlk; u8 lr; struct list_head node;}; /* * Derived from: * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 * Section: 5.1.5 Method Status Codes */static const char * const opal_errors[] = { "Success", "Not Authorized", "Unknown Error", "SP Busy", "SP Failed", "SP Disabled", "SP Frozen", "No Sessions Available", "Uniqueness Conflict", "Insufficient Space", "Insufficient Rows", "Invalid Function", "Invalid Parameter", "Invalid Reference", "Unknown Error", "TPER Malfunction", "Transaction Failure", "Response Overflow", "Authority Locked Out",}; static const char *opal_error_to_human(int error){ if (error == 0x3f) return "Failed"; if (error >= ARRAY_SIZE(opal_errors) || error < 0) return "Unknown Error"; return opal_errors[error];} static void print_buffer(const u8 *ptr, u32 length){#ifdef DEBUG print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length); pr_debug("\n");#endif} /* * Allocate/update a SED Opal key and add it to the SED Opal keyring. */static int update_sed_opal_key(const char *desc, u_char *key_data, int keylen){ key_ref_t kr; if (!sed_opal_keyring) return -ENOKEY; kr = key_create_or_update(make_key_ref(sed_opal_keyring, true), "user", desc, (const void *)key_data, keylen, KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_WRITE, KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN | KEY_ALLOC_BYPASS_RESTRICTION); if (IS_ERR(kr)) { pr_err("Error adding SED key (%ld)\n", PTR_ERR(kr)); return PTR_ERR(kr); } return 0;} /* * Read a SED Opal key from the SED Opal keyring. */static int read_sed_opal_key(const char *key_name, u_char *buffer, int buflen){ int ret; key_ref_t kref; struct key *key; if (!sed_opal_keyring) return -ENOKEY; kref = keyring_search(make_key_ref(sed_opal_keyring, true), &key_type_user, key_name, true); if (IS_ERR(kref)) return PTR_ERR(kref); key = key_ref_to_ptr(kref); down_read(&key->sem); ret = key_validate(key); if (ret == 0) { if (buflen > key->datalen) buflen = key->datalen; ret = key->type->read(key, (char *)buffer, buflen); } up_read(&key->sem); key_ref_put(kref); return ret;} static int opal_get_key(struct opal_dev *dev, struct opal_key *key){ int ret = 0; switch (key->key_type) { case OPAL_INCLUDED: /* the key is ready to use */ break; case OPAL_KEYRING: /* the key is in the keyring */ ret = read_sed_opal_key(OPAL_AUTH_KEY, key->key, OPAL_KEY_MAX); if (ret > 0) { if (ret > U8_MAX) { ret = -ENOSPC; goto error; } key->key_len = ret; key->key_type = OPAL_INCLUDED; } break; default: ret = -EINVAL; break; } if (ret < 0) goto error; /* must have a PEK by now or it's an error */ if (key->key_type != OPAL_INCLUDED || key->key_len == 0) { ret = -EINVAL; goto error; } return 0;error: pr_debug("Error getting password: %d\n", ret); return ret;} static bool check_tper(const void *data){ const struct d0_tper_features *tper = data; u8 flags = tper->supported_features; if (!(flags & TPER_SYNC_SUPPORTED)) { pr_debug("TPer sync not supported. flags = %d\n", tper->supported_features); return false; } return true;} static bool check_lcksuppt(const void *data){ const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & LOCKING_SUPPORTED_MASK);} static bool check_lckenabled(const void *data){ const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & LOCKING_ENABLED_MASK);} static bool check_locked(const void *data){ const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & LOCKED_MASK);} static bool check_mbrenabled(const void *data){ const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & MBR_ENABLED_MASK);} static bool check_mbrdone(const void *data){ const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & MBR_DONE_MASK);} static bool check_sum(const void *data){ const struct d0_single_user_mode *sum = data; u32 nlo = be32_to_cpu(sum->num_locking_objects); if (nlo == 0) { pr_debug("Need at least one locking object.\n"); return false; } pr_debug("Number of locking objects: %d\n", nlo); return true;} static u16 get_comid_v100(const void *data){ const struct d0_opal_v100 *v100 = data; return be16_to_cpu(v100->baseComID);} static u16 get_comid_v200(const void *data){ const struct d0_opal_v200 *v200 = data; return be16_to_cpu(v200->baseComID);} static int opal_send_cmd(struct opal_dev *dev){ return dev->send_recv(dev->data, dev->comid, TCG_SECP_01, dev->cmd, IO_BUFFER_LENGTH, true);} static int opal_recv_cmd(struct opal_dev *dev){ return dev->send_recv(dev->data, dev->comid, TCG_SECP_01, dev->resp, IO_BUFFER_LENGTH, false);} static int opal_recv_check(struct opal_dev *dev){ size_t buflen = IO_BUFFER_LENGTH; void *buffer = dev->resp; struct opal_header *hdr = buffer; int ret; do { pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n", hdr->cp.outstandingData, hdr->cp.minTransfer); if (hdr->cp.outstandingData == 0 || hdr->cp.minTransfer != 0) return 0; memset(buffer, 0, buflen); ret = opal_recv_cmd(dev); } while (!ret); return ret;} static int opal_send_recv(struct opal_dev *dev, cont_fn *cont){ int ret; Lines 1–500 of 3727. Load more
// SPDX-License-Identifier: GPL-2.0 /* * Copyright © 2016 Intel Corporation * * Authors: * Scott Bauer <scott.bauer@intel.com> * Rafael Antognolli <rafael.antognolli@intel.com> */ #define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt #include <linux/delay.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/blkdev.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <uapi/linux/sed-opal.h> #include <linux/sed-opal.h> #include <linux/sed-opal-key.h> #include <linux/string.h> #include <linux/kdev_t.h> #include <linux/key.h> #include <linux/key-type.h> #include <keys/user-type.h> #include "opal_proto.h" #define IO_BUFFER_LENGTH 2048 #define MAX_TOKS 64 /* Number of bytes needed by cmd_finalize. */ #define CMD_FINALIZE_BYTES_NEEDED 7 static struct key *sed_opal_keyring; struct opal_step { int (*fn)(struct opal_dev *dev, void *data); void *data; }; typedef int (cont_fn)(struct opal_dev *dev); enum opal_atom_width { OPAL_WIDTH_TINY, OPAL_WIDTH_SHORT, OPAL_WIDTH_MEDIUM, OPAL_WIDTH_LONG, OPAL_WIDTH_TOKEN }; /* * On the parsed response, we don't store again the toks that are already * stored in the response buffer. Instead, for each token, we just store a * pointer to the position in the buffer where the token starts, and the size * of the token in bytes. */ struct opal_resp_tok { const u8 *pos; size_t len; enum opal_response_token type; enum opal_atom_width width; union { u64 u; s64 s; } stored; }; /* * From the response header it's not possible to know how many tokens there are * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later * if we start dealing with messages that have more than that, we can increase * this number. This is done to avoid having to make two passes through the * response, the first one counting how many tokens we have and the second one * actually storing the positions. */ struct parsed_resp { int num; struct opal_resp_tok toks[MAX_TOKS]; }; struct opal_dev { u32 flags; void *data; sec_send_recv *send_recv; struct mutex dev_lock; u16 comid; u32 hsn; u32 tsn; u64 align; /* alignment granularity */ u64 lowest_lba; u32 logical_block_size; u8 align_required; /* ALIGN: 0 or 1 */ size_t pos; u8 *cmd; u8 *resp; struct parsed_resp parsed; size_t prev_d_len; void *prev_data; struct list_head unlk_lst; }; static const u8 opaluid[][OPAL_UID_LENGTH] = { /* users */ [OPAL_SMUID_UID] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff }, [OPAL_THISSP_UID] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, [OPAL_ADMINSP_UID] = { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 }, [OPAL_LOCKINGSP_UID] = { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 }, [OPAL_ENTERPRISE_LOCKINGSP_UID] = { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 }, [OPAL_ANYBODY_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 }, [OPAL_SID_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 }, [OPAL_ADMIN1_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 }, [OPAL_USER1_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 }, [OPAL_USER2_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 }, [OPAL_PSID_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 }, [OPAL_ENTERPRISE_BANDMASTER0_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 }, [OPAL_ENTERPRISE_ERASEMASTER_UID] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 }, /* tables */ [OPAL_TABLE_TABLE] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 }, [OPAL_LOCKINGRANGE_GLOBAL] = { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 }, [OPAL_LOCKINGRANGE_ACE_START_TO_KEY] = { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xD0, 0x01 }, [OPAL_LOCKINGRANGE_ACE_RDLOCKED] = { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 }, [OPAL_LOCKINGRANGE_ACE_WRLOCKED] = { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 }, [OPAL_MBRCONTROL] = { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 }, [OPAL_MBR] = { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 }, [OPAL_AUTHORITY_TABLE] = { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00}, [OPAL_C_PIN_TABLE] = { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00}, [OPAL_LOCKING_INFO_TABLE] = { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 }, [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] = { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 }, [OPAL_DATASTORE] = { 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00 }, [OPAL_LOCKING_TABLE] = { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00 }, /* C_PIN_TABLE object ID's */ [OPAL_C_PIN_MSID] = { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02}, [OPAL_C_PIN_SID] = { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01}, [OPAL_C_PIN_ADMIN1] = { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01}, /* half UID's (only first 4 bytes used) */ [OPAL_HALF_UID_AUTHORITY_OBJ_REF] = { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff }, [OPAL_HALF_UID_BOOLEAN_ACE] = { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff }, /* special value for omitted optional parameter */ [OPAL_UID_HEXFF] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, }; /* * TCG Storage SSC Methods. * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 * Section: 6.3 Assigned UIDs */ static const u8 opalmethod[][OPAL_METHOD_LENGTH] = { [OPAL_PROPERTIES] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 }, [OPAL_STARTSESSION] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 }, [OPAL_REVERT] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 }, [OPAL_ACTIVATE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 }, [OPAL_EGET] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 }, [OPAL_ESET] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 }, [OPAL_NEXT] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 }, [OPAL_EAUTHENTICATE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c }, [OPAL_GETACL] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d }, [OPAL_GENKEY] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 }, [OPAL_REVERTSP] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 }, [OPAL_GET] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 }, [OPAL_SET] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 }, [OPAL_AUTHENTICATE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c }, [OPAL_RANDOM] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 }, [OPAL_ERASE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 }, [OPAL_REACTIVATE] = { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x01 }, }; static int end_opal_session_error(struct opal_dev *dev); static int opal_discovery0_step(struct opal_dev *dev); struct opal_suspend_data { struct opal_lock_unlock unlk; u8 lr; struct list_head node; }; /* * Derived from: * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 * Section: 5.1.5 Method Status Codes */ static const char * const opal_errors[] = { "Success", "Not Authorized", "Unknown Error", "SP Busy", "SP Failed", "SP Disabled", "SP Frozen", "No Sessions Available", "Uniqueness Conflict", "Insufficient Space", "Insufficient Rows", "Invalid Function", "Invalid Parameter", "Invalid Reference", "Unknown Error", "TPER Malfunction", "Transaction Failure", "Response Overflow", "Authority Locked Out", }; static const char *opal_error_to_human(int error) { if (error == 0x3f) return "Failed"; if (error >= ARRAY_SIZE(opal_errors) || error < 0) return "Unknown Error"; return opal_errors[error]; } static void print_buffer(const u8 *ptr, u32 length) { #ifdef DEBUG print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length); pr_debug("\n"); #endif } /* * Allocate/update a SED Opal key and add it to the SED Opal keyring. */ static int update_sed_opal_key(const char *desc, u_char *key_data, int keylen) { key_ref_t kr; if (!sed_opal_keyring) return -ENOKEY; kr = key_create_or_update(make_key_ref(sed_opal_keyring, true), "user", desc, (const void *)key_data, keylen, KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_WRITE, KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN | KEY_ALLOC_BYPASS_RESTRICTION); if (IS_ERR(kr)) { pr_err("Error adding SED key (%ld)\n", PTR_ERR(kr)); return PTR_ERR(kr); } return 0; } /* * Read a SED Opal key from the SED Opal keyring. */ static int read_sed_opal_key(const char *key_name, u_char *buffer, int buflen) { int ret; key_ref_t kref; struct key *key; if (!sed_opal_keyring) return -ENOKEY; kref = keyring_search(make_key_ref(sed_opal_keyring, true), &key_type_user, key_name, true); if (IS_ERR(kref)) return PTR_ERR(kref); key = key_ref_to_ptr(kref); down_read(&key->sem); ret = key_validate(key); if (ret == 0) { if (buflen > key->datalen) buflen = key->datalen; ret = key->type->read(key, (char *)buffer, buflen); } up_read(&key->sem); key_ref_put(kref); return ret; } static int opal_get_key(struct opal_dev *dev, struct opal_key *key) { int ret = 0; switch (key->key_type) { case OPAL_INCLUDED: /* the key is ready to use */ break; case OPAL_KEYRING: /* the key is in the keyring */ ret = read_sed_opal_key(OPAL_AUTH_KEY, key->key, OPAL_KEY_MAX); if (ret > 0) { if (ret > U8_MAX) { ret = -ENOSPC; goto error; } key->key_len = ret; key->key_type = OPAL_INCLUDED; } break; default: ret = -EINVAL; break; } if (ret < 0) goto error; /* must have a PEK by now or it's an error */ if (key->key_type != OPAL_INCLUDED || key->key_len == 0) { ret = -EINVAL; goto error; } return 0; error: pr_debug("Error getting password: %d\n", ret); return ret; } static bool check_tper(const void *data) { const struct d0_tper_features *tper = data; u8 flags = tper->supported_features; if (!(flags & TPER_SYNC_SUPPORTED)) { pr_debug("TPer sync not supported. flags = %d\n", tper->supported_features); return false; } return true; } static bool check_lcksuppt(const void *data) { const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & LOCKING_SUPPORTED_MASK); } static bool check_lckenabled(const void *data) { const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & LOCKING_ENABLED_MASK); } static bool check_locked(const void *data) { const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & LOCKED_MASK); } static bool check_mbrenabled(const void *data) { const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & MBR_ENABLED_MASK); } static bool check_mbrdone(const void *data) { const struct d0_locking_features *lfeat = data; u8 sup_feat = lfeat->supported_features; return !!(sup_feat & MBR_DONE_MASK); } static bool check_sum(const void *data) { const struct d0_single_user_mode *sum = data; u32 nlo = be32_to_cpu(sum->num_locking_objects); if (nlo == 0) { pr_debug("Need at least one locking object.\n"); return false; } pr_debug("Number of locking objects: %d\n", nlo); return true; } static u16 get_comid_v100(const void *data) { const struct d0_opal_v100 *v100 = data; return be16_to_cpu(v100->baseComID); } static u16 get_comid_v200(const void *data) { const struct d0_opal_v200 *v200 = data; return be16_to_cpu(v200->baseComID); } static int opal_send_cmd(struct opal_dev *dev) { return dev->send_recv(dev->data, dev->comid, TCG_SECP_01, dev->cmd, IO_BUFFER_LENGTH, true); } static int opal_recv_cmd(struct opal_dev *dev) { return dev->send_recv(dev->data, dev->comid, TCG_SECP_01, dev->resp, IO_BUFFER_LENGTH, false); } static int opal_recv_check(struct opal_dev *dev) { size_t buflen = IO_BUFFER_LENGTH; void *buffer = dev->resp; struct opal_header *hdr = buffer; int ret; do { pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n", hdr->cp.outstandingData, hdr->cp.minTransfer); if (hdr->cp.outstandingData == 0 || hdr->cp.minTransfer != 0) return 0; memset(buffer, 0, buflen); ret = opal_recv_cmd(dev); } while (!ret); return ret; } static int opal_send_recv(struct opal_dev *dev, cont_fn *cont) { int ret;