From: padmakar <[email protected]> The changes here includes the interface for i2c/smbus for nvme-mi protocol. We have used an address of 0x15 using which the guest VM can send and recieve the nvme-mi commands. Since the nvme-mi device uses the I2C_SLAVE as parent, we have used the send and recieve callbacks by which the nvme-mi device will get the required notification. With the callback approach, we have eliminated the use of threads.
Please provide us with your valuable feedback on this patch. --- hw/nvme/nvme-mi.c | 152 ++++++++++++++++++++++-------------------------------- hw/nvme/nvme-mi.h | 23 ++++++--- 2 files changed, 79 insertions(+), 96 deletions(-) diff --git a/hw/nvme/nvme-mi.c b/hw/nvme/nvme-mi.c index 5e93417..a90ce90 100644 --- a/hw/nvme/nvme-mi.c +++ b/hw/nvme/nvme-mi.c @@ -4,7 +4,7 @@ * Copyright (c) 2021, Samsung Electronics co Ltd. * * Written by Padmakar Kalghatgi <[email protected]> - * Arun Kumar Agasar <[email protected]> + * Arun Kumar Agasar <[email protected]> * Saurav Kumar <[email protected]> * * This code is licensed under the GNU GPL v2 or later. @@ -19,10 +19,8 @@ * The nvme-mi device has to be used along with nvme device only * * Add options: - * -device nvme-mi,bus=<nvme bus number> - * -device vhost-vsock-pci, guest-cid=<vsock cid> + * -device nvme-mi,nvme=<nvme id>,address=0x15", * - * the cid is used to connect to the vsock */ #include "qemu/osdep.h" @@ -41,8 +39,8 @@ static void nvme_mi_send_resp(NvmeMiCtrl *ctrl_mi, uint8_t *resp, uint32_t size) { uint32_t crc_value = crc32c(0xFFFFFFFF, resp, size); size += 4; - uint32_t retries = 5; uint32_t offset = 0; + uint32_t ofst = 0; uint32_t som = 1; uint32_t eom = 0; uint32_t pktseq = 0; @@ -51,24 +49,17 @@ static void nvme_mi_send_resp(NvmeMiCtrl *ctrl_mi, uint8_t *resp, uint32_t size) uint32_t sizesent = size > mtus ? mtus : size; size -= sizesent; eom = size > 0 ? 0 : 1; - g_autofree uint8_t *buf = (uint8_t *)g_malloc(sizesent + 8); + g_autofree uint8_t *buf = (uint8_t *)g_malloc0(sizesent + 8); buf[2] = sizesent + 5; buf[7] = (som << 7) | (eom << 6) | (pktseq << 5); som = 0; memcpy(buf + 8, resp + offset, sizesent); offset += sizesent; if (size <= 0) { - memcpy(buf + 4 + offset , &crc_value, sizeof(crc_value)); - } - retries = 5; - while (retries > 0) { - int32_t nsend = send(ctrl_mi->sock_desc, buf, sizesent + 8, 0); - if (nsend < 0) { - retries--; - } else { - break; - } + memcpy(buf + 8 + offset , &crc_value, sizeof(crc_value)); } + memcpy(ctrl_mi->misendrecv.sendrecvbuf + ofst, buf, sizesent + 8); + ofst += sizesent + 8; } } @@ -176,7 +167,6 @@ static void nvme_mi_controller_health_ds(NvmeMiCtrl *ctrl_mi, (dword1 & 0x2)) { nvme_mi_chds.cwarn.temp_above_or_under_thresh = 0x1; } - printf("size = %lu\n", sizeof(resp) + sizeof(NvmeMiCtrlHealthDs)); g_autofree uint8_t *resp_buf = (uint8_t *)g_malloc(sizeof(resp) + sizeof(NvmeMiCtrlHealthDs)); resp.mgmt_resp = 1 << 0x10; @@ -283,9 +273,8 @@ static void nvme_mi_vpd_read(NvmeMiCtrl *ctrl_mi, NvmeMIRequest *req) 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) +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); @@ -308,7 +297,7 @@ static void nvme_mi_nvm_subsys_health_status_poll(NvmeMiCtrl *ctrl_mi, NvmeMiNvmSubsysHspds nshds; nvme_mi_resp_hdr_init(&resp, false); for (uint32_t cntlid = 1; cntlid < ARRAY_SIZE(ctrl_mi->n->subsys->ctrls); - cntlid++) { + cntlid++) { NvmeCtrl *ctrl = nvme_subsys_ctrl(ctrl_mi->n->subsys, cntlid); if (!ctrl) { @@ -335,7 +324,8 @@ static void nvme_mi_nvm_subsys_health_status_poll(NvmeMiCtrl *ctrl_mi, } - g_autofree uint8_t *resp_buf = (uint8_t *)g_malloc(sizeof(resp) + sizeof(nshds)); + g_autofree uint8_t *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)); @@ -553,15 +543,12 @@ static void nvme_mi_admin_command(NvmeMiCtrl *ctrl_mi, void* req_arg) NvmeAdminMIRequest *req = (NvmeAdminMIRequest *) (msg); switch (req->opc) { case NVME_ADM_MI_CMD_IDENTIFY: - printf("identify\n"); nvme_mi_admin_identify(ctrl_mi, req); break; case NVME_ADM_MI_CMD_GET_LOG_PAGE: - printf("get log page\n"); nvme_mi_admin_get_log_page(ctrl_mi, req); break; case NVME_ADM_MI_CMD_GET_FEATURES: - printf("get features\n"); nvme_mi_admin_get_features(ctrl_mi, req); break; default: @@ -578,92 +565,79 @@ static void nvme_mi_admin_command(NvmeMiCtrl *ctrl_mi, void* req_arg) return; } -static void nvme_mi_init(NvmeMiCtrl *ctrl_mi) +static uint8_t nvme_mi_i2c_recv(I2CSlave *s) { - pthread_t vsock_tid; - pthread_create(&vsock_tid, NULL, vsock_server_start, ctrl_mi); - pthread_detach(vsock_tid); + NvmeMiCtrl *mictrl = (NvmeMiCtrl *)s; + NvmeMiSendRecvStruct *misendrecv = &mictrl->misendrecv; + if (misendrecv->bsyncflag == true) { + return -1; + } + return misendrecv->sendrecvbuf[misendrecv->sendlen++]; } -void *vsock_server_start(void *arg) +static int nvme_mi_i2c_send(I2CSlave *s, uint8_t data) { - NvmeMiCtrl *ctrl_mi = (NvmeMiCtrl *)arg; - int listenfd = 0, c = 0; - struct sockaddr_vm sa = { - .svm_family = AF_VSOCK, - .svm_cid = VMADDR_CID_ANY, - .svm_port = 1342, - }; - struct sockaddr_vm client; - listenfd = socket(AF_VSOCK, SOCK_STREAM, 0); - if (listenfd == -1) { - pthread_exit(NULL); - } - if (bind(listenfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { - pthread_exit(NULL); + NvmeMiCtrl *mictrl = (NvmeMiCtrl *)s; + NvmeMiSendRecvStruct *misendrecv = &mictrl->misendrecv; + + misendrecv->bsyncflag = true; + misendrecv->sendlen = 0; + switch (misendrecv->len) { + case 1: + misendrecv->total_len = data; + break; + case 6: + misendrecv->eom = (data & 0x40) >> 6; + break; } - listen(listenfd, 1); - puts("Waiting for incoming connections..."); - c = sizeof(struct sockaddr_vm); - while (1) { - ctrl_mi->sock_desc = accept(listenfd, (struct sockaddr *)&client, - (socklen_t *)&c); - if ((ctrl_mi->sock_desc) < 0) { - continue; - } - - NvmeMiMctpHeader mctp_hdr; - uint32_t total_len = 0; - uint8_t *getdata_buf = NULL; - while (!mctp_hdr.EOM) { - uint8_t buf[7]; - recv(ctrl_mi->sock_desc, buf, 7, 0); - mctp_hdr.byte_count = buf[1]; - mctp_hdr.EOM = (buf[6] & 0x40) >> 6; - mctp_hdr.SOM = (buf[6] & 0x80) >> 7; - mctp_hdr.pckt_seq = (buf[6] & 0x20) >> 5; - - uint32_t curr_len = total_len; - total_len = total_len + (mctp_hdr.byte_count - 5); - - getdata_buf = (uint8_t *)g_realloc(getdata_buf, total_len); - recv(ctrl_mi->sock_desc, getdata_buf + curr_len, - (mctp_hdr.byte_count - 5), 0); + misendrecv->sendrecvbuf[++misendrecv->len] = data; + if (misendrecv->len == misendrecv->total_len + 3) { + misendrecv->cmdbuffer = (uint8_t *)g_realloc(misendrecv->cmdbuffer, + misendrecv->len - 5); + memcpy(misendrecv->cmdbuffer + misendrecv->offset, + misendrecv->sendrecvbuf + 8, misendrecv->len - 5); + + misendrecv->offset = misendrecv->len - 5; + misendrecv->total_len = 0; + misendrecv->len = 0; + + if (misendrecv->eom == 1) { + nvme_mi_admin_command(mictrl, misendrecv->cmdbuffer); + misendrecv->offset = 0; + misendrecv->bsyncflag = false; } - NvmeMiMessageHeader msghdr; - memcpy(&msghdr, getdata_buf, sizeof(NvmeMiMessageHeader)); - nvme_mi_admin_command(ctrl_mi, getdata_buf); } - pthread_exit(0); + return 0; } static void nvme_mi_realize(DeviceState *dev, Error **errp) { - NvmeMiCtrl *ctrl_mi = (NvmeMiCtrl *)malloc(sizeof(NvmeMiCtrl)); - BusState *s = qdev_get_parent_bus(dev); - ctrl_mi->n = NVME(s->parent); - ctrl_mi->mctp_unit_size = 64; - ctrl_mi->smbus_freq = 0x01; - ctrl_mi->sock_desc = 0; - memset(&ctrl_mi->vpd_data, 0, sizeof(ctrl_mi->vpd_data)); - - nvme_mi_init(ctrl_mi); + NvmeMiCtrl *s = (NvmeMiCtrl *)(dev); + + s->smbus_freq = 100; + s->mctp_unit_size = 64; } +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); - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - - dc->bus_type = TYPE_NVME_BUS; dc->realize = nvme_mi_realize; - dc->desc = "nvme mi"; + k->recv = nvme_mi_i2c_recv; + 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_DEVICE, + .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(NvmeMiCtrl), .class_init = nvme_mi_class_init, }; diff --git a/hw/nvme/nvme-mi.h b/hw/nvme/nvme-mi.h index 4c155a0..92a20e6 100644 --- a/hw/nvme/nvme-mi.h +++ b/hw/nvme/nvme-mi.h @@ -5,7 +5,7 @@ * * Authors: * Padmakar Kalghatgi <[email protected]> - * Arun Kumar Agasar <[email protected]> + * Arun Kumar Agasar <[email protected]> * Saurav Kumar <[email protected]> * * This code is licensed under the GNU GPL v2 or later. @@ -14,14 +14,12 @@ #ifndef NVME_MI_H #define NVME_MI_H -#include <sys/socket.h> -#include <linux/vm_sockets.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdint.h> #include <stdbool.h> -#include <pthread.h> +#include "hw/i2c/i2c.h" #define TYPE_NVME_MI "nvme-mi" @@ -32,17 +30,28 @@ #define OPT_SUPP_CMD_LIST 4 #define MGMT_EPT_BUFF_CMD_SUPP_LIST 5 + +typedef struct NvmeMiSendRecvStruct { + uint32_t sendlen; + uint8_t len; + uint8_t total_len; + uint32_t offset; + uint8_t eom; + bool bsyncflag; + u_char sendrecvbuf[5000]; + uint8_t *cmdbuffer; +} NvmeMiSendRecvStruct; typedef struct NvmeMiVpdElements { long common_header; } NvmeMiVpdElements; typedef struct NvmeMiCtrl { - int32_t sock_desc; + I2CSlave parent_obj; uint32_t mctp_unit_size; uint32_t smbus_freq; - NvmeCtrl *n; NvmeMiVpdElements vpd_data; - u_char dummy[1000]; + NvmeMiSendRecvStruct misendrecv; + NvmeCtrl *n; } NvmeMiCtrl; enum NvmeMiMngmtInterfaceCmdSetsOpcodes { -- 2.7.0.windows.1
