xref: /illumos-gate/usr/src/lib/libnvme/common/libnvme_vendor.c (revision 9bfeae155b3e1a3e699b678dba5e3b7f2223eca1)
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 	&micron_7300,
31 	&micron_74x0,
32 	&micron_x500,
33 	&micron_9550,
34 	&intel_p5510,
35 	&solidigm_p5x20,
36 	&solidigm_ps10x0,
37 	&kioxia_cd8,
38 	&phison_x200
39 };
40 
41 /*
42  * Our job is to attempt to map a given device to vendor specific information,
43  * if it exists. It may not.
44  */
45 void
46 nvme_vendor_map_ctrl(nvme_ctrl_t *ctrl)
47 {
48 	int *vid, *did, *svidp, *sdidp;
49 	uint16_t svid = UINT16_MAX, sdid = UINT16_MAX;
50 
51 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, ctrl->nc_devi, "vendor-id",
52 	    &vid) != 1 || di_prop_lookup_ints(DDI_DEV_T_ANY, ctrl->nc_devi,
53 	    "device-id", &did) != 1) {
54 		return;
55 	}
56 
57 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, ctrl->nc_devi,
58 	    "subsystem-vendor-id", &svidp) == 1) {
59 		svid = (uint16_t)*svidp;
60 	}
61 
62 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, ctrl->nc_devi, "subsystem-id",
63 	    &sdidp) == 1) {
64 		sdid = (uint16_t)*sdidp;
65 	}
66 
67 	for (size_t dev = 0; dev < ARRAY_SIZE(nvme_vsd_devices); dev++) {
68 		const nvme_vsd_t *vsd = nvme_vsd_devices[dev];
69 
70 		for (size_t i = 0; i < vsd->nvd_nident; i++) {
71 			const nvme_vsd_ident_t *ident = &vsd->nvd_ident[i];
72 			if (ident->nvdi_vid != (uint16_t)vid[0] ||
73 			    ident->nvdi_did != (uint16_t)did[0]) {
74 				continue;
75 			}
76 
77 			if (ident->nvdi_subsys && (ident->nvdi_svid != svid ||
78 			    ident->nvdi_sdid != sdid)) {
79 				continue;
80 			}
81 
82 			ctrl->nc_vsd = nvme_vsd_devices[dev];
83 			return;
84 		}
85 	}
86 }
87 
88 bool
89 nvme_vendor_vuc_supported(nvme_ctrl_t *ctrl, const char *name)
90 {
91 	if (ctrl->nc_vsd != NULL) {
92 		for (size_t i = 0; i < ctrl->nc_vsd->nvd_nvuc; i++) {
93 			if (strcmp(name, ctrl->nc_vsd->nvd_vuc[i].nvd_short) ==
94 			    0) {
95 				return (true);
96 			}
97 		}
98 	}
99 
100 	return (nvme_ctrl_error(ctrl, NVME_ERR_VU_FUNC_UNSUP_BY_DEV, 0,
101 	    "device missing support for vendor unique command %s", name));
102 }
103