xref: /illumos-gate/usr/src/cmd/nvmeadm/nvmeadm_sandisk.c (revision fe5224a3e61e4d791ea239810e79697fc96f7b16)
1*fe5224a3SRobert Mustacchi /*
2*fe5224a3SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*fe5224a3SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*fe5224a3SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*fe5224a3SRobert Mustacchi  * 1.0 of the CDDL.
6*fe5224a3SRobert Mustacchi  *
7*fe5224a3SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*fe5224a3SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*fe5224a3SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*fe5224a3SRobert Mustacchi  */
11*fe5224a3SRobert Mustacchi 
12*fe5224a3SRobert Mustacchi /*
13*fe5224a3SRobert Mustacchi  * Copyright 2026 Oxide Computer Company
14*fe5224a3SRobert Mustacchi  */
15*fe5224a3SRobert Mustacchi 
16*fe5224a3SRobert Mustacchi /*
17*fe5224a3SRobert Mustacchi  * Sandisk vendor-specific commands. These generally start with the x6x
18*fe5224a3SRobert Mustacchi  * generation of controllers. For prior generations (e.g. x4x and x5x), see
19*fe5224a3SRobert Mustacchi  * nvmeadm_wdc.c.
20*fe5224a3SRobert Mustacchi  */
21*fe5224a3SRobert Mustacchi 
22*fe5224a3SRobert Mustacchi #include <stdio.h>
23*fe5224a3SRobert Mustacchi #include <err.h>
24*fe5224a3SRobert Mustacchi #include <stdlib.h>
25*fe5224a3SRobert Mustacchi #include <sys/stat.h>
26*fe5224a3SRobert Mustacchi #include <fcntl.h>
27*fe5224a3SRobert Mustacchi #include <unistd.h>
28*fe5224a3SRobert Mustacchi #include <sys/debug.h>
29*fe5224a3SRobert Mustacchi #include <sys/sysmacros.h>
30*fe5224a3SRobert Mustacchi #include <sys/nvme/wdc.h>
31*fe5224a3SRobert Mustacchi 
32*fe5224a3SRobert Mustacchi #include "nvmeadm.h"
33*fe5224a3SRobert Mustacchi 
34*fe5224a3SRobert Mustacchi typedef struct {
35*fe5224a3SRobert Mustacchi 	uint8_t se_lane;
36*fe5224a3SRobert Mustacchi 	const char *se_output;
37*fe5224a3SRobert Mustacchi } sandisk_eye_t;
38*fe5224a3SRobert Mustacchi 
39*fe5224a3SRobert Mustacchi void
usage_sandisk_hwrev(const char * c_name)40*fe5224a3SRobert Mustacchi usage_sandisk_hwrev(const char *c_name)
41*fe5224a3SRobert Mustacchi {
42*fe5224a3SRobert Mustacchi 	(void) fprintf(stderr, "%s <ctl>\n\n"
43*fe5224a3SRobert Mustacchi 	    "  Print device hardware revision\n", c_name);
44*fe5224a3SRobert Mustacchi }
45*fe5224a3SRobert Mustacchi 
46*fe5224a3SRobert Mustacchi int
do_sandisk_hwrev(const nvme_process_arg_t * npa)47*fe5224a3SRobert Mustacchi do_sandisk_hwrev(const nvme_process_arg_t *npa)
48*fe5224a3SRobert Mustacchi {
49*fe5224a3SRobert Mustacchi 	uint8_t major, minor;
50*fe5224a3SRobert Mustacchi 	nvme_vuc_disc_t *vuc;
51*fe5224a3SRobert Mustacchi 
52*fe5224a3SRobert Mustacchi 	if (npa->npa_argc > 0) {
53*fe5224a3SRobert Mustacchi 		errx(-1, "%s passed extraneous arguments starting with %s",
54*fe5224a3SRobert Mustacchi 		    npa->npa_cmd->c_name, npa->npa_argv[0]);
55*fe5224a3SRobert Mustacchi 	}
56*fe5224a3SRobert Mustacchi 
57*fe5224a3SRobert Mustacchi 	vuc = nvmeadm_vuc_init(npa, npa->npa_cmd->c_name);
58*fe5224a3SRobert Mustacchi 	if (!nvme_sndk_hw_rev(npa->npa_ctrl, &major, &minor)) {
59*fe5224a3SRobert Mustacchi 		nvmeadm_fatal(npa, "failed to retrieve hardware revision");
60*fe5224a3SRobert Mustacchi 	}
61*fe5224a3SRobert Mustacchi 
62*fe5224a3SRobert Mustacchi 	(void) printf("%u.%u\n", major, minor);
63*fe5224a3SRobert Mustacchi 	nvmeadm_vuc_fini(npa, vuc);
64*fe5224a3SRobert Mustacchi 	return (0);
65*fe5224a3SRobert Mustacchi }
66*fe5224a3SRobert Mustacchi 
67*fe5224a3SRobert Mustacchi void
usage_sandisk_pcieye(const char * c_name)68*fe5224a3SRobert Mustacchi usage_sandisk_pcieye(const char *c_name)
69*fe5224a3SRobert Mustacchi {
70*fe5224a3SRobert Mustacchi 	(void) fprintf(stderr, "%s -l lane -o output <ctl>\n\n"
71*fe5224a3SRobert Mustacchi 	    "  Write PCIe eye data from the specified lane to output file.\n",
72*fe5224a3SRobert Mustacchi 	    c_name);
73*fe5224a3SRobert Mustacchi }
74*fe5224a3SRobert Mustacchi 
75*fe5224a3SRobert Mustacchi void
optparse_sandisk_pcieye(nvme_process_arg_t * npa)76*fe5224a3SRobert Mustacchi optparse_sandisk_pcieye(nvme_process_arg_t *npa)
77*fe5224a3SRobert Mustacchi {
78*fe5224a3SRobert Mustacchi 	int c;
79*fe5224a3SRobert Mustacchi 	sandisk_eye_t *eye;
80*fe5224a3SRobert Mustacchi 
81*fe5224a3SRobert Mustacchi 	if ((eye = calloc(1, sizeof (sandisk_eye_t))) == NULL) {
82*fe5224a3SRobert Mustacchi 		err(-1, "failed to allocate memory for pci-eye options "
83*fe5224a3SRobert Mustacchi 		    "structure");
84*fe5224a3SRobert Mustacchi 	}
85*fe5224a3SRobert Mustacchi 
86*fe5224a3SRobert Mustacchi 	eye->se_lane = UINT8_MAX;
87*fe5224a3SRobert Mustacchi 	while ((c = getopt(npa->npa_argc, npa->npa_argv, ":l:o:")) != -1) {
88*fe5224a3SRobert Mustacchi 		const char *errstr;
89*fe5224a3SRobert Mustacchi 
90*fe5224a3SRobert Mustacchi 		switch (c) {
91*fe5224a3SRobert Mustacchi 		case 'l':
92*fe5224a3SRobert Mustacchi 			eye->se_lane = (uint8_t)strtonumx(optarg, 0, 3, &errstr,
93*fe5224a3SRobert Mustacchi 			    0);
94*fe5224a3SRobert Mustacchi 			if (errstr != NULL) {
95*fe5224a3SRobert Mustacchi 				errx(-1, "invalid lane specified, valid values "
96*fe5224a3SRobert Mustacchi 				    "are 0-3: %s is %s", optarg, errstr);
97*fe5224a3SRobert Mustacchi 			}
98*fe5224a3SRobert Mustacchi 			break;
99*fe5224a3SRobert Mustacchi 		case 'o':
100*fe5224a3SRobert Mustacchi 			eye->se_output = optarg;
101*fe5224a3SRobert Mustacchi 			break;
102*fe5224a3SRobert Mustacchi 		case '?':
103*fe5224a3SRobert Mustacchi 			errx(-1, "unknown option: -%c", optopt);
104*fe5224a3SRobert Mustacchi 		case ':':
105*fe5224a3SRobert Mustacchi 			errx(-1, "option -%c requires an argument", optopt);
106*fe5224a3SRobert Mustacchi 		}
107*fe5224a3SRobert Mustacchi 	}
108*fe5224a3SRobert Mustacchi 
109*fe5224a3SRobert Mustacchi 	if (eye->se_lane == UINT8_MAX) {
110*fe5224a3SRobert Mustacchi 		errx(-1, "missing required PCIe lane (0-3), specify with -l");
111*fe5224a3SRobert Mustacchi 	}
112*fe5224a3SRobert Mustacchi 
113*fe5224a3SRobert Mustacchi 	if (eye->se_output == NULL) {
114*fe5224a3SRobert Mustacchi 		errx(-1, "missing required output file, specify with -o");
115*fe5224a3SRobert Mustacchi 	}
116*fe5224a3SRobert Mustacchi 
117*fe5224a3SRobert Mustacchi 	npa->npa_cmd_arg = eye;
118*fe5224a3SRobert Mustacchi }
119*fe5224a3SRobert Mustacchi 
120*fe5224a3SRobert Mustacchi int
do_sandisk_pcieye(const nvme_process_arg_t * npa)121*fe5224a3SRobert Mustacchi do_sandisk_pcieye(const nvme_process_arg_t *npa)
122*fe5224a3SRobert Mustacchi {
123*fe5224a3SRobert Mustacchi 	const sandisk_eye_t *eye = npa->npa_cmd_arg;
124*fe5224a3SRobert Mustacchi 	nvme_vuc_disc_t *vuc;
125*fe5224a3SRobert Mustacchi 	uint8_t *buf;
126*fe5224a3SRobert Mustacchi 	int ofd;
127*fe5224a3SRobert Mustacchi 
128*fe5224a3SRobert Mustacchi 	if ((buf = calloc(WDC_SN861_VUC_EYE_LEN, sizeof (uint8_t))) == NULL) {
129*fe5224a3SRobert Mustacchi 		err(-1, "failed to allocate eye diagram buffer");
130*fe5224a3SRobert Mustacchi 	}
131*fe5224a3SRobert Mustacchi 
132*fe5224a3SRobert Mustacchi 	vuc = nvmeadm_vuc_init(npa, npa->npa_cmd->c_name);
133*fe5224a3SRobert Mustacchi 
134*fe5224a3SRobert Mustacchi 	ofd = open(eye->se_output, O_WRONLY | O_CREAT | O_TRUNC, 0644);
135*fe5224a3SRobert Mustacchi 	if (ofd < 0) {
136*fe5224a3SRobert Mustacchi 		err(-1, "failed to open output file %s", eye->se_output);
137*fe5224a3SRobert Mustacchi 	}
138*fe5224a3SRobert Mustacchi 
139*fe5224a3SRobert Mustacchi 	if (!nvme_sndk_pci_eye(npa->npa_ctrl, eye->se_lane, buf,
140*fe5224a3SRobert Mustacchi 	    WDC_SN861_VUC_EYE_LEN)) {
141*fe5224a3SRobert Mustacchi 		nvmeadm_fatal(npa, "failed to retrieve PCIe eye information");
142*fe5224a3SRobert Mustacchi 	}
143*fe5224a3SRobert Mustacchi 
144*fe5224a3SRobert Mustacchi 	size_t off = 0, len = WDC_SN861_VUC_EYE_LEN;
145*fe5224a3SRobert Mustacchi 	while (len > 0) {
146*fe5224a3SRobert Mustacchi 		size_t towrite = MIN(len, 32 * 1024);
147*fe5224a3SRobert Mustacchi 		ssize_t ret = write(ofd, buf + off, towrite);
148*fe5224a3SRobert Mustacchi 		if (ret < 0) {
149*fe5224a3SRobert Mustacchi 			err(-1, "failed to write eye data to output file");
150*fe5224a3SRobert Mustacchi 		}
151*fe5224a3SRobert Mustacchi 
152*fe5224a3SRobert Mustacchi 		off += (size_t)ret;
153*fe5224a3SRobert Mustacchi 		len -= (size_t)ret;
154*fe5224a3SRobert Mustacchi 	}
155*fe5224a3SRobert Mustacchi 
156*fe5224a3SRobert Mustacchi 	nvmeadm_vuc_fini(npa, vuc);
157*fe5224a3SRobert Mustacchi 	VERIFY0(close(ofd));
158*fe5224a3SRobert Mustacchi 	free(buf);
159*fe5224a3SRobert Mustacchi 	return (0);
160*fe5224a3SRobert Mustacchi }
161