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