Spdk/examples/nvme/identify/identify.c
Daniel Verkamp fcb00f3780 nvme: expand probe information to a struct
spdk_nvme_probe() will now provide a struct spdk_nvme_probe_info to the
probe and attach callbacks in place of the PCI device pointer.

This struct contains the useful information that could be retrieved from
the PCI device during probe.

The goal of this change is to allow expansion of the probe information
in the future when other transports (specifically, NVMe over Fabrics)
are added that do not necessarily use PCI addressing or device IDs.

Change-Id: I59a2a9e874e248ce5fa1d7f4b57c8056962ff3cd
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
2016-11-02 14:15:02 -07:00

920 lines
30 KiB
C

/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <rte_config.h>
#include <rte_lcore.h>
#include "spdk/nvme.h"
#include "spdk/env.h"
#include "spdk/nvme_intel.h"
#include "spdk/pci_ids.h"
static int outstanding_commands;
struct feature {
uint32_t result;
bool valid;
};
static struct feature features[256];
static struct spdk_nvme_error_information_entry error_page[256];
static struct spdk_nvme_health_information_page health_page;
static struct spdk_nvme_intel_smart_information_page intel_smart_page;
static struct spdk_nvme_intel_temperature_page intel_temperature_page;
static struct spdk_nvme_intel_marketing_description_page intel_md_page;
static bool g_hex_dump = false;
static void
hex_dump(const void *data, size_t size)
{
size_t offset = 0, i;
const uint8_t *bytes = data;
while (size) {
printf("%08zX:", offset);
for (i = 0; i < 16; i++) {
if (i == 8) {
printf("-");
} else {
printf(" ");
}
if (i < size) {
printf("%02X", bytes[offset + i]);
} else {
printf(" ");
}
}
printf(" ");
for (i = 0; i < 16; i++) {
if (i < size) {
if (bytes[offset + i] > 0x20 && bytes[offset + i] < 0x7F) {
printf("%c", bytes[offset + i]);
} else {
printf(".");
}
}
}
printf("\n");
offset += 16;
if (size > 16) {
size -= 16;
} else {
break;
}
}
}
static void
get_feature_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
{
struct feature *feature = cb_arg;
int fid = feature - features;
if (spdk_nvme_cpl_is_error(cpl)) {
printf("get_feature(0x%02X) failed\n", fid);
} else {
feature->result = cpl->cdw0;
feature->valid = true;
}
outstanding_commands--;
}
static void
get_log_page_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
{
if (spdk_nvme_cpl_is_error(cpl)) {
printf("get log page failed\n");
}
outstanding_commands--;
}
static int
get_feature(struct spdk_nvme_ctrlr *ctrlr, uint8_t fid)
{
struct spdk_nvme_cmd cmd = {};
cmd.opc = SPDK_NVME_OPC_GET_FEATURES;
cmd.cdw10 = fid;
return spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, &cmd, NULL, 0, get_feature_completion, &features[fid]);
}
static void
get_features(struct spdk_nvme_ctrlr *ctrlr)
{
size_t i;
uint8_t features_to_get[] = {
SPDK_NVME_FEAT_ARBITRATION,
SPDK_NVME_FEAT_POWER_MANAGEMENT,
SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD,
SPDK_NVME_FEAT_ERROR_RECOVERY,
};
/* Submit several GET FEATURES commands and wait for them to complete */
outstanding_commands = 0;
for (i = 0; i < sizeof(features_to_get) / sizeof(*features_to_get); i++) {
if (get_feature(ctrlr, features_to_get[i]) == 0) {
outstanding_commands++;
} else {
printf("get_feature(0x%02X) failed to submit command\n", features_to_get[i]);
}
}
while (outstanding_commands) {
spdk_nvme_ctrlr_process_admin_completions(ctrlr);
}
}
static int
get_error_log_page(struct spdk_nvme_ctrlr *ctrlr)
{
const struct spdk_nvme_ctrlr_data *cdata;
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_ERROR,
SPDK_NVME_GLOBAL_NS_TAG, error_page,
sizeof(*error_page) * (cdata->elpe + 1),
get_log_page_completion, NULL)) {
printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
exit(1);
}
return 0;
}
static int
get_health_log_page(struct spdk_nvme_ctrlr *ctrlr)
{
if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_HEALTH_INFORMATION,
SPDK_NVME_GLOBAL_NS_TAG, &health_page, sizeof(health_page), get_log_page_completion, NULL)) {
printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
exit(1);
}
return 0;
}
static int
get_intel_smart_log_page(struct spdk_nvme_ctrlr *ctrlr)
{
if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_INTEL_LOG_SMART, SPDK_NVME_GLOBAL_NS_TAG,
&intel_smart_page, sizeof(intel_smart_page), get_log_page_completion, NULL)) {
printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
exit(1);
}
return 0;
}
static int
get_intel_temperature_log_page(struct spdk_nvme_ctrlr *ctrlr)
{
if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_INTEL_LOG_TEMPERATURE,
SPDK_NVME_GLOBAL_NS_TAG, &intel_temperature_page, sizeof(intel_temperature_page),
get_log_page_completion, NULL)) {
printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
exit(1);
}
return 0;
}
static int
get_intel_md_log_page(struct spdk_nvme_ctrlr *ctrlr)
{
if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_INTEL_MARKETING_DESCRIPTION,
SPDK_NVME_GLOBAL_NS_TAG, &intel_md_page, sizeof(intel_md_page),
get_log_page_completion, NULL)) {
printf("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
exit(1);
}
return 0;
}
static void
get_log_pages(struct spdk_nvme_ctrlr *ctrlr)
{
const struct spdk_nvme_ctrlr_data *cdata;
outstanding_commands = 0;
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
if (get_error_log_page(ctrlr) == 0) {
outstanding_commands++;
} else {
printf("Get Error Log Page failed\n");
}
if (get_health_log_page(ctrlr) == 0) {
outstanding_commands++;
} else {
printf("Get Log Page (SMART/health) failed\n");
}
if (cdata->vid == SPDK_PCI_VID_INTEL) {
if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_LOG_SMART)) {
if (get_intel_smart_log_page(ctrlr) == 0) {
outstanding_commands++;
} else {
printf("Get Log Page (Intel SMART/health) failed\n");
}
}
if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_LOG_TEMPERATURE)) {
if (get_intel_temperature_log_page(ctrlr) == 0) {
outstanding_commands++;
} else {
printf("Get Log Page (Intel temperature) failed\n");
}
}
if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_MARKETING_DESCRIPTION)) {
if (get_intel_md_log_page(ctrlr) == 0) {
outstanding_commands++;
} else {
printf("Get Log Page (Intel Marketing Description) failed\n");
}
}
}
while (outstanding_commands) {
spdk_nvme_ctrlr_process_admin_completions(ctrlr);
}
}
static void
print_uint128_hex(uint64_t *v)
{
unsigned long long lo = v[0], hi = v[1];
if (hi) {
printf("0x%llX%016llX", hi, lo);
} else {
printf("0x%llX", lo);
}
}
static void
print_uint128_dec(uint64_t *v)
{
unsigned long long lo = v[0], hi = v[1];
if (hi) {
/* can't handle large (>64-bit) decimal values for now, so fall back to hex */
print_uint128_hex(v);
} else {
printf("%llu", (unsigned long long)lo);
}
}
/* The len should be <= 8.*/
static void
print_uint_var_dec(uint8_t *array, unsigned int len)
{
uint64_t result = 0;
int i = len;
while (i > 0) {
result += (uint64_t)array[i - 1] << (8 * (i - 1));
i--;
}
printf("%lu", result);
}
static void
print_namespace(struct spdk_nvme_ns *ns)
{
const struct spdk_nvme_ns_data *nsdata;
uint32_t i;
uint32_t flags;
nsdata = spdk_nvme_ns_get_data(ns);
flags = spdk_nvme_ns_get_flags(ns);
printf("Namespace ID:%d\n", spdk_nvme_ns_get_id(ns));
if (g_hex_dump) {
hex_dump(nsdata, sizeof(*nsdata));
printf("\n");
}
if (!spdk_nvme_ns_is_active(ns)) {
printf("Inactive namespace ID\n\n");
return;
}
printf("Deallocate: %s\n",
(flags & SPDK_NVME_NS_DEALLOCATE_SUPPORTED) ? "Supported" : "Not Supported");
printf("Flush: %s\n",
(flags & SPDK_NVME_NS_FLUSH_SUPPORTED) ? "Supported" : "Not Supported");
printf("Reservation: %s\n",
(flags & SPDK_NVME_NS_RESERVATION_SUPPORTED) ? "Supported" : "Not Supported");
if (flags & SPDK_NVME_NS_DPS_PI_SUPPORTED) {
printf("End-to-End Data Protection: Supported\n");
printf("Protection Type: Type%d\n", nsdata->dps.pit);
printf("Metadata Transfered as: %s\n",
nsdata->flbas.extended ? "Extended Data LBA" : "Separate Metadata Buffer");
printf("Metadata Location: %s\n",
nsdata->dps.md_start ? "First 8 Bytes" : "Last 8 Bytes");
}
printf("Size (in LBAs): %lld (%lldM)\n",
(long long)nsdata->nsze,
(long long)nsdata->nsze / 1024 / 1024);
printf("Capacity (in LBAs): %lld (%lldM)\n",
(long long)nsdata->ncap,
(long long)nsdata->ncap / 1024 / 1024);
printf("Utilization (in LBAs): %lld (%lldM)\n",
(long long)nsdata->nuse,
(long long)nsdata->nuse / 1024 / 1024);
printf("Thin Provisioning: %s\n",
nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported");
printf("Number of LBA Formats: %d\n", nsdata->nlbaf + 1);
printf("Current LBA Format: LBA Format #%02d\n",
nsdata->flbas.format);
for (i = 0; i <= nsdata->nlbaf; i++)
printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n",
i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms);
printf("\n");
}
static void
print_controller(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_pci_addr *pci_addr)
{
const struct spdk_nvme_ctrlr_data *cdata;
union spdk_nvme_cap_register cap;
union spdk_nvme_vs_register vs;
uint8_t str[512];
uint32_t i;
struct spdk_nvme_error_information_entry *error_entry;
cap = spdk_nvme_ctrlr_get_regs_cap(ctrlr);
vs = spdk_nvme_ctrlr_get_regs_vs(ctrlr);
get_features(ctrlr);
get_log_pages(ctrlr);
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
printf("=====================================================\n");
printf("NVMe Controller at PCI bus %d, device %d, function %d\n",
pci_addr->bus, pci_addr->dev, pci_addr->func);
printf("=====================================================\n");
if (g_hex_dump) {
hex_dump(cdata, sizeof(*cdata));
printf("\n");
}
printf("Controller Capabilities/Features\n");
printf("================================\n");
printf("Vendor ID: %04x\n", cdata->vid);
printf("Subsystem Vendor ID: %04x\n", cdata->ssvid);
snprintf(str, sizeof(cdata->sn) + 1, "%s", cdata->sn);
printf("Serial Number: %s\n", str);
snprintf(str, sizeof(cdata->mn) + 1, "%s", cdata->mn);
printf("Model Number: %s\n", str);
snprintf(str, sizeof(cdata->fr) + 1, "%s", cdata->fr);
printf("Firmware Version: %s\n", str);
printf("Recommended Arb Burst: %d\n", cdata->rab);
printf("IEEE OUI Identifier: %02x %02x %02x\n",
cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
printf("Multi-path I/O\n");
printf(" May have multiple subsystem ports: %s\n", cdata->cmic.multi_port ? "Yes" : "No");
printf(" May be connected to multiple hosts: %s\n", cdata->cmic.multi_host ? "Yes" : "No");
printf(" Associated with SR-IOV VF: %s\n", cdata->cmic.sr_iov ? "Yes" : "No");
printf("Max Data Transfer Size: ");
if (cdata->mdts == 0)
printf("Unlimited\n");
else
printf("%" PRIu64 "\n", (uint64_t)1 << (12 + cap.bits.mpsmin + cdata->mdts));
if (features[SPDK_NVME_FEAT_ERROR_RECOVERY].valid) {
unsigned tler = features[SPDK_NVME_FEAT_ERROR_RECOVERY].result & 0xFFFF;
printf("Error Recovery Timeout: ");
if (tler == 0) {
printf("Unlimited\n");
} else {
printf("%u milliseconds\n", tler * 100);
}
}
printf("NVMe Specification Version (VS): %u.%u", vs.bits.mjr, vs.bits.mnr);
if (vs.bits.ter) {
printf(".%u", vs.bits.ter);
}
printf("\n");
if (cdata->ver.raw != 0) {
printf("NVMe Specification Version (Identify): %u.%u", cdata->ver.bits.mjr, cdata->ver.bits.mnr);
if (cdata->ver.bits.ter) {
printf(".%u", cdata->ver.bits.ter);
}
printf("\n");
}
printf("Maximum Queue Entries: %u\n", cap.bits.mqes + 1);
printf("Contiguous Queues Required: %s\n", cap.bits.cqr ? "Yes" : "No");
printf("Arbitration Mechanisms Supported\n");
printf(" Weighted Round Robin: %s\n",
cap.bits.ams & SPDK_NVME_CAP_AMS_WRR ? "Supported" : "Not Supported");
printf(" Vendor Specific: %s\n",
cap.bits.ams & SPDK_NVME_CAP_AMS_VS ? "Supported" : "Not Supported");
printf("Reset Timeout: %" PRIu64 " ms\n", (uint64_t)500 * cap.bits.to);
printf("Doorbell Stride: %" PRIu64 " bytes\n",
(uint64_t)1 << (2 + cap.bits.dstrd));
printf("NVM Subsystem Reset: %s\n",
cap.bits.nssrs ? "Supported" : "Not Supported");
printf("Command Sets Supported\n");
printf(" NVM Command Set: %s\n",
cap.bits.css_nvm ? "Supported" : "Not Supported");
printf("Memory Page Size Minimum: %" PRIu64 " bytes\n",
(uint64_t)1 << (12 + cap.bits.mpsmin));
printf("Memory Page Size Maximum: %" PRIu64 " bytes\n",
(uint64_t)1 << (12 + cap.bits.mpsmax));
printf("Optional Asynchronous Events Supported\n");
printf(" Namespace Attribute Notices: %s\n",
cdata->oaes.ns_attribute_notices ? "Supported" : "Not Supported");
printf(" Firmware Activation Notices: %s\n",
cdata->oaes.fw_activation_notices ? "Supported" : "Not Supported");
printf("\n");
printf("Admin Command Set Attributes\n");
printf("============================\n");
printf("Security Send/Receive: %s\n",
cdata->oacs.security ? "Supported" : "Not Supported");
printf("Format NVM: %s\n",
cdata->oacs.format ? "Supported" : "Not Supported");
printf("Firmware Activate/Download: %s\n",
cdata->oacs.firmware ? "Supported" : "Not Supported");
printf("Abort Command Limit: %d\n", cdata->acl + 1);
printf("Async Event Request Limit: %d\n", cdata->aerl + 1);
printf("Number of Firmware Slots: ");
if (cdata->oacs.firmware != 0)
printf("%d\n", cdata->frmw.num_slots);
else
printf("N/A\n");
printf("Firmware Slot 1 Read-Only: ");
if (cdata->oacs.firmware != 0)
printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No");
else
printf("N/A\n");
printf("Per-Namespace SMART Log: %s\n",
cdata->lpa.ns_smart ? "Yes" : "No");
printf("Error Log Page Entries Supported: %d\n", cdata->elpe + 1);
printf("\n");
printf("NVM Command Set Attributes\n");
printf("==========================\n");
printf("Submission Queue Entry Size\n");
printf(" Max: %d\n", 1 << cdata->sqes.max);
printf(" Min: %d\n", 1 << cdata->sqes.min);
printf("Completion Queue Entry Size\n");
printf(" Max: %d\n", 1 << cdata->cqes.max);
printf(" Min: %d\n", 1 << cdata->cqes.min);
printf("Number of Namespaces: %d\n", cdata->nn);
printf("Compare Command: %s\n",
cdata->oncs.compare ? "Supported" : "Not Supported");
printf("Write Uncorrectable Command: %s\n",
cdata->oncs.write_unc ? "Supported" : "Not Supported");
printf("Dataset Management Command: %s\n",
cdata->oncs.dsm ? "Supported" : "Not Supported");
printf("Write Zeroes Command: %s\n",
cdata->oncs.write_zeroes ? "Supported" : "Not Supported");
printf("Set Features Save Field: %s\n",
cdata->oncs.set_features_save ? "Supported" : "Not Supported");
printf("Reservations: %s\n",
cdata->oncs.reservations ? "Supported" : "Not Supported");
printf("Volatile Write Cache: %s\n",
cdata->vwc.present ? "Present" : "Not Present");
printf("Scatter-Gather List\n");
printf(" SGL Command Set: %s\n",
cdata->sgls.supported ? "Supported" : "Not Supported");
printf(" SGL Keyed: %s\n",
cdata->sgls.keyed_sgl ? "Supported" : "Not Supported");
printf(" SGL Bit Bucket Descriptor: %s\n",
cdata->sgls.bit_bucket_descriptor ? "Supported" : "Not Supported");
printf(" SGL Metadata Pointer: %s\n",
cdata->sgls.metadata_pointer ? "Supported" : "Not Supported");
printf(" Oversized SGL: %s\n",
cdata->sgls.oversized_sgl ? "Supported" : "Not Supported");
printf(" SGL Metadata Address: %s\n",
cdata->sgls.metadata_address ? "Supported" : "Not Supported");
printf(" SGL Offset: %s\n",
cdata->sgls.sgl_offset ? "Supported" : "Not Supported");
printf("\n");
printf("Error Log\n");
printf("=========\n");
for (i = 0; i <= cdata->elpe; i++) {
error_entry = &error_page[i];
if (error_entry->error_count == 0) {
continue;
}
if (i != 0) {
printf("-----------\n");
}
printf("Entry: %u\n", i);
printf("Error Count: 0x%"PRIx64"\n", error_entry->error_count);
printf("Submission Queue Id: 0x%x\n", error_entry->sqid);
printf("Command Id: 0x%x\n", error_entry->cid);
printf("Phase Bit: %x\n", error_entry->status.p);
printf("Status Code: 0x%x\n", error_entry->status.sc);
printf("Status Code Type: 0x%x\n", error_entry->status.sct);
printf("Do Not Retry: %x\n", error_entry->status.dnr);
printf("Error Location: 0x%x\n", error_entry->error_location);
printf("LBA: 0x%"PRIx64"\n", error_entry->lba);
printf("Namespace: 0x%x\n", error_entry->nsid);
printf("Vendor Log Page: 0x%x\n", error_entry->vendor_specific);
}
printf("\n");
if (features[SPDK_NVME_FEAT_ARBITRATION].valid) {
uint32_t arb = features[SPDK_NVME_FEAT_ARBITRATION].result;
unsigned ab, lpw, mpw, hpw;
ab = arb & 0x7;
lpw = ((arb >> 8) & 0xFF) + 1;
mpw = ((arb >> 16) & 0xFF) + 1;
hpw = ((arb >> 24) & 0xFF) + 1;
printf("Arbitration\n");
printf("===========\n");
printf("Arbitration Burst: ");
if (ab == 0x7) {
printf("no limit\n");
} else {
printf("%u\n", 1u << ab);
}
printf("Low Priority Weight: %u\n", lpw);
printf("Medium Priority Weight: %u\n", mpw);
printf("High Priority Weight: %u\n", hpw);
printf("\n");
}
if (features[SPDK_NVME_FEAT_POWER_MANAGEMENT].valid) {
unsigned ps = features[SPDK_NVME_FEAT_POWER_MANAGEMENT].result & 0x1F;
printf("Power Management\n");
printf("================\n");
printf("Number of Power States: %u\n", cdata->npss + 1);
printf("Current Power State: Power State #%u\n", ps);
for (i = 0; i <= cdata->npss; i++) {
const struct spdk_nvme_power_state *psd = &cdata->psd[i];
printf("Power State #%u: ", i);
if (psd->mps) {
/* MP scale is 0.0001 W */
printf("Max Power: %u.%04u W\n",
psd->mp / 10000,
psd->mp % 10000);
} else {
/* MP scale is 0.01 W */
printf("Max Power: %3u.%02u W\n",
psd->mp / 100,
psd->mp % 100);
}
/* TODO: print other power state descriptor fields */
}
printf("\n");
}
if (features[SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD].valid) {
printf("Health Information\n");
printf("==================\n");
if (g_hex_dump) {
hex_dump(&health_page, sizeof(health_page));
printf("\n");
}
printf("Critical Warnings:\n");
printf(" Available Spare Space: %s\n",
health_page.critical_warning.bits.available_spare ? "WARNING" : "OK");
printf(" Temperature: %s\n",
health_page.critical_warning.bits.temperature ? "WARNING" : "OK");
printf(" Device Reliability: %s\n",
health_page.critical_warning.bits.device_reliability ? "WARNING" : "OK");
printf(" Read Only: %s\n",
health_page.critical_warning.bits.read_only ? "Yes" : "No");
printf(" Volatile Memory Backup: %s\n",
health_page.critical_warning.bits.volatile_memory_backup ? "WARNING" : "OK");
printf("Current Temperature: %u Kelvin (%u Celsius)\n",
health_page.temperature,
health_page.temperature - 273);
printf("Temperature Threshold: %u Kelvin (%u Celsius)\n",
features[SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD].result,
features[SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD].result - 273);
printf("Available Spare: %u%%\n", health_page.available_spare);
printf("Life Percentage Used: %u%%\n", health_page.percentage_used);
printf("Data Units Read: ");
print_uint128_dec(health_page.data_units_read);
printf("\n");
printf("Data Units Written: ");
print_uint128_dec(health_page.data_units_written);
printf("\n");
printf("Host Read Commands: ");
print_uint128_dec(health_page.host_read_commands);
printf("\n");
printf("Host Write Commands: ");
print_uint128_dec(health_page.host_write_commands);
printf("\n");
printf("Controller Busy Time: ");
print_uint128_dec(health_page.controller_busy_time);
printf(" minutes\n");
printf("Power Cycles: ");
print_uint128_dec(health_page.power_cycles);
printf("\n");
printf("Power On Hours: ");
print_uint128_dec(health_page.power_on_hours);
printf(" hours\n");
printf("Unsafe Shutdowns: ");
print_uint128_dec(health_page.unsafe_shutdowns);
printf("\n");
printf("Unrecoverable Media Errors: ");
print_uint128_dec(health_page.media_errors);
printf("\n");
printf("Lifetime Error Log Entries: ");
print_uint128_dec(health_page.num_error_info_log_entries);
printf("\n");
printf("\n");
}
if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_LOG_SMART)) {
size_t i = 0;
printf("Intel Health Information\n");
printf("==================\n");
for (i = 0;
i < sizeof(intel_smart_page.attributes) / sizeof(intel_smart_page.attributes[0]); i++) {
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_PROGRAM_FAIL_COUNT) {
printf("Program Fail Count:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_ERASE_FAIL_COUNT) {
printf("Erase Fail Count:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_WEAR_LEVELING_COUNT) {
printf("Wear Leveling Count:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: \n");
printf(" Min: ");
print_uint_var_dec(&intel_smart_page.attributes[i].raw_value[0], 2);
printf("\n");
printf(" Max: ");
print_uint_var_dec(&intel_smart_page.attributes[i].raw_value[2], 2);
printf("\n");
printf(" Avg: ");
print_uint_var_dec(&intel_smart_page.attributes[i].raw_value[4], 2);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_E2E_ERROR_COUNT) {
printf("End to End Error Detection Count:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_CRC_ERROR_COUNT) {
printf("CRC Error Count:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_MEDIA_WEAR) {
printf("Timed Workload, Media Wear:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_HOST_READ_PERCENTAGE) {
printf("Timed Workload, Host Read/Write Ratio:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("%%");
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_TIMER) {
printf("Timed Workload, Timer:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_THERMAL_THROTTLE_STATUS) {
printf("Thermal Throttle Status:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: \n");
printf(" Percentage: %d%%\n", intel_smart_page.attributes[i].raw_value[0]);
printf(" Throttling Event Count: ");
print_uint_var_dec(&intel_smart_page.attributes[i].raw_value[1], 4);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_RETRY_BUFFER_OVERFLOW_COUNTER) {
printf("Retry Buffer Overflow Counter:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_PLL_LOCK_LOSS_COUNT) {
printf("PLL Lock Loss Count:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_NAND_BYTES_WRITTEN) {
printf("NAND Bytes Written:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
if (intel_smart_page.attributes[i].code == SPDK_NVME_INTEL_SMART_HOST_BYTES_WRITTEN) {
printf("Host Bytes Written:\n");
printf(" Normalized Value : %d\n",
intel_smart_page.attributes[i].normalized_value);
printf(" Current Raw Value: ");
print_uint_var_dec(intel_smart_page.attributes[i].raw_value, 6);
printf("\n");
}
}
printf("\n");
}
if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_LOG_TEMPERATURE)) {
printf("Intel Temperature Information\n");
printf("==================\n");
printf("Current Temperature: %lu\n", intel_temperature_page.current_temperature);
printf("Overtemp shutdown Flag for last critical component temperature: %lu\n",
intel_temperature_page.shutdown_flag_last);
printf("Overtemp shutdown Flag for life critical component temperature: %lu\n",
intel_temperature_page.shutdown_flag_life);
printf("Highest temperature: %lu\n", intel_temperature_page.highest_temperature);
printf("Lowest temperature: %lu\n", intel_temperature_page.lowest_temperature);
printf("Specified Maximum Operating Temperature: %lu\n",
intel_temperature_page.specified_max_op_temperature);
printf("Specified Minimum Operating Temperature: %lu\n",
intel_temperature_page.specified_min_op_temperature);
printf("Estimated offset: %ld\n", intel_temperature_page.estimated_offset);
printf("\n");
printf("\n");
}
if (spdk_nvme_ctrlr_is_log_page_supported(ctrlr, SPDK_NVME_INTEL_MARKETING_DESCRIPTION)) {
printf("Intel Marketing Information\n");
printf("==================\n");
snprintf(str, sizeof(intel_md_page.marketing_product), "%s", intel_md_page.marketing_product);
printf("Marketing Product Information: %s\n", str);
printf("\n");
printf("\n");
}
for (i = 1; i <= spdk_nvme_ctrlr_get_num_ns(ctrlr); i++) {
print_namespace(spdk_nvme_ctrlr_get_ns(ctrlr, i));
}
}
static void
usage(const char *program_name)
{
printf("%s [options]", program_name);
printf("\n");
printf("options:\n");
printf(" -x print hex dump of raw data\n");
}
static int
parse_args(int argc, char **argv)
{
int op;
while ((op = getopt(argc, argv, "x")) != -1) {
switch (op) {
case 'x':
g_hex_dump = true;
break;
default:
usage(argv[0]);
return 1;
}
}
optind = 1;
return 0;
}
static bool
probe_cb(void *cb_ctx, const struct spdk_nvme_probe_info *probe_info,
struct spdk_nvme_ctrlr_opts *opts)
{
return true;
}
static void
attach_cb(void *cb_ctx, const struct spdk_nvme_probe_info *probe_info,
struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
{
print_controller(ctrlr, &probe_info->pci_addr);
spdk_nvme_detach(ctrlr);
}
static const char *ealargs[] = {
"identify",
"-c 0x1",
"-n 4",
"--proc-type=auto",
};
int main(int argc, char **argv)
{
int rc;
rc = parse_args(argc, argv);
if (rc != 0) {
return rc;
}
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]),
(char **)(void *)(uintptr_t)ealargs);
if (rc < 0) {
fprintf(stderr, "could not initialize dpdk\n");
exit(1);
}
rc = 0;
if (spdk_nvme_probe(NULL, probe_cb, attach_cb, NULL) != 0) {
fprintf(stderr, "spdk_nvme_probe() failed\n");
rc = 1;
}
return rc;
}