Skip to content

Commit 632ebb7

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 9aef347 commit 632ebb7

7 files changed

Lines changed: 936 additions & 27 deletions

File tree

plugins/sandisk/sandisk-nvme.c

Lines changed: 373 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
{
@@ -571,18 +576,384 @@ static int sndk_drive_resize(int argc, char **argv,
571576
return ret;
572577
}
573578

579+
static void sndk_print_fw_act_history_log_normal(__u8 *data, int num_entries)
580+
{
581+
int i, j;
582+
char previous_fw[9];
583+
char new_fw[9];
584+
char commit_action_bin[8];
585+
char time_str[100];
586+
__u16 oldestEntryIdx = 0, entryIdx = 0;
587+
uint64_t timestamp;
588+
int fw_vers_len = 0;
589+
const char *null_fw = "--------";
590+
591+
memset((void *)time_str, '\0', 100);
592+
593+
if (data[0] == SNDK_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
594+
printf(" Firmware Activate History Log\n");
595+
printf(" Power Cycle Previous New\n");
596+
printf(" Entry Timestamp Count Firmware Firmware Slot Action Result\n");
597+
printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n");
598+
599+
struct sndk_fw_act_history_log_format_c2 *fw_act_history_entry =
600+
(struct sndk_fw_act_history_log_format_c2 *)(data);
601+
602+
oldestEntryIdx = SNDK_MAX_NUM_ACT_HIST_ENTRIES;
603+
if (num_entries == SNDK_MAX_NUM_ACT_HIST_ENTRIES) {
604+
/* find lowest/oldest entry */
605+
for (i = 0; i < num_entries; i++) {
606+
j = (i+1 == SNDK_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1;
607+
if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) >
608+
le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) {
609+
oldestEntryIdx = j;
610+
break;
611+
}
612+
}
613+
}
614+
if (oldestEntryIdx == SNDK_MAX_NUM_ACT_HIST_ENTRIES)
615+
entryIdx = 0;
616+
else
617+
entryIdx = oldestEntryIdx;
618+
619+
for (i = 0; i < num_entries; i++) {
620+
memset((void *)previous_fw, 0, 9);
621+
memset((void *)new_fw, 0, 9);
622+
memset((void *)commit_action_bin, 0, 8);
623+
624+
memcpy(previous_fw,
625+
(char *)&(fw_act_history_entry->entry[entryIdx].previous_fw_version),
626+
8);
627+
fw_vers_len = strlen((char *)
628+
&(fw_act_history_entry->entry[entryIdx].current_fw_version));
629+
if (fw_vers_len > 1)
630+
memcpy(new_fw,
631+
(char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version),
632+
8);
633+
else
634+
memcpy(new_fw, null_fw, 8);
635+
636+
printf("%5"PRIu16"",
637+
(uint16_t)le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries));
638+
639+
timestamp = (0x0000FFFFFFFFFFFF &
640+
le64_to_cpu(
641+
fw_act_history_entry->entry[entryIdx].timestamp));
642+
printf(" ");
643+
printf("%16"PRIu64"", timestamp);
644+
printf(" ");
645+
646+
printf("%16"PRIu64"",
647+
(uint64_t)le64_to_cpu(fw_act_history_entry->entry[entryIdx].power_cycle_count));
648+
printf(" ");
649+
printf("%s", (char *)previous_fw);
650+
printf(" ");
651+
printf("%s", (char *)new_fw);
652+
printf(" ");
653+
printf("%2"PRIu8"",
654+
(uint8_t)fw_act_history_entry->entry[entryIdx].slot_number);
655+
printf(" ");
656+
sndk_get_commit_action_bin(
657+
fw_act_history_entry->entry[entryIdx].commit_action_type,
658+
(char *)&commit_action_bin);
659+
printf(" %s", (char *)commit_action_bin);
660+
printf(" ");
661+
if (!le16_to_cpu(fw_act_history_entry->entry[entryIdx].result))
662+
printf("pass");
663+
else
664+
printf("fail #%d",
665+
(uint16_t)le16_to_cpu(fw_act_history_entry->entry[entryIdx].result));
666+
printf("\n");
667+
668+
entryIdx++;
669+
if (entryIdx >= SNDK_MAX_NUM_ACT_HIST_ENTRIES)
670+
entryIdx = 0;
671+
}
672+
} else
673+
fprintf(stderr, "ERROR: SNDK: %s: Unknown log page\n", __func__);
674+
}
675+
676+
static void sndk_print_fw_act_history_log_json(__u8 *data, int num_entries)
677+
{
678+
struct json_object *root = json_create_object();
679+
int i, j;
680+
char previous_fw[9];
681+
char new_fw[9];
682+
char commit_action_bin[8];
683+
char fail_str[32];
684+
char time_str[100];
685+
char ext_time_str[20];
686+
uint64_t timestamp;
687+
int fw_vers_len = 0;
688+
689+
memset((void *)previous_fw, 0, 9);
690+
memset((void *)new_fw, 0, 9);
691+
memset((void *)commit_action_bin, 0, 8);
692+
memset((void *)time_str, '\0', 100);
693+
memset((void *)ext_time_str, 0, 20);
694+
memset((void *)fail_str, 0, 11);
695+
char *null_fw = "--------";
696+
__u16 oldestEntryIdx = 0, entryIdx = 0;
697+
698+
if (data[0] == SNDK_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
699+
struct sndk_fw_act_history_log_format_c2 *fw_act_history_entry =
700+
(struct sndk_fw_act_history_log_format_c2 *)(data);
701+
702+
oldestEntryIdx = SNDK_MAX_NUM_ACT_HIST_ENTRIES;
703+
if (num_entries == SNDK_MAX_NUM_ACT_HIST_ENTRIES) {
704+
/* find lowest/oldest entry */
705+
for (i = 0; i < num_entries; i++) {
706+
j = (i+1 == SNDK_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1;
707+
if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) >
708+
le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) {
709+
oldestEntryIdx = j;
710+
break;
711+
}
712+
}
713+
}
714+
if (oldestEntryIdx == SNDK_MAX_NUM_ACT_HIST_ENTRIES)
715+
entryIdx = 0;
716+
else
717+
entryIdx = oldestEntryIdx;
718+
719+
for (i = 0; i < num_entries; i++) {
720+
memcpy(previous_fw,
721+
(char *)&(fw_act_history_entry->entry[entryIdx].previous_fw_version),
722+
8);
723+
fw_vers_len = strlen((char *)
724+
&(fw_act_history_entry->entry[entryIdx].current_fw_version));
725+
if (fw_vers_len > 1)
726+
memcpy(new_fw,
727+
(char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version),
728+
8);
729+
else
730+
memcpy(new_fw, null_fw, 8);
731+
732+
json_object_add_value_int(root, "Entry",
733+
le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries));
734+
735+
timestamp = (0x0000FFFFFFFFFFFF &
736+
le64_to_cpu(
737+
fw_act_history_entry->entry[entryIdx].timestamp));
738+
json_object_add_value_uint64(root, "Timestamp", timestamp);
739+
740+
json_object_add_value_int(root, "Power Cycle Count",
741+
le64_to_cpu(
742+
fw_act_history_entry->entry[entryIdx].power_cycle_count));
743+
json_object_add_value_string(root, "Previous Firmware",
744+
previous_fw);
745+
json_object_add_value_string(root, "New Firmware",
746+
new_fw);
747+
json_object_add_value_int(root, "Slot",
748+
fw_act_history_entry->entry[entryIdx].slot_number);
749+
750+
sndk_get_commit_action_bin(
751+
fw_act_history_entry->entry[entryIdx].commit_action_type,
752+
(char *)&commit_action_bin);
753+
json_object_add_value_string(root, "Action", commit_action_bin);
754+
755+
if (!le16_to_cpu(fw_act_history_entry->entry[entryIdx].result)) {
756+
json_object_add_value_string(root, "Result", "pass");
757+
} else {
758+
sprintf((char *)fail_str, "fail #%d",
759+
(int)(le16_to_cpu(fw_act_history_entry->entry[entryIdx].result)));
760+
json_object_add_value_string(root, "Result", fail_str);
761+
}
762+
763+
json_print_object(root, NULL);
764+
printf("\n");
765+
766+
entryIdx++;
767+
if (entryIdx >= SNDK_MAX_NUM_ACT_HIST_ENTRIES)
768+
entryIdx = 0;
769+
}
770+
} else
771+
fprintf(stderr, "ERROR: SNDK: %s: Unknown log page\n", __func__);
772+
773+
json_free_object(root);
774+
}
775+
776+
static int sndk_print_fw_act_history_log(__u8 *data, int num_entries, int fmt)
777+
{
778+
if (!data) {
779+
fprintf(stderr, "ERROR: SNDK: Invalid buffer in print_fw act_history_log\n");
780+
return -1;
781+
}
782+
783+
switch (fmt) {
784+
case NORMAL:
785+
sndk_print_fw_act_history_log_normal(data, num_entries);
786+
break;
787+
case JSON:
788+
sndk_print_fw_act_history_log_json(data, num_entries);
789+
break;
790+
}
791+
return 0;
792+
}
793+
794+
static int sndk_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev,
795+
char *format)
796+
{
797+
struct sndk_fw_act_history_log_format_c2 *fw_act_history_log;
798+
__u32 tot_entries = 0, num_entries = 0;
799+
nvme_print_flags_t fmt;
800+
__u8 *data;
801+
int ret;
802+
bool c2GuidMatch = false;
803+
804+
if (!sndk_check_device(r, dev))
805+
return -1;
806+
807+
ret = validate_output_format(format, &fmt);
808+
if (ret < 0) {
809+
fprintf(stderr, "ERROR: SNDK: invalid output format\n");
810+
return ret;
811+
}
812+
813+
data = (__u8 *)malloc(sizeof(__u8) * SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN);
814+
if (!data) {
815+
fprintf(stderr, "ERROR: SNDK: malloc: %s\n", strerror(errno));
816+
return -1;
817+
}
818+
819+
memset(data, 0, sizeof(__u8) * SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN);
820+
821+
ret = nvme_get_log_simple(dev_fd(dev),
822+
SNDK_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID,
823+
SNDK_FW_ACT_HISTORY_C2_LOG_BUF_LEN, data);
824+
825+
if (strcmp(format, "json"))
826+
nvme_show_status(ret);
827+
828+
if (!ret) {
829+
/* Get the log page data and verify the GUID */
830+
fw_act_history_log = (struct sndk_fw_act_history_log_format_c2 *)(data);
831+
832+
c2GuidMatch = !memcmp(ocp_C2_guid,
833+
fw_act_history_log->log_page_guid,
834+
SNDK_GUID_LENGTH);
835+
836+
if (c2GuidMatch) {
837+
/* parse the data */
838+
tot_entries = le32_to_cpu(fw_act_history_log->num_entries);
839+
840+
if (tot_entries > 0) {
841+
num_entries = (tot_entries < SNDK_MAX_NUM_ACT_HIST_ENTRIES) ?
842+
tot_entries : SNDK_MAX_NUM_ACT_HIST_ENTRIES;
843+
ret = sndk_print_fw_act_history_log(data, num_entries,
844+
fmt);
845+
} else {
846+
fprintf(stderr, "INFO: SNDK: No entries found.\n");
847+
ret = 0;
848+
}
849+
} else {
850+
fprintf(stderr, "ERROR: SNDK: Invalid C2 log page GUID\n");
851+
ret = -1;
852+
}
853+
} else {
854+
fprintf(stderr, "ERROR: SNDK: Unable to read FW Activate History Log Page data\n");
855+
ret = -1;
856+
}
857+
858+
free(data);
859+
return ret;
860+
}
861+
862+
574863
static int sndk_vs_fw_activate_history(int argc, char **argv,
575864
struct command *command,
576865
struct plugin *plugin)
577866
{
578-
return run_wdc_vs_fw_activate_history(argc, argv, command, plugin);
867+
const char *desc = "Retrieve FW activate history table.";
868+
__u64 capabilities = 0;
869+
struct nvme_dev *dev;
870+
nvme_root_t r;
871+
int ret = -1;
872+
873+
struct config {
874+
char *output_format;
875+
};
876+
877+
struct config cfg = {
878+
.output_format = "normal",
879+
};
880+
881+
OPT_ARGS(opts) = {
882+
OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
883+
OPT_END()
884+
};
885+
886+
ret = parse_and_open(&dev, argc, argv, desc, opts);
887+
if (ret)
888+
return ret;
889+
890+
r = nvme_scan(NULL);
891+
capabilities = sndk_get_drive_capabilities(r, dev);
892+
893+
if (capabilities & SNDK_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2) {
894+
ret = sndk_get_fw_act_history_C2(r, dev, cfg.output_format);
895+
896+
if (ret) {
897+
fprintf(stderr, "ERROR: SNDK: Failure reading the FW ");
898+
fprintf(stderr, "Activate History, ret = %d\n", ret);
899+
}
900+
} else
901+
/* Fall back to the wdc plugin command */
902+
ret = run_wdc_vs_fw_activate_history(argc, argv, command, plugin);
903+
904+
nvme_free_tree(r);
905+
dev_close(dev);
906+
return ret;
907+
}
908+
909+
static int sndk_do_clear_fw_activate_history_fid(int fd)
910+
{
911+
int ret = -1;
912+
__u32 result;
913+
__u32 value = 1 << 31; /* Bit 31 - Clear Firmware Update History Log */
914+
915+
ret = nvme_set_features_simple(fd, SNDK_NVME_CLEAR_FW_ACT_HIST_VU_FID, 0, value,
916+
false, &result);
917+
918+
nvme_show_status(ret);
919+
return ret;
579920
}
580921

581922
static int sndk_clear_fw_activate_history(int argc, char **argv,
582923
struct command *command,
583924
struct plugin *plugin)
584925
{
585-
return run_wdc_clear_fw_activate_history(argc, argv, command, plugin);
926+
const char *desc = "Clear FW activate history table.";
927+
__u64 capabilities = 0;
928+
struct nvme_dev *dev;
929+
nvme_root_t r;
930+
int ret;
931+
932+
OPT_ARGS(opts) = {
933+
OPT_END()
934+
};
935+
936+
ret = parse_and_open(&dev, argc, argv, desc, opts);
937+
if (ret)
938+
return ret;
939+
940+
r = nvme_scan(NULL);
941+
capabilities = sndk_get_drive_capabilities(r, dev);
942+
943+
if (capabilities & SNDK_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY) {
944+
ret = sndk_do_clear_fw_activate_history_fid(dev_fd(dev));
945+
946+
if (ret) {
947+
fprintf(stderr, "ERROR: SNDK: Failure clearing the FW ");
948+
fprintf(stderr, "Activate History, ret = %d\n", ret);
949+
}
950+
} else
951+
/* Fall back to the wdc plugin command */
952+
ret = run_wdc_clear_fw_activate_history(argc, argv, command, plugin);
953+
954+
nvme_free_tree(r);
955+
dev_close(dev);
956+
return ret;
586957
}
587958

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

0 commit comments

Comments
 (0)