Index: usr.sbin/bhyve/bhyve.8 =================================================================== --- usr.sbin/bhyve/bhyve.8 +++ usr.sbin/bhyve/bhyve.8 @@ -538,6 +538,8 @@ Sector size (defaults to blockif sector size). .It Li ser Serial number with maximum 20 characters. +.It Li smart +Passthough host's NVMe device logpage(page 2) .El .Pp AHCI devices: Index: usr.sbin/bhyve/pci_nvme.c =================================================================== --- usr.sbin/bhyve/pci_nvme.c +++ usr.sbin/bhyve/pci_nvme.c @@ -35,6 +35,7 @@ * * options: * -s ,nvme,devpath,maxq=#,qsz=#,ioslots=#,sectsz=#,ser=A-Z,eui64=#,dsm= + * ,smart=nvmedev * * accepted devpath: * /dev/blockdev @@ -48,6 +49,7 @@ * ser = serial number (20-chars max) * eui64 = IEEE Extended Unique Identifier (8 byte value) * dsm = DataSet Management support. Option is one of auto, enable,disable + * smart = passthough logpage(page 2) from host. * */ @@ -59,12 +61,22 @@ #include __FBSDID("$FreeBSD$"); +#include +#ifndef WITHOUT_CAPSICUM +#include +#endif #include #include +#include #include #include +#ifndef WITHOUT_CAPSICUM +#include +#endif +#include #include +#include #include #include #include @@ -72,6 +84,8 @@ #include #include #include +#include +#include #include #include @@ -302,6 +316,9 @@ uint32_t read_dunits_remainder; uint32_t write_dunits_remainder; + /* Health log passthrough device handle */ + int health_passthrough_ctx; + STAILQ_HEAD(, pci_nvme_aer) aer_list; uint32_t aer_count; }; @@ -1064,6 +1081,8 @@ { uint32_t logsize; uint8_t logpage = command->cdw10 & 0xFF; + struct nvme_pt_command pt; + u_int numd; DPRINTF("%s log page %u len %u", __func__, logpage, logsize); @@ -1095,6 +1114,24 @@ sizeof(sc->health_log.host_write_commands)); pthread_mutex_unlock(&sc->mtx); + if ( sc->health_passthrough_ctx > 0 ) { + memset(&pt, 0, sizeof(pt)); + numd = sizeof(sc->health_log) / sizeof(uint32_t) - 1; + + pt.cmd.opc = NVME_OPC_GET_LOG_PAGE; + pt.cmd.nsid = NVME_GLOBAL_NAMESPACE_TAG; + pt.cmd.cdw10 = htole32( + (numd << 16) | /* NUMDL */ + logpage); /* LID */ + pt.cmd.cdw11 = htole32( + (numd >> 16)); /* NUMDU */ + pt.buf = &sc->health_log; + pt.len = sizeof(sc->health_log); + pt.is_read = 1; + + ioctl(sc->health_passthrough_ctx, NVME_PASSTHROUGH_CMD, &pt); + } + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, command->prp2, (uint8_t *)&sc->health_log, MIN(logsize, sizeof(sc->health_log)), @@ -2611,6 +2648,11 @@ uint32_t sectsz; int optidx; +#ifndef WITHOUT_CAPSICUM + cap_rights_t rights; + cap_ioctl_t cmds[] = { NVME_PASSTHROUGH_CMD }; +#endif + sc->max_queues = NVME_QUEUES; sc->max_qentries = NVME_MAX_QENTRIES; sc->ioslots = NVME_IOSLOTS; @@ -2668,6 +2710,21 @@ sc->dataset_management = NVME_DATASET_MANAGEMENT_ENABLE; else if (!strcmp("disable", config)) sc->dataset_management = NVME_DATASET_MANAGEMENT_DISABLE; + } else if (!strcmp("smart", xopts)) { + sc->health_passthrough_ctx = open(config, O_RDONLY); + if (sc->health_passthrough_ctx < 0) { + perror("Could not open smart passthrough device"); + free(uopt); + return (-1); + } +#ifndef WITHOUT_CAPSICUM + cap_rights_init(&rights, CAP_IOCTL); + + if (caph_rights_limit(sc->health_passthrough_ctx, &rights) == -1) + errx(EX_OSERR, "Unable to apply rights for sandbox"); + if (caph_ioctls_limit(sc->health_passthrough_ctx, cmds, nitems(cmds)) == -1) + errx(EX_OSERR, "Unable to apply rights for sandbox"); +#endif } else if (optidx == 0) { snprintf(bident, sizeof(bident), "%d:%d", sc->nsc_pi->pi_slot, sc->nsc_pi->pi_func);