sedutil: patch to support nvme-mi interface
We need sedutil to test and verify TCG feature of NVMe SSD in BMC.
In the meanwhile, we are tracking the patch on:
https://github.com/jinliangw/sedutil/tree/nvme-mi
Tested:
sedutil-cli --query mctp:1,16:0
mctp:1,16:0 NVMe MZWLR3T8HBLS-00AGG MPK9GP5Q S6HRNA0T517671
TPer function (0x0001)
ACKNAK = N, ASYNC = N. BufferManagement = N, comIDManagement = Y, Streaming = Y, SYNC = Y
Locking function (0x0002)
Locked = N, LockingEnabled = N, LockingSupported = Y, MBRDone = N, MBREnabled = N, MediaEncrypt = Y
Geometry function (0x0003)
Align = Y, Alignment Granularity = 9223372036854775807 (18446744073709551104), Logical Block size = 512, Lowest Aligned LBA = 0
SingleUser function (0x0201)
ALL = N, ANY = N, Policy = Y, Locking Objects = 33
DataStore function (0x0202)
Max Tables = 8, Max Size Tables = 10485760, Table size alignment = 1
OPAL 2.0 function (0x0203)
Base comID = 0x1000, Initial PIN = 0x00, Reverted PIN = 0x00, comIDs = 2
Locking Admins = 4, Locking Users = 33, Range Crossing = Y
TPer Properties:
AckNak = 0 Asynchronous = 0
ContinuedTokens = 0 SequenceNumbers = 0 DefSessionTimeout = 120000
MaxAuthentications = 4 MaxComIDTime = 60000 MaxComPacketSize = 16384
MaxIndTokenSize = 16328 MaxMethods = 1 MaxPackets = 1
MaxPacketSize = 16364 MaxReadSessions = 8 MaxResponseComPacketSize = 16384
MaxSessions = 9 MaxSessionTimeout = 0 MaxSubpackets = 1
MaxTransactionLimit = 1 MinSessionTimeout = 60000
Host Properties:
MaxComPacketSize = 2048 MaxIndTokenSize = 1992 MaxMethods = 1
MaxPackets = 1 MaxPacketSize = 2028 MaxSubpackets = 1
Google-Bug-Id: 274977344
Signed-off-by: Jinliang Wang <jinliangw@google.com>
Change-Id: Ia85646beb85c41a8193d9c0712fc976feb78cc61
diff --git a/recipes-extended/sedutil/sedutil/0001-Support-nvme-mi-device.patch b/recipes-extended/sedutil/sedutil/0001-Support-nvme-mi-device.patch
new file mode 100644
index 0000000..51bd2e0
--- /dev/null
+++ b/recipes-extended/sedutil/sedutil/0001-Support-nvme-mi-device.patch
@@ -0,0 +1,357 @@
+From a6b0a1544d10c67c942025555d6a4a5d3f787292 Mon Sep 17 00:00:00 2001
+From: Jinliang Wang <jinliangw@google.com>
+Date: Mon, 19 Dec 2022 15:20:55 -0800
+Subject: [PATCH] Support nvme-mi device
+
+Support NVMe-MI device based on libnvme-mi library.
+
+Tested:
+sedutil-cli --query mctp:1,17:0
+
+Patch Tracking Bug: b/274977344
+Upstream info / review: https://github.com/Drive-Trust-Alliance/sedutil/pull/421
+Upstream-Status: Submitted
+Justification: Upstreaming to Drive-Trust-Alliance
+
+Signed-off-by: Jinliang Wang <jinliangw@google.com>
+---
+ Makefile.am | 1 +
+ configure.ac | 5 +
+ linux/DtaDevLinuxNvmeMi.cpp | 194 ++++++++++++++++++++++++++++++++++++
+ linux/DtaDevLinuxNvmeMi.h | 64 ++++++++++++
+ linux/DtaDevOS.cpp | 5 +
+ 5 files changed, 269 insertions(+)
+ create mode 100644 linux/DtaDevLinuxNvmeMi.cpp
+ create mode 100644 linux/DtaDevLinuxNvmeMi.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 6656d59..fd0f487 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -28,6 +28,7 @@ SEDUTIL_LINUX_CODE = \
+ linux/Version.h linux/os.h linux/DtaDevLinuxDrive.h \
+ linux/DtaDevLinuxNvme.cpp linux/DtaDevLinuxSata.cpp \
+ linux/DtaDevLinuxNvme.h linux/DtaDevLinuxSata.h \
++ linux/DtaDevLinuxNvmeMi.h linux/DtaDevLinuxNvmeMi.cpp \
+ linux/DtaDevOS.cpp linux/DtaDevOS.h
+ sbin_PROGRAMS = sedutil-cli linuxpba
+ sedutil_cli_SOURCES = Common/sedutil.cpp Common/DtaOptions.cpp \
+diff --git a/configure.ac b/configure.ac
+index 1ad8ba0..be52b95 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -11,6 +11,10 @@ AC_PROG_CXX
+ AC_PROG_CC
+
+ # Checks for libraries.
++AC_CHECK_LIB(nvme-mi, nvme_mi_create_root)
++
++# libnvme-mi uses meson build tool which enables D_FILE_OFFSET_BITS=64 by default
++AC_SYS_LARGEFILE
+
+ # Checks for header files.
+ AC_CHECK_HEADERS([arpa/inet.h fcntl.h malloc.h stdint.h stdlib.h string.h sys/ioctl.h unistd.h])
+@@ -23,6 +27,7 @@ AC_TYPE_UINT16_T
+ AC_TYPE_UINT32_T
+ AC_TYPE_UINT8_T
+
++
+ # Checks for library functions.
+ AC_CHECK_FUNCS([memset])
+
+diff --git a/linux/DtaDevLinuxNvmeMi.cpp b/linux/DtaDevLinuxNvmeMi.cpp
+new file mode 100644
+index 0000000..d81b2f7
+--- /dev/null
++++ b/linux/DtaDevLinuxNvmeMi.cpp
+@@ -0,0 +1,194 @@
++/* C:B**************************************************************************
++This software is Copyright 2014-2017 Bright Plaza Inc. <drivetrust@drivetrust.com>
++
++This file is part of sedutil.
++
++sedutil is free software: you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation, either version 3 of the License, or
++(at your option) any later version.
++
++sedutil is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with sedutil. If not, see <http://www.gnu.org/licenses/>.
++
++ * C:E********************************************************************** */
++#include "config.h"
++#include "os.h"
++#include "DtaDevLinuxNvmeMi.h"
++
++#include <cstring>
++
++static int parse_mi_dev(const char *dev, unsigned int *net, uint8_t *eid,
++ unsigned int *ctrl)
++{
++ int rc;
++
++ /* <net>,<eid>:<ctrl-id> form */
++ rc = sscanf(dev, "mctp:%u,%hhu:%u", net, eid, ctrl);
++ if (rc == 3)
++ return 0;
++
++ /* <net>,<eid> form, implicit ctrl-id = 0 */
++ *ctrl = 0;
++ rc = sscanf(dev, "mctp:%u,%hhu", net, eid);
++ if (rc == 2)
++ return 0;
++
++ return -1;
++}
++
++
++/** The Device class represents a single disk device.
++ * Linux specific implementation using the NVMe interface
++ */
++DtaDevLinuxNvmeMi::DtaDevLinuxNvmeMi() {
++ net = 0;
++ eid = 0;
++ ctrl_id = 0;
++
++ root = NULL;
++ endpoint = NULL;
++ controller = NULL;
++}
++
++bool DtaDevLinuxNvmeMi::init(const char * devref)
++{
++ LOG(D1) << "Creating DtaDevLinuxNvmeMi::init " << devref;
++
++ int rc = parse_mi_dev(devref, &net, &eid, &ctrl_id);
++ if (rc)
++ {
++ LOG(E) << "invalid nvme-mi device specifier: " << devref;
++ goto error_free;
++ }
++
++ root = nvme_mi_create_root(stderr, LOG_WARNING);
++ if (!root)
++ {
++ LOG(E) << "can't create NVMe root";
++ goto error_free;
++ }
++
++ endpoint = nvme_mi_open_mctp(root, net, eid);
++ if (!endpoint)
++ {
++ LOG(E) << "can't open MCTP endpoint " << devref;
++ goto error_free;
++ }
++
++ controller = nvme_mi_init_ctrl(endpoint, ctrl_id);
++ if (!controller)
++ {
++ LOG(E) << "can't open MCTP controller " << devref;
++ goto error_free;
++ }
++
++ return TRUE; // isOpen = true
++
++error_free:
++ if (controller) {
++ nvme_mi_close_ctrl(controller);
++ controller = NULL;
++ }
++
++ if (endpoint) {
++ nvme_mi_close(endpoint);
++ endpoint = NULL;
++ }
++
++ if (root) {
++ nvme_mi_free_root(root);
++ root = NULL;
++ }
++ return FALSE; // isOpen = false
++}
++
++/** Send an ioctl to the device using nvme admin commands. */
++uint8_t DtaDevLinuxNvmeMi::sendCmd(ATACOMMAND cmd, uint8_t protocol,
++ uint16_t comID, void * buffer, uint32_t bufferlen)
++{
++ int rc;
++ LOG(D1) << "Entering DtaDevLinuxNvmeMi::sendCmd()";
++ if (IF_RECV == cmd) {
++ LOG(D3) << "Security Receive Command";
++ struct nvme_security_receive_args args = { 0 };
++ args.args_size = sizeof(args);
++ args.secp = protocol;
++ args.spsp0 = comID & 0xFF;
++ args.spsp1 = (comID >> 8);
++ args.al = bufferlen;
++ args.data_len = bufferlen;
++ args.data = buffer;
++
++ rc = nvme_mi_admin_security_recv(controller, &args);
++ if (rc < 0)
++ {
++ // transport layer error
++ LOG(E) << "security-receive failed: " << std::strerror(errno);
++ return rc;
++ }
++ }
++ else {
++ LOG(D3) << "Security Send Command";
++ nvme_security_send_args args= { 0 };
++ args.args_size = sizeof(args);
++ args.secp = protocol;
++ args.spsp0 = comID & 0xFF;
++ args.spsp1 = (comID >> 8);
++ args.tl = bufferlen;
++ args.data_len = bufferlen;
++ args.data = buffer;
++
++ rc = nvme_mi_admin_security_send(controller, &args);
++ if (rc < 0) {
++ // transport layer error
++ LOG(E) << "security-send failed: " << std::strerror(errno);
++ return rc;
++ }
++ }
++
++ if (rc != 0) {
++ // Status Field in Complection Queue Entry is not zero
++ LOG(E) << "NVME Security Command Error:" << std::hex << rc << std::dec;
++ }
++ return rc;
++}
++
++void DtaDevLinuxNvmeMi::identify(OPAL_DiskInfo& disk_info)
++{
++ LOG(D4) << "Entering DtaDevLinuxNvmeMi::identify()";
++ int rc = nvme_mi_admin_identify_ctrl(controller, &id_ctrl);
++ if (rc) {
++ LOG(E) << "Identify Controller failed: " << std::strerror(errno);
++ disk_info.devType = DEVICE_TYPE_OTHER;
++ return;
++ }
++
++ disk_info.devType = DEVICE_TYPE_NVME;
++ memcpy(disk_info.serialNum, id_ctrl.sn, sizeof(disk_info.serialNum));
++ memcpy(disk_info.modelNum, id_ctrl.mn, sizeof(disk_info.modelNum));
++ memcpy(disk_info.firmwareRev, id_ctrl.fr, sizeof(disk_info.firmwareRev));
++ return;
++}
++
++/** Close the device reference so this object can be delete. */
++DtaDevLinuxNvmeMi::~DtaDevLinuxNvmeMi()
++{
++ LOG(D1) << "Destroying DtaDevLinuxNvmeMi";
++ if (controller) {
++ nvme_mi_close_ctrl(controller);
++ }
++
++ if (endpoint) {
++ nvme_mi_close(endpoint);
++ }
++
++ if (root) {
++ nvme_mi_free_root(root);
++ }
++}
+diff --git a/linux/DtaDevLinuxNvmeMi.h b/linux/DtaDevLinuxNvmeMi.h
+new file mode 100644
+index 0000000..905e437
+--- /dev/null
++++ b/linux/DtaDevLinuxNvmeMi.h
+@@ -0,0 +1,64 @@
++/* C:B**************************************************************************
++This software is Copyright 2014-2017 Bright Plaza Inc. <drivetrust@drivetrust.com>
++
++This file is part of sedutil.
++
++sedutil is free software: you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation, either version 3 of the License, or
++(at your option) any later version.
++
++sedutil is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with sedutil. If not, see <http://www.gnu.org/licenses/>.
++
++ * C:E********************************************************************** */
++#pragma once
++#include <libnvme-mi.h>
++#include "DtaStructures.h"
++#include "DtaDevLinuxDrive.h"
++
++/** Linux specific implementation of DtaDevOS.
++ * Uses the NVMe to send commands to the
++ * device
++ */
++class DtaDevLinuxNvmeMi: public DtaDevLinuxDrive{
++public:
++ /** Default constructor */
++ DtaDevLinuxNvmeMi();
++ /** Destructor */
++ ~DtaDevLinuxNvmeMi();
++ /** NVMe specific initialization.
++ * This function should perform the necessary authority and environment checking
++ * to allow proper functioning of the program, open the device, perform an ATA
++ * identify, add the fields from the identify response to the disk info structure
++ * and if the device is an ATA device perform a call to Discovery0() to complete
++ * the disk_info structure
++ * @param devref character representation of the device is standard OS lexicon
++ */
++ bool init(const char * devref);
++ /** NVMe specific method to send a command to the device
++ * @param cmd command to be sent to the device
++ * @param protocol security protocol to be used in the command
++ * @param comID communications ID to be used
++ * @param buffer input/output buffer
++ * @param bufferlen length of the input/output buffer
++ */
++ uint8_t sendCmd(ATACOMMAND cmd, uint8_t protocol, uint16_t comID,
++ void * buffer, uint32_t bufferlen);
++ /** NVMe specific routine to send an identify to the device */
++ void identify(OPAL_DiskInfo& disk_info);
++
++private:
++ unsigned int net;
++ unsigned char eid;
++ unsigned int ctrl_id;
++ nvme_root_t root;
++ nvme_mi_ep_t endpoint;
++ nvme_mi_ctrl_t controller;
++ struct nvme_id_ctrl id_ctrl;
++};
+diff --git a/linux/DtaDevOS.cpp b/linux/DtaDevOS.cpp
+index 5261e73..f6163bc 100644
+--- a/linux/DtaDevOS.cpp
++++ b/linux/DtaDevOS.cpp
+@@ -36,6 +36,7 @@ along with sedutil. If not, see <http://www.gnu.org/licenses/>.
+ #include "DtaDevOS.h"
+ #include "DtaHexDump.h"
+ #include "DtaDevLinuxSata.h"
++#include "DtaDevLinuxNvmeMi.h"
+ #include "DtaDevLinuxNvme.h"
+ #include "DtaDevGeneric.h"
+
+@@ -70,6 +71,10 @@ void DtaDevOS::init(const char * devref)
+ // DtaDevLinuxSata *SataDrive = new DtaDevLinuxSata();
+ drive = new DtaDevLinuxSata();
+ }
++ else if (!strncmp(devref, "mctp:", 5))
++ {
++ drive = new DtaDevLinuxNvmeMi();
++ }
+ else
+ {
+ LOG(E) << "DtaDevOS::init ERROR - unknown drive type";
+--
+2.39.0.314.g84b9a713c41-goog
+
diff --git a/recipes-extended/sedutil/sedutil_%.bbappend b/recipes-extended/sedutil/sedutil_%.bbappend
new file mode 100644
index 0000000..663b221
--- /dev/null
+++ b/recipes-extended/sedutil/sedutil_%.bbappend
@@ -0,0 +1,12 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += " libnvme"
+
+SRC_URI += " \
+ file://0001-Support-nvme-mi-device.patch \
+ "
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${B}/sedutil-cli ${D}${bindir}/
+}