#include <stdio.h>
#include <err.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/debug.h>
#include <sys/sysmacros.h>
#include <sys/nvme/wdc.h>
#include "nvmeadm.h"
typedef struct {
uint8_t se_lane;
const char *se_output;
} sandisk_eye_t;
void
usage_sandisk_hwrev(const char *c_name)
{
(void) fprintf(stderr, "%s <ctl>\n\n"
" Print device hardware revision\n", c_name);
}
int
do_sandisk_hwrev(const nvme_process_arg_t *npa)
{
uint8_t major, minor;
nvme_vuc_disc_t *vuc;
if (npa->npa_argc > 0) {
errx(-1, "%s passed extraneous arguments starting with %s",
npa->npa_cmd->c_name, npa->npa_argv[0]);
}
vuc = nvmeadm_vuc_init(npa, npa->npa_cmd->c_name);
if (!nvme_sndk_hw_rev(npa->npa_ctrl, &major, &minor)) {
nvmeadm_fatal(npa, "failed to retrieve hardware revision");
}
(void) printf("%u.%u\n", major, minor);
nvmeadm_vuc_fini(npa, vuc);
return (0);
}
void
usage_sandisk_pcieye(const char *c_name)
{
(void) fprintf(stderr, "%s -l lane -o output <ctl>\n\n"
" Write PCIe eye data from the specified lane to output file.\n",
c_name);
}
void
optparse_sandisk_pcieye(nvme_process_arg_t *npa)
{
int c;
sandisk_eye_t *eye;
if ((eye = calloc(1, sizeof (sandisk_eye_t))) == NULL) {
err(-1, "failed to allocate memory for pci-eye options "
"structure");
}
eye->se_lane = UINT8_MAX;
while ((c = getopt(npa->npa_argc, npa->npa_argv, ":l:o:")) != -1) {
const char *errstr;
switch (c) {
case 'l':
eye->se_lane = (uint8_t)strtonumx(optarg, 0, 3, &errstr,
0);
if (errstr != NULL) {
errx(-1, "invalid lane specified, valid values "
"are 0-3: %s is %s", optarg, errstr);
}
break;
case 'o':
eye->se_output = optarg;
break;
case '?':
errx(-1, "unknown option: -%c", optopt);
case ':':
errx(-1, "option -%c requires an argument", optopt);
}
}
if (eye->se_lane == UINT8_MAX) {
errx(-1, "missing required PCIe lane (0-3), specify with -l");
}
if (eye->se_output == NULL) {
errx(-1, "missing required output file, specify with -o");
}
npa->npa_cmd_arg = eye;
}
int
do_sandisk_pcieye(const nvme_process_arg_t *npa)
{
const sandisk_eye_t *eye = npa->npa_cmd_arg;
nvme_vuc_disc_t *vuc;
uint8_t *buf;
int ofd;
if ((buf = calloc(WDC_SN861_VUC_EYE_LEN, sizeof (uint8_t))) == NULL) {
err(-1, "failed to allocate eye diagram buffer");
}
vuc = nvmeadm_vuc_init(npa, npa->npa_cmd->c_name);
ofd = open(eye->se_output, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (ofd < 0) {
err(-1, "failed to open output file %s", eye->se_output);
}
if (!nvme_sndk_pci_eye(npa->npa_ctrl, eye->se_lane, buf,
WDC_SN861_VUC_EYE_LEN)) {
nvmeadm_fatal(npa, "failed to retrieve PCIe eye information");
}
size_t off = 0, len = WDC_SN861_VUC_EYE_LEN;
while (len > 0) {
size_t towrite = MIN(len, 32 * 1024);
ssize_t ret = write(ofd, buf + off, towrite);
if (ret < 0) {
err(-1, "failed to write eye data to output file");
}
off += (size_t)ret;
len -= (size_t)ret;
}
nvmeadm_vuc_fini(npa, vuc);
VERIFY0(close(ofd));
free(buf);
return (0);
}