Signed-off-by: Mohit Kapoor

---

diff --git a/Makefile b/Makefile
index 86eb7c6..3ea82dd 100644
--- a/Makefile
+++ b/Makefile
@@ -83,6 +83,13 @@ PLUGIN_OBJS :=					\
 	plugins/wdc/wdc-utils.o			\
 	plugins/huawei/huawei-nvme.o		\
 	plugins/netapp/netapp-nvme.o		\
+	plugins/mi/util/hal/mi-nvme-hal-main.o 		\
+	plugins/mi/util/hal/mi-nvme-qemu/mi-nvme-qemu.o \
+	plugins/mi/util/mi-nvme-util-base.o			\
+	plugins/mi/util/mi-nvme-util-crc.o 			\
+	plugins/mi/util/mi-nvme-util-tool.o 			\
+	plugins/mi/mi-nvme.o			\
+	plugins/mi/mi-nvme-cmd.o			\
 	plugins/toshiba/toshiba-nvme.o		\
 	plugins/micron/micron-nvme.o		\
 	plugins/seagate/seagate-nvme.o 		\
diff --git a/plugins/mi/mi-nvme-cmd.c b/plugins/mi/mi-nvme-cmd.c
new file mode 100644
index 0000000..3a71170
--- /dev/null
+++ b/plugins/mi/mi-nvme-cmd.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-cmd.c - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#include "mi-nvme-cmd.h"
+
+uint32_t gettransmissionunitsize()
+{
+    return MCTP_TRANS_UNIT_SIZE_VAL_DEF;
+}
+
+int executecommand(__u8 *cmdobj)
+{
+    struct nvme_mi_mctp_message_t message;
+    memset(&message, 0, sizeof(struct nvme_mi_mctp_message_t));
+    nvme_mi_admin_cmd_mctp_message adminmessage;
+    memset(&adminmessage, 0, sizeof(nvme_mi_admin_cmd_mctp_message));
+    bool ret = false;
+    uint32_t RequestDataSize = 0;
+    struct gencmd_nvmemi *micmd;
+    struct gencmd_nvmemi_admin *miadmincmd;
+    uint32_t uiMCTP_TUS = gettransmissionunitsize();
+
+    ret = initialize(uiMCTP_TUS);
+    if (ret == false) {
+        return -1;
+    }
+
+    streply.length = 0;
+    streply.errorcode = 0;
+    memset(streply.replybuf, 0, sizeof(streply.replybuf));
+
+    /*Skipping first element in the structure.... Size of buffer is 4 bytes each(uint32_t) in the  NVMe_MI_Header structure*/
+    memcpy(&message.msgPld, cmdobj, sizeof(struct nvme_mi_mctp_message_t) - 8);
+
+    /*Check if the incoming command is an MI/MI-Admin Command*/
+    if (message.msgPld.nvme_mi_message_header & 0x00001000)	{
+        miadmincmd = (struct gencmd_nvmemi_admin *)cmdobj;
+        /*Skipping first element in the structure....Size of buffer is 4 bytes each(uint32_t) in the  NVMe_MI_Header structure*/
+        memcpy(&adminmessage.msgPld, cmdobj, sizeof(nvme_mi_admin_cmd_mctp_message) - 8);
+        if (miadmincmd->buf != NULL) {
+            adminmessage.msgPld.buffer = miadmincmd->buf;
+        }
+        ret = execute_nvme_mi_admin_command(adminmessage, &(streply), REPLY_BUFFER_SIZE, miadmincmd->dlen);
+    } else if (message.msgPld.nvme_mi_message_header & 0x00000800) {
+        micmd = (struct gencmd_nvmemi *)cmdobj;
+        if (micmd->buf != NULL) {
+        message.msgPld.buffer = micmd->buf;
+        }
+        ret = execute_nvme_mi_command(message, &(streply), REPLY_BUFFER_SIZE, RequestDataSize);
+    }
+
+    if (!ret) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+int getresponsedata(uint8_t *buf, uint32_t size, bool ismicmd)
+{
+    uint32_t offset = 0;
+    uint32_t length = gettransmissionunitsize() - NVME_MI_HEADER_SIZE;
+    uint32_t bytesread = 0;
+
+    if (buf == NULL) {
+        printf("Error : getresponsedata input buf is NULL\n");
+        return -1;
+    }
+
+    if (ismicmd == true) {
+        offset = MCTP_PKT_HEADER_SIZE + NVME_MI_STATUS_SIZE + NVME_MI_HEADER_SIZE;
+        length = gettransmissionunitsize() - NVME_MI_HEADER_SIZE - NVME_MI_STATUS_SIZE;
+        streply.length = streply.length -  NVME_MI_HEADER_SIZE - NVME_MI_STATUS_SIZE - CRC_SIZE;
+    } else {
+        offset = MCTP_PKT_HEADER_SIZE + NVME_MI_STATUS_SIZE + NVME_MI_HEADER_SIZE + CQENTRY_SIZE;
+        length = gettransmissionunitsize() - NVME_MI_HEADER_SIZE - NVME_MI_STATUS_SIZE - CQENTRY_SIZE;
+        streply.length = streply.length - NVME_MI_HEADER_SIZE - NVME_MI_STATUS_SIZE - CRC_SIZE - CQENTRY_SIZE;
+    }
+
+    if (length > size) {
+        length = size;
+    }
+
+    while (bytesread < streply.length) {
+        memcpy(buf + bytesread, streply.replybuf + offset, length);
+        offset += length + MCTP_PKT_HEADER_SIZE;
+        bytesread += length;
+
+        if (bytesread + gettransmissionunitsize() > streply.length) {
+            length = streply.length - bytesread;
+        } else {
+            length = gettransmissionunitsize();
+        }
+    }
+    return 0;
+}
+
+void getresponsemessage(uint8_t *buf, uint32_t size)
+{
+    memcpy(buf, streply.replybuf + MCTP_PKT_HEADER_SIZE, size);
+}
diff --git a/plugins/mi/mi-nvme-cmd.h b/plugins/mi/mi-nvme-cmd.h
new file mode 100644
index 0000000..9a15ada
--- /dev/null
+++ b/plugins/mi/mi-nvme-cmd.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-cmd.h - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#ifndef _MI_NVME__CMD_H_
+#define _MI_NVME_CMD_H_
+
+#include "mi-nvme-struct.h"
+#include "util/mi-nvme-util-base.h"
+#include "util/mi-nvme-util-tool.h"
+
+mctp_reply_buffer_struct streply;
+
+uint32_t gettransmissionunitsize();
+int executecommand(__u8 *cmdobj);
+int getresponsedata(uint8_t *buf, uint32_t size, bool flagmi);
+void getresponsemessage(uint8_t *buf, uint32_t size);
+
+#endif
diff --git a/plugins/mi/mi-nvme-struct.h b/plugins/mi/mi-nvme-struct.h
new file mode 100644
index 0000000..4eed296
--- /dev/null
+++ b/plugins/mi/mi-nvme-struct.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-struct.h - Implementation of NVMe Management Interface commands in NVMe.
+ * This file contains required header and response structures for MI commands.
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#ifndef _MI_NVME__HEADER_H_
+#define _MI_NVME_HEADER_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <linux/types.h>
+
+#define MCTP_PKT_HEADER_SIZE 8
+#define NVME_MI_HEADER_SIZE 4
+#define NVME_MI_STATUS_SIZE 4
+#define CQENTRY_SIZE 12
+#define MCTP_TRANS_UNIT_SIZE_VAL_DEF 64
+
+enum nvmemi_opcode {
+    nvmemi_cmd_readnvmemids = 0x00,
+    nvmemi_cmd_subsyshealthstpoll = 0x01,
+    nvmemi_cmd_chsp = 0x02,
+    nvmemi_cmd_configurationset	= 0x03,
+    nvmemi_cmd_configurationget = 0x04,
+    nvmemi_cmd_vpdread = 0x05,
+    nvmemi_cmd_vpdwrite = 0x06
+};
+
+typedef enum _MI_COMMAND_TYPE {
+    COMMAND_TYPE_MI,
+    COMMAND_TYPE_MI_ADMIN
+}MI_COMMAND_TYPE;
+
+enum CONFIGURATION_IDENTIFIER {
+    RESERVED,
+    SMBUS_I2C_FREQ,
+    HEALTH_STATUS_CHG,
+    MCTP_TRANS_UNIT_SIZE,
+};
+
+struct nvmemi_message_header_struct {
+    uint32_t message_type:7;
+    uint32_t ic:1;
+    uint32_t csi:1;
+    uint32_t reserved:2;
+    uint32_t nmimt:4;
+    uint32_t ror:1;
+    uint32_t reserved1:16;
+};
+
+typedef struct _mctp_message_header {
+    uint8_t messsage_type:7;
+    uint8_t ic:1;
+    uint8_t instance_id:5;
+    uint8_t rsvd:1;
+    uint8_t D:1;
+    uint8_t RQ:1;
+    uint8_t Command_Code;
+}mctp_message_header;
+
+/*Generic command Structure for NVMe MI Commands*/
+struct gencmd_nvmemi {
+    struct nvmemi_message_header_struct msg_header;
+    uint8_t opcode;
+    uint8_t reserved0;
+    uint8_t reserved1;
+    uint8_t reserved2;
+    uint32_t cdw0;
+    uint32_t cdw1;
+    uint8_t *buf;
+    uint32_t mic;
+};
+
+/*Generic command Structure for NVMe MI Admin Commands*/
+struct gencmd_nvmemi_admin {
+    struct nvmemi_message_header_struct msg_header;
+    uint8_t opcode;
+    uint8_t cflgs;
+    uint16_t ctlid;
+    uint32_t nsid;
+    uint32_t cdw2;
+    uint32_t cdw3;
+    uint32_t cdw4;
+    uint32_t cdw5;
+    uint32_t dofst;
+    uint32_t dlen;
+    uint32_t cdw8;
+    uint32_t cdw9;
+    uint32_t cdw10;
+    uint32_t cdw11;
+    uint32_t cdw12;
+    uint32_t cdw13;
+    uint32_t cdw14;
+    uint32_t cdw15;
+    uint8_t *buf;
+    uint32_t mic;
+};
+
+struct admin_cmd_resp_dw3 {
+    uint16_t cid;
+    uint16_t p:1;
+    uint16_t sc:8;
+    uint16_t sct:3;
+    uint16_t crd:2;
+    uint16_t m:1;
+    uint16_t NVME_DIR_SND_ID_OP_ENABLE:1;
+};
+
+struct nvme_admin_cmd_resp_status {
+    uint8_t msg_type:7;
+    uint8_t ic:1;
+
+    uint8_t csi:1;
+    uint8_t reserved :2;
+    uint8_t nvme_mi_msg_type:4;
+    uint8_t ror:1;
+
+    uint16_t reserved1;
+
+    uint32_t status:8;
+    uint32_t nvme_mgmt_response:24;
+
+    uint32_t cqdw0;
+    uint32_t cqdw1;
+    struct admin_cmd_resp_dw3 cqdw3;
+};
+
+struct nvme_mi_cmd_resp {
+    uint8_t msg_type:7;
+    uint8_t ic:1;
+
+    uint8_t csi:1;
+    uint8_t reserved:2;
+    uint8_t nvme_mi_msg_type:4;
+    uint8_t ror:1;
+
+    uint16_t reserved1;
+
+    uint32_t status:8;
+    uint32_t nvme_mgmt_response:24;
+};
+
+struct read_nvme_mi_data_struct_resp {
+    uint16_t resp_data_len;
+    uint8_t reserved;
+};
+
+struct smbus_i2c_freq_cfgget_resp {
+    uint8_t smbus_i2c_freq:4;
+    uint8_t reserved1:4;
+    uint16_t reserved2;
+};
+
+struct mctp_tus_cfgget_resp {
+    uint16_t mctp_trans_unit_size;
+    uint8_t reserved;
+};
+
+struct nvme_subsys_info_data {
+    uint8_t nump;
+    uint8_t mjr;
+    uint8_t mnr;
+    uint8_t reserved[29];
+};
+
+struct option_sup_cmd_struct {
+    uint8_t cmdtype;
+    uint8_t opc;
+};
+
+struct option_sup_cmd_list_struct {
+    uint16_t numcmd;
+    struct option_sup_cmd_struct cmdstruct[2047];
+};
+
+struct nss_status_struct {
+    uint8_t RESERVED			:2;
+    uint8_t PORT1_PLA			:1;
+    uint8_t PORT2_PLA			:1;
+    uint8_t RESET_NOT_REQ      :1;
+    uint8_t DRIVE_FUNC         :1;
+    uint8_t RESERVED1          :2;
+};
+
+struct comp_ctrl_status_struct {
+    uint16_t READY									:1;
+    uint16_t CFS					                :1;
+    uint16_t SHN_STS								:2;
+    uint16_t NSSR_OCCURRED						    :1;
+    uint16_t CECO									:1;
+    uint16_t NSAC									:1;
+    uint16_t FWACT									:1;
+    uint16_t CS_CH									:1;
+    uint16_t CTC									:1;
+    uint16_t PERCENTAGE_USED						:1;
+    uint16_t AVAILABLE_SPARE						:1;
+    uint16_t CRITICAL_WARNING						:1;
+    uint16_t RESERVED								:3;
+};
+
+struct nvm_subsys_health_struct {
+    struct nss_status_struct nss_status;
+    uint8_t smart_warnings;
+    uint8_t composite_temp;
+    uint8_t per_drv_life_used;
+    struct comp_ctrl_status_struct  comp_ctrl_status;
+    uint16_t reserved;
+};
+
+struct ctrl_health_status_poll_resp {
+    __u16 reserved;
+    __u8 rent;
+};
+
+struct cwarn_struct {
+    __u8 spare_thresh:1;
+    __u8 temp_above_or_under_thresh:1;
+    __u8 rel_degraded:1;
+    __u8 read_only:1;
+    __u8 vol_mem_bup_fail:1;
+    __u8 reserved:3;
+};
+
+struct csts_struct {
+    __u16 rdy									:1;
+    __u16 cfs					                :1;
+    __u16 shst									:2;
+    __u16 nssro								    :1;
+    __u16 en									:1;
+    __u16 nssac									:1;
+    __u16 fwact									:1;
+    __u16 reserved                              :8;
+};
+
+struct ctrl_health_data {
+    __u16 ctlid;
+    struct csts_struct csts;
+    __u16 ctemp;
+    __u8 pdlu;
+    __u8 spare;
+    struct cwarn_struct cwarn;
+    __u8 reserved[7];
+};
+
+struct log_page_error_info
+{
+	uint64_t errcnt;
+	uint16_t subqid;
+	uint16_t cid;
+	uint16_t statusfield;
+	uint8_t perr_loc_byte;
+	uint8_t perr_loc_bit:3;
+	uint8_t perr_loc_res:5;
+	uint64_t lba;
+	uint32_t ns;
+	uint8_t vsinfoavl;
+	uint8_t reserved[35];
+};
+
+struct getf_temp_thres
+{
+	uint16_t tmpth;
+	uint16_t tmpsel:4;
+	uint16_t thsel:2;
+	uint16_t reserved:10;
+};
+
+struct getf_no_queues
+{
+	uint16_t nsqa;
+	uint16_t ncqa;
+};
+
+#endif
diff --git a/plugins/mi/mi-nvme.c b/plugins/mi/mi-nvme.c
new file mode 100644
index 0000000..91ed5c7
--- /dev/null
+++ b/plugins/mi/mi-nvme.c
@@ -0,0 +1,1213 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme.c - Implementation of NVMe Management Interface commands in NVMe.
+ * This file contains the MI command implementation for the plugin
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "common.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "json.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include <time.h>
+#include "mi-nvme.h"
+#include "linux/nvme.h"
+#include "mi-nvme-cmd.h"
+#include "util/hal/mi-nvme-hal-main.h"
+
+void cleanup_nvmemi()
+{
+    bool ret = close_device();
+    if (ret == false) {
+        printf("Error : Close device Failed!\n");
+    }
+}
+
+int parse_and_open_nvmemi(int argc, char **argv, const char *desc,
+    const struct argconfig_commandline_options *opts)
+{
+    int ret = 0;
+    ret = argconfig_parse(argc, argv, desc, opts);
+	if (ret < 0) {
+		return ret;
+    }
+
+    printf("Setting Sideband Interface to QEMU MI\n");
+    SetSidebandInterface(qemu_nvme_mi);
+
+    return ret;
+}
+
+void msg_header_nvmemi(struct nvmemi_message_header_struct *str, MI_COMMAND_TYPE cmdtype)
+{
+    if (cmdtype == COMMAND_TYPE_MI) {
+        str->message_type = 4;
+        str->ic = 1;
+        str->csi = 0;
+        str->reserved = 0;
+        str->nmimt = 1;
+        str->ror = 0;
+        str->reserved1 = 0;
+    } else if (cmdtype == COMMAND_TYPE_MI_ADMIN) {
+        str->message_type = 4;
+        str->ic = 1;
+        str->csi = 0;
+        str->reserved = 0;
+        str->nmimt = 2;
+        str->ror = 0;
+        str->reserved1 = 0;
+    }
+}
+
+static int nvmemi_cmd_response(struct nvme_mi_cmd_resp *resp, bool ismgmtresp)
+{
+    if (ismgmtresp) {
+        printf("Get the response message for the executed command\n");
+        getresponsemessage((__u8 *)resp, sizeof(struct nvme_mi_cmd_resp));
+    }
+
+    return 0;
+}
+
+static int nvmemi_readnvmemids(__u16 ctrlid, __u8 portid, __u8 dtyp)
+{
+    int retval = 0;
+    __u32 cdw0 = ctrlid | portid << 16 | dtyp << 24;
+    __u32 cdw1 = 0;
+    struct nvmemi_message_header_struct str;
+
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI);
+
+    struct gencmd_nvmemi cmd = {
+        .msg_header = str,
+        .opcode = nvmemi_cmd_readnvmemids,
+        .reserved0 = 0,
+        .reserved1 = 0,
+        .reserved2 = 0,
+        .cdw0 = cdw0,
+        .cdw1 = cdw1,
+        .buf = NULL,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    struct read_nvme_mi_data_struct_resp readNVMeDS;
+    struct nvme_mi_cmd_resp resp;
+    memset(&readNVMeDS, 0, sizeof(struct read_nvme_mi_data_struct_resp));
+    memset(&resp, 0, sizeof(struct nvme_mi_cmd_resp));
+
+    retval = nvmemi_cmd_response(&resp, true);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Copy the Management Response*/
+    uint64_t address = (uint64_t)&resp;
+	memcpy(&readNVMeDS, (void*)(address + 5), sizeof(struct read_nvme_mi_data_struct_resp));
+
+    if (readNVMeDS.resp_data_len == 0) {
+        printf("Response data length is 0 in NVMe Management Response!\n");
+        return -1;
+    }
+
+    __u8 *Respbuffer = (__u8 *)malloc(readNVMeDS.resp_data_len);
+    if (Respbuffer == NULL) {
+        printf("Memory allocation error.\n");
+        return -1;
+    }
+
+    retval = getresponsedata(Respbuffer, readNVMeDS.resp_data_len, true);
+    if (retval == -1) {
+        printf("Error : Failed to get response data for the command!\n");
+        return retval;
+    }
+
+    if (dtyp == 0x0) {
+        struct nvme_subsys_info_data NVMeSubsysInfoDS;
+        memset(&NVMeSubsysInfoDS, 0, sizeof(struct nvme_subsys_info_data));
+        memcpy(&NVMeSubsysInfoDS, Respbuffer, readNVMeDS.resp_data_len);
+
+        printf("NVMe-MI Major Version Number = %u\n", NVMeSubsysInfoDS.mjr);
+        printf("NVMe-MI Minor Version Number = %u\n", NVMeSubsysInfoDS.mnr);
+        printf("Number of Ports = %u\n", NVMeSubsysInfoDS.nump);
+    } else if (dtyp == 0x4) {
+        struct option_sup_cmd_list_struct opCommandList;
+        memset(&opCommandList, 0 , sizeof(struct option_sup_cmd_list_struct));
+        memcpy(&opCommandList, Respbuffer, readNVMeDS.resp_data_len);
+
+        printf("Number of commands = %u\n", opCommandList.numcmd);
+    }
+
+    if (Respbuffer != NULL) {
+        free(Respbuffer);
+        Respbuffer = NULL;
+    }
+
+    return retval;
+}
+
+static int readnvmemids(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "Read NVMe MI Data Structure";
+    const char *ctrlid = "Controller Identifier";
+    const char *portid = "Port Identifier";
+    const char *dtyp = "Data Structure Type";
+
+    int retval;
+    int err = -1;
+
+    struct config {
+        __u16 ctrlid;
+        __u8 portid;
+        __u8 dtyp;
+    };
+
+    struct config cfg;
+
+    OPT_ARGS(opts) = {
+        OPT_SHRT("ctrlid", 'c', &cfg.ctrlid, ctrlid),
+        OPT_BYTE("portid", 'p', &cfg.portid, portid),
+        OPT_BYTE("dtyp", 'd', &cfg.dtyp, dtyp),
+        OPT_END()
+    };
+
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    printf("Issuing readnvmemids Command, ctrlid:%"PRIx16" portid:%d dtyp:%d\n",
+            (uint16_t)cfg.ctrlid, cfg.portid, cfg.dtyp);
+    err = nvmemi_readnvmemids(cfg.ctrlid, cfg.portid, cfg.dtyp);
+    if (!err) {
+        printf("readnvmemids: Success\n");
+    } else if (err > 0) {
+        printf("readnvmemids: Fail, ctrlid:%"PRIx16" portid:%d dtyp:%d\n",
+            (uint16_t)cfg.ctrlid, cfg.portid, cfg.dtyp);
+    }
+
+    cleanup_nvmemi();
+    return err;
+}
+
+static int nvmemi_shspoll(__u8 cs)
+{
+    int retval = 0;
+    __u32 Reserved = 0;
+    __u32 cdw0 = Reserved | cs << 31;
+
+    struct nvmemi_message_header_struct str;
+
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI);
+
+    struct gencmd_nvmemi cmd = {
+        .msg_header = str,
+        .opcode = nvmemi_cmd_subsyshealthstpoll,
+        .reserved0 = 0,
+        .reserved1 = 0,
+        .reserved2 = 0,
+        .cdw0 = cdw0,
+        .cdw1 = 0,
+        .buf = NULL,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    struct nvm_subsys_health_struct subsysStruct;
+    memset(&subsysStruct, 0, sizeof(struct nvm_subsys_health_struct));
+    uint16_t sizetocopy = sizeof(struct nvm_subsys_health_struct);
+
+    __u8 *Respbuffer = (__u8 *)malloc(sizetocopy);
+
+    if (Respbuffer == NULL) {
+        printf("Memory allocation error.\n");
+        return -1;
+    }
+
+    retval = getresponsedata(Respbuffer, sizetocopy, true);
+    if (retval == -1) {
+        printf("Error : Failed to get response data for the command!\n");
+        return retval;
+    }
+
+    memcpy(&subsysStruct, Respbuffer, sizetocopy);
+
+    printf("**********COMMAND RESPONSE START**********\n");
+    printf("SMART Warnings = %u\n", subsysStruct.smart_warnings);
+    printf("Composite Temprature = %u\n", subsysStruct.composite_temp);
+    printf("Percentage Drive Life Used = %u\n", subsysStruct.per_drv_life_used);
+    printf("**********COMMAND RESPONSE END**********\n");
+
+    if (Respbuffer != NULL) {
+        free(Respbuffer);
+        Respbuffer = NULL;
+    }
+
+    return retval;
+}
+
+static int shspoll(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "NVM Subsystem Health Status Poll";
+    const char *cs = "Clear Status";
+
+    int retval;
+    int err = -1;
+
+    struct config {
+        __u8 cs;
+    };
+
+    struct config cfg;
+
+    OPT_ARGS(opts) = {
+        OPT_SHRT("cs", 'c', &cfg.cs, cs),
+        OPT_END()
+    };
+
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    printf("Issuing Subsystem Health Status Poll Command, cs:%"PRIx8"\n",
+            (uint8_t)cfg.cs);
+    err = nvmemi_shspoll(cfg.cs);
+    if (!err) {
+        printf("NVM Subsystem Health Status Poll: Success\n");
+    } else if (err > 0) {
+        printf("NVM Subsystem Health Status Poll Fail, ctrlid:%"PRIx8"\n",
+            (uint8_t)cfg.cs);
+    }
+
+    cleanup_nvmemi();
+    return err;
+}
+
+static int nvmemi_chspoll(__u32 cdw0, __u32 cdw1)
+{
+    int retval = 0;
+    struct nvmemi_message_header_struct str;
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI);
+
+    struct gencmd_nvmemi cmd = {
+        .msg_header = str,
+        .opcode = nvmemi_cmd_chsp,
+        .reserved0 = 0,
+        .reserved1 = 0,
+        .reserved2 = 0,
+        .cdw0 = cdw0,
+        .cdw1 = cdw1,
+        .buf = NULL,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    struct ctrl_health_status_poll_resp mgmtresp;
+    struct nvme_mi_cmd_resp resp;
+    memset(&mgmtresp, 0, sizeof(struct ctrl_health_status_poll_resp));
+    memset(&resp, 0, sizeof(struct nvme_mi_cmd_resp));
+
+    retval = nvmemi_cmd_response(&resp, true);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Copy the Management Response*/
+    uint64_t address = (uint64_t)&resp;
+	memcpy(&mgmtresp, (void*)(address + 5), sizeof(struct ctrl_health_status_poll_resp));
+    //memcpy((void *)&mgmtresp, (void *)&resp.nvme_mgmt_response , sizeof(struct ctrl_health_status_poll_resp));
+
+    if (mgmtresp.rent == 0) {
+        printf("The number of Response Entries is zero!\n");
+        return -1;
+    }
+
+    __u8 *Respbuffer = (__u8 *)malloc(mgmtresp.rent * sizeof(struct ctrl_health_data));
+    if (Respbuffer == NULL) {
+        printf("Memory allocation error.\n");
+        return -1;
+    }
+
+    retval = getresponsedata(Respbuffer, mgmtresp.rent * sizeof(struct ctrl_health_data), true);
+    if (retval == -1) {
+        printf("Error : Failed to get response data for the command!\n");
+        return retval;
+    }
+
+    struct ctrl_health_data chds;
+    memset(&chds, 0, sizeof(struct ctrl_health_data));
+    memcpy(&chds, Respbuffer, sizeof(struct ctrl_health_data));
+
+    printf("Controller Identifier = %u\n", chds.ctlid);
+    printf("Composite Temprature = %u\n", chds.ctemp);
+    printf("Percentage Used = %u\n", chds.pdlu);
+    printf("Available Space = %u\n", chds.spare);
+
+    if (Respbuffer != NULL) {
+        free(Respbuffer);
+        Respbuffer = NULL;
+    }
+
+    return retval;
+}
+
+static int chspoll(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "NVM Controller Health Status Poll";
+    const char *cdw0 = "Command DWORD0 Value";
+    const char *cdw1 = "Command DWORD1 Value";
+
+    int retval;
+    int err = -1;
+
+    struct config {
+        __u32 cdw0;
+        __u32 cdw1;
+    };
+
+    struct config cfg;
+
+    OPT_ARGS(opts) = {
+        OPT_SHRT("cdw0", 'c', &cfg.cdw0, cdw0),
+        OPT_SHRT("cdw1", 'd', &cfg.cdw1, cdw1),
+        OPT_END()
+    };
+
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    printf("Issuing Controller Health Status Poll Command, cdw0 : \
+         %"PRIx32" cdw1 : %"PRIx32"\n", cfg.cdw0, cfg.cdw1);
+
+    err = nvmemi_chspoll(cfg.cdw0, cfg.cdw1);
+    if (!err) {
+        printf("Controller Health Status Poll: Success\n");
+    } else if (err > 0) {
+        printf("Controller Health Status Poll Failed!\n");
+    }
+
+    cleanup_nvmemi();
+    return err;
+}
+
+static int nvmemi_configget(__u8 configid, __u8 portid)
+{
+    int retval = 0;
+    __u32 cdw0 = configid | portid << 24;
+    __u32 cdw1 = 0;
+    struct nvmemi_message_header_struct str;
+
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI);
+
+    struct gencmd_nvmemi cmd = {
+        .msg_header = str,
+        .opcode = nvmemi_cmd_configurationget,
+        .reserved0 = 0,
+        .reserved1 = 0,
+        .reserved2 = 0,
+        .cdw0 = cdw0,
+        .cdw1 = cdw1,
+        .buf = NULL,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    struct nvme_mi_cmd_resp resp;
+    memset(&resp, 0, sizeof(struct nvme_mi_cmd_resp));
+
+    retval = nvmemi_cmd_response(&resp, true);
+    if (retval == -1) {
+        return retval;
+    }
+
+
+    uint64_t address = (uint64_t)&resp;
+
+    if (configid == SMBUS_I2C_FREQ) {
+        struct smbus_i2c_freq_cfgget_resp mgmt_resp;
+        memset(&mgmt_resp, 0, sizeof(struct smbus_i2c_freq_cfgget_resp));
+        memcpy(&mgmt_resp, (void *)(address + 5), sizeof(struct smbus_i2c_freq_cfgget_resp));
+        printf("SMBus frequency:%d\n", mgmt_resp.smbus_i2c_freq);
+    } else if (configid == MCTP_TRANS_UNIT_SIZE) {
+        struct mctp_tus_cfgget_resp mgmt_resp;
+        memset(&mgmt_resp, 0, sizeof(struct mctp_tus_cfgget_resp));
+        memcpy(&mgmt_resp, (void *)(address + 5), sizeof(struct mctp_tus_cfgget_resp));
+        printf("MCTP Transmission unit size:%d\n" , mgmt_resp.mctp_trans_unit_size);
+    }
+
+    cleanup_nvmemi();
+    return retval;
+}
+
+static int configget(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "Configuration Get";
+    const char *configid = "Configuration Identifier";
+    const char *portid = "Port Identifier";
+
+    int retval;
+    int err = -1;
+
+    struct config {
+        __u8 configid;
+        __u8 portid;
+    };
+
+    struct config cfg;
+
+    OPT_ARGS(opts) = {
+        OPT_BYTE("configid", 'c', &cfg.configid, configid),
+        OPT_BYTE("portid", 'p', &cfg.portid, portid),
+        OPT_END()
+    };
+
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    printf("Issuing Configuration Get  Command, configid:%d\t portid:%d\n",
+            cfg.configid, cfg.portid);
+    err = nvmemi_configget(cfg.configid, cfg.portid);
+    return err;
+}
+
+static int nvmemi_configset(__u8 configid, __u8 portid, __u8 smbusfreq, __u16 mctpunitsz)
+{
+    int retval = 0;
+    __u32 cdw0 = 0;
+    __u32 cdw1 = 0;
+
+    if (configid == SMBUS_I2C_FREQ) {
+        cdw0 = configid | smbusfreq << 8 | portid << 24;
+        cdw1 = 0;
+    } else if (configid == MCTP_TRANS_UNIT_SIZE) {
+        cdw0 = configid | portid << 24;
+        cdw1 = mctpunitsz;
+    }
+
+    struct nvmemi_message_header_struct str;
+
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI);
+
+    struct gencmd_nvmemi cmd = {
+        .msg_header = str,
+        .opcode = nvmemi_cmd_configurationset,
+        .reserved0 = 0,
+        .reserved1 = 0,
+        .reserved2 = 0,
+        .cdw0 = cdw0,
+        .cdw1 = cdw1,
+        .buf = NULL,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    struct nvme_mi_cmd_resp resp;
+    memset(&resp, 0, sizeof(struct nvme_mi_cmd_resp));
+
+    retval = nvmemi_cmd_response(&resp, false);
+    if (retval == -1) {
+        return retval;
+    }
+
+    cleanup_nvmemi();
+    return retval;
+}
+
+static int configset(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "Configuration Set";
+    const char *configid = "Configuration Identifier";
+    const char *portid = "Port Identifier";
+    const char *smbusfreq = "SMBus I2C frequency";
+    const char *mctpunitsz = "MCTP Transmission Unit Size";
+
+    int retval;
+    int err = -1;
+
+    struct config {
+        __u8 configid;
+        __u8 portid;
+        __u8 smbusfreq;
+        __u16 mctpunitsz;
+    };
+
+    struct config cfg;
+
+    OPT_ARGS(opts) = {
+        OPT_BYTE("configid", 'c', &cfg.configid, configid),
+        OPT_BYTE("portid", 'p', &cfg.portid, portid),
+        OPT_BYTE("smbusfreq", 'f', &cfg.smbusfreq, smbusfreq),
+        OPT_BYTE("mctpunitsz", 's', &cfg.mctpunitsz, mctpunitsz),
+        OPT_END()
+    };
+
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    printf("Issuing Configuration Set Command, configid:%d portid:%d smbusfreq:%d mctpunitsz:%d\n",
+            cfg.configid, cfg.portid, cfg.smbusfreq, cfg.mctpunitsz);
+    err = nvmemi_configset(cfg.configid, cfg.portid, cfg.smbusfreq, cfg.mctpunitsz);
+    return err;
+}
+
+static int nvmemi_vpdread(__u16 dofst, __u16 dlen, char *file)
+{
+    int retval = 0;
+    __u32 cdw0 = dofst;
+    __u32 cdw1 = dlen;
+
+    struct nvmemi_message_header_struct str;
+
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI);
+
+    struct gencmd_nvmemi cmd = {
+        .msg_header = str,
+        .opcode = nvmemi_cmd_vpdread,
+        .reserved0 = 0,
+        .reserved1 = 0,
+        .reserved2 = 0,
+        .cdw0 = cdw0,
+        .cdw1 = cdw1,
+        .buf = NULL,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    struct nvme_mi_cmd_resp resp;
+    memset(&resp, 0, sizeof(struct nvme_mi_cmd_resp));
+
+    retval = nvmemi_cmd_response(&resp, false);
+    if (retval == -1) {
+        return retval;
+    }
+
+    int dfd = -1;
+    int opcode = 2;
+    int flags = opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT;
+    int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+    uint64_t address = (uint64_t)&resp;
+
+    if (strlen(file)) {
+        dfd = open(file, flags, mode);
+        if (dfd < 0) {
+            printf("Failed to open the file\n");
+        } else {
+            printf("Open successful\n");
+        }
+    }
+
+    int sz = write(dfd, (void *)(address + 8), dlen);
+    if (sz < 0) {
+        printf("Failed to write\n");
+    }
+
+    cleanup_nvmemi();
+    return retval;
+}
+
+static int vpdread(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "VPD Read";
+    const char *dofst = "Data Offset";
+    const char *dlen = "Data Length";
+    const char *data = "Response Data";
+
+    int retval;
+    int err = -1;
+
+    struct config {
+        __u16 dofst;
+        __u16 dlen;
+        char *data;
+    };
+
+    struct config cfg;
+
+    OPT_ARGS(opts) = {
+        OPT_SHRT("dofst", 'o', &cfg.dofst, dofst),
+        OPT_SHRT("dlen", 'l', &cfg.dlen, dlen),
+        OPT_FILE("data", 'd', &cfg.data, data),
+        OPT_END()
+    };
+
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    printf("Issuing VPD Read Command, dofst:%d\t dlen:%d\n",
+            cfg.dofst, cfg.dlen);
+    err = nvmemi_vpdread(cfg.dofst, cfg.dlen, cfg.data);
+    return err;
+}
+
+static int nvmemi_vpdwrite(__u16 dofst, __u16 dlen, char *req_data)
+{
+    int retval = 0;
+    __u32 cdw0 = dofst;
+    __u32 cdw1 = dlen;
+
+    struct nvmemi_message_header_struct str;
+
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI);
+
+    struct gencmd_nvmemi cmd = {
+        .msg_header = str,
+        .opcode = nvmemi_cmd_vpdread,
+        .reserved0 = 0,
+        .reserved1 = 0,
+        .reserved2 = 0,
+        .cdw0 = cdw0,
+        .cdw1 = cdw1,
+        .buf = (uint8_t *)req_data,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    struct nvme_mi_cmd_resp resp;
+    memset(&resp, 0, sizeof(struct nvme_mi_cmd_resp));
+
+    retval = nvmemi_cmd_response(&resp, false);
+    if (retval == -1) {
+        return retval;
+    }
+
+    cleanup_nvmemi();
+    return retval;
+}
+
+static int vpdwrite(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "VPD Write";
+    const char *dofst = "Data Offset";
+    const char *dlen = "Data Length";
+    const char *data = "Request Data";
+
+    int retval;
+    int err = -1;
+    int dfd = -1;
+    int opcode = 1;
+    int flags = opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT;
+    int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
+
+    struct config {
+        __u16 dofst;
+        __u16 dlen;
+        char *data;
+    };
+
+    struct config cfg = {
+        .data = "",
+    };
+
+    OPT_ARGS(opts) = {
+        OPT_SHRT("dofst", 'o', &cfg.dofst, dofst),
+        OPT_SHRT("dlen", 'l', &cfg.dlen, dlen),
+        OPT_FILE("data", 'd', &cfg.data, data),
+        OPT_END()
+    };
+
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    if (strlen(cfg.data)) {
+        dfd = open(cfg.data, flags, mode);
+        if (dfd < 0) {
+            printf("Failed to open the file\n");
+        } else {
+            printf("Open successful\n");
+        }
+    }
+    char req_data[cfg.dlen];
+    int sz = read(dfd, req_data, cfg.dlen);
+    if (sz < 0) {
+        printf("Failed to read\n");
+    }
+    printf("Issuing VPD Write Command, dofst:%d\t dlen:%d\n", cfg.dofst, cfg.dlen);
+    err = nvmemi_vpdwrite(cfg.dofst, cfg.dlen, req_data);
+    return err;
+}
+
+static int nvmemi_id(__u8 cns, __u16 cntid)
+{
+    __u32 data_len = 0;
+    int retval = 0;
+    __u32 cdw10 = 0;
+    cdw10 = cns | cntid << 16;
+
+    struct nvmemi_message_header_struct str;
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI_ADMIN);
+
+    if (cns == NVME_ID_CNS_NS) {
+        data_len = sizeof(struct nvme_id_ns);
+    } else if (cns == NVME_ID_CNS_CTRL) {
+        data_len = sizeof(struct nvme_id_ctrl);
+    }
+
+    struct gencmd_nvmemi_admin cmd = {
+        .msg_header = str,
+        .opcode = nvme_admin_identify,
+        .cflgs = 0x3,
+        .ctlid = 0,
+        .nsid = 0,
+        .cdw2 = 0,
+        .cdw3 = 0,
+        .cdw4 = 0,
+        .cdw5 = 0,
+        .dofst = 0,
+        .dlen = data_len,
+        .cdw8 = 0,
+        .cdw9 = 0,
+        .cdw10 = cdw10,
+        .cdw11 = 0,
+        .cdw12 = 0,
+		.cdw13 = 0,
+		.cdw14 = 0,
+        .cdw15 = 0,
+        .buf = NULL,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    retval = nvmemi_cmd_response(NULL, false);
+    if (retval == -1) {
+        return retval;
+    }
+
+    __u8 *Respbuffer = (__u8 *)malloc(data_len);
+    if (Respbuffer == NULL) {
+        printf("Memory allocation error.\n");
+        return -1;
+    }
+    memset(Respbuffer, 0, data_len);
+
+    retval = getresponsedata(Respbuffer, data_len, false);
+    if (retval == -1) {
+        printf("Error : Failed to get response data for the command!\n");
+        return retval;
+    }
+
+    if (cns == NVME_ID_CNS_NS) {
+        struct nvme_id_ns idns;
+        memset(&idns, 0, sizeof(struct nvme_id_ns));
+        memcpy(&idns, Respbuffer, sizeof(struct nvme_id_ns));
+        nvme_show_id_ns(&idns, 0, 0);
+    } else if (cns == NVME_ID_CNS_CTRL) {
+        struct nvme_id_ctrl idctrl;
+        memset(&idctrl, 0, sizeof(struct nvme_id_ctrl));
+        memcpy(&idctrl, Respbuffer, sizeof(struct nvme_id_ctrl));
+        nvme_show_id_ctrl(&idctrl, 0);
+    }
+
+    if (Respbuffer != NULL) {
+        free(Respbuffer);
+        Respbuffer = NULL;
+    }
+
+    return retval;
+}
+
+static int identify(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "Identify Command";
+    char *cns = "Controller or Namespace Structure";
+    const char *cntid = "Controller Identifier";
+
+    struct config {
+        __u8 cns;
+        __u16 cntid;
+    };
+    struct config cfg;
+
+    OPT_ARGS(opts) = {
+        OPT_SHRT("cns", 'c', &cfg.cns, cns),
+        OPT_BYTE("cntid", 'C', &cfg.cntid, cntid),
+        OPT_END()
+    };
+
+    int retval = -1;
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    printf("Issuing Identify Command, \
+        cns:%"PRIx8" cntid:%"PRIx16" \n", cfg.cns, cfg.cntid);
+
+    retval = nvmemi_id(cfg.cns, cfg.cntid);
+    if (!retval) {
+        printf("identify: Success\n");
+    } else if (retval > 0) {
+        printf("identify: Failed\n");
+    }
+
+    cleanup_nvmemi();
+    return retval;
+}
+
+static int nvmemi_getlog(__u8 log_id, __u8 lsp, __u64 lpo,
+                 __u16 lsi, bool rae, __u8 uuid_ix, __u32 data_len)
+{
+    __u32 numd = (data_len >> 2) - 1;
+	__u16 numdu = numd >> 16, numdl = numd & 0xffff;
+	__u32 cdw10 = log_id | (numdl << 16) | (rae ? 1 << 15 : 0) | lsp << 8;
+    int retval = 0;
+
+    struct nvmemi_message_header_struct str;
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI_ADMIN);
+
+    struct gencmd_nvmemi_admin cmd = {
+        .msg_header = str,
+        .opcode = nvme_admin_get_log_page,
+        .cflgs = 0x3,
+        .ctlid = 0,
+        .nsid = 0,
+        .cdw2 = 0,
+        .cdw3 = 0,
+        .cdw4 = 0,
+        .cdw5 = 0,
+        .dofst = 0,
+        .dlen = data_len,
+        .cdw8 = 0,
+        .cdw9 = 0,
+        .cdw10 = cdw10,
+        .cdw11 = numdu | (lsi << 16),
+        .cdw12 = lpo & 0xffffffff,
+		.cdw13 = lpo >> 32,
+		.cdw14 = uuid_ix,
+        .cdw15 = 0,
+        .buf = NULL,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    retval = nvmemi_cmd_response(NULL, false);
+    if (retval == -1) {
+        return retval;
+    }
+
+    __u8 *Respbuffer = (__u8 *)malloc(data_len);
+    if (Respbuffer == NULL) {
+        printf("Memory allocation error.\n");
+        return -1;
+    }
+
+    retval = getresponsedata(Respbuffer, data_len, false);
+    if (retval == -1) {
+        printf("Error : Failed to get response data for the command!\n");
+        return retval;
+    }
+
+    printf("sizeof logpage error info : 0x%lx\n", sizeof(struct log_page_error_info));
+    if (log_id == 0x1) {
+        struct log_page_error_info resp;
+        memset(&resp, 0, sizeof(struct log_page_error_info));
+        memcpy(&resp, Respbuffer, sizeof(struct log_page_error_info));
+        printf("Error Count = %"PRIx64"\n", resp.errcnt);
+        printf("Submission Queue ID = %"PRIx16"\n", resp.subqid);
+        printf("Command ID = %"PRIx16"\n", resp.cid);
+        printf("Status Field = %"PRIx16"\n", resp.cid);
+        printf("LBA = %"PRIx64"\n", resp.lba);
+        printf("Namespace = %"PRIx32"\n", resp.ns);
+        printf("Vendor Specific Information Available = %"PRIx8"\n", resp.ns);
+    }
+
+    if (Respbuffer != NULL) {
+        free(Respbuffer);
+        Respbuffer = NULL;
+    }
+
+    return retval;
+}
+
+static int getlog(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "NVMe Get Log Page command via Sideband";
+	const char *log_id = "identifier of log to retrieve";
+	const char *log_len = "how many bytes to retrieve";
+	const char *lsp = "log specific field";
+	const char *lpo = "log page offset specifies the location within a log page from where to start returning data";
+	const char *rae = "retain an asynchronous event";
+	const char *uuid_index = "UUID index";
+	int retval = 0;
+
+	struct config {
+		__u8  log_id;
+		__u32 log_len;
+		__u64 lpo;
+		__u8  lsp;
+		__u8  uuid_index;
+		int   rae;
+	};
+
+	struct config cfg = {
+		.log_id       = 0xff,
+		.log_len      = 0,
+		.lpo          = NVME_NO_LOG_LPO,
+		.lsp          = NVME_NO_LOG_LSP,
+		.rae          = 0,
+		.uuid_index   = 0,
+	};
+
+	OPT_ARGS(opts) = {
+		OPT_UINT("log-id",       'i', &cfg.log_id,       log_id),
+		OPT_UINT("log-len",      'l', &cfg.log_len,      log_len),
+		OPT_LONG("lpo",          'o', &cfg.lpo,          lpo),
+		OPT_BYTE("lsp",          's', &cfg.lsp,          lsp),
+		OPT_FLAG("rae",          'r', &cfg.rae,          rae),
+		OPT_BYTE("uuid-index",   'U', &cfg.uuid_index,   uuid_index),
+		OPT_END()
+	};
+
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    retval = nvmemi_getlog(cfg.log_id,
+				     cfg.lsp, cfg.lpo, 0, cfg.rae,
+				     cfg.uuid_index, cfg.log_len);
+    if (!retval) {
+        printf("Get Log Page: Success\n");
+    } else if (retval > 0) {
+        printf("Get Log Page: Failed\n");
+    }
+
+    cleanup_nvmemi();
+    return retval;
+}
+
+static int nvmemi_getfeature(__u8 fid, __u8 sel, __u32 cdw11,
+		     __u32 data_len)
+{
+	__u32 cdw10 = fid | sel << 8;
+    int retval = 0;
+
+    struct nvmemi_message_header_struct str;
+    msg_header_nvmemi(&str, COMMAND_TYPE_MI_ADMIN);
+
+    struct gencmd_nvmemi_admin cmd = {
+        .msg_header = str,
+        .opcode = nvme_admin_get_features,
+        .cflgs = 0x3,
+        .ctlid = 0,
+        .nsid = 0,
+        .cdw2 = 0,
+        .cdw3 = 0,
+        .cdw4 = 0,
+        .cdw5 = 0,
+        .dofst = 0,
+        .dlen = data_len,
+        .cdw8 = 0,
+        .cdw9 = 0,
+        .cdw10 = cdw10,
+        .cdw11 = cdw11,
+        .cdw12 = 0,
+		.cdw13 = 0,
+		.cdw14 = 0,
+        .cdw15 = 0,
+        .buf = NULL,
+        .mic = 0
+    };
+
+    /*Sending Command*/
+    retval = executecommand((__u8 *)&cmd);
+    if (retval == -1) {
+        return retval;
+    }
+
+    /*Checking Response*/
+    retval = nvmemi_cmd_response(NULL, false);
+    if (retval == -1) {
+        return retval;
+    }
+
+    __u8 *Respbuffer = (__u8 *)malloc(data_len);
+    if (Respbuffer == NULL) {
+        printf("Memory allocation error.\n");
+        return -1;
+    }
+
+    retval = getresponsedata(Respbuffer, data_len, false);
+    if (retval == -1) {
+        printf("Error : Failed to get response data for the command!\n");
+        return retval;
+    }
+
+    if (fid == NVME_FEAT_TEMP_THRESH) {
+        struct getf_temp_thres resp;
+        memset(&resp, 0, sizeof(struct getf_temp_thres));
+        memcpy(&resp, Respbuffer, sizeof(struct getf_temp_thres));
+        printf("Temprature Threshold = %"PRIx16"\n", resp.tmpth);
+        printf("Threshold Temprature Select = %"PRIx16"\n", resp.tmpsel);
+        printf("Threshold Type Select = %"PRIx16"\n", resp.thsel);
+    } else if (fid == NVME_FEAT_NUM_QUEUES) {
+        struct getf_no_queues resp;
+        memset(&resp, 0, sizeof(struct getf_no_queues));
+        memcpy(&resp, Respbuffer, sizeof(struct getf_no_queues));
+        printf("Number of I/O Submission Queues Requested = \
+        %"PRIx16"\n", resp.nsqa);
+        printf("Number of I/O Completion Queues Requested = \
+        %"PRIx16"\n", resp.ncqa);
+    }
+
+    if (Respbuffer != NULL) {
+        free(Respbuffer);
+        Respbuffer = NULL;
+    }
+
+    return retval;
+}
+
+static int getfeature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+    const char *desc = "NVMe Get Features Command via Sideband Interface.";
+	const char *namespace_id = "identifier of desired namespace";
+	const char *feature_id = "feature identifier";
+	const char *sel = "[0-3]: current/default/saved/supported";
+	const char *data_len = "buffer len if data is returned through host memory buffer";
+	const char *cdw11 = "dword 11 for interrupt vector config";
+
+	int retval = 0;
+
+	struct config {
+		__u32 namespace_id;
+		__u8  feature_id;
+		__u8  sel;
+		__u32 cdw11;
+		__u32 data_len;
+	};
+
+	struct config cfg = {
+		.namespace_id = 0,
+		.feature_id   = 0,
+		.sel          = 0,
+		.cdw11        = 0,
+		.data_len     = 0,
+	};
+
+	OPT_ARGS(opts) = {
+		OPT_UINT("namespace-id",  'n', &cfg.namespace_id,   namespace_id),
+		OPT_UINT("feature-id",    'f', &cfg.feature_id,     feature_id),
+		OPT_BYTE("sel",           's', &cfg.sel,            sel),
+		OPT_UINT("data-len",      'l', &cfg.data_len,       data_len),
+		OPT_UINT("cdw11",         'c', &cfg.cdw11,          cdw11),
+		OPT_END()
+	};
+
+    retval = parse_and_open_nvmemi(argc, argv, desc, opts);
+    if (retval < 0) {
+        printf("parse_and_open_nvmemi failed!\n");
+        return errno;
+    }
+
+    retval = nvmemi_getfeature(cfg.feature_id,
+				     cfg.sel, cfg.cdw11, cfg.data_len);
+    if (!retval) {
+        printf("Get Log Page: Success\n");
+    } else if (retval > 0) {
+        printf("Get Log Page: Failed\n");
+    }
+
+    cleanup_nvmemi();
+    return retval;
+}
\ No newline at end of file
diff --git a/plugins/mi/mi-nvme.h b/plugins/mi/mi-nvme.h
new file mode 100644
index 0000000..3fa9285
--- /dev/null
+++ b/plugins/mi/mi-nvme.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme.h - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/mi/mi-nvme
+
+#if !defined(MI) || defined(CMD_HEADER_MULTI_READ)
+#define MI
+
+#include "cmd.h"
+
+PLUGIN(NAME("mi", "NVMe Management Interface Specific Extention"),
+    COMMAND_LIST(
+        ENTRY("readnvmemids", "nvme-mi : Read NVMe-MI Data Structure", readnvmemids)
+        ENTRY("shspoll", "nvme-mi : NVM Subsystem Health Status Poll", shspoll)
+        ENTRY("chspoll", "nvme-mi : Controller Health Status Poll", chspoll)
+        ENTRY("configget", "nvme-mi : Configuration Get", configget)
+        ENTRY("configset", "nvme-mi : Configuration Set", configset)
+        ENTRY("vpdread", "nvme-mi : VPD Read", vpdread)
+        ENTRY("vpdwrite", "nvme-mi : VPD Write", vpdwrite)
+        ENTRY("identify", "nvme-mi-admin : Identify", identify)
+        ENTRY("getlogpage", "nvme-mi-admin : Get Log Page", getlog)
+        ENTRY("getfeatures", "nvme-mi-admin : Get Features", getfeature)
+    )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/mi/util/hal/mi-nvme-hal-main.c b/plugins/mi/util/hal/mi-nvme-hal-main.c
new file mode 100644
index 0000000..cdabe36
--- /dev/null
+++ b/plugins/mi/util/hal/mi-nvme-hal-main.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-hal-main.c - Implementation of HAL Layer for supporting Multiple Hardwares
+ * for NVMe Management Interface command support
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#include "mi-nvme-hal-main.h"
+
+void SetSidebandInterface(SidebandInterface interface)
+{
+    sbInterface = interface;
+}
+
+SidebandInterface GetSidebandInterface()
+{
+    return sbInterface;
+}
+
+int hal_init()
+{
+    int retval = -1;
+    switch (GetSidebandInterface()) {
+    case qemu_nvme_mi:
+        retval = qemu_mi_init();
+        break;
+    default:
+        break;
+    }
+    return retval;
+}
+
+int hal_open()
+{
+    int retval = -1;
+    switch (GetSidebandInterface()) {
+    case qemu_nvme_mi:
+        retval = qemu_mi_open();
+        break;
+    default:
+        break;
+    }
+    return retval;
+}
+
+int hal_close()
+{
+    int retval = -1;
+    switch (GetSidebandInterface()) {
+    case qemu_nvme_mi:
+        retval = qemu_mi_close();
+        break;
+    default:
+        break;
+    }
+    return retval;
+}
+
+int hal_i2c_write(uint8_t *data_out, uint16_t num_bytes)
+{
+    int retval = -1;
+    switch (GetSidebandInterface()) {
+    case qemu_nvme_mi:
+        retval = qemu_mi_write(data_out, num_bytes);
+        break;
+    default:
+        break;
+    }
+    return retval;
+}
+
+int hal_i2c_read(uint8_t *data_in, uint16_t num_bytes)
+{
+    uint32_t retval = -1;
+    switch (GetSidebandInterface()) {
+    case qemu_nvme_mi:
+        retval = qemu_mi_read(data_in, num_bytes);
+        break;
+    default:
+        break;
+    }
+    return retval;
+}
diff --git a/plugins/mi/util/hal/mi-nvme-hal-main.h b/plugins/mi/util/hal/mi-nvme-hal-main.h
new file mode 100644
index 0000000..ad9bc58
--- /dev/null
+++ b/plugins/mi/util/hal/mi-nvme-hal-main.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-hal-main.h - Implementation of HAL Layer for supporting Multiple Hardwares
+ * for NVMe Management Interface command support
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#include <stdint.h>
+#include "mi-nvme-qemu/mi-nvme-qemu.h"
+
+typedef enum _SidebandInterface {
+    qemu_nvme_mi
+} SidebandInterface;
+
+SidebandInterface sbInterface;
+
+int hal_init();
+int hal_open();
+int hal_close();
+int hal_i2c_write(uint8_t *data_out, uint16_t num_bytes);
+int hal_i2c_read(uint8_t *data_in, uint16_t num_bytes);
+void SetSidebandInterface(SidebandInterface interface);
+SidebandInterface GetSidebandInterface();
diff --git a/plugins/mi/util/hal/mi-nvme-qemu/mi-nvme-qemu.c b/plugins/mi/util/hal/mi-nvme-qemu/mi-nvme-qemu.c
new file mode 100644
index 0000000..7a0e42f
--- /dev/null
+++ b/plugins/mi/util/hal/mi-nvme-qemu/mi-nvme-qemu.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-qemu.c - Implementation of QEMU HAL Layer for
+ * for NVMe Management Interface command support via QEMU
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#include "mi-nvme-qemu.h"
+static int connectfd = 0;
+
+int qemu_mi_init()
+{
+    connectfd = -1;
+    struct sockaddr_vm sa = {
+                        .svm_family = AF_VSOCK,
+                        .svm_cid = HOST_CID,
+                        .svm_port = 1342,
+                    };
+    connectfd = socket(AF_VSOCK, SOCK_STREAM, 0);
+    if (connectfd == -1) {
+            printf("Socket Error : Could not create socket!\n");
+    }
+    if (connect(connectfd, (struct sockaddr *)&sa , sizeof(sa)) < 0) {
+        printf("Socket Error : Could not connect to QEMU Socket!\n");
+        return -1;
+    }
+    printf("Connection established with QEMU Socket. Socket Handle is 0x%x\n", connectfd);
+    return connectfd;
+}
+
+int qemu_mi_read(uint8_t *data_in, uint16_t num_bytes)
+{
+    printf("qemu_mi_read : QEMU Socket handle : 0x%x num bytes to receive : %d\n", connectfd, num_bytes);
+    int nrecv = 0;
+    if (connectfd != -1) {
+        nrecv = 0;
+        nrecv = recv(connectfd, data_in , num_bytes, 0);
+        if (nrecv < 0) {
+            printf("Error while Revieving packet from QEMU!\n");
+            return -1;
+        }
+        printf("Message successfully Received. Bytes Received : %d\n", nrecv);
+    }
+    return nrecv;
+}
+
+int qemu_mi_write(uint8_t *data_out, uint16_t num_bytes)
+{
+    printf("qemu_mi_write : QEMU Socket handle : 0x%x\n", connectfd);
+    int nsend = 0;
+    if (connectfd != -1) {
+        nsend = write(connectfd, data_out, num_bytes);
+        if (nsend < 0) {
+            printf("Error while sending packet to QEMU!\n");
+            return -1;
+        }
+        printf("Message successfully sent. Bytes sent : %d\n", nsend);
+    }
+    return nsend;
+}
+
+int qemu_mi_open()
+{
+    if (connectfd == -1) {
+        int handle = -1;
+        handle = qemu_mi_init();
+        if (handle != -1) {
+            return handle;
+        } else {
+            return -1;
+        }
+    } else {
+        printf("qemu_mi_open : QEMU Socket handle : 0x%x\n", connectfd);
+        return connectfd;
+    }
+}
+
+int qemu_mi_close()
+{
+    if (connectfd != -1) {
+        printf("qemu_mi_close : QEMU Socket handle : 0x%x\n", connectfd);
+        close(connectfd);
+        connectfd = -1;
+    }
+    return connectfd;
+}
\ No newline at end of file
diff --git a/plugins/mi/util/hal/mi-nvme-qemu/mi-nvme-qemu.h b/plugins/mi/util/hal/mi-nvme-qemu/mi-nvme-qemu.h
new file mode 100644
index 0000000..4bd084a
--- /dev/null
+++ b/plugins/mi/util/hal/mi-nvme-qemu/mi-nvme-qemu.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-qemu.h - Implementation of QEMU HAL Layer for
+ * for NVMe Management Interface command support via QEMU
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#ifndef __MI_NVME_QEMU_H__
+#define __MI_NVME_QEMU_H__
+
+#include <stdint.h>
+#include <sys/socket.h>
+#include <linux/vm_sockets.h>
+#include <stdio.h>
+#include <string.h>
+#include<unistd.h>
+#define HOST_CID 2
+
+char server_reply[2000];
+int n;
+
+int qemu_mi_open();
+int qemu_mi_close();
+int qemu_mi_init();
+int qemu_mi_read(uint8_t *data_in, uint16_t num_bytes);
+int qemu_mi_write(uint8_t *data_out, uint16_t num_bytes);
+
+#endif
diff --git a/plugins/mi/util/mi-nvme-util-base.c b/plugins/mi/util/mi-nvme-util-base.c
new file mode 100644
index 0000000..0d71f72
--- /dev/null
+++ b/plugins/mi/util/mi-nvme-util-base.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-util-base.c - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#include "mi-nvme-util-master.h"
+
+extern __u32 TotalByteCount;
+
+void print_mctp_packet (mctp_i2c_header *m)
+{
+    printf("\t\t\t Destination Addr    : 0x%02X (7-bit: 0x%02x)\n", m->destAddr, m->destAddr >> 1);
+    printf("\t\t\t Source      Addr    : 0x%02X (7-bit: 0x%02x)\n", m->srcAddr & 0xFE, m->srcAddr >> 1);
+    printf("\t\t\t Byte Count          : 0x%02X (%d dec)\n", m->byteCnt, m->byteCnt);
+    printf("\t\t\t MCTP Header Version : %d\n", m->headerVer & 0xF);
+    printf("\t\t\t Destination Endpoint: 0x%02X\n", m->destEID);
+    printf("\t\t\t Source      Endpoint: 0x%02X\n", m->srcEID);
+    printf("\t\t\t Message Tag         : 0x%X\n", m->pktCtrl & MCTP_CTRL_PKT_MSGTAG_MASK);
+    printf("\t\t\t MCTP Pkt Seq Num    : %d\n", (m->pktCtrl & MCTP_CTRL_PKT_PKTSEQ_MASK) >> MCTP_CTRL_PKT_PKTSEQ_SHIFT);
+    printf("\t\t\t Packet Control bits : SOM(%d), EOM(%d), TO(%d)\n",
+        (m->pktCtrl & MCTP_CTRL_PKT_SOM) >> MCTP_CTRL_PKT_SOM_SHIFT,
+        (m->pktCtrl & MCTP_CTRL_PKT_EOM) >> MCTP_CTRL_PKT_EOM_SHIFT,
+        (m->pktCtrl & MCTP_CTRL_PKT_TO) >> MCTP_CTRL_PKT_TO_SHIFT);
+}
+
+void format_base_pkt (mctp_message_t *m)
+{
+    /* Prepare the I2C header */
+     m->i2cHdr.cmdCode = MCTP_CMD_CODE;
+    m->i2cHdr.headerVer = MCTP_HEADER_VER;
+    m->i2cHdr.destEID = MCTP_EID_DESTINATION;
+    m->i2cHdr.srcEID = MCTP_EID_SOURCE;
+    /* Base on Table 11 of the MCTP Base Specification about the Response message setting */
+    m->i2cHdr.pktCtrl = MCTP_CTRL_MSGTAG(3) | MCTP_CTRL_PKT_SOM | MCTP_CTRL_PKT_EOM | MCTP_CTRL_PKT_TO | 1;
+}
+
+int rcv_pkt (void *inp_parm)
+{
+    unsigned int status = 0;
+    uint8_t eom = 0;
+    mctp_i2c_header mctp_hdr;
+    rcv_parm_t *rcv_parm = (rcv_parm_t *)inp_parm;
+
+    printf("Getting Data from the device.\n");
+    switch (GetSidebandInterface())
+    {
+    case qemu_nvme_mi:
+        rcv_parm->buf_size = 0;
+        memset(&mctp_hdr, 0, sizeof(mctp_i2c_header));
+        uint32_t bytesread = 0;
+        while (!eom) {
+            uint8_t buf[8];
+            /*Reading first 8 bytes of header info*/
+            int ret = hal_i2c_read(buf, 8);
+            if (ret == -1) {
+                printf("Unable to receive MI response header from device.\n");
+                status = -1;
+                break;
+            }
+            mctp_hdr.byteCnt = buf[2];
+            eom = (buf[7] & 0x40) >> 6;
+            printf("Header info received from device:\n");
+            print_mctp_packet((mctp_i2c_header *)buf);
+
+            /*copy header info to response buffer*/
+            memcpy(rcv_parm->buffer + bytesread, buf, 8);
+            bytesread += 8;
+
+            /*Reading the data sent in next transaction*/
+            ret = hal_i2c_read(rcv_parm->buffer + bytesread, mctp_hdr.byteCnt - 5);
+            if (ret == -1) {
+                printf("Unable to receive data from the device.\n");
+                status = -1;
+                break;
+            }
+            printf("Data Received from Device:\n");
+            PrintBuffer(rcv_parm->buffer + bytesread, mctp_hdr.byteCnt - 5);
+            rcv_parm->buf_size += mctp_hdr.byteCnt - 5;
+            bytesread += mctp_hdr.byteCnt - 5;
+        }
+        *(rcv_parm->ret_bytes) = rcv_parm->buf_size;
+        break;
+    default:
+        break;
+    }
+    return status;
+}
+
+int xmit_pkt (__u8 *buffer)
+{
+    mctp_message_t *message = NULL;
+    __u8 *p = NULL;
+    __u32 mtu = mctp_tus;
+    __u32 bytesleft = 0;
+    int ret = -1;
+
+    message = (mctp_message_t *)buffer;
+    bytesleft = TotalByteCount - 5;
+    /* Append PEC byte to the end of the packet */
+    p = buffer + TotalByteCount + 3;
+    message->i2cHdr.byteCnt = TotalByteCount;
+    *p = Calc_Crc8((__u8 *)buffer, TotalByteCount + 3);
+
+    if ((sys_cfg.sys_flags | SYS_FLAG_PEC_OVERRIDE) &&
+        (sys_cfg.peccode == 1))
+    {
+        *p ^= *buffer; /* Screw up the PEC */
+    }
+
+    usleep(10);
+
+    print_mctp_packet(&message->i2cHdr);
+
+    if (bytesleft) {
+        if ((sys_cfg.sys_flags & SYS_FLAG_PEC_OVERRIDE) &&
+            (sys_cfg.peccode == 0)) {
+            ret = send_data(TotalByteCount+2, (__u8 *)&message->i2cHdr.cmdCode);
+        } else {
+            ret = send_data(TotalByteCount+3, (__u8 *)&message->i2cHdr.cmdCode);
+        }
+    } else {
+        bool isStart = true;
+        __u32  counter = 0;
+        do
+        {
+            mctp_message_t msg_in_chunks;
+            __u8 *buffer_in_chunks;
+
+            buffer_in_chunks = (__u8*)&msg_in_chunks;
+
+            memcpy(&msg_in_chunks, message, MCTP_HEADER_SIZE);
+            msg_in_chunks.i2cHdr.byteCnt = mtu + 5;
+
+            msg_in_chunks.i2cHdr.pktCtrl &= 0x0F;
+            msg_in_chunks.i2cHdr.pktCtrl |= ((counter % 4)<<4);
+
+            if (isStart == true) {
+                msg_in_chunks.i2cHdr.pktCtrl |= 0x80; /*Start of message*/
+                memcpy(&msg_in_chunks.msgHdr, buffer + MCTP_HEADER_SIZE + (mtu*counter), mtu);
+                isStart = false;
+            } else if (bytesleft <= mtu) {
+                msg_in_chunks.i2cHdr.pktCtrl |= 0x40; /*End of message*/
+                msg_in_chunks.i2cHdr.byteCnt = bytesleft + 5;
+                memcpy(&msg_in_chunks.msgHdr, buffer + MCTP_HEADER_SIZE + (mtu*counter), bytesleft);
+            } else {
+                msg_in_chunks.i2cHdr.byteCnt = BYTE_COUNT_WHEN_DATA_EXCEEDS_MTU;
+                memcpy(&msg_in_chunks.msgHdr, buffer + MCTP_HEADER_SIZE + (mtu*counter), mtu);
+            }
+
+            p = buffer_in_chunks + msg_in_chunks.i2cHdr.byteCnt + 3;
+            *p = Calc_Crc8((__u8 *)buffer_in_chunks, msg_in_chunks.i2cHdr.byteCnt + 3);
+
+            if ((sys_cfg.sys_flags | SYS_FLAG_PEC_OVERRIDE) && (sys_cfg.peccode == 1)){
+                *p ^= *buffer_in_chunks; /* Screw up the PEC */
+            }
+
+            if ((sys_cfg.sys_flags & SYS_FLAG_PEC_OVERRIDE) &&
+                (sys_cfg.peccode == 0)) {
+                ret = send_data(msg_in_chunks.i2cHdr.byteCnt + 2, (__u8 *)&msg_in_chunks.i2cHdr.cmdCode);
+                if (ret == -1) {
+                    break;
+                }
+            } else {
+                ret = send_data(msg_in_chunks.i2cHdr.byteCnt + 3, (__u8 *)&msg_in_chunks.i2cHdr.cmdCode);
+                if (ret == -1) {
+                    break;
+                }
+            }
+
+            bytesleft -= mtu;
+            counter++;
+        } while (bytesleft > 0);
+    }
+    return ret;
+}
+
+bool mi_pkt_transaction (__u8 *TxBuf, __u8 *RxBuf, __u16 Rxbuf_size)
+{
+    mctp_reply_buffer_struct *stReplyStruct;
+    stReplyStruct = (mctp_reply_buffer_struct*)RxBuf;
+
+    rcv_parm_t rcv_parm;
+    rcv_parm.buf_size = Rxbuf_size;
+    rcv_parm.buffer = stReplyStruct->replybuf;
+    rcv_parm.ret_bytes = &stReplyStruct->length;
+    rcv_parm.errcode = &stReplyStruct->errorcode;
+
+    int ret = xmit_pkt(TxBuf);
+    if (ret == -1) {
+        printf("Unable to send command to device.\n");
+        return false;
+    }
+    sleep(1);
+    ret = rcv_pkt (&rcv_parm);
+    if (ret == -1) {
+        printf("Unable to receive receive response from device.\n");
+        return false;
+    }
+    return true;
+}
+
+bool execute_nvme_mi_command(struct nvme_mi_mctp_message_t message, mctp_reply_buffer_struct *stReply, int replysize, int RequestDataSize)
+{
+    uint8_t *buffer  = NULL;
+    uint32_t size_of_message = 0;
+    uint32_t crc = 0;
+    bool ret = false;
+
+    format_base_pkt((mctp_message_t*)&message);
+
+    sys_cfg.sys_flags |= SYS_FLAG_NVME_MI;
+
+    if (message.msgPld.buffer == NULL) {
+        size_of_message = sizeof(struct nvme_mi_mctp_message_t) - SIZE_OF_BUFFER_ADDRESS;
+        buffer = (uint8_t*)malloc(size_of_message + 1); /*Adding one for the PEC Byte*/
+        TotalByteCount = size_of_message - 3;
+
+        /*Copy the contents of message apart from buffer, as it is NULL*/
+        if (buffer !=NULL) {
+            memcpy(buffer, &message, OFST_TILL_BUFFER_NVME_MI_CMD);
+        }
+    } else if (message.msgPld.opcode == 06) {   /*This check is for VPD Write*/
+        size_of_message = sizeof(struct nvme_mi_mctp_message_t) - SIZE_OF_BUFFER_ADDRESS;
+        int buffer_len = message.msgPld.dword1 & 0xFFFF;
+
+        size_of_message += buffer_len;
+        TotalByteCount = size_of_message - 3;
+
+        buffer = (uint8_t*)malloc(size_of_message + 1);	/*Adding one for PEC byte*/
+        if (buffer !=NULL) {
+            memcpy(buffer, &message, OFST_TILL_BUFFER_NVME_MI_CMD);
+            memcpy(buffer + OFST_TILL_BUFFER_NVME_MI_CMD, message.msgPld.buffer, buffer_len);
+        }
+
+    } else {
+        size_of_message = sizeof(struct nvme_mi_mctp_message_t)  - SIZE_OF_BUFFER_ADDRESS + RequestDataSize;
+        buffer = (uint8_t*)malloc(size_of_message + 1);	/*Add one for the PEC byte*/
+
+        TotalByteCount = size_of_message - 3;
+        if (buffer != NULL) {
+            memcpy(buffer, &message, OFST_TILL_BUFFER_NVME_MI_CMD);
+            memcpy(buffer+OFST_TILL_BUFFER_NVME_MI_CMD, message.msgPld.buffer, RequestDataSize);
+        }
+    }
+
+    if (buffer != NULL) {
+        crc = GenerateCRC(buffer + MCTP_HEADER_SIZE, size_of_message - MCTP_HEADER_SIZE - CRC_SIZE );
+        memcpy(buffer + size_of_message - CRC_SIZE, &crc ,CRC_SIZE);
+        ret = mi_pkt_transaction(buffer, (__u8 *)stReply, replysize);
+        if (buffer !=NULL) {
+            free(buffer);
+            buffer = NULL;
+        }
+    }
+
+    return ret;
+}
+
+bool execute_nvme_mi_admin_command(nvme_mi_admin_cmd_mctp_message message, mctp_reply_buffer_struct *stReply, int replysize, int RequestDataSize)
+{
+    uint8_t *buffer  = NULL;
+    uint32_t size_of_message = 0;
+    uint32_t crc = 0;
+    bool ret = false;
+
+    format_base_pkt((mctp_message_t*)&message);
+
+    if (message.msgPld.buffer == NULL) {
+        size_of_message = sizeof(nvme_mi_admin_cmd_mctp_message) - SIZE_OF_BUFFER_ADDRESS;
+        buffer = (uint8_t*)malloc(size_of_message + 1);		// Adding one for the PEC byte
+
+        TotalByteCount = size_of_message - 3;
+
+        /*Copy the contents of message apart from buffer, as it is NULL*/
+        if (buffer != NULL) {
+            memcpy(buffer, &message, OFST_TILL_BUFFER_NVME_MI_ADMIN_CMD);
+            memcpy(buffer + OFST_TILL_BUFFER_NVME_MI_ADMIN_CMD, (char*)&message
+                + OFST_TILL_BUFFER_NVME_MI_ADMIN_CMD + SIZE_OF_BUFFER_ADDRESS,SIZE_OF_MIC);
+        }
+    } else {
+        size_of_message = sizeof(nvme_mi_admin_cmd_mctp_message) - SIZE_OF_BUFFER_ADDRESS + RequestDataSize;
+        buffer = (uint8_t*)malloc(size_of_message + 1);		/*Adding one for the PEC Byte*/
+
+        TotalByteCount = size_of_message - 3;
+        if (buffer !=NULL) {
+            memcpy(buffer, &message, OFST_TILL_BUFFER_NVME_MI_ADMIN_CMD);
+            memcpy(buffer + OFST_TILL_BUFFER_NVME_MI_ADMIN_CMD, message.msgPld.buffer, RequestDataSize);
+        }
+    }
+
+    if (buffer !=NULL) {
+        /*CRC has to be calculated only for the message body*/
+        crc = GenerateCRC(buffer + MCTP_HEADER_SIZE, size_of_message - MCTP_HEADER_SIZE - CRC_SIZE);
+        memcpy(buffer + size_of_message - CRC_SIZE, &crc, CRC_SIZE);
+        ret = mi_pkt_transaction(buffer, (__u8 *)stReply, replysize);
+    }
+
+    if (buffer !=NULL) {
+        free(buffer);
+        buffer = NULL;
+    }
+
+    return ret;
+}
diff --git a/plugins/mi/util/mi-nvme-util-base.h b/plugins/mi/util/mi-nvme-util-base.h
new file mode 100644
index 0000000..f9e41fc
--- /dev/null
+++ b/plugins/mi/util/mi-nvme-util-base.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-util-base.h - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#ifndef __MI_NVME_UTIL_BASE_H__
+#define __MI_NVME_UTIL_BASE_H__
+
+#include <pthread.h>
+#include <linux/types.h>
+
+#define MCTP_CMD_CODE                       0x0F
+#define MCTP_HEADER_VER                     0x1
+
+#define MCTP_EID_DESTINATION                0x00
+#define MCTP_EID_SOURCE                     0x00
+
+/* Byte 7 Packet Control Bits */
+#define MCTP_CTRL_PKT_MSGTAG_MASK           0x07
+#define MCTP_CTRL_PKT_TO                    0x08
+#define MCTP_CTRL_PKT_TO_SHIFT              3
+#define MCTP_CTRL_PKT_PKTSEQ_MASK           0x30
+#define MCTP_CTRL_PKT_PKTSEQ_SHIFT          4
+#define MCTP_CTRL_PKT_EOM                   0x40
+#define MCTP_CTRL_PKT_EOM_SHIFT             6
+#define MCTP_CTRL_PKT_SOM                   0x80
+#define MCTP_CTRL_PKT_SOM_SHIFT             7
+#define MCTP_CTRL_MSGTAG(x)                 (x & MCTP_CTRL_PKT_MSGTAG_MASK)
+#define MCTP_CTRL_PKTSEQ(x)                 ((x << MCTP_CTRL_PKT_PKTSEQ_SHIFT) & MCTP_CTRL_PKT_PKTSEQ_MASK)
+
+/* Byte 8 Packet Message Type Bits */
+#define MCTP_CTRL_MSG_IC                    0x80
+#define MCTP_CTRL_MSG_IC_SHIFT              7
+#define VDM_ARG_COUNT 20
+
+#define SIZE_OF_BUFFER_ADDRESS 8
+#define SIZE_OF_32_BUFFER_ADDRESS 4
+#define OFST_TILL_BUFFER_NVME_MI_ADMIN_CMD 76
+#define OFST_TILL_BUFFER_NVME_MI_CMD 24
+#define SIZE_OF_MIC 4
+#define MCTP_HEADER_SIZE 8
+#define CRC_SIZE 4
+#define BYTE_COUNT_WHEN_DATA_EXCEEDS_MTU 69
+#define REPLY_BUFFER_SIZE 5120
+#define REPLAY_BUFFER_SIZE 5120
+#define REPLAY_RESPONSE_MESSAGE_SIZE 20
+
+#define PACKED
+#pragma pack(push,1)
+
+typedef struct _mctp_i2c_header {
+    __u8                 destAddr;
+    __u8                 cmdCode;
+    __u8                 byteCnt;
+    __u8                 srcAddr;
+    __u8                 headerVer;
+    __u8                 destEID;
+    __u8                 srcEID;
+    /* Byte 3 for msgTag(2:0), TO(3), pktSeq(5:4), EOM(6), SOM(7) */
+    __u8                 pktCtrl;
+} mctp_i2c_header;
+
+typedef struct mctp_msg_header_ {
+    __u8                 msgTpe;
+    union
+    {
+        struct
+        {
+            /* Byte for InstID(4:0), D(6), Rq(7) fields */
+            __u8    InstCde;
+            __u8    cmdCode;
+            __u8    OpCpl;
+        } ctrMsg;
+    } msgReqRsp;
+} mctp_msg_header_t;
+
+typedef struct mctp_msg_payload_ {
+    union
+    {
+        struct
+        {
+            __u8        EID_status;
+            __u8        EP_Type;
+            __u8        Misc;
+            __u8        byte[((VDM_ARG_COUNT*4)+13)];
+        } baseCtrl;
+    } dataPld;
+} mctp_msg_payload_t;
+
+typedef struct mctp_message_ {
+    mctp_i2c_header  i2cHdr;
+    mctp_msg_header_t  msgHdr;
+    mctp_msg_payload_t msgPld;
+    __u32                pad[1];
+} mctp_message_t;
+
+typedef struct _mctp_message_header_t
+{
+    __u8 messsage_type : 7;
+    __u8 ic : 1;
+    __u8 instance_id : 5;
+    __u8 rsvd : 1;
+    __u8 D : 1;
+    __u8 RQ : 1;
+    __u8 Command_Code;
+}mctp_message_header_t;
+
+typedef struct _nvme_mi_mctp_cmd_pld
+{
+    mctp_message_header_t nvme_mi_message_header;
+    __u8*    buffer;
+}nvme_mi_mctp_cmd_pld;
+
+typedef struct _mctp_command_packet
+{
+    mctp_i2c_header  i2cHdr;
+    nvme_mi_mctp_cmd_pld msgPld;
+}mctp_command_packet;
+
+typedef struct _mctp_command_reply_packet
+{
+    mctp_i2c_header  i2cHdr;
+    nvme_mi_mctp_cmd_pld msgPld;
+}mctp_command_reply_packet;
+
+struct nvme_mi_mctp_message_pld
+{
+    __u32 nvme_mi_message_header;
+    __u8 opcode;
+    __u8 reserved0;
+    __u8 reserved1;
+    __u8 reserved2;
+    __u32 dword0;
+    __u32 dword1;
+    __u8 *buffer;
+    __u32 mic;
+}__attribute__((packed));
+
+typedef struct _nvme_mi_Admin_cmd_mctp_message_pld
+{
+    __u32 nvme_mi_message_header;
+    __u8 opcode;
+    __u8 cflgs;
+    __u16 ctlid;
+    __u32 cdw1;
+    __u32 cdw2;
+    __u32 cdw3;
+    __u32 cdw4;
+    __u32 cdw5;
+    __u32 dofst;
+    __u32 dlen;
+    __u32 cdw8;
+    __u32 cdw9;
+    __u32 cdw10;
+    __u32 cdw11;
+    __u32 cdw12;
+    __u32 cdw13;
+    __u32 cdw14;
+    __u32 cdw15;
+    __u8* buffer;
+    __u32 mic;
+}nvme_mi_Admin_cmd_mctp_message_pld;
+
+struct nvme_mi_mctp_message_t {
+    mctp_i2c_header i2cHdr;
+    struct nvme_mi_mctp_message_pld	msgPld;
+}__attribute__((packed));
+
+typedef struct _nvme_mi_admin_cmd_mctp_message_ {
+    mctp_i2c_header i2cHdr;
+    nvme_mi_Admin_cmd_mctp_message_pld     msgPld;
+}nvme_mi_admin_cmd_mctp_message;
+
+typedef struct rcv_parm_
+{
+    __u16 buf_size;
+    __u8 *buffer;
+    __u32 *ret_bytes;
+    __u32 *errcode;
+} rcv_parm_t;
+
+typedef struct _mctp_reply_buffer_struct
+{
+    __u8 replybuf[REPLY_BUFFER_SIZE];
+    __u32 length;
+    __u32 errorcode;
+}mctp_reply_buffer_struct;
+
+#pragma pack(pop)
+#undef PACKED
+
+void format_base_pkt(mctp_message_t *m);
+int rcv_pkt(void *inp_parm);
+int xmit_pkt(__u8 *buffer);
+bool mi_pkt_transaction(__u8 *TxBuf, __u8 *RxBuf, __u16 Rxbuf_size);
+bool execute_nvme_mi_command(struct nvme_mi_mctp_message_t message, mctp_reply_buffer_struct *stReply, int replysize, int RequestDataSize);
+bool execute_nvme_mi_admin_command(nvme_mi_admin_cmd_mctp_message message, mctp_reply_buffer_struct *stReply, int replysize, int RequestDataSize);
+
+#endif
diff --git a/plugins/mi/util/mi-nvme-util-crc.c b/plugins/mi/util/mi-nvme-util-crc.c
new file mode 100644
index 0000000..76e1171
--- /dev/null
+++ b/plugins/mi/util/mi-nvme-util-crc.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-util-crc.c - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#include "mi-nvme-util-master.h"
+
+static __u8 crc8(__u8 crc, __u8 crc_data)
+{
+    __u8 i = 0, data = 0;
+    data = crc ^ crc_data;
+
+    for ( i = 0; i < 8; i++ ) {
+        if (( data & 0x80 ) != 0 ) {
+            data <<= 1;
+            data ^= 0x07;
+        } else {
+            data <<= 1;
+        }
+    }
+    return data;
+}
+
+__u8 Calc_Crc8(__u8 *Buffer, __u8 byte_cnt)
+{
+    __u8 crc = 0, *p;
+    int i;
+    p = Buffer;
+
+    for (i = 0; i < byte_cnt; i++) {
+        crc = crc8(crc, *p++);
+    }
+    return (crc);
+}
+
+uint32_t GenerateCRC(uint8_t *message, uint32_t length)
+{
+    if (message != NULL) {
+        uint32_t crc = Calc_Crc32(0x1EDC6F41, -1, message, length);
+        printf("Generated CRC32 : %"PRIx32" \n", crc);
+        return crc;
+    }
+    return 0;
+}
+
+void gen_crc_table(uint32_t poly)
+{
+  register uint16_t i = 0, j = 0;
+  register uint32_t crc_accum = 0;
+
+  for (i = 0;  i < 256;  i++) {
+    crc_accum = ( (uint32_t) i << 24 );
+    for (j = 0;  j < 8;  j++ ) {
+      if (crc_accum & 0x80000000L) {
+        crc_accum = (crc_accum << 1) ^ poly;
+      } else {
+        crc_accum = (crc_accum << 1);
+      }
+    }
+    crc_table[i] = crc_accum;
+  }
+}
+
+uint32_t Calc_Crc32(uint32_t poly, uint32_t crc_accum, uint8_t *data_blk_ptr, uint32_t data_blk_size)
+{
+    register uint32_t i = 0, j = 0;
+    gen_crc_table(poly);
+
+    for (j = 0; j < data_blk_size; j++) {
+        i = ((int) (crc_accum >> 24) ^ *data_blk_ptr++) & 0xFF;
+        crc_accum = (crc_accum << 8) ^ crc_table[i];
+    }
+    crc_accum = ~crc_accum;
+    return crc_accum;
+}
diff --git a/plugins/mi/util/mi-nvme-util-crc.h b/plugins/mi/util/mi-nvme-util-crc.h
new file mode 100644
index 0000000..a9f6f54
--- /dev/null
+++ b/plugins/mi/util/mi-nvme-util-crc.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-util-crc.h - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#ifndef __MI_NVME_UTIL_CRC_H__
+#define __MI_NVME_UTIL_CRC_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+uint32_t crc_table[256];
+
+uint32_t GenerateCRC(uint8_t *message, uint32_t length);
+void gen_crc_table();
+uint32_t Calc_Crc32(uint32_t poly, uint32_t crc_accum, uint8_t *message, uint32_t size);
+__u8 Calc_Crc8(__u8 *Buffer, __u8 byte_cnt);
+
+#endif
diff --git a/plugins/mi/util/mi-nvme-util-master.h b/plugins/mi/util/mi-nvme-util-master.h
new file mode 100644
index 0000000..ae2a322
--- /dev/null
+++ b/plugins/mi/util/mi-nvme-util-master.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-util-master.h - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#ifndef __MI_NVME_UTIL_MASTER_H__
+#define __MI_NVME_UTIL_MASTER_H__
+#include <linux/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include "hal/mi-nvme-hal-main.h"
+#include "mi-nvme-util-tool.h"
+#include "mi-nvme-util-base.h"
+#include "mi-nvme-util-crc.h"
+
+#endif
diff --git a/plugins/mi/util/mi-nvme-util-tool.c b/plugins/mi/util/mi-nvme-util-tool.c
new file mode 100644
index 0000000..8d7f533
--- /dev/null
+++ b/plugins/mi/util/mi-nvme-util-tool.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-util-tool.c - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#include "mi-nvme-util-master.h"
+
+static bool state_dev = false;
+static bool hardware_init = false;
+
+system_cfg_t sys_cfg;
+__u32 mctp_tus;
+__u32 TotalByteCount;
+
+bool initialize(__u32 uiMCTP_TUS)
+{
+    bool retval = false;
+    memset(&sys_cfg, 0, sizeof(system_cfg_t));
+
+    switch (GetSidebandInterface()) {
+    case qemu_nvme_mi:
+        mctp_tus = uiMCTP_TUS;
+        if (!hardware_init) {
+            int ret = hal_init();
+            if (ret == -1) {
+                printf("Initialiation Failed.\n");
+                return false;
+            }
+            printf("QEMU Socket initialized : %d\n", ret);
+            hardware_init = true;
+        }
+
+        retval = open_device();
+        if (retval == false) {
+            printf("open device Failed!\n");
+            return false;
+        }
+        break;
+    default:
+        break;
+    }
+
+    return retval;
+}
+
+int send_data(__u16 num_write, __u8 *data_out)
+{
+    int count = 0;
+
+    printf("\nData being written to the device, byte count = 0x%X:\n", num_write);
+    __u8 *buffertemp = (__u8*)malloc(num_write + 1);
+    if (buffertemp != NULL) {
+        buffertemp[0] = sys_cfg.taddr << 1;
+        memcpy(&buffertemp[1], data_out, num_write);
+        PrintBuffer(buffertemp, num_write + 1);
+
+        free(buffertemp);
+        buffertemp = NULL;
+    }
+
+    count = hal_i2c_write(data_out, num_write);
+    usleep(10);
+
+    printf("num_write=0x%02x(0x%02x)\n", num_write, count);
+
+    if (count < 0) {
+        printf("Error in sending data\n");
+        return -1;
+    }
+    printf("Number of bytes written to the device 0x%02x(%d)\n", count, count);
+
+    return count;
+}
+
+bool open_device()
+{
+    int status = -1, i = 0;
+
+    if (!state_dev) {
+        for (i = 0; i < MAX_OPEN_RETRY; i++) {
+            status = hal_open();
+            if (status < 0) {
+                printf("Unable to open device\n");
+            } else {
+                break;
+            }
+        }
+
+        if (status <= 0) {
+            printf("Unable to open device on port %d\n", sys_cfg.aport);
+            return false;
+        }
+
+        state_dev = true;
+    }
+    return true;
+}
+
+bool close_device()
+{
+    int status = -1, i = 0;
+
+    if (state_dev) {
+        for (i = 0; i < MAX_CLOSE_RETRY; i++) {
+            status = hal_close();
+            if (status == -1) {
+                break;
+            }
+        }
+
+        if (status != -1) {
+            printf("Device handle close unsuccessful!\n");
+            return false;
+        }
+        state_dev = false;
+    }
+    return true;
+}
+
+void PrintBuffer( __u8* buffer,__u32 length)
+{
+    __u32 i = 0;
+    for (i = 0; i < length; i += 0x8) {
+        if (i+1 > length -1) {
+            printf("%06x     %02x\n",i,buffer[i]);
+        } else if (i+2 > length -1) {
+            printf("%06x     %02x %02x \n",i, buffer[i], \
+            buffer[i + 1]);
+        } else if (i+3 > length -1) {
+            printf("%06x     %02x %02x %02x\n", i, buffer[i], \
+            buffer[i + 1], buffer[i + 2]);
+        } else if (i+4 > length -1) {
+            printf("%06x     %02x %02x %02x %02x\n", i, buffer[i], \
+            buffer[i + 1], buffer[i + 2], buffer[i + 3]);
+        } else if (i+5 > length -1) {
+            printf("%06x     %02x %02x %02x %02x %02x\n", i, buffer[i], \
+            buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4]);
+        } else if (i+6 > length -1) {
+            printf("%06x     %02x %02x %02x %02x %02x %02x\n", i, \
+            buffer[i], buffer[i + 1], buffer[i + 2], buffer[i + 3], \
+            buffer[i + 4], buffer[i + 5]);
+        } else if (i+7 > length -1) {
+            printf("%06x     %02x %02x %02x %02x %02x %02x %02x\n", i, \
+            buffer[i], buffer[i + 1], buffer[i + 2], buffer[i + 3], \
+            buffer[i + 4], buffer[i + 5], buffer[i + 6]);
+        } else {
+            printf("%06x     %02x %02x %02x %02x %02x %02x %02x %02x\n",i , \
+            buffer[i], buffer[i + 1], buffer[i + 2], buffer[i + 3], \
+            buffer[i + 4], buffer[i + 5], buffer[i + 6], buffer[i + 7]);
+        }
+    }
+}
diff --git a/plugins/mi/util/mi-nvme-util-tool.h b/plugins/mi/util/mi-nvme-util-tool.h
new file mode 100644
index 0000000..1b7b103
--- /dev/null
+++ b/plugins/mi/util/mi-nvme-util-tool.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * mi-nvme-util-tool.h - Implementation of NVMe Management Interface commands in Nvme
+ *
+ * Developer : Mohit Kapoor <mohit....@samsung.com>
+ */
+
+#include "mi-nvme-util-base.h"
+
+#ifndef __MI_NVME_UTIL_TOOL_H__
+#define __MI_NVME_UTIL_TOOL_H__
+
+#define SYS_FLAG_PEC_OVERRIDE 0x00000400
+#define SYS_FLAG_NVME_MI 0x00010000
+#define MAX_OPEN_RETRY 10
+#define MAX_CLOSE_RETRY 5
+
+typedef struct _system_cfg_t {
+    __u32 sys_flags;
+    __u32 verbose_level;
+    __u32 op_state;
+
+    int phandle;
+    int dhandle;
+    __u16 iport;
+    __u16 aport;
+    __u16 dport;
+
+    __u8 taddr;
+    __u8 saddr;
+
+    __u8 peccode;
+} system_cfg_t;
+
+__u32 mctp_tus;
+extern system_cfg_t  sys_cfg;
+
+bool initialize(__u32 uiMCTP_TUS);
+int send_data(__u16 num_write, __u8 *data_out);
+bool open_device();
+bool close_device();
+void PrintBuffer(__u8* buffer,__u32 length);
+
+#endif


Reply via email to