/*-
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Copyright (c) 2022-2024 Chelsio Communications, Inc.
 * Written by: John Baldwin <jhb@FreeBSD.org>
 */

#ifndef __LIBNVMF_INTERNAL_H__
#define __LIBNVMF_INTERNAL_H__

#include <sys/queue.h>

struct nvmf_transport_ops {
	/* Association management. */
	struct nvmf_association *(*allocate_association)(bool controller,
	    const struct nvmf_association_params *params);
	void (*update_association)(struct nvmf_association *na,
	    const struct nvme_controller_data *cdata);
	void (*free_association)(struct nvmf_association *na);

	/* Queue pair management. */
	struct nvmf_qpair *(*allocate_qpair)(struct nvmf_association *na,
	    const struct nvmf_qpair_params *params);
	void (*free_qpair)(struct nvmf_qpair *qp);

	/* Create params for kernel handoff. */
	int (*kernel_handoff_params)(struct nvmf_qpair *qp,
	    struct nvmf_handoff_qpair_params *qparams);

	/* Capsule operations. */
	struct nvmf_capsule *(*allocate_capsule)(struct nvmf_qpair *qp);
	void (*free_capsule)(struct nvmf_capsule *nc);
	int (*transmit_capsule)(struct nvmf_capsule *nc);
	int (*receive_capsule)(struct nvmf_qpair *qp,
	    struct nvmf_capsule **ncp);
	uint8_t (*validate_command_capsule)(const struct nvmf_capsule *nc);

	/* Transferring controller data. */
	size_t (*capsule_data_len)(const struct nvmf_capsule *nc);
	int (*receive_controller_data)(const struct nvmf_capsule *nc,
	    uint32_t data_offset, void *buf, size_t len);
	int (*send_controller_data)(const struct nvmf_capsule *nc,
	    const void *buf, size_t len);
};

struct nvmf_association {
	struct nvmf_transport_ops *na_ops;
	enum nvmf_trtype na_trtype;
	bool na_controller;

	struct nvmf_association_params na_params;

	/* Each qpair holds a reference on an association. */
	u_int na_refs;

	char *na_last_error;
};

struct nvmf_qpair {
	struct nvmf_association *nq_association;
	bool nq_admin;

	uint16_t nq_cid;	/* host only */

	/*
	 * Queue sizes.  This assumes the same size for both the
	 * completion and submission queues within a pair.
	 */
	u_int	nq_qsize;

	/* Flow control management for submission queues. */
	bool nq_flow_control;
	uint16_t nq_sqhd;
	uint16_t nq_sqtail;	/* host only */

	/* Value in response to/from CONNECT. */
	uint16_t nq_cntlid;

	uint32_t nq_kato;	/* valid on admin queue only */

	TAILQ_HEAD(, nvmf_capsule) nq_rx_capsules;
};

struct nvmf_capsule {
	struct nvmf_qpair *nc_qpair;

	/* Either a SQE or CQE. */
	union {
		struct nvme_command nc_sqe;
		struct nvme_completion nc_cqe;
	};
	int	nc_qe_len;

	/*
	 * Is SQHD in received capsule valid?  False for locally-
	 * synthesized responses.
	 */
	bool	nc_sqhd_valid;

	/* Data buffer. */
	bool	nc_send_data;
	void	*nc_data;
	size_t	nc_data_len;

	TAILQ_ENTRY(nvmf_capsule) nc_link;
};

extern struct nvmf_transport_ops tcp_ops;

void	na_clear_error(struct nvmf_association *na);
void	na_error(struct nvmf_association *na, const char *fmt, ...);

int	nvmf_kernel_handoff_params(struct nvmf_qpair *qp,
    struct nvmf_handoff_qpair_params *qparams);

#endif /* !__LIBNVMF_INTERNAL_H__ */