root/usr/src/uts/common/sys/nvme/discovery.h
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2024 Oxide Computer Company
 */

#ifndef _SYS_NVME_DISCOVERY_H
#define _SYS_NVME_DISCOVERY_H

/*
 * This defines common types that are used for discovering features of NVMe
 * devices. The primary way for users to consume these types is through the
 * libnvme discovery APIs.
 */

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
        NVME_LOG_ID_MANDATORY,
        NVME_LOG_ID_OPTIONAL,
        NVME_LOG_ID_VENDOR_SPECIFIC
} nvme_log_disc_kind_t;

/*
 * Different logs cover different aspects of a device. These are listed below
 * referring to the NVMe controller, the NVM subsystem itself, and then
 * particular namespaces. NVMe 2.x adds the notion of a domain. From a
 * specification perspective, the NVM subsystem is instead sometimes referred to
 * as a domain. A controller can only access a single domain so while the 2.x
 * specifications suggest the scope is slightly different for the NVM subsystem
 * below, they're basically the same for our purposes.
 */
typedef enum {
        NVME_LOG_SCOPE_CTRL     = 1 << 0,
        NVME_LOG_SCOPE_NVM      = 1 << 1,
        NVME_LOG_SCOPE_NS       = 1 << 2
} nvme_log_disc_scope_t;

typedef enum {
        /*
         * This indicates that the implementation information is based on
         * knowledge from a base spec.
         */
        NVME_LOG_DISC_S_SPEC    = 1 << 0,
        /*
         * This indicates that the knowledge is from the identify controller
         * data structure.
         */
        NVME_LOG_DISC_S_ID_CTRL = 1 << 1,
        /*
         * This indicates that we have used our internal information database
         * about devices from a vendor's datasheets to determine that something
         * is supported.
         */
        NVME_LOG_DISC_S_DB      = 1 << 2,
        /*
         * This indicates that we have used a command (whether vendor-specific
         * or the NVMe 2.x Supported Log Pages) to get additional information
         * about this.
         */
        NVME_LOG_DISC_S_CMD     = 1 << 3
} nvme_log_disc_source_t;

typedef enum {
        /*
         * These next three flags indicate that the log page requires additional
         * information for it to complete successfully. These are specifically
         * the log specific parameter or a log specific indicator (e.g. an
         * endurance group, NVM set, domain, etc.). RAE was introduced in NVMe
         * 1.3 and applied to logs that already existed. It will not be possible
         * to set RAE on a log request that operates on a controller prior to
         * NVMe 1.3.
         */
        NVME_LOG_DISC_F_NEED_LSP        = 1 << 0,
        NVME_LOG_DISC_F_NEED_LSI        = 1 << 1,
        NVME_LOG_DISC_F_NEED_RAE        = 1 << 2,
        /*
         * Log pages whose only scope is a namespace are required to specify a
         * namespace. Otherwise, when the scope includes a controller or NVM
         * subsystem then it is assumed that the default is to target the
         * controller (e.g.  the health log page).
         */
        NVME_LOG_DISC_F_NEED_NSID       = 1 << 3
} nvme_log_disc_fields_t;


typedef enum {
        NVME_FEAT_SCOPE_CTRL    = 1 << 0,
        NVME_FEAT_SCOPE_NS      = 1 << 1
} nvme_feat_scope_t;

typedef enum {
        /*
         * Indicates that this feature requires an argument to select some part
         * of the feature in cdw11.
         */
        NVME_GET_FEAT_F_CDW11   = 1 << 0,
        /*
         * Indicates that this feature will output data to a specific buffer and
         * therefore a data argument is required for this feature.
         */
        NVME_GET_FEAT_F_DATA    = 1 << 1,
        /*
         * Indicates that this feature requires a namespace ID to be specified
         * when getting this feature. In general, while one can usually set a
         * feature to target the broadcast namespace, the same is not true of
         * getting a feature.
         */
        NVME_GET_FEAT_F_NSID    = 1 << 2,
} nvme_get_feat_fields_t;

typedef enum {
        /*
         * These indicate that the feature requires fields set in the various
         * control words to set the feature.
         */
        NVME_SET_FEAT_F_CDW11   = 1 << 0,
        NVME_SET_FEAT_F_CDW12   = 1 << 1,
        NVME_SET_FEAT_F_CDW13   = 1 << 2,
        NVME_SET_FEAT_F_CDW14   = 1 << 3,
        NVME_SET_FEAT_F_CDW15   = 1 << 4,
        /*
         * Indicates that there is a data payload component to this feature that
         * must be set.
         */
        NVME_SET_FEAT_F_DATA    = 1 << 5,
        /*
         * Indicates that this feature requires a namespace ID. Broadcast IDs
         * are more often allowed than with getting a feature, but it still
         * depends.
         */
        NVME_SET_FEAT_F_NSID    = 1 << 6
} nvme_set_feat_fields_t;

typedef enum {
        /*
         * Indicates that getting the feature outputs data in cdw0 for
         * consumption. This is the most common form of data output for getting
         * features. Setting features usually doesn't output data in cdw0;
         * however, a few are defined to.
         */
        NVME_FEAT_OUTPUT_CDW0   = 1 << 0,
        /*
         * Indicates that data is output in the data buffer that was passed in.
         * This is only ever used for get features.
         */
        NVME_FEAT_OUTPUT_DATA   = 1 << 1
} nvme_feat_output_t;

typedef enum {
        /*
         * Indicates that when getting or setting this feature that requires a
         * namespace ID, the broadcast namespace is allowed.
         */
        NVME_FEAT_F_GET_BCAST_NSID      = 1 << 0,
        NVME_FEAT_F_SET_BCAST_NSID      = 1 << 1
} nvme_feat_flags_t;

typedef enum {
        NVME_FEAT_MANDATORY     = 0,
        NVME_FEAT_OPTIONAL,
        NVME_FEAT_VENDOR_SPECIFIC
} nvme_feat_kind_t;

/*
 * This enumeration indicates whether or not a given feature is specific to a
 * command set, and if so what one. The default is that most features are
 * present for all command sets, which uses the NVME_FEAT_CSI_NONE value.
 * Otherwise, it uses a bit-field to indicate what it is present in.
 */
typedef enum {
        NVME_FEAT_CSI_NONE      = 0,
        NVME_FEAT_CSI_NVM       = 1 << 0,
} nvme_feat_csi_t;

/*
 * Prior to NVMe 2.x, there was no standard way to determine if a given log page
 * was actually implemented or not. While several features had bits in the
 * identify controller namespace, some (e.g. LBA Range Type) are optional,
 * command-set specific, and have no such way of knowing if they're supported
 * short of saying so. If we cannot determine this from the controller's
 * version, type, and identify controller information, then we will indicate
 * that we don't know. When we have full support for leveraging the NVMe 2.x
 * Feature Identifiers Supported and Effects log pages and someone is
 * interrogating an NVMe 2.x controller, then ideally one should not see
 * unknown.
 */
typedef enum {
        NVME_FEAT_IMPL_UNKNOWN = 0,
        NVME_FEAT_IMPL_UNSUPPORTED,
        NVME_FEAT_IMPL_SUPPORTED
} nvme_feat_impl_t;

#ifdef __cplusplus
}
#endif

#endif /* _SYS_NVME_DISCOVERY_H */