1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2025 Oxide Computer Company
14 */
15
16 /*
17 * Implements logic to map a device to a vendor-specific entity.
18 */
19
20 #include <libdevinfo.h>
21 #include <sys/sysmacros.h>
22 #include <string.h>
23
24 #include "libnvme_impl.h"
25
26 const nvme_vsd_t *const nvme_vsd_devices[] = {
27 &wdc_sn840,
28 &wdc_sn65x,
29 &wdc_sn861,
30 µn_7300,
31 µn_74x0,
32 µn_x500,
33 µn_9550,
34 &intel_p5510,
35 &solidigm_p5x20,
36 &solidigm_ps10x0,
37 &kioxia_cd8,
38 &phison_x200,
39 &samsung_pm9d3a
40 };
41
42 /*
43 * Our job is to attempt to map a given device to vendor specific information,
44 * if it exists. It may not.
45 */
46 void
nvme_vendor_map_ctrl(nvme_ctrl_t * ctrl)47 nvme_vendor_map_ctrl(nvme_ctrl_t *ctrl)
48 {
49 int *vid, *did, *svidp, *sdidp;
50 uint16_t svid = UINT16_MAX, sdid = UINT16_MAX;
51
52 if (di_prop_lookup_ints(DDI_DEV_T_ANY, ctrl->nc_devi, "vendor-id",
53 &vid) != 1 || di_prop_lookup_ints(DDI_DEV_T_ANY, ctrl->nc_devi,
54 "device-id", &did) != 1) {
55 return;
56 }
57
58 if (di_prop_lookup_ints(DDI_DEV_T_ANY, ctrl->nc_devi,
59 "subsystem-vendor-id", &svidp) == 1) {
60 svid = (uint16_t)*svidp;
61 }
62
63 if (di_prop_lookup_ints(DDI_DEV_T_ANY, ctrl->nc_devi, "subsystem-id",
64 &sdidp) == 1) {
65 sdid = (uint16_t)*sdidp;
66 }
67
68 for (size_t dev = 0; dev < ARRAY_SIZE(nvme_vsd_devices); dev++) {
69 const nvme_vsd_t *vsd = nvme_vsd_devices[dev];
70
71 for (size_t i = 0; i < vsd->nvd_nident; i++) {
72 const nvme_vsd_ident_t *ident = &vsd->nvd_ident[i];
73 if (ident->nvdi_vid != (uint16_t)vid[0] ||
74 ident->nvdi_did != (uint16_t)did[0]) {
75 continue;
76 }
77
78 if (ident->nvdi_subsys && (ident->nvdi_svid != svid ||
79 ident->nvdi_sdid != sdid)) {
80 continue;
81 }
82
83 ctrl->nc_vsd = nvme_vsd_devices[dev];
84 return;
85 }
86 }
87 }
88
89 bool
nvme_vendor_vuc_supported(nvme_ctrl_t * ctrl,const char * name)90 nvme_vendor_vuc_supported(nvme_ctrl_t *ctrl, const char *name)
91 {
92 if (ctrl->nc_vsd != NULL) {
93 for (size_t i = 0; i < ctrl->nc_vsd->nvd_nvuc; i++) {
94 if (strcmp(name, ctrl->nc_vsd->nvd_vuc[i].nvd_short) ==
95 0) {
96 return (true);
97 }
98 }
99 }
100
101 return (nvme_ctrl_error(ctrl, NVME_ERR_VU_FUNC_UNSUP_BY_DEV, 0,
102 "device missing support for vendor unique command %s", name));
103 }
104