Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ jobs:
timeout-minutes: 60
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # v2.31.0
- uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0
with:
msystem: UCRT64
update: true
Expand Down
16 changes: 16 additions & 0 deletions completions/_nvme
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ _nvme () {
'ns-rescan:rescan the NVMe namespaces'
'show-regs:show the controller registers; require admin character device'
'boot-part-log:retrieve boot partition log'
'power-measurement-log:retrieve power measurement log'
'fid-support-effects-log:retrieve fid support and effects log'
'supported-log-pages:retrieve support log pages details'
'lockdown:submit a lockdown command'
Expand Down Expand Up @@ -1350,6 +1351,21 @@ _nvme () {
_arguments '*:: :->subcmds'
_describe -t commands "nvme boot-part-log options" _bootpartlog
;;
(power-measurement-log)
local _powermeaslog
_powermeaslog=(
/dev/nvme':supply a device to use (required)'
--raw-binary':output in binary format'
-b':alias for --raw-binary'
--output-format=':output format: normal|json|binary'
-o':alias for --output-format'
--verbose':increase output verbosity'
-v':alias for --verbose'
--timeout=':timeout value, in milliseconds'
)
_arguments '*:: :->subcmds'
_describe -t commands "nvme power-measurement-log options" _powermeaslog
;;
(get-feature)
local _getf
_getf=(
Expand Down
8 changes: 6 additions & 2 deletions completions/bash-nvme-completion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ nvme_list_opts () {
opts+=" --lsp -s --output-file= -f \
--output-format= -o"
;;
"power-measurement-log")
opts+=" --raw-binary -b --output-format= -o \
--verbose -v --timeout="
;;
"media-unit-stat-log")
opts+=" --dom-id= -d --output-format= -o \
--raw-binary -b"
Expand Down Expand Up @@ -542,7 +546,7 @@ nvme_list_opts () {
;;
esac

opts+=" -h --help -j --json"
opts+=" -h --help"

if [[ $vals == " " ]]; then
COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
Expand Down Expand Up @@ -1799,7 +1803,7 @@ _nvme_subcmds () {
error-log effects-log endurance-log \
predictable-lat-log pred-lat-event-agg-log \
persistent-event-log endurance-agg-log \
lba-status-log resv-notif-log get-feature \
lba-status-log resv-notif-log power-measurement-log get-feature \
device-self-test self-test-log set-feature \
set-property get-property format fw-commit \
fw-download admin-passthru io-passthru \
Expand Down
5 changes: 3 additions & 2 deletions libnvme/libnvme/nvme.i
Original file line number Diff line number Diff line change
Expand Up @@ -879,10 +879,11 @@ struct libnvme_ns *libnvme_ctrl_next_ns(struct libnvme_ctrl *c, struct libnvme_n
%feature("autodoc", "Set the libnvme logging verbosity.\n"
"\n"
"Args:\n"
" level: One of 'debug', 'info', 'warning', or 'err'.") log_level;
" level: One of 'debug-verbose', 'debug', 'info', 'warning', or 'err'.") log_level;
void log_level(const char *level) {
int log_level = LIBNVME_DEFAULT_LOGLEVEL;
if (!strcmp(level, "debug")) log_level = LIBNVME_LOG_DEBUG;
if (!strcmp(level, "debug-verbose")) log_level = LIBNVME_LOG_DEBUG_VERBOSE;
else if (!strcmp(level, "debug")) log_level = LIBNVME_LOG_DEBUG;
else if (!strcmp(level, "info")) log_level = LIBNVME_LOG_INFO;
else if (!strcmp(level, "warning")) log_level = LIBNVME_LOG_WARN;
else if (!strcmp(level, "err")) log_level = LIBNVME_LOG_ERR;
Expand Down
204 changes: 203 additions & 1 deletion libnvme/src/nvme/ioctl-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
#include <errno.h>
#include <ntddscsi.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#include <ccan/minmax/minmax.h>

#include <libnvme.h>

#include "cleanup.h"
#include "ioctl.h"
#include "private.h"
#include "types.h"
Expand Down Expand Up @@ -99,6 +101,29 @@ static bool get_is_win_pe(void)
return false;
}

/**
* get_ns_handle_from_ctrl() - Open the default namespace handle for a controller
* @hdl: Controller transport handle
*
* Return: Namespace transport handle on success, or NULL on failure.
*
* The caller owns the returned handle and must call libnvme_close() when it
* is no longer needed.
*/
static struct libnvme_transport_handle *get_ns_handle_from_ctrl(
struct libnvme_transport_handle *hdl)
{
struct libnvme_transport_handle *ns_hdl = NULL;
const char *ctrl_name;
__cleanup_free char *ns_name;

ctrl_name = libnvme_transport_handle_get_name(hdl);
if (asprintf(&ns_name, "%sn1", ctrl_name) >= 0)
libnvme_open(hdl->ctx, ns_name, &ns_hdl);

return ns_hdl;
}

__libnvme_public int libnvme_reset_subsystem(struct libnvme_transport_handle *hdl)
{
(void)hdl;
Expand Down Expand Up @@ -1324,6 +1349,177 @@ static int submit_admin_fw_download(struct libnvme_transport_handle *hdl,
return err;
}

#if !HAVE_STORAGE_REINITIALIZE_MEDIA
/*
* Definitions for values and types not yet included in mingw's winioctl.h.
* Values found in the 10.0.26100.0 Windows SDK winioctl.h.
*/

typedef enum _STORAGE_SANITIZE_METHOD {
StorageSanitizeMethodDefault = 0,
StorageSanitizeMethodBlockErase,
StorageSanitizeMethodCryptoErase
} STORAGE_SANITIZE_METHOD, *PSTORAGE_SANITIZE_METHOD;

typedef struct _STORAGE_REINITIALIZE_MEDIA {
DWORD Version;
DWORD Size;
DWORD TimeoutInSeconds;
struct {
DWORD SanitizeMethod : 4;
DWORD DisallowUnrestrictedSanitizeExit : 1;
DWORD Reserved : 27;
} SanitizeOption;
} STORAGE_REINITIALIZE_MEDIA, *PSTORAGE_REINITIALIZE_MEDIA;
#endif

static int submit_admin_sanitize_reinit_media(
struct libnvme_transport_handle *hdl,
struct libnvme_passthru_cmd *cmd)
{
struct libnvme_transport_handle *ns_hdl = NULL;
STORAGE_REINITIALIZE_MEDIA reinit_media = {0};
STORAGE_SANITIZE_METHOD sanitize_method = StorageSanitizeMethodDefault;
ULONG returned_len = 0;
void *user_data = NULL;
BOOL lock_succeeded = FALSE;
BOOL result = FALSE;
int err = 0;
__u8 sanact;
__u8 ause;

/*
* IOCTL_STORAGE_REINITIALIZE_MEDIA requires a handle to a disk (ns).
* If the provided handle is a controller, get a handle to the default
* namespace and issue the command on that handle instead.
*/
if (libnvme_transport_handle_is_ns(hdl)) {
ns_hdl = hdl;
} else {
ns_hdl = get_ns_handle_from_ctrl(hdl);
if (!ns_hdl) {
err = -ENODEV;
goto out;
}
}

user_data = hdl->submit_entry(hdl, cmd);
if (hdl->ctx->dry_run)
goto out;

if (ns_hdl->fd == INVALID_HANDLE_VALUE || ns_hdl->fd == NULL) {
err = -EBADF;
goto out;
}

sanact = NVME_FIELD_DECODE(cmd->cdw10,
NVME_SANITIZE_CDW10_SANACT_SHIFT,
NVME_SANITIZE_CDW10_SANACT_MASK);
ause = NVME_FIELD_DECODE(cmd->cdw10,
NVME_SANITIZE_CDW10_AUSE_SHIFT,
NVME_SANITIZE_CDW10_AUSE_MASK);

switch (sanact) {
case NVME_SANITIZE_SANACT_START_BLOCK_ERASE:
sanitize_method = StorageSanitizeMethodBlockErase;
break;
case NVME_SANITIZE_SANACT_START_CRYPTO_ERASE:
sanitize_method = StorageSanitizeMethodCryptoErase;
break;
case NVME_SANITIZE_SANACT_START_OVERWRITE:
case NVME_SANITIZE_SANACT_EXIT_FAILURE:
case NVME_SANITIZE_SANACT_EXIT_MEDIA_VERIF:
libnvme_msg(hdl->ctx, LIBNVME_LOG_ERR,
"SANACT=%u is not supported on Windows.\n", sanact);
err = -ENOTSUP;
goto out;
default:
err = create_nvme_status_code(NVME_SC_INVALID_FIELD,
NVME_SCT_GENERIC, false);
goto out;
}

/*
* Attempt to lock the volume before reinitializing media as documented
* in the Windows Storage documentationto flush cached data.
* If locking fails, the sanitize can still proceed.
*/
lock_succeeded = DeviceIoControl(ns_hdl->fd, FSCTL_LOCK_VOLUME,
NULL, 0, NULL, 0, &returned_len, NULL);

reinit_media.Version = sizeof(STORAGE_REINITIALIZE_MEDIA);
reinit_media.Size = sizeof(STORAGE_REINITIALIZE_MEDIA);
reinit_media.TimeoutInSeconds = (cmd->timeout_ms > 0) ?
((cmd->timeout_ms + 999) / 1000) : 0;
reinit_media.SanitizeOption.SanitizeMethod = sanitize_method;
reinit_media.SanitizeOption.DisallowUnrestrictedSanitizeExit = !ause;

do {
err = 0;
result = DeviceIoControl(ns_hdl->fd,
IOCTL_STORAGE_REINITIALIZE_MEDIA,
&reinit_media,
sizeof(reinit_media),
NULL,
0,
&returned_len,
NULL);
if (result)
break;

err = -get_errno_from_error(GetLastError());
} while (hdl->decide_retry(hdl, cmd, err));

if (err) {
libnvme_msg(hdl->ctx, LIBNVME_LOG_DEBUG, "%s: failed, "
"GetLastError=%lu, err=%d\n",
__func__, GetLastError(), err);
goto out;
}

cmd->result = 0;

out:
if (lock_succeeded)
DeviceIoControl(ns_hdl->fd, FSCTL_UNLOCK_VOLUME,
NULL, 0, NULL, 0, &returned_len, NULL);

if (ns_hdl && !libnvme_transport_handle_is_ns(hdl))
libnvme_close(ns_hdl);

hdl->submit_exit(hdl, cmd, err, user_data);
return err;
}

static int submit_admin_sanitize(
struct libnvme_transport_handle *hdl,
struct libnvme_passthru_cmd *cmd)
{
int err;

/*
* Windows documentation says IOCTL_STORAGE_PROTOCOL_COMMAND
* should work for sanitize commands, but in practice the command
* returns a failing result and a pending status, and the command
* never gets passed to the controller.
*
* Run sanitize using IOCTL_STORAGE_REINITIALIZE_MEDIA instead.
* For controller handles, this will be run on the default namespace
* handle if available. If not available, -ENODEV will be returned.
*/

err = submit_admin_sanitize_reinit_media(hdl, cmd);
if (err == -ENODEV) {
/*
* Default namespace handle not available,
* fall back to IOCTL_STORAGE_PROTOCOL_COMMAND.
*/
err = submit_storage_protocol_command(hdl, cmd);
}

return err;
}

/* SCSI operation code for sanitize command - from ddk/scsi.h */
#define SCSIOP_SANITIZE 0x48

Expand Down Expand Up @@ -1482,6 +1678,12 @@ static int submit_admin_format_nvm(struct libnvme_transport_handle *hdl,
if (get_is_win_pe())
return submit_storage_protocol_command(hdl, cmd);

if (!libnvme_transport_handle_is_ns(hdl)) {
libnvme_msg(hdl->ctx, LIBNVME_LOG_ERR, "Windows only supports "
"format on namespace devices (e.g. nvme0n1)\n");
return -ENOTSUP;
}

/*
* Extract the Secure Erase Settings (SES) from CDW10 and call the
* appropriate implementation based on the requested erase type.
Expand Down Expand Up @@ -1719,7 +1921,7 @@ __libnvme_public int libnvme_submit_admin_passthru(struct libnvme_transport_hand
case nvme_admin_security_recv:
return submit_admin_security_send_receive(hdl, cmd);
case nvme_admin_sanitize_nvm:
return submit_storage_protocol_command(hdl, cmd);
return submit_admin_sanitize(hdl, cmd);
case 0xC0 ... 0xFF: /* vendor-specific commands */
return submit_storage_protocol_command(hdl, cmd);
default:
Expand Down
9 changes: 5 additions & 4 deletions libnvme/src/nvme/lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
#include <nvme/lib-types.h>

enum libnvme_log_level {
LIBNVME_LOG_ERR = 0,
LIBNVME_LOG_WARN = 1,
LIBNVME_LOG_INFO = 2,
LIBNVME_LOG_DEBUG = 3,
LIBNVME_LOG_ERR = 0,
LIBNVME_LOG_WARN = 1,
LIBNVME_LOG_INFO = 2,
LIBNVME_LOG_DEBUG = 3,
LIBNVME_LOG_DEBUG_VERBOSE = 4,
};

#define LIBNVME_DEFAULT_LOGLEVEL LIBNVME_LOG_WARN
Expand Down
29 changes: 26 additions & 3 deletions logging.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,21 @@ bool is_printable_at_level(int level)

int map_log_level(int verbose, bool quiet)
{
if (verbose == 0 || quiet)
if (quiet)
return LIBNVME_LOG_ERR;

if (verbose == 1)
switch (verbose) {
case 0:
return LIBNVME_LOG_ERR;
case 1:
return LIBNVME_LOG_INFO;
case 2:
return LIBNVME_LOG_DEBUG;
default:
break;
}

return LIBNVME_LOG_DEBUG;
return LIBNVME_LOG_DEBUG_VERBOSE;
}

static void nvme_show_common(struct libnvme_passthru_cmd *cmd)
Expand Down Expand Up @@ -77,6 +85,20 @@ static void nvme_show_latency(struct timeval start, struct timeval end)
(end.tv_usec - start.tv_usec)));
}

static void nvme_show_data(const char *data, uintptr_t addr, int len)
{
if (len) {
nvme_show_key_value(data, "%lu bytes", len);
d((unsigned char *)addr, len, 16, 1);
}
}

static void nvme_show_datum(struct libnvme_passthru_cmd *cmd)
{
nvme_show_data("data", (uintptr_t)cmd->addr, cmd->data_len);
nvme_show_data("metadata", (uintptr_t)cmd->metadata, cmd->metadata_len);
}

static void nvme_log_retry(int errnum)
{
if (log_level < LIBNVME_LOG_DEBUG)
Expand Down Expand Up @@ -105,6 +127,7 @@ void nvme_submit_exit(struct libnvme_transport_handle *hdl,
gettimeofday(&sb->end, NULL);
nvme_show_command(cmd, err);
nvme_show_latency(sb->start, sb->end);
nvme_show_datum(cmd);
}
}

Expand Down
Loading
Loading