diff --git a/CHANGELOG.md b/CHANGELOG.md index 13a6c136b..f32e4e542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,11 @@ New `get_spdk_version` RPC method is introduced to get version info of the runni The `start_nbd_disk` RPC method now take nbd_device as an optional parameter. If nbd_device is specified, use that specified nbd device. If it's not specified, pick available one. +### Opal + +Add Opal scan support for NVMe to check whether it supports SED Opal and dump +device info. nvme_manage tool can be used to invoke this. + ## v19.01: ### ocf bdev diff --git a/examples/nvme/nvme_manage/nvme_manage.c b/examples/nvme/nvme_manage/nvme_manage.c index 8f83661fe..e7f465367 100644 --- a/examples/nvme/nvme_manage/nvme_manage.c +++ b/examples/nvme/nvme_manage/nvme_manage.c @@ -37,6 +37,7 @@ #include "spdk/env.h" #include "spdk/string.h" #include "spdk/util.h" +#include "spdk/opal.h" #define MAX_DEVS 64 @@ -46,6 +47,7 @@ struct dev { const struct spdk_nvme_ctrlr_data *cdata; struct spdk_nvme_ns_data *common_ns_data; int outstanding_admin_cmds; + struct spdk_opal_dev *opal_dev; }; static struct dev devs[MAX_DEVS]; @@ -140,7 +142,8 @@ static void usage(void) printf("\t[5: detach namespace from controller]\n"); printf("\t[6: format namespace or controller]\n"); printf("\t[7: firmware update]\n"); - printf("\t[8: quit]\n"); + printf("\t[8: opal scan]\n"); + printf("\t[9: quit]\n"); } static void @@ -850,6 +853,108 @@ update_firmware_image(void) spdk_dma_free(fw_image); } +static void spdk_dump_opal_info(struct spdk_opal_info *opal) +{ + if (!opal->opal_ssc_dev) { + SPDK_ERRLOG("This device is not Opal enabled. Not Supported!\n"); + return; + } + + if (opal->tper) { + printf("\nOpal TPer feature:\n"); + printf("ACKNACK = %s", (opal->tper_acknack ? "Y, " : "N, ")); + printf("ASYNC = %s", (opal->tper_async ? "Y, " : "N, ")); + printf("BufferManagement = %s\n", (opal->tper_buffer_mgt ? "Y, " : "N, ")); + printf("ComIDManagement = %s", (opal->tper_comid_mgt ? "Y, " : "N, ")); + printf("Streaming = %s", (opal->tper_streaming ? "Y, " : "N, ")); + printf("Sync = %s\n", (opal->tper_sync ? "Y" : "N")); + printf("\n"); + } + + if (opal->locking) { + printf("Opal Locking feature:\n"); + printf("Locked = %s", (opal->locking_locked ? "Y, " : "N, ")); + printf("Locking Enabled = %s", (opal->locking_locking_enabled ? "Y, " : "N, ")); + printf("Locking supported = %s\n", (opal->locking_locking_supported ? "Y" : "N")); + + printf("MBR done = %s", (opal->locking_mbr_done ? "Y, " : "N, ")); + printf("MBR enabled = %s", (opal->locking_mbr_enabled ? "Y, " : "N, ")); + printf("Media encrypt = %s\n", (opal->locking_media_encrypt ? "Y" : "N")); + printf("\n"); + } + + if (opal->geometry) { + printf("Opal Geometry feature:\n"); + printf("Align = %s", (opal->geometry_align ? "Y, " : "N, ")); + printf("Logical block size = %d, ", opal->geometry_logical_block_size); + printf("Lowest aligned LBA = %ld\n", opal->geometry_lowest_aligned_lba); + printf("\n"); + } + + if (opal->single_user_mode) { + printf("Opal Single User Mode feature:\n"); + printf("Any in SUM = %s", (opal->single_user_any ? "Y, " : "N, ")); + printf("All in SUM = %s", (opal->single_user_all ? "Y, " : "N, ")); + printf("Policy: %s Authority,\n", (opal->single_user_policy ? "Admin" : "Users")); + printf("Number of locking objects = %d\n ", opal->single_user_locking_objects); + printf("\n"); + } + + if (opal->datastore) { + printf("Opal DataStore feature:\n"); + printf("Table alignment = %d, ", opal->datastore_alignment); + printf("Max number of tables = %d, ", opal->datastore_max_tables); + printf("Max size of tables = %d\n", opal->datastore_max_table_size); + printf("\n"); + } + + if (opal->opal_v100) { + printf("Opal V100 feature:\n"); + printf("Base comID = %d, ", opal->opal_v100_base_comid); + printf("Number of comIDs = %d, ", opal->opal_v100_num_comid); + printf("Range crossing = %s\n", (opal->opal_v100_range_crossing ? "N" : "Y")); + printf("\n"); + } + + if (opal->opal_v200) { + printf("Opal V200 feature:\n"); + printf("Base comID = %d, ", opal->opal_v200_base_comid); + printf("Number of comIDs = %d, ", opal->opal_v200_num_comid); + printf("Initial PIN = %d,\n", opal->opal_v200_initial_pin); + printf("Reverted PIN = %d, ", opal->opal_v200_reverted_pin); + printf("Number of admins = %d, ", opal->opal_v200_num_admin); + printf("Number of users = %d\n", opal->opal_v200_num_user); + printf("\n\n"); + } +} + +static void +test_opal(void) +{ + struct dev *iter; + + foreach_dev(iter) { + if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) { + iter->opal_dev = spdk_opal_init_dev(iter->ctrlr); + if (iter->opal_dev == NULL) { + return; + } + if (spdk_opal_supported(iter->opal_dev)) { + printf("\n\nOpal Supported:\n"); + display_controller(iter, CONTROLLER_DISPLAY_SIMPLISTIC); + spdk_opal_scan(iter->opal_dev); + spdk_dump_opal_info(spdk_opal_get_info(iter->opal_dev)); + } + spdk_opal_close(iter->opal_dev); + } else { + printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\n", + iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func); + printf("%04x:%02x:%02x.%02x: Opal Not Supported\n\n\n", + iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func); + } + } +} + static void args_usage(const char *program_name) { @@ -943,6 +1048,9 @@ int main(int argc, char **argv) update_firmware_image(); break; case 8: + test_opal(); + break; + case 9: exit_flag = true; break; default: diff --git a/include/spdk/opal.h b/include/spdk/opal.h new file mode 100644 index 000000000..0aec383a8 --- /dev/null +++ b/include/spdk/opal.h @@ -0,0 +1,145 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SPDK_OPAL_H +#define SPDK_OPAL_H + +#include "spdk/stdinc.h" +#include "spdk/nvme.h" +#include "spdk/log.h" +#include "spdk/endian.h" +#include "spdk/string.h" + +#define SPDK_OPAL_NOT_SUPPORTED 0xFF + +/* + * TCG Storage Architecture Core Spec v2.01 r1.00 + * 5.1.5 Method Status Codes + */ +#define SPDK_OPAL_FAILED 0x3F + +static const char *const spdk_opal_errors[] = { + "SUCCESS", + "NOT AUTHORIZED", + "OBSOLETE/UNKNOWN ERROR", + "SP BUSY", + "SP FAILED", + "SP DISABLED", + "SP FROZEN", + "NO SESSIONS AVAILABLE", + "UNIQUENESS CONFLICT", + "INSUFFICIENT SPACE", + "INSUFFICIENT ROWS", + "UNKNOWN ERROR", + "INVALID PARAMETER", + "OBSOLETE/UNKNOWN ERROR", + "UNKNOWN ERROR", + "TPER MALFUNCTION", + "TRANSACTION FAILURE", + "RESPONSE OVERFLOW", + "AUTHORITY LOCKED OUT", +}; + +enum spdk_opal_cmd { + OPAL_CMD_SAVE, + OPAL_CMD_LOCK_UNLOCK, + OPAL_CMD_TAKE_OWNERSHIP, + OPAL_CMD_ACTIVATE_LSP, /* locking sp */ + OPAL_CMD_SET_NEW_PASSWD, + OPAL_CMD_ACTIVATE_USER, + OPAL_CMD_REVERT_TPER, + OPAL_CMD_SETUP_LOCKING_RANGE, + OPAL_CMD_ADD_USER_TO_LOCKING_RANGE, + OPAL_CMD_ENABLE_DISABLE_SHADOW_MBR, + OPAL_CMD_ERASE_LOCKING_RANGE, + OPAL_CMD_SECURE_ERASE_LOCKING_RANGE, + OPAL_CMD_INITIAL_SETUP, +}; + +struct spdk_opal_info { + uint8_t tper : 1; + uint8_t locking : 1; + uint8_t geometry : 1; + uint8_t single_user_mode : 1; + uint8_t datastore : 1; + uint8_t opal_v200 : 1; + uint8_t opal_v100 : 1; + uint8_t vendor_specific : 1; + uint8_t opal_ssc_dev : 1; + uint8_t tper_acknack : 1; + uint8_t tper_async : 1; + uint8_t tper_buffer_mgt : 1; + uint8_t tper_comid_mgt : 1; + uint8_t tper_streaming : 1; + uint8_t tper_sync : 1; + uint8_t locking_locked : 1; + uint8_t locking_locking_enabled : 1; + uint8_t locking_locking_supported : 1; + uint8_t locking_mbr_done : 1; + uint8_t locking_mbr_enabled : 1; + uint8_t locking_media_encrypt : 1; + uint8_t geometry_align : 1; + uint64_t geometry_alignment_granularity; + uint32_t geometry_logical_block_size; + uint64_t geometry_lowest_aligned_lba; + uint8_t single_user_any : 1; + uint8_t single_user_all : 1; + uint8_t single_user_policy : 1; + uint32_t single_user_locking_objects; + uint16_t datastore_max_tables; + uint32_t datastore_max_table_size; + uint32_t datastore_alignment; + uint16_t opal_v100_base_comid; + uint16_t opal_v100_num_comid; + uint8_t opal_v100_range_crossing : 1; + uint16_t opal_v200_base_comid; + uint16_t opal_v200_num_comid; + uint8_t opal_v200_initial_pin; + uint8_t opal_v200_reverted_pin; + uint16_t opal_v200_num_admin; + uint16_t opal_v200_num_user; + uint8_t opal_v200_range_crossing : 1; + uint16_t vu_feature_code; /* vendor specific feature */ +}; + +struct spdk_opal_dev; + +struct spdk_opal_dev *spdk_opal_init_dev(void *dev_handler); + +void spdk_opal_scan(struct spdk_opal_dev *dev); +void spdk_opal_close(struct spdk_opal_dev *dev); +struct spdk_opal_info *spdk_opal_get_info(struct spdk_opal_dev *dev); + +bool spdk_opal_supported(struct spdk_opal_dev *dev); + +#endif diff --git a/include/spdk/opal_spec.h b/include/spdk/opal_spec.h new file mode 100644 index 000000000..5605f8e77 --- /dev/null +++ b/include/spdk/opal_spec.h @@ -0,0 +1,376 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SPDK_OPAL_SPEC_H +#define SPDK_OPAL_SPEC_H + +#include "spdk/stdinc.h" + +/* + * TCG Storage Architecture Core Spec v2.01 r1.00 + * 3.2.2.3 Tokens + */ +#define SPDK_TINY_ATOM_TYPE_MAX 0x7F +#define SPDK_SHORT_ATOM_TYPE_MAX 0xBF +#define SPDK_MEDIUM_ATOM_TYPE_MAX 0xDF +#define SPDK_LONG_ATOM_TYPE_MAX 0xE3 + +#define SPDK_TINY_ATOM_SIGN_FLAG 0x40 + +#define SPDK_TINY_ATOM_DATA_MASK 0x3F + +#define SPDK_SHORT_ATOM_ID 0x80 +#define SPDK_SHORT_ATOM_BYTESTRING_FLAG 0x20 +#define SPDK_SHORT_ATOM_SIGN_FLAG 0x10 +#define SPDK_SHORT_ATOM_LEN_MASK 0x0F + +#define SPDK_MEDIUM_ATOM_ID 0xC0 +#define SPDK_MEDIUM_ATOM_BYTESTRING_FLAG 0x10 + +#define SPDK_MEDIUM_ATOM_SIGN_FLAG 0x08 +#define SPDK_MEDIUM_ATOM_LEN_MASK 0x07 + +#define SPDK_LONG_ATOM_ID 0xE0 +#define SPDK_LONG_ATOM_BYTESTRING_FLAG 0x02 +#define SPDK_LONG_ATOM_SIGN_FLAG 0x01 + +/* + * TCG Storage Architecture Core Spec v2.01 r1.00 + * Table-26 ComID management + */ +#define LV0_DISCOVERY_COMID 0x01 + +/* + * TCG Storage Opal v2.01 r1.00 + * 5.2.3 Type Table Modification + */ +#define OPAL_MANUFACTURED_INACTIVE 0x08 + +#define LOCKING_RANGE_NON_GLOBAL 0x03 + +/* + * Feature Code + */ +enum spdk_lv0_discovery_feature_code { + /* + * TCG Storage Architecture Core Spec v2.01 r1.00 + * 3.3.6 Level 0 Discovery + */ + FEATURECODE_TPER = 0x0001, + FEATURECODE_LOCKING = 0x0002, + + /* + * Opal SSC 1.00 r3.00 Final + * 3.1.1.4 Opal SSC Feature + */ + FEATURECODE_OPALV100 = 0x0200, + + /* + * TCG Storage Opal v2.01 r1.00 + * 3.1.1.4 Geometry Reporting Feature + * 3.1.1.5 Opal SSC V2.00 Feature + */ + FEATURECODE_OPALV200 = 0x0203, + FEATURECODE_GEOMETRY = 0x0003, + + /* + * TCG Storage Opal Feature Set Single User Mode v1.00 r2.00 + * 4.2.1 Single User Mode Feature Descriptor + */ + FEATURECODE_SINGLEUSER = 0x0201, + + /* + * TCG Storage Opal Feature Set Additional DataStore Tables v1.00 r1.00 + * 4.1.1 DataStore Table Feature Descriptor + */ + FEATURECODE_DATASTORE = 0x0202, +}; + +/* + * TCG Storage Architecture Core Spec v2.01 r1.00 + * 5.1.4 Abstract Type + */ +enum spdk_opal_token { + /* boolean */ + SPDK_OPAL_TRUE = 0x01, + SPDK_OPAL_FALSE = 0x00, + + /* cell_block + * 5.1.4.2.3 */ + SPDK_OPAL_TABLE = 0x00, + SPDK_OPAL_STARTROW = 0x01, + SPDK_OPAL_ENDROW = 0x02, + SPDK_OPAL_STARTCOLUMN = 0x03, + SPDK_OPAL_ENDCOLUMN = 0x04, + SPDK_OPAL_VALUES = 0x01, + + /* C_PIN table + * 5.3.2.12 */ + SPDK_OPAL_PIN = 0x03, + + /* locking table + * 5.7.2.2 */ + SPDK_OPAL_RANGESTART = 0x03, + SPDK_OPAL_RANGELENGTH = 0x04, + SPDK_OPAL_READLOCKENABLED = 0x05, + SPDK_OPAL_WRITELOCKENABLED = 0x06, + SPDK_OPAL_READLOCKED = 0x07, + SPDK_OPAL_WRITELOCKED = 0x08, + SPDK_OPAL_ACTIVEKEY = 0x0A, + + /* locking info table */ + SPDK_OPAL_MAXRANGES = 0x04, + + /* mbr control */ + SPDK_OPAL_MBRENABLE = 0x01, + SPDK_OPAL_MBRDONE = 0x02, + + /* properties */ + SPDK_OPAL_HOSTPROPERTIES = 0x00, + + /* control tokens */ + SPDK_OPAL_STARTLIST = 0xF0, + SPDK_OPAL_ENDLIST = 0xF1, + SPDK_OPAL_STARTNAME = 0xF2, + SPDK_OPAL_ENDNAME = 0xF3, + SPDK_OPAL_CALL = 0xF8, + SPDK_OPAL_ENDOFDATA = 0xF9, + SPDK_OPAL_ENDOFSESSION = 0xFA, + SPDK_OPAL_STARTTRANSACTON = 0xFB, + SPDK_OPAL_ENDTRANSACTON = 0xFC, + SPDK_OPAL_EMPTYATOM = 0xFF, + SPDK_OPAL_WHERE = 0x00, + + /* life cycle */ + SPDK_OPAL_LIFECYCLE = 0x06, + + /* Autority table */ + SPDK_OPAL_AUTH_ENABLE = 0x05, +}; + +/* + * TCG Storage Architecture Core Spec v2.01 r1.00 + * Table-39 Level0 Discovery Header Format + */ +struct spdk_d0_header { + uint32_t length; + uint32_t revision; + uint32_t reserved_0; + uint32_t reserved_1; + uint8_t vendor_specfic[32]; +}; + +/* + * TCG Storage Architecture Core Spec v2.01 r1.00 + * Table-42 TPer Feature Descriptor + */ +struct spdk_d0_tper_features { + uint16_t feature_code; + uint8_t reserved_0 : 4; + uint8_t version : 4; + uint8_t length; + uint8_t sync : 1; + uint8_t async : 1; + uint8_t acknack : 1; + uint8_t buffer_management : 1; + uint8_t streaming : 1; + uint8_t reserved_1 : 1; + uint8_t comid_management : 1; + uint8_t reserved_2 : 1; + + uint32_t reserved_3; + uint32_t reserved_4; + uint32_t reserved_5; +}; + +/* + * TCG Storage Architecture Core Spec v2.01 r1.00 + * Table-43 Locking Feature Descriptor + */ +struct spdk_d0_locking_features { + uint16_t feature_code; + uint8_t reserved_0 : 4; + uint8_t version : 4; + uint8_t length; + + uint8_t locking_supported : 1; + uint8_t locking_enabled : 1; + uint8_t locked : 1; + uint8_t media_encryption : 1; + uint8_t mbr_enabled : 1; + uint8_t mbr_done : 1; + uint8_t reserved_1 : 1; + uint8_t reserved_2 : 1; + + uint32_t reserved_3; + uint32_t reserved_4; + uint32_t reserved_5; +}; + +/* + * TCG Storage Opal Feature Set Single User Mode v1.00 r2.00 + * 4.2.1 Single User Mode Feature Descriptor + */ +struct spdk_d0_sum { + uint16_t feature_code; + uint8_t reserved_0 : 4; + uint8_t version : 4; + uint8_t length; + uint32_t num_locking_objects; + + uint8_t any : 1; + uint8_t all : 1; + uint8_t policy : 1; + uint8_t reserved_1 : 5; + + uint8_t reserved_2; + uint16_t reserved_3; + uint32_t reserved_4; +}; + +/* + * TCG Storage Opal v2.01 r1.00 + * 3.1.1.4 Geometry Reporting Feature + */ +struct spdk_d0_geo_features { + uint16_t feature_code; + uint8_t reserved_0 : 4; + uint8_t version : 4; + uint8_t length; + + uint8_t align : 1; + uint8_t reserved_1 : 7; + uint8_t reserved_2[7]; + uint32_t logical_block_size; + uint64_t alignment_granularity; + uint64_t lowest_aligned_lba; +}; + +/* + * TCG Storage Opal Feature Set Additional DataStore Tables v1.00 r1.00 + * 4.1.1 DataStore Table Feature Descriptor + */ +struct spdk_d0_datastore_features { + uint16_t feature_code; + uint8_t reserved_0 : 4; + uint8_t version : 4; + uint8_t length; + + uint16_t reserved_1; + uint16_t max_tables; + uint32_t max_table_size; + uint32_t alignment; +}; + +/* + * Opal SSC 1.00 r3.00 Final + * 3.1.1.4 Opal SSC Feature + */ +struct spdk_d0_opal_v100 { + uint16_t feature_code; + uint8_t reserved_0 : 4; + uint8_t version : 4; + uint8_t length; + uint16_t base_comid; + uint16_t number_comids; + uint8_t range_crossing : 1; + + uint8_t reserved_1 : 7; + uint8_t reserved_2; + uint16_t reserved_3; + uint32_t reserved_4; + uint32_t reserved_5; +}; + +/* + * TCG Storage Opal v2.01 r1.00 + * 3.1.1.4 Geometry Reporting Feature + * 3.1.1.5 Opal SSC V2.00 Feature + */ +struct spdk_d0_opal_v200 { + uint16_t featureCode; + uint8_t reserved_0 : 4; + uint8_t version : 4; + uint8_t length; + uint16_t base_comid; + uint16_t num_comids; + + uint8_t range_crossing : 1; + uint8_t reserved_1 : 7; + + uint16_t num_locking_admin_auth; /* Number of Locking SP Admin Authorities Supported */ + uint16_t num_locking_user_auth; + uint8_t initial_pin; + uint8_t reverted_pin; + uint8_t reserved_2; + uint32_t reserved_3; +}; + +/* + * TCG Storage Architecture Core Spec v2.01 r1.00 + * 3.2.3 ComPackets, Packets & Subpackets + */ + +/* CommPacket header format + * (big-endian) + */ +struct spdk_opal_compacket { + uint32_t reserved; + uint8_t comid[2]; + uint8_t extended_comid[2]; + + uint32_t outstanding_data; + uint32_t min_transfer; + uint32_t length; +}; + +/* packet header format */ +struct spdk_opal_packet { + uint32_t session_tsn; + uint32_t session_hsn; + uint32_t seq_number; + + uint16_t reserved; + uint16_t ack_type; + uint32_t acknowledgment; + uint32_t length; +}; + +/* data subpacket header */ +struct spdk_opal_data_subpacket { + uint8_t reserved[6]; + uint16_t kind; + uint32_t length; +}; + +#endif diff --git a/include/spdk/scsi_spec.h b/include/spdk/scsi_spec.h index 4559e9657..2bca212a2 100644 --- a/include/spdk/scsi_spec.h +++ b/include/spdk/scsi_spec.h @@ -724,6 +724,13 @@ struct spdk_scsi_pr_out_reg_and_move_param_list { }; SPDK_STATIC_ASSERT(sizeof(struct spdk_scsi_pr_out_reg_and_move_param_list) == 24, "Incorrect size"); +/* + * SPC-4 + * Table-258 SECURITY PROTOCOL field in SECURITY PROTOCOL IN command + */ +#define SPDK_SCSI_SECP_INFO 0x00 +#define SPDK_SCSI_SECP_TCG 0x01 + #define SPDK_SCSI_UNMAP_LBPU 1 << 7 #define SPDK_SCSI_UNMAP_LBPWS 1 << 6 #define SPDK_SCSI_UNMAP_LBPWS10 1 << 5 diff --git a/lib/nvme/Makefile b/lib/nvme/Makefile index db6315aa6..16dec61d5 100644 --- a/lib/nvme/Makefile +++ b/lib/nvme/Makefile @@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk C_SRCS = nvme_ctrlr_cmd.c nvme_ctrlr.c nvme_fabric.c nvme_ns_cmd.c nvme_ns.c nvme_pcie.c nvme_qpair.c nvme.c nvme_quirks.c nvme_transport.c nvme_uevent.c nvme_ctrlr_ocssd_cmd.c \ - nvme_ns_ocssd_cmd.c nvme_tcp.c + nvme_ns_ocssd_cmd.c nvme_tcp.c nvme_opal.c C_SRCS-$(CONFIG_RDMA) += nvme_rdma.c LIBNAME = nvme LOCAL_SYS_LIBS = -luuid diff --git a/lib/nvme/nvme_opal.c b/lib/nvme/nvme_opal.c new file mode 100644 index 000000000..d9b47d528 --- /dev/null +++ b/lib/nvme/nvme_opal.c @@ -0,0 +1,573 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "spdk/opal.h" +#include "spdk_internal/event.h" +#include "spdk_internal/log.h" +#include "spdk/util.h" + +#include "nvme_opal_internal.h" + +typedef int (spdk_opal_cb)(struct spdk_opal_dev *dev); + +static int opal_end_session_error(struct spdk_opal_dev *dev); + +static const char * +opal_error_to_human(int error) +{ + if (error == SPDK_OPAL_FAILED) { + return "FAILED"; + } + + if ((size_t)error >= SPDK_COUNTOF(spdk_opal_errors) || error < 0) { + return "UNKNOWN ERROR"; + } + + return spdk_opal_errors[error]; +} + +static int +opal_send_cmd(struct spdk_opal_dev *dev) +{ + return spdk_nvme_ctrlr_security_send(dev->dev_handler, SPDK_SCSI_SECP_TCG, dev->comid, + 0, dev->cmd, IO_BUFFER_LENGTH); +} + +static int +opal_recv_cmd(struct spdk_opal_dev *dev) +{ + void *response = dev->resp; + struct spdk_opal_header *header = response; + int ret = 0; + uint64_t start = spdk_get_ticks(); + uint64_t now; + + do { + ret = spdk_nvme_ctrlr_security_receive(dev->dev_handler, SPDK_SCSI_SECP_TCG, dev->comid, + 0, dev->resp, IO_BUFFER_LENGTH); + if (ret) { + SPDK_ERRLOG("Security Receive Error on dev = %p\n", dev); + return ret; + } + SPDK_DEBUGLOG(SPDK_LOG_OPAL, "outstanding_data=%d, minTransfer=%d\n", + header->com_packet.outstanding_data, + header->com_packet.min_transfer); + + if (header->com_packet.outstanding_data == 0 && + header->com_packet.min_transfer == 0) { + return 0; /* return if all the response data are ready by tper and received by host */ + } else { /* check timeout */ + now = spdk_get_ticks(); + if (now - start > dev->timeout * spdk_get_ticks_hz()) { + SPDK_ERRLOG("Secutiy Receive Timeout on dev = %p\n", dev); + return 0x0F; /* TPer Malfunction */ + } + } + + memset(response, 0, IO_BUFFER_LENGTH); + } while (!ret); + + return ret; +} + +static int +opal_send_recv(struct spdk_opal_dev *dev, spdk_opal_cb *cb) +{ + int ret; + + ret = opal_send_cmd(dev); + if (ret) { + return ret; + } + ret = opal_recv_cmd(dev); + if (ret) { + return ret; + } + return cb(dev); +} + +static void +opal_add_token_u8(int *err, struct spdk_opal_dev *dev, uint8_t token) +{ + if (*err) { + return; + } + if (dev->cmd_pos >= IO_BUFFER_LENGTH - 1) { + SPDK_ERRLOG("Error adding u8: end of buffer.\n"); + *err = -ERANGE; + return; + } + dev->cmd[dev->cmd_pos++] = token; +} + +static int +opal_cmd_finalize(struct spdk_opal_dev *dev, uint32_t hsn, uint32_t tsn, bool eod) +{ + struct spdk_opal_header *hdr; + int err = 0; + + if (eod) { + opal_add_token_u8(&err, dev, SPDK_OPAL_ENDOFDATA); + opal_add_token_u8(&err, dev, SPDK_OPAL_STARTLIST); + opal_add_token_u8(&err, dev, 0); + opal_add_token_u8(&err, dev, 0); + opal_add_token_u8(&err, dev, 0); + opal_add_token_u8(&err, dev, SPDK_OPAL_ENDLIST); + } + + if (err) { + SPDK_ERRLOG("Error finalizing command.\n"); + return -EFAULT; + } + + hdr = (struct spdk_opal_header *)dev->cmd; + + to_be32(&hdr->packet.session_tsn, tsn); + to_be32(&hdr->packet.session_hsn, hsn); + + to_be32(&hdr->sub_packet.length, dev->cmd_pos - sizeof(*hdr)); + while (dev->cmd_pos % 4) { + if (dev->cmd_pos >= IO_BUFFER_LENGTH) { + SPDK_ERRLOG("Error: Buffer overrun\n"); + return -ERANGE; + } + dev->cmd[dev->cmd_pos++] = 0; + } + to_be32(&hdr->packet.length, dev->cmd_pos - sizeof(hdr->com_packet) - + sizeof(hdr->packet)); + to_be32(&hdr->com_packet.length, dev->cmd_pos - sizeof(hdr->com_packet)); + + return 0; +} + +static int +opal_finalize_and_send(struct spdk_opal_dev *dev, bool eod, spdk_opal_cb cb) +{ + int ret; + + ret = opal_cmd_finalize(dev, dev->hsn, dev->tsn, eod); + if (ret) { + SPDK_ERRLOG("Error finalizing command buffer: %d\n", ret); + return ret; + } + + return opal_send_recv(dev, cb); +} + +static inline void +opal_clear_cmd(struct spdk_opal_dev *dev) +{ + dev->cmd_pos = sizeof(struct spdk_opal_header); + memset(dev->cmd, 0, IO_BUFFER_LENGTH); +} + +static inline void +opal_set_comid(struct spdk_opal_dev *dev, uint16_t comid) +{ + struct spdk_opal_header *hdr = (struct spdk_opal_header *)dev->cmd; + + hdr->com_packet.comid[0] = comid >> 8; + hdr->com_packet.comid[1] = comid; + hdr->com_packet.extended_comid[0] = 0; + hdr->com_packet.extended_comid[1] = 0; +} + +static int +opal_next(struct spdk_opal_dev *dev) +{ + const struct spdk_opal_step *step; + int state = 0, error = 0; + + do { + step = &dev->steps[state]; + if (!step->opal_fn) { + if (state != 0) { + break; + } else { + SPDK_ERRLOG("First step is NULL\n"); + return -1; + } + } + + error = step->opal_fn(dev, step->data); + if (error) { + SPDK_ERRLOG("Error on step function: %d with error %d: %s\n", + state, error, + opal_error_to_human(error)); + if (state > 1) { + opal_end_session_error(dev); + return error; + } + } + state++; + } while (!error); + + return error; +} + +static void +opal_check_tper(struct spdk_opal_dev *dev, const void *data) +{ + const struct spdk_d0_tper_features *tper = data; + struct spdk_opal_info *opal_info = dev->opal_info; + + opal_info->opal_ssc_dev = 1; + opal_info->tper = 1; + opal_info->tper_acknack = tper->acknack; + opal_info->tper_async = tper->async; + opal_info->tper_buffer_mgt = tper->buffer_management; + opal_info->tper_comid_mgt = tper->comid_management; + opal_info->tper_streaming = tper->streaming; + opal_info->tper_sync = tper->sync; +} + +/* + * check single user mode + */ +static bool +opal_check_sum(struct spdk_opal_dev *dev, const void *data) +{ + const struct spdk_d0_sum *sum = data; + uint32_t num_locking_objects = from_be32(&sum->num_locking_objects); + struct spdk_opal_info *opal_info = dev->opal_info; + + if (num_locking_objects == 0) { + SPDK_NOTICELOG("Need at least one locking object.\n"); + return false; + } + + opal_info->single_user_mode = 1; + opal_info->single_user_locking_objects = num_locking_objects; + opal_info->single_user_any = sum->any; + opal_info->single_user_all = sum->all; + opal_info->single_user_policy = sum->policy; + + return true; +} + +static void +opal_check_lock(struct spdk_opal_dev *dev, const void *data) +{ + const struct spdk_d0_locking_features *lock = data; + struct spdk_opal_info *opal_info = dev->opal_info; + + opal_info->locking = 1; + opal_info->locking_locked = lock->locked; + opal_info->locking_locking_enabled = lock->locking_enabled; + opal_info->locking_locking_supported = lock->locking_supported; + opal_info->locking_mbr_done = lock->mbr_done; + opal_info->locking_mbr_enabled = lock->mbr_enabled; + opal_info->locking_media_encrypt = lock->media_encryption; +} + +static void +opal_check_geometry(struct spdk_opal_dev *dev, const void *data) +{ + const struct spdk_d0_geo_features *geo = data; + struct spdk_opal_info *opal_info = dev->opal_info; + uint64_t align = from_be64(&geo->alignment_granularity); + uint64_t lowest_lba = from_be64(&geo->lowest_aligned_lba); + + dev->align = align; + dev->lowest_lba = lowest_lba; + + opal_info->geometry = 1; + opal_info->geometry_align = geo->align; + opal_info->geometry_logical_block_size = from_be64(&geo->logical_block_size); + opal_info->geometry_lowest_aligned_lba = lowest_lba; + opal_info->geometry_alignment_granularity = align; +} + +static void +opal_check_datastore(struct spdk_opal_dev *dev, const void *data) +{ + const struct spdk_d0_datastore_features *datastore = data; + struct spdk_opal_info *opal_info = dev->opal_info; + + opal_info->datastore = 1; + opal_info->datastore_max_tables = from_be16(&datastore->max_tables); + opal_info->datastore_max_table_size = from_be32(&datastore->max_table_size); + opal_info->datastore_alignment = from_be32(&datastore->alignment); +} + +static uint16_t +opal_get_comid_v100(struct spdk_opal_dev *dev, const void *data) +{ + const struct spdk_d0_opal_v100 *v100 = data; + struct spdk_opal_info *opal_info = dev->opal_info; + uint16_t base_comid = from_be16(&v100->base_comid); + + opal_info->opal_v100 = 1; + opal_info->opal_v100_base_comid = base_comid; + opal_info->opal_v100_num_comid = from_be16(&v100->number_comids); + opal_info->opal_v100_range_crossing = v100->range_crossing; + + return base_comid; +} + +static uint16_t +opal_get_comid_v200(struct spdk_opal_dev *dev, const void *data) +{ + const struct spdk_d0_opal_v200 *v200 = data; + struct spdk_opal_info *opal_info = dev->opal_info; + uint16_t base_comid = from_be16(&v200->base_comid); + + opal_info->opal_v200 = 1; + opal_info->opal_v200_base_comid = base_comid; + opal_info->opal_v200_num_comid = from_be16(&v200->num_comids); + opal_info->opal_v200_range_crossing = v200->range_crossing; + opal_info->opal_v200_num_admin = from_be16(&v200->num_locking_admin_auth); + opal_info->opal_v200_num_user = from_be16(&v200->num_locking_user_auth); + + opal_info->opal_v200_initial_pin = v200->initial_pin; + opal_info->opal_v200_reverted_pin = v200->reverted_pin; + + return base_comid; +} + +static int +opal_discovery0_end(struct spdk_opal_dev *dev) +{ + bool found_com_id = false, supported = false, single_user = false; + const struct spdk_d0_header *hdr = (struct spdk_d0_header *)dev->resp; + const uint8_t *epos = dev->resp, *cpos = dev->resp; + uint16_t comid = 0; + uint32_t hlen = from_be32(&(hdr->length)); + + if (hlen > IO_BUFFER_LENGTH - sizeof(*hdr)) { + SPDK_ERRLOG("Discovery length overflows buffer (%zu+%u)/%u\n", + sizeof(*hdr), hlen, IO_BUFFER_LENGTH); + return -EFAULT; + } + + epos += hlen; /* end of buffer */ + cpos += sizeof(*hdr); /* current position on buffer */ + + while (cpos < epos) { + const union spdk_discovery0_features *body = + (const union spdk_discovery0_features *)cpos; + uint16_t feature_code = from_be16(&(body->tper.feature_code)); + + switch (feature_code) { + case FEATURECODE_TPER: + opal_check_tper(dev, body); + break; + case FEATURECODE_SINGLEUSER: + single_user = opal_check_sum(dev, body); + break; + case FEATURECODE_GEOMETRY: + opal_check_geometry(dev, body); + break; + case FEATURECODE_LOCKING: + opal_check_lock(dev, body); + break; + case FEATURECODE_DATASTORE: + opal_check_datastore(dev, body); + break; + case FEATURECODE_OPALV100: + comid = opal_get_comid_v100(dev, body); + found_com_id = true; + supported = true; + break; + case FEATURECODE_OPALV200: + comid = opal_get_comid_v200(dev, body); + found_com_id = true; + supported = true; + break; + default: + SPDK_NOTICELOG("Unknow feature code: %d\n", feature_code); + } + cpos += body->tper.length + 4; + } + + if (supported == false) { + SPDK_ERRLOG("Opal Not Supported.\n"); + return SPDK_OPAL_NOT_SUPPORTED; + } + + if (single_user == false) { + SPDK_NOTICELOG("Single User Mode Not Supported\n"); + } + + if (found_com_id == false) { + SPDK_ERRLOG("Could not find OPAL comid for device. Returning early\n"); + return -EINVAL; + } + + dev->comid = comid; + return 0; +} + +static int +opal_discovery0(struct spdk_opal_dev *dev, void *data) +{ + int ret; + + memset(dev->resp, 0, IO_BUFFER_LENGTH); + dev->comid = LV0_DISCOVERY_COMID; + ret = opal_recv_cmd(dev); + if (ret) { + return ret; + } + + return opal_discovery0_end(dev); +} + +static inline void +opal_setup_dev(struct spdk_opal_dev *dev, + const struct spdk_opal_step *steps) +{ + dev->steps = steps; + dev->tsn = 0; + dev->hsn = 0; + dev->prev_data = NULL; + dev->timeout = SPDK_OPAL_TPER_TIMEOUT; +} + +static int +opal_end_session_cb(struct spdk_opal_dev *dev) +{ + dev->hsn = 0; + dev->tsn = 0; + return 0; +} + +static int +opal_end_session(struct spdk_opal_dev *dev, void *data) +{ + int err = 0; + bool eod = 0; + + opal_clear_cmd(dev); + opal_set_comid(dev, dev->comid); + opal_add_token_u8(&err, dev, SPDK_OPAL_ENDOFSESSION); + + if (err < 0) { + return err; + } + return opal_finalize_and_send(dev, eod, opal_end_session_cb); +} + +static int +opal_end_session_error(struct spdk_opal_dev *dev) +{ + const struct spdk_opal_step error_end_session[] = { + { opal_end_session, }, + { NULL, } + }; + dev->steps = error_end_session; + return opal_next(dev); +} + +static int +opal_check_support(struct spdk_opal_dev *dev) +{ + const struct spdk_opal_step steps[] = { + { opal_discovery0, }, + { NULL, } + }; + int ret; + + opal_setup_dev(dev, steps); + ret = opal_next(dev); + if (ret == 0) { + dev->supported = true; + } else { + dev->supported = false; + } + + return ret; +} + +void +spdk_opal_close(struct spdk_opal_dev *dev) +{ + free(dev->opal_info); + free(dev); +} + +struct spdk_opal_dev * +spdk_opal_init_dev(void *dev_handler) +{ + struct spdk_opal_dev *dev; + struct spdk_opal_info *info; + + dev = calloc(1, sizeof(*dev)); + if (!dev) { + SPDK_ERRLOG("Memory allocation failed\n"); + return NULL; + } + + dev->dev_handler = dev_handler; + + info = calloc(1, sizeof(struct spdk_opal_info)); + if (info == NULL) { + free(dev); + SPDK_ERRLOG("Memory allocation failed\n"); + return NULL; + } + + dev->opal_info = info; + if (opal_check_support(dev) != 0) { + SPDK_INFOLOG(SPDK_LOG_OPAL, "Opal is not supported on this device\n"); + dev->supported = false; + } + return dev; +} + +void +spdk_opal_scan(struct spdk_opal_dev *dev) +{ + int ret; + + ret = opal_check_support(dev); + if (ret) { + SPDK_ERRLOG("check opal support failed: %d\n", ret); + spdk_opal_close(dev); + return; + } +} + +struct spdk_opal_info * +spdk_opal_get_info(struct spdk_opal_dev *dev) +{ + return dev->opal_info; +} + +bool +spdk_opal_supported(struct spdk_opal_dev *dev) +{ + return dev->supported; +} + +/* Log component for opal submodule */ +SPDK_LOG_REGISTER_COMPONENT("opal", SPDK_LOG_OPAL) diff --git a/lib/nvme/nvme_opal_internal.h b/lib/nvme/nvme_opal_internal.h new file mode 100644 index 000000000..288ccc883 --- /dev/null +++ b/lib/nvme/nvme_opal_internal.h @@ -0,0 +1,337 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SPDK_OPAL_INTERNAL_H +#define SPDK_OPAL_INTERNAL_H + +#include "spdk/opal_spec.h" +#include "spdk/opal.h" +#include "spdk/scsi_spec.h" + +#define IO_BUFFER_LENGTH 2048 +#define MAX_TOKS 64 +#define OPAL_KEY_MAX 256 +#define OPAL_UID_LENGTH 8 +#define OPAL_MAX_LRS 8 /* minimum 8 defined by spec */ + +#define SPDK_OPAL_TPER_TIMEOUT 30 /* seconds */ + +#define GENERIC_HOST_SESSION_NUM 0x69 + +#define OPAL_INVAL_PARAM 12 + +#define SPDK_DTAERROR_NO_METHOD_STATUS 0x89 + +enum opal_token_type { + OPAL_DTA_TOKENID_BYTESTRING = 0xE0, + OPAL_DTA_TOKENID_SINT = 0xE1, + OPAL_DTA_TOKENID_UINT = 0xE2, + OPAL_DTA_TOKENID_TOKEN = 0xE3, /* actual token is returned */ + OPAL_DTA_TOKENID_INVALID = 0X0, +}; + +enum opal_atom_width { + OPAL_WIDTH_TINY, /* 1 byte in length */ + OPAL_WIDTH_SHORT, /* a 1-byte header and contain up to 15 bytes of data */ + OPAL_WIDTH_MEDIUM, /* a 2-byte header and contain up to 2047 bytes of data */ + OPAL_WIDTH_LONG, /* a 4-byte header and which contain up to 16,777,215 bytes of data */ + OPAL_WIDTH_TOKEN +}; + +enum opal_uid_enum { + /* users */ + UID_SMUID, + UID_THISSP, + UID_ADMINSP, + UID_LOCKINGSP, + UID_ANYBODY, + UID_SID, + UID_ADMIN1, + UID_USER1, + UID_USER2, + + /* tables */ + UID_LOCKINGRANGE_GLOBAL, + UID_LOCKINGRANGE_ACE_RDLOCKED, + UID_LOCKINGRANGE_ACE_WRLOCKED, + UID_MBRCONTROL, + UID_MBR, + UID_AUTHORITY_TABLE, + UID_C_PIN_TABLE, + UID_LOCKING_INFO_TABLE, + UID_PSID, + + /* C_PIN_TABLE object ID's */ + UID_C_PIN_MSID, + UID_C_PIN_SID, + UID_C_PIN_ADMIN1, + UID_C_PIN_USER1, + + /* half UID's (only first 4 bytes used) */ + UID_HALF_AUTHORITY_OBJ_REF, + UID_HALF_BOOLEAN_ACE, +}; + +/* enum for indexing the spdk_opal_method array */ +enum opal_method_enum { + PROPERTIES_METHOD, + STARTSESSION_METHOD, + REVERT_METHOD, + ACTIVATE_METHOD, + NEXT_METHOD, + GETACL_METHOD, + GENKEY_METHOD, + REVERTSP_METHOD, + GET_METHOD, + SET_METHOD, + AUTHENTICATE_METHOD, + RANDOM_METHOD, +}; + +union spdk_discovery0_features { + struct spdk_d0_tper_features tper; + struct spdk_d0_locking_features locking; + struct spdk_d0_geo_features geometry; + struct spdk_d0_datastore_features datastore; + struct spdk_d0_sum sumode; + struct spdk_d0_opal_v200 opalv200; + struct spdk_d0_opal_v100 opalv100; +}; + +struct spdk_opal_session { + uint32_t sum; /* single user mode */ + uint32_t who; + struct spdk_opal_key *opal_key; +}; + +struct spdk_opal_lock_unlock { + struct spdk_opal_session session; + uint32_t l_state; +}; + +struct spdk_opal_new_pw { + struct spdk_opal_session session_start; + struct spdk_opal_session new_user_pw; +}; + +static const uint8_t spdk_opal_uid[][OPAL_UID_LENGTH] = { + /* users */ + [UID_SMUID] = /* Session Manager UID */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff }, + [UID_THISSP] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + [UID_ADMINSP] = + { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 }, + [UID_LOCKINGSP] = + { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 }, + [UID_ANYBODY] = + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 }, + [UID_SID] = /* Security Identifier UID */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 }, + [UID_ADMIN1] = + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 }, + [UID_USER1] = + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 }, + [UID_USER2] = + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 }, + + /* tables */ + [UID_LOCKINGRANGE_GLOBAL] = + { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 }, + [UID_LOCKINGRANGE_ACE_RDLOCKED] = + { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 }, + [UID_LOCKINGRANGE_ACE_WRLOCKED] = + { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 }, + [UID_MBRCONTROL] = + { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 }, + [UID_MBR] = + { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 }, + [UID_AUTHORITY_TABLE] = + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00}, + [UID_C_PIN_TABLE] = + { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00}, + [UID_LOCKING_INFO_TABLE] = + { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 }, + [UID_PSID] = + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 }, + + /* C_PIN_TABLE object ID's */ + [UID_C_PIN_MSID] = + { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02}, + [UID_C_PIN_SID] = + { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01}, + [UID_C_PIN_ADMIN1] = + { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01}, + [UID_C_PIN_USER1] = + { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x03, 0x00, 0x01}, + + /* half UID's (only first 4 bytes used) */ + [UID_HALF_AUTHORITY_OBJ_REF] = + { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff }, + [UID_HALF_BOOLEAN_ACE] = + { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff }, +}; + +/* + * TCG Storage SSC Methods. + */ +static const uint8_t spdk_opal_method[][OPAL_UID_LENGTH] = { + [PROPERTIES_METHOD] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 }, + [STARTSESSION_METHOD] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 }, + [REVERT_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 }, + [ACTIVATE_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 }, + [NEXT_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 }, + [GETACL_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d }, + [GENKEY_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 }, + [REVERTSP_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 }, + [GET_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 }, + [SET_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 }, + [AUTHENTICATE_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c }, + [RANDOM_METHOD] = + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 }, +}; + +enum spdk_opal_user { + OPAL_ADMIN1 = 0x0, + OPAL_USER1 = 0x01, + OPAL_USER2 = 0x02, + OPAL_USER3 = 0x03, + OPAL_USER4 = 0x04, + OPAL_USER5 = 0x05, + OPAL_USER6 = 0x06, + OPAL_USER7 = 0x07, + OPAL_USER8 = 0x08, + OPAL_USER9 = 0x09, +}; + +/* + * Response token + */ +struct spdk_opal_resp_token { + const uint8_t *pos; + uint8_t _padding[7]; + union { + uint64_t unsigned_num; + int64_t signed_num; + } stored; + size_t len; + enum opal_token_type type; + enum opal_atom_width width; +}; + +struct spdk_opal_resp_parsed { + int num; + struct spdk_opal_resp_token resp_tokens[MAX_TOKS]; +}; + +struct spdk_opal_step { + int (*opal_fn)(struct spdk_opal_dev *dev, void *data); + void *data; +}; + +struct spdk_opal_key { + uint8_t locking_range; + uint8_t key_len; + uint8_t _padding[6]; + uint8_t key[OPAL_KEY_MAX]; +}; + +struct spdk_opal_locking_range_activate { + struct spdk_opal_key key; + uint32_t sum; /* single user mode */ + uint8_t lockingrange_num; + uint8_t lockingrange[OPAL_MAX_LRS]; +}; + +struct spdk_opal_locking_range_setup { + uint8_t id; + uint8_t _padding[7]; + uint64_t range_start; + uint64_t range_length; + bool RLE; /* Read Lock enabled */ + bool WLE; /* Write Lock Enabled */ + struct spdk_opal_session session; +}; + +/* header of a response */ +struct spdk_opal_header { + struct spdk_opal_compacket com_packet; + struct spdk_opal_packet packet; + struct spdk_opal_data_subpacket sub_packet; +}; + +struct spdk_opal_dev { + bool supported; + void *dev_handler; + + const struct spdk_opal_step *steps; + uint16_t comid; + uint32_t hsn; + uint32_t tsn; + uint64_t align; + uint64_t lowest_lba; + + size_t cmd_pos; + uint8_t cmd[IO_BUFFER_LENGTH]; + uint8_t resp[IO_BUFFER_LENGTH]; + + struct spdk_opal_resp_parsed parsed_resp; + size_t prev_d_len; + void *prev_data; + + struct spdk_opal_key *dev_key; + + struct spdk_opal_info *opal_info; + + uint64_t timeout; /* seconds */ +}; + +enum opal_lock_state { + OPAL_LS_DISALBELOCKING = 0x00, + OPAL_LS_READLOCK_ENABLE = 0x01, + OPAL_LS_WRITELOCK_ENABLE = 0x02, + OPAL_LS_RWLOCK_ENABLE = 0x04, +}; + +#endif