xref: /dpdk/drivers/crypto/ionic/ionic_crypto_cmds.c (revision 2c1662bb53cab994552d82814ce81ad183947f62)
1a677112dSAndrew Boyer /* SPDX-License-Identifier: BSD-3-Clause
2a677112dSAndrew Boyer  * Copyright 2021-2024 Advanced Micro Devices, Inc.
3a677112dSAndrew Boyer  */
4a677112dSAndrew Boyer 
5a677112dSAndrew Boyer #include <stdbool.h>
6a677112dSAndrew Boyer 
7a677112dSAndrew Boyer #include <rte_malloc.h>
8a677112dSAndrew Boyer #include <rte_memzone.h>
9a677112dSAndrew Boyer 
10a677112dSAndrew Boyer #include "ionic_crypto.h"
11a677112dSAndrew Boyer 
12a677112dSAndrew Boyer /* queuetype support level */
13a677112dSAndrew Boyer static const uint8_t iocpt_qtype_vers[IOCPT_QTYPE_MAX] = {
14a677112dSAndrew Boyer 	[IOCPT_QTYPE_ADMINQ]  = 0,   /* 0 = Base version */
15a677112dSAndrew Boyer 	[IOCPT_QTYPE_NOTIFYQ] = 0,   /* 0 = Base version */
16a677112dSAndrew Boyer 	[IOCPT_QTYPE_CRYPTOQ] = 0,   /* 0 = Base version */
17a677112dSAndrew Boyer };
18a677112dSAndrew Boyer 
19a677112dSAndrew Boyer static const char *
iocpt_error_to_str(enum iocpt_status_code code)20*2c1662bbSAndrew Boyer iocpt_error_to_str(enum iocpt_status_code code)
21*2c1662bbSAndrew Boyer {
22*2c1662bbSAndrew Boyer 	switch (code) {
23*2c1662bbSAndrew Boyer 	case IOCPT_RC_SUCCESS:
24*2c1662bbSAndrew Boyer 		return "IOCPT_RC_SUCCESS";
25*2c1662bbSAndrew Boyer 	case IOCPT_RC_EVERSION:
26*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EVERSION";
27*2c1662bbSAndrew Boyer 	case IOCPT_RC_EOPCODE:
28*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EOPCODE";
29*2c1662bbSAndrew Boyer 	case IOCPT_RC_EIO:
30*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EIO";
31*2c1662bbSAndrew Boyer 	case IOCPT_RC_EPERM:
32*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EPERM";
33*2c1662bbSAndrew Boyer 	case IOCPT_RC_EQID:
34*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EQID";
35*2c1662bbSAndrew Boyer 	case IOCPT_RC_EQTYPE:
36*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EQTYPE";
37*2c1662bbSAndrew Boyer 	case IOCPT_RC_ENOENT:
38*2c1662bbSAndrew Boyer 		return "IOCPT_RC_ENOENT";
39*2c1662bbSAndrew Boyer 	case IOCPT_RC_EINTR:
40*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EINTR";
41*2c1662bbSAndrew Boyer 	case IOCPT_RC_EAGAIN:
42*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EAGAIN";
43*2c1662bbSAndrew Boyer 	case IOCPT_RC_ENOMEM:
44*2c1662bbSAndrew Boyer 		return "IOCPT_RC_ENOMEM";
45*2c1662bbSAndrew Boyer 	case IOCPT_RC_EFAULT:
46*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EFAULT";
47*2c1662bbSAndrew Boyer 	case IOCPT_RC_EBUSY:
48*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EBUSY";
49*2c1662bbSAndrew Boyer 	case IOCPT_RC_EEXIST:
50*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EEXIST";
51*2c1662bbSAndrew Boyer 	case IOCPT_RC_EINVAL:
52*2c1662bbSAndrew Boyer 		return "IOCPT_RC_EINVAL";
53*2c1662bbSAndrew Boyer 	case IOCPT_RC_ENOSPC:
54*2c1662bbSAndrew Boyer 		return "IOCPT_RC_ENOSPC";
55*2c1662bbSAndrew Boyer 	case IOCPT_RC_ERANGE:
56*2c1662bbSAndrew Boyer 		return "IOCPT_RC_ERANGE";
57*2c1662bbSAndrew Boyer 	case IOCPT_RC_BAD_ADDR:
58*2c1662bbSAndrew Boyer 		return "IOCPT_RC_BAD_ADDR";
59*2c1662bbSAndrew Boyer 	case IOCPT_RC_DEV_CMD:
60*2c1662bbSAndrew Boyer 		return "IOCPT_RC_DEV_CMD";
61*2c1662bbSAndrew Boyer 	case IOCPT_RC_ERROR:
62*2c1662bbSAndrew Boyer 		return "IOCPT_RC_ERROR";
63*2c1662bbSAndrew Boyer 	default:
64*2c1662bbSAndrew Boyer 		return "IOCPT_RC_UNKNOWN";
65*2c1662bbSAndrew Boyer 	}
66*2c1662bbSAndrew Boyer }
67*2c1662bbSAndrew Boyer 
68*2c1662bbSAndrew Boyer static const char *
iocpt_opcode_to_str(enum iocpt_cmd_opcode opcode)69a677112dSAndrew Boyer iocpt_opcode_to_str(enum iocpt_cmd_opcode opcode)
70a677112dSAndrew Boyer {
71a677112dSAndrew Boyer 	switch (opcode) {
72a677112dSAndrew Boyer 	case IOCPT_CMD_NOP:
73a677112dSAndrew Boyer 		return "IOCPT_CMD_NOP";
74a677112dSAndrew Boyer 	case IOCPT_CMD_IDENTIFY:
75a677112dSAndrew Boyer 		return "IOCPT_CMD_IDENTIFY";
76a677112dSAndrew Boyer 	case IOCPT_CMD_RESET:
77a677112dSAndrew Boyer 		return "IOCPT_CMD_RESET";
78a677112dSAndrew Boyer 	case IOCPT_CMD_LIF_IDENTIFY:
79a677112dSAndrew Boyer 		return "IOCPT_CMD_LIF_IDENTIFY";
80a677112dSAndrew Boyer 	case IOCPT_CMD_LIF_INIT:
81a677112dSAndrew Boyer 		return "IOCPT_CMD_LIF_INIT";
82a677112dSAndrew Boyer 	case IOCPT_CMD_LIF_RESET:
83a677112dSAndrew Boyer 		return "IOCPT_CMD_LIF_RESET";
84a677112dSAndrew Boyer 	case IOCPT_CMD_LIF_GETATTR:
85a677112dSAndrew Boyer 		return "IOCPT_CMD_LIF_GETATTR";
86a677112dSAndrew Boyer 	case IOCPT_CMD_LIF_SETATTR:
87a677112dSAndrew Boyer 		return "IOCPT_CMD_LIF_SETATTR";
88a677112dSAndrew Boyer 	case IOCPT_CMD_Q_IDENTIFY:
89a677112dSAndrew Boyer 		return "IOCPT_CMD_Q_IDENTIFY";
90a677112dSAndrew Boyer 	case IOCPT_CMD_Q_INIT:
91a677112dSAndrew Boyer 		return "IOCPT_CMD_Q_INIT";
92a677112dSAndrew Boyer 	case IOCPT_CMD_Q_CONTROL:
93a677112dSAndrew Boyer 		return "IOCPT_CMD_Q_CONTROL";
94a677112dSAndrew Boyer 	case IOCPT_CMD_SESS_CONTROL:
95a677112dSAndrew Boyer 		return "IOCPT_CMD_SESS_CONTROL";
96a677112dSAndrew Boyer 	default:
97a677112dSAndrew Boyer 		return "DEVCMD_UNKNOWN";
98a677112dSAndrew Boyer 	}
99a677112dSAndrew Boyer }
100a677112dSAndrew Boyer 
101a677112dSAndrew Boyer /* Dev_cmd Interface */
102a677112dSAndrew Boyer 
103a677112dSAndrew Boyer static void
iocpt_dev_cmd_go(struct iocpt_dev * dev,union iocpt_dev_cmd * cmd)104a677112dSAndrew Boyer iocpt_dev_cmd_go(struct iocpt_dev *dev, union iocpt_dev_cmd *cmd)
105a677112dSAndrew Boyer {
106a677112dSAndrew Boyer 	uint32_t cmd_size = RTE_DIM(cmd->words);
107a677112dSAndrew Boyer 	uint32_t i;
108a677112dSAndrew Boyer 
109a677112dSAndrew Boyer 	IOCPT_PRINT(DEBUG, "Sending %s (%d) via dev_cmd",
110a677112dSAndrew Boyer 		iocpt_opcode_to_str(cmd->cmd.opcode), cmd->cmd.opcode);
111a677112dSAndrew Boyer 
112a677112dSAndrew Boyer 	for (i = 0; i < cmd_size; i++)
113a677112dSAndrew Boyer 		iowrite32(cmd->words[i], &dev->dev_cmd->cmd.words[i]);
114a677112dSAndrew Boyer 
115a677112dSAndrew Boyer 	iowrite32(0, &dev->dev_cmd->done);
116a677112dSAndrew Boyer 	iowrite32(1, &dev->dev_cmd->doorbell);
117a677112dSAndrew Boyer }
118a677112dSAndrew Boyer 
119a677112dSAndrew Boyer static int
iocpt_dev_cmd_wait(struct iocpt_dev * dev,unsigned long max_wait)120a677112dSAndrew Boyer iocpt_dev_cmd_wait(struct iocpt_dev *dev, unsigned long max_wait)
121a677112dSAndrew Boyer {
122a677112dSAndrew Boyer 	unsigned long step_usec = IONIC_DEVCMD_CHECK_PERIOD_US;
123a677112dSAndrew Boyer 	unsigned long max_wait_usec = max_wait * 1000000L;
124a677112dSAndrew Boyer 	unsigned long elapsed_usec = 0;
125a677112dSAndrew Boyer 	int done;
126a677112dSAndrew Boyer 
127a677112dSAndrew Boyer 	/* Wait for dev cmd to complete.. but no more than max_wait sec */
128a677112dSAndrew Boyer 
129a677112dSAndrew Boyer 	do {
130a677112dSAndrew Boyer 		done = ioread32(&dev->dev_cmd->done) & IONIC_DEV_CMD_DONE;
131a677112dSAndrew Boyer 		if (done != 0) {
132a677112dSAndrew Boyer 			IOCPT_PRINT(DEBUG, "DEVCMD %d done took %lu usecs",
133a677112dSAndrew Boyer 				ioread8(&dev->dev_cmd->cmd.cmd.opcode),
134a677112dSAndrew Boyer 				elapsed_usec);
135a677112dSAndrew Boyer 			return 0;
136a677112dSAndrew Boyer 		}
137a677112dSAndrew Boyer 
138a677112dSAndrew Boyer 		rte_delay_us_block(step_usec);
139a677112dSAndrew Boyer 
140a677112dSAndrew Boyer 		elapsed_usec += step_usec;
141a677112dSAndrew Boyer 	} while (elapsed_usec < max_wait_usec);
142a677112dSAndrew Boyer 
143a677112dSAndrew Boyer 	IOCPT_PRINT(ERR, "DEVCMD %d timeout after %lu usecs",
144a677112dSAndrew Boyer 		ioread8(&dev->dev_cmd->cmd.cmd.opcode), elapsed_usec);
145a677112dSAndrew Boyer 
146a677112dSAndrew Boyer 	return -ETIMEDOUT;
147a677112dSAndrew Boyer }
148a677112dSAndrew Boyer 
149*2c1662bbSAndrew Boyer static void
iocpt_dev_cmd_comp(struct iocpt_dev * dev,void * mem)150*2c1662bbSAndrew Boyer iocpt_dev_cmd_comp(struct iocpt_dev *dev, void *mem)
151*2c1662bbSAndrew Boyer {
152*2c1662bbSAndrew Boyer 	union iocpt_dev_cmd_comp *comp = mem;
153*2c1662bbSAndrew Boyer 	uint32_t comp_size = RTE_DIM(comp->words);
154*2c1662bbSAndrew Boyer 	uint32_t i;
155*2c1662bbSAndrew Boyer 
156*2c1662bbSAndrew Boyer 	for (i = 0; i < comp_size; i++)
157*2c1662bbSAndrew Boyer 		comp->words[i] = ioread32(&dev->dev_cmd->comp.words[i]);
158*2c1662bbSAndrew Boyer }
159*2c1662bbSAndrew Boyer 
160a677112dSAndrew Boyer static int
iocpt_dev_cmd_wait_check(struct iocpt_dev * dev,unsigned long max_wait)161a677112dSAndrew Boyer iocpt_dev_cmd_wait_check(struct iocpt_dev *dev, unsigned long max_wait)
162a677112dSAndrew Boyer {
163a677112dSAndrew Boyer 	uint8_t status;
164a677112dSAndrew Boyer 	int err;
165a677112dSAndrew Boyer 
166a677112dSAndrew Boyer 	err = iocpt_dev_cmd_wait(dev, max_wait);
167a677112dSAndrew Boyer 	if (err == 0) {
168a677112dSAndrew Boyer 		status = ioread8(&dev->dev_cmd->comp.comp.status);
169a677112dSAndrew Boyer 		if (status == IOCPT_RC_EAGAIN)
170a677112dSAndrew Boyer 			err = -EAGAIN;
171a677112dSAndrew Boyer 		else if (status != 0)
172a677112dSAndrew Boyer 			err = -EIO;
173a677112dSAndrew Boyer 	}
174a677112dSAndrew Boyer 
175a677112dSAndrew Boyer 	IOCPT_PRINT(DEBUG, "dev_cmd returned %d", err);
176a677112dSAndrew Boyer 	return err;
177a677112dSAndrew Boyer }
178a677112dSAndrew Boyer 
179a677112dSAndrew Boyer /* Dev_cmds */
180a677112dSAndrew Boyer 
181a677112dSAndrew Boyer static void
iocpt_dev_cmd_reset(struct iocpt_dev * dev)182a677112dSAndrew Boyer iocpt_dev_cmd_reset(struct iocpt_dev *dev)
183a677112dSAndrew Boyer {
184a677112dSAndrew Boyer 	union iocpt_dev_cmd cmd = {
185a677112dSAndrew Boyer 		.reset.opcode = IOCPT_CMD_RESET,
186a677112dSAndrew Boyer 	};
187a677112dSAndrew Boyer 
188a677112dSAndrew Boyer 	iocpt_dev_cmd_go(dev, &cmd);
189a677112dSAndrew Boyer }
190a677112dSAndrew Boyer 
191a677112dSAndrew Boyer static void
iocpt_dev_cmd_lif_identify(struct iocpt_dev * dev,uint8_t ver)192a677112dSAndrew Boyer iocpt_dev_cmd_lif_identify(struct iocpt_dev *dev, uint8_t ver)
193a677112dSAndrew Boyer {
194a677112dSAndrew Boyer 	union iocpt_dev_cmd cmd = {
195a677112dSAndrew Boyer 		.lif_identify.opcode = IOCPT_CMD_LIF_IDENTIFY,
196a677112dSAndrew Boyer 		.lif_identify.type = IOCPT_LIF_TYPE_DEFAULT,
197a677112dSAndrew Boyer 		.lif_identify.ver = ver,
198a677112dSAndrew Boyer 	};
199a677112dSAndrew Boyer 
200a677112dSAndrew Boyer 	iocpt_dev_cmd_go(dev, &cmd);
201a677112dSAndrew Boyer }
202a677112dSAndrew Boyer 
203a677112dSAndrew Boyer static void
iocpt_dev_cmd_lif_init(struct iocpt_dev * dev,rte_iova_t info_pa)204a677112dSAndrew Boyer iocpt_dev_cmd_lif_init(struct iocpt_dev *dev, rte_iova_t info_pa)
205a677112dSAndrew Boyer {
206a677112dSAndrew Boyer 	union iocpt_dev_cmd cmd = {
207a677112dSAndrew Boyer 		.lif_init.opcode = IOCPT_CMD_LIF_INIT,
208a677112dSAndrew Boyer 		.lif_init.type = IOCPT_LIF_TYPE_DEFAULT,
209a677112dSAndrew Boyer 		.lif_init.info_pa = info_pa,
210a677112dSAndrew Boyer 	};
211a677112dSAndrew Boyer 
212a677112dSAndrew Boyer 	iocpt_dev_cmd_go(dev, &cmd);
213a677112dSAndrew Boyer }
214a677112dSAndrew Boyer 
215a677112dSAndrew Boyer static void
iocpt_dev_cmd_lif_reset(struct iocpt_dev * dev)216a677112dSAndrew Boyer iocpt_dev_cmd_lif_reset(struct iocpt_dev *dev)
217a677112dSAndrew Boyer {
218a677112dSAndrew Boyer 	union iocpt_dev_cmd cmd = {
219a677112dSAndrew Boyer 		.lif_reset.opcode = IOCPT_CMD_LIF_RESET,
220a677112dSAndrew Boyer 	};
221a677112dSAndrew Boyer 
222a677112dSAndrew Boyer 	iocpt_dev_cmd_go(dev, &cmd);
223a677112dSAndrew Boyer }
224a677112dSAndrew Boyer 
225a677112dSAndrew Boyer static void
iocpt_dev_cmd_queue_identify(struct iocpt_dev * dev,uint8_t qtype,uint8_t qver)226a677112dSAndrew Boyer iocpt_dev_cmd_queue_identify(struct iocpt_dev *dev,
227a677112dSAndrew Boyer 		uint8_t qtype, uint8_t qver)
228a677112dSAndrew Boyer {
229a677112dSAndrew Boyer 	union iocpt_dev_cmd cmd = {
230a677112dSAndrew Boyer 		.q_identify.opcode = IOCPT_CMD_Q_IDENTIFY,
231a677112dSAndrew Boyer 		.q_identify.type = qtype,
232a677112dSAndrew Boyer 		.q_identify.ver = qver,
233a677112dSAndrew Boyer 	};
234a677112dSAndrew Boyer 
235a677112dSAndrew Boyer 	iocpt_dev_cmd_go(dev, &cmd);
236a677112dSAndrew Boyer }
237a677112dSAndrew Boyer 
238*2c1662bbSAndrew Boyer static void
iocpt_dev_cmd_adminq_init(struct iocpt_dev * dev)239*2c1662bbSAndrew Boyer iocpt_dev_cmd_adminq_init(struct iocpt_dev *dev)
240*2c1662bbSAndrew Boyer {
241*2c1662bbSAndrew Boyer 	struct iocpt_queue *q = &dev->adminq->q;
242*2c1662bbSAndrew Boyer 	struct iocpt_cq *cq = &dev->adminq->cq;
243*2c1662bbSAndrew Boyer 
244*2c1662bbSAndrew Boyer 	union iocpt_dev_cmd cmd = {
245*2c1662bbSAndrew Boyer 		.q_init.opcode = IOCPT_CMD_Q_INIT,
246*2c1662bbSAndrew Boyer 		.q_init.type = q->type,
247*2c1662bbSAndrew Boyer 		.q_init.ver = dev->qtype_info[q->type].version,
248*2c1662bbSAndrew Boyer 		.q_init.index = rte_cpu_to_le_32(q->index),
249*2c1662bbSAndrew Boyer 		.q_init.flags = rte_cpu_to_le_16(IOCPT_QINIT_F_ENA),
250*2c1662bbSAndrew Boyer 		.q_init.intr_index = rte_cpu_to_le_16(IONIC_INTR_NONE),
251*2c1662bbSAndrew Boyer 		.q_init.ring_size = rte_log2_u32(q->num_descs),
252*2c1662bbSAndrew Boyer 		.q_init.ring_base = rte_cpu_to_le_64(q->base_pa),
253*2c1662bbSAndrew Boyer 		.q_init.cq_ring_base = rte_cpu_to_le_64(cq->base_pa),
254*2c1662bbSAndrew Boyer 	};
255*2c1662bbSAndrew Boyer 
256*2c1662bbSAndrew Boyer 	IOCPT_PRINT(DEBUG, "adminq.q_init.ver %u", cmd.q_init.ver);
257*2c1662bbSAndrew Boyer 
258*2c1662bbSAndrew Boyer 	iocpt_dev_cmd_go(dev, &cmd);
259*2c1662bbSAndrew Boyer }
260*2c1662bbSAndrew Boyer 
261a677112dSAndrew Boyer /* Dev_cmd consumers */
262a677112dSAndrew Boyer 
263a677112dSAndrew Boyer static void
iocpt_queue_identify(struct iocpt_dev * dev)264a677112dSAndrew Boyer iocpt_queue_identify(struct iocpt_dev *dev)
265a677112dSAndrew Boyer {
266a677112dSAndrew Boyer 	union iocpt_q_identity *q_ident = &dev->ident.q;
267a677112dSAndrew Boyer 	uint32_t q_words = RTE_DIM(q_ident->words);
268a677112dSAndrew Boyer 	uint32_t cmd_words = RTE_DIM(dev->dev_cmd->data);
269a677112dSAndrew Boyer 	uint32_t i, nwords, qtype;
270a677112dSAndrew Boyer 	int err;
271a677112dSAndrew Boyer 
272a677112dSAndrew Boyer 	for (qtype = 0; qtype < RTE_DIM(iocpt_qtype_vers); qtype++) {
273a677112dSAndrew Boyer 		struct iocpt_qtype_info *qti = &dev->qtype_info[qtype];
274a677112dSAndrew Boyer 
275a677112dSAndrew Boyer 		/* Filter out the types this driver knows about */
276a677112dSAndrew Boyer 		switch (qtype) {
277a677112dSAndrew Boyer 		case IOCPT_QTYPE_ADMINQ:
278a677112dSAndrew Boyer 		case IOCPT_QTYPE_NOTIFYQ:
279a677112dSAndrew Boyer 		case IOCPT_QTYPE_CRYPTOQ:
280a677112dSAndrew Boyer 			break;
281a677112dSAndrew Boyer 		default:
282a677112dSAndrew Boyer 			continue;
283a677112dSAndrew Boyer 		}
284a677112dSAndrew Boyer 
285a677112dSAndrew Boyer 		memset(qti, 0, sizeof(*qti));
286a677112dSAndrew Boyer 
287a677112dSAndrew Boyer 		if (iocpt_is_embedded()) {
288a677112dSAndrew Boyer 			/* When embedded, FW will always match the driver */
289a677112dSAndrew Boyer 			qti->version = iocpt_qtype_vers[qtype];
290a677112dSAndrew Boyer 			continue;
291a677112dSAndrew Boyer 		}
292a677112dSAndrew Boyer 
293a677112dSAndrew Boyer 		/* On the host, query the FW for info */
294a677112dSAndrew Boyer 		iocpt_dev_cmd_queue_identify(dev,
295a677112dSAndrew Boyer 			qtype, iocpt_qtype_vers[qtype]);
296a677112dSAndrew Boyer 		err = iocpt_dev_cmd_wait_check(dev, IONIC_DEVCMD_TIMEOUT);
297a677112dSAndrew Boyer 		if (err == -EINVAL) {
298a677112dSAndrew Boyer 			IOCPT_PRINT(ERR, "qtype %d not supported", qtype);
299a677112dSAndrew Boyer 			continue;
300a677112dSAndrew Boyer 		} else if (err == -EIO) {
301a677112dSAndrew Boyer 			IOCPT_PRINT(ERR, "q_ident failed, older FW");
302a677112dSAndrew Boyer 			return;
303a677112dSAndrew Boyer 		} else if (err != 0) {
304a677112dSAndrew Boyer 			IOCPT_PRINT(ERR, "q_ident failed, qtype %d: %d",
305a677112dSAndrew Boyer 				qtype, err);
306a677112dSAndrew Boyer 			return;
307a677112dSAndrew Boyer 		}
308a677112dSAndrew Boyer 
309a677112dSAndrew Boyer 		nwords = RTE_MIN(q_words, cmd_words);
310a677112dSAndrew Boyer 		for (i = 0; i < nwords; i++)
311a677112dSAndrew Boyer 			q_ident->words[i] = ioread32(&dev->dev_cmd->data[i]);
312a677112dSAndrew Boyer 
313a677112dSAndrew Boyer 		qti->version   = q_ident->version;
314a677112dSAndrew Boyer 		qti->supported = q_ident->supported;
315a677112dSAndrew Boyer 		qti->features  = rte_le_to_cpu_64(q_ident->features);
316a677112dSAndrew Boyer 		qti->desc_sz   = rte_le_to_cpu_16(q_ident->desc_sz);
317a677112dSAndrew Boyer 		qti->comp_sz   = rte_le_to_cpu_16(q_ident->comp_sz);
318a677112dSAndrew Boyer 		qti->sg_desc_sz = rte_le_to_cpu_16(q_ident->sg_desc_sz);
319a677112dSAndrew Boyer 		qti->max_sg_elems = rte_le_to_cpu_16(q_ident->max_sg_elems);
320a677112dSAndrew Boyer 		qti->sg_desc_stride =
321a677112dSAndrew Boyer 			rte_le_to_cpu_16(q_ident->sg_desc_stride);
322a677112dSAndrew Boyer 
323a677112dSAndrew Boyer 		IOCPT_PRINT(DEBUG, " qtype[%d].version = %d",
324a677112dSAndrew Boyer 			qtype, qti->version);
325a677112dSAndrew Boyer 		IOCPT_PRINT(DEBUG, " qtype[%d].supported = %#x",
326a677112dSAndrew Boyer 			qtype, qti->supported);
327a677112dSAndrew Boyer 		IOCPT_PRINT(DEBUG, " qtype[%d].features = %#jx",
328a677112dSAndrew Boyer 			qtype, qti->features);
329a677112dSAndrew Boyer 		IOCPT_PRINT(DEBUG, " qtype[%d].desc_sz = %d",
330a677112dSAndrew Boyer 			qtype, qti->desc_sz);
331a677112dSAndrew Boyer 		IOCPT_PRINT(DEBUG, " qtype[%d].comp_sz = %d",
332a677112dSAndrew Boyer 			qtype, qti->comp_sz);
333a677112dSAndrew Boyer 		IOCPT_PRINT(DEBUG, " qtype[%d].sg_desc_sz = %d",
334a677112dSAndrew Boyer 			qtype, qti->sg_desc_sz);
335a677112dSAndrew Boyer 		IOCPT_PRINT(DEBUG, " qtype[%d].max_sg_elems = %d",
336a677112dSAndrew Boyer 			qtype, qti->max_sg_elems);
337a677112dSAndrew Boyer 		IOCPT_PRINT(DEBUG, " qtype[%d].sg_desc_stride = %d",
338a677112dSAndrew Boyer 			qtype, qti->sg_desc_stride);
339a677112dSAndrew Boyer 	}
340a677112dSAndrew Boyer }
341a677112dSAndrew Boyer 
342a677112dSAndrew Boyer int
iocpt_dev_identify(struct iocpt_dev * dev)343a677112dSAndrew Boyer iocpt_dev_identify(struct iocpt_dev *dev)
344a677112dSAndrew Boyer {
345a677112dSAndrew Boyer 	union iocpt_lif_identity *ident = &dev->ident.lif;
346a677112dSAndrew Boyer 	union iocpt_lif_config *cfg = &ident->config;
347a677112dSAndrew Boyer 	uint64_t features;
348a677112dSAndrew Boyer 	uint32_t cmd_size = RTE_DIM(dev->dev_cmd->data);
349a677112dSAndrew Boyer 	uint32_t dev_size = RTE_DIM(ident->words);
350a677112dSAndrew Boyer 	uint32_t i, nwords;
351a677112dSAndrew Boyer 	int err;
352a677112dSAndrew Boyer 
353a677112dSAndrew Boyer 	memset(ident, 0, sizeof(*ident));
354a677112dSAndrew Boyer 
355a677112dSAndrew Boyer 	iocpt_dev_cmd_lif_identify(dev, IOCPT_IDENTITY_VERSION_1);
356a677112dSAndrew Boyer 	err = iocpt_dev_cmd_wait_check(dev, IONIC_DEVCMD_TIMEOUT);
357a677112dSAndrew Boyer 	if (err != 0)
358a677112dSAndrew Boyer 		return err;
359a677112dSAndrew Boyer 
360a677112dSAndrew Boyer 	nwords = RTE_MIN(dev_size, cmd_size);
361a677112dSAndrew Boyer 	for (i = 0; i < nwords; i++)
362a677112dSAndrew Boyer 		ident->words[i] = ioread32(&dev->dev_cmd->data[i]);
363a677112dSAndrew Boyer 
364a677112dSAndrew Boyer 	dev->max_qps =
365a677112dSAndrew Boyer 		rte_le_to_cpu_32(cfg->queue_count[IOCPT_QTYPE_CRYPTOQ]);
366a677112dSAndrew Boyer 	dev->max_sessions =
367a677112dSAndrew Boyer 		rte_le_to_cpu_32(ident->max_nb_sessions);
368a677112dSAndrew Boyer 
369a677112dSAndrew Boyer 	features = rte_le_to_cpu_64(ident->features);
370a677112dSAndrew Boyer 	dev->features = RTE_CRYPTODEV_FF_HW_ACCELERATED;
371a677112dSAndrew Boyer 	if (features & IOCPT_HW_SYM)
372a677112dSAndrew Boyer 		dev->features |= RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO;
373a677112dSAndrew Boyer 	if (features & IOCPT_HW_ASYM)
374a677112dSAndrew Boyer 		dev->features |= RTE_CRYPTODEV_FF_ASYMMETRIC_CRYPTO;
375a677112dSAndrew Boyer 	if (features & IOCPT_HW_CHAIN)
376a677112dSAndrew Boyer 		dev->features |= RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING;
377a677112dSAndrew Boyer 	if (features & IOCPT_HW_IP)
378a677112dSAndrew Boyer 		dev->features |= RTE_CRYPTODEV_FF_IN_PLACE_SGL;
379a677112dSAndrew Boyer 	if (features & IOCPT_HW_OOP) {
380a677112dSAndrew Boyer 		dev->features |= RTE_CRYPTODEV_FF_OOP_SGL_IN_SGL_OUT;
381a677112dSAndrew Boyer 		dev->features |= RTE_CRYPTODEV_FF_OOP_SGL_IN_LB_OUT;
382a677112dSAndrew Boyer 		dev->features |= RTE_CRYPTODEV_FF_OOP_LB_IN_LB_OUT;
383a677112dSAndrew Boyer 		dev->features |= RTE_CRYPTODEV_FF_OOP_LB_IN_SGL_OUT;
384a677112dSAndrew Boyer 	}
385a677112dSAndrew Boyer 
386a677112dSAndrew Boyer 	IOCPT_PRINT(INFO, "crypto.features %#jx",
387a677112dSAndrew Boyer 		rte_le_to_cpu_64(ident->features));
388a677112dSAndrew Boyer 	IOCPT_PRINT(INFO, "crypto.features_active %#jx",
389a677112dSAndrew Boyer 		rte_le_to_cpu_64(cfg->features));
390a677112dSAndrew Boyer 	IOCPT_PRINT(INFO, "crypto.queue_count[IOCPT_QTYPE_ADMINQ] %#x",
391a677112dSAndrew Boyer 		rte_le_to_cpu_32(cfg->queue_count[IOCPT_QTYPE_ADMINQ]));
392a677112dSAndrew Boyer 	IOCPT_PRINT(INFO, "crypto.queue_count[IOCPT_QTYPE_NOTIFYQ] %#x",
393a677112dSAndrew Boyer 		rte_le_to_cpu_32(cfg->queue_count[IOCPT_QTYPE_NOTIFYQ]));
394a677112dSAndrew Boyer 	IOCPT_PRINT(INFO, "crypto.queue_count[IOCPT_QTYPE_CRYPTOQ] %#x",
395a677112dSAndrew Boyer 		rte_le_to_cpu_32(cfg->queue_count[IOCPT_QTYPE_CRYPTOQ]));
396a677112dSAndrew Boyer 	IOCPT_PRINT(INFO, "crypto.max_sessions %u",
397a677112dSAndrew Boyer 		rte_le_to_cpu_32(ident->max_nb_sessions));
398a677112dSAndrew Boyer 
399a677112dSAndrew Boyer 	iocpt_queue_identify(dev);
400a677112dSAndrew Boyer 
401a677112dSAndrew Boyer 	return 0;
402a677112dSAndrew Boyer }
403a677112dSAndrew Boyer 
404a677112dSAndrew Boyer int
iocpt_dev_init(struct iocpt_dev * dev,rte_iova_t info_pa)405a677112dSAndrew Boyer iocpt_dev_init(struct iocpt_dev *dev, rte_iova_t info_pa)
406a677112dSAndrew Boyer {
407a677112dSAndrew Boyer 	uint32_t retries = 5;
408a677112dSAndrew Boyer 	int err;
409a677112dSAndrew Boyer 
410a677112dSAndrew Boyer retry_lif_init:
411a677112dSAndrew Boyer 	iocpt_dev_cmd_lif_init(dev, info_pa);
412a677112dSAndrew Boyer 
413a677112dSAndrew Boyer 	err = iocpt_dev_cmd_wait_check(dev, IONIC_DEVCMD_TIMEOUT);
414a677112dSAndrew Boyer 	if (err == -EAGAIN && retries > 0) {
415a677112dSAndrew Boyer 		retries--;
416a677112dSAndrew Boyer 		rte_delay_us_block(IONIC_DEVCMD_RETRY_WAIT_US);
417a677112dSAndrew Boyer 		goto retry_lif_init;
418a677112dSAndrew Boyer 	}
419a677112dSAndrew Boyer 
420a677112dSAndrew Boyer 	return err;
421a677112dSAndrew Boyer }
422a677112dSAndrew Boyer 
423a677112dSAndrew Boyer void
iocpt_dev_reset(struct iocpt_dev * dev)424a677112dSAndrew Boyer iocpt_dev_reset(struct iocpt_dev *dev)
425a677112dSAndrew Boyer {
426a677112dSAndrew Boyer 	iocpt_dev_cmd_lif_reset(dev);
427a677112dSAndrew Boyer 	(void)iocpt_dev_cmd_wait_check(dev, IONIC_DEVCMD_TIMEOUT);
428a677112dSAndrew Boyer 
429a677112dSAndrew Boyer 	iocpt_dev_cmd_reset(dev);
430a677112dSAndrew Boyer 	(void)iocpt_dev_cmd_wait_check(dev, IONIC_DEVCMD_TIMEOUT);
431a677112dSAndrew Boyer }
432*2c1662bbSAndrew Boyer 
433*2c1662bbSAndrew Boyer int
iocpt_dev_adminq_init(struct iocpt_dev * dev)434*2c1662bbSAndrew Boyer iocpt_dev_adminq_init(struct iocpt_dev *dev)
435*2c1662bbSAndrew Boyer {
436*2c1662bbSAndrew Boyer 	struct iocpt_queue *q = &dev->adminq->q;
437*2c1662bbSAndrew Boyer 	struct iocpt_q_init_comp comp;
438*2c1662bbSAndrew Boyer 	uint32_t retries = 5;
439*2c1662bbSAndrew Boyer 	int err;
440*2c1662bbSAndrew Boyer 
441*2c1662bbSAndrew Boyer retry_adminq_init:
442*2c1662bbSAndrew Boyer 	iocpt_dev_cmd_adminq_init(dev);
443*2c1662bbSAndrew Boyer 
444*2c1662bbSAndrew Boyer 	err = iocpt_dev_cmd_wait_check(dev, IONIC_DEVCMD_TIMEOUT);
445*2c1662bbSAndrew Boyer 	if (err == -EAGAIN && retries > 0) {
446*2c1662bbSAndrew Boyer 		retries--;
447*2c1662bbSAndrew Boyer 		rte_delay_us_block(IONIC_DEVCMD_RETRY_WAIT_US);
448*2c1662bbSAndrew Boyer 		goto retry_adminq_init;
449*2c1662bbSAndrew Boyer 	}
450*2c1662bbSAndrew Boyer 	if (err != 0)
451*2c1662bbSAndrew Boyer 		return err;
452*2c1662bbSAndrew Boyer 
453*2c1662bbSAndrew Boyer 	iocpt_dev_cmd_comp(dev, &comp);
454*2c1662bbSAndrew Boyer 
455*2c1662bbSAndrew Boyer 	q->hw_type = comp.hw_type;
456*2c1662bbSAndrew Boyer 	q->hw_index = rte_le_to_cpu_32(comp.hw_index);
457*2c1662bbSAndrew Boyer 	q->db = iocpt_db_map(dev, q);
458*2c1662bbSAndrew Boyer 
459*2c1662bbSAndrew Boyer 	IOCPT_PRINT(DEBUG, "adminq->hw_type %d", q->hw_type);
460*2c1662bbSAndrew Boyer 	IOCPT_PRINT(DEBUG, "adminq->hw_index %d", q->hw_index);
461*2c1662bbSAndrew Boyer 	IOCPT_PRINT(DEBUG, "adminq->db %p", q->db);
462*2c1662bbSAndrew Boyer 
463*2c1662bbSAndrew Boyer 	dev->adminq->flags |= IOCPT_Q_F_INITED;
464*2c1662bbSAndrew Boyer 
465*2c1662bbSAndrew Boyer 	return 0;
466*2c1662bbSAndrew Boyer }
467*2c1662bbSAndrew Boyer 
468*2c1662bbSAndrew Boyer /* Admin_cmd interface */
469*2c1662bbSAndrew Boyer 
470*2c1662bbSAndrew Boyer static bool
iocpt_adminq_service(struct iocpt_cq * cq,uint16_t cq_desc_index,void * cb_arg __rte_unused)471*2c1662bbSAndrew Boyer iocpt_adminq_service(struct iocpt_cq *cq, uint16_t cq_desc_index,
472*2c1662bbSAndrew Boyer 		void *cb_arg __rte_unused)
473*2c1662bbSAndrew Boyer {
474*2c1662bbSAndrew Boyer 	struct iocpt_admin_comp *cq_desc_base = cq->base;
475*2c1662bbSAndrew Boyer 	struct iocpt_admin_comp *cq_desc = &cq_desc_base[cq_desc_index];
476*2c1662bbSAndrew Boyer 	struct iocpt_admin_q *adminq =
477*2c1662bbSAndrew Boyer 		container_of(cq, struct iocpt_admin_q, cq);
478*2c1662bbSAndrew Boyer 	struct iocpt_queue *q = &adminq->q;
479*2c1662bbSAndrew Boyer 	struct iocpt_admin_ctx *ctx;
480*2c1662bbSAndrew Boyer 	uint16_t curr_q_tail_idx;
481*2c1662bbSAndrew Boyer 	uint16_t stop_index;
482*2c1662bbSAndrew Boyer 	void **info;
483*2c1662bbSAndrew Boyer 
484*2c1662bbSAndrew Boyer 	if (!iocpt_color_match(cq_desc->color, cq->done_color))
485*2c1662bbSAndrew Boyer 		return false;
486*2c1662bbSAndrew Boyer 
487*2c1662bbSAndrew Boyer 	stop_index = rte_le_to_cpu_16(cq_desc->comp_index);
488*2c1662bbSAndrew Boyer 
489*2c1662bbSAndrew Boyer 	do {
490*2c1662bbSAndrew Boyer 		info = IOCPT_INFO_PTR(q, q->tail_idx);
491*2c1662bbSAndrew Boyer 
492*2c1662bbSAndrew Boyer 		ctx = info[0];
493*2c1662bbSAndrew Boyer 		if (ctx != NULL) {
494*2c1662bbSAndrew Boyer 			memcpy(&ctx->comp, cq_desc, sizeof(*cq_desc));
495*2c1662bbSAndrew Boyer 			ctx->pending_work = false; /* done */
496*2c1662bbSAndrew Boyer 		}
497*2c1662bbSAndrew Boyer 
498*2c1662bbSAndrew Boyer 		curr_q_tail_idx = q->tail_idx;
499*2c1662bbSAndrew Boyer 		q->tail_idx = Q_NEXT_TO_SRVC(q, 1);
500*2c1662bbSAndrew Boyer 	} while (curr_q_tail_idx != stop_index);
501*2c1662bbSAndrew Boyer 
502*2c1662bbSAndrew Boyer 	return true;
503*2c1662bbSAndrew Boyer }
504*2c1662bbSAndrew Boyer 
505*2c1662bbSAndrew Boyer /** iocpt_adminq_post - Post an admin command.
506*2c1662bbSAndrew Boyer  * @dev:		Handle to dev.
507*2c1662bbSAndrew Boyer  * @cmd_ctx:		Api admin command context.
508*2c1662bbSAndrew Boyer  *
509*2c1662bbSAndrew Boyer  * Return: zero or negative error status.
510*2c1662bbSAndrew Boyer  */
511*2c1662bbSAndrew Boyer static int
iocpt_adminq_post(struct iocpt_dev * dev,struct iocpt_admin_ctx * ctx)512*2c1662bbSAndrew Boyer iocpt_adminq_post(struct iocpt_dev *dev, struct iocpt_admin_ctx *ctx)
513*2c1662bbSAndrew Boyer {
514*2c1662bbSAndrew Boyer 	struct iocpt_queue *q = &dev->adminq->q;
515*2c1662bbSAndrew Boyer 	struct iocpt_admin_cmd *q_desc_base = q->base;
516*2c1662bbSAndrew Boyer 	struct iocpt_admin_cmd *q_desc;
517*2c1662bbSAndrew Boyer 	void **info;
518*2c1662bbSAndrew Boyer 	int err = 0;
519*2c1662bbSAndrew Boyer 
520*2c1662bbSAndrew Boyer 	rte_spinlock_lock(&dev->adminq_lock);
521*2c1662bbSAndrew Boyer 
522*2c1662bbSAndrew Boyer 	if (iocpt_q_space_avail(q) < 1) {
523*2c1662bbSAndrew Boyer 		err = -ENOSPC;
524*2c1662bbSAndrew Boyer 		goto err_out;
525*2c1662bbSAndrew Boyer 	}
526*2c1662bbSAndrew Boyer 
527*2c1662bbSAndrew Boyer 	q_desc = &q_desc_base[q->head_idx];
528*2c1662bbSAndrew Boyer 
529*2c1662bbSAndrew Boyer 	memcpy(q_desc, &ctx->cmd, sizeof(ctx->cmd));
530*2c1662bbSAndrew Boyer 
531*2c1662bbSAndrew Boyer 	info = IOCPT_INFO_PTR(q, q->head_idx);
532*2c1662bbSAndrew Boyer 	info[0] = ctx;
533*2c1662bbSAndrew Boyer 
534*2c1662bbSAndrew Boyer 	q->head_idx = Q_NEXT_TO_POST(q, 1);
535*2c1662bbSAndrew Boyer 
536*2c1662bbSAndrew Boyer 	/* Ring doorbell */
537*2c1662bbSAndrew Boyer 	iocpt_q_flush(q);
538*2c1662bbSAndrew Boyer 
539*2c1662bbSAndrew Boyer err_out:
540*2c1662bbSAndrew Boyer 	rte_spinlock_unlock(&dev->adminq_lock);
541*2c1662bbSAndrew Boyer 
542*2c1662bbSAndrew Boyer 	return err;
543*2c1662bbSAndrew Boyer }
544*2c1662bbSAndrew Boyer 
545*2c1662bbSAndrew Boyer static int
iocpt_adminq_wait_for_completion(struct iocpt_dev * dev,struct iocpt_admin_ctx * ctx,unsigned long max_wait)546*2c1662bbSAndrew Boyer iocpt_adminq_wait_for_completion(struct iocpt_dev *dev,
547*2c1662bbSAndrew Boyer 		struct iocpt_admin_ctx *ctx, unsigned long max_wait)
548*2c1662bbSAndrew Boyer {
549*2c1662bbSAndrew Boyer 	struct iocpt_queue *q = &dev->adminq->q;
550*2c1662bbSAndrew Boyer 	unsigned long step_usec = IONIC_DEVCMD_CHECK_PERIOD_US;
551*2c1662bbSAndrew Boyer 	unsigned long step_deadline;
552*2c1662bbSAndrew Boyer 	unsigned long max_wait_usec = max_wait * 1000000L;
553*2c1662bbSAndrew Boyer 	unsigned long elapsed_usec = 0;
554*2c1662bbSAndrew Boyer 	int budget = 8;
555*2c1662bbSAndrew Boyer 	uint16_t idx;
556*2c1662bbSAndrew Boyer 	void **info;
557*2c1662bbSAndrew Boyer 
558*2c1662bbSAndrew Boyer 	step_deadline = IONIC_ADMINQ_WDOG_MS * 1000 / step_usec;
559*2c1662bbSAndrew Boyer 
560*2c1662bbSAndrew Boyer 	while (ctx->pending_work && elapsed_usec < max_wait_usec) {
561*2c1662bbSAndrew Boyer 		/*
562*2c1662bbSAndrew Boyer 		 * Locking here as adminq is served inline and could be
563*2c1662bbSAndrew Boyer 		 * called from multiple places
564*2c1662bbSAndrew Boyer 		 */
565*2c1662bbSAndrew Boyer 		rte_spinlock_lock(&dev->adminq_service_lock);
566*2c1662bbSAndrew Boyer 
567*2c1662bbSAndrew Boyer 		iocpt_cq_service(&dev->adminq->cq, budget,
568*2c1662bbSAndrew Boyer 			iocpt_adminq_service, NULL);
569*2c1662bbSAndrew Boyer 
570*2c1662bbSAndrew Boyer 		/*
571*2c1662bbSAndrew Boyer 		 * Ring the doorbell again if work is pending after step_usec.
572*2c1662bbSAndrew Boyer 		 */
573*2c1662bbSAndrew Boyer 		if (ctx->pending_work && !step_deadline) {
574*2c1662bbSAndrew Boyer 			step_deadline = IONIC_ADMINQ_WDOG_MS *
575*2c1662bbSAndrew Boyer 				1000 / step_usec;
576*2c1662bbSAndrew Boyer 
577*2c1662bbSAndrew Boyer 			rte_spinlock_lock(&dev->adminq_lock);
578*2c1662bbSAndrew Boyer 			idx = Q_NEXT_TO_POST(q, -1);
579*2c1662bbSAndrew Boyer 			info = IOCPT_INFO_PTR(q, idx);
580*2c1662bbSAndrew Boyer 			if (info[0] == ctx)
581*2c1662bbSAndrew Boyer 				iocpt_q_flush(q);
582*2c1662bbSAndrew Boyer 			rte_spinlock_unlock(&dev->adminq_lock);
583*2c1662bbSAndrew Boyer 		}
584*2c1662bbSAndrew Boyer 
585*2c1662bbSAndrew Boyer 		rte_spinlock_unlock(&dev->adminq_service_lock);
586*2c1662bbSAndrew Boyer 
587*2c1662bbSAndrew Boyer 		rte_delay_us_block(step_usec);
588*2c1662bbSAndrew Boyer 		elapsed_usec += step_usec;
589*2c1662bbSAndrew Boyer 		step_deadline--;
590*2c1662bbSAndrew Boyer 	}
591*2c1662bbSAndrew Boyer 
592*2c1662bbSAndrew Boyer 	return (!ctx->pending_work);
593*2c1662bbSAndrew Boyer }
594*2c1662bbSAndrew Boyer 
595*2c1662bbSAndrew Boyer static int
iocpt_adminq_check_err(struct iocpt_admin_ctx * ctx,bool timeout)596*2c1662bbSAndrew Boyer iocpt_adminq_check_err(struct iocpt_admin_ctx *ctx, bool timeout)
597*2c1662bbSAndrew Boyer {
598*2c1662bbSAndrew Boyer 	const char *name;
599*2c1662bbSAndrew Boyer 	const char *status;
600*2c1662bbSAndrew Boyer 
601*2c1662bbSAndrew Boyer 	name = iocpt_opcode_to_str(ctx->cmd.cmd.opcode);
602*2c1662bbSAndrew Boyer 
603*2c1662bbSAndrew Boyer 	if (ctx->comp.comp.status == IOCPT_RC_EAGAIN) {
604*2c1662bbSAndrew Boyer 		IOCPT_PRINT(DEBUG, "%s (%d) returned EAGAIN (%d)",
605*2c1662bbSAndrew Boyer 			name, ctx->cmd.cmd.opcode,
606*2c1662bbSAndrew Boyer 			ctx->comp.comp.status);
607*2c1662bbSAndrew Boyer 		return -EAGAIN;
608*2c1662bbSAndrew Boyer 	}
609*2c1662bbSAndrew Boyer 	if (ctx->comp.comp.status != 0 || timeout) {
610*2c1662bbSAndrew Boyer 		status = iocpt_error_to_str(ctx->comp.comp.status);
611*2c1662bbSAndrew Boyer 		IOCPT_PRINT(ERR, "%s (%d) failed: %s (%d)",
612*2c1662bbSAndrew Boyer 			name,
613*2c1662bbSAndrew Boyer 			ctx->cmd.cmd.opcode,
614*2c1662bbSAndrew Boyer 			timeout ? "TIMEOUT" : status,
615*2c1662bbSAndrew Boyer 			timeout ? -1 : ctx->comp.comp.status);
616*2c1662bbSAndrew Boyer 		return -EIO;
617*2c1662bbSAndrew Boyer 	}
618*2c1662bbSAndrew Boyer 
619*2c1662bbSAndrew Boyer 	if (ctx->cmd.cmd.opcode != IOCPT_CMD_SESS_CONTROL) {
620*2c1662bbSAndrew Boyer 		IOCPT_PRINT(DEBUG, "%s (%d) succeeded",
621*2c1662bbSAndrew Boyer 			name, ctx->cmd.cmd.opcode);
622*2c1662bbSAndrew Boyer 	}
623*2c1662bbSAndrew Boyer 
624*2c1662bbSAndrew Boyer 	return 0;
625*2c1662bbSAndrew Boyer }
626*2c1662bbSAndrew Boyer 
627*2c1662bbSAndrew Boyer int
iocpt_adminq_post_wait(struct iocpt_dev * dev,struct iocpt_admin_ctx * ctx)628*2c1662bbSAndrew Boyer iocpt_adminq_post_wait(struct iocpt_dev *dev, struct iocpt_admin_ctx *ctx)
629*2c1662bbSAndrew Boyer {
630*2c1662bbSAndrew Boyer 	bool done;
631*2c1662bbSAndrew Boyer 	int err;
632*2c1662bbSAndrew Boyer 
633*2c1662bbSAndrew Boyer 	if (ctx->cmd.cmd.opcode != IOCPT_CMD_SESS_CONTROL) {
634*2c1662bbSAndrew Boyer 		IOCPT_PRINT(DEBUG, "Sending %s (%d) via the admin queue",
635*2c1662bbSAndrew Boyer 			iocpt_opcode_to_str(ctx->cmd.cmd.opcode),
636*2c1662bbSAndrew Boyer 			ctx->cmd.cmd.opcode);
637*2c1662bbSAndrew Boyer 	}
638*2c1662bbSAndrew Boyer 
639*2c1662bbSAndrew Boyer 	err = iocpt_adminq_post(dev, ctx);
640*2c1662bbSAndrew Boyer 	if (err != 0) {
641*2c1662bbSAndrew Boyer 		IOCPT_PRINT(ERR, "Failure posting %d to the admin queue (%d)",
642*2c1662bbSAndrew Boyer 			ctx->cmd.cmd.opcode, err);
643*2c1662bbSAndrew Boyer 		return err;
644*2c1662bbSAndrew Boyer 	}
645*2c1662bbSAndrew Boyer 
646*2c1662bbSAndrew Boyer 	done = iocpt_adminq_wait_for_completion(dev, ctx,
647*2c1662bbSAndrew Boyer 		IONIC_DEVCMD_TIMEOUT);
648*2c1662bbSAndrew Boyer 
649*2c1662bbSAndrew Boyer 	return iocpt_adminq_check_err(ctx, !done /* timed out */);
650*2c1662bbSAndrew Boyer }
651