// SPDX-License-Identifier: LGPL-2.1-or-later /* * This file is part of libnvme. * Copyright (c) 2021 Code Construct Pty Ltd * * Authors: Jeremy Kerr */ /** * DOC: mi.h - NVMe Management Interface library (libnvme-mi) definitions. * * These provide an abstraction for the MI messaging between controllers * and a host, typically over an MCTP-over-i2c link to a NVMe device, used * as part of the out-of-band management of a system. * * We have a few data structures define here to reflect the topology * of a MI connection with an NVMe subsystem: * * - &nvme_mi_ep_t: an MI endpoint - our mechanism of communication with a * NVMe subsystem. For MCTP, an endpoint will be the component that * holds the MCTP address (EID), and receives our request message. * * endpoints are defined in the NVMe-MI spec, and are specific to the MI * interface. * * Each endpoint will provide access to one or more of: * * - &nvme_mi_ctrl_t: a NVMe controller, as defined by the NVMe base spec. * The controllers are responsible for processing any NVMe standard * commands (eg, the Admin command set). An endpoint (&nvme_mi_ep_t) * may provide access to multiple controllers - so each of the controller- * type commands will require a &nvme_mi_ctrl_t to be specified, rather than * an endpoint * * A couple of conventions with the libnvme-mi API: * * - All types and functions have the nvme_mi prefix, to distinguish from * the libnvme core. * * - We currently support either MI commands and Admin commands. The * former adds a _mi prefix, the latter an _admin prefix. [This does * result in the MI functions having a double _mi, like * &nvme_mi_mi_subsystem_health_status_poll, which is apparently amusing * for our German-speaking readers] * * For return values: unless specified in the per-function documentation, * all functions: * * - return 0 on success * * - return -1, with errno set, for errors communicating with the MI device, * either in request or response data * * - return >1 on MI status errors. This value is the 8-bit MI status * value, represented by &enum nvme_mi_resp_status. Note that the * status values may be vendor-defined above 0xe0. * * For the second case, we have a few conventions for errno values: * * - EPROTO: response data violated the MI protocol, and libnvme cannot * validly interpret the response * * - EIO: Other I/O error communicating with device (eg., valid but * unexpected response data) * * - EINVAL: invalid input arguments for a command * * In line with the core NVMe API, the Admin command functions take an * `_args` structure to provide the command-specific parameters. However, * for the MI interface, the fd and timeout members of these _args structs * are ignored. * * References to the specifications here will either to be the NVM Express * Management Interface ("NVMe-MI") or the NVM Express Base specification * ("NVMe"). At the time of writing, the versions we're referencing here * are: * - NVMe-MI 1.2b * - NVMe 2.0b * with a couple of accommodations for older spec types, particularly NVMe-MI * 1.1, where possible. * */ #ifndef _LIBNVME_MI_MI_H #define _LIBNVME_MI_MI_H #include #include #include "types.h" #include "tree.h" /** * NVME_MI_MSGTYPE_NVME - MCTP message type for NVMe-MI messages. * * This is defined by MCTP, but is referenced as part of the NVMe-MI message * spec. This is the MCTP NVMe message type (0x4), with the message-integrity * bit (0x80) set. */ #define NVME_MI_MSGTYPE_NVME 0x84 /* Basic MI message definitions */ /** * enum nvme_mi_message_type - NVMe-MI message type field. * @NVME_MI_MT_CONTROL: NVME-MI Control Primitive * @NVME_MI_MT_MI: NVMe-MI command * @NVME_MI_MT_ADMIN: NVMe Admin command * @NVME_MI_MT_PCIE: PCIe command * * Used as byte 1 of both request and response messages (NMIMT bits of NMP * byte). Not to be confused with the MCTP message type in byte 0. */ enum nvme_mi_message_type { NVME_MI_MT_CONTROL = 0, NVME_MI_MT_MI = 1, NVME_MI_MT_ADMIN = 2, NVME_MI_MT_PCIE = 4, }; /** * enum nvme_mi_ror: Request or response field. * @NVME_MI_ROR_REQ: request message * @NVME_MI_ROR_RSP: response message */ enum nvme_mi_ror { NVME_MI_ROR_REQ = 0, NVME_MI_ROR_RSP = 1, }; /** * enum nvme_mi_resp_status - values for the response status field * @NVME_MI_RESP_SUCCESS: success * @NVME_MI_RESP_MPR: More Processing Required * @NVME_MI_RESP_INTERNAL_ERR: Internal Error * @NVME_MI_RESP_INVALID_OPCODE: Invalid command opcode * @NVME_MI_RESP_INVALID_PARAM: Invalid command parameter * @NVME_MI_RESP_INVALID_CMD_SIZE: Invalid command size * @NVME_MI_RESP_INVALID_INPUT_SIZE: Invalid command input data size * @NVME_MI_RESP_ACCESS_DENIED: Access Denied * @NVME_MI_RESP_VPD_UPDATES_EXCEEDED: More VPD updates than allowed * @NVME_MI_RESP_PCIE_INACCESSIBLE: PCIe functionality currently unavailable * @NVME_MI_RESP_MEB_SANITIZED: MEB has been cleared due to sanitize * @NVME_MI_RESP_ENC_SERV_FAILURE: Enclosure services process failed * @NVME_MI_RESP_ENC_SERV_XFER_FAILURE: Transfer with enclosure services failed * @NVME_MI_RESP_ENC_FAILURE: Unreoverable enclosure failure * @NVME_MI_RESP_ENC_XFER_REFUSED: Enclosure services transfer refused * @NVME_MI_RESP_ENC_FUNC_UNSUP: Unsupported enclosure services function * @NVME_MI_RESP_ENC_SERV_UNAVAIL: Enclosure services unavailable * @NVME_MI_RESP_ENC_DEGRADED: Noncritical failure detected by enc. services * @NVME_MI_RESP_SANITIZE_IN_PROGRESS: Command prohibited during sanitize */ enum nvme_mi_resp_status { NVME_MI_RESP_SUCCESS = 0x00, NVME_MI_RESP_MPR = 0x01, NVME_MI_RESP_INTERNAL_ERR = 0x02, NVME_MI_RESP_INVALID_OPCODE = 0x03, NVME_MI_RESP_INVALID_PARAM = 0x04, NVME_MI_RESP_INVALID_CMD_SIZE = 0x05, NVME_MI_RESP_INVALID_INPUT_SIZE = 0x06, NVME_MI_RESP_ACCESS_DENIED = 0x07, /* 0x08 - 0x1f: reserved */ NVME_MI_RESP_VPD_UPDATES_EXCEEDED = 0x20, NVME_MI_RESP_PCIE_INACCESSIBLE = 0x21, NVME_MI_RESP_MEB_SANITIZED = 0x22, NVME_MI_RESP_ENC_SERV_FAILURE = 0x23, NVME_MI_RESP_ENC_SERV_XFER_FAILURE = 0x24, NVME_MI_RESP_ENC_FAILURE = 0x25, NVME_MI_RESP_ENC_XFER_REFUSED = 0x26, NVME_MI_RESP_ENC_FUNC_UNSUP = 0x27, NVME_MI_RESP_ENC_SERV_UNAVAIL = 0x28, NVME_MI_RESP_ENC_DEGRADED = 0x29, NVME_MI_RESP_SANITIZE_IN_PROGRESS = 0x2a, /* 0x2b - 0xdf: reserved */ /* 0xe0 - 0xff: vendor specific */ }; /** * struct nvme_mi_msg_hdr - General MI message header. * @type: MCTP message type, will always be NVME_MI_MSGTYPE_NVME * @nmp: NVMe-MI message parameters (including MI message type) * @meb: Management Endpoint Buffer flag; unused for libnvme-mi implementation * @rsvd0: currently reserved * * Wire format shared by both request and response messages, per NVMe-MI * section 3.1. This is used for all message types, MI and Admin. */ struct nvme_mi_msg_hdr { __u8 type; __u8 nmp; __u8 meb; __u8 rsvd0; } __attribute__((packed)); /** * struct nvme_mi_msg_resp - Generic response type. * @hdr: the general request/response message header * @status: response status value (see &enum nvme_mi_resp_status) * @rsvd0: reserved data, may be defined by specific response * * Every response will start with one of these; command-specific responses * will define parts of the reserved data, and may add further fields. */ struct nvme_mi_msg_resp { struct nvme_mi_msg_hdr hdr; __u8 status; __u8 rsvd0[3]; }; /** * enum nvme_mi_mi_opcode - Operation code for supported NVMe-MI commands. * @nvme_mi_mi_opcode_mi_data_read: Read NVMe-MI Data Structure * @nvme_mi_mi_opcode_subsys_health_status_poll: Subsystem Health Status Poll * @nvme_mi_mi_opcode_configuration_set: MI Configuration Set * @nvme_mi_mi_opcode_configuration_get: MI Configuration Get */ enum nvme_mi_mi_opcode { nvme_mi_mi_opcode_mi_data_read = 0x00, nvme_mi_mi_opcode_subsys_health_status_poll = 0x01, nvme_mi_mi_opcode_configuration_set = 0x03, nvme_mi_mi_opcode_configuration_get = 0x04, }; /** * struct nvme_mi_mi_req_hdr - MI request message header. * @hdr: generic MI message header * @opcode: opcode (OPC) for the specific MI command * @rsvd0: reserved bytes * @cdw0: Management Request Doubleword 0 - command specific usage * @cdw1: Management Request Doubleword 1 - command specific usage * * Wire format for MI request message headers, defined in section 5 of NVMe-MI. */ struct nvme_mi_mi_req_hdr { struct nvme_mi_msg_hdr hdr; __u8 opcode; __u8 rsvd0[3]; __le32 cdw0, cdw1; }; /** * struct nvme_mi_mi_resp_hdr - MI response message header. * @hdr: generic MI message header * @status: generic response status from command; non-zero on failure. * @nmresp: NVMe Management Response: command-type-specific response data * * Wire format for MI response message header, defined in section 5 of NVMe-MI. */ struct nvme_mi_mi_resp_hdr { struct nvme_mi_msg_hdr hdr; __u8 status; __u8 nmresp[3]; }; /** * enum nvme_mi_dtyp - Data Structure Type field. * @nvme_mi_dtyp_subsys_info: NVM Subsystem Information * @nvme_mi_dtyp_port_info: Port information * @nvme_mi_dtyp_ctrl_list: Controller List * @nvme_mi_dtyp_ctrl_info: Controller Information * @nvme_mi_dtyp_opt_cmd_support: Optionally Supported Command List * @nvme_mi_dtyp_meb_support: Management Endpoint Buffer Command Support List * * Data Structure Type field for Read NVMe-MI Data Structure command, used to * indicate the particular structure to query from the endpoint. */ enum nvme_mi_dtyp { nvme_mi_dtyp_subsys_info = 0x00, nvme_mi_dtyp_port_info = 0x01, nvme_mi_dtyp_ctrl_list = 0x02, nvme_mi_dtyp_ctrl_info = 0x03, nvme_mi_dtyp_opt_cmd_support = 0x04, nvme_mi_dtyp_meb_support = 0x05, }; /** * enum nvme_mi_config_id - NVMe-MI Configuration identifier. * @NVME_MI_CONFIG_SMBUS_FREQ: Current SMBus/I2C frequency * @NVME_MI_CONFIG_HEALTH_STATUS_CHANGE: Health Status change - used to clear * health status bits in CCS bits of * status poll. Only for Set ops. * @NVME_MI_CONFIG_MCTP_MTU: MCTP maximum transmission unit size of port * specified in dw 0 * * Configuration parameters for the MI Get/Set Configuration commands. * * See &nvme_mi_mi_config_get() and &nvme_mi_config_set(). */ enum nvme_mi_config_id { NVME_MI_CONFIG_SMBUS_FREQ = 0x1, NVME_MI_CONFIG_HEALTH_STATUS_CHANGE = 0x2, NVME_MI_CONFIG_MCTP_MTU = 0x3, }; /** * enum nvme_mi_config_smbus_freq - SMBus/I2C frequency values * @NVME_MI_CONFIG_SMBUS_FREQ_100kHz: 100kHz * @NVME_MI_CONFIG_SMBUS_FREQ_400kHz: 400kHz * @NVME_MI_CONFIG_SMBUS_FREQ_1MHz: 1MHz * * Values used in the SMBus Frequency device configuration. See * &nvme_mi_mi_config_get_smbus_freq() and &nvme_mi_mi_config_set_smbus_freq(). */ enum nvme_mi_config_smbus_freq { NVME_MI_CONFIG_SMBUS_FREQ_100kHz = 0x1, NVME_MI_CONFIG_SMBUS_FREQ_400kHz = 0x2, NVME_MI_CONFIG_SMBUS_FREQ_1MHz = 0x3, }; /* Admin command definitions */ /** * struct nvme_mi_admin_req_hdr - Admin command request header. * @hdr: Generic MI message header * @opcode: Admin command opcode (using enum nvme_admin_opcode) * @flags: Command Flags, indicating dlen and doff validity; Only defined in * NVMe-MI version 1.1, no fields defined in 1.2 (where the dlen/doff * are always considered valid). * @ctrl_id: Controller ID target of command * @cdw1: Submission Queue Entry doubleword 1 * @cdw2: Submission Queue Entry doubleword 2 * @cdw3: Submission Queue Entry doubleword 3 * @cdw4: Submission Queue Entry doubleword 4 * @cdw5: Submission Queue Entry doubleword 5 * @doff: Offset of data to return from command * @dlen: Length of sent/returned data * @rsvd0: Reserved * @rsvd1: Reserved * @cdw10: Submission Queue Entry doubleword 10 * @cdw11: Submission Queue Entry doubleword 11 * @cdw12: Submission Queue Entry doubleword 12 * @cdw13: Submission Queue Entry doubleword 13 * @cdw14: Submission Queue Entry doubleword 14 * @cdw15: Submission Queue Entry doubleword 15 * * Wire format for Admin command message headers, defined in section 6 of * NVMe-MI. */ struct nvme_mi_admin_req_hdr { struct nvme_mi_msg_hdr hdr; __u8 opcode; __u8 flags; __le16 ctrl_id; __le32 cdw1, cdw2, cdw3, cdw4, cdw5; __le32 doff; __le32 dlen; __le32 rsvd0, rsvd1; __le32 cdw10, cdw11, cdw12, cdw13, cdw14, cdw15; } __attribute((packed)); /** * struct nvme_mi_admin_resp_hdr - Admin command response header. * @hdr: Generic MI message header * @status: Generic response code, non-zero on failure * @rsvd0: Reserved * @cdw0: Completion Queue Entry doubleword 0 * @cdw1: Completion Queue Entry doubleword 1 * @cdw3: Completion Queue Entry doubleword 3 * * This is the generic response format with the three doublewords of completion * queue data, plus optional response data. */ struct nvme_mi_admin_resp_hdr { struct nvme_mi_msg_hdr hdr; __u8 status; __u8 rsvd0[3]; __le32 cdw0, cdw1, cdw3; } __attribute__((packed)); /** * enum nvme_mi_control_opcode - Operation code for Control Primitives. * @nvme_mi_control_opcode_pause: Suspend response transmission/timeout * @nvme_mi_control_opcode_resume: Resume from a paused condition * @nvme_mi_control_opcode_abort: Re-initialize a Command Slot to the Idle state * @nvme_mi_control_opcode_get_state: Get the state of a Command Slot * @nvme_mi_control_opcode_replay: Retransmit the Response Message */ enum nvme_mi_control_opcode { nvme_mi_control_opcode_pause = 0x00, nvme_mi_control_opcode_resume = 0x01, nvme_mi_control_opcode_abort = 0x02, nvme_mi_control_opcode_get_state = 0x03, nvme_mi_control_opcode_replay = 0x04, }; /** * struct nvme_mi_control_req - The Control Primitive request. * @hdr: Generic MI message header * @opcode: Control Primitive Opcodes (using &enum nvme_mi_control_opcode) * @tag: flag - Opaque value passed from request to response * @cpsp: Control Primitive Specific Parameter * */ struct nvme_mi_control_req { struct nvme_mi_msg_hdr hdr; __u8 opcode; __u8 tag; __le16 cpsp; } __attribute((packed)); /** struct nvme_mi_control_resp - The Control Primitive response. * @hdr: Generic MI message header * @status: Generic response code, non-zero on failure * @tag: flag - Opaque value passed from request to response * @cpsr: Control Primitive Specific Response * */ struct nvme_mi_control_resp { struct nvme_mi_msg_hdr hdr; __u8 status; __u8 tag; __le16 cpsr; } __attribute((packed)); /** * nvme_mi_status_to_string() - return a string representation of the MI * status. * @status: MI response status * * Gives a string description of @status, as per section 4.1.2 of the NVMe-MI * spec. The status value should be of type NVME_STATUS_MI, and extracted * from the return value using nvme_status_get_value(). * * Returned string is const, and should not be free()ed. * * Returns: A string representing the status value */ const char *nvme_mi_status_to_string(int status); /** * nvme_mi_create_root() - Create top-level MI (root) handle. * @fp: File descriptor for logging messages * @log_level: Logging level to use * * Create the top-level (library) handle for creating subsequent endpoint * objects. Similar to nvme_create_root(), but we provide this to allow linking * without the core libnvme. * * Return: new root object, or NULL on failure. * * See &nvme_create_root. */ nvme_root_t nvme_mi_create_root(FILE *fp, int log_level); /** * nvme_mi_free_root() - Free root object. * @root: root to free */ void nvme_mi_free_root(nvme_root_t root); /** * nvme_mi_set_probe_enabled() - enable/disable the probe for new endpoints * @root: &nvme_root_t object * @enabled: whether to probe new endpoints * * Controls whether newly-created endpoints are probed for quirks on creation. * Defaults to enabled, which results in some initial messaging with the * endpoint to determine model-specific details. */ void nvme_mi_set_probe_enabled(nvme_root_t root, bool enabled); /* Top level management object: NVMe-MI Management Endpoint */ struct nvme_mi_ep; /** * typedef nvme_mi_ep_t - MI Endpoint object. * * Represents our communication endpoint on the remote MI-capable device. * To be used for direct MI commands for the endpoint (through the * nvme_mi_mi_* functions(), or to communicate with individual controllers * (see &nvme_mi_init_ctrl). * * Endpoints are created through a transport-specific constructor; currently * only MCTP-connected endpoints are supported, through &nvme_mi_open_mctp. * Subsequent operations on the endpoint (and related controllers) are * transport-independent. */ typedef struct nvme_mi_ep * nvme_mi_ep_t; /** * nvme_mi_first_endpoint - Start endpoint iterator * @m: &nvme_root_t object * * Return: first MI endpoint object under this root, or NULL if no endpoints * are present. * * See: &nvme_mi_next_endpoint, &nvme_mi_for_each_endpoint */ nvme_mi_ep_t nvme_mi_first_endpoint(nvme_root_t m); /** * nvme_mi_next_endpoint - Continue endpoint iterator * @m: &nvme_root_t object * @e: &nvme_mi_ep_t current position of iterator * * Return: next endpoint MI endpoint object after @e under this root, or NULL * if no further endpoints are present. * * See: &nvme_mi_first_endpoint, &nvme_mi_for_each_endpoint */ nvme_mi_ep_t nvme_mi_next_endpoint(nvme_root_t m, nvme_mi_ep_t e); /** * nvme_mi_for_each_endpoint - Iterator for NVMe-MI endpoints. * @m: &nvme_root_t containing endpoints * @e: &nvme_mi_ep_t object, set on each iteration */ #define nvme_mi_for_each_endpoint(m, e) \ for (e = nvme_mi_first_endpoint(m); e != NULL; \ e = nvme_mi_next_endpoint(m, e)) /** * nvme_mi_for_each_endpoint_safe - Iterator for NVMe-MI endpoints, allowing * deletion during traversal * @m: &nvme_root_t containing endpoints * @e: &nvme_mi_ep_t object, set on each iteration * @_e: &nvme_mi_ep_t object used as temporary storage */ #define nvme_mi_for_each_endpoint_safe(m, e, _e) \ for (e = nvme_mi_first_endpoint(m), _e = nvme_mi_next_endpoint(m, e); \ e != NULL; \ e = _e, _e = nvme_mi_next_endpoint(m, e)) /** * nvme_mi_ep_set_timeout - set a timeout for NVMe-MI responses * @ep: MI endpoint object * @timeout_ms: Timeout for MI responses, given in milliseconds */ int nvme_mi_ep_set_timeout(nvme_mi_ep_t ep, unsigned int timeout_ms); /** * nvme_mi_ep_set_mprt_max - set the maximum wait time for a More Processing * Required response * @ep: MI endpoint object * @mprt_max_ms: Maximum more processing required wait time * * NVMe-MI endpoints may respond to a request with a "More Processing Required" * response; this also includes a hint on the worst-case processing time for * the eventual response data, with a specification-defined maximum of 65.535 * seconds. * * This function provides a way to limit the maximum time we're prepared to * wait for the final response. Specify zero in @mprt_max_ms for no limit. * This should be larger than the command/response timeout set in * &nvme_mi_ep_set_timeout(). */ void nvme_mi_ep_set_mprt_max(nvme_mi_ep_t ep, unsigned int mprt_max_ms); /** * nvme_mi_ep_get_timeout - get the current timeout value for NVMe-MI responses * @ep: MI endpoint object * * Returns the current timeout value, in milliseconds, for this endpoint. */ unsigned int nvme_mi_ep_get_timeout(nvme_mi_ep_t ep); struct nvme_mi_ctrl; /** * typedef nvme_mi_ctrl_t - NVMe-MI Controller object. * * Provides NVMe command functionality, through the MI interface. */ typedef struct nvme_mi_ctrl * nvme_mi_ctrl_t; /** * nvme_mi_first_ctrl - Start controller iterator * @ep: &nvme_mi_ep_t object * * Return: first MI controller object under this root, or NULL if no controllers * are present. * * See: &nvme_mi_next_ctrl, &nvme_mi_for_each_ctrl */ nvme_mi_ctrl_t nvme_mi_first_ctrl(nvme_mi_ep_t ep); /** * nvme_mi_next_ctrl - Continue ctrl iterator * @ep: &nvme_mi_ep_t object * @c: &nvme_mi_ctrl_t current position of iterator * * Return: next MI controller object after @c under this endpoint, or NULL * if no further controllers are present. * * See: &nvme_mi_first_ctrl, &nvme_mi_for_each_ctrl */ nvme_mi_ctrl_t nvme_mi_next_ctrl(nvme_mi_ep_t ep, nvme_mi_ctrl_t c); /** * nvme_mi_for_each_ctrl - Iterator for NVMe-MI controllers. * @ep: &nvme_mi_ep_t containing endpoints * @c: &nvme_mi_ctrl_t object, set on each iteration * * Allows iteration of the list of controllers behind an endpoint. Unless the * controllers have already been created explicitly, you'll probably want to * call &nvme_mi_scan_ep() to scan for the controllers first. * * See: &nvme_mi_scan_ep() */ #define nvme_mi_for_each_ctrl(ep, c) \ for (c = nvme_mi_first_ctrl(ep); c != NULL; \ c = nvme_mi_next_ctrl(ep, c)) /** * nvme_mi_for_each_ctrl_safe - Iterator for NVMe-MI controllers, allowing * deletion during traversal * @ep: &nvme_mi_ep_t containing controllers * @c: &nvme_mi_ctrl_t object, set on each iteration * @_c: &nvme_mi_ctrl_t object used as temporary storage * * Allows iteration of the list of controllers behind an endpoint, safe against * deletion during iteration. Unless the controllers have already been created * explicitly (or you're just iterating to destroy controllers) you'll probably * want to call &nvme_mi_scan_ep() to scan for the controllers first. * * See: &nvme_mi_scan_ep() */ #define nvme_mi_for_each_ctrl_safe(ep, c, _c) \ for (c = nvme_mi_first_ctrl(ep), _c = nvme_mi_next_ctrl(ep, c); \ c != NULL; \ c = _c, _c = nvme_mi_next_ctrl(ep, c)) /** * nvme_mi_open_mctp() - Create an endpoint using a MCTP connection. * @root: root object to create under * @netid: MCTP network ID on this system * @eid: MCTP endpoint ID * * Transport-specific endpoint initialization for MI-connected endpoints. Once * an endpoint is created, the rest of the API is transport-independent. * * Return: New endpoint object for @netid & @eid, or NULL on failure. * * See &nvme_mi_close */ nvme_mi_ep_t nvme_mi_open_mctp(nvme_root_t root, unsigned int netid, uint8_t eid); /** * nvme_mi_close() - Close an endpoint connection and release resources, * including controller objects. * * @ep: Endpoint object to close */ void nvme_mi_close(nvme_mi_ep_t ep); /** * nvme_mi_scan_mctp - look for MCTP-connected NVMe-MI endpoints. * * Description: This function queries the system MCTP daemon ("mctpd") over * D-Bus, to find MCTP endpoints that report support for NVMe-MI over MCTP. * * This requires libvnme-mi to be compiled with D-Bus support; if not, this * will return NULL. * * Return: A @nvme_root_t populated with a set of MCTP-connected endpoints, * or NULL on failure */ nvme_root_t nvme_mi_scan_mctp(void); /** * nvme_mi_scan_ep - query an endpoint for its NVMe controllers. * @ep: Endpoint to scan * @force_rescan: close existing controllers and rescan * * This function queries an MI endpoint for the controllers available, by * performing an MI Read MI Data Structure command (requesting the * controller list). The controllers are stored in the endpoint's internal * list, and can be iterated with nvme_mi_for_each_ctrl. * * This will only scan the endpoint once, unless @force_rescan is set. If * so, all existing controller objects will be freed - the caller must not * hold a reference to those across this call. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &nvme_mi_for_each_ctrl */ int nvme_mi_scan_ep(nvme_mi_ep_t ep, bool force_rescan); /** * nvme_mi_init_ctrl() - initialise a NVMe controller. * @ep: Endpoint to create under * @ctrl_id: ID of controller to initialize. * * Create a connection to a controller behind the endpoint specified in @ep. * Controller IDs may be queried from the endpoint through * &nvme_mi_mi_read_mi_data_ctrl_list. * * Return: New controller object, or NULL on failure. * * See &nvme_mi_close_ctrl */ nvme_mi_ctrl_t nvme_mi_init_ctrl(nvme_mi_ep_t ep, __u16 ctrl_id); /** * nvme_mi_close_ctrl() - free a controller * @ctrl: controller to free */ void nvme_mi_close_ctrl(nvme_mi_ctrl_t ctrl); /** * nvme_mi_ctrl_id() - get the ID of a controller * @ctrl: controller to query * * Retrieve the ID of the controller, as defined by hardware, and available * in the Identify (Controller List) data. This is the value passed to * @nvme_mi_init_ctrl, but may have been created internally via * @nvme_mi_scan_ep. * * Return: the (locally-stored) ID of this controller. */ __u16 nvme_mi_ctrl_id(nvme_mi_ctrl_t ctrl); /** * nvme_mi_endpoint_desc - Get a string describing a MI endpoint. * @ep: endpoint to describe * * Generates a human-readable string describing the endpoint, with possibly * transport-specific data. The string is allocated during the call, and the * caller is responsible for free()-ing the string. * * Return: a newly-allocated string containing the endpoint description, or * NULL on failure. */ char *nvme_mi_endpoint_desc(nvme_mi_ep_t ep); /* MI Command API: nvme_mi_mi_ prefix */ /** * nvme_mi_mi_read_mi_data_subsys() - Perform a Read MI Data Structure command, * retrieving subsystem data. * @ep: endpoint for MI communication * @s: subsystem information to populate * * Retrieves the Subsystem information - number of external ports and * NVMe version information. See &struct nvme_mi_read_nvm_ss_info. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ int nvme_mi_mi_read_mi_data_subsys(nvme_mi_ep_t ep, struct nvme_mi_read_nvm_ss_info *s); /** * nvme_mi_mi_read_mi_data_port() - Perform a Read MI Data Structure command, * retrieving port data. * @ep: endpoint for MI communication * @portid: id of port data to retrieve * @p: port information to populate * * Retrieves the Port information, for the specified port ID. The subsystem * data (from &nvme_mi_mi_read_mi_data_subsys) nmp field contains the allowed * range of port IDs. * * See &struct nvme_mi_read_port_info. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ int nvme_mi_mi_read_mi_data_port(nvme_mi_ep_t ep, __u8 portid, struct nvme_mi_read_port_info *p); /** * nvme_mi_mi_read_mi_data_ctrl_list() - Perform a Read MI Data Structure * command, retrieving the list of attached controllers. * @ep: endpoint for MI communication * @start_ctrlid: starting controller ID * @list: controller list to populate * * Retrieves the list of attached controllers, with IDs greater than or * equal to @start_ctrlid. * * See &struct nvme_ctrl_list. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ int nvme_mi_mi_read_mi_data_ctrl_list(nvme_mi_ep_t ep, __u8 start_ctrlid, struct nvme_ctrl_list *list); /** * nvme_mi_mi_read_mi_data_ctrl() - Perform a Read MI Data Structure command, * retrieving controller information * @ep: endpoint for MI communication * @ctrl_id: ID of controller to query * @ctrl: controller data to populate * * Retrieves the Controller Information Data Structure for the attached * controller with ID @ctrlid. * * See &struct nvme_mi_read_ctrl_info. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ int nvme_mi_mi_read_mi_data_ctrl(nvme_mi_ep_t ep, __u16 ctrl_id, struct nvme_mi_read_ctrl_info *ctrl); /** * nvme_mi_mi_subsystem_health_status_poll() - Read the Subsystem Health * Data Structure from the NVM subsystem * @ep: endpoint for MI communication * @clear: flag to clear the Composite Controller Status state * @nshds: subsystem health status data to populate * * Retrieves the Subsystem Health Data Structure into @nshds. If @clear is * set, requests that the Composite Controller Status bits are cleared after * the read. See NVMe-MI section 5.6 for details on the CCS bits. * * See &struct nvme_mi_nvm_ss_health_status. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ int nvme_mi_mi_subsystem_health_status_poll(nvme_mi_ep_t ep, bool clear, struct nvme_mi_nvm_ss_health_status *nshds); /** * nvme_mi_mi_config_get - query a configuration parameter * @ep: endpoint for MI communication * @dw0: management doubleword 0, containing configuration identifier, plus * config-specific fields * @dw1: management doubleword 0, config-specific. * @nmresp: set to queried configuration data in NMRESP field of response. * * Performs a MI Configuration Get command, with the configuration identifier * as the LSB of @dw0. Other @dw0 and @dw1 data is configuration-identifier * specific. * * On a successful Configuration Get, the @nmresp pointer will be populated with * the bytes from the 3-byte NMRESP field, converted to native endian. * * See &enum nvme_mi_config_id for identifiers. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ int nvme_mi_mi_config_get(nvme_mi_ep_t ep, __u32 dw0, __u32 dw1, __u32 *nmresp); /** * nvme_mi_mi_config_set - set a configuration parameter * @ep: endpoint for MI communication * @dw0: management doubleword 0, containing configuration identifier, plus * config-specific fields * @dw1: management doubleword 0, config-specific. * * Performs a MI Configuration Set command, with the command as the LSB of * @dw0. Other @dw0 and @dw1 data is configuration-identifier specific. * * See &enum nvme_mi_config_id for identifiers. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ int nvme_mi_mi_config_set(nvme_mi_ep_t ep, __u32 dw0, __u32 dw1); /** * nvme_mi_mi_config_get_smbus_freq - get configuration: SMBus port frequency * @ep: endpoint for MI communication * @port: port ID to query * @freq: output value for current frequency configuration * * Performs a MI Configuration Get, to query the current SMBus frequency of * the port specified in @port. On success, populates @freq with the port * frequency * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ static inline int nvme_mi_mi_config_get_smbus_freq(nvme_mi_ep_t ep, __u8 port, enum nvme_mi_config_smbus_freq *freq) { __u32 tmp, dw0; int rc; dw0 = port << 24 | NVME_MI_CONFIG_SMBUS_FREQ; rc = nvme_mi_mi_config_get(ep, dw0, 0, &tmp); if (!rc) *freq = (enum nvme_mi_config_smbus_freq)(tmp & 0x3); return rc; } /** * nvme_mi_mi_config_set_smbus_freq - set configuration: SMBus port frequency * @ep: endpoint for MI communication * @port: port ID to set * @freq: new frequency configuration * * Performs a MI Configuration Set, to update the current SMBus frequency of * the port specified in @port. * * See &struct nvme_mi_read_port_info for the maximum supported SMBus frequency * for the port. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ static inline int nvme_mi_mi_config_set_smbus_freq(nvme_mi_ep_t ep, __u8 port, enum nvme_mi_config_smbus_freq freq) { __u32 dw0 = port << 24 | (freq & 0x3) << 8 | NVME_MI_CONFIG_SMBUS_FREQ; return nvme_mi_mi_config_set(ep, dw0, 0); } /** * nvme_mi_mi_config_set_health_status_change - clear CCS bits in health status * @ep: endpoint for MI communication * @mask: bitmask to clear * * Performs a MI Configuration Set, to update the current health status poll * values of the Composite Controller Status bits. Bits set in @mask will * be cleared from future health status poll data, and may be re-triggered by * a future health change event. * * See &nvme_mi_mi_subsystem_health_status_poll(), &enum nvme_mi_ccs for * values in @mask. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ static inline int nvme_mi_mi_config_set_health_status_change(nvme_mi_ep_t ep, __u32 mask) { return nvme_mi_mi_config_set(ep, NVME_MI_CONFIG_HEALTH_STATUS_CHANGE, mask); } /** * nvme_mi_mi_config_get_mctp_mtu - get configuration: MCTP MTU * @ep: endpoint for MI communication * @port: port ID to query * @mtu: output value for current MCTP MTU configuration * * Performs a MI Configuration Get, to query the current MCTP Maximum * Transmission Unit size (MTU) of the port specified in @port. On success, * populates @mtu with the MTU. * * The default reset value is 64, corresponding to the MCTP baseline MTU. * * Some controllers may also use this as the maximum receive unit size, and * may not accept MCTP messages larger than the configured MTU. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ static inline int nvme_mi_mi_config_get_mctp_mtu(nvme_mi_ep_t ep, __u8 port, __u16 *mtu) { __u32 tmp, dw0; int rc; dw0 = port << 24 | NVME_MI_CONFIG_MCTP_MTU; rc = nvme_mi_mi_config_get(ep, dw0, 0, &tmp); if (!rc) *mtu = tmp & 0xffff; return rc; } /** * nvme_mi_mi_config_set_mctp_mtu - set configuration: MCTP MTU * @ep: endpoint for MI communication * @port: port ID to set * @mtu: new MTU configuration * * Performs a MI Configuration Set, to update the current MCTP MTU value for * the port specified in @port. * * Some controllers may also use this as the maximum receive unit size, and * may not accept MCTP messages larger than the configured MTU. When setting * this value, you will likely need to change the MTU of the local MCTP * interface(s) to match. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ static inline int nvme_mi_mi_config_set_mctp_mtu(nvme_mi_ep_t ep, __u8 port, __u16 mtu) { __u32 dw0 = port << 24 | NVME_MI_CONFIG_MCTP_MTU; return nvme_mi_mi_config_set(ep, dw0, mtu); } /* Admin channel functions */ /** * nvme_mi_admin_xfer() - Raw admin transfer interface. * @ctrl: controller to send the admin command to * @admin_req: request data * @req_data_size: size of request data payload * @admin_resp: buffer for response data * @resp_data_offset: offset into request data to retrieve from controller * @resp_data_size: size of response data buffer, updated to received size * * Performs an arbitrary NVMe Admin command, using the provided request data, * in @admin_req. The size of the request data *payload* is specified in * @req_data_size - this does not include the standard header length (so a * header-only request would have a size of 0). * * On success, response data is stored in @admin_resp, which has an optional * appended payload buffer of @resp_data_size bytes. The actual payload * transferred will be stored in @resp_data_size. These sizes do not include * the Admin request header, so 0 represents no payload. * * As with all Admin commands, we can request partial data from the Admin * Response payload, offset by @resp_data_offset. * * See: &struct nvme_mi_admin_req_hdr and &struct nvme_mi_admin_resp_hdr. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise.. */ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl, struct nvme_mi_admin_req_hdr *admin_req, size_t req_data_size, struct nvme_mi_admin_resp_hdr *admin_resp, off_t resp_data_offset, size_t *resp_data_size); /** * nvme_mi_admin_admin_passthru() - Submit an nvme admin passthrough command * @ctrl: Controller to send command to * @opcode: The nvme admin command to send * @flags: NVMe command flags (not used) * @rsvd: Reserved for future use * @nsid: Namespace identifier * @cdw2: Command dword 2 * @cdw3: Command dword 3 * @cdw10: Command dword 10 * @cdw11: Command dword 11 * @cdw12: Command dword 12 * @cdw13: Command dword 13 * @cdw14: Command dword 14 * @cdw15: Command dword 15 * @data_len: Length of the data transferred in this command in bytes * @data: Pointer to user address of the data buffer * @metadata_len:Length of metadata transferred in this command(not used) * @metadata: Pointer to user address of the metadata buffer(not used) * @timeout_ms: How long to wait for the command to complete * @result: Optional field to return the result from the CQE dword 0 * * Send a customized NVMe Admin command request message and get the corresponding * response message. * * This interface supports no data, host to controller and controller to * host but it doesn't support bidirectional data transfer. * Also this interface only supports data transfer size range [0, 4096] (bytes) * so the & data_len parameter must be less than 4097. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15, __u32 data_len, void *data, __u32 metadata_len, void *metadata, __u32 timeout_ms, __u32 *result); /** * nvme_mi_admin_identify_partial() - Perform an Admin identify command, * and retrieve partial response data. * @ctrl: Controller to process identify command * @args: Identify command arguments * @offset: offset of identify data to retrieve from response * @size: size of identify data to return * * Perform an Identify command, using the Identify command parameters in @args. * The @offset and @size arguments allow the caller to retrieve part of * the identify response. See NVMe-MI section 6.2 for the semantics (and some * handy diagrams) of the offset & size parameters. * * Will return an error if the length of the response data (from the controller) * did not match @size. * * Unless you're performing a vendor-unique identify command, You'll probably * want to use one of the identify helpers (nvme_mi_admin_identify, * nvme_mi_admin_identify_cns_nsid, or nvme_mi_admin_identify_) instead * of this. If the type of your identify command is standardized but not * yet supported by libnvme-mi, please contact the maintainers. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_identify_args */ int nvme_mi_admin_identify_partial(nvme_mi_ctrl_t ctrl, struct nvme_identify_args *args, off_t offset, size_t size); /** * nvme_mi_admin_identify() - Perform an Admin identify command. * @ctrl: Controller to process identify command * @args: Identify command arguments * * Perform an Identify command, using the Identify command parameters in @args. * Stores the identify data in ->data, and (if set) the result from cdw0 * into args->result. * * Will return an error if the length of the response data (from the * controller) is not a full &NVME_IDENTIFY_DATA_SIZE. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_identify_args */ static inline int nvme_mi_admin_identify(nvme_mi_ctrl_t ctrl, struct nvme_identify_args *args) { return nvme_mi_admin_identify_partial(ctrl, args, 0, NVME_IDENTIFY_DATA_SIZE); } /** * nvme_mi_control() - Perform a Control Primitive command * @ep: endpoint for MI communication * @opcode: Control Primitive opcode (using &enum nvme_mi_control_opcode) * @cpsp: Control Primitive Specific Parameter * @result_cpsr: Optional field to return the result from the CPSR field * * Perform a Control Primitive command, using the opcode specified in @opcode * Stores the result from the CPSR field in @result_cpsr if set. * * Return: 0 on success, non-zero on failure * * See: &enum nvme_mi_control_opcode * */ int nvme_mi_control(nvme_mi_ep_t ep, __u8 opcode, __u16 cpsp, __u16 *result_cpsr); /** * nvme_mi_admin_identify_cns_nsid() - Perform an Admin identify command using * specific CNS/NSID parameters. * @ctrl: Controller to process identify command * @cns: Controller or Namespace Structure, specifying identified object * @nsid: namespace ID * @data: buffer for identify data response * * Perform an Identify command, using the CNS specifier @cns, and the * namespace ID @nsid if required by the CNS type. * * Stores the identify data in @data, which is expected to be a buffer of * &NVME_IDENTIFY_DATA_SIZE bytes. * * Will return an error if the length of the response data (from the * controller) is not a full &NVME_IDENTIFY_DATA_SIZE. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_identify_cns_nsid(nvme_mi_ctrl_t ctrl, enum nvme_identify_cns cns, __u32 nsid, void *data) { struct nvme_identify_args args = { .result = NULL, .data = data, .args_size = sizeof(args), .cns = cns, .csi = NVME_CSI_NVM, .nsid = nsid, .cntid = NVME_CNTLID_NONE, .cns_specific_id = NVME_CNSSPECID_NONE, .uuidx = NVME_UUID_NONE, }; return nvme_mi_admin_identify(ctrl, &args); } /** * nvme_mi_admin_identify_ns() - Perform an Admin identify command for a * namespace * @ctrl: Controller to process identify command * @nsid: namespace ID * @ns: Namespace identification to populate * * Perform an Identify (namespace) command, setting the namespace id data * in @ns. The namespace is expected to active and allocated. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_identify_ns(nvme_mi_ctrl_t ctrl, __u32 nsid, struct nvme_id_ns *ns) { return nvme_mi_admin_identify_cns_nsid(ctrl, NVME_IDENTIFY_CNS_NS, nsid, ns); } /** * nvme_mi_admin_identify_ns_descs() - Perform an Admin identify Namespace * Identification Descriptor list command for a namespace * @ctrl: Controller to process identify command * @nsid: Namespace ID * @descs: Namespace Identification Descriptor list to populate * * Perform an Identify namespace identification description list command, * setting the namespace identification description list in @descs * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_identify_ns_descs(nvme_mi_ctrl_t ctrl, __u32 nsid, struct nvme_ns_id_desc *descs) { return nvme_mi_admin_identify_cns_nsid(ctrl, NVME_IDENTIFY_CNS_NS_DESC_LIST, nsid, descs); } /** * nvme_mi_admin_identify_allocated_ns() - Perform an Admin identify command * for an allocated namespace * @ctrl: Controller to process identify command * @nsid: namespace ID * @ns: Namespace identification to populate * * Perform an Identify (namespace) command, setting the namespace id data * in @ns. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_identify_allocated_ns(nvme_mi_ctrl_t ctrl, __u32 nsid, struct nvme_id_ns *ns) { return nvme_mi_admin_identify_cns_nsid(ctrl, NVME_IDENTIFY_CNS_ALLOCATED_NS, nsid, ns); } /** * nvme_mi_admin_identify_ctrl() - Perform an Admin identify for a controller * @ctrl: Controller to process identify command * @id: Controller identify data to populate * * Perform an Identify command, for the controller specified by @ctrl, * writing identify data to @id. * * Will return an error if the length of the response data (from the * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @id will be * fully populated on success. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_id_ctrl */ static inline int nvme_mi_admin_identify_ctrl(nvme_mi_ctrl_t ctrl, struct nvme_id_ctrl *id) { return nvme_mi_admin_identify_cns_nsid(ctrl, NVME_IDENTIFY_CNS_CTRL, NVME_NSID_NONE, id); } /** * nvme_mi_admin_identify_ctrl_list() - Perform an Admin identify for a * controller list. * @ctrl: Controller to process identify command * @cntid: Controller ID to specify list start * @list: List data to populate * * Perform an Identify command, for the controller list starting with * IDs greater than or equal to @cntid. * * Will return an error if the length of the response data (from the * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @id will be * fully populated on success. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_ctrl_list */ static inline int nvme_mi_admin_identify_ctrl_list(nvme_mi_ctrl_t ctrl, __u16 cntid, struct nvme_ctrl_list *list) { struct nvme_identify_args args = { .result = NULL, .data = list, .args_size = sizeof(args), .cns = NVME_IDENTIFY_CNS_CTRL_LIST, .csi = NVME_CSI_NVM, .nsid = NVME_NSID_NONE, .cntid = cntid, .cns_specific_id = NVME_CNSSPECID_NONE, .uuidx = NVME_UUID_NONE, }; return nvme_mi_admin_identify(ctrl, &args); } /** * nvme_mi_admin_identify_nsid_ctrl_list() - Perform an Admin identify for a * controller list with specific namespace ID * @ctrl: Controller to process identify command * @nsid: Namespace identifier * @cntid: Controller ID to specify list start * @list: List data to populate * * Perform an Identify command, for the controller list for @nsid, starting * with IDs greater than or equal to @cntid. * * Will return an error if the length of the response data (from the * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @id will be * fully populated on success. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_ctrl_list */ static inline int nvme_mi_admin_identify_nsid_ctrl_list(nvme_mi_ctrl_t ctrl, __u32 nsid, __u16 cntid, struct nvme_ctrl_list *list) { struct nvme_identify_args args = { .result = NULL, .data = list, .args_size = sizeof(args), .cns = NVME_IDENTIFY_CNS_NS_CTRL_LIST, .csi = NVME_CSI_NVM, .nsid = nsid, .cntid = cntid, .cns_specific_id = NVME_CNSSPECID_NONE, .uuidx = NVME_UUID_NONE, }; return nvme_mi_admin_identify(ctrl, &args); } /** * nvme_mi_admin_identify_allocated_ns_list() - Perform an Admin identify for * an allocated namespace list * @ctrl: Controller to process identify command * @nsid: Namespace ID to specify list start * @list: List data to populate * * Perform an Identify command, for the allocated namespace list starting with * IDs greater than or equal to @nsid. Specify &NVME_NSID_NONE for the start * of the list. * * Will return an error if the length of the response data (from the * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @list will be * be fully populated on success. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_ns_list */ static inline int nvme_mi_admin_identify_allocated_ns_list(nvme_mi_ctrl_t ctrl, __u32 nsid, struct nvme_ns_list *list) { struct nvme_identify_args args = { .result = NULL, .data = list, .args_size = sizeof(args), .cns = NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST, .csi = NVME_CSI_NVM, .nsid = nsid, .cns_specific_id = NVME_CNSSPECID_NONE, .uuidx = NVME_UUID_NONE, }; return nvme_mi_admin_identify(ctrl, &args); } /** * nvme_mi_admin_identify_active_ns_list() - Perform an Admin identify for an * active namespace list * @ctrl: Controller to process identify command * @nsid: Namespace ID to specify list start * @list: List data to populate * * Perform an Identify command, for the active namespace list starting with * IDs greater than or equal to @nsid. Specify &NVME_NSID_NONE for the start * of the list. * * Will return an error if the length of the response data (from the * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @list will be * be fully populated on success. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_ns_list */ static inline int nvme_mi_admin_identify_active_ns_list(nvme_mi_ctrl_t ctrl, __u32 nsid, struct nvme_ns_list *list) { struct nvme_identify_args args = { .result = NULL, .data = list, .args_size = sizeof(args), .cns = NVME_IDENTIFY_CNS_NS_ACTIVE_LIST, .csi = NVME_CSI_NVM, .nsid = nsid, .cns_specific_id = NVME_CNSSPECID_NONE, .uuidx = NVME_UUID_NONE, }; return nvme_mi_admin_identify(ctrl, &args); } /** * nvme_mi_admin_identify_primary_ctrl() - Perform an Admin identify for * primary controller capabilities data structure. * @ctrl: Controller to process identify command * @cntid: Controller ID to specify * @cap: Primary Controller Capabilities data structure to populate * * Perform an Identify command to get the Primary Controller Capabilities data * for the controller specified by @cntid * * Will return an error if the length of the response data (from the * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @cap will be * be fully populated on success. * * Return: 0 on success, non-zero on failure * * See: &struct nvme_primary_ctrl_cap */ static inline int nvme_mi_admin_identify_primary_ctrl(nvme_mi_ctrl_t ctrl, __u16 cntid, struct nvme_primary_ctrl_cap *cap) { struct nvme_identify_args args = { .result = NULL, .data = cap, .args_size = sizeof(args), .cns = NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP, .csi = NVME_CSI_NVM, .nsid = NVME_NSID_NONE, .cntid = cntid, .cns_specific_id = NVME_CNSSPECID_NONE, .uuidx = NVME_UUID_NONE, }; return nvme_mi_admin_identify(ctrl, &args); } /** * nvme_mi_admin_identify_secondary_ctrl_list() - Perform an Admin identify for * a secondary controller list. * @ctrl: Controller to process identify command * @cntid: Controller ID to specify list start * @list: List data to populate * * Perform an Identify command, for the secondary controllers associated with * the current primary controller. Only entries with IDs greater than or * equal to @cntid are returned. * * Will return an error if the length of the response data (from the * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @list will be * be fully populated on success. * * Return: 0 on success, non-zero on failure * * See: &struct nvme_secondary_ctrl_list */ static inline int nvme_mi_admin_identify_secondary_ctrl_list(nvme_mi_ctrl_t ctrl, __u16 cntid, struct nvme_secondary_ctrl_list *list) { struct nvme_identify_args args = { .result = NULL, .data = list, .args_size = sizeof(args), .cns = NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST, .csi = NVME_CSI_NVM, .nsid = NVME_NSID_NONE, .cntid = cntid, .cns_specific_id = NVME_CNSSPECID_NONE, .uuidx = NVME_UUID_NONE, }; return nvme_mi_admin_identify(ctrl, &args); } /** * nvme_mi_admin_get_log_page() - Retrieve log page data from controller * @ctrl: Controller to query * @xfer_len: The chunk size of the read * @args: Get Log Page command arguments * * Performs a Get Log Page Admin command as specified by @args. Response data * is stored in @args->data, which should be a buffer of @args->data_len bytes. * Resulting data length is stored in @args->data_len on successful * command completion. * * This request may be implemented as multiple log page commands, in order * to fit within MI message-size limits. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_get_log_args */ int nvme_mi_admin_get_log_page(nvme_mi_ctrl_t ctrl, __u32 xfer_len, struct nvme_get_log_args *args); /** * nvme_mi_admin_get_log() - Retrieve log page data from controller * @ctrl: Controller to query * @args: Get Log Page command arguments * * Performs a Get Log Page Admin command as specified by @args. Response data * is stored in @args->data, which should be a buffer of @args->data_len bytes. * Resulting data length is stored in @args->data_len on successful * command completion. * * This request may be implemented as multiple log page commands, in order * to fit within MI message-size limits. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_get_log_args */ int nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, struct nvme_get_log_args *args); /** * nvme_mi_admin_get_nsid_log() - Helper for Get Log Page functions * @ctrl: Controller to query * @rae: Retain Asynchronous Events * @lid: Log identifier * @nsid: Namespace ID * @len: length of log buffer * @log: pointer for resulting log data * * Performs a Get Log Page Admin command for a specific log ID @lid and * namespace ID @nsid. Log data is expected to be @len bytes, and is stored * in @log on success. The @rae flag is passed as-is to the Get Log Page * command, and is specific to the Log Page requested. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_nsid_log(nvme_mi_ctrl_t ctrl, bool rae, enum nvme_cmd_get_log_lid lid, __u32 nsid, __u32 len, void *log) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = log, .args_size = sizeof(args), .lid = lid, .len = len, .nsid = nsid, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = rae, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_simple() - Helper for Get Log Page functions with no * NSID or RAE requirements * @ctrl: Controller to query * @lid: Log identifier * @len: length of log buffer * @log: pointer for resulting log data * * Performs a Get Log Page Admin command for a specific log ID @lid, using * NVME_NSID_ALL for the namespace identifier, and rae set to false. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_simple(nvme_mi_ctrl_t ctrl, enum nvme_cmd_get_log_lid lid, __u32 len, void *log) { return nvme_mi_admin_get_nsid_log(ctrl, false, lid, NVME_NSID_ALL, len, log); } /** * nvme_mi_admin_get_log_supported_log_pages() - Retrieve nmve supported log * pages * @ctrl: Controller to query * @rae: Retain asynchronous events * @log: Array of LID supported and Effects data structures * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_supported_log_pages(nvme_mi_ctrl_t ctrl, bool rae, struct nvme_supported_log_pages *log) { return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_SUPPORTED_LOG_PAGES, NVME_NSID_ALL, sizeof(*log), log); } /** * nvme_mi_admin_get_log_error() - Retrieve nvme error log * @ctrl: Controller to query * @nr_entries: Number of error log entries allocated * @rae: Retain asynchronous events * @err_log: Array of error logs of size 'entries' * * This log page describes extended error information for a command that * completed with error, or may report an error that is not specific to a * particular command. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_error(nvme_mi_ctrl_t ctrl, unsigned int nr_entries, bool rae, struct nvme_error_log_page *err_log) { return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_ERROR, NVME_NSID_ALL, sizeof(*err_log) * nr_entries, err_log); } /** * nvme_mi_admin_get_log_smart() - Retrieve nvme smart log * @ctrl: Controller to query * @nsid: Optional namespace identifier * @rae: Retain asynchronous events * @smart_log: User address to store the smart log * * This log page provides SMART and general health information. The information * provided is over the life of the controller and is retained across power * cycles. To request the controller log page, the namespace identifier * specified is FFFFFFFFh. The controller may also support requesting the log * page on a per namespace basis, as indicated by bit 0 of the LPA field in the * Identify Controller data structure. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_smart(nvme_mi_ctrl_t ctrl, __u32 nsid, bool rae, struct nvme_smart_log *smart_log) { return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_SMART, nsid, sizeof(*smart_log), smart_log); } /** * nvme_mi_admin_get_log_fw_slot() - Retrieves the controller firmware log * @ctrl: Controller to query * @rae: Retain asynchronous events * @fw_log: User address to store the log page * * This log page describes the firmware revision stored in each firmware slot * supported. The firmware revision is indicated as an ASCII string. The log * page also indicates the active slot number. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_fw_slot(nvme_mi_ctrl_t ctrl, bool rae, struct nvme_firmware_slot *fw_log) { return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_FW_SLOT, NVME_NSID_ALL, sizeof(*fw_log), fw_log); } /** * nvme_mi_admin_get_log_changed_ns_list() - Retrieve namespace changed list * @ctrl: Controller to query * @rae: Retain asynchronous events * @ns_log: User address to store the log page * * This log page describes namespaces attached to this controller that have * changed since the last time the namespace was identified, been added, or * deleted. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_changed_ns_list(nvme_mi_ctrl_t ctrl, bool rae, struct nvme_ns_list *ns_log) { return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_CHANGED_NS, NVME_NSID_ALL, sizeof(*ns_log), ns_log); } /** * nvme_mi_admin_get_log_cmd_effects() - Retrieve nvme command effects log * @ctrl: Controller to query * @csi: Command Set Identifier * @effects_log: User address to store the effects log * * This log page describes the commands that the controller supports and the * effects of those commands on the state of the NVM subsystem. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_cmd_effects(nvme_mi_ctrl_t ctrl, enum nvme_csi csi, struct nvme_cmd_effects_log *effects_log) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = effects_log, .args_size = sizeof(args), .lid = NVME_LOG_LID_CMD_EFFECTS, .len = sizeof(*effects_log), .nsid = NVME_NSID_ALL, .csi = csi, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_device_self_test() - Retrieve the device self test log * @ctrl: Controller to query * @log: Userspace address of the log payload * * The log page indicates the status of an in progress self test and the * percent complete of that operation, and the results of the previous 20 * self-test operations. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_device_self_test(nvme_mi_ctrl_t ctrl, struct nvme_self_test_log *log) { return nvme_mi_admin_get_nsid_log(ctrl, false, NVME_LOG_LID_DEVICE_SELF_TEST, NVME_NSID_ALL, sizeof(*log), log); } /** * nvme_mi_admin_get_log_create_telemetry_host() - Create host telemetry log * @ctrl: Controller to query * @log: Userspace address of the log payload * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_create_telemetry_host(nvme_mi_ctrl_t ctrl, struct nvme_telemetry_log *log) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_TELEMETRY_HOST, .len = sizeof(*log), .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_TELEM_HOST_LSP_CREATE, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_telemetry_host() - Get Telemetry Host-Initiated log * page * @ctrl: Controller to query * @offset: Offset into the telemetry data * @len: Length of provided user buffer to hold the log data in bytes * @log: User address for log page data * * Retrieves the Telemetry Host-Initiated log page at the requested offset * using the previously existing capture. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_telemetry_host(nvme_mi_ctrl_t ctrl, __u64 offset, __u32 len, void *log) { struct nvme_get_log_args args = { .lpo = offset, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_TELEMETRY_HOST, .len = len, .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_TELEM_HOST_LSP_RETAIN, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_telemetry_ctrl() - Get Telemetry Controller-Initiated * log page * @ctrl: Controller to query * @rae: Retain asynchronous events * @offset: Offset into the telemetry data * @len: Length of provided user buffer to hold the log data in bytes * @log: User address for log page data * * Retrieves the Telemetry Controller-Initiated log page at the requested offset * using the previously existing capture. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_telemetry_ctrl(nvme_mi_ctrl_t ctrl, bool rae, __u64 offset, __u32 len, void *log) { struct nvme_get_log_args args = { .lpo = offset, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_TELEMETRY_CTRL, .len = len, .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = rae, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_endurance_group() - Get Endurance Group log * @ctrl: Controller to query * @endgid: Starting group identifier to return in the list * @log: User address to store the endurance log * * This log page indicates if an Endurance Group Event has occurred for a * particular Endurance Group. If an Endurance Group Event has occurred, the * details of the particular event are included in the Endurance Group * Information log page for that Endurance Group. An asynchronous event is * generated when an entry for an Endurance Group is newly added to this log * page. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_endurance_group(nvme_mi_ctrl_t ctrl, __u16 endgid, struct nvme_endurance_group_log *log) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_ENDURANCE_GROUP, .len = sizeof(*log), .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = endgid, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_predictable_lat_nvmset() - Predictable Latency Per NVM * Set * @ctrl: Controller to query * @nvmsetid: NVM set id * @log: User address to store the predictable latency log * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_predictable_lat_nvmset(nvme_mi_ctrl_t ctrl, __u16 nvmsetid, struct nvme_nvmset_predictable_lat_log *log) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_PREDICTABLE_LAT_NVMSET, .len = sizeof(*log), .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = nvmsetid, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_predictable_lat_event() - Retrieve Predictable Latency * Event Aggregate Log Page * @ctrl: Controller to query * @rae: Retain asynchronous events * @offset: Offset into the predictable latency event * @len: Length of provided user buffer to hold the log data in bytes * @log: User address for log page data * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_predictable_lat_event(nvme_mi_ctrl_t ctrl, bool rae, __u32 offset, __u32 len, void *log) { struct nvme_get_log_args args = { .lpo = offset, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_PREDICTABLE_LAT_AGG, .len = len, .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = rae, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_ana() - Retrieve Asymmetric Namespace Access log page * @ctrl: Controller to query * @lsp: Log specific, see &enum nvme_get_log_ana_lsp * @rae: Retain asynchronous events * @offset: Offset to the start of the log page * @len: The allocated length of the log page * @log: User address to store the ana log * * This log consists of a header describing the log and descriptors containing * the asymmetric namespace access information for ANA Groups that contain * namespaces that are attached to the controller processing the command. * * See &struct nvme_ana_log for the definition of the returned structure. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_ana(nvme_mi_ctrl_t ctrl, enum nvme_log_ana_lsp lsp, bool rae, __u64 offset, __u32 len, void *log) { struct nvme_get_log_args args = { .lpo = offset, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_ANA, .len = len, .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = (__u8)lsp, .uuidx = NVME_UUID_NONE, .rae = rae, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_ana_groups() - Retrieve Asymmetric Namespace Access * groups only log page * @ctrl: Controller to query * @rae: Retain asynchronous events * @len: The allocated length of the log page * @log: User address to store the ana group log * * See &struct nvme_ana_group_desc for the definition of the returned structure. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_ana_groups(nvme_mi_ctrl_t ctrl, bool rae, __u32 len, struct nvme_ana_group_desc *log) { return nvme_mi_admin_get_log_ana(ctrl, NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY, rae, 0, len, log); } /** * nvme_mi_admin_get_ana_log_atomic() - Retrieve Asymmetric Namespace Access * log page atomically * @ctrl: Controller to query * @rgo: Whether to retrieve ANA groups only (no NSIDs) * @rae: Whether to retain asynchronous events * @retries: The maximum number of times to retry on log page changes * @log: Pointer to a buffer to receive the ANA log page * @len: Input: the length of the log page buffer. * Output: the actual length of the ANA log page. * * See &struct nvme_ana_log for the definition of the returned structure. * * Return: If successful, returns 0 and sets *len to the actual log page length. * If unsuccessful, returns the nvme command status if a response was received * (see &enum nvme_status_field) or -1 with errno set otherwise. * Sets errno = EINVAL if retries == 0. * Sets errno = EAGAIN if unable to read the log page atomically * because chgcnt changed during each of the retries attempts. * Sets errno = ENOSPC if the full log page does not fit in the provided buffer. */ int nvme_mi_admin_get_ana_log_atomic(nvme_mi_ctrl_t ctrl, bool rgo, bool rae, unsigned int retries, struct nvme_ana_log *log, __u32 *len); /** * nvme_mi_admin_get_log_lba_status() - Retrieve LBA Status * @ctrl: Controller to query * @rae: Retain asynchronous events * @offset: Offset to the start of the log page * @len: The allocated length of the log page * @log: User address to store the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_lba_status(nvme_mi_ctrl_t ctrl, bool rae, __u64 offset, __u32 len, void *log) { struct nvme_get_log_args args = { .lpo = offset, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_LBA_STATUS, .len = len, .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = rae, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_endurance_grp_evt() - Retrieve Rotational Media * Information * @ctrl: Controller to query * @rae: Retain asynchronous events * @offset: Offset to the start of the log page * @len: The allocated length of the log page * @log: User address to store the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_endurance_grp_evt(nvme_mi_ctrl_t ctrl, bool rae, __u32 offset, __u32 len, void *log) { struct nvme_get_log_args args = { .lpo = offset, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_ENDURANCE_GRP_EVT, .len = len, .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = rae, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_fid_supported_effects() - Retrieve Feature Identifiers * Supported and Effects * @ctrl: Controller to query * @rae: Retain asynchronous events * @log: FID Supported and Effects data structure * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_fid_supported_effects(nvme_mi_ctrl_t ctrl, bool rae, struct nvme_fid_supported_effects_log *log) { return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_FID_SUPPORTED_EFFECTS, NVME_NSID_NONE, sizeof(*log), log); } /** * nvme_mi_admin_get_log_mi_cmd_supported_effects() - displays the MI Commands * Supported by the controller * @ctrl: Controller to query * @rae: Retain asynchronous events * @log: MI Command Supported and Effects data structure * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_mi_cmd_supported_effects(nvme_mi_ctrl_t ctrl, bool rae, struct nvme_mi_cmd_supported_effects_log *log) { return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS, NVME_NSID_NONE, sizeof(*log), log); } /** * nvme_mi_admin_get_log_boot_partition() - Retrieve Boot Partition * @ctrl: Controller to query * @rae: Retain asynchronous events * @lsp: The log specified field of LID * @len: The allocated size, minimum * struct nvme_boot_partition * @part: User address to store the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_boot_partition(nvme_mi_ctrl_t ctrl, bool rae, __u8 lsp, __u32 len, struct nvme_boot_partition *part) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = part, .args_size = sizeof(args), .lid = NVME_LOG_LID_BOOT_PARTITION, .len = len, .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = rae, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_phy_rx_eom() - Retrieve Physical Interface Receiver Eye Opening Measurement Log * @ctrl: Controller to query * @lsp: Log specific, controls action and measurement quality * @controller: Target controller ID * @len: The allocated size, minimum * struct nvme_phy_rx_eom_log * @log: User address to store the log page * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise */ static inline int nvme_mi_admin_get_log_phy_rx_eom(nvme_mi_ctrl_t ctrl, __u8 lsp, __u16 controller, __u32 len, struct nvme_phy_rx_eom_log *log) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_PHY_RX_EOM, .len = len, .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = controller, .lsp = lsp, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_discovery() - Retrieve Discovery log page * @ctrl: Controller to query * @rae: Retain asynchronous events * @offset: Offset of this log to retrieve * @len: The allocated size for this portion of the log * @log: User address to store the discovery log * * Supported only by fabrics discovery controllers, returning discovery * records. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_discovery(nvme_mi_ctrl_t ctrl, bool rae, __u32 offset, __u32 len, void *log) { struct nvme_get_log_args args = { .lpo = offset, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_DISCOVER, .len = len, .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = rae, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_media_unit_stat() - Retrieve Media Unit Status * @ctrl: Controller to query * @domid: Domain Identifier selection, if supported * @mus: User address to store the Media Unit statistics log * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_media_unit_stat(nvme_mi_ctrl_t ctrl, __u16 domid, struct nvme_media_unit_stat_log *mus) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = mus, .args_size = sizeof(args), .lid = NVME_LOG_LID_MEDIA_UNIT_STATUS, .len = sizeof(*mus), .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = domid, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_support_cap_config_list() - Retrieve Supported * Capacity Configuration List * @ctrl: Controller to query * @domid: Domain Identifier selection, if supported * @cap: User address to store supported capabilities config list * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_support_cap_config_list(nvme_mi_ctrl_t ctrl, __u16 domid, struct nvme_supported_cap_config_list_log *cap) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = cap, .args_size = sizeof(args), .lid = NVME_LOG_LID_SUPPORTED_CAP_CONFIG_LIST, .len = sizeof(*cap), .nsid = NVME_NSID_NONE, .csi = NVME_CSI_NVM, .lsi = domid, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_reservation() - Retrieve Reservation Notification * @ctrl: Controller to query * @rae: Retain asynchronous events * @log: User address to store the reservation log * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_reservation(nvme_mi_ctrl_t ctrl, bool rae, struct nvme_resv_notification_log *log) { return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_RESERVATION, NVME_NSID_ALL, sizeof(*log), log); } /** * nvme_mi_admin_get_log_sanitize() - Retrieve Sanitize Status * @ctrl: Controller to query * @rae: Retain asynchronous events * @log: User address to store the sanitize log * * The Sanitize Status log page reports sanitize operation time estimates and * information about the most recent sanitize operation. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_sanitize(nvme_mi_ctrl_t ctrl, bool rae, struct nvme_sanitize_log_page *log) { return nvme_mi_admin_get_nsid_log(ctrl, rae, NVME_LOG_LID_SANITIZE, NVME_NSID_ALL, sizeof(*log), log); } /** * nvme_mi_admin_get_log_zns_changed_zones() - Retrieve list of zones that have * changed * @ctrl: Controller to query * @nsid: Namespace ID * @rae: Retain asynchronous events * @log: User address to store the changed zone log * * The list of zones that have changed state due to an exceptional event. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_zns_changed_zones(nvme_mi_ctrl_t ctrl, __u32 nsid, bool rae, struct nvme_zns_changed_zone_log *log) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = log, .args_size = sizeof(args), .lid = NVME_LOG_LID_ZNS_CHANGED_ZONES, .len = sizeof(*log), .nsid = nsid, .csi = NVME_CSI_ZNS, .lsi = NVME_LOG_LSI_NONE, .lsp = NVME_LOG_LSP_NONE, .uuidx = NVME_UUID_NONE, .rae = rae, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_persistent_event() - Retrieve Persistent Event Log * @ctrl: Controller to query * @action: Action the controller should take during processing this command * @size: Size of @pevent_log * @pevent_log: User address to store the persistent event log * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_persistent_event(nvme_mi_ctrl_t ctrl, enum nvme_pevent_log_action action, __u32 size, void *pevent_log) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = pevent_log, .args_size = sizeof(args), .lid = NVME_LOG_LID_PERSISTENT_EVENT, .len = size, .nsid = NVME_NSID_ALL, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = (__u8)action, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_get_log_lockdown() - Retrieve lockdown Log * @ctrl: Controller to query * @cnscp: Contents and Scope of Command and Feature Identifier Lists * @lockdown_log: Buffer to store the lockdown log * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_log_lockdown(nvme_mi_ctrl_t ctrl, __u8 cnscp, struct nvme_lockdown_log *lockdown_log) { struct nvme_get_log_args args = { .lpo = 0, .result = NULL, .log = lockdown_log, .args_size = sizeof(args), .lid = NVME_LOG_LID_CMD_AND_FEAT_LOCKDOWN, .len = sizeof(*lockdown_log), .nsid = NVME_NSID_ALL, .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = cnscp, .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; return nvme_mi_admin_get_log(ctrl, &args); } /** * nvme_mi_admin_security_send() - Perform a Security Send command on a * controller. * @ctrl: Controller to send command to * @args: Security Send command arguments * * Performs a Security Send Admin command as specified by @args. Response data * is stored in @args->data, which should be a buffer of @args->data_len bytes. * Resulting data length is stored in @args->data_len on successful * command completion. * * Security Send data length should not be greater than 4096 bytes to * comply with specification limits. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_get_log_args */ int nvme_mi_admin_security_send(nvme_mi_ctrl_t ctrl, struct nvme_security_send_args *args); /** * nvme_mi_admin_security_recv() - Perform a Security Receive command on a * controller. * @ctrl: Controller to send command to * @args: Security Receive command arguments * * Performs a Security Receive Admin command as specified by @args. Response * data is stored in @args->data, which should be a buffer of @args->data_len * bytes. Resulting data length is stored in @args->data_len on successful * command completion. * * Security Receive data length should not be greater than 4096 bytes to * comply with specification limits. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. * * See: &struct nvme_get_log_args */ int nvme_mi_admin_security_recv(nvme_mi_ctrl_t ctrl, struct nvme_security_receive_args *args); /** * nvme_mi_admin_get_features - Perform a Get Feature command on a controller * @ctrl: Controller to send command to * @args: Get Features command arguments * * Performs a Get Features Admin command as specified by @args. Returned * feature data will be stored in @args->result and @args->data, depending * on the specification of the feature itself; most features do not return * additional data. See section 5.27.1 of the NVMe spec (v2.0b) for * feature-specific information. * * On success, @args->data_len will be updated with the actual data length * received. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ int nvme_mi_admin_get_features(nvme_mi_ctrl_t ctrl, struct nvme_get_features_args *args); /** * nvme_mi_admin_get_features_data() - Helper function for &nvme_mi_admin_get_features() * @ctrl: Controller to send command to * @fid: Feature identifier * @nsid: Namespace ID, if applicable for @fid * @data_len: Length of feature data, if applicable for @fid, in bytes * @data: User address of feature data, if applicable * @result: The command completion result from CQE dword0 * * Helper for optionally features that optionally return data, using the * SEL_CURRENT selector value. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_get_features_data(nvme_mi_ctrl_t ctrl, enum nvme_features_id fid, __u32 nsid, __u32 data_len, void *data, __u32 *result) { struct nvme_get_features_args args = { .result = result, .data = data, .args_size = sizeof(args), .nsid = nsid, .sel = NVME_GET_FEATURES_SEL_CURRENT, .cdw11 = 0, .data_len = data_len, .fid = (__u8)fid, .uuidx = NVME_UUID_NONE, }; return nvme_mi_admin_get_features(ctrl, &args); } /** * nvme_mi_admin_get_features_simple - Get a simple feature value with no data * @ctrl: Controller to send command to * @fid: Feature identifier * @nsid: Namespace id, if required by @fid * @result: output feature data */ static inline int nvme_mi_admin_get_features_simple(nvme_mi_ctrl_t ctrl, enum nvme_features_id fid, __u32 nsid, __u32 *result) { return nvme_mi_admin_get_features_data(ctrl, fid, nsid, 0, NULL, result); } /** * nvme_mi_admin_set_features - Perform a Set Features command on a controller * @ctrl: Controller to send command to * @args: Set Features command arguments * * Performs a Set Features Admin command as specified by @args. Result * data will be stored in @args->result. * on the specification of the feature itself; most features do not return * additional data. See section 5.27.1 of the NVMe spec (v2.0b) for * feature-specific information. * * On success, @args->data_len will be updated with the actual data length * received. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ int nvme_mi_admin_set_features(nvme_mi_ctrl_t ctrl, struct nvme_set_features_args *args); /** * nvme_mi_admin_ns_mgmt - Issue a Namespace Management command * @ctrl: Controller to send command to * @args: Namespace management command arguments * * Issues a Namespace Management command to @ctrl, with arguments specified * from @args. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl, struct nvme_ns_mgmt_args *args); /** * nvme_mi_admin_ns_mgmt_create - Helper for Namespace Management Create command * @ctrl: Controller to send command to * @ns: New namespace parameters * @csi: Command Set Identifier for new NS * @nsid: Set to new namespace ID on create * @data: Host Software Specified Fields that defines ns creation parameters * * Issues a Namespace Management (Create) command to @ctrl, to create a * new namespace specified by @ns, using command set @csi. On success, * the new namespace ID will be written to @nsid. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_ns_mgmt_create(nvme_mi_ctrl_t ctrl, struct nvme_id_ns *ns, __u8 csi, __u32 *nsid, struct nvme_ns_mgmt_host_sw_specified *data) { struct nvme_ns_mgmt_args args = { .result = nsid, .ns = ns, .args_size = sizeof(args), .nsid = NVME_NSID_NONE, .sel = NVME_NS_MGMT_SEL_CREATE, .csi = csi, .data = data, }; return nvme_mi_admin_ns_mgmt(ctrl, &args); } /** * nvme_mi_admin_ns_mgmt_delete - Helper for Namespace Management Delete command * @ctrl: Controller to send command to * @nsid: Namespace ID to delete * * Issues a Namespace Management (Delete) command to @ctrl, to delete the * namespace with id @nsid. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_ns_mgmt_delete(nvme_mi_ctrl_t ctrl, __u32 nsid) { struct nvme_ns_mgmt_args args = { .args_size = sizeof(args), .nsid = nsid, .sel = NVME_NS_MGMT_SEL_DELETE, }; return nvme_mi_admin_ns_mgmt(ctrl, &args); } /** * nvme_mi_admin_ns_attach() - Attach or detach namespace to controller(s) * @ctrl: Controller to send command to * @args: Namespace Attach command arguments * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl, struct nvme_ns_attach_args *args); /** * nvme_mi_admin_ns_attach_ctrls() - Attach namespace to controllers * @ctrl: Controller to send command to * @nsid: Namespace ID to attach * @ctrlist: Controller list to modify attachment state of nsid * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_ns_attach_ctrls(nvme_mi_ctrl_t ctrl, __u32 nsid, struct nvme_ctrl_list *ctrlist) { struct nvme_ns_attach_args args = { .result = NULL, .ctrlist = ctrlist, .args_size = sizeof(args), .nsid = nsid, .sel = NVME_NS_ATTACH_SEL_CTRL_ATTACH, }; return nvme_mi_admin_ns_attach(ctrl, &args); } /** * nvme_mi_admin_ns_detach_ctrls() - Detach namespace from controllers * @ctrl: Controller to send command to * @nsid: Namespace ID to detach * @ctrlist: Controller list to modify attachment state of nsid * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ static inline int nvme_mi_admin_ns_detach_ctrls(nvme_mi_ctrl_t ctrl, __u32 nsid, struct nvme_ctrl_list *ctrlist) { struct nvme_ns_attach_args args = { .result = NULL, .ctrlist = ctrlist, .args_size = sizeof(args), .nsid = nsid, .sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH, }; return nvme_mi_admin_ns_attach(ctrl, &args); } /** * nvme_mi_admin_fw_download() - Download part or all of a firmware image to * the controller * @ctrl: Controller to send firmware data to * @args: &struct nvme_fw_download_args argument structure * * The Firmware Image Download command downloads all or a portion of an image * for a future update to the controller. The Firmware Image Download command * downloads a new image (in whole or in part) to the controller. * * The image may be constructed of multiple pieces that are individually * downloaded with separate Firmware Image Download commands. Each Firmware * Image Download command includes a Dword Offset and Number of Dwords that * specify a dword range. * * The new firmware image is not activated as part of the Firmware Image * Download command. Use the nvme_mi_admin_fw_commit() to activate a newly * downloaded image. * * Return: 0 on success, non-zero on failure */ int nvme_mi_admin_fw_download(nvme_mi_ctrl_t ctrl, struct nvme_fw_download_args *args); /** * nvme_mi_admin_fw_commit() - Commit firmware using the specified action * @ctrl: Controller to send firmware data to * @args: &struct nvme_fw_download_args argument structure * * The Firmware Commit command modifies the firmware image or Boot Partitions. * * Return: 0 on success, non-zero on failure */ int nvme_mi_admin_fw_commit(nvme_mi_ctrl_t ctrl, struct nvme_fw_commit_args *args); /** * nvme_mi_admin_format_nvm() - Format NVMe namespace * @ctrl: Controller to send command to * @args: Format NVM command arguments * * Perform a low-level format to set the LBA data & metadata size. May destroy * data & metadata on the specified namespaces * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl, struct nvme_format_nvm_args *args); /** * nvme_mi_admin_sanitize_nvm() - Start a subsystem Sanitize operation * @ctrl: Controller to send command to * @args: Sanitize command arguments * * A sanitize operation alters all user data in the NVM subsystem such that * recovery of any previous user data from any cache, the non-volatile media, * or any Controller Memory Buffer is not possible. * * The Sanitize command starts a sanitize operation or to recover from a * previously failed sanitize operation. The sanitize operation types that may * be supported are Block Erase, Crypto Erase, and Overwrite. All sanitize * operations are processed in the background, i.e., completion of the sanitize * command does not indicate completion of the sanitize operation. * * Return: The nvme command status if a response was received (see * &enum nvme_status_field) or -1 with errno set otherwise. */ int nvme_mi_admin_sanitize_nvm(nvme_mi_ctrl_t ctrl, struct nvme_sanitize_nvm_args *args); #endif /* _LIBNVME_MI_MI_H */