xref: /freebsd/sys/dev/nvmf/controller/nvmft_qpair.c (revision 365b89e8ea4af34a05f68aa28e77573e89fa00b2)
1a15f7c96SJohn Baldwin /*-
2a15f7c96SJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause
3a15f7c96SJohn Baldwin  *
4a15f7c96SJohn Baldwin  * Copyright (c) 2023-2024 Chelsio Communications, Inc.
5a15f7c96SJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
6a15f7c96SJohn Baldwin  */
7a15f7c96SJohn Baldwin 
8a15f7c96SJohn Baldwin #include <sys/types.h>
9a15f7c96SJohn Baldwin #include <sys/_bitset.h>
10a15f7c96SJohn Baldwin #include <sys/bitset.h>
11a15f7c96SJohn Baldwin #include <sys/lock.h>
12a15f7c96SJohn Baldwin #include <sys/mutex.h>
13a15f7c96SJohn Baldwin 
14a15f7c96SJohn Baldwin #include <dev/nvmf/nvmf_transport.h>
15a15f7c96SJohn Baldwin #include <dev/nvmf/controller/nvmft_var.h>
16a15f7c96SJohn Baldwin 
17a15f7c96SJohn Baldwin /*
18a15f7c96SJohn Baldwin  * A bitmask of command ID values.  This is used to detect duplicate
19a15f7c96SJohn Baldwin  * commands with the same ID.
20a15f7c96SJohn Baldwin  */
21a15f7c96SJohn Baldwin #define	NUM_CIDS	(UINT16_MAX + 1)
22a15f7c96SJohn Baldwin BITSET_DEFINE(cidset, NUM_CIDS);
23a15f7c96SJohn Baldwin 
24a15f7c96SJohn Baldwin struct nvmft_qpair {
25a15f7c96SJohn Baldwin 	struct nvmft_controller *ctrlr;
26a15f7c96SJohn Baldwin 	struct nvmf_qpair *qp;
27a15f7c96SJohn Baldwin 	struct cidset *cids;
28a15f7c96SJohn Baldwin 
29a15f7c96SJohn Baldwin 	bool	admin;
30a15f7c96SJohn Baldwin 	bool	sq_flow_control;
31a15f7c96SJohn Baldwin 	uint16_t qid;
32a15f7c96SJohn Baldwin 	u_int	qsize;
33a15f7c96SJohn Baldwin 	uint16_t sqhd;
34a15f7c96SJohn Baldwin 	volatile u_int qp_refs;		/* Internal references on 'qp'. */
35a15f7c96SJohn Baldwin 
361b3fa1acSJohn Baldwin 	struct task datamove_task;
371b3fa1acSJohn Baldwin 	STAILQ_HEAD(, ctl_io_hdr) datamove_queue;
381b3fa1acSJohn Baldwin 
39a15f7c96SJohn Baldwin 	struct mtx lock;
40a15f7c96SJohn Baldwin 
41a15f7c96SJohn Baldwin 	char	name[16];
42a15f7c96SJohn Baldwin };
43a15f7c96SJohn Baldwin 
44a15f7c96SJohn Baldwin static int	_nvmft_send_generic_error(struct nvmft_qpair *qp,
45a15f7c96SJohn Baldwin     struct nvmf_capsule *nc, uint8_t sc_status);
461b3fa1acSJohn Baldwin static void	nvmft_datamove_task(void *context, int pending);
47a15f7c96SJohn Baldwin 
48a15f7c96SJohn Baldwin static void
nvmft_qpair_error(void * arg,int error)49a15f7c96SJohn Baldwin nvmft_qpair_error(void *arg, int error)
50a15f7c96SJohn Baldwin {
51a15f7c96SJohn Baldwin 	struct nvmft_qpair *qp = arg;
52a15f7c96SJohn Baldwin 	struct nvmft_controller *ctrlr = qp->ctrlr;
53a15f7c96SJohn Baldwin 
54a15f7c96SJohn Baldwin 	/*
55a15f7c96SJohn Baldwin 	 * XXX: The Linux TCP initiator sends a RST immediately after
56a15f7c96SJohn Baldwin 	 * the FIN, so treat ECONNRESET as plain EOF to avoid spurious
57a15f7c96SJohn Baldwin 	 * errors on shutdown.
58a15f7c96SJohn Baldwin 	 */
59a15f7c96SJohn Baldwin 	if (error == ECONNRESET)
60a15f7c96SJohn Baldwin 		error = 0;
61a15f7c96SJohn Baldwin 
62a15f7c96SJohn Baldwin 	if (error != 0)
63a15f7c96SJohn Baldwin 		nvmft_printf(ctrlr, "error %d on %s\n", error, qp->name);
64a15f7c96SJohn Baldwin 	nvmft_controller_error(ctrlr, qp, error);
65a15f7c96SJohn Baldwin }
66a15f7c96SJohn Baldwin 
67a15f7c96SJohn Baldwin static void
nvmft_receive_capsule(void * arg,struct nvmf_capsule * nc)68a15f7c96SJohn Baldwin nvmft_receive_capsule(void *arg, struct nvmf_capsule *nc)
69a15f7c96SJohn Baldwin {
70a15f7c96SJohn Baldwin 	struct nvmft_qpair *qp = arg;
71a15f7c96SJohn Baldwin 	struct nvmft_controller *ctrlr = qp->ctrlr;
72a15f7c96SJohn Baldwin 	const struct nvme_command *cmd;
73a15f7c96SJohn Baldwin 	uint8_t sc_status;
74a15f7c96SJohn Baldwin 
75a15f7c96SJohn Baldwin 	cmd = nvmf_capsule_sqe(nc);
76a15f7c96SJohn Baldwin 	if (ctrlr == NULL) {
77a15f7c96SJohn Baldwin 		printf("NVMFT: %s received CID %u opcode %u on newborn queue\n",
78a15f7c96SJohn Baldwin 		    qp->name, le16toh(cmd->cid), cmd->opc);
79a15f7c96SJohn Baldwin 		nvmf_free_capsule(nc);
80a15f7c96SJohn Baldwin 		return;
81a15f7c96SJohn Baldwin 	}
82a15f7c96SJohn Baldwin 
83a15f7c96SJohn Baldwin 	sc_status = nvmf_validate_command_capsule(nc);
84a15f7c96SJohn Baldwin 	if (sc_status != NVME_SC_SUCCESS) {
85a15f7c96SJohn Baldwin 		_nvmft_send_generic_error(qp, nc, sc_status);
86a15f7c96SJohn Baldwin 		nvmf_free_capsule(nc);
87a15f7c96SJohn Baldwin 		return;
88a15f7c96SJohn Baldwin 	}
89a15f7c96SJohn Baldwin 
90a15f7c96SJohn Baldwin 	/* Don't bother byte-swapping CID. */
91a15f7c96SJohn Baldwin 	if (BIT_TEST_SET_ATOMIC(NUM_CIDS, cmd->cid, qp->cids)) {
92a15f7c96SJohn Baldwin 		_nvmft_send_generic_error(qp, nc, NVME_SC_COMMAND_ID_CONFLICT);
93a15f7c96SJohn Baldwin 		nvmf_free_capsule(nc);
94a15f7c96SJohn Baldwin 		return;
95a15f7c96SJohn Baldwin 	}
96a15f7c96SJohn Baldwin 
97a15f7c96SJohn Baldwin 	if (qp->admin)
98a15f7c96SJohn Baldwin 		nvmft_handle_admin_command(ctrlr, nc);
99a15f7c96SJohn Baldwin 	else
100a15f7c96SJohn Baldwin 		nvmft_handle_io_command(qp, qp->qid, nc);
101a15f7c96SJohn Baldwin }
102a15f7c96SJohn Baldwin 
103a15f7c96SJohn Baldwin struct nvmft_qpair *
nvmft_qpair_init(enum nvmf_trtype trtype,const nvlist_t * params,uint16_t qid,const char * name)104*365b89e8SJohn Baldwin nvmft_qpair_init(enum nvmf_trtype trtype, const nvlist_t *params, uint16_t qid,
105a15f7c96SJohn Baldwin     const char *name)
106a15f7c96SJohn Baldwin {
107a15f7c96SJohn Baldwin 	struct nvmft_qpair *qp;
108a15f7c96SJohn Baldwin 
109a15f7c96SJohn Baldwin 	qp = malloc(sizeof(*qp), M_NVMFT, M_WAITOK | M_ZERO);
110*365b89e8SJohn Baldwin 	qp->admin = nvlist_get_bool(params, "admin");
111*365b89e8SJohn Baldwin 	qp->sq_flow_control = nvlist_get_bool(params, "sq_flow_control");
112*365b89e8SJohn Baldwin 	qp->qsize = nvlist_get_number(params, "qsize");
113a15f7c96SJohn Baldwin 	qp->qid = qid;
114*365b89e8SJohn Baldwin 	qp->sqhd = nvlist_get_number(params, "sqhd");
115a15f7c96SJohn Baldwin 	strlcpy(qp->name, name, sizeof(qp->name));
116a15f7c96SJohn Baldwin 	mtx_init(&qp->lock, "nvmft qp", NULL, MTX_DEF);
117a15f7c96SJohn Baldwin 	qp->cids = BITSET_ALLOC(NUM_CIDS, M_NVMFT, M_WAITOK | M_ZERO);
1181b3fa1acSJohn Baldwin 	STAILQ_INIT(&qp->datamove_queue);
1191b3fa1acSJohn Baldwin 	TASK_INIT(&qp->datamove_task, 0, nvmft_datamove_task, qp);
120a15f7c96SJohn Baldwin 
121*365b89e8SJohn Baldwin 	qp->qp = nvmf_allocate_qpair(trtype, true, params, nvmft_qpair_error,
122a15f7c96SJohn Baldwin 	    qp, nvmft_receive_capsule, qp);
123a15f7c96SJohn Baldwin 	if (qp->qp == NULL) {
124a15f7c96SJohn Baldwin 		mtx_destroy(&qp->lock);
125a15f7c96SJohn Baldwin 		free(qp->cids, M_NVMFT);
126a15f7c96SJohn Baldwin 		free(qp, M_NVMFT);
127a15f7c96SJohn Baldwin 		return (NULL);
128a15f7c96SJohn Baldwin 	}
129a15f7c96SJohn Baldwin 
130a15f7c96SJohn Baldwin 	refcount_init(&qp->qp_refs, 1);
131a15f7c96SJohn Baldwin 	return (qp);
132a15f7c96SJohn Baldwin }
133a15f7c96SJohn Baldwin 
134a15f7c96SJohn Baldwin void
nvmft_qpair_shutdown(struct nvmft_qpair * qp)135a15f7c96SJohn Baldwin nvmft_qpair_shutdown(struct nvmft_qpair *qp)
136a15f7c96SJohn Baldwin {
1371b3fa1acSJohn Baldwin 	STAILQ_HEAD(, ctl_io_hdr) datamove_queue;
138a15f7c96SJohn Baldwin 	struct nvmf_qpair *nq;
1391b3fa1acSJohn Baldwin 	union ctl_io *io;
140a15f7c96SJohn Baldwin 
1411b3fa1acSJohn Baldwin 	STAILQ_INIT(&datamove_queue);
142a15f7c96SJohn Baldwin 	mtx_lock(&qp->lock);
143a15f7c96SJohn Baldwin 	nq = qp->qp;
144a15f7c96SJohn Baldwin 	qp->qp = NULL;
1451b3fa1acSJohn Baldwin 	STAILQ_CONCAT(&datamove_queue, &qp->datamove_queue);
146a15f7c96SJohn Baldwin 	mtx_unlock(&qp->lock);
147a15f7c96SJohn Baldwin 	if (nq != NULL && refcount_release(&qp->qp_refs))
148a15f7c96SJohn Baldwin 		nvmf_free_qpair(nq);
1491b3fa1acSJohn Baldwin 
1501b3fa1acSJohn Baldwin 	while (!STAILQ_EMPTY(&datamove_queue)) {
1511b3fa1acSJohn Baldwin 		io = (union ctl_io *)STAILQ_FIRST(&datamove_queue);
1521b3fa1acSJohn Baldwin 		STAILQ_REMOVE_HEAD(&datamove_queue, links);
1531b3fa1acSJohn Baldwin 		nvmft_abort_datamove(io);
1541b3fa1acSJohn Baldwin 	}
1551b3fa1acSJohn Baldwin 	nvmft_drain_task(&qp->datamove_task);
156a15f7c96SJohn Baldwin }
157a15f7c96SJohn Baldwin 
158a15f7c96SJohn Baldwin void
nvmft_qpair_destroy(struct nvmft_qpair * qp)159a15f7c96SJohn Baldwin nvmft_qpair_destroy(struct nvmft_qpair *qp)
160a15f7c96SJohn Baldwin {
161a15f7c96SJohn Baldwin 	nvmft_qpair_shutdown(qp);
162a15f7c96SJohn Baldwin 	mtx_destroy(&qp->lock);
163a15f7c96SJohn Baldwin 	free(qp->cids, M_NVMFT);
164a15f7c96SJohn Baldwin 	free(qp, M_NVMFT);
165a15f7c96SJohn Baldwin }
166a15f7c96SJohn Baldwin 
167a15f7c96SJohn Baldwin struct nvmft_controller *
nvmft_qpair_ctrlr(struct nvmft_qpair * qp)168a15f7c96SJohn Baldwin nvmft_qpair_ctrlr(struct nvmft_qpair *qp)
169a15f7c96SJohn Baldwin {
170a15f7c96SJohn Baldwin 	return (qp->ctrlr);
171a15f7c96SJohn Baldwin }
172a15f7c96SJohn Baldwin 
173a15f7c96SJohn Baldwin uint16_t
nvmft_qpair_id(struct nvmft_qpair * qp)174a15f7c96SJohn Baldwin nvmft_qpair_id(struct nvmft_qpair *qp)
175a15f7c96SJohn Baldwin {
176a15f7c96SJohn Baldwin 	return (qp->qid);
177a15f7c96SJohn Baldwin }
178a15f7c96SJohn Baldwin 
179a15f7c96SJohn Baldwin const char *
nvmft_qpair_name(struct nvmft_qpair * qp)180a15f7c96SJohn Baldwin nvmft_qpair_name(struct nvmft_qpair *qp)
181a15f7c96SJohn Baldwin {
182a15f7c96SJohn Baldwin 	return (qp->name);
183a15f7c96SJohn Baldwin }
184a15f7c96SJohn Baldwin 
185a15f7c96SJohn Baldwin static int
_nvmft_send_response(struct nvmft_qpair * qp,const void * cqe)186a15f7c96SJohn Baldwin _nvmft_send_response(struct nvmft_qpair *qp, const void *cqe)
187a15f7c96SJohn Baldwin {
188a15f7c96SJohn Baldwin 	struct nvme_completion cpl;
189a15f7c96SJohn Baldwin 	struct nvmf_qpair *nq;
190a15f7c96SJohn Baldwin 	struct nvmf_capsule *rc;
191a15f7c96SJohn Baldwin 	int error;
192a15f7c96SJohn Baldwin 
193a15f7c96SJohn Baldwin 	memcpy(&cpl, cqe, sizeof(cpl));
194a15f7c96SJohn Baldwin 	mtx_lock(&qp->lock);
195a15f7c96SJohn Baldwin 	nq = qp->qp;
196a15f7c96SJohn Baldwin 	if (nq == NULL) {
197a15f7c96SJohn Baldwin 		mtx_unlock(&qp->lock);
198a15f7c96SJohn Baldwin 		return (ENOTCONN);
199a15f7c96SJohn Baldwin 	}
200a15f7c96SJohn Baldwin 	refcount_acquire(&qp->qp_refs);
201a15f7c96SJohn Baldwin 
202a15f7c96SJohn Baldwin 	/* Set SQHD. */
203a15f7c96SJohn Baldwin 	if (qp->sq_flow_control) {
204a15f7c96SJohn Baldwin 		qp->sqhd = (qp->sqhd + 1) % qp->qsize;
205a15f7c96SJohn Baldwin 		cpl.sqhd = htole16(qp->sqhd);
206a15f7c96SJohn Baldwin 	} else
207a15f7c96SJohn Baldwin 		cpl.sqhd = 0;
208a15f7c96SJohn Baldwin 	mtx_unlock(&qp->lock);
209a15f7c96SJohn Baldwin 
210a15f7c96SJohn Baldwin 	rc = nvmf_allocate_response(nq, &cpl, M_WAITOK);
211a15f7c96SJohn Baldwin 	error = nvmf_transmit_capsule(rc);
212a15f7c96SJohn Baldwin 	nvmf_free_capsule(rc);
213a15f7c96SJohn Baldwin 
214a15f7c96SJohn Baldwin 	if (refcount_release(&qp->qp_refs))
215a15f7c96SJohn Baldwin 		nvmf_free_qpair(nq);
216a15f7c96SJohn Baldwin 	return (error);
217a15f7c96SJohn Baldwin }
218a15f7c96SJohn Baldwin 
219a15f7c96SJohn Baldwin void
nvmft_command_completed(struct nvmft_qpair * qp,struct nvmf_capsule * nc)220a15f7c96SJohn Baldwin nvmft_command_completed(struct nvmft_qpair *qp, struct nvmf_capsule *nc)
221a15f7c96SJohn Baldwin {
222a15f7c96SJohn Baldwin 	const struct nvme_command *cmd = nvmf_capsule_sqe(nc);
223a15f7c96SJohn Baldwin 
224a15f7c96SJohn Baldwin 	/* Don't bother byte-swapping CID. */
225a15f7c96SJohn Baldwin 	KASSERT(BIT_ISSET(NUM_CIDS, cmd->cid, qp->cids),
226a15f7c96SJohn Baldwin 	    ("%s: CID %u not busy", __func__, cmd->cid));
227a15f7c96SJohn Baldwin 
228a15f7c96SJohn Baldwin 	BIT_CLR_ATOMIC(NUM_CIDS, cmd->cid, qp->cids);
229a15f7c96SJohn Baldwin }
230a15f7c96SJohn Baldwin 
231a15f7c96SJohn Baldwin int
nvmft_send_response(struct nvmft_qpair * qp,const void * cqe)232a15f7c96SJohn Baldwin nvmft_send_response(struct nvmft_qpair *qp, const void *cqe)
233a15f7c96SJohn Baldwin {
234a15f7c96SJohn Baldwin 	const struct nvme_completion *cpl = cqe;
235a15f7c96SJohn Baldwin 
236a15f7c96SJohn Baldwin 	/* Don't bother byte-swapping CID. */
237a15f7c96SJohn Baldwin 	KASSERT(BIT_ISSET(NUM_CIDS, cpl->cid, qp->cids),
238a15f7c96SJohn Baldwin 	    ("%s: CID %u not busy", __func__, cpl->cid));
239a15f7c96SJohn Baldwin 
240a15f7c96SJohn Baldwin 	BIT_CLR_ATOMIC(NUM_CIDS, cpl->cid, qp->cids);
241a15f7c96SJohn Baldwin 	return (_nvmft_send_response(qp, cqe));
242a15f7c96SJohn Baldwin }
243a15f7c96SJohn Baldwin 
244a15f7c96SJohn Baldwin void
nvmft_init_cqe(void * cqe,struct nvmf_capsule * nc,uint16_t status)245a15f7c96SJohn Baldwin nvmft_init_cqe(void *cqe, struct nvmf_capsule *nc, uint16_t status)
246a15f7c96SJohn Baldwin {
247a15f7c96SJohn Baldwin 	struct nvme_completion *cpl = cqe;
248a15f7c96SJohn Baldwin 	const struct nvme_command *cmd = nvmf_capsule_sqe(nc);
249a15f7c96SJohn Baldwin 
250a15f7c96SJohn Baldwin 	memset(cpl, 0, sizeof(*cpl));
251a15f7c96SJohn Baldwin 	cpl->cid = cmd->cid;
252a15f7c96SJohn Baldwin 	cpl->status = htole16(status);
253a15f7c96SJohn Baldwin }
254a15f7c96SJohn Baldwin 
255a15f7c96SJohn Baldwin int
nvmft_send_error(struct nvmft_qpair * qp,struct nvmf_capsule * nc,uint8_t sc_type,uint8_t sc_status)256a15f7c96SJohn Baldwin nvmft_send_error(struct nvmft_qpair *qp, struct nvmf_capsule *nc,
257a15f7c96SJohn Baldwin     uint8_t sc_type, uint8_t sc_status)
258a15f7c96SJohn Baldwin {
259a15f7c96SJohn Baldwin 	struct nvme_completion cpl;
260a15f7c96SJohn Baldwin 	uint16_t status;
261a15f7c96SJohn Baldwin 
262a15f7c96SJohn Baldwin 	status = NVMEF(NVME_STATUS_SCT, sc_type) |
263a15f7c96SJohn Baldwin 	    NVMEF(NVME_STATUS_SC, sc_status);
264a15f7c96SJohn Baldwin 	nvmft_init_cqe(&cpl, nc, status);
265a15f7c96SJohn Baldwin 	return (nvmft_send_response(qp, &cpl));
266a15f7c96SJohn Baldwin }
267a15f7c96SJohn Baldwin 
268a15f7c96SJohn Baldwin int
nvmft_send_generic_error(struct nvmft_qpair * qp,struct nvmf_capsule * nc,uint8_t sc_status)269a15f7c96SJohn Baldwin nvmft_send_generic_error(struct nvmft_qpair *qp, struct nvmf_capsule *nc,
270a15f7c96SJohn Baldwin     uint8_t sc_status)
271a15f7c96SJohn Baldwin {
272a15f7c96SJohn Baldwin 	return (nvmft_send_error(qp, nc, NVME_SCT_GENERIC, sc_status));
273a15f7c96SJohn Baldwin }
274a15f7c96SJohn Baldwin 
275a15f7c96SJohn Baldwin /*
276a15f7c96SJohn Baldwin  * This version doesn't clear CID in qp->cids and is used for errors
277a15f7c96SJohn Baldwin  * before the CID is validated.
278a15f7c96SJohn Baldwin  */
279a15f7c96SJohn Baldwin static int
_nvmft_send_generic_error(struct nvmft_qpair * qp,struct nvmf_capsule * nc,uint8_t sc_status)280a15f7c96SJohn Baldwin _nvmft_send_generic_error(struct nvmft_qpair *qp, struct nvmf_capsule *nc,
281a15f7c96SJohn Baldwin     uint8_t sc_status)
282a15f7c96SJohn Baldwin {
283a15f7c96SJohn Baldwin 	struct nvme_completion cpl;
284a15f7c96SJohn Baldwin 	uint16_t status;
285a15f7c96SJohn Baldwin 
286a15f7c96SJohn Baldwin 	status = NVMEF(NVME_STATUS_SCT, NVME_SCT_GENERIC) |
287a15f7c96SJohn Baldwin 	    NVMEF(NVME_STATUS_SC, sc_status);
288a15f7c96SJohn Baldwin 	nvmft_init_cqe(&cpl, nc, status);
289a15f7c96SJohn Baldwin 	return (_nvmft_send_response(qp, &cpl));
290a15f7c96SJohn Baldwin }
291a15f7c96SJohn Baldwin 
292a15f7c96SJohn Baldwin int
nvmft_send_success(struct nvmft_qpair * qp,struct nvmf_capsule * nc)293a15f7c96SJohn Baldwin nvmft_send_success(struct nvmft_qpair *qp, struct nvmf_capsule *nc)
294a15f7c96SJohn Baldwin {
295a15f7c96SJohn Baldwin 	return (nvmft_send_generic_error(qp, nc, NVME_SC_SUCCESS));
296a15f7c96SJohn Baldwin }
297a15f7c96SJohn Baldwin 
298a15f7c96SJohn Baldwin static void
nvmft_init_connect_rsp(struct nvmf_fabric_connect_rsp * rsp,const struct nvmf_fabric_connect_cmd * cmd,uint16_t status)299a15f7c96SJohn Baldwin nvmft_init_connect_rsp(struct nvmf_fabric_connect_rsp *rsp,
300a15f7c96SJohn Baldwin     const struct nvmf_fabric_connect_cmd *cmd, uint16_t status)
301a15f7c96SJohn Baldwin {
302a15f7c96SJohn Baldwin 	memset(rsp, 0, sizeof(*rsp));
303a15f7c96SJohn Baldwin 	rsp->cid = cmd->cid;
304a15f7c96SJohn Baldwin 	rsp->status = htole16(status);
305a15f7c96SJohn Baldwin }
306a15f7c96SJohn Baldwin 
307a15f7c96SJohn Baldwin static int
nvmft_send_connect_response(struct nvmft_qpair * qp,const struct nvmf_fabric_connect_rsp * rsp)308a15f7c96SJohn Baldwin nvmft_send_connect_response(struct nvmft_qpair *qp,
309a15f7c96SJohn Baldwin     const struct nvmf_fabric_connect_rsp *rsp)
310a15f7c96SJohn Baldwin {
311a15f7c96SJohn Baldwin 	struct nvmf_capsule *rc;
312a15f7c96SJohn Baldwin 	struct nvmf_qpair *nq;
313a15f7c96SJohn Baldwin 	int error;
314a15f7c96SJohn Baldwin 
315a15f7c96SJohn Baldwin 	mtx_lock(&qp->lock);
316a15f7c96SJohn Baldwin 	nq = qp->qp;
317a15f7c96SJohn Baldwin 	if (nq == NULL) {
318a15f7c96SJohn Baldwin 		mtx_unlock(&qp->lock);
319a15f7c96SJohn Baldwin 		return (ENOTCONN);
320a15f7c96SJohn Baldwin 	}
321a15f7c96SJohn Baldwin 	refcount_acquire(&qp->qp_refs);
322a15f7c96SJohn Baldwin 	mtx_unlock(&qp->lock);
323a15f7c96SJohn Baldwin 
324a15f7c96SJohn Baldwin 	rc = nvmf_allocate_response(qp->qp, rsp, M_WAITOK);
325a15f7c96SJohn Baldwin 	error = nvmf_transmit_capsule(rc);
326a15f7c96SJohn Baldwin 	nvmf_free_capsule(rc);
327a15f7c96SJohn Baldwin 
328a15f7c96SJohn Baldwin 	if (refcount_release(&qp->qp_refs))
329a15f7c96SJohn Baldwin 		nvmf_free_qpair(nq);
330a15f7c96SJohn Baldwin 	return (error);
331a15f7c96SJohn Baldwin }
332a15f7c96SJohn Baldwin 
333a15f7c96SJohn Baldwin void
nvmft_connect_error(struct nvmft_qpair * qp,const struct nvmf_fabric_connect_cmd * cmd,uint8_t sc_type,uint8_t sc_status)334a15f7c96SJohn Baldwin nvmft_connect_error(struct nvmft_qpair *qp,
335a15f7c96SJohn Baldwin     const struct nvmf_fabric_connect_cmd *cmd, uint8_t sc_type,
336a15f7c96SJohn Baldwin     uint8_t sc_status)
337a15f7c96SJohn Baldwin {
338a15f7c96SJohn Baldwin 	struct nvmf_fabric_connect_rsp rsp;
339a15f7c96SJohn Baldwin 	uint16_t status;
340a15f7c96SJohn Baldwin 
341a15f7c96SJohn Baldwin 	status = NVMEF(NVME_STATUS_SCT, sc_type) |
342a15f7c96SJohn Baldwin 	    NVMEF(NVME_STATUS_SC, sc_status);
343a15f7c96SJohn Baldwin 	nvmft_init_connect_rsp(&rsp, cmd, status);
344a15f7c96SJohn Baldwin 	nvmft_send_connect_response(qp, &rsp);
345a15f7c96SJohn Baldwin }
346a15f7c96SJohn Baldwin 
347a15f7c96SJohn Baldwin void
nvmft_connect_invalid_parameters(struct nvmft_qpair * qp,const struct nvmf_fabric_connect_cmd * cmd,bool data,uint16_t offset)348a15f7c96SJohn Baldwin nvmft_connect_invalid_parameters(struct nvmft_qpair *qp,
349a15f7c96SJohn Baldwin     const struct nvmf_fabric_connect_cmd *cmd, bool data, uint16_t offset)
350a15f7c96SJohn Baldwin {
351a15f7c96SJohn Baldwin 	struct nvmf_fabric_connect_rsp rsp;
352a15f7c96SJohn Baldwin 
353a15f7c96SJohn Baldwin 	nvmft_init_connect_rsp(&rsp, cmd,
354a15f7c96SJohn Baldwin 	    NVMEF(NVME_STATUS_SCT, NVME_SCT_COMMAND_SPECIFIC) |
355a15f7c96SJohn Baldwin 	    NVMEF(NVME_STATUS_SC, NVMF_FABRIC_SC_INVALID_PARAM));
356a15f7c96SJohn Baldwin 	rsp.status_code_specific.invalid.ipo = htole16(offset);
357a15f7c96SJohn Baldwin 	rsp.status_code_specific.invalid.iattr = data ? 1 : 0;
358a15f7c96SJohn Baldwin 	nvmft_send_connect_response(qp, &rsp);
359a15f7c96SJohn Baldwin }
360a15f7c96SJohn Baldwin 
361a15f7c96SJohn Baldwin int
nvmft_finish_accept(struct nvmft_qpair * qp,const struct nvmf_fabric_connect_cmd * cmd,struct nvmft_controller * ctrlr)362a15f7c96SJohn Baldwin nvmft_finish_accept(struct nvmft_qpair *qp,
363a15f7c96SJohn Baldwin     const struct nvmf_fabric_connect_cmd *cmd, struct nvmft_controller *ctrlr)
364a15f7c96SJohn Baldwin {
365a15f7c96SJohn Baldwin 	struct nvmf_fabric_connect_rsp rsp;
366a15f7c96SJohn Baldwin 
367a15f7c96SJohn Baldwin 	qp->ctrlr = ctrlr;
368a15f7c96SJohn Baldwin 	nvmft_init_connect_rsp(&rsp, cmd, 0);
369a15f7c96SJohn Baldwin 	if (qp->sq_flow_control)
370a15f7c96SJohn Baldwin 		rsp.sqhd = htole16(qp->sqhd);
371a15f7c96SJohn Baldwin 	else
372a15f7c96SJohn Baldwin 		rsp.sqhd = htole16(0xffff);
373a15f7c96SJohn Baldwin 	rsp.status_code_specific.success.cntlid = htole16(ctrlr->cntlid);
374a15f7c96SJohn Baldwin 	return (nvmft_send_connect_response(qp, &rsp));
375a15f7c96SJohn Baldwin }
3761b3fa1acSJohn Baldwin 
3771b3fa1acSJohn Baldwin void
nvmft_qpair_datamove(struct nvmft_qpair * qp,union ctl_io * io)3781b3fa1acSJohn Baldwin nvmft_qpair_datamove(struct nvmft_qpair *qp, union ctl_io *io)
3791b3fa1acSJohn Baldwin {
3801b3fa1acSJohn Baldwin 	bool enqueue_task;
3811b3fa1acSJohn Baldwin 
3821b3fa1acSJohn Baldwin 	mtx_lock(&qp->lock);
3831b3fa1acSJohn Baldwin 	if (qp->qp == NULL) {
3841b3fa1acSJohn Baldwin 		mtx_unlock(&qp->lock);
3851b3fa1acSJohn Baldwin 		nvmft_abort_datamove(io);
3861b3fa1acSJohn Baldwin 		return;
3871b3fa1acSJohn Baldwin 	}
3881b3fa1acSJohn Baldwin 	enqueue_task = STAILQ_EMPTY(&qp->datamove_queue);
3891b3fa1acSJohn Baldwin 	STAILQ_INSERT_TAIL(&qp->datamove_queue, &io->io_hdr, links);
3901b3fa1acSJohn Baldwin 	mtx_unlock(&qp->lock);
3911b3fa1acSJohn Baldwin 	if (enqueue_task)
3921b3fa1acSJohn Baldwin 		nvmft_enqueue_task(&qp->datamove_task);
3931b3fa1acSJohn Baldwin }
3941b3fa1acSJohn Baldwin 
3951b3fa1acSJohn Baldwin static void
nvmft_datamove_task(void * context,int pending __unused)3961b3fa1acSJohn Baldwin nvmft_datamove_task(void *context, int pending __unused)
3971b3fa1acSJohn Baldwin {
3981b3fa1acSJohn Baldwin 	struct nvmft_qpair *qp = context;
3991b3fa1acSJohn Baldwin 	union ctl_io *io;
4001b3fa1acSJohn Baldwin 	bool abort;
4011b3fa1acSJohn Baldwin 
4021b3fa1acSJohn Baldwin 	mtx_lock(&qp->lock);
4031b3fa1acSJohn Baldwin 	while (!STAILQ_EMPTY(&qp->datamove_queue)) {
4041b3fa1acSJohn Baldwin 		io = (union ctl_io *)STAILQ_FIRST(&qp->datamove_queue);
4051b3fa1acSJohn Baldwin 		STAILQ_REMOVE_HEAD(&qp->datamove_queue, links);
4061b3fa1acSJohn Baldwin 		abort = (qp->qp == NULL);
4071b3fa1acSJohn Baldwin 		mtx_unlock(&qp->lock);
4081b3fa1acSJohn Baldwin 		if (abort)
4091b3fa1acSJohn Baldwin 			nvmft_abort_datamove(io);
4101b3fa1acSJohn Baldwin 		else
4111b3fa1acSJohn Baldwin 			nvmft_handle_datamove(io);
4121b3fa1acSJohn Baldwin 		mtx_lock(&qp->lock);
4131b3fa1acSJohn Baldwin 	}
4141b3fa1acSJohn Baldwin 	mtx_unlock(&qp->lock);
4151b3fa1acSJohn Baldwin }
416