Skip to content

Commit 0d5eeb1

Browse files
sndk: Support fabric attached SN861
Since the pci device id is not available in the fabric attached case, other fields in the C2 log page are used to identify the drive. The vs-fw-activate-history and clear-fw-activate-history wdc plugin commands were ported to the sandisk plugin. Update the required libnvme commit to pick up new required function - nvme_get_uuid_list. Signed-off-by: jeff-lien-sndk <[email protected]> Reviewed-by: brandon-paupore-sndk <[email protected]>
1 parent eb12965 commit 0d5eeb1

7 files changed

Lines changed: 939 additions & 30 deletions

File tree

plugins/sandisk/sandisk-nvme.c

Lines changed: 355 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
#include "sandisk-utils.h"
2929
#include "plugins/wdc/wdc-nvme-cmds.h"
3030

31+
static __u8 ocp_C2_guid[SNDK_GUID_LENGTH] = {
32+
0x6D, 0x79, 0x9A, 0x76, 0xB4, 0xDA, 0xF6, 0xA3,
33+
0xE2, 0x4D, 0xB2, 0x8A, 0xAC, 0xF3, 0x1C, 0xD1
34+
};
35+
3136
static int sndk_do_cap_telemetry_log(struct nvme_dev *dev, const char *file,
3237
__u32 bs, int type, int data_area)
3338
{
@@ -494,18 +499,366 @@ static int sndk_drive_resize(int argc, char **argv,
494499
return run_wdc_drive_resize(argc, argv, command, plugin);
495500
}
496501

502+
static void sndk_print_fw_act_history_log_normal(__u8 *data, int num_entries)
503+
{
504+
int i, j;
505+
char previous_fw[9];
506+
char new_fw[9];
507+
char commit_action_bin[8];
508+
char time_str[100];
509+
__u16 oldestEntryIdx = 0, entryIdx = 0;
510+
uint64_t timestamp;
511+
const char *null_fw = "--------";
512+
513+
memset((void *)time_str, '\0', 100);
514+
515+
if (data[0] == SNDK_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
516+
printf(" Firmware Activate History Log\n");
517+
printf(" Power Cycle Previous New\n");
518+
printf(" Entry Timestamp Count Firmware Firmware Slot Action Result\n");
519+
printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n");
520+
521+
struct sndk_fw_act_history_log_format_c2 *fw_act_history_entry = (struct sndk_fw_act_history_log_format_c2 *)(data);
522+
523+
oldestEntryIdx = SNDK_MAX_NUM_ACT_HIST_ENTRIES;
524+
if (num_entries == SNDK_MAX_NUM_ACT_HIST_ENTRIES) {
525+
/* find lowest/oldest entry */
526+
for (i = 0; i < num_entries; i++) {
527+
j = (i+1 == SNDK_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1;
528+
if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) >
529+
le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) {
530+
oldestEntryIdx = j;
531+
break;
532+
}
533+
}
534+
}
535+
if (oldestEntryIdx == SNDK_MAX_NUM_ACT_HIST_ENTRIES)
536+
entryIdx = 0;
537+
else
538+
entryIdx = oldestEntryIdx;
539+
540+
for (i = 0; i < num_entries; i++) {
541+
memset((void *)previous_fw, 0, 9);
542+
memset((void *)new_fw, 0, 9);
543+
memset((void *)commit_action_bin, 0, 8);
544+
545+
memcpy(previous_fw, (char *)&(fw_act_history_entry->entry[entryIdx].previous_fw_version), 8);
546+
if (strlen((char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version)) > 1)
547+
memcpy(new_fw, (char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version), 8);
548+
else
549+
memcpy(new_fw, null_fw, 8);
550+
551+
printf("%5"PRIu16"", (uint16_t)le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries));
552+
553+
timestamp = (0x0000FFFFFFFFFFFF &
554+
le64_to_cpu(
555+
fw_act_history_entry->entry[entryIdx].timestamp));
556+
printf(" ");
557+
printf("%16"PRIu64"", timestamp);
558+
printf(" ");
559+
560+
printf("%16"PRIu64"", (uint64_t)le64_to_cpu(fw_act_history_entry->entry[entryIdx].power_cycle_count));
561+
printf(" ");
562+
printf("%s", (char *)previous_fw);
563+
printf(" ");
564+
printf("%s", (char *)new_fw);
565+
printf(" ");
566+
printf("%2"PRIu8"", (uint8_t)fw_act_history_entry->entry[entryIdx].slot_number);
567+
printf(" ");
568+
sndk_get_commit_action_bin(
569+
fw_act_history_entry->entry[entryIdx].commit_action_type,
570+
(char *)&commit_action_bin);
571+
printf(" %s", (char *)commit_action_bin);
572+
printf(" ");
573+
if (!le16_to_cpu(fw_act_history_entry->entry[entryIdx].result))
574+
printf("pass");
575+
else
576+
printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry->entry[entryIdx].result));
577+
printf("\n");
578+
579+
entryIdx++;
580+
if (entryIdx >= SNDK_MAX_NUM_ACT_HIST_ENTRIES)
581+
entryIdx = 0;
582+
}
583+
} else
584+
fprintf(stderr, "ERROR: SNDK: %s: Unknown log page\n", __func__);
585+
}
586+
587+
static void sndk_print_fw_act_history_log_json(__u8 *data, int num_entries)
588+
{
589+
struct json_object *root = json_create_object();
590+
int i, j;
591+
char previous_fw[9];
592+
char new_fw[9];
593+
char commit_action_bin[8];
594+
char fail_str[32];
595+
char time_str[100];
596+
char ext_time_str[20];
597+
uint64_t timestamp;
598+
599+
memset((void *)previous_fw, 0, 9);
600+
memset((void *)new_fw, 0, 9);
601+
memset((void *)commit_action_bin, 0, 8);
602+
memset((void *)time_str, '\0', 100);
603+
memset((void *)ext_time_str, 0, 20);
604+
memset((void *)fail_str, 0, 11);
605+
char *null_fw = "--------";
606+
__u16 oldestEntryIdx = 0, entryIdx = 0;
607+
608+
if (data[0] == SNDK_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
609+
struct sndk_fw_act_history_log_format_c2 *fw_act_history_entry = (struct sndk_fw_act_history_log_format_c2 *)(data);
610+
611+
oldestEntryIdx = SNDK_MAX_NUM_ACT_HIST_ENTRIES;
612+
if (num_entries == SNDK_MAX_NUM_ACT_HIST_ENTRIES) {
613+
/* find lowest/oldest entry */
614+
for (i = 0; i < num_entries; i++) {
615+
j = (i+1 == SNDK_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1;
616+
if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) >
617+
le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) {
618+
oldestEntryIdx = j;
619+
break;
620+
}
621+
}
622+
}
623+
if (oldestEntryIdx == SNDK_MAX_NUM_ACT_HIST_ENTRIES)
624+
entryIdx = 0;
625+
else
626+
entryIdx = oldestEntryIdx;
627+
628+
for (i = 0; i < num_entries; i++) {
629+
memcpy(previous_fw,
630+
(char *)&(fw_act_history_entry->entry[entryIdx].previous_fw_version),
631+
8);
632+
if (strlen((char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version)) > 1)
633+
memcpy(new_fw,
634+
(char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version),
635+
8);
636+
else
637+
memcpy(new_fw, null_fw, 8);
638+
639+
json_object_add_value_int(root, "Entry",
640+
le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries));
641+
642+
timestamp = (0x0000FFFFFFFFFFFF &
643+
le64_to_cpu(
644+
fw_act_history_entry->entry[entryIdx].timestamp));
645+
json_object_add_value_uint64(root, "Timestamp", timestamp);
646+
647+
json_object_add_value_int(root, "Power Cycle Count",
648+
le64_to_cpu(fw_act_history_entry->entry[entryIdx].power_cycle_count));
649+
json_object_add_value_string(root, "Previous Firmware",
650+
previous_fw);
651+
json_object_add_value_string(root, "New Firmware",
652+
new_fw);
653+
json_object_add_value_int(root, "Slot",
654+
fw_act_history_entry->entry[entryIdx].slot_number);
655+
656+
sndk_get_commit_action_bin(
657+
fw_act_history_entry->entry[entryIdx].commit_action_type,
658+
(char *)&commit_action_bin);
659+
json_object_add_value_string(root, "Action", commit_action_bin);
660+
661+
if (!le16_to_cpu(fw_act_history_entry->entry[entryIdx].result)) {
662+
json_object_add_value_string(root, "Result", "pass");
663+
} else {
664+
sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry->entry[entryIdx].result)));
665+
json_object_add_value_string(root, "Result", fail_str);
666+
}
667+
668+
json_print_object(root, NULL);
669+
printf("\n");
670+
671+
entryIdx++;
672+
if (entryIdx >= SNDK_MAX_NUM_ACT_HIST_ENTRIES)
673+
entryIdx = 0;
674+
}
675+
} else
676+
fprintf(stderr, "ERROR: SNDK: %s: Unknown log page\n", __func__);
677+
678+
json_free_object(root);
679+
}
680+
681+
static int sndk_print_fw_act_history_log(__u8 *data, int num_entries, int fmt)
682+
{
683+
if (!data) {
684+
fprintf(stderr, "ERROR: SNDK: Invalid buffer to read fw activate history entries\n");
685+
return -1;
686+
}
687+
688+
switch (fmt) {
689+
case NORMAL:
690+
sndk_print_fw_act_history_log_normal(data, num_entries);
691+
break;
692+
case JSON:
693+
sndk_print_fw_act_history_log_json(data, num_entries);
694+
break;
695+
}
696+
return 0;
697+
}
698+
699+
static int sndk_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev,
700+
char *format)
701+
{
702+
struct sndk_fw_act_history_log_format_c2 *fw_act_history_log;
703+
__u32 tot_entries = 0, num_entries = 0;
704+
nvme_print_flags_t fmt;
705+
__u8 *data;
706+
int ret;
707+
bool c2GuidMatch = false;
708+
709+
if (!sndk_check_device(r, dev))
710+
return -1;
711+
712+
ret = validate_output_format(format, &fmt);
713+
if (ret < 0) {
714+
fprintf(stderr, "ERROR: SNDK: invalid output format\n");
715+
return ret;
716+
}
717+
718+
data = (__u8 *)malloc(sizeof(__u8) * SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN);
719+
if (!data) {
720+
fprintf(stderr, "ERROR: SNDK: malloc: %s\n", strerror(errno));
721+
return -1;
722+
}
723+
724+
memset(data, 0, sizeof(__u8) * SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN);
725+
726+
ret = nvme_get_log_simple(dev_fd(dev),
727+
SNDK_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID,
728+
SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN, data);
729+
730+
if (strcmp(format, "json"))
731+
nvme_show_status(ret);
732+
733+
if (!ret) {
734+
/* Get the log page data and verify the GUID */
735+
fw_act_history_log = (struct sndk_fw_act_history_log_format_c2 *)(data);
736+
737+
c2GuidMatch = !memcmp(ocp_C2_guid,
738+
fw_act_history_log->log_page_guid,
739+
SNDK_GUID_LENGTH);
740+
741+
if (c2GuidMatch) {
742+
/* parse the data */
743+
tot_entries = le32_to_cpu(fw_act_history_log->num_entries);
744+
745+
if (tot_entries > 0) {
746+
num_entries = (tot_entries < SNDK_MAX_NUM_ACT_HIST_ENTRIES) ?
747+
tot_entries : SNDK_MAX_NUM_ACT_HIST_ENTRIES;
748+
ret = sndk_print_fw_act_history_log(data, num_entries,
749+
fmt);
750+
} else {
751+
fprintf(stderr, "INFO: SNDK: No entries found.\n");
752+
ret = 0;
753+
}
754+
} else {
755+
fprintf(stderr, "ERROR: SNDK: Invalid C2 log page GUID\n");
756+
ret = -1;
757+
}
758+
} else {
759+
fprintf(stderr, "ERROR: SNDK: Unable to read FW Activate History Log Page data\n");
760+
ret = -1;
761+
}
762+
763+
free(data);
764+
return ret;
765+
}
766+
767+
497768
static int sndk_vs_fw_activate_history(int argc, char **argv,
498769
struct command *command,
499770
struct plugin *plugin)
500771
{
501-
return run_wdc_vs_fw_activate_history(argc, argv, command, plugin);
772+
const char *desc = "Retrieve FW activate history table.";
773+
__u64 capabilities = 0;
774+
struct nvme_dev *dev;
775+
nvme_root_t r;
776+
int ret = -1;
777+
778+
struct config {
779+
char *output_format;
780+
};
781+
782+
struct config cfg = {
783+
.output_format = "normal",
784+
};
785+
786+
OPT_ARGS(opts) = {
787+
OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
788+
OPT_END()
789+
};
790+
791+
ret = parse_and_open(&dev, argc, argv, desc, opts);
792+
if (ret)
793+
return ret;
794+
795+
r = nvme_scan(NULL);
796+
capabilities = sndk_get_drive_capabilities(r, dev);
797+
798+
if (capabilities & SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2) {
799+
ret = sndk_get_fw_act_history_C2(r, dev, cfg.output_format);
800+
801+
if (ret)
802+
fprintf(stderr, "ERROR: SNDK: Failure reading the FW "
803+
"Activate History, ret = %d\n", ret);
804+
}
805+
else
806+
/* Fall back to the wdc plugin command */
807+
ret = run_wdc_vs_fw_activate_history(argc, argv, command, plugin);
808+
809+
nvme_free_tree(r);
810+
dev_close(dev);
811+
return ret;
812+
}
813+
814+
static int sndk_do_clear_fw_activate_history_fid(int fd)
815+
{
816+
int ret = -1;
817+
__u32 result;
818+
__u32 value = 1 << 31; /* Bit 31 - Clear Firmware Update History Log */
819+
820+
ret = nvme_set_features_simple(fd, SNDK_NVME_CLEAR_FW_ACT_HIST_VU_FID, 0, value,
821+
false, &result);
822+
823+
nvme_show_status(ret);
824+
return ret;
502825
}
503826

504827
static int sndk_clear_fw_activate_history(int argc, char **argv,
505828
struct command *command,
506829
struct plugin *plugin)
507830
{
508-
return run_wdc_clear_fw_activate_history(argc, argv, command, plugin);
831+
const char *desc = "Clear FW activate history table.";
832+
__u64 capabilities = 0;
833+
struct nvme_dev *dev;
834+
nvme_root_t r;
835+
int ret;
836+
837+
OPT_ARGS(opts) = {
838+
OPT_END()
839+
};
840+
841+
ret = parse_and_open(&dev, argc, argv, desc, opts);
842+
if (ret)
843+
return ret;
844+
845+
r = nvme_scan(NULL);
846+
capabilities = sndk_get_drive_capabilities(r, dev);
847+
848+
if (capabilities & SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY) {
849+
ret = sndk_do_clear_fw_activate_history_fid(dev_fd(dev));
850+
851+
if (ret)
852+
fprintf(stderr, "ERROR: SNDK: Failure clearing the FW "
853+
"Activate History, ret = %d\n", ret);
854+
}
855+
else
856+
/* Fall back to the wdc plugin command */
857+
ret = run_wdc_clear_fw_activate_history(argc, argv, command, plugin);
858+
859+
nvme_free_tree(r);
860+
dev_close(dev);
861+
return ret;
509862
}
510863

511864
static int sndk_vs_telemetry_controller_option(int argc, char **argv,

plugins/sandisk/sandisk-nvme.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#if !defined(SANDISK_NVME) || defined(CMD_HEADER_MULTI_READ)
66
#define SANDISK_NVME
77

8-
#define SANDISK_PLUGIN_VERSION "3.0.4"
8+
#define SANDISK_PLUGIN_VERSION "3.0.6"
99
#include "cmd.h"
1010

1111
PLUGIN(NAME("sndk", "Sandisk vendor specific extensions", SANDISK_PLUGIN_VERSION),

0 commit comments

Comments
 (0)