All of lore.kernel.org
 help / color / mirror / Atom feed
From: Padmakar Kalghatgi <p.kalghatgi@samsung.com>
To: Klaus Jensen <its@irrelevant.dk>
Cc: fam@euphon.net, kwolf@redhat.com, arun.kka@samsung.com,
	jg123.choi@samsung.com, qemu-block@nongnu.org,
	k.jensen@samsung.com, d.palani@samsung.com,
	qemu-devel@nongnu.org, mreitz@redhat.com, u.kishore@samsung.com,
	stefanha@redhat.com, kbusch@kernel.org, javier.gonz@samsung.com,
	prakash.v@samsung.com, mohit.kap@samsung.com
Subject: Re: [RFC PATCH: v4 1/2] add mi device in qemu
Date: Tue, 26 Oct 2021 18:43:58 +0530	[thread overview]
Message-ID: <20211026131358.GA23684@test.sa.corp.samsungelectronics.net> (raw)
In-Reply-To: <YVPtogzu2OSh/1yK@apples.localdomain>

[-- Attachment #1: Type: text/plain, Size: 35529 bytes --]

This patch addresses most of the review comments raised by Klaus.
Mainly, I have ensured that the emulated mi device in qemu posts
the response rather than waiting for the guest-os(mi utility) to ask 
for the response. For the same purpose, I have added a new device called
nvme-mi-slave which acts as an i2c slave and to which the emulated
mi device posts the response. The guest-os(mi utility) reads response 
from this slave. The nvme-mi-slave has to be used in tandem with nvme-mi device.


In addition to the above change, we will be providing the mi utility 
on the guest as a standalone rather than as a plugin to the 
nvme-cli application.

We will be glad to hear any suggestions, corrections in the approach 
we have used. 

Please find the patch below:

========================================================================
diff --git a/hw/nvme/meson.build b/hw/nvme/meson.build
index 3cf4004..8768ca1 100644
--- a/hw/nvme/meson.build
+++ b/hw/nvme/meson.build
@@ -1 +1 @@
-softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('ctrl.c',
'dif.c', 'ns.c', 'subsys.c'))
+softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('ctrl.c',
'dif.c', 'ns.c', 'subsys.c', 'nvme-mi.c', 'nvme-mi-slave.c'))
diff --git a/hw/nvme/nvme-mi-slave.c b/hw/nvme/nvme-mi-slave.c
new file mode 100644
index 0000000..e6ada07
--- /dev/null
+++ b/hw/nvme/nvme-mi-slave.c
@@ -0,0 +1,93 @@
+/*
+ * QEMU NVMe-MI Controller
+ *
+ * Copyright (c) 2021, Samsung Electronics co Ltd.
+ *
+ * Written by Padmakar Kalghatgi <p.kalghatgi@samsung.com>
+ *
+ * This code is licensed under the GNU GPL v2 or later.
+ * 
+ * This module acts as a host slave, to which the QEMU-MI module
+ * will post the response to.
+ * 
+ * Need to use as following to enable this device
+ * -device nvme-mi-i2c-slave, addr=<slaveaddr>
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-core.h"
+#include "hw/block/block.h"
+#include "nvme-mi-slave.h"
+
+static uint8_t nvme_mi_slave_i2c_recv(I2CSlave *s)
+{
+    Nvmemislave *mislave = (Nvmemislave *)s;
+	
+    if (mislave->syncflag == true) {
+        return -1;
+    }
+    return mislave->recvbuffer[mislave->recvlen++];
+}
+
+static int nvme_mi_slave_i2c_send(I2CSlave *s, uint8_t data)
+{    
+    Nvmemislave *mislave = (Nvmemislave *)s;
+    mislave->syncflag = true;
+
+    switch (mislave->pktpos) {
+    case NVME_MI_BYTE_LENGTH_POS:
+        mislave->pktlen = data;
+        break;
+    case NVME_MI_EOM_POS:
+        mislave->eom = (data >> 6) & 1;
+        break;
+    }
+    mislave->recvbuffer[mislave->sendlen++] = data;
+    mislave->pktpos++;
+    if (mislave->pktpos == mislave->pktlen + 3) {
+        mislave->pktlen = 0;
+        mislave->pktpos = 0;
+
+        if (mislave->eom == 1) {
+            mislave->sendlen = 0;
+            mislave->recvlen = 0;
+            mislave->eom = 0;
+            mislave->syncflag = false;          
+        }
+    }
+    return 0;
+}
+
+static void nvme_mi_slave_realize(DeviceState *dev, Error **errp)
+{
+    Nvmemislave *mislave = (Nvmemislave *)dev;
+    mislave->sendlen = 0;
+    mislave->recvlen = 0;
+    mislave->eom = 0;
+    mislave->syncflag = false;
+}
+
+static void nvme_mi_slave_class_init(ObjectClass *oc, void *data)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(oc);
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    
+    dc->realize = nvme_mi_slave_realize;
+    k->recv = nvme_mi_slave_i2c_recv;
+    k->send = nvme_mi_slave_i2c_send;
+}
+
+static const TypeInfo nvme_mi_slave = {
+    .name = TYPE_NVME_MI_SLAVE,
+    .parent = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(Nvmemislave),
+    .class_init = nvme_mi_slave_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&nvme_mi_slave);
+}
+
+type_init(register_types);
diff --git a/hw/nvme/nvme-mi-slave.h b/hw/nvme/nvme-mi-slave.h
new file mode 100644
index 0000000..971411a
--- /dev/null
+++ b/hw/nvme/nvme-mi-slave.h
@@ -0,0 +1,28 @@
+#ifndef NVMEMISLAVEH
+#define NVMEMISLAVEH
+
+#include "hw/i2c/i2c.h"
+#define TYPE_NVME_MI_SLAVE "nvme-mi-i2c-slave"
+
+#define MAX_NVME_MI_BUF_SIZE 5000
+
+enum Nvmemislavepktpos
+{
+   NVME_MI_ADDR_POS = 0,
+   NVME_MI_BYTE_LENGTH_POS = 2,
+   NVME_MI_EOM_POS = 7
+};
+
+typedef struct Nvmemislave
+{
+    I2CSlave parent_obj;
+    uint32_t sendlen;
+    uint32_t recvlen;
+    uint32_t pktpos;
+    uint32_t pktlen;
+    uint8_t eom;
+    bool syncflag;
+    u_char recvbuffer[MAX_NVME_MI_BUF_SIZE];
+} Nvmemislave;
+
+#endif
\ No newline at end of file
diff --git a/hw/nvme/nvme-mi.c b/hw/nvme/nvme-mi.c
new file mode 100644
index 0000000..ad98bd8
--- /dev/null
+++ b/hw/nvme/nvme-mi.c
@@ -0,0 +1,684 @@
+    /*
+ * QEMU NVMe-MI Controller
+ *
+ * Copyright (c) 2021, Samsung Electronics co Ltd.
+ *
+ * Written by Padmakar Kalghatgi <p.kalghatgi@samsung.com>
+ *            Arun Kumar Agasar <arun.kka@samsung.com>
+ *            Saurav Kumar <saurav.29@partner.samsung.com>
+ *
+ * This code is licensed under the GNU GPL v2 or later.
+ */
+
+/**
+ * Reference Specs: http://www.nvmexpress.org,
+ *
+ *
+ * Usage
+ * -----
+ * The nvme-mi device has to be used along with nvme device only
+ *
+ * Add options:
+ *    -device  nvme-mi,nvme=<nvme id>,address=0x15",
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-core.h"
+#include "hw/block/block.h"
+#include "hw/pci/msix.h"
+#include "include/block/nvme.h"
+#include "nvme.h"
+#include "nvme-mi.h"
+#include "qemu/crc32c.h"
+#include "hw/i2c/smbus_master.h"
+
+#define NVME_TEMPERATURE 0x143
+#define NVME_TEMPERATURE_WARNING 0x157
+#define NVME_TEMPERATURE_CRITICAL 0x175
+
+static uint8_t nvme_mi_gen_pec(uint8_t *data, size_t len)
+{
+    uint8_t pec = 0xff;
+    size_t i, j;
+    for (i = 0; i < len; i++) {
+        pec ^= data[i];
+        for (j = 0; j < 8; j++) {
+            if ((pec & 0x80) != 0) {
+                pec = (uint8_t)((pec << 1) ^ 0x31);
+            } else {
+                pec <<= 1;
+            }
+        }
+    }
+    return pec;
+}
+static void nvme_mi_send_resp(NvmeMiCtrl *ctrl_mi, uint8_t *resp,
uint32_t size)
+{
+    uint32_t crc_value = crc32c(0xFFFFFFFF, resp, size);
+    uint32_t offset = 0;
+    uint32_t som = 1;
+    uint32_t eom = 0;
+    uint32_t pktseq = 0;
+    uint32_t mtus = ctrl_mi->mctp_unit_size;
+    size += sizeof(crc_value);
+    while (size > 0) {
+        size_t sizesent = MIN(size, mtus);
+        size -= sizesent;
+        eom = size > 0 ? 0 : 1;
+        g_autofree uint8_t *buf = (uint8_t *)g_malloc0(sizesent + 8 +
1);
+        buf[2] = sizesent + 6;
+        buf[7] = (som << 7) | (eom << 6) | (pktseq << 5);
+        som = 0;
+        memcpy(buf + 8, resp + offset, sizesent);
+        uint8_t pec = nvme_mi_gen_pec(resp + offset, sizesent);
+        buf[9] = pec;
+        offset += sizesent;
+        if (size <= 0) {
+            memcpy(buf + sizesent + NVME_MI_SMBUS_HEADER_AND_PEC -
sizeof(crc_value),
+                   &crc_value, sizeof(crc_value));
+        }
+        memcpy(ctrl_mi->misendrecv.state.sendrecvbuf +
ctrl_mi->misendrecv.total_len,
+               buf, sizesent + NVME_MI_SMBUS_HEADER_AND_PEC);
+        ctrl_mi->misendrecv.total_len += sizesent +
NVME_MI_SMBUS_HEADER_AND_PEC;
+
+    }
+
+
+}
+
+static void nvme_mi_resp_hdr_init(NvmeMiResponse *resp, int NvmeMiType)
+{
+    resp->msg_header.msgtype = 4;
+    resp->msg_header.ic = 1;
+    resp->msg_header.csi = 0;
+    resp->msg_header.reserved = 0;
+    resp->msg_header.nmimt = NvmeMiType;
+    resp->msg_header.ror = 1;
+    resp->msg_header.reserved1 = 0;
+}
+static void nvme_mi_nvm_subsys_ds(NvmeMiCtrl *ctrl_mi, NvmeMiRequest
*req)
+{
+    NvmeMiResponse resp;
+    NvmMiSubsysInfoDs ds;
+    uint32_t total_size = sizeof(resp) + sizeof(ds);
+    uint8_t resp_message[total_size];
+    ds.nump = 1;
+    ds.mjr = (ctrl_mi->n->bar.vs & 0xFF0000) >> 16;
+    ds.mnr = (ctrl_mi->n->bar.vs & 0xFF00) >> 8;
+
+    nvme_mi_resp_hdr_init(&resp , NVME_MI_CMD);
+    resp.status = SUCCESS;
+    resp.mgmt_resp = sizeof(ds);
+    memcpy(resp_message, &resp, sizeof(resp));
+    memcpy(resp_message + sizeof(resp), &ds, sizeof(ds));
+
+    nvme_mi_send_resp(ctrl_mi, resp_message, total_size);
+}
+
+static void nvme_mi_opt_supp_cmd_list(NvmeMiCtrl *ctrl_mi,
NvmeMiRequest *req)
+{
+    NvmeMiResponse resp;
+    uint32_t offset = 0, size = 0, total_size = 0;
+    uint16_t mi_opt_cmd_cnt, admin_mi_opt_cmd_cnt, total_commands;
+    g_autofree uint8_t *resp_message = NULL;
+    g_autofree uint8_t *cmd_supp_list = NULL;
+    nvme_mi_resp_hdr_init(&resp , NVME_MI_CMD);
+    resp.status = SUCCESS;
+
+    mi_opt_cmd_cnt = sizeof(NvmeMiCmdOptSupList) /
+                              sizeof(uint32_t);
+    admin_mi_opt_cmd_cnt = sizeof(NvmeMiAdminCmdOptSupList) /
+                                    sizeof(uint32_t);
+
+    total_commands = mi_opt_cmd_cnt + admin_mi_opt_cmd_cnt;
+    size = 2 * (total_commands + 1);
+
+    cmd_supp_list = (uint8_t *)g_malloc0(size);
+
+    memcpy(cmd_supp_list, &total_commands, sizeof(uint16_t));
+    offset += sizeof(uint16_t);
+    for (uint32_t i = 0; i < mi_opt_cmd_cnt; i++) {
+        memcpy(cmd_supp_list + offset, &NvmeMiCmdOptSupList[i],
+               sizeof(uint8_t));
+        cmd_supp_list[offset + 1] = 1;
+        offset += 2;
+    }
+
+    for (uint32_t i = 0; i < admin_mi_opt_cmd_cnt; i++) {
+        memcpy(cmd_supp_list + offset, &NvmeMiAdminCmdOptSupList[i],
+               sizeof(uint8_t));
+        cmd_supp_list[offset + 1] = 1;
+        offset += 2;
+    }
+
+    resp.mgmt_resp = size;
+    total_size = sizeof(resp) + size;
+    resp_message = (uint8_t *) g_malloc(total_size);
+    memcpy(resp_message, &resp, sizeof(resp));
+    memcpy(resp_message + sizeof(resp), cmd_supp_list, size);
+
+    nvme_mi_send_resp(ctrl_mi, resp_message, total_size);
+}
+
+static void nvme_mi_controller_health_ds(NvmeMiCtrl *ctrl_mi,
+                                         NvmeMiRequest *req)
+{
+    uint32_t dword0 = req->dword0;
+    uint32_t dword1 = req->dword1;
+    uint32_t maxrent = (dword0 >> 16) & 0xFF;
+    uint32_t reportall = (dword0 >> 31) & 0x1;
+    uint32_t incvf = (dword0 >> 26) & 0x1;
+    uint32_t incpf = (dword0 >> 25) & 0x1;
+    uint32_t incf = (dword0 >> 24) & 0x1;
+    g_autofree uint8_t *resp_buf = NULL;
+
+    NvmeMiResponse resp;
+    nvme_mi_resp_hdr_init(&resp , NVME_MI_CMD);
+
+    if (maxrent > 255 || (reportall == 0) || incvf || incpf || (incf ==
0)) {
+        resp.status = INVALID_PARAMETER;
+        return nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp,
sizeof(resp));
+    }
+    NvmeMiCtrlHealthDs nvme_mi_chds;
+    if (dword1 & 0x1) {
+        nvme_mi_chds.csts.rdy = ctrl_mi->n->bar.csts & 0x1;
+        nvme_mi_chds.csts.cfs |= ctrl_mi->n->bar.csts & 0x2;
+        nvme_mi_chds.csts.shst |= ctrl_mi->n->bar.csts & 0xa;
+        nvme_mi_chds.csts.nssro |= ctrl_mi->n->bar.csts & 0x10;
+        nvme_mi_chds.csts.en |= ctrl_mi->n->bar.cc & 0x1 << 5;
+    }
+    if (dword1 & 0x2) {
+        nvme_mi_chds.ctemp = ctrl_mi->n->temperature;
+    }
+    if (((ctrl_mi->n->temperature >=
ctrl_mi->n->features.temp_thresh_hi) ||
+        (ctrl_mi->n->temperature <=
ctrl_mi->n->features.temp_thresh_low)) &&
+         (dword1 & 0x2)) {
+        nvme_mi_chds.cwarn.temp_above_or_under_thresh = 0x1;
+    }
+    resp_buf = (uint8_t *)g_malloc(sizeof(resp) +
+                                   sizeof(NvmeMiCtrlHealthDs));
+    resp.mgmt_resp = 1 << 0x10;
+    memcpy(resp_buf, &resp, sizeof(resp));
+    memcpy(resp_buf + sizeof(resp), &nvme_mi_chds,
sizeof(nvme_mi_chds));
+    nvme_mi_send_resp(ctrl_mi, resp_buf, sizeof(resp) +
sizeof(NvmeMiCtrlHealthDs));
+}
+
+static void nvme_mi_read_nvme_mi_ds(NvmeMiCtrl *ctrl_mi, NvmeMiRequest
*req)
+{
+    ReadNvmeMiDs ds;
+    int dtyp;
+    ds.cntrlid = req->dword0 & 0xFFFF;
+    ds.portlid = (req->dword0 & 0xFF0000) >> 16;
+    ds.dtyp = (req->dword0 & ~0xFF) >> 24;
+    dtyp = ds.dtyp;
+    switch (dtyp) {
+    case NVM_SUBSYSTEM_INFORMATION:
+        nvme_mi_nvm_subsys_ds(ctrl_mi, req);
+        break;
+    case OPT_SUPP_CMD_LIST:
+        nvme_mi_opt_supp_cmd_list(ctrl_mi, req);
+        break;
+    }
+}
+
+static void nvme_mi_configuration_get(NvmeMiCtrl *ctrl_mi,
NvmeMiRequest *req)
+{
+    uint8_t config_identifier = (req->dword0 & 0xFF);
+    NvmeMiResponse resp;
+    uint32_t total_size = sizeof(resp);
+    uint8_t resp_message[total_size];
+    switch (config_identifier) {
+    case SMBUS_I2C_FREQ: {
+       nvme_mi_resp_hdr_init(&resp, NVME_MI_CMD);
+       resp.status = SUCCESS;
+       resp.mgmt_resp = ctrl_mi->smbus_freq;
+       memcpy(resp_message, &resp, sizeof(resp));
+
+       nvme_mi_send_resp(ctrl_mi, resp_message, total_size);
+    }
+    break;
+    case MCTP_TRANS_UNIT_SIZE: {
+        nvme_mi_resp_hdr_init(&resp, NVME_MI_CMD);
+        resp.status = SUCCESS;
+        resp.mgmt_resp = ctrl_mi->mctp_unit_size;
+        memcpy(resp_message, &resp, sizeof(resp));
+
+        nvme_mi_send_resp(ctrl_mi, resp_message, total_size);
+    }
+    break;
+    }
+}
+
+static void nvme_mi_configuration_set(NvmeMiCtrl *ctrl_mi,
NvmeMiRequest *req)
+{
+    uint8_t config_identifier = (req->dword0 & 0xFF);
+    NvmeMiResponse resp;
+    uint32_t total_size = sizeof(resp);
+    uint8_t resp_message[total_size];
+    switch (config_identifier) {
+    case SMBUS_I2C_FREQ: {
+        nvme_mi_resp_hdr_init(&resp, NVME_MI_CMD);
+        resp.status = SUCCESS;
+        resp.mgmt_resp = 0;
+        ctrl_mi->smbus_freq = (req->dword0 & 0xF00) >> 8;
+        memcpy(resp_message, &resp, sizeof(resp));
+
+        nvme_mi_send_resp(ctrl_mi, resp_message, total_size);
+    }
+    break;
+    case MCTP_TRANS_UNIT_SIZE: {
+        nvme_mi_resp_hdr_init(&resp, NVME_MI_CMD);
+        resp.status = SUCCESS;
+        ctrl_mi->mctp_unit_size = (req->dword1 & 0xFFFF);
+        memcpy(resp_message, &resp, sizeof(resp));
+
+        nvme_mi_send_resp(ctrl_mi, resp_message, total_size);
+    }
+    break;
+    default:
+        nvme_mi_resp_hdr_init(&resp, NVME_MI_CMD);
+        resp.status = INVALID_PARAMETER;
+        memcpy(resp_message, &resp, sizeof(resp));
+        nvme_mi_send_resp(ctrl_mi, resp_message, total_size);
+    }
+
+}
+
+static void nvme_mi_vpd_read(NvmeMiCtrl *ctrl_mi, NvmeMiRequest *req)
+{
+    uint16_t dofst = (req->dword0 & 0xFFFF);
+    uint16_t dlen = (req->dword1 & 0xFFFF);
+    NvmeMiResponse resp;
+    g_autofree uint8_t *resp_buf = NULL;
+    nvme_mi_resp_hdr_init(&resp, NVME_MI_CMD);
+    if ((dofst + dlen) > sizeof(NvmeMiVpdElements)) {
+        resp.status = INVALID_PARAMETER;
+        nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp, sizeof(resp));
+    } else {
+        resp.status = SUCCESS;
+        resp_buf = (uint8_t *) g_malloc(dlen + sizeof(resp));
+        memcpy(resp_buf, &resp, sizeof(resp));
+        memcpy(resp_buf + sizeof(resp), &ctrl_mi->vpd_data + dofst,
dlen);
+        nvme_mi_send_resp(ctrl_mi, resp_buf, dlen + sizeof(resp));
+    }
+}
+static void nvme_mi_vpd_write(NvmeMiCtrl *ctrl_mi,
+                              NvmeMiRequest *req, uint8_t *buf)
+{
+    uint16_t dofst = (req->dword0 & 0xFFFF);
+    uint16_t dlen = (req->dword1 & 0xFFFF);
+    NvmeMiResponse resp;
+    nvme_mi_resp_hdr_init(&resp, NVME_MI_CMD);
+    if ((dofst + dlen) > sizeof(NvmeMiVpdElements)) {
+        resp.status = INVALID_PARAMETER;
+        nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp, sizeof(resp));
+    } else {
+        resp.status = SUCCESS;
+        memcpy(&ctrl_mi->vpd_data + dofst, buf + 16 , dlen);
+        nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp, sizeof(resp));
+    }
+}
+
+static void nvme_mi_nvm_subsys_health_status_poll(NvmeMiCtrl *ctrl_mi,
+                                                  NvmeMiRequest *req)
+{
+    NvmeMiResponse resp;
+    NvmeMiNvmSubsysHspds nshds;
+    NvmeCtrl *ctrl = NULL;
+    g_autofree uint8_t *resp_buf = NULL;
+    nvme_mi_resp_hdr_init(&resp, NVME_MI_CMD);
+    for (uint32_t cntlid = 1; cntlid <
ARRAY_SIZE(ctrl_mi->n->subsys->ctrls);
+                  cntlid++) {
+
+        ctrl = nvme_subsys_ctrl(ctrl_mi->n->subsys, cntlid);
+        if (!ctrl) {
+            continue;
+        }
+
+        if ((ctrl->bar.csts & 0x1) == 0x1) {
+            nshds.ccs = 0x1;
+        }
+        if ((ctrl->bar.csts & 0x2) == 0x2) {
+            nshds.ccs |= 0x2;
+        }
+        if ((ctrl->bar.csts & 0x10) == 0x10) {
+            nshds.ccs |= 0x10;
+        }
+        if (find_first_bit(ctrl->changed_nsids, NVME_CHANGED_NSID_SIZE)
!=
+            NVME_CHANGED_NSID_SIZE) {
+                nshds.ccs |= 0x40;
+        }
+        if ((ctrl->temperature >= ctrl->features.temp_thresh_hi) ||
+           (ctrl->temperature <= ctrl->features.temp_thresh_low)) {
+            nshds.ccs |= 0x200;
+        }
+    }
+
+
+    resp_buf = (uint8_t *)g_malloc(sizeof(resp) + sizeof(nshds));
+    memcpy(resp_buf, &resp, sizeof(resp));
+    memcpy(resp_buf + sizeof(resp), &nshds, sizeof(nshds));
+    nvme_mi_send_resp(ctrl_mi, resp_buf, sizeof(resp_buf));
+}
+
+static void nvme_mi_admin_identify_ns(NvmeMiCtrl *ctrl_mi,
+                                      NvmeAdminMiRequest *req,
+                                      uint32_t dofst, uint32_t dlen)
+{
+    NvmeIdNs *id_ns;
+    uint32_t nsid = req->sqentry1;
+    NvmeMiAdminResponse resp;
+    NvmeNamespace *ns;
+    g_autofree uint8_t *resp_buff = NULL;
+    nvme_mi_resp_hdr_init((NvmeMiResponse *)&resp, NVME_ADM_CMD);
+    resp.status = SUCCESS;
+    ns = nvme_ns(ctrl_mi->n, nsid);
+    if (!ns) {
+        resp.cqdword0 = 0;
+        resp.cqdword1 = 0;
+        resp.cqdword3 = NVME_INVALID_NSID << 16;
+            nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp,
sizeof(NvmeMiAdminResponse));
+        return ;
+    }
+
+    id_ns = &ns->id_ns;
+
+    resp_buff = g_malloc0(sizeof(NvmeMiAdminResponse) + dlen);
+    memcpy(resp_buff, &resp, sizeof(NvmeMiAdminResponse));
+    memcpy(resp_buff + sizeof(NvmeMiAdminResponse), id_ns + dofst,
dlen);
+
+    nvme_mi_send_resp(ctrl_mi, (uint8_t *)resp_buff,
+                      (sizeof(NvmeMiAdminResponse) + dlen));
+}
+static void nvme_mi_admin_identify_ctrl(NvmeMiCtrl *ctrl_mi,
+                                        NvmeAdminMiRequest *req,
+                                        uint32_t dofst, uint32_t dlen)
+{
+    NvmeMiAdminResponse resp;
+    g_autofree uint8_t *resp_buff = NULL;
+    nvme_mi_resp_hdr_init((NvmeMiResponse *)&resp, NVME_ADM_CMD);
+    resp.status = SUCCESS;
+    resp_buff = g_malloc0(sizeof(NvmeMiAdminResponse) + dlen);
+    memcpy(resp_buff, &resp, sizeof(NvmeMiAdminResponse));
+    memcpy(resp_buff + sizeof(NvmeMiAdminResponse),
&ctrl_mi->n->id_ctrl + dofst, dlen);
+
+    nvme_mi_send_resp(ctrl_mi, (uint8_t *)resp_buff,
+                     (sizeof(NvmeMiAdminResponse) + dlen));
+}
+static void nvme_mi_admin_identify(NvmeMiCtrl *ctrl_mi,
NvmeAdminMiRequest *req)
+{
+    uint32_t cns = req->sqentry10 & 0xFF;
+    uint32_t cflags = req->cmdflags;
+    uint32_t dofst = req->dataofst;
+    uint32_t dlen = req->datalen;
+    NvmeMiResponse resp;
+    if (dofst + dlen > 4096) {
+        nvme_mi_resp_hdr_init(&resp, true);
+        resp.status = INVALID_PARAMETER;
+        return nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp,
sizeof(resp));
+    }
+    if ((cflags & 0x1) == 0) {
+        dlen = 4096;
+    }
+    if (!(cflags & 0x2)) {
+        dofst = 0;
+    }
+    switch (cns) {
+    case 0x00:
+        return nvme_mi_admin_identify_ns(ctrl_mi, req, dofst, dlen);
+    case 0x1:
+        return nvme_mi_admin_identify_ctrl(ctrl_mi, req, dofst, dlen);
+    default:
+    {
+        NvmeMiAdminResponse resp;
+        nvme_mi_resp_hdr_init((NvmeMiResponse *)&resp, NVME_ADM_CMD);
+        resp.status = SUCCESS;
+        resp.cqdword3 = NVME_INVALID_FIELD << 16;
+        nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp, sizeof(resp));
+    }
+    }
+}
+static void nvme_mi_admin_error_info_log(NvmeMiCtrl *ctrl_mi,
+                                         NvmeAdminMiRequest *req,
+                                         uint32_t dofst, uint32_t dlen)
+{
+    NvmeMiAdminResponse resp;
+    NvmeErrorLog errlog = { };
+    g_autofree uint8_t *resp_buff = NULL;
+    memset(&errlog, 0x0, sizeof(errlog));
+    nvme_mi_resp_hdr_init((NvmeMiResponse *)&resp, NVME_ADM_CMD);
+    resp.status = SUCCESS;
+    resp_buff = g_malloc0(sizeof(NvmeMiAdminResponse) + dlen);
+    memcpy(resp_buff, &resp, sizeof(NvmeMiAdminResponse));
+    memcpy(resp_buff + sizeof(NvmeMiAdminResponse), &errlog + dofst,
dlen);
+    nvme_mi_send_resp(ctrl_mi, (uint8_t *)resp_buff,
+                     (sizeof(NvmeMiAdminResponse) + dlen));
+}
+
+static void nvme_mi_admin_get_log_page(NvmeMiCtrl *ctrl_mi,
+                                       NvmeAdminMiRequest *req)
+{
+    uint32_t lid = req->sqentry10;
+    uint32_t cflags = req->cmdflags;
+    uint32_t dofst = req->dataofst;
+    uint32_t dlen = req->datalen;
+    NvmeMiResponse resp;
+
+    switch (lid) {
+    case 0x00:
+        if (dofst + dlen > sizeof(NvmeErrorLog)) {
+            nvme_mi_resp_hdr_init(&resp, NVME_ADM_CMD);
+            resp.status = INVALID_PARAMETER;
+            return nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp,
sizeof(resp));
+        }
+        if ((cflags & 0x1) == 0) {
+            dlen = sizeof(NvmeErrorLog);
+        }
+        if (!(cflags & 0x2)) {
+            dofst = 0;
+        }
+        if (dofst + dlen > sizeof(NvmeErrorLog)) {
+            nvme_mi_resp_hdr_init(&resp, NVME_ADM_CMD);
+            resp.status = INVALID_PARAMETER;
+            return nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp,
sizeof(resp));
+        }
+
+        return nvme_mi_admin_error_info_log(ctrl_mi, req, dofst, dlen);
+    default:
+    {
+        NvmeMiAdminResponse resp;
+        nvme_mi_resp_hdr_init((NvmeMiResponse *)&resp, NVME_ADM_CMD);
+        resp.status = SUCCESS;
+        resp.cqdword3 = NVME_INVALID_FIELD << 16;
+        nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp, sizeof(resp));
+    }
+    }
+}
+
+static void nvme_mi_admin_get_features(NvmeMiCtrl *ctrl_mi,
+                                       NvmeAdminMiRequest *req)
+{
+    uint32_t fid = req->sqentry10 & 0xFF;
+    uint32_t dofst = req->dataofst;
+    uint32_t dlen = req->datalen;
+    NvmeMiResponse miresp;
+    NvmeMiAdminResponse miadminresp;
+    if (dofst || dlen) {
+
+        nvme_mi_resp_hdr_init(&miresp, NVME_ADM_CMD);
+        miresp.status = INVALID_PARAMETER;
+        return nvme_mi_send_resp(ctrl_mi, (uint8_t *)&miresp,
sizeof(miresp));
+    }
+
+    nvme_mi_resp_hdr_init((NvmeMiResponse *)&miadminresp,
NVME_ADM_CMD);
+    miadminresp.status = SUCCESS;
+
+    switch (fid) {
+    case NVME_TEMPERATURE_THRESHOLD:
+        miadminresp.cqdword0 = 0;
+
+        if (NVME_TEMP_TMPSEL(req->sqentry11) !=
NVME_TEMP_TMPSEL_COMPOSITE) {
+            break;
+        }
+
+        if (NVME_TEMP_THSEL(req->sqentry11) == NVME_TEMP_THSEL_OVER) {
+            miadminresp.cqdword0 = NVME_TEMPERATURE_WARNING;
+        }
+        break;
+    case NVME_NUMBER_OF_QUEUES:
+        miadminresp.cqdword0 = (ctrl_mi->n->params.max_ioqpairs - 1) |
+                        ((ctrl_mi->n->params.max_ioqpairs - 1) << 16);
+        break;
+    default:
+        miadminresp.cqdword3 = NVME_INVALID_FIELD << 16;
+        break;
+    }
+
+    return nvme_mi_send_resp(ctrl_mi, (uint8_t *)&miadminresp,
sizeof(miadminresp));
+}
+
+static void nvme_mi_admin_command(NvmeMiCtrl *ctrl_mi, void* req_arg)
+{
+    uint8_t *msg  = ((uint8_t *)req_arg);
+    NvmeMiMessageHeader msghdr;
+    NvmeMiRequest *req = (NvmeMiRequest *) (msg);
+    memcpy(&msghdr, msg, sizeof(NvmeMiMessageHeader));
+    if (msghdr.nmimt == 1) {
+        switch (req->opc) {
+        case READ_NVME_MI_DS:
+            nvme_mi_read_nvme_mi_ds(ctrl_mi, req);
+            break;
+        case CHSP:
+            nvme_mi_controller_health_ds(ctrl_mi, req);
+            break;
+        case NVM_SHSP:
+            nvme_mi_nvm_subsys_health_status_poll(ctrl_mi, req);
+            break;
+        case CONFIGURATION_SET:
+            nvme_mi_configuration_set(ctrl_mi, req);
+            break;
+        case CONFIGURATION_GET:
+            nvme_mi_configuration_get(ctrl_mi, req);
+            break;
+        case VPD_READ:
+            nvme_mi_vpd_read(ctrl_mi, req);
+            break;
+        case VPD_WRITE:
+            nvme_mi_vpd_write(ctrl_mi, req, msg);
+            break;
+        default:
+        {
+            NvmeMiResponse resp;
+            nvme_mi_resp_hdr_init(&resp, false);
+            resp.status = INVALID_COMMAND_OPCODE;
+            nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp, sizeof(resp));
+            break;
+        }
+        }
+    } else {
+        NvmeAdminMiRequest *req = (NvmeAdminMiRequest *) (msg);
+        switch  (req->opc) {
+        case NVME_ADM_CMD_IDENTIFY:
+            nvme_mi_admin_identify(ctrl_mi, req);
+            break;
+        case NVME_ADM_CMD_GET_LOG_PAGE:
+            nvme_mi_admin_get_log_page(ctrl_mi, req);
+            break;
+        case NVME_ADM_CMD_GET_FEATURES:
+            nvme_mi_admin_get_features(ctrl_mi, req);
+            break;
+        default:
+        {
+            NvmeMiResponse resp;
+            nvme_mi_resp_hdr_init(&resp, true);
+            resp.status = INVALID_COMMAND_OPCODE;
+            nvme_mi_send_resp(ctrl_mi, (uint8_t *)&resp, sizeof(resp));
+            break;
+        }
+        }
+    }
+
+    return;
+}
+
+static int nvme_mi_i2c_send(I2CSlave *s, uint8_t data)
+{
+    NvmeMiCtrl *mictrl = (NvmeMiCtrl *)s;
+    NvmeMiSendRecvStruct *misendrecv = &mictrl->misendrecv;
+
+    switch (misendrecv->state.pktpos) {
+    case NVME_MI_BYTE_LENGTH_POS:
+        misendrecv->state.pktlen = data;
+        break;
+    case NVME_MI_HOST_SLAVE_ADDR_POS:
+        misendrecv->hostslaveaddr = data >> 1;
+        break;
+    case NVME_MI_EOM_POS:
+        misendrecv->eom = (data >> 6) & 1;
+        break;
+    }
+    misendrecv->state.sendrecvbuf[++misendrecv->state.pktpos] = data;
+    if (misendrecv->state.pktpos == misendrecv->state.pktlen + 3) {
+        misendrecv->cmdbuffer = (uint8_t
*)g_realloc(misendrecv->cmdbuffer,
+                                                     misendrecv->offset
+
+
misendrecv->state.pktpos - 5);
+        memcpy(misendrecv->cmdbuffer + misendrecv->offset,
+               misendrecv->state.sendrecvbuf + 8,
misendrecv->state.pktpos - 5);
+
+        misendrecv->offset += misendrecv->state.pktpos - 5;
+        misendrecv->state.pktlen = 0;
+        misendrecv->state.pktpos = 0;
+
+        if (misendrecv->eom == 1) {
+            misendrecv->total_len = 0;
+            misendrecv->eom = 0;
+            nvme_mi_admin_command(mictrl, misendrecv->cmdbuffer);
+            misendrecv->offset = 0;
+            i2c_end_transfer(mictrl->bus);
+            for (int i = 0; i < misendrecv->total_len; i++) {
+                smbus_send_byte(mictrl->bus, misendrecv->hostslaveaddr,
+                                misendrecv->state.sendrecvbuf[i]);
+            }
+        }
+    }
+    return 0;
+}
+
+static void nvme_mi_realize(DeviceState *dev, Error **errp)
+{
+    NvmeMiCtrl *s = (NvmeMiCtrl *)(dev);
+    s->bus = (I2CBus *)dev->parent_bus;
+    s->smbus_freq = NVME_MI_DEF_SMBUS_FREQ;
+    s->mctp_unit_size = NVME_MI_DEF_MCTP_TRANS_UNIT_SIZE;
+}
+static Property nvme_mi_props[] = {
+     DEFINE_PROP_LINK("nvme", NvmeMiCtrl, n, TYPE_NVME, NvmeCtrl *),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void nvme_mi_class_init(ObjectClass *oc, void *data)
+{
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(oc);
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = nvme_mi_realize;
+    k->send = nvme_mi_i2c_send;
+
+    device_class_set_props(dc, nvme_mi_props);
+}
+
+static const TypeInfo nvme_mi = {
+    .name = TYPE_NVME_MI,
+    .parent = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(NvmeMiCtrl),
+    .class_init = nvme_mi_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&nvme_mi);
+}
+
+type_init(register_types);
diff --git a/hw/nvme/nvme-mi.h b/hw/nvme/nvme-mi.h
new file mode 100644
index 0000000..5e3007d
--- /dev/null
+++ b/hw/nvme/nvme-mi.h
@@ -0,0 +1,288 @@
+/*
+ * QEMU NVMe-MI
+ *
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Authors:
+ *   Padmakar Kalghatgi      <p.kalghatgi@samsung.com>
+ *   Arun Kumar Agasar       <arun.kka@samsung.com>
+ *   Saurav Kumar            <saurav.29@partner.samsung.com>
+ *
+ * This code is licensed under the GNU GPL v2 or later.
+ */
+
+#ifndef NVME_MI_H
+#define NVME_MI_H
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "hw/i2c/i2c.h"
+
+#define TYPE_NVME_MI "nvme-mi-i2c"
+
+#define NVM_SUBSYSTEM_INFORMATION 0
+#define PORT_INFORMATION 1
+#define CONTROLLER_LIST 2
+#define CONTROLLER_INFORMATION 3
+#define OPT_SUPP_CMD_LIST 4
+#define MGMT_EPT_BUFF_CMD_SUPP_LIST 5
+
+/*
+ *  considering MCTP transmission unit size
+ *  being 64, total MI payload size equal to 4224
+ *  and further including the SMBUS header for
+ *  each of the MCTP packet, I have defined maximum
+ *  buffer size of 5000
+ */
+#define MAX_NVME_MI_BUF_SIZE 5000
+#define NVME_MI_SMBUS_HEADER_AND_PEC 9
+
+/* value of 1 for the frequency means 100Khz */
+#define NVME_MI_DEF_SMBUS_FREQ 1
+#define NVME_MI_DEF_MCTP_TRANS_UNIT_SIZE 64
+
+enum NvmeMiMngmtInterfaceCmdSetsOpcodes {
+   READ_NVME_MI_DS                   = 0x00,
+   NVM_SHSP                          = 0x01,
+   CHSP                              = 0x02,
+   CONFIGURATION_SET                 = 0x03,
+   CONFIGURATION_GET                 = 0x04,
+   VPD_READ                          = 0x05,
+   VPD_WRITE                         = 0x06,
+   MI_RESET                          = 0x07,
+   SES_RECEIVE                       = 0x08,
+   SES_SEND                          = 0x09,
+   MANAGEMENT_ENDPOINT_BUFFER_READ   = 0x0A,
+   MANAGEMENT_ENDPOINT_BUFFER_WRITE  = 0x0B,
+   MI_RESERVED                       = 0x0C,
+   VENDOR_SPECIFIC                   = 0xC0
+};
+
+enum NvmeMiControlPrimitiveOpcodes {
+   PAUSE                             = 0x00,
+   RESUME                            = 0x01,
+   ABORT                             = 0x02,
+   GET_STATE                         = 0x03,
+   REPLAY                            = 0x04,
+   CTRL_PRIMITIVE_RESERVED           = 0x05,
+   CTRL_PRIMITIVE_VENDOR_SPECIFIC    = 0xF0
+};
+
+enum NvmeMiType {
+    CP,
+    NVME_MI_CMD,
+    NVME_ADM_CMD
+};
+
+enum NvmeMiConfigGetResponseValue {
+   DEFAULT_MCTP_SIZE   = 64,
+   DEFAULT_SMBUS_FREQ  = 1,
+   SET_SMBUS_FREQ      = 129,
+   SET_7BITS           = 255,
+   SET_4BITS           = 15,
+   SET_16BITS          = 65535
+};
+
+enum NvmeMiConfigurationIdentifier {
+   SMBUS_I2C_FREQ = 1,
+   HEALTH_STATUS_CHG,
+   MCTP_TRANS_UNIT_SIZE,
+};
+
+enum NvmeMiResponseMessageStatus {
+   SUCCESS,
+   MORE_PROCESSING_REQUIRED,
+   INTERNAL_ERROR,
+   INVALID_COMMAND_OPCODE,
+   INVALID_PARAMETER,
+   INVALID_COMMAND_SIZE,
+   INVALID_COMMAND_INPUT_DATA_SIZE,
+   ACCESS_DENIED,
+   VPD_UPDATES_EXCEEDED = 0x20,
+   PCIe_INACCESSIBLE
+};
+
+uint32_t NvmeMiCmdOptSupList[] = {
+  /*
+   * MANAGEMENT_ENDPOINT_BUFFER_READ,
+   * MANAGEMENT_ENDPOINT_BUFFER_WRITE,
+   */
+};
+
+uint32_t NvmeMiAdminCmdOptSupList[] = {
+   /*
+    *  NVME_ADM_CMD_DST,
+    *  NVME_ADM_CMD_DOWNLOAD_FW,
+    *  NVME_ADM_CMD_ACTIVATE_FW,
+    *  NVME_ADM_CMD_FORMAT_NVM,
+    *  NVME_ADM_CMD_NS_MANAGEMENT,
+    *  NVME_ADM_CMD_NS_ATTACHMENT,
+    *  NVME_ADM_CMD_DIRECTIVE_SEND,
+    *  NVME_ADM_CMD_DIRECTIVE_RECV,
+    *  NVME_ADM_CMD_SET_FEATURES,
+    *  NVME_ADM_CMD_SANITIZE,
+    */
+};
+
+enum NvmemiPktPos {
+   NVME_MI_BYTE_LENGTH_POS = 1,
+   NVME_MI_HOST_SLAVE_ADDR_POS = 2,
+   NVME_MI_EOM_POS = 6
+};
+
+typedef struct pktposstate {
+  u_char sendrecvbuf[MAX_NVME_MI_BUF_SIZE];
+  uint32_t pktlen, pktpos, mode;
+} pktposstate;
+
+typedef struct NvmeMiSendRecvStruct {
+   uint32_t total_len;
+   uint32_t offset;
+   uint8_t eom;
+   pktposstate state;
+   uint8_t *cmdbuffer;
+   uint8_t hostslaveaddr;
+} NvmeMiSendRecvStruct;
+
+typedef struct NvmeMiVpdElements {
+    long common_header;
+} NvmeMiVpdElements;
+
+typedef struct NvmeMiCtrl {
+   I2CSlave parent_obj;
+   uint32_t mctp_unit_size;
+   uint32_t smbus_freq;
+   NvmeMiVpdElements vpd_data;
+   NvmeMiSendRecvStruct  misendrecv;
+   NvmeCtrl *n;
+   I2CBus *bus;
+} NvmeMiCtrl;
+
+typedef struct NvmeMiMessageHeader {
+   uint32_t msgtype: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;
+} NvmeMiMessageHeader;
+
+typedef struct NvmeMiRequest {
+   NvmeMiMessageHeader msg_header;
+   uint32_t               opc:8;
+   uint32_t               rsvd:24;
+   uint32_t               dword0;
+   uint32_t               dword1;
+   uint32_t               mic;
+} NvmeMiRequest;
+
+typedef struct NvmeAdminMiRequest {
+   NvmeMiMessageHeader msg_header;
+   uint8_t                opc;
+   uint8_t                cmdflags;
+   uint16_t               cntlid;
+   uint32_t               sqentry1;
+   uint32_t               sqentry2;
+   uint32_t               sqentry3;
+   uint32_t               sqentry4;
+   uint32_t               sqentry5;
+   uint32_t               dataofst;
+   uint32_t               datalen;
+   uint32_t               reserved[2];
+   uint32_t               sqentry10;
+   uint32_t               sqentry11;
+   uint32_t               sqentry12;
+   uint32_t               sqentry13;
+   uint32_t               sqentry14;
+   uint32_t               sqentry15;
+   uint32_t               mic;
+} NvmeAdminMiRequest;
+
+typedef struct ReadNvmeMiDs {
+    uint16_t cntrlid;
+    uint8_t  portlid;
+    uint8_t  dtyp;
+}  ReadNvmeMiDs;
+
+typedef struct NvmeMiConfigurationSet {
+    uint8_t conf_identifier_dword_0;
+    uint16_t conf_identifier_specific_dword_0;
+    uint16_t conf_identifier_specific_dword_1;
+}  MiConfigurationSet;
+
+typedef struct NvmeMiNvmSubsysHspds {
+    uint8_t nss;
+    uint8_t sw;
+    uint8_t ctemp;
+    uint8_t pdlu;
+    uint16_t ccs;
+    uint16_t reserved;
+} NvmeMiNvmSubsysHspds;
+
+typedef struct NvmeMiControlPrimitives {
+    uint32_t nmh;
+    uint32_t cpo;
+    uint32_t tag;
+    uint32_t cpsp;
+    uint32_t mic;
+} NvmeMiControlPrimitives;
+
+typedef struct NvmMiSubsysInfoDs {
+    uint8_t nump;
+    uint8_t mjr;
+    uint8_t mnr;
+    uint8_t rsvd[29];
+} NvmMiSubsysInfoDs;
+
+typedef struct NvmeMiCwarnStruct {
+    uint8_t spare_thresh:1;
+    uint8_t temp_above_or_under_thresh:1;
+    uint8_t rel_degraded:1;
+    uint8_t read_only:1;
+    uint8_t vol_mem_bup_fail:1;
+    uint8_t reserved:3;
+} NvmeMiCwarnStruct;
+
+typedef struct NvmeMiCstsStruct {
+    uint16_t rdy:1;
+    uint16_t cfs:1;
+    uint16_t shst:2;
+    uint16_t nssro:1;
+    uint16_t en:1;
+    uint16_t nssac:1;
+    uint16_t fwact:1;
+    uint16_t reserved:8;
+} NvmeMiCstsStruct;
+
+typedef struct NvmeMiCtrlHealthDs {
+   uint16_t ctlid;
+   NvmeMiCstsStruct csts;
+   uint16_t ctemp;
+   uint16_t pdlu;
+   uint8_t spare;
+   NvmeMiCwarnStruct cwarn;
+   uint8_t reserved[7];
+} NvmeMiCtrlHealthDs;
+
+typedef struct NvmeMiResponse {
+   NvmeMiMessageHeader msg_header;
+   uint32_t status:8;
+   uint32_t mgmt_resp:24;
+} NvmeMiResponse;
+
+typedef struct NvmeMiAdminResponse {
+   NvmeMiMessageHeader msg_header;
+   uint32_t status:8;
+   uint32_t mgmt_resp:24;
+   uint32_t cqdword0;
+   uint32_t cqdword1;
+   uint32_t cqdword3;
+} NvmeMiAdminResponse;
+
+
+
+#endif


[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



  parent reply	other threads:[~2021-10-26 13:19 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20210803080737epcas5p1c9bd6ecde8700d1194748533a3812db6@epcas5p1.samsung.com>
2021-08-03  7:24 ` [RFC PATCH: v3 1/2] add mi device in qemu Padmakar Kalghatgi
2021-08-03  7:24   ` Padmakar Kalghatgi
     [not found]   ` <CGME20210803094723epcas5p323efa7e40e3d843ff8b91507c48edd17@epcas5p3.samsung.com>
2021-08-03  9:04     ` [RFC PATCH : v3 2/2] Implementation of nvme-mi plugin in nvme-cli Mohit Kapoor
2021-08-03  9:04       ` Mohit Kapoor
2021-09-06 14:18       ` Mohit Kapoor
2021-09-06 14:18         ` Mohit Kapoor
2021-08-18  6:01   ` [RFC PATCH: v3 1/2] add mi device in qemu Klaus Jensen
2021-08-18  6:01     ` Klaus Jensen
2021-08-19 16:34     ` Padmakar Kalghatgi
2021-08-19 16:34       ` Padmakar Kalghatgi
2021-09-29  4:37   ` Klaus Jensen
2021-10-01 15:15     ` Padmakar Kalghatgi
2021-10-26 13:13     ` Padmakar Kalghatgi [this message]
2021-10-27  5:36       ` [RFC PATCH: v4 2/2] separate utility for nvme-mi Arun Kumar Kashinath Agasar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211026131358.GA23684@test.sa.corp.samsungelectronics.net \
    --to=p.kalghatgi@samsung.com \
    --cc=arun.kka@samsung.com \
    --cc=d.palani@samsung.com \
    --cc=fam@euphon.net \
    --cc=its@irrelevant.dk \
    --cc=javier.gonz@samsung.com \
    --cc=jg123.choi@samsung.com \
    --cc=k.jensen@samsung.com \
    --cc=kbusch@kernel.org \
    --cc=kwolf@redhat.com \
    --cc=mohit.kap@samsung.com \
    --cc=mreitz@redhat.com \
    --cc=prakash.v@samsung.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    --cc=u.kishore@samsung.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.