xref: /illumos-gate/usr/src/uts/common/io/ena/ena_admin.c (revision c46e4de3)
16f443ebcSRyan Zezeski /*
26f443ebcSRyan Zezeski  * This file and its contents are supplied under the terms of the
36f443ebcSRyan Zezeski  * Common Development and Distribution License ("CDDL"), version 1.0.
46f443ebcSRyan Zezeski  * You may only use this file in accordance with the terms of version
56f443ebcSRyan Zezeski  * 1.0 of the CDDL.
66f443ebcSRyan Zezeski  *
76f443ebcSRyan Zezeski  * A full copy of the text of the CDDL should have accompanied this
86f443ebcSRyan Zezeski  * source.  A copy of the CDDL is also available via the Internet at
96f443ebcSRyan Zezeski  * http://www.illumos.org/license/CDDL.
106f443ebcSRyan Zezeski  */
116f443ebcSRyan Zezeski 
126f443ebcSRyan Zezeski /*
13eebd18daSAndy Fiddaman  * Copyright 2024 Oxide Computer Company
146f443ebcSRyan Zezeski  */
156f443ebcSRyan Zezeski 
166f443ebcSRyan Zezeski /*
176f443ebcSRyan Zezeski  * This file contains everything having to do with communicating with
186f443ebcSRyan Zezeski  * the admin queue for sending commands to the device.
196f443ebcSRyan Zezeski  */
206f443ebcSRyan Zezeski 
216f443ebcSRyan Zezeski #include "ena_hw.h"
226f443ebcSRyan Zezeski #include "ena.h"
236f443ebcSRyan Zezeski 
246f443ebcSRyan Zezeski /*
256f443ebcSRyan Zezeski  * Mark the context as complete (a response has been received).
266f443ebcSRyan Zezeski  */
276f443ebcSRyan Zezeski static void
ena_complete_cmd_ctx(ena_cmd_ctx_t * ctx,enahw_resp_desc_t * hwresp)286f443ebcSRyan Zezeski ena_complete_cmd_ctx(ena_cmd_ctx_t *ctx, enahw_resp_desc_t *hwresp)
296f443ebcSRyan Zezeski {
306f443ebcSRyan Zezeski 	bcopy(hwresp, ctx->ectx_resp, sizeof (*hwresp));
31*c46e4de3SAndy Fiddaman 	ctx->ectx_pending = false;
32*c46e4de3SAndy Fiddaman }
33*c46e4de3SAndy Fiddaman 
34*c46e4de3SAndy Fiddaman static inline void
ena_reset_cmd_ctx(ena_cmd_ctx_t * ctx)35*c46e4de3SAndy Fiddaman ena_reset_cmd_ctx(ena_cmd_ctx_t *ctx)
36*c46e4de3SAndy Fiddaman {
37*c46e4de3SAndy Fiddaman 	ctx->ectx_pending = false;
38*c46e4de3SAndy Fiddaman 	ctx->ectx_resp = NULL;
39*c46e4de3SAndy Fiddaman 	ctx->ectx_cmd_opcode = ENAHW_CMD_NONE;
406f443ebcSRyan Zezeski }
416f443ebcSRyan Zezeski 
426f443ebcSRyan Zezeski /*
436f443ebcSRyan Zezeski  * Reset and release the context back to the free list.
446f443ebcSRyan Zezeski  */
456f443ebcSRyan Zezeski static void
ena_release_cmd_ctx(ena_t * ena,ena_cmd_ctx_t * ctx)466f443ebcSRyan Zezeski ena_release_cmd_ctx(ena_t *ena, ena_cmd_ctx_t *ctx)
476f443ebcSRyan Zezeski {
48*c46e4de3SAndy Fiddaman 	ASSERT(ctx->ectx_pending == false);
49*c46e4de3SAndy Fiddaman 	ena_reset_cmd_ctx(ctx);
506f443ebcSRyan Zezeski 
516f443ebcSRyan Zezeski 	mutex_enter(&ena->ena_aq.ea_sq_lock);
52eebd18daSAndy Fiddaman 	/*
53eebd18daSAndy Fiddaman 	 * We return the free descriptor to the end of the list so that we
54eebd18daSAndy Fiddaman 	 * cycle through them with each admin command, and don't end up almost
55eebd18daSAndy Fiddaman 	 * always re-using the same entry with the same command ID. While the
56*c46e4de3SAndy Fiddaman 	 * controller does not appear to mind, it's a little counter-intuitive.
57eebd18daSAndy Fiddaman 	 */
58*c46e4de3SAndy Fiddaman 	list_remove(&ena->ena_aq.ea_cmd_ctxs_used, ctx);
59eebd18daSAndy Fiddaman 	list_insert_tail(&ena->ena_aq.ea_cmd_ctxs_free, ctx);
606f443ebcSRyan Zezeski 	ena->ena_aq.ea_pending_cmds--;
616f443ebcSRyan Zezeski 	mutex_exit(&ena->ena_aq.ea_sq_lock);
626f443ebcSRyan Zezeski }
636f443ebcSRyan Zezeski 
64*c46e4de3SAndy Fiddaman void
ena_release_all_cmd_ctx(ena_t * ena)65*c46e4de3SAndy Fiddaman ena_release_all_cmd_ctx(ena_t *ena)
66*c46e4de3SAndy Fiddaman {
67*c46e4de3SAndy Fiddaman 	ena_adminq_t *aq = &ena->ena_aq;
68*c46e4de3SAndy Fiddaman 	ena_cmd_ctx_t *ctx;
69*c46e4de3SAndy Fiddaman 
70*c46e4de3SAndy Fiddaman 	mutex_enter(&aq->ea_sq_lock);
71*c46e4de3SAndy Fiddaman 	while ((ctx = list_remove_head(&aq->ea_cmd_ctxs_used)) != NULL) {
72*c46e4de3SAndy Fiddaman 		ena_reset_cmd_ctx(ctx);
73*c46e4de3SAndy Fiddaman 		list_insert_tail(&aq->ea_cmd_ctxs_free, ctx);
74*c46e4de3SAndy Fiddaman 	}
75*c46e4de3SAndy Fiddaman 	aq->ea_pending_cmds = 0;
76*c46e4de3SAndy Fiddaman 	mutex_exit(&aq->ea_sq_lock);
77*c46e4de3SAndy Fiddaman }
78*c46e4de3SAndy Fiddaman 
79*c46e4de3SAndy Fiddaman void
ena_create_cmd_ctx(ena_t * ena)80*c46e4de3SAndy Fiddaman ena_create_cmd_ctx(ena_t *ena)
81*c46e4de3SAndy Fiddaman {
82*c46e4de3SAndy Fiddaman 	ena_adminq_t *aq = &ena->ena_aq;
83*c46e4de3SAndy Fiddaman 
84*c46e4de3SAndy Fiddaman 	for (uint_t i = 0; i < aq->ea_qlen; i++) {
85*c46e4de3SAndy Fiddaman 		ena_cmd_ctx_t *ctx = &aq->ea_cmd_ctxs[i];
86*c46e4de3SAndy Fiddaman 
87*c46e4de3SAndy Fiddaman 		ctx->ectx_id = i;
88*c46e4de3SAndy Fiddaman 		ena_reset_cmd_ctx(ctx);
89*c46e4de3SAndy Fiddaman 		list_insert_tail(&aq->ea_cmd_ctxs_free, ctx);
90*c46e4de3SAndy Fiddaman 	}
91*c46e4de3SAndy Fiddaman }
92*c46e4de3SAndy Fiddaman 
936f443ebcSRyan Zezeski /*
94eebd18daSAndy Fiddaman  * Acquire the next available command context.
956f443ebcSRyan Zezeski  */
966f443ebcSRyan Zezeski static ena_cmd_ctx_t *
ena_acquire_cmd_ctx(ena_adminq_t * aq)976f443ebcSRyan Zezeski ena_acquire_cmd_ctx(ena_adminq_t *aq)
986f443ebcSRyan Zezeski {
996f443ebcSRyan Zezeski 	VERIFY(MUTEX_HELD(&aq->ea_sq_lock));
1006f443ebcSRyan Zezeski 	ASSERT3U(aq->ea_pending_cmds, <, aq->ea_qlen);
1016f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = list_remove_head(&aq->ea_cmd_ctxs_free);
102*c46e4de3SAndy Fiddaman 	list_insert_head(&aq->ea_cmd_ctxs_used, ctx);
1036f443ebcSRyan Zezeski 
104*c46e4de3SAndy Fiddaman 	ctx->ectx_pending = true;
1056f443ebcSRyan Zezeski 	return (ctx);
1066f443ebcSRyan Zezeski }
1076f443ebcSRyan Zezeski 
1086f443ebcSRyan Zezeski /*
1096f443ebcSRyan Zezeski  * Submit a command to the admin queue.
1106f443ebcSRyan Zezeski  */
1116f443ebcSRyan Zezeski int
ena_admin_submit_cmd(ena_t * ena,enahw_cmd_desc_t * cmd,enahw_resp_desc_t * resp,ena_cmd_ctx_t ** ctx)1126f443ebcSRyan Zezeski ena_admin_submit_cmd(ena_t *ena, enahw_cmd_desc_t *cmd, enahw_resp_desc_t *resp,
1136f443ebcSRyan Zezeski     ena_cmd_ctx_t **ctx)
1146f443ebcSRyan Zezeski {
1156f443ebcSRyan Zezeski 	VERIFY3U(cmd->ecd_opcode, !=, 0);
1166f443ebcSRyan Zezeski 	ena_adminq_t *aq = &ena->ena_aq;
1176f443ebcSRyan Zezeski 	ena_admin_sq_t *sq = &aq->ea_sq;
118*c46e4de3SAndy Fiddaman 	const uint16_t modulo_mask = aq->ea_qlen - 1;
1196f443ebcSRyan Zezeski 	ena_cmd_ctx_t *lctx = NULL;
1206f443ebcSRyan Zezeski 
1216f443ebcSRyan Zezeski 	mutex_enter(&aq->ea_sq_lock);
1226f443ebcSRyan Zezeski 	uint16_t tail_mod = sq->eas_tail & modulo_mask;
1236f443ebcSRyan Zezeski 
1246f443ebcSRyan Zezeski 	if (aq->ea_pending_cmds >= aq->ea_qlen) {
1256f443ebcSRyan Zezeski 		mutex_enter(&aq->ea_stat_lock);
1266f443ebcSRyan Zezeski 		aq->ea_stats.queue_full++;
1276f443ebcSRyan Zezeski 		mutex_exit(&aq->ea_stat_lock);
1286f443ebcSRyan Zezeski 		mutex_exit(&aq->ea_sq_lock);
1296f443ebcSRyan Zezeski 		return (ENOSPC);
1306f443ebcSRyan Zezeski 	}
1316f443ebcSRyan Zezeski 
1326f443ebcSRyan Zezeski 	lctx = ena_acquire_cmd_ctx(aq);
1336f443ebcSRyan Zezeski 	lctx->ectx_cmd_opcode = cmd->ecd_opcode;
1346f443ebcSRyan Zezeski 	lctx->ectx_resp = resp;
1356f443ebcSRyan Zezeski 
1366f443ebcSRyan Zezeski 	cmd->ecd_flags = sq->eas_phase & ENAHW_CMD_PHASE_MASK;
1376f443ebcSRyan Zezeski 	ENAHW_CMD_ID(cmd, lctx->ectx_id);
1386f443ebcSRyan Zezeski 	bcopy(cmd, &sq->eas_entries[tail_mod], sizeof (*cmd));
1396f443ebcSRyan Zezeski 	ENA_DMA_SYNC(sq->eas_dma, DDI_DMA_SYNC_FORDEV);
140*c46e4de3SAndy Fiddaman 
1416f443ebcSRyan Zezeski 	sq->eas_tail++;
1426f443ebcSRyan Zezeski 	aq->ea_pending_cmds++;
1436f443ebcSRyan Zezeski 
1446f443ebcSRyan Zezeski 	mutex_enter(&aq->ea_stat_lock);
1456f443ebcSRyan Zezeski 	aq->ea_stats.cmds_submitted++;
1466f443ebcSRyan Zezeski 	mutex_exit(&aq->ea_stat_lock);
1476f443ebcSRyan Zezeski 
1486f443ebcSRyan Zezeski 	DTRACE_PROBE4(cmd__submit, enahw_cmd_desc_t *, cmd, ena_cmd_ctx_t *,
1496f443ebcSRyan Zezeski 	    lctx, uint16_t, tail_mod, uint8_t, sq->eas_phase);
1506f443ebcSRyan Zezeski 
1516f443ebcSRyan Zezeski 	if ((sq->eas_tail & modulo_mask) == 0) {
152eebd18daSAndy Fiddaman 		sq->eas_phase ^= 1;
1536f443ebcSRyan Zezeski 	}
1546f443ebcSRyan Zezeski 
1556f443ebcSRyan Zezeski 	ena_hw_abs_write32(ena, sq->eas_dbaddr, sq->eas_tail);
1566f443ebcSRyan Zezeski 	mutex_exit(&aq->ea_sq_lock);
1576f443ebcSRyan Zezeski 	*ctx = lctx;
1586f443ebcSRyan Zezeski 	return (0);
1596f443ebcSRyan Zezeski }
1606f443ebcSRyan Zezeski 
1616f443ebcSRyan Zezeski /*
1626f443ebcSRyan Zezeski  * Read a single response from the admin queue.
1636f443ebcSRyan Zezeski  */
1646f443ebcSRyan Zezeski static void
ena_admin_read_resp(ena_t * ena,enahw_resp_desc_t * hwresp)1656f443ebcSRyan Zezeski ena_admin_read_resp(ena_t *ena, enahw_resp_desc_t *hwresp)
1666f443ebcSRyan Zezeski {
1676f443ebcSRyan Zezeski 	ena_adminq_t *aq = &ena->ena_aq;
1686f443ebcSRyan Zezeski 	ena_admin_cq_t *cq = &aq->ea_cq;
1696f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = NULL;
1706f443ebcSRyan Zezeski 	uint16_t modulo_mask = aq->ea_qlen - 1;
171*c46e4de3SAndy Fiddaman 
1726f443ebcSRyan Zezeski 	VERIFY(MUTEX_HELD(&aq->ea_cq_lock));
1736f443ebcSRyan Zezeski 
1746f443ebcSRyan Zezeski 	uint16_t head_mod = cq->eac_head & modulo_mask;
1756f443ebcSRyan Zezeski 	uint8_t phase = cq->eac_phase & ENAHW_RESP_PHASE_MASK;
1766f443ebcSRyan Zezeski 	uint16_t cmd_id = ENAHW_RESP_CMD_ID(hwresp);
177*c46e4de3SAndy Fiddaman 
1786f443ebcSRyan Zezeski 	ctx = &aq->ea_cmd_ctxs[cmd_id];
179*c46e4de3SAndy Fiddaman 
1806f443ebcSRyan Zezeski 	ASSERT3U(ctx->ectx_id, ==, cmd_id);
1816f443ebcSRyan Zezeski 	ena_complete_cmd_ctx(ctx, hwresp);
1826f443ebcSRyan Zezeski 
1836f443ebcSRyan Zezeski 	if (hwresp->erd_status != ENAHW_RESP_SUCCESS) {
1846f443ebcSRyan Zezeski 		mutex_enter(&aq->ea_stat_lock);
1856f443ebcSRyan Zezeski 		aq->ea_stats.cmds_fail++;
1866f443ebcSRyan Zezeski 		mutex_exit(&aq->ea_stat_lock);
1876f443ebcSRyan Zezeski 		DTRACE_PROBE4(cmd__fail, enahw_resp_desc_t *, hwresp,
1886f443ebcSRyan Zezeski 		    ena_cmd_ctx_t *, ctx, uint16_t, head_mod, uint8_t, phase);
1896f443ebcSRyan Zezeski 		return;
1906f443ebcSRyan Zezeski 	}
1916f443ebcSRyan Zezeski 
1926f443ebcSRyan Zezeski 	DTRACE_PROBE4(cmd__success, enahw_resp_desc_t *, hwresp,
1936f443ebcSRyan Zezeski 	    ena_cmd_ctx_t *, ctx, uint16_t, head_mod, uint8_t, phase);
1946f443ebcSRyan Zezeski 	mutex_enter(&aq->ea_stat_lock);
1956f443ebcSRyan Zezeski 	aq->ea_stats.cmds_success++;
1966f443ebcSRyan Zezeski 	mutex_exit(&aq->ea_stat_lock);
1976f443ebcSRyan Zezeski }
1986f443ebcSRyan Zezeski 
1996f443ebcSRyan Zezeski static void
ena_admin_process_responses(ena_t * ena)2006f443ebcSRyan Zezeski ena_admin_process_responses(ena_t *ena)
2016f443ebcSRyan Zezeski {
2026f443ebcSRyan Zezeski 	ena_adminq_t *aq = &ena->ena_aq;
2036f443ebcSRyan Zezeski 	ena_admin_cq_t *cq = &aq->ea_cq;
2046f443ebcSRyan Zezeski 	uint16_t modulo_mask = aq->ea_qlen - 1;
2056f443ebcSRyan Zezeski 	enahw_resp_desc_t *hwresp;
2066f443ebcSRyan Zezeski 
2076f443ebcSRyan Zezeski 	mutex_enter(&aq->ea_cq_lock);
2086f443ebcSRyan Zezeski 	uint16_t head_mod = cq->eac_head & modulo_mask;
2096f443ebcSRyan Zezeski 	uint8_t phase = cq->eac_phase & ENAHW_RESP_PHASE_MASK;
2106f443ebcSRyan Zezeski 
2116f443ebcSRyan Zezeski 	ENA_DMA_SYNC(cq->eac_dma, DDI_DMA_SYNC_FORKERNEL);
2126f443ebcSRyan Zezeski 	hwresp = &cq->eac_entries[head_mod];
2136f443ebcSRyan Zezeski 	while ((hwresp->erd_flags & ENAHW_RESP_PHASE_MASK) == phase) {
2146f443ebcSRyan Zezeski 		ena_admin_read_resp(ena, hwresp);
2156f443ebcSRyan Zezeski 
2166f443ebcSRyan Zezeski 		cq->eac_head++;
2176f443ebcSRyan Zezeski 		head_mod = cq->eac_head & modulo_mask;
2186f443ebcSRyan Zezeski 
2196f443ebcSRyan Zezeski 		if (head_mod == 0) {
220eebd18daSAndy Fiddaman 			phase ^= 1;
2216f443ebcSRyan Zezeski 		}
2226f443ebcSRyan Zezeski 
2236f443ebcSRyan Zezeski 		hwresp = &cq->eac_entries[head_mod];
2246f443ebcSRyan Zezeski 	}
2256f443ebcSRyan Zezeski 
2266f443ebcSRyan Zezeski 	cq->eac_phase = phase;
2276f443ebcSRyan Zezeski 	mutex_exit(&aq->ea_cq_lock);
2286f443ebcSRyan Zezeski }
2296f443ebcSRyan Zezeski 
2306f443ebcSRyan Zezeski /*
2316f443ebcSRyan Zezeski  * Wait for the command described by ctx to complete by polling for
2326f443ebcSRyan Zezeski  * status updates.
2336f443ebcSRyan Zezeski  */
2346f443ebcSRyan Zezeski int
ena_admin_poll_for_resp(ena_t * ena,ena_cmd_ctx_t * ctx)2356f443ebcSRyan Zezeski ena_admin_poll_for_resp(ena_t *ena, ena_cmd_ctx_t *ctx)
2366f443ebcSRyan Zezeski {
2376f443ebcSRyan Zezeski 	int ret = 0;
2386f443ebcSRyan Zezeski 	hrtime_t expire = gethrtime() + ena->ena_aq.ea_cmd_timeout_ns;
2396f443ebcSRyan Zezeski 
240*c46e4de3SAndy Fiddaman 	for (;;) {
2416f443ebcSRyan Zezeski 		ena_admin_process_responses(ena);
2426f443ebcSRyan Zezeski 
2436f443ebcSRyan Zezeski 		if (!ctx->ectx_pending) {
2446f443ebcSRyan Zezeski 			break;
2456f443ebcSRyan Zezeski 		}
2466f443ebcSRyan Zezeski 
2476f443ebcSRyan Zezeski 		/* Wait for 1 millisecond. */
2486f443ebcSRyan Zezeski 		delay(drv_usectohz(1000));
2496f443ebcSRyan Zezeski 
2506f443ebcSRyan Zezeski 		if (gethrtime() > expire) {
2516f443ebcSRyan Zezeski 			/*
2526f443ebcSRyan Zezeski 			 * We have no visibility into the device to
2536f443ebcSRyan Zezeski 			 * confirm it is making progress on this
2546f443ebcSRyan Zezeski 			 * command. At this point the driver and
2556f443ebcSRyan Zezeski 			 * device cannot agree on the state of the
2566f443ebcSRyan Zezeski 			 * world: perhaps the device is still making
2576f443ebcSRyan Zezeski 			 * progress but not fast enough, perhaps the
2586f443ebcSRyan Zezeski 			 * device completed the command but there was
2596f443ebcSRyan Zezeski 			 * a failure to deliver the reply, perhaps the
2606f443ebcSRyan Zezeski 			 * command failed but once again the reply was
2616f443ebcSRyan Zezeski 			 * not delivered. With this unknown state the
2626f443ebcSRyan Zezeski 			 * best thing to do is to reset the device and
263*c46e4de3SAndy Fiddaman 			 * start from scratch. There is even a reset
264*c46e4de3SAndy Fiddaman 			 * reason code just for this.
2656f443ebcSRyan Zezeski 			 */
266*c46e4de3SAndy Fiddaman 			ena_err(ena, "timed out waiting for admin response");
267*c46e4de3SAndy Fiddaman 			ena_trigger_reset(ena, ENAHW_RESET_ADMIN_TO);
268*c46e4de3SAndy Fiddaman 			return (EIO);
2696f443ebcSRyan Zezeski 		}
2706f443ebcSRyan Zezeski 	}
2716f443ebcSRyan Zezeski 
2726f443ebcSRyan Zezeski 	ret = enahw_resp_status_to_errno(ena, ctx->ectx_resp->erd_status);
2736f443ebcSRyan Zezeski 	ena_release_cmd_ctx(ena, ctx);
2746f443ebcSRyan Zezeski 	return (ret);
2756f443ebcSRyan Zezeski }
2766f443ebcSRyan Zezeski 
2776f443ebcSRyan Zezeski void
ena_free_host_info(ena_t * ena)2786f443ebcSRyan Zezeski ena_free_host_info(ena_t *ena)
2796f443ebcSRyan Zezeski {
2806f443ebcSRyan Zezeski 	ena_dma_free(&ena->ena_host_info);
2816f443ebcSRyan Zezeski }
2826f443ebcSRyan Zezeski 
283*c46e4de3SAndy Fiddaman bool
ena_init_host_info(ena_t * ena)2846f443ebcSRyan Zezeski ena_init_host_info(ena_t *ena)
2856f443ebcSRyan Zezeski {
2866f443ebcSRyan Zezeski 	enahw_host_info_t *ehi;
2876f443ebcSRyan Zezeski 	int ret = 0;
2886f443ebcSRyan Zezeski 	int *regs;
2896f443ebcSRyan Zezeski 	uint_t nregs;
2906f443ebcSRyan Zezeski 	ena_dma_buf_t *hi_dma;
2916f443ebcSRyan Zezeski 	enahw_cmd_desc_t cmd;
2926f443ebcSRyan Zezeski 	enahw_feat_host_attr_t *ha_cmd =
2936f443ebcSRyan Zezeski 	    &cmd.ecd_cmd.ecd_set_feat.ecsf_feat.ecsf_host_attr;
2946f443ebcSRyan Zezeski 	enahw_resp_desc_t resp;
2956f443ebcSRyan Zezeski 
2966f443ebcSRyan Zezeski 	hi_dma = &ena->ena_host_info;
2976f443ebcSRyan Zezeski 
298*c46e4de3SAndy Fiddaman 	if (hi_dma->edb_va == NULL) {
299*c46e4de3SAndy Fiddaman 		ena_dma_conf_t conf = {
300*c46e4de3SAndy Fiddaman 			.edc_size = ENAHW_HOST_INFO_ALLOC_SZ,
301*c46e4de3SAndy Fiddaman 			.edc_align = ENAHW_HOST_INFO_ALIGNMENT,
302*c46e4de3SAndy Fiddaman 			.edc_sgl = 1,
303*c46e4de3SAndy Fiddaman 			.edc_endian = DDI_NEVERSWAP_ACC,
304*c46e4de3SAndy Fiddaman 			.edc_stream = false,
305*c46e4de3SAndy Fiddaman 		};
306*c46e4de3SAndy Fiddaman 
307*c46e4de3SAndy Fiddaman 		if (!ena_dma_alloc(ena, hi_dma, &conf, 4096)) {
308*c46e4de3SAndy Fiddaman 			ena_err(ena, "failed to allocate DMA for host info");
309*c46e4de3SAndy Fiddaman 			return (false);
310*c46e4de3SAndy Fiddaman 		}
3116f443ebcSRyan Zezeski 	}
3126f443ebcSRyan Zezeski 
3136f443ebcSRyan Zezeski 	ehi = (void *)hi_dma->edb_va;
3146f443ebcSRyan Zezeski 	ehi->ehi_ena_spec_version =
3156f443ebcSRyan Zezeski 	    ((ENA_SPEC_VERSION_MAJOR << ENAHW_HOST_INFO_SPEC_MAJOR_SHIFT) |
3166f443ebcSRyan Zezeski 	    (ENA_SPEC_VERSION_MINOR));
3176f443ebcSRyan Zezeski 
3186f443ebcSRyan Zezeski 	ehi->ehi_bdf = 0;
3196f443ebcSRyan Zezeski 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ena->ena_dip,
3206f443ebcSRyan Zezeski 	    DDI_PROP_DONTPASS, "reg", &regs, &nregs) == DDI_PROP_SUCCESS) {
3216f443ebcSRyan Zezeski 		if (nregs != 0) {
3226f443ebcSRyan Zezeski 			ehi->ehi_bdf |= PCI_REG_BUS_G(regs[0]) << 8;
3236f443ebcSRyan Zezeski 			ehi->ehi_bdf |= PCI_REG_DEV_G(regs[0]) << 3;
3246f443ebcSRyan Zezeski 			ehi->ehi_bdf |= PCI_REG_FUNC_G(regs[0]);
3256f443ebcSRyan Zezeski 		}
3266f443ebcSRyan Zezeski 
3276f443ebcSRyan Zezeski 		ddi_prop_free(regs);
3286f443ebcSRyan Zezeski 	}
3296f443ebcSRyan Zezeski 
3306f443ebcSRyan Zezeski 	/*
3316f443ebcSRyan Zezeski 	 * There is no illumos OS type, it would be nice to ping
3326f443ebcSRyan Zezeski 	 * someone at Amazon and see if we can't get one added.
3336f443ebcSRyan Zezeski 	 */
3346f443ebcSRyan Zezeski 	ehi->ehi_os_type = ENAHW_OS_FREEBSD;
3356f443ebcSRyan Zezeski 	ehi->ehi_kernel_ver = 511; /* If you know you know */
3366f443ebcSRyan Zezeski 	(void) strlcpy((char *)ehi->ehi_kernel_ver_str, utsname.version,
3376f443ebcSRyan Zezeski 	    sizeof (ehi->ehi_kernel_ver_str));
3386f443ebcSRyan Zezeski 	ehi->ehi_os_dist = 0;	/* What everyone else does. */
3396f443ebcSRyan Zezeski 	ehi->ehi_driver_ver =
3406f443ebcSRyan Zezeski 	    (ENA_MODULE_VER_MAJOR) |
3416f443ebcSRyan Zezeski 	    (ENA_MODULE_VER_MINOR << ENAHW_HOST_INFO_MINOR_SHIFT) |
3426f443ebcSRyan Zezeski 	    (ENA_MODULE_VER_SUBMINOR << ENAHW_HOST_INFO_SUB_MINOR_SHIFT);
3436f443ebcSRyan Zezeski 	ehi->ehi_num_cpus = ncpus_online;
3446f443ebcSRyan Zezeski 
3456f443ebcSRyan Zezeski 	/*
3466f443ebcSRyan Zezeski 	 * ENA devices are not created equal. Some will support
3476f443ebcSRyan Zezeski 	 * features not found in others. This field tells the device
3486f443ebcSRyan Zezeski 	 * which features the driver supports.
3496f443ebcSRyan Zezeski 	 *
3506f443ebcSRyan Zezeski 	 * ENAHW_HOST_INFO_RX_OFFSET
3516f443ebcSRyan Zezeski 	 *
3526f443ebcSRyan Zezeski 	 *    Some ENA devices will write the frame data at an offset
3536f443ebcSRyan Zezeski 	 *    in the buffer, presumably for alignment purposes. We
3546f443ebcSRyan Zezeski 	 *    support this feature for the sole reason that the Linux
3556f443ebcSRyan Zezeski 	 *    driver does as well.
3566f443ebcSRyan Zezeski 	 *
3576f443ebcSRyan Zezeski 	 * ENAHW_HOST_INFO_INTERRUPT_MODERATION
3586f443ebcSRyan Zezeski 	 *
3596f443ebcSRyan Zezeski 	 *    Based on the Linux history this flag indicates that the
3606f443ebcSRyan Zezeski 	 *    driver "supports interrupt moderation properly". What
3616f443ebcSRyan Zezeski 	 *    that means is anyone's guess. The Linux driver seems to
3626f443ebcSRyan Zezeski 	 *    have some "adaptive" interrupt moderation, so perhaps
3636f443ebcSRyan Zezeski 	 *    it's that? In any case, FreeBSD doesn't bother with
3646f443ebcSRyan Zezeski 	 *    setting this flag, so we'll leave it be for now as well.
3656f443ebcSRyan Zezeski 	 *
3666f443ebcSRyan Zezeski 	 *    If you're curious to know if the device supports
3676f443ebcSRyan Zezeski 	 *    interrupt moderation: the FEAT_INTERRUPT_MODERATION flag
3686f443ebcSRyan Zezeski 	 *    will be set in ena_hw.eh_supported_features.
3696f443ebcSRyan Zezeski 	 *
3706f443ebcSRyan Zezeski 	 * ENAHW_HOST_INFO_RX_BUF_MIRRORING
3716f443ebcSRyan Zezeski 	 *
3726f443ebcSRyan Zezeski 	 *    Support traffic mirroring by allowing the hypervisor to
3736f443ebcSRyan Zezeski 	 *    read the buffer memory directly. This probably has to do
3746f443ebcSRyan Zezeski 	 *    with AWS flow logs, allowing more efficient mirroring.
3756f443ebcSRyan Zezeski 	 *    But it's hard to say for sure given we only have the
3766f443ebcSRyan Zezeski 	 *    Linux commit log to go off of. In any case, the only
3776f443ebcSRyan Zezeski 	 *    requirement for this feature is that the Rx DMA buffers
3786f443ebcSRyan Zezeski 	 *    be read/write, which they are.
3796f443ebcSRyan Zezeski 	 *
3806f443ebcSRyan Zezeski 	 * ENAHW_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY
3816f443ebcSRyan Zezeski 	 *
3826f443ebcSRyan Zezeski 	 *    The device supports the retrieving and updating of the
3836f443ebcSRyan Zezeski 	 *    RSS function and hash key. As we don't yet implement RSS
3846f443ebcSRyan Zezeski 	 *    this is disabled.
385*c46e4de3SAndy Fiddaman 	 *
386*c46e4de3SAndy Fiddaman 	 * ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE
387*c46e4de3SAndy Fiddaman 	 *
388*c46e4de3SAndy Fiddaman 	 *    Dynamic Rx Buffer feature. This feature allows the driver to
389*c46e4de3SAndy Fiddaman 	 *    avoid additional Rx buffer allocations by effectively using a
390*c46e4de3SAndy Fiddaman 	 *    buffer more than once if there is space remaining after receiving
391*c46e4de3SAndy Fiddaman 	 *    a packet. We currently use fixed TCBs and rings and don't
392*c46e4de3SAndy Fiddaman 	 *    implement this feature.
393*c46e4de3SAndy Fiddaman 	 *
394*c46e4de3SAndy Fiddaman 	 * ENA_ADMIN_HOST_INFO_TX_IPV6_CSUM_OFFLOAD
395*c46e4de3SAndy Fiddaman 	 *
396*c46e4de3SAndy Fiddaman 	 *    Indicate that the driver supports Tx IPv6 checksum offload.
397*c46e4de3SAndy Fiddaman 	 *
398*c46e4de3SAndy Fiddaman 	 * ENA_ADMIN_HOST_INFO_PHC
399*c46e4de3SAndy Fiddaman 	 *
400*c46e4de3SAndy Fiddaman 	 *    Instructs the device to enable its PHC (Precision Time Protocol
401*c46e4de3SAndy Fiddaman 	 *    Hardware Clock). In Linux, this would be exposed to userland NTP
402*c46e4de3SAndy Fiddaman 	 *    software as a PTP device. We don't support this so leave it
403*c46e4de3SAndy Fiddaman 	 *    disabled.
4046f443ebcSRyan Zezeski 	 */
4056f443ebcSRyan Zezeski 	ehi->ehi_driver_supported_features =
4066f443ebcSRyan Zezeski 	    ENAHW_HOST_INFO_RX_OFFSET_MASK |
4076f443ebcSRyan Zezeski 	    ENAHW_HOST_INFO_RX_BUF_MIRRORING_MASK;
4086f443ebcSRyan Zezeski 
4096f443ebcSRyan Zezeski 	ENA_DMA_SYNC(*hi_dma, DDI_DMA_SYNC_FORDEV);
4106f443ebcSRyan Zezeski 	bzero(&cmd, sizeof (cmd));
4116f443ebcSRyan Zezeski 	ena_set_dma_addr(ena, hi_dma->edb_cookie->dmac_laddress,
4126f443ebcSRyan Zezeski 	    &ha_cmd->efha_os_addr);
4136f443ebcSRyan Zezeski 
4146f443ebcSRyan Zezeski 	/*
4156f443ebcSRyan Zezeski 	 * You might notice the "debug area" is not allocated or
4166f443ebcSRyan Zezeski 	 * configured, that is on purpose.
4176f443ebcSRyan Zezeski 	 *
4186f443ebcSRyan Zezeski 	 * The "debug area" is a region of host memory that contains
4196f443ebcSRyan Zezeski 	 * the String Set (SS) tables used to report statistics to
4206f443ebcSRyan Zezeski 	 * tools like ethtool (on Linux). This table consists of one
4216f443ebcSRyan Zezeski 	 * of more entries of a 32-byte string (the name of the
4226f443ebcSRyan Zezeski 	 * statistic) along with its associated 64-bit value. The
4236f443ebcSRyan Zezeski 	 * stats reported here contain both the host-side stats as
4246f443ebcSRyan Zezeski 	 * well as device-reported stats (ENAHW_GET_STATS_TYPE_ENI). I
4256f443ebcSRyan Zezeski 	 * believe the reason for calling it the "debug area" is that
4266f443ebcSRyan Zezeski 	 * it can be accessed from outside of the guest, allowing an
4276f443ebcSRyan Zezeski 	 * AWS user (?) or Amazon employee to get basic information
4286f443ebcSRyan Zezeski 	 * about the state of the device from the guest's point of
4296f443ebcSRyan Zezeski 	 * view.
4306f443ebcSRyan Zezeski 	 *
4316f443ebcSRyan Zezeski 	 * In the fullness of time, our driver should probably support
4326f443ebcSRyan Zezeski 	 * this aspect of ENA. For the time being, all testing
4336f443ebcSRyan Zezeski 	 * indicates the driver and device function fine without it.
4346f443ebcSRyan Zezeski 	 */
4356f443ebcSRyan Zezeski 
4366f443ebcSRyan Zezeski 	ret = ena_set_feature(ena, &cmd, &resp, ENAHW_FEAT_HOST_ATTR_CONFIG,
4376f443ebcSRyan Zezeski 	    ENAHW_FEAT_HOST_ATTR_CONFIG_VER);
4386f443ebcSRyan Zezeski 	if (ret != 0) {
4396f443ebcSRyan Zezeski 		ena_err(ena, "failed to set host attributes: %d", ret);
4406f443ebcSRyan Zezeski 		ena_dma_free(hi_dma);
441*c46e4de3SAndy Fiddaman 		return (false);
4426f443ebcSRyan Zezeski 	}
4436f443ebcSRyan Zezeski 
444*c46e4de3SAndy Fiddaman 	return (true);
4456f443ebcSRyan Zezeski }
4466f443ebcSRyan Zezeski 
4476f443ebcSRyan Zezeski int
ena_create_cq(ena_t * ena,uint16_t num_descs,uint64_t phys_addr,bool is_tx,uint32_t vector,uint16_t * hw_index,uint32_t ** unmask_addr,uint32_t ** numanode)4486f443ebcSRyan Zezeski ena_create_cq(ena_t *ena, uint16_t num_descs, uint64_t phys_addr,
449*c46e4de3SAndy Fiddaman     bool is_tx, uint32_t vector, uint16_t *hw_index,
45013776732SAndy Fiddaman     uint32_t **unmask_addr, uint32_t **numanode)
4516f443ebcSRyan Zezeski {
4526f443ebcSRyan Zezeski 	int ret;
4536f443ebcSRyan Zezeski 	enahw_cmd_desc_t cmd;
4546f443ebcSRyan Zezeski 	enahw_cmd_create_cq_t *cmd_cq = &cmd.ecd_cmd.ecd_create_cq;
4556f443ebcSRyan Zezeski 	enahw_resp_desc_t resp;
4566f443ebcSRyan Zezeski 	enahw_resp_create_cq_t *resp_cq = &resp.erd_resp.erd_create_cq;
4576f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = NULL;
4586f443ebcSRyan Zezeski 	uint8_t desc_size = is_tx ? sizeof (enahw_tx_cdesc_t) :
4596f443ebcSRyan Zezeski 	    sizeof (enahw_rx_cdesc_t);
4606f443ebcSRyan Zezeski 
4616f443ebcSRyan Zezeski 	bzero(&cmd, sizeof (cmd));
4626f443ebcSRyan Zezeski 	bzero(&resp, sizeof (resp));
4636f443ebcSRyan Zezeski 
4646f443ebcSRyan Zezeski 	cmd.ecd_opcode = ENAHW_CMD_CREATE_CQ;
4656f443ebcSRyan Zezeski 	ENAHW_CMD_CREATE_CQ_INTERRUPT_MODE_ENABLE(cmd_cq);
4666f443ebcSRyan Zezeski 	ASSERT3U(desc_size % 4, ==, 0);
4676f443ebcSRyan Zezeski 	ENAHW_CMD_CREATE_CQ_DESC_SIZE_WORDS(cmd_cq, desc_size / 4);
4686f443ebcSRyan Zezeski 	cmd_cq->ecq_num_descs = num_descs;
4696f443ebcSRyan Zezeski 	cmd_cq->ecq_msix_vector = vector;
4706f443ebcSRyan Zezeski 	ena_set_dma_addr(ena, phys_addr, &cmd_cq->ecq_addr);
4716f443ebcSRyan Zezeski 
4726f443ebcSRyan Zezeski 	if ((ret = ena_admin_submit_cmd(ena, &cmd, &resp, &ctx)) != 0) {
4736f443ebcSRyan Zezeski 		ena_err(ena, "failed to submit Create CQ command: %d", ret);
4746f443ebcSRyan Zezeski 		return (ret);
4756f443ebcSRyan Zezeski 	}
4766f443ebcSRyan Zezeski 
4776f443ebcSRyan Zezeski 	if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) {
4786f443ebcSRyan Zezeski 		ena_err(ena, "failed to Create CQ: %d", ret);
4796f443ebcSRyan Zezeski 		return (ret);
4806f443ebcSRyan Zezeski 	}
4816f443ebcSRyan Zezeski 
4826f443ebcSRyan Zezeski 	*hw_index = resp_cq->ercq_idx;
4836f443ebcSRyan Zezeski 	*unmask_addr = (uint32_t *)(ena->ena_reg_base +
4846f443ebcSRyan Zezeski 	    resp_cq->ercq_interrupt_mask_reg_offset);
4856f443ebcSRyan Zezeski 
4866f443ebcSRyan Zezeski 	if (resp_cq->ercq_numa_node_reg_offset != 0) {
4876f443ebcSRyan Zezeski 		*numanode = (uint32_t *)(ena->ena_reg_base +
4886f443ebcSRyan Zezeski 		    resp_cq->ercq_numa_node_reg_offset);
4896f443ebcSRyan Zezeski 	} else {
4906f443ebcSRyan Zezeski 		*numanode = NULL;
4916f443ebcSRyan Zezeski 	}
4926f443ebcSRyan Zezeski 
49313776732SAndy Fiddaman 	/*
49413776732SAndy Fiddaman 	 * The CQ head doorbell register is no longer supported by any
49513776732SAndy Fiddaman 	 * existing adapter hardware.
49613776732SAndy Fiddaman 	 */
49713776732SAndy Fiddaman 	VERIFY0(resp_cq->ercq_head_db_reg_offset);
49813776732SAndy Fiddaman 
4996f443ebcSRyan Zezeski 	return (0);
5006f443ebcSRyan Zezeski }
5016f443ebcSRyan Zezeski 
5026f443ebcSRyan Zezeski int
ena_destroy_cq(ena_t * ena,uint16_t hw_idx)5036f443ebcSRyan Zezeski ena_destroy_cq(ena_t *ena, uint16_t hw_idx)
5046f443ebcSRyan Zezeski {
5056f443ebcSRyan Zezeski 	enahw_cmd_desc_t cmd;
5066f443ebcSRyan Zezeski 	enahw_resp_desc_t resp;
5076f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = NULL;
5086f443ebcSRyan Zezeski 	int ret;
5096f443ebcSRyan Zezeski 
5106f443ebcSRyan Zezeski 	bzero(&cmd, sizeof (cmd));
5116f443ebcSRyan Zezeski 	bzero(&resp, sizeof (resp));
5126f443ebcSRyan Zezeski 	cmd.ecd_opcode = ENAHW_CMD_DESTROY_CQ;
5136f443ebcSRyan Zezeski 	cmd.ecd_cmd.ecd_destroy_cq.edcq_idx = hw_idx;
5146f443ebcSRyan Zezeski 
5156f443ebcSRyan Zezeski 	if ((ret = ena_admin_submit_cmd(ena, &cmd, &resp, &ctx)) != 0) {
5166f443ebcSRyan Zezeski 		ena_err(ena, "failed to submit Destroy CQ command: %d", ret);
5176f443ebcSRyan Zezeski 		return (ret);
5186f443ebcSRyan Zezeski 	}
5196f443ebcSRyan Zezeski 
5206f443ebcSRyan Zezeski 	if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) {
5216f443ebcSRyan Zezeski 		ena_err(ena, "failed to Destroy CQ: %d", ret);
5226f443ebcSRyan Zezeski 		return (ret);
5236f443ebcSRyan Zezeski 	}
5246f443ebcSRyan Zezeski 
5256f443ebcSRyan Zezeski 	return (0);
5266f443ebcSRyan Zezeski }
5276f443ebcSRyan Zezeski 
5286f443ebcSRyan Zezeski int
ena_create_sq(ena_t * ena,uint16_t num_descs,uint64_t phys_addr,bool is_tx,uint16_t cq_index,uint16_t * hw_index,uint32_t ** db_addr)5296f443ebcSRyan Zezeski ena_create_sq(ena_t *ena, uint16_t num_descs, uint64_t phys_addr,
530*c46e4de3SAndy Fiddaman     bool is_tx, uint16_t cq_index, uint16_t *hw_index, uint32_t **db_addr)
5316f443ebcSRyan Zezeski {
5326f443ebcSRyan Zezeski 	int ret;
5336f443ebcSRyan Zezeski 	enahw_cmd_desc_t cmd;
5346f443ebcSRyan Zezeski 	enahw_cmd_create_sq_t *cmd_sq = &cmd.ecd_cmd.ecd_create_sq;
5356f443ebcSRyan Zezeski 	enahw_resp_desc_t resp;
5366f443ebcSRyan Zezeski 	enahw_resp_create_sq_t *resp_sq = &resp.erd_resp.erd_create_sq;
5376f443ebcSRyan Zezeski 	enahw_sq_direction_t dir =
5386f443ebcSRyan Zezeski 	    is_tx ? ENAHW_SQ_DIRECTION_TX : ENAHW_SQ_DIRECTION_RX;
5396f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = NULL;
5406f443ebcSRyan Zezeski 
5416f443ebcSRyan Zezeski 	if (!ISP2(num_descs)) {
5426f443ebcSRyan Zezeski 		ena_err(ena, "the number of descs must be a power of 2, but "
5436f443ebcSRyan Zezeski 		    " is %d", num_descs);
544*c46e4de3SAndy Fiddaman 		return (false);
5456f443ebcSRyan Zezeski 	}
5466f443ebcSRyan Zezeski 
5476f443ebcSRyan Zezeski 	bzero(&cmd, sizeof (cmd));
5486f443ebcSRyan Zezeski 	bzero(&resp, sizeof (resp));
5496f443ebcSRyan Zezeski 	cmd.ecd_opcode = ENAHW_CMD_CREATE_SQ;
5506f443ebcSRyan Zezeski 	ENAHW_CMD_CREATE_SQ_DIR(cmd_sq, dir);
5516f443ebcSRyan Zezeski 	ENAHW_CMD_CREATE_SQ_PLACEMENT_POLICY(cmd_sq,
5526f443ebcSRyan Zezeski 	    ENAHW_PLACEMENT_POLICY_HOST);
5536f443ebcSRyan Zezeski 	ENAHW_CMD_CREATE_SQ_COMPLETION_POLICY(cmd_sq,
5546f443ebcSRyan Zezeski 	    ENAHW_COMPLETION_POLICY_DESC);
5556f443ebcSRyan Zezeski 	/*
5566f443ebcSRyan Zezeski 	 * We limit all SQ descriptor rings to an SGL of 1, therefore
5576f443ebcSRyan Zezeski 	 * they are always physically contiguous.
5586f443ebcSRyan Zezeski 	 */
5596f443ebcSRyan Zezeski 	ENAHW_CMD_CREATE_SQ_PHYSMEM_CONTIG(cmd_sq);
5606f443ebcSRyan Zezeski 	cmd_sq->ecsq_cq_idx = cq_index;
5616f443ebcSRyan Zezeski 	cmd_sq->ecsq_num_descs = num_descs;
5626f443ebcSRyan Zezeski 
5636f443ebcSRyan Zezeski 	/*
5646f443ebcSRyan Zezeski 	 * If we ever use a non-host placement policy, then guard this
5656f443ebcSRyan Zezeski 	 * code against placement type (this value should not be set
5666f443ebcSRyan Zezeski 	 * for device placement).
5676f443ebcSRyan Zezeski 	 */
5686f443ebcSRyan Zezeski 	ena_set_dma_addr(ena, phys_addr, &cmd_sq->ecsq_base);
5696f443ebcSRyan Zezeski 
5706f443ebcSRyan Zezeski 	if ((ret = ena_admin_submit_cmd(ena, &cmd, &resp, &ctx)) != 0) {
5716f443ebcSRyan Zezeski 		ena_err(ena, "failed to submit Create SQ command: %d", ret);
5726f443ebcSRyan Zezeski 		return (ret);
5736f443ebcSRyan Zezeski 	}
5746f443ebcSRyan Zezeski 
5756f443ebcSRyan Zezeski 	if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) {
5766f443ebcSRyan Zezeski 		ena_err(ena, "failed to Create SQ: %d", ret);
5776f443ebcSRyan Zezeski 		return (ret);
5786f443ebcSRyan Zezeski 	}
5796f443ebcSRyan Zezeski 
5806f443ebcSRyan Zezeski 	*hw_index = resp_sq->ersq_idx;
5816f443ebcSRyan Zezeski 	*db_addr = (uint32_t *)(ena->ena_reg_base +
5826f443ebcSRyan Zezeski 	    resp_sq->ersq_db_reg_offset);
5836f443ebcSRyan Zezeski 	return (0);
5846f443ebcSRyan Zezeski }
5856f443ebcSRyan Zezeski 
5866f443ebcSRyan Zezeski int
ena_destroy_sq(ena_t * ena,uint16_t hw_idx,bool is_tx)587*c46e4de3SAndy Fiddaman ena_destroy_sq(ena_t *ena, uint16_t hw_idx, bool is_tx)
5886f443ebcSRyan Zezeski {
5896f443ebcSRyan Zezeski 	enahw_cmd_desc_t cmd;
5906f443ebcSRyan Zezeski 	enahw_cmd_destroy_sq_t *cmd_sq = &cmd.ecd_cmd.ecd_destroy_sq;
591eebd18daSAndy Fiddaman 	enahw_sq_direction_t dir =
592eebd18daSAndy Fiddaman 	    is_tx ? ENAHW_SQ_DIRECTION_TX : ENAHW_SQ_DIRECTION_RX;
5936f443ebcSRyan Zezeski 	enahw_resp_desc_t resp;
5946f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = NULL;
5956f443ebcSRyan Zezeski 	int ret;
5966f443ebcSRyan Zezeski 
5976f443ebcSRyan Zezeski 	bzero(&cmd, sizeof (cmd));
5986f443ebcSRyan Zezeski 	bzero(&resp, sizeof (resp));
5996f443ebcSRyan Zezeski 	cmd.ecd_opcode = ENAHW_CMD_DESTROY_SQ;
6006f443ebcSRyan Zezeski 	cmd_sq->edsq_idx = hw_idx;
601eebd18daSAndy Fiddaman 	ENAHW_CMD_DESTROY_SQ_DIR(cmd_sq, dir);
6026f443ebcSRyan Zezeski 
6036f443ebcSRyan Zezeski 	if ((ret = ena_admin_submit_cmd(ena, &cmd, &resp, &ctx)) != 0) {
6046f443ebcSRyan Zezeski 		ena_err(ena, "failed to submit Destroy SQ command: %d", ret);
6056f443ebcSRyan Zezeski 		return (ret);
6066f443ebcSRyan Zezeski 	}
6076f443ebcSRyan Zezeski 
6086f443ebcSRyan Zezeski 	if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) {
6096f443ebcSRyan Zezeski 		ena_err(ena, "failed Destroy SQ: %d", ret);
6106f443ebcSRyan Zezeski 		return (ret);
6116f443ebcSRyan Zezeski 	}
6126f443ebcSRyan Zezeski 
6136f443ebcSRyan Zezeski 	return (0);
6146f443ebcSRyan Zezeski }
6156f443ebcSRyan Zezeski 
6166f443ebcSRyan Zezeski int
ena_set_feature(ena_t * ena,enahw_cmd_desc_t * cmd,enahw_resp_desc_t * resp,const enahw_feature_id_t feat_id,const uint8_t feat_ver)6176f443ebcSRyan Zezeski ena_set_feature(ena_t *ena, enahw_cmd_desc_t *cmd, enahw_resp_desc_t *resp,
6186f443ebcSRyan Zezeski     const enahw_feature_id_t feat_id, const uint8_t feat_ver)
6196f443ebcSRyan Zezeski {
6206f443ebcSRyan Zezeski 	enahw_cmd_set_feat_t *cmd_sf = &cmd->ecd_cmd.ecd_set_feat;
6216f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = NULL;
6226f443ebcSRyan Zezeski 	int ret = 0;
6236f443ebcSRyan Zezeski 
624*c46e4de3SAndy Fiddaman 	if (!ena_is_feat_avail(ena, feat_id)) {
6256f443ebcSRyan Zezeski 		ena_err(ena, "attempted to set unsupported feature: 0x%x %d"
6266f443ebcSRyan Zezeski 		    " (0x%x)", feat_id, feat_ver, ena->ena_supported_features);
6276f443ebcSRyan Zezeski 		return (ENOTSUP);
6286f443ebcSRyan Zezeski 	}
6296f443ebcSRyan Zezeski 
6306f443ebcSRyan Zezeski 	cmd->ecd_opcode = ENAHW_CMD_SET_FEATURE;
6316f443ebcSRyan Zezeski 	cmd_sf->ecsf_comm.efc_id = feat_id;
6326f443ebcSRyan Zezeski 	cmd_sf->ecsf_comm.efc_version = feat_ver;
6336f443ebcSRyan Zezeski 	cmd_sf->ecsf_comm.efc_flags = 0;
6346f443ebcSRyan Zezeski 
6356f443ebcSRyan Zezeski 	if ((ret = ena_admin_submit_cmd(ena, cmd, resp, &ctx)) != 0) {
6366f443ebcSRyan Zezeski 		ena_err(ena, "failed to submit Set Feature command: %d", ret);
6376f443ebcSRyan Zezeski 		return (ret);
6386f443ebcSRyan Zezeski 	}
6396f443ebcSRyan Zezeski 
6406f443ebcSRyan Zezeski 	return (ena_admin_poll_for_resp(ena, ctx));
6416f443ebcSRyan Zezeski }
6426f443ebcSRyan Zezeski 
6436f443ebcSRyan Zezeski int
ena_get_feature(ena_t * ena,enahw_resp_desc_t * resp,const enahw_feature_id_t feat_id,const uint8_t feat_ver)6446f443ebcSRyan Zezeski ena_get_feature(ena_t *ena, enahw_resp_desc_t *resp,
6456f443ebcSRyan Zezeski     const enahw_feature_id_t feat_id, const uint8_t feat_ver)
6466f443ebcSRyan Zezeski {
6476f443ebcSRyan Zezeski 	enahw_cmd_desc_t cmd;
6486f443ebcSRyan Zezeski 	enahw_cmd_get_feat_t *cmd_gf = &cmd.ecd_cmd.ecd_get_feat;
6496f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = NULL;
6506f443ebcSRyan Zezeski 	int ret = 0;
6516f443ebcSRyan Zezeski 
652*c46e4de3SAndy Fiddaman 	if (!ena_is_feat_avail(ena, feat_id)) {
6536f443ebcSRyan Zezeski 		return (ENOTSUP);
6546f443ebcSRyan Zezeski 	}
6556f443ebcSRyan Zezeski 
6566f443ebcSRyan Zezeski 	bzero(&cmd, sizeof (cmd));
6576f443ebcSRyan Zezeski 	cmd.ecd_opcode = ENAHW_CMD_GET_FEATURE;
6586f443ebcSRyan Zezeski 	cmd_gf->ecgf_comm.efc_id = feat_id;
6596f443ebcSRyan Zezeski 	cmd_gf->ecgf_comm.efc_version = feat_ver;
6606f443ebcSRyan Zezeski 	ENAHW_GET_FEAT_FLAGS_GET_CURR_VAL(cmd_gf);
6616f443ebcSRyan Zezeski 
6626f443ebcSRyan Zezeski 	if ((ret = ena_admin_submit_cmd(ena, &cmd, resp, &ctx)) != 0) {
6636f443ebcSRyan Zezeski 		ena_err(ena, "failed to submit Get Feature command: %d", ret);
6646f443ebcSRyan Zezeski 		return (ret);
6656f443ebcSRyan Zezeski 	}
6666f443ebcSRyan Zezeski 
6676f443ebcSRyan Zezeski 	return (ena_admin_poll_for_resp(ena, ctx));
6686f443ebcSRyan Zezeski }
6696f443ebcSRyan Zezeski 
6706f443ebcSRyan Zezeski int
ena_admin_get_basic_stats(ena_t * ena,enahw_resp_desc_t * resp)6716f443ebcSRyan Zezeski ena_admin_get_basic_stats(ena_t *ena, enahw_resp_desc_t *resp)
6726f443ebcSRyan Zezeski {
6736f443ebcSRyan Zezeski 	int ret = 0;
6746f443ebcSRyan Zezeski 	enahw_cmd_desc_t cmd;
6756f443ebcSRyan Zezeski 	enahw_cmd_get_stats_t *cmd_stats = &cmd.ecd_cmd.ecd_get_stats;
6766f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = NULL;
6776f443ebcSRyan Zezeski 
6786f443ebcSRyan Zezeski 	bzero(&cmd, sizeof (cmd));
6796f443ebcSRyan Zezeski 	bzero(resp, sizeof (*resp));
6806f443ebcSRyan Zezeski 	cmd.ecd_opcode = ENAHW_CMD_GET_STATS;
6816f443ebcSRyan Zezeski 	cmd_stats->ecgs_type = ENAHW_GET_STATS_TYPE_BASIC;
6826f443ebcSRyan Zezeski 	cmd_stats->ecgs_scope = ENAHW_GET_STATS_SCOPE_ETH;
6836f443ebcSRyan Zezeski 	cmd_stats->ecgs_device_id = ENAHW_CMD_GET_STATS_MY_DEVICE_ID;
6846f443ebcSRyan Zezeski 
6856f443ebcSRyan Zezeski 	if ((ret = ena_admin_submit_cmd(ena, &cmd, resp, &ctx)) != 0) {
6866f443ebcSRyan Zezeski 		ena_err(ena, "failed to submit Get Basic Stats command: %d",
6876f443ebcSRyan Zezeski 		    ret);
6886f443ebcSRyan Zezeski 		return (ret);
6896f443ebcSRyan Zezeski 	}
6906f443ebcSRyan Zezeski 
6916f443ebcSRyan Zezeski 	if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) {
6926f443ebcSRyan Zezeski 		ena_err(ena, "failed to Get Basic Stats: %d", ret);
6936f443ebcSRyan Zezeski 		return (ret);
6946f443ebcSRyan Zezeski 	}
6956f443ebcSRyan Zezeski 
6966f443ebcSRyan Zezeski 	return (0);
6976f443ebcSRyan Zezeski }
6986f443ebcSRyan Zezeski 
6996f443ebcSRyan Zezeski int
ena_admin_get_eni_stats(ena_t * ena,enahw_resp_desc_t * resp)7006f443ebcSRyan Zezeski ena_admin_get_eni_stats(ena_t *ena, enahw_resp_desc_t *resp)
7016f443ebcSRyan Zezeski {
7026f443ebcSRyan Zezeski 	int ret = 0;
7036f443ebcSRyan Zezeski 	enahw_cmd_desc_t cmd;
7046f443ebcSRyan Zezeski 	enahw_cmd_get_stats_t *cmd_stats = &cmd.ecd_cmd.ecd_get_stats;
7056f443ebcSRyan Zezeski 	ena_cmd_ctx_t *ctx = NULL;
7066f443ebcSRyan Zezeski 
7076f443ebcSRyan Zezeski 	bzero(&cmd, sizeof (cmd));
7086f443ebcSRyan Zezeski 	bzero(resp, sizeof (*resp));
7096f443ebcSRyan Zezeski 	cmd.ecd_opcode = ENAHW_CMD_GET_STATS;
7106f443ebcSRyan Zezeski 	cmd_stats->ecgs_type = ENAHW_GET_STATS_TYPE_ENI;
7116f443ebcSRyan Zezeski 	cmd_stats->ecgs_scope = ENAHW_GET_STATS_SCOPE_ETH;
7126f443ebcSRyan Zezeski 	cmd_stats->ecgs_device_id = ENAHW_CMD_GET_STATS_MY_DEVICE_ID;
7136f443ebcSRyan Zezeski 
7146f443ebcSRyan Zezeski 	if ((ret = ena_admin_submit_cmd(ena, &cmd, resp, &ctx)) != 0) {
7156f443ebcSRyan Zezeski 		ena_err(ena, "failed to submit Get ENI Stats command: %d", ret);
7166f443ebcSRyan Zezeski 		return (ret);
7176f443ebcSRyan Zezeski 	}
7186f443ebcSRyan Zezeski 
7196f443ebcSRyan Zezeski 	if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) {
7206f443ebcSRyan Zezeski 		ena_err(ena, "failed to Get ENI Stats: %d", ret);
7216f443ebcSRyan Zezeski 		return (ret);
7226f443ebcSRyan Zezeski 	}
7236f443ebcSRyan Zezeski 
7246f443ebcSRyan Zezeski 	return (0);
7256f443ebcSRyan Zezeski }
726