// SPDX-License-Identifier: LGPL-2.1-or-later
/*
 * This file is part of libnvme.
 * Copyright (c) 2020 Western Digital Corporation or its affiliates.
 *
 * Authors: Keith Busch <keith.busch@wdc.com>
 *	    Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
 *	    Daniel Wagner <dwagner@suse.de>
 */

#pragma once

#include <nvme/lib-types.h>

/**
 * DOC: ioctl.h
 *
 * Linux NVMe ioctl interface functions
 */

/* '0' is interpreted by the kernel to mean 'apply the default timeout' */
#define NVME_DEFAULT_IOCTL_TIMEOUT 0

/*
 * 4k is the smallest possible transfer unit, so restricting to 4k
 * avoids having to check the MDTS value of the controller.
 */
#define NVME_LOG_PAGE_PDU_SIZE 4096

/**
 * struct libnvme_passthru_completion - Async passthru completion record
 * @cmd:	Command that completed
 * @cookie:	User cookie provided to libnvme_submit_*_passthru()
 * @status:	Completion status (NVMe status or negative errno)
 *
 * Used for both admin and IO passthru command completions.
 */
struct libnvme_passthru_completion {
	struct libnvme_passthru_cmd *cmd;
	void *cookie;
	int status;
};

/**
 * libnvme_submit_admin_passthru() - Queue admin passthru command
 * @hdl:	Transport handle
 * @cmd:	The nvme admin command to send
 * @cookie:	User-defined opaque value returned at completion
 *
 * Queues @cmd for asynchronous execution. Completion is reported via
 * libnvme_reap_passthru().
 *
 * Return: 0 on successful queueing, negative error code otherwise.
 */
int libnvme_submit_admin_passthru(struct libnvme_transport_handle *hdl,
		struct libnvme_passthru_cmd *cmd, void *cookie);

/**
 * libnvme_exec_admin_passthru() - Submit an admin passthru command and wait
 * @hdl:	Transport handle
 * @cmd:	The nvme admin command to send
 *
 * Synchronous command execution.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field), or negative error code otherwise.
 */
int libnvme_exec_admin_passthru(struct libnvme_transport_handle *hdl,
		struct libnvme_passthru_cmd *cmd);

/**
 * libnvme_submit_io_passthru() - Queue IO passthru command
 * @hdl:	Transport handle
 * @cmd:	The nvme IO command to send
 * @cookie:	User-defined opaque value returned at completion
 *
 * Queues @cmd for asynchronous execution. Completion is reported via
 * libnvme_reap_passthru().
 *
 * Return: 0 on successful queueing, negative error code otherwise.
 */
int libnvme_submit_io_passthru(struct libnvme_transport_handle *hdl,
		struct libnvme_passthru_cmd *cmd, void *cookie);

/**
 * libnvme_exec_io_passthru() - Submit an IO passthru command and wait
 * @hdl:	Transport handle
 * @cmd:	The nvme IO command to send
 *
 * Synchronous command execution. Note: when io_uring is enabled, this shares
 * the async queue. Avoid mixing this with direct async API usage on the same
 * handle. For batching, use the async API exclusively.
 *
 * Return: The nvme command status if a response was received (see
 * &enum nvme_status_field), or negative error code otherwise.
 */
int libnvme_exec_io_passthru(struct libnvme_transport_handle *hdl,
		struct libnvme_passthru_cmd *cmd);

/**
 * libnvme_reap_passthru() - Reap one async completion
 * @hdl:	Transport handle
 * @completion: Completion output structure
 *
 * Waits for one queued passthru command to complete and stores the
 * completed command pointer, associated cookie, and completion status in
 * @completion.
 *
 * Return: 0 on success, negative error code otherwise.
 */
int libnvme_reap_passthru(struct libnvme_transport_handle *hdl,
		struct libnvme_passthru_completion *completion);

/**
 * libnvme_wait_passthru() - Wait for all pending passthru completions
 * @hdl:	Transport handle
 *
 * Drains all pending passthru commands from the async queue. Use this
 * after batching multiple libnvme_submit_admin_passthru() calls when io_uring
 * is enabled.
 *
 * Return: 0 on success, or the first non-zero status encountered.
 */
int libnvme_wait_passthru(struct libnvme_transport_handle *hdl);

/**
 * libnvme_reset_subsystem() - Initiate a subsystem reset
 * @hdl:	Transport handle
 *
 * This should only be sent to controller handles, not to namespaces.
 *
 * Return: Zero if a subsystem reset was initiated or negative error code
 * otherwise.
 */
int libnvme_reset_subsystem(struct libnvme_transport_handle *hdl);

/**
 * libnvme_reset_ctrl() - Initiate a controller reset
 * @hdl:	Transport handle
 *
 * This should only be sent to controller handles, not to namespaces.
 *
 * Return: 0 if a reset was initiated or negative error code otherwise.
 */
int libnvme_reset_ctrl(struct libnvme_transport_handle *hdl);

/**
 * libnvme_rescan_ns() - Initiate a controller rescan
 * @hdl:	Transport handle
 *
 * This should only be sent to controller handles, not to namespaces.
 *
 * Return: 0 if a rescan was initiated or negative error code otherwise.
 */
int libnvme_rescan_ns(struct libnvme_transport_handle *hdl);

/**
 * libnvme_get_nsid() - Retrieve the NSID from a namespace file descriptor
 * @hdl:	Transport handle
 * @nsid:	User pointer to namespace id
 *
 * This should only be sent to namespace handles, not to controllers. The
 * kernel's interface returns the nsid as the return value. This is unfortunate
 * for many architectures that are incapable of allowing distinguishing a
 * namespace id > 0x80000000 from a negative error number.
 *
 * Return: 0 if @nsid was set successfully or negative error code otherwise.
 */
int libnvme_get_nsid(struct libnvme_transport_handle *hdl, __u32 *nsid);

/**
 * libnvme_update_block_size() - Update the block size
 * @hdl:	Transport handle
 * @block_size:	New block size
 *
 * Notify the kernel blkdev to update its block size after a block size change.
 * This should only be used for namespace handles, not controllers.
 *
 * Return: 0 if the block size was updated or a negative error code otherwise.
 */
int libnvme_update_block_size(struct libnvme_transport_handle *hdl,
		int block_size);
