#include <sys/sysmacros.h>
#include <sys/nvme/wdc.h>
#include "libnvme_impl.h"
static const uint32_t nvme_sndk_timeout = 20;
static const nvme_vsd_ident_t sandisk_sn861_idents[] = {
{
.nvdi_vid = WDC_PCI_VID,
.nvdi_did = WDC_SN861_DID_U2,
.nvdi_human = "SanDisk DC SN861 U.2",
}, {
.nvdi_vid = WDC_PCI_VID,
.nvdi_did = WDC_SN861_DID_E3,
.nvdi_human = "SanDisk DC SN861 E3.S",
}, {
.nvdi_vid = WDC_PCI_VID,
.nvdi_did = WDC_SN861_DID_E1,
.nvdi_human = "SanDisk DC SN861 E1.S",
}
};
static const nvme_log_page_info_t *sandisk_sn861_log_pages[] = {
&ocp_log_smart, &ocp_log_errrec, &ocp_log_fwact, &ocp_log_lat,
&ocp_log_devcap, &ocp_log_unsup
};
static const nvme_vuc_disc_t sndk_sn861_vuc[] = { {
.nvd_short = "sandisk/pci-eye",
.nvd_desc = "per-lane PCI eye diagram",
.nvd_opc = WDC_SN861_VUC_EYE_OPC,
.nvd_dt = NVME_VUC_DISC_IO_OUTPUT,
.nvd_lock = NVME_VUC_DISC_LOCK_NONE
}, {
.nvd_short = "sandisk/hwrev",
.nvd_desc = "print hardware revision",
.nvd_opc = WDC_SN861_VUC_HWREV_OPC,
.nvd_dt = NVME_VUC_DISC_IO_OUTPUT,
.nvd_lock = NVME_VUC_DISC_LOCK_NONE
} };
const nvme_vsd_t sandisk_sn861 = {
.nvd_ident = sandisk_sn861_idents,
.nvd_nident = ARRAY_SIZE(sandisk_sn861_idents),
.nvd_logs = sandisk_sn861_log_pages,
.nvd_nlogs = ARRAY_SIZE(sandisk_sn861_log_pages),
.nvd_vuc = sndk_sn861_vuc,
.nvd_nvuc = ARRAY_SIZE(sndk_sn861_vuc)
};
bool
nvme_sndk_pci_eye(nvme_ctrl_t *ctrl, uint8_t lane, void *buf, size_t len)
{
nvme_vuc_req_t *req = NULL;
if (buf == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid eye diagram buffer output pointer: %p",
buf));
}
if (len < WDC_SN861_VUC_EYE_LEN) {
return (nvme_ctrl_error(ctrl, NVME_ERR_PCIE_EYE_BUF_RANGE, 0,
"eye diagram buffer output size is too small: found 0x%zx "
"bytes, but need at least 0x%x", len,
WDC_SN861_VUC_EYE_LEN));
}
if (lane >= 4) {
return (nvme_ctrl_error(ctrl, NVME_ERR_PCIE_LANE_RANGE, 0,
"invalid PCIe lane %u: must be between 0-3", lane));
}
if (!nvme_vendor_vuc_supported(ctrl, "sandisk/pci-eye")) {
return (false);
}
if (!nvme_vuc_req_init(ctrl, &req)) {
return (false);
}
if (!nvme_vuc_req_set_opcode(req, WDC_SN861_VUC_EYE_OPC) ||
!nvme_vuc_req_set_cdw12(req, WDC_SN861_VUC_EYE_CDW12) ||
!nvme_vuc_req_set_cdw13(req, lane) ||
!nvme_vuc_req_set_timeout(req, nvme_sndk_timeout) ||
!nvme_vuc_req_set_output(req, buf, len) ||
!nvme_vuc_req_exec(req)) {
nvme_vuc_req_fini(req);
return (false);
}
nvme_vuc_req_fini(req);
return (nvme_ctrl_success(ctrl));
}
bool
nvme_sndk_hw_rev(nvme_ctrl_t *ctrl, uint8_t *majorp, uint8_t *minorp)
{
uint32_t vers;
nvme_vuc_req_t *req = NULL;
if (majorp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid major number output pointer: %p",
majorp));
}
if (minorp == NULL) {
return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
"encountered invalid minor number output pointer: %p",
majorp));
}
if (!nvme_vendor_vuc_supported(ctrl, "sandisk/hwrev")) {
return (false);
}
if (!nvme_vuc_req_init(ctrl, &req)) {
return (false);
}
if (!nvme_vuc_req_set_opcode(req, WDC_SN861_VUC_HWREV_OPC) ||
!nvme_vuc_req_set_cdw12(req, WDC_SN861_VUC_HWREV_CDW12) ||
!nvme_vuc_req_set_timeout(req, nvme_sndk_timeout) ||
!nvme_vuc_req_set_output(req, &vers, sizeof (vers)) ||
!nvme_vuc_req_exec(req)) {
nvme_vuc_req_fini(req);
return (false);
}
nvme_vuc_req_fini(req);
if (vers > 100) {
return (nvme_ctrl_error(ctrl, NVME_ERR_INTERNAL, 0, "returned "
"version is in an unexpected format and cannot be parsed "
"into its major and minor number: 0x%x", vers));
}
*minorp = vers % 10;
*majorp = (vers / 10) % 10;
return (nvme_ctrl_success(ctrl));
}