138514Sdfr/*-
259603Sdfr * SPDX-License-Identifier: BSD-2-Clause
338514Sdfr *
438514Sdfr * Copyright (c) 2022-2024 Chelsio Communications, Inc.
538514Sdfr * Written by: John Baldwin <jhb@FreeBSD.org>
638514Sdfr */
738514Sdfr
838514Sdfr#ifndef __LIBNVMF_H__
938514Sdfr#define	__LIBNVMF_H__
1038514Sdfr
1138514Sdfr#include <sys/uio.h>
1238514Sdfr#include <stdbool.h>
1338514Sdfr#include <stddef.h>
1438514Sdfr#include <dev/nvme/nvme.h>
1538514Sdfr#include <dev/nvmf/nvmf.h>
1638514Sdfr#include <dev/nvmf/nvmf_proto.h>
1738514Sdfr
1838514Sdfrstruct nvmf_capsule;
1938514Sdfrstruct nvmf_association;
2038514Sdfrstruct nvmf_qpair;
2138514Sdfr
2238514Sdfr/*
2338514Sdfr * Parameters shared by all queue-pairs of an association.  Note that
2438514Sdfr * this contains the requested values used to initiate transport
2538514Sdfr * negotiation.
2650477Speter */
2738514Sdfrstruct nvmf_association_params {
2838514Sdfr	bool sq_flow_control;		/* SQ flow control required. */
2959603Sdfr	bool dynamic_controller_model;	/* Controller only */
3059603Sdfr	uint16_t max_admin_qsize;	/* Controller only */
3138514Sdfr	uint32_t max_io_qsize;		/* Controller only, 0 for discovery */
3276166Smarkm	union {
3338514Sdfr		struct {
3476166Smarkm			uint8_t pda;	/* Tx-side PDA. */
3538514Sdfr			bool header_digests;
3677642Sdd			bool data_digests;
3738514Sdfr			uint32_t maxr2t;	/* Host only */
3838514Sdfr			uint32_t maxh2cdata;	/* Controller only */
3938514Sdfr		} tcp;
4038514Sdfr	};
4138514Sdfr};
4276166Smarkm
4338514Sdfr/* Parameters specific to a single queue pair of an association. */
4485735Sgreenstruct nvmf_qpair_params {
4585735Sgreen	bool admin;			/* Host only */
4685735Sgreen	union {
4738514Sdfr		struct {
4839071Sdfr			int fd;
4939071Sdfr		} tcp;
5052128Speter	};
5139071Sdfr};
5239071Sdfr
5339071Sdfr/* Transport-independent APIs. */
5452128Speter
5539071Sdfr/*
5639071Sdfr * A host should allocate a new association for each association with
5776166Smarkm * a controller.  After the admin queue has been allocated and the
58102288Speter * controller's data has been fetched, it should be passed to
5939071Sdfr * nvmf_update_association to update internal transport-specific
6059603Sdfr * parameters before allocating I/O queues.
6138514Sdfr *
6238514Sdfr * A controller uses a single association to manage all incoming
6359603Sdfr * queues since it is not known until after parsing the CONNECT
6459603Sdfr * command which transport queues are admin vs I/O and which
6539071Sdfr * controller they are created against.
6639071Sdfr */
6739071Sdfrstruct nvmf_association *nvmf_allocate_association(enum nvmf_trtype trtype,
6839071Sdfr    bool controller, const struct nvmf_association_params *params);
6959603Sdfrvoid	nvmf_update_assocation(struct nvmf_association *na,
7080700Sjake    const struct nvme_controller_data *cdata);
7180700Sjakevoid	nvmf_free_association(struct nvmf_association *na);
7280700Sjake
7380700Sjake/* The most recent association-wide error message. */
7438514Sdfrconst char *nvmf_association_error(const struct nvmf_association *na);
7538514Sdfr
7640254Speter/*
7739071Sdfr * A queue pair represents either an Admin or I/O
7839071Sdfr * submission/completion queue pair.
7939071Sdfr *
8039071Sdfr * Each open qpair holds a reference on its association.  Once queue
8139071Sdfr * pairs are allocated, callers can safely free the association to
8239071Sdfr * ease bookkeeping.
8339071Sdfr *
8439071Sdfr * If nvmf_allocate_qpair fails, a detailed error message can be obtained
8539071Sdfr * from nvmf_association_error.
8639071Sdfr */
8740254Speterstruct nvmf_qpair *nvmf_allocate_qpair(struct nvmf_association *na,
8840254Speter    const struct nvmf_qpair_params *params);
8940254Spetervoid	nvmf_free_qpair(struct nvmf_qpair *qp);
9040254Speter
9140254Speter/*
9240292Speter * Capsules are either commands (host -> controller) or responses
9340292Speter * (controller -> host).  A single data buffer segment may be
9459603Sdfr * associated with a command capsule.  Transmitted data is not copied
9559603Sdfr * by this API but instead must be preserved until the capsule is
9659603Sdfr * transmitted and freed.
9738514Sdfr */
9838514Sdfrstruct nvmf_capsule *nvmf_allocate_command(struct nvmf_qpair *qp,
9959751Speter    const void *sqe);
10059751Speterstruct nvmf_capsule *nvmf_allocate_response(struct nvmf_qpair *qp,
10159751Speter    const void *cqe);
10259751Spetervoid	nvmf_free_capsule(struct nvmf_capsule *nc);
10359603Sdfrint	nvmf_capsule_append_data(struct nvmf_capsule *nc,
10459603Sdfr    void *buf, size_t len, bool send);
10559603Sdfrint	nvmf_transmit_capsule(struct nvmf_capsule *nc);
10659603Sdfrint	nvmf_receive_capsule(struct nvmf_qpair *qp, struct nvmf_capsule **ncp);
10759603Sdfrconst void *nvmf_capsule_sqe(const struct nvmf_capsule *nc);
10838514Sdfrconst void *nvmf_capsule_cqe(const struct nvmf_capsule *nc);
10959603Sdfr
11059751Speter/* Return a string name for a transport type. */
11178161Speterconst char *nvmf_transport_type(uint8_t trtype);
11278161Speter
11385736Sgreen/* Validate a NVMe Qualified Name. */
11485736Sgreenbool	nvmf_nqn_valid(const char *nqn);
11585736Sgreen
11659603Sdfr/* Controller-specific APIs. */
11759603Sdfr
11859603Sdfr/*
11959603Sdfr * A controller calls this function to check for any
12059603Sdfr * transport-specific errors (invalid fields) in a received command
12159603Sdfr * capsule.  The callback returns a generic command status value:
12259751Speter * NVME_SC_SUCCESS if no error is found.
12359751Speter */
12459751Speteruint8_t	nvmf_validate_command_capsule(const struct nvmf_capsule *nc);
12578161Speter
12685736Sgreen/*
12759603Sdfr * A controller calls this function to query the amount of data
12859603Sdfr * associated with a command capsule.
12959603Sdfr */
13059603Sdfrsize_t	nvmf_capsule_data_len(const struct nvmf_capsule *cc);
13159603Sdfr
13259603Sdfr/*
13359603Sdfr * A controller calls this function to receive data associated with a
13459603Sdfr * command capsule (e.g. the data for a WRITE command).  This can
13559603Sdfr * either return in-capsule data or fetch data from the host
13659603Sdfr * (e.g. using a R2T PDU over TCP).  The received command capsule
13759603Sdfr * should be passed in 'nc'.  The received data is stored in '*buf'.
13859603Sdfr */
13959603Sdfrint	nvmf_receive_controller_data(const struct nvmf_capsule *nc,
14059603Sdfr    uint32_t data_offset, void *buf, size_t len);
14159751Speter
14259603Sdfr/*
14359603Sdfr * A controller calls this function to send data in response to a
14466719Sjhb * command along with a response capsule.  If the data transfer
14566719Sjhb * succeeds, a success response is sent.  If the data transfer fails,
14659603Sdfr * an appropriate error status capsule is sent.  Regardless, a
14738514Sdfr * response capsule is always sent.
14859603Sdfr */
14959603Sdfrint	nvmf_send_controller_data(const struct nvmf_capsule *nc,
15059603Sdfr    const void *buf, size_t len);
15159603Sdfr
15266719Sjhb/*
15359603Sdfr * Construct a CQE for a reply to a command capsule in 'nc' with the
15459603Sdfr * completion status 'status'.  This is useful when additional CQE
15559603Sdfr * info is required beyond the completion status.
15659603Sdfr */
157104094Sphkvoid	nvmf_init_cqe(void *cqe, const struct nvmf_capsule *nc,
15866719Sjhb    uint16_t status);
15966719Sjhb
16059603Sdfr/*
16159603Sdfr * Construct and send a response capsule to a command capsule with
16259603Sdfr * the supplied CQE.
16359603Sdfr */
16459603Sdfrint	nvmf_send_response(const struct nvmf_capsule *nc, const void *cqe);
16595228Smarcel
16695228Smarcel/*
16795228Smarcel * Wait for a single command capsule and return it in *ncp.  This can
16895228Smarcel * fail if an invalid capsule is received or an I/O error occurs.
16959603Sdfr */
17038514Sdfrint	nvmf_controller_receive_capsule(struct nvmf_qpair *qp,
17138514Sdfr    struct nvmf_capsule **ncp);
17238514Sdfr
17338514Sdfr/* Send a response capsule from a controller. */
17438514Sdfrint	nvmf_controller_transmit_response(struct nvmf_capsule *nc);
17538514Sdfr
17638514Sdfr/* Construct and send an error response capsule. */
17740156Speterint	nvmf_send_error(const struct nvmf_capsule *cc, uint8_t sc_type,
17840156Speter    uint8_t sc_status);
17940156Speter
18040156Speter/*
18181500Swpaul * Construct and send an error response capsule using a generic status
18281500Swpaul * code.
18340156Speter */
18438514Sdfrint	nvmf_send_generic_error(const struct nvmf_capsule *nc,
18559603Sdfr    uint8_t sc_status);
18638514Sdfr
18740156Speter/* Construct and send a simple success response capsule. */
18882848Speterint	nvmf_send_success(const struct nvmf_capsule *nc);
18982848Speter
19082848Speter/*
19182848Speter * Allocate a new queue pair and wait for the CONNECT command capsule.
19282848Speter * If this fails, a detailed error message can be obtained from
19382848Speter * nvmf_association_error.  On success, the command capsule is saved
19482848Speter * in '*ccp' and the connect data is saved in 'data'.  The caller
19582848Speter * must send an explicit response and free the the command capsule.
19682848Speter */
19782848Speterstruct nvmf_qpair *nvmf_accept(struct nvmf_association *na,
19882848Speter    const struct nvmf_qpair_params *params, struct nvmf_capsule **ccp,
19982848Speter    struct nvmf_fabric_connect_data *data);
20082848Speter
20159603Sdfr/*
20282848Speter * Construct and send a response capsule with the Fabrics CONNECT
20359603Sdfr * invalid parameters error status.  If data is true the offset is
20482848Speter * relative to the CONNECT data structure, otherwise the offset is
20559603Sdfr * relative to the SQE.
20682848Speter */
20782848Spetervoid	nvmf_connect_invalid_parameters(const struct nvmf_capsule *cc,
20882848Speter    bool data, uint16_t offset);
20982848Speter
21040156Speter/* Construct and send a response capsule for a successful CONNECT. */
21182848Speterint	nvmf_finish_accept(const struct nvmf_capsule *cc, uint16_t cntlid);
21282848Speter
21382848Speter/* Compute the initial state of CAP for a controller. */
21482848Speteruint64_t nvmf_controller_cap(struct nvmf_qpair *qp);
21582848Speter
21682848Speter/* Generate a serial number string from a host ID. */
21782848Spetervoid	nvmf_controller_serial(char *buf, size_t len, u_long hostid);
21882848Speter
21982848Speter/*
22082848Speter * Populate an Identify Controller data structure for a Discovery
22159603Sdfr * controller.
22259603Sdfr */
22382848Spetervoid	nvmf_init_discovery_controller_data(struct nvmf_qpair *qp,
22482848Speter    struct nvme_controller_data *cdata);
22582848Speter
22682848Speter/*
22782848Speter * Populate an Identify Controller data structure for an I/O
22882848Speter * controller.
22982848Speter */
23059603Sdfrvoid	nvmf_init_io_controller_data(struct nvmf_qpair *qp, const char *serial,
23182848Speter    const char *subnqn, int nn, uint32_t ioccsz,
23282848Speter    struct nvme_controller_data *cdata);
23382848Speter
23459603Sdfr/*
23582848Speter * Validate if a new value for CC is legal given the existing values of
23659603Sdfr * CAP and CC.
23738514Sdfr */
23838514Sdfrbool	nvmf_validate_cc(struct nvmf_qpair *qp, uint64_t cap, uint32_t old_cc,
23940156Speter    uint32_t new_cc);
24038514Sdfr
24138514Sdfr/* Return the log page id (LID) of a GET_LOG_PAGE command. */
24259751Speteruint8_t	nvmf_get_log_page_id(const struct nvme_command *cmd);
24340254Speter
24440254Speter/* Return the requested data length of a GET_LOG_PAGE command. */
24540254Speteruint64_t nvmf_get_log_page_length(const struct nvme_command *cmd);
24640254Speter
24740254Speter/* Return the requested data offset of a GET_LOG_PAGE command. */
24840254Speteruint64_t nvmf_get_log_page_offset(const struct nvme_command *cmd);
24940254Speter
25040254Speter/* Prepare to handoff a controller qpair. */
25140292Speterint	nvmf_handoff_controller_qpair(struct nvmf_qpair *qp,
25240292Speter    struct nvmf_handoff_controller_qpair *h);
25340254Speter
25440254Speter/* Host-specific APIs. */
25540254Speter
25640254Speter/*
25740254Speter * Connect to an admin or I/O queue.  If this fails, a detailed error
25840254Speter * message can be obtained from nvmf_association_error.
25940254Speter */
26040254Speterstruct nvmf_qpair *nvmf_connect(struct nvmf_association *na,
26140254Speter    const struct nvmf_qpair_params *params, uint16_t qid, u_int queue_size,
26240254Speter    const uint8_t hostid[16], uint16_t cntlid, const char *subnqn,
26340254Speter    const char *hostnqn, uint32_t kato);
26440254Speter
26540254Speter/* Return the CNTLID for a queue returned from CONNECT. */
26640254Speteruint16_t nvmf_cntlid(struct nvmf_qpair *qp);
26740254Speter
26840254Speter/*
26940254Speter * Send a command to the controller.  This can fail with EBUSY if the
27040254Speter * submission queue is full.
27140254Speter */
27240254Speterint	nvmf_host_transmit_command(struct nvmf_capsule *nc);
27340254Speter
27440254Speter/*
27540254Speter * Wait for a response to a command.  If there are no outstanding
27640254Speter * commands in the SQ, fails with EWOULDBLOCK.
27740254Speter */
27840254Speterint	nvmf_host_receive_response(struct nvmf_qpair *qp,
27940254Speter    struct nvmf_capsule **rcp);
28040254Speter
28140254Speter/*
28240254Speter * Wait for a response to a specific command.  The command must have been
28340254Speter * succesfully sent previously.
28440254Speter */
28540254Speterint	nvmf_host_wait_for_response(struct nvmf_capsule *cc,
28640254Speter    struct nvmf_capsule **rcp);
28740254Speter
28840254Speter/* Build a KeepAlive command. */
28940254Speterstruct nvmf_capsule *nvmf_keepalive(struct nvmf_qpair *qp);
29040254Speter
29140254Speter/* Read a controller property. */
29240254Speterint	nvmf_read_property(struct nvmf_qpair *qp, uint32_t offset, uint8_t size,
29359603Sdfr    uint64_t *value);
29438514Sdfr
29559603Sdfr/* Write a controller property. */
29639071Sdfrint	nvmf_write_property(struct nvmf_qpair *qp, uint32_t offset,
29738514Sdfr    uint8_t size, uint64_t value);
29838514Sdfr
29938514Sdfr/* Construct a 16-byte HostId from kern.hostuuid. */
30038514Sdfrint	nvmf_hostid_from_hostuuid(uint8_t hostid[16]);
30138514Sdfr
30238514Sdfr/* Construct a NQN from kern.hostuuid. */
30380700Sjakeint	nvmf_nqn_from_hostuuid(char nqn[NVMF_NQN_MAX_LEN]);
30438514Sdfr
30538514Sdfr/* Fetch controller data via IDENTIFY. */
30638514Sdfrint	nvmf_host_identify_controller(struct nvmf_qpair *qp,
30738514Sdfr    struct nvme_controller_data *data);
30838514Sdfr
30938514Sdfr/* Fetch namespace data via IDENTIFY. */
31038514Sdfrint	nvmf_host_identify_namespace(struct nvmf_qpair *qp, uint32_t nsid,
31138514Sdfr    struct nvme_namespace_data *nsdata);
31239071Sdfr
31338514Sdfr/*
31440254Speter * Fetch discovery log page.  The memory for the log page is allocated
31540254Speter * by malloc() and returned in *logp.  The caller must free the
31640254Speter * memory.
31738514Sdfr */
31839071Sdfrint	nvmf_host_fetch_discovery_log_page(struct nvmf_qpair *qp,
31938514Sdfr    struct nvme_discovery_log **logp);
32038514Sdfr
32138514Sdfr/*
32238514Sdfr * Request a desired number of I/O queues via SET_FEATURES.  The
32339071Sdfr * number of actual I/O queues available is returned in *actual on
32439071Sdfr * success.
32539071Sdfr */
32639071Sdfrint	nvmf_host_request_queues(struct nvmf_qpair *qp, u_int requested,
32739071Sdfr    u_int *actual);
32839071Sdfr
32939071Sdfr/*
33039071Sdfr * Handoff active host association to the kernel.  This frees the
33139071Sdfr * qpairs (even on error).
33239071Sdfr */
33339071Sdfrint	nvmf_handoff_host(struct nvmf_qpair *admin_qp, u_int num_queues,
33439071Sdfr    struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata);
33539071Sdfr
33639071Sdfr/*
33739071Sdfr * Disconnect an active host association previously handed off to the
33839071Sdfr * kernel.  *name is either the name of the device (nvmeX) for this
33939071Sdfr * association or the remote subsystem NQN.
34039071Sdfr */
34139071Sdfrint	nvmf_disconnect_host(const char *host);
34239071Sdfr
34339071Sdfr/*
34439071Sdfr * Disconnect all active host associations previously handed off to
34539071Sdfr * the kernel.
34639071Sdfr */
34739071Sdfrint	nvmf_disconnect_all(void);
34839071Sdfr
34939071Sdfr/*
35039071Sdfr * Fetch reconnect parameters from an existing kernel host to use for
35139071Sdfr * establishing a new association.
35239071Sdfr */
35339071Sdfrint	nvmf_reconnect_params(int fd, struct nvmf_reconnect_params *rparams);
35439071Sdfr
35539071Sdfr/*
35639071Sdfr * Handoff active host association to an existing host in the kernel.
35739071Sdfr * This frees the qpairs (even on error).
35859603Sdfr */
35959603Sdfrint	nvmf_reconnect_host(int fd, struct nvmf_qpair *admin_qp,
36059603Sdfr    u_int num_queues, struct nvmf_qpair **io_queues,
36159603Sdfr    const struct nvme_controller_data *cdata);
36259603Sdfr
36338514Sdfr#endif /* !__LIBNVMF_H__ */
36438514Sdfr