diff --git a/Common/DtaOptions.h b/Common/DtaOptions.h
index c012af1d..007bb15f 100644
--- a/Common/DtaOptions.h
+++ b/Common/DtaOptions.h
@@ -21,6 +21,8 @@ along with sedutil. If not, see .
#ifndef _DTAOPTIONS_H
#define _DTAOPTIONS_H
+#include
+
/** Output modes */
typedef enum _sedutiloutput {
sedutilNormal,
diff --git a/Makefile.am b/Makefile.am
index 6656d593..fd0f4873 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 1ad8ba06..be52b958 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 00000000..4dc46d90
--- /dev/null
+++ b/linux/DtaDevLinuxNvmeMi.cpp
@@ -0,0 +1,202 @@
+/* C:B**************************************************************************
+This software is Copyright 2014-2017 Bright Plaza Inc.
+
+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 .
+
+ * C:E********************************************************************** */
+#include "config.h"
+#include "os.h"
+#include "DtaDevLinuxNvmeMi.h"
+
+#include
+
+constexpr int tcgDefaultTimeoutMS = 20*1000;
+
+static int parse_mi_dev(const char *dev, unsigned int *net, uint8_t *eid,
+ unsigned int *ctrl)
+{
+ int rc;
+
+ /* ,: form */
+ rc = sscanf(dev, "mctp:%u,%hhu:%u", net, eid, ctrl);
+ if (rc == 3)
+ return 0;
+
+ /* , 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;
+
+ unsigned int timeout = nvme_mi_ep_get_timeout(endpoint);
+ nvme_mi_ep_set_timeout(endpoint, tcgDefaultTimeoutMS);
+ rc = nvme_mi_admin_security_recv(controller, &args);
+ nvme_mi_ep_set_timeout(endpoint, timeout);
+ 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;
+
+ unsigned int timeout = nvme_mi_ep_get_timeout(endpoint);
+ nvme_mi_ep_set_timeout(endpoint, tcgDefaultTimeoutMS);
+ rc = nvme_mi_admin_security_send(controller, &args);
+ nvme_mi_ep_set_timeout(endpoint, timeout);
+ 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 00000000..905e437f
--- /dev/null
+++ b/linux/DtaDevLinuxNvmeMi.h
@@ -0,0 +1,64 @@
+/* C:B**************************************************************************
+This software is Copyright 2014-2017 Bright Plaza Inc.
+
+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 .
+
+ * C:E********************************************************************** */
+#pragma once
+#include
+#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 5261e736..f6163bcc 100644
--- a/linux/DtaDevOS.cpp
+++ b/linux/DtaDevOS.cpp
@@ -36,6 +36,7 @@ along with sedutil. If not, see .
#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";