xref: /illumos-gate/usr/src/uts/common/io/mlxcx/mlxcx_cmd.c (revision f9c7ecc9013918bf789e154e2ed5f2e8fb6ce24c)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2020, The University of Queensland
14  * Copyright (c) 2018, Joyent, Inc.
15  */
16 
17 /*
18  * Controls the management of commands that are issues to and from the HCA
19  * command queue.
20  */
21 
22 #include <mlxcx.h>
23 
24 #include <sys/debug.h>
25 #include <sys/sysmacros.h>
26 
27 /*
28  * When we start up the command queue, it will undergo some internal
29  * initialization after we set the command queue address. These values allow us
30  * to control how much time we should wait for that to occur.
31  */
32 clock_t mlxcx_cmd_init_delay = 1000 * 10; /* 10 ms in us */
33 uint_t mlxcx_cmd_init_trys = 100; /* Wait at most 1s */
34 
35 clock_t mlxcx_cmd_delay = 1000 * 1; /* 1 ms in us */
36 uint_t mlxcx_cmd_tries = 5000; /* Wait at most 1s */
37 
38 /*
39  * This macro is used to identify that we care about our own function that we're
40  * communicating with. We always use this function.
41  */
42 #define	MLXCX_FUNCTION_SELF	(to_be16(0))
43 
44 static const char *
45 mlxcx_cmd_response_string(mlxcx_cmd_ret_t ret)
46 {
47 	switch (ret) {
48 	case MLXCX_CMD_R_OK:
49 		return ("MLXCX_CMD_R_OK");
50 	case MLXCX_CMD_R_INTERNAL_ERR:
51 		return ("MLXCX_CMD_R_INTERNAL_ERR");
52 	case MLXCX_CMD_R_BAD_OP:
53 		return ("MLXCX_CMD_R_BAD_OP");
54 	case MLXCX_CMD_R_BAD_PARAM:
55 		return ("MLXCX_CMD_R_BAD_PARAM");
56 	case MLXCX_CMD_R_BAD_SYS_STATE:
57 		return ("MLXCX_CMD_R_BAD_SYS_STATE");
58 	case MLXCX_CMD_R_BAD_RESOURCE:
59 		return ("MLXCX_CMD_R_BAD_RESOURCE");
60 	case MLXCX_CMD_R_RESOURCE_BUSY:
61 		return ("MLXCX_CMD_R_RESOURCE_BUSY");
62 	case MLXCX_CMD_R_EXCEED_LIM:
63 		return ("MLXCX_CMD_R_EXCEED_LIM");
64 	case MLXCX_CMD_R_BAD_RES_STATE:
65 		return ("MLXCX_CMD_R_BAD_RES_STATE");
66 	case MLXCX_CMD_R_BAD_INDEX:
67 		return ("MLXCX_CMD_R_BAD_INDEX");
68 	case MLXCX_CMD_R_NO_RESOURCES:
69 		return ("MLXCX_CMD_R_NO_RESOURCES");
70 	case MLXCX_CMD_R_BAD_INPUT_LEN:
71 		return ("MLXCX_CMD_R_BAD_INPUT_LEN");
72 	case MLXCX_CMD_R_BAD_OUTPUT_LEN:
73 		return ("MLXCX_CMD_R_BAD_OUTPUT_LEN");
74 	case MLXCX_CMD_R_BAD_RESOURCE_STATE:
75 		return ("MLXCX_CMD_R_BAD_RESOURCE_STATE");
76 	case MLXCX_CMD_R_BAD_PKT:
77 		return ("MLXCX_CMD_R_BAD_PKT");
78 	case MLXCX_CMD_R_BAD_SIZE:
79 		return ("MLXCX_CMD_R_BAD_SIZE");
80 	default:
81 		return ("Unknown command");
82 	}
83 }
84 
85 static const char *
86 mlxcx_cmd_opcode_string(mlxcx_cmd_op_t op)
87 {
88 	switch (op) {
89 	case MLXCX_OP_QUERY_HCA_CAP:
90 		return ("MLXCX_OP_QUERY_HCA_CAP");
91 	case MLXCX_OP_QUERY_ADAPTER:
92 		return ("MLXCX_OP_QUERY_ADAPTER");
93 	case MLXCX_OP_INIT_HCA:
94 		return ("MLXCX_OP_INIT_HCA");
95 	case MLXCX_OP_TEARDOWN_HCA:
96 		return ("MLXCX_OP_TEARDOWN_HCA");
97 	case MLXCX_OP_ENABLE_HCA:
98 		return ("MLXCX_OP_ENABLE_HCA");
99 	case MLXCX_OP_DISABLE_HCA:
100 		return ("MLXCX_OP_DISABLE_HCA");
101 	case MLXCX_OP_QUERY_PAGES:
102 		return ("MLXCX_OP_QUERY_PAGES");
103 	case MLXCX_OP_MANAGE_PAGES:
104 		return ("MLXCX_OP_MANAGE_PAGES");
105 	case MLXCX_OP_SET_HCA_CAP:
106 		return ("MLXCX_OP_SET_HCA_CAP");
107 	case MLXCX_OP_QUERY_ISSI:
108 		return ("MLXCX_OP_QUERY_ISSI");
109 	case MLXCX_OP_SET_ISSI:
110 		return ("MLXCX_OP_SET_ISSI");
111 	case MLXCX_OP_SET_DRIVER_VERSION:
112 		return ("MLXCX_OP_SET_DRIVER_VERSION");
113 	case MLXCX_OP_QUERY_OTHER_HCA_CAP:
114 		return ("MLXCX_OP_QUERY_OTHER_HCA_CAP");
115 	case MLXCX_OP_MODIFY_OTHER_HCA_CAP:
116 		return ("MLXCX_OP_MODIFY_OTHER_HCA_CAP");
117 	case MLXCX_OP_SET_TUNNELED_OPERATIONS:
118 		return ("MLXCX_OP_SET_TUNNELED_OPERATIONS");
119 	case MLXCX_OP_CREATE_MKEY:
120 		return ("MLXCX_OP_CREATE_MKEY");
121 	case MLXCX_OP_QUERY_MKEY:
122 		return ("MLXCX_OP_QUERY_MKEY");
123 	case MLXCX_OP_DESTROY_MKEY:
124 		return ("MLXCX_OP_DESTROY_MKEY");
125 	case MLXCX_OP_QUERY_SPECIAL_CONTEXTS:
126 		return ("MLXCX_OP_QUERY_SPECIAL_CONTEXTS");
127 	case MLXCX_OP_PAGE_FAULT_RESUME:
128 		return ("MLXCX_OP_PAGE_FAULT_RESUME");
129 	case MLXCX_OP_CREATE_EQ:
130 		return ("MLXCX_OP_CREATE_EQ");
131 	case MLXCX_OP_DESTROY_EQ:
132 		return ("MLXCX_OP_DESTROY_EQ");
133 	case MLXCX_OP_QUERY_EQ:
134 		return ("MLXCX_OP_QUERY_EQ");
135 	case MLXCX_OP_GEN_EQE:
136 		return ("MLXCX_OP_GEN_EQE");
137 	case MLXCX_OP_CREATE_CQ:
138 		return ("MLXCX_OP_CREATE_CQ");
139 	case MLXCX_OP_DESTROY_CQ:
140 		return ("MLXCX_OP_DESTROY_CQ");
141 	case MLXCX_OP_QUERY_CQ:
142 		return ("MLXCX_OP_QUERY_CQ");
143 	case MLXCX_OP_MODIFY_CQ:
144 		return ("MLXCX_OP_MODIFY_CQ");
145 	case MLXCX_OP_CREATE_QP:
146 		return ("MLXCX_OP_CREATE_QP");
147 	case MLXCX_OP_DESTROY_QP:
148 		return ("MLXCX_OP_DESTROY_QP");
149 	case MLXCX_OP_RST2INIT_QP:
150 		return ("MLXCX_OP_RST2INIT_QP");
151 	case MLXCX_OP_INIT2RTR_QP:
152 		return ("MLXCX_OP_INIT2RTR_QP");
153 	case MLXCX_OP_RTR2RTS_QP:
154 		return ("MLXCX_OP_RTR2RTS_QP");
155 	case MLXCX_OP_RTS2RTS_QP:
156 		return ("MLXCX_OP_RTS2RTS_QP");
157 	case MLXCX_OP_SQERR2RTS_QP:
158 		return ("MLXCX_OP_SQERR2RTS_QP");
159 	case MLXCX_OP__2ERR_QP:
160 		return ("MLXCX_OP__2ERR_QP");
161 	case MLXCX_OP__2RST_QP:
162 		return ("MLXCX_OP__2RST_QP");
163 	case MLXCX_OP_QUERY_QP:
164 		return ("MLXCX_OP_QUERY_QP");
165 	case MLXCX_OP_SQD_RTS_QP:
166 		return ("MLXCX_OP_SQD_RTS_QP");
167 	case MLXCX_OP_INIT2INIT_QP:
168 		return ("MLXCX_OP_INIT2INIT_QP");
169 	case MLXCX_OP_CREATE_PSV:
170 		return ("MLXCX_OP_CREATE_PSV");
171 	case MLXCX_OP_DESTROY_PSV:
172 		return ("MLXCX_OP_DESTROY_PSV");
173 	case MLXCX_OP_CREATE_SRQ:
174 		return ("MLXCX_OP_CREATE_SRQ");
175 	case MLXCX_OP_DESTROY_SRQ:
176 		return ("MLXCX_OP_DESTROY_SRQ");
177 	case MLXCX_OP_QUERY_SRQ:
178 		return ("MLXCX_OP_QUERY_SRQ");
179 	case MLXCX_OP_ARM_RQ:
180 		return ("MLXCX_OP_ARM_RQ");
181 	case MLXCX_OP_CREATE_XRC_SRQ:
182 		return ("MLXCX_OP_CREATE_XRC_SRQ");
183 	case MLXCX_OP_DESTROY_XRC_SRQ:
184 		return ("MLXCX_OP_DESTROY_XRC_SRQ");
185 	case MLXCX_OP_QUERY_XRC_SRQ:
186 		return ("MLXCX_OP_QUERY_XRC_SRQ");
187 	case MLXCX_OP_ARM_XRC_SRQ:
188 		return ("MLXCX_OP_ARM_XRC_SRQ");
189 	case MLXCX_OP_CREATE_DCT:
190 		return ("MLXCX_OP_CREATE_DCT");
191 	case MLXCX_OP_DESTROY_DCT:
192 		return ("MLXCX_OP_DESTROY_DCT");
193 	case MLXCX_OP_DRAIN_DCT:
194 		return ("MLXCX_OP_DRAIN_DCT");
195 	case MLXCX_OP_QUERY_DCT:
196 		return ("MLXCX_OP_QUERY_DCT");
197 	case MLXCX_OP_ARM_DCT_FOR_KEY_VIOLATION:
198 		return ("MLXCX_OP_ARM_DCT_FOR_KEY_VIOLATION");
199 	case MLXCX_OP_CREATE_XRQ:
200 		return ("MLXCX_OP_CREATE_XRQ");
201 	case MLXCX_OP_DESTROY_XRQ:
202 		return ("MLXCX_OP_DESTROY_XRQ");
203 	case MLXCX_OP_QUERY_XRQ:
204 		return ("MLXCX_OP_QUERY_XRQ");
205 	case MLXCX_OP_CREATE_NVMF_BACKEND_CONTROLLER:
206 		return ("MLXCX_OP_CREATE_NVMF_BACKEND_CONTROLLER");
207 	case MLXCX_OP_DESTROY_NVMF_BACKEND_CONTROLLER:
208 		return ("MLXCX_OP_DESTROY_NVMF_BACKEND_CONTROLLER");
209 	case MLXCX_OP_QUERY_NVMF_BACKEND_CONTROLLER:
210 		return ("MLXCX_OP_QUERY_NVMF_BACKEND_CONTROLLER");
211 	case MLXCX_OP_ATTACH_NVMF_NAMESPACE:
212 		return ("MLXCX_OP_ATTACH_NVMF_NAMESPACE");
213 	case MLXCX_OP_DETACH_NVMF_NAMESPACE:
214 		return ("MLXCX_OP_DETACH_NVMF_NAMESPACE");
215 	case MLXCX_OP_QUERY_XRQ_DC_PARAMS_ENTRY:
216 		return ("MLXCX_OP_QUERY_XRQ_DC_PARAMS_ENTRY");
217 	case MLXCX_OP_SET_XRQ_DC_PARAMS_ENTRY:
218 		return ("MLXCX_OP_SET_XRQ_DC_PARAMS_ENTRY");
219 	case MLXCX_OP_QUERY_XRQ_ERROR_PARAMS:
220 		return ("MLXCX_OP_QUERY_XRQ_ERROR_PARAMS");
221 	case MLXCX_OP_QUERY_VPORT_STATE:
222 		return ("MLXCX_OP_QUERY_VPORT_STATE");
223 	case MLXCX_OP_MODIFY_VPORT_STATE:
224 		return ("MLXCX_OP_MODIFY_VPORT_STATE");
225 	case MLXCX_OP_QUERY_ESW_VPORT_CONTEXT:
226 		return ("MLXCX_OP_QUERY_ESW_VPORT_CONTEXT");
227 	case MLXCX_OP_MODIFY_ESW_VPORT_CONTEXT:
228 		return ("MLXCX_OP_MODIFY_ESW_VPORT_CONTEXT");
229 	case MLXCX_OP_QUERY_NIC_VPORT_CONTEXT:
230 		return ("MLXCX_OP_QUERY_NIC_VPORT_CONTEXT");
231 	case MLXCX_OP_MODIFY_NIC_VPORT_CONTEXT:
232 		return ("MLXCX_OP_MODIFY_NIC_VPORT_CONTEXT");
233 	case MLXCX_OP_QUERY_ROCE_ADDRESS:
234 		return ("MLXCX_OP_QUERY_ROCE_ADDRESS");
235 	case MLXCX_OP_SET_ROCE_ADDRESS:
236 		return ("MLXCX_OP_SET_ROCE_ADDRESS");
237 	case MLXCX_OP_QUERY_HCA_VPORT_CONTEXT:
238 		return ("MLXCX_OP_QUERY_HCA_VPORT_CONTEXT");
239 	case MLXCX_OP_MODIFY_HCA_VPORT_CONTEXT:
240 		return ("MLXCX_OP_MODIFY_HCA_VPORT_CONTEXT");
241 	case MLXCX_OP_QUERY_HCA_VPORT_GID:
242 		return ("MLXCX_OP_QUERY_HCA_VPORT_GID");
243 	case MLXCX_OP_QUERY_HCA_VPORT_PKEY:
244 		return ("MLXCX_OP_QUERY_HCA_VPORT_PKEY");
245 	case MLXCX_OP_QUERY_VPORT_COUNTER:
246 		return ("MLXCX_OP_QUERY_VPORT_COUNTER");
247 	case MLXCX_OP_ALLOC_Q_COUNTER:
248 		return ("MLXCX_OP_ALLOC_Q_COUNTER");
249 	case MLXCX_OP_DEALLOC_Q_COUNTER:
250 		return ("MLXCX_OP_DEALLOC_Q_COUNTER");
251 	case MLXCX_OP_QUERY_Q_COUNTER:
252 		return ("MLXCX_OP_QUERY_Q_COUNTER");
253 	case MLXCX_OP_SET_PP_RATE_LIMIT:
254 		return ("MLXCX_OP_SET_PP_RATE_LIMIT");
255 	case MLXCX_OP_QUERY_PP_RATE_LIMIT:
256 		return ("MLXCX_OP_QUERY_PP_RATE_LIMIT");
257 	case MLXCX_OP_ALLOC_PD:
258 		return ("MLXCX_OP_ALLOC_PD");
259 	case MLXCX_OP_DEALLOC_PD:
260 		return ("MLXCX_OP_DEALLOC_PD");
261 	case MLXCX_OP_ALLOC_UAR:
262 		return ("MLXCX_OP_ALLOC_UAR");
263 	case MLXCX_OP_DEALLOC_UAR:
264 		return ("MLXCX_OP_DEALLOC_UAR");
265 	case MLXCX_OP_CONFIG_INT_MODERATION:
266 		return ("MLXCX_OP_CONFIG_INT_MODERATION");
267 	case MLXCX_OP_ACCESS_REG:
268 		return ("MLXCX_OP_ACCESS_REG");
269 	case MLXCX_OP_ATTACH_TO_MCG:
270 		return ("MLXCX_OP_ATTACH_TO_MCG");
271 	case MLXCX_OP_DETACH_FROM_MCG:
272 		return ("MLXCX_OP_DETACH_FROM_MCG");
273 	case MLXCX_OP_MAD_IFC:
274 		return ("MLXCX_OP_MAD_IFC");
275 	case MLXCX_OP_QUERY_MAD_DEMUX:
276 		return ("MLXCX_OP_QUERY_MAD_DEMUX");
277 	case MLXCX_OP_SET_MAD_DEMUX:
278 		return ("MLXCX_OP_SET_MAD_DEMUX");
279 	case MLXCX_OP_NOP:
280 		return ("MLXCX_OP_NOP");
281 	case MLXCX_OP_ALLOC_XRCD:
282 		return ("MLXCX_OP_ALLOC_XRCD");
283 	case MLXCX_OP_DEALLOC_XRCD:
284 		return ("MLXCX_OP_DEALLOC_XRCD");
285 	case MLXCX_OP_ALLOC_TRANSPORT_DOMAIN:
286 		return ("MLXCX_OP_ALLOC_TRANSPORT_DOMAIN");
287 	case MLXCX_OP_DEALLOC_TRANSPORT_DOMAIN:
288 		return ("MLXCX_OP_DEALLOC_TRANSPORT_DOMAIN");
289 	case MLXCX_OP_QUERY_CONG_STATUS:
290 		return ("MLXCX_OP_QUERY_CONG_STATUS");
291 	case MLXCX_OP_MODIFY_CONG_STATUS:
292 		return ("MLXCX_OP_MODIFY_CONG_STATUS");
293 	case MLXCX_OP_QUERY_CONG_PARAMS:
294 		return ("MLXCX_OP_QUERY_CONG_PARAMS");
295 	case MLXCX_OP_MODIFY_CONG_PARAMS:
296 		return ("MLXCX_OP_MODIFY_CONG_PARAMS");
297 	case MLXCX_OP_QUERY_CONG_STATISTICS:
298 		return ("MLXCX_OP_QUERY_CONG_STATISTICS");
299 	case MLXCX_OP_ADD_VXLAN_UDP_DPORT:
300 		return ("MLXCX_OP_ADD_VXLAN_UDP_DPORT");
301 	case MLXCX_OP_DELETE_VXLAN_UDP_DPORT:
302 		return ("MLXCX_OP_DELETE_VXLAN_UDP_DPORT");
303 	case MLXCX_OP_SET_L2_TABLE_ENTRY:
304 		return ("MLXCX_OP_SET_L2_TABLE_ENTRY");
305 	case MLXCX_OP_QUERY_L2_TABLE_ENTRY:
306 		return ("MLXCX_OP_QUERY_L2_TABLE_ENTRY");
307 	case MLXCX_OP_DELETE_L2_TABLE_ENTRY:
308 		return ("MLXCX_OP_DELETE_L2_TABLE_ENTRY");
309 	case MLXCX_OP_SET_WOL_ROL:
310 		return ("MLXCX_OP_SET_WOL_ROL");
311 	case MLXCX_OP_QUERY_WOL_ROL:
312 		return ("MLXCX_OP_QUERY_WOL_ROL");
313 	case MLXCX_OP_CREATE_TIR:
314 		return ("MLXCX_OP_CREATE_TIR");
315 	case MLXCX_OP_MODIFY_TIR:
316 		return ("MLXCX_OP_MODIFY_TIR");
317 	case MLXCX_OP_DESTROY_TIR:
318 		return ("MLXCX_OP_DESTROY_TIR");
319 	case MLXCX_OP_QUERY_TIR:
320 		return ("MLXCX_OP_QUERY_TIR");
321 	case MLXCX_OP_CREATE_SQ:
322 		return ("MLXCX_OP_CREATE_SQ");
323 	case MLXCX_OP_MODIFY_SQ:
324 		return ("MLXCX_OP_MODIFY_SQ");
325 	case MLXCX_OP_DESTROY_SQ:
326 		return ("MLXCX_OP_DESTROY_SQ");
327 	case MLXCX_OP_QUERY_SQ:
328 		return ("MLXCX_OP_QUERY_SQ");
329 	case MLXCX_OP_CREATE_RQ:
330 		return ("MLXCX_OP_CREATE_RQ");
331 	case MLXCX_OP_MODIFY_RQ:
332 		return ("MLXCX_OP_MODIFY_RQ");
333 	case MLXCX_OP_DESTROY_RQ:
334 		return ("MLXCX_OP_DESTROY_RQ");
335 	case MLXCX_OP_QUERY_RQ:
336 		return ("MLXCX_OP_QUERY_RQ");
337 	case MLXCX_OP_CREATE_RMP:
338 		return ("MLXCX_OP_CREATE_RMP");
339 	case MLXCX_OP_MODIFY_RMP:
340 		return ("MLXCX_OP_MODIFY_RMP");
341 	case MLXCX_OP_DESTROY_RMP:
342 		return ("MLXCX_OP_DESTROY_RMP");
343 	case MLXCX_OP_QUERY_RMP:
344 		return ("MLXCX_OP_QUERY_RMP");
345 	case MLXCX_OP_CREATE_TIS:
346 		return ("MLXCX_OP_CREATE_TIS");
347 	case MLXCX_OP_MODIFY_TIS:
348 		return ("MLXCX_OP_MODIFY_TIS");
349 	case MLXCX_OP_DESTROY_TIS:
350 		return ("MLXCX_OP_DESTROY_TIS");
351 	case MLXCX_OP_QUERY_TIS:
352 		return ("MLXCX_OP_QUERY_TIS");
353 	case MLXCX_OP_CREATE_RQT:
354 		return ("MLXCX_OP_CREATE_RQT");
355 	case MLXCX_OP_MODIFY_RQT:
356 		return ("MLXCX_OP_MODIFY_RQT");
357 	case MLXCX_OP_DESTROY_RQT:
358 		return ("MLXCX_OP_DESTROY_RQT");
359 	case MLXCX_OP_QUERY_RQT:
360 		return ("MLXCX_OP_QUERY_RQT");
361 	case MLXCX_OP_SET_FLOW_TABLE_ROOT:
362 		return ("MLXCX_OP_SET_FLOW_TABLE_ROOT");
363 	case MLXCX_OP_CREATE_FLOW_TABLE:
364 		return ("MLXCX_OP_CREATE_FLOW_TABLE");
365 	case MLXCX_OP_DESTROY_FLOW_TABLE:
366 		return ("MLXCX_OP_DESTROY_FLOW_TABLE");
367 	case MLXCX_OP_QUERY_FLOW_TABLE:
368 		return ("MLXCX_OP_QUERY_FLOW_TABLE");
369 	case MLXCX_OP_CREATE_FLOW_GROUP:
370 		return ("MLXCX_OP_CREATE_FLOW_GROUP");
371 	case MLXCX_OP_DESTROY_FLOW_GROUP:
372 		return ("MLXCX_OP_DESTROY_FLOW_GROUP");
373 	case MLXCX_OP_QUERY_FLOW_GROUP:
374 		return ("MLXCX_OP_QUERY_FLOW_GROUP");
375 	case MLXCX_OP_SET_FLOW_TABLE_ENTRY:
376 		return ("MLXCX_OP_SET_FLOW_TABLE_ENTRY");
377 	case MLXCX_OP_QUERY_FLOW_TABLE_ENTRY:
378 		return ("MLXCX_OP_QUERY_FLOW_TABLE_ENTRY");
379 	case MLXCX_OP_DELETE_FLOW_TABLE_ENTRY:
380 		return ("MLXCX_OP_DELETE_FLOW_TABLE_ENTRY");
381 	case MLXCX_OP_ALLOC_FLOW_COUNTER:
382 		return ("MLXCX_OP_ALLOC_FLOW_COUNTER");
383 	case MLXCX_OP_DEALLOC_FLOW_COUNTER:
384 		return ("MLXCX_OP_DEALLOC_FLOW_COUNTER");
385 	case MLXCX_OP_QUERY_FLOW_COUNTER:
386 		return ("MLXCX_OP_QUERY_FLOW_COUNTER");
387 	case MLXCX_OP_MODIFY_FLOW_TABLE:
388 		return ("MLXCX_OP_MODIFY_FLOW_TABLE");
389 	case MLXCX_OP_ALLOC_ENCAP_HEADER:
390 		return ("MLXCX_OP_ALLOC_ENCAP_HEADER");
391 	case MLXCX_OP_DEALLOC_ENCAP_HEADER:
392 		return ("MLXCX_OP_DEALLOC_ENCAP_HEADER");
393 	case MLXCX_OP_QUERY_ENCAP_HEADER:
394 		return ("MLXCX_OP_QUERY_ENCAP_HEADER");
395 	default:
396 		return ("Unknown Opcode");
397 	}
398 }
399 
400 const char *
401 mlxcx_port_status_string(mlxcx_port_status_t st)
402 {
403 	switch (st) {
404 	case MLXCX_PORT_STATUS_UP:
405 		return ("UP");
406 	case MLXCX_PORT_STATUS_DOWN:
407 		return ("DOWN");
408 	case MLXCX_PORT_STATUS_UP_ONCE:
409 		return ("UP_ONCE");
410 	case MLXCX_PORT_STATUS_DISABLED:
411 		return ("DISABLED");
412 	default:
413 		return ("UNKNOWN");
414 	}
415 }
416 
417 void
418 mlxcx_eth_proto_to_string(mlxcx_eth_proto_t p, char *buf, size_t size)
419 {
420 	if (p & MLXCX_PROTO_SGMII)
421 		(void) strlcat(buf, "SGMII|", size);
422 	if (p & MLXCX_PROTO_1000BASE_KX)
423 		(void) strlcat(buf, "1000BASE_KX|", size);
424 	if (p & MLXCX_PROTO_10GBASE_CX4)
425 		(void) strlcat(buf, "10GBASE_CX4|", size);
426 	if (p & MLXCX_PROTO_10GBASE_KX4)
427 		(void) strlcat(buf, "10GBASE_KX4|", size);
428 	if (p & MLXCX_PROTO_10GBASE_KR)
429 		(void) strlcat(buf, "10GBASE_KR|", size);
430 	if (p & MLXCX_PROTO_40GBASE_CR4)
431 		(void) strlcat(buf, "40GBASE_CR4|", size);
432 	if (p & MLXCX_PROTO_40GBASE_KR4)
433 		(void) strlcat(buf, "40GBASE_KR4|", size);
434 	if (p & MLXCX_PROTO_SGMII_100BASE)
435 		(void) strlcat(buf, "SGMII_100BASE|", size);
436 	if (p & MLXCX_PROTO_10GBASE_CR)
437 		(void) strlcat(buf, "10GBASE_CR|", size);
438 	if (p & MLXCX_PROTO_10GBASE_SR)
439 		(void) strlcat(buf, "10GBASE_SR|", size);
440 	if (p & MLXCX_PROTO_10GBASE_ER_LR)
441 		(void) strlcat(buf, "10GBASE_ER_LR|", size);
442 	if (p & MLXCX_PROTO_40GBASE_SR4)
443 		(void) strlcat(buf, "40GBASE_SR4|", size);
444 	if (p & MLXCX_PROTO_40GBASE_LR4_ER4)
445 		(void) strlcat(buf, "40GBASE_LR4_ER4|", size);
446 	if (p & MLXCX_PROTO_50GBASE_SR2)
447 		(void) strlcat(buf, "50GBASE_SR2|", size);
448 	if (p & MLXCX_PROTO_100GBASE_CR4)
449 		(void) strlcat(buf, "100GBASE_CR4|", size);
450 	if (p & MLXCX_PROTO_100GBASE_SR4)
451 		(void) strlcat(buf, "100GBASE_SR4|", size);
452 	if (p & MLXCX_PROTO_100GBASE_KR4)
453 		(void) strlcat(buf, "100GBASE_KR4|", size);
454 	if (p & MLXCX_PROTO_25GBASE_CR)
455 		(void) strlcat(buf, "25GBASE_CR|", size);
456 	if (p & MLXCX_PROTO_25GBASE_KR)
457 		(void) strlcat(buf, "25GBASE_KR|", size);
458 	if (p & MLXCX_PROTO_25GBASE_SR)
459 		(void) strlcat(buf, "25GBASE_SR|", size);
460 	if (p & MLXCX_PROTO_50GBASE_CR2)
461 		(void) strlcat(buf, "50GBASE_CR2|", size);
462 	/* Chop off the trailing '|' */
463 	if (strlen(buf) > 0)
464 		buf[strlen(buf) - 1] = '\0';
465 }
466 
467 void
468 mlxcx_cmd_queue_fini(mlxcx_t *mlxp)
469 {
470 	mlxcx_cmd_queue_t *cmd = &mlxp->mlx_cmd;
471 
472 	mutex_enter(&cmd->mcmd_lock);
473 	VERIFY3S(cmd->mcmd_status, ==, MLXCX_CMD_QUEUE_S_IDLE);
474 	mutex_exit(&cmd->mcmd_lock);
475 
476 	if (cmd->mcmd_tokens != NULL) {
477 		id_space_destroy(cmd->mcmd_tokens);
478 		cmd->mcmd_tokens = NULL;
479 	}
480 
481 	if (cmd->mcmd_taskq != NULL) {
482 		ddi_taskq_destroy(cmd->mcmd_taskq);
483 		cmd->mcmd_taskq = NULL;
484 	}
485 
486 	cv_destroy(&cmd->mcmd_cv);
487 	mutex_destroy(&cmd->mcmd_lock);
488 
489 	cmd->mcmd_ent = NULL;
490 	mlxcx_dma_free(&cmd->mcmd_dma);
491 }
492 
493 boolean_t
494 mlxcx_cmd_queue_init(mlxcx_t *mlxp)
495 {
496 	uint32_t tmp, cmd_low, cmd_high, i;
497 	mlxcx_cmd_queue_t *cmd = &mlxp->mlx_cmd;
498 	char buf[64];
499 	const ddi_dma_cookie_t *ck;
500 
501 	ddi_device_acc_attr_t acc;
502 	ddi_dma_attr_t attr;
503 
504 	tmp = mlxcx_get32(mlxp, MLXCX_ISS_FIRMWARE);
505 	mlxp->mlx_fw_maj = MLXCX_ISS_FW_MAJOR(tmp);
506 	mlxp->mlx_fw_min = MLXCX_ISS_FW_MINOR(tmp);
507 
508 	tmp = mlxcx_get32(mlxp, MLXCX_ISS_FW_CMD);
509 	mlxp->mlx_fw_rev = MLXCX_ISS_FW_REV(tmp);
510 	mlxp->mlx_cmd_rev = MLXCX_ISS_CMD_REV(tmp);
511 
512 	if (mlxp->mlx_cmd_rev != MLXCX_CMD_REVISION) {
513 		mlxcx_warn(mlxp, "found unsupported command revision: %u, "
514 		    "expected %u", mlxp->mlx_cmd_rev, MLXCX_CMD_REVISION);
515 		return (B_FALSE);
516 	}
517 
518 	cmd_low = mlxcx_get32(mlxp, MLXCX_ISS_CMD_LOW);
519 	cmd->mcmd_size_l2 = MLXCX_ISS_CMDQ_SIZE(cmd_low);
520 	cmd->mcmd_stride_l2 = MLXCX_ISS_CMDQ_STRIDE(cmd_low);
521 
522 	mutex_init(&cmd->mcmd_lock, NULL, MUTEX_DRIVER, NULL);
523 	cv_init(&cmd->mcmd_cv, NULL, CV_DRIVER, NULL);
524 	cmd->mcmd_status = MLXCX_CMD_QUEUE_S_IDLE;
525 
526 	(void) snprintf(buf, sizeof (buf), "mlxcx_tokens_%d", mlxp->mlx_inst);
527 	if ((cmd->mcmd_tokens = id_space_create(buf, 1, UINT8_MAX)) == NULL) {
528 		mlxcx_warn(mlxp, "failed to allocate token id space");
529 		mlxcx_cmd_queue_fini(mlxp);
530 		return (B_FALSE);
531 	}
532 
533 	(void) snprintf(buf, sizeof (buf), "mlxcx_cmdq_%d", mlxp->mlx_inst);
534 	if ((cmd->mcmd_taskq = ddi_taskq_create(mlxp->mlx_dip, buf, 1,
535 	    TASKQ_DEFAULTPRI, 0)) == NULL) {
536 		mlxcx_warn(mlxp, "failed to create command queue task queue");
537 		mlxcx_cmd_queue_fini(mlxp);
538 		return (B_FALSE);
539 	}
540 
541 	mlxcx_dma_acc_attr(mlxp, &acc);
542 	mlxcx_dma_page_attr(mlxp, &attr);
543 
544 	if (!mlxcx_dma_alloc(mlxp, &cmd->mcmd_dma, &attr, &acc, B_TRUE,
545 	    MLXCX_CMD_DMA_PAGE_SIZE, B_TRUE)) {
546 		mlxcx_warn(mlxp, "failed to allocate command dma buffer");
547 		mlxcx_cmd_queue_fini(mlxp);
548 		return (B_FALSE);
549 	}
550 
551 	ck = mlxcx_dma_cookie_one(&cmd->mcmd_dma);
552 	cmd_high = (uint32_t)(ck->dmac_laddress >> 32);
553 	cmd_low = (uint32_t)(ck->dmac_laddress & UINT32_MAX);
554 
555 	mlxcx_put32(mlxp, MLXCX_ISS_CMD_HIGH, cmd_high);
556 	mlxcx_put32(mlxp, MLXCX_ISS_CMD_LOW, cmd_low);
557 
558 	/*
559 	 * Before this is ready, the initializing bit must become zero.
560 	 */
561 	for (i = 0; i < mlxcx_cmd_init_trys; i++) {
562 		uint32_t init = mlxcx_get32(mlxp, MLXCX_ISS_INIT);
563 
564 		if (MLXCX_ISS_INITIALIZING(init) == 0)
565 			break;
566 		delay(drv_usectohz(mlxcx_cmd_init_delay));
567 	}
568 	if (i == mlxcx_cmd_init_trys) {
569 		mlxcx_warn(mlxp, "timed out initializing command queue");
570 		mlxcx_cmd_queue_fini(mlxp);
571 		return (B_FALSE);
572 	}
573 
574 	cmd->mcmd_ent = (void *)cmd->mcmd_dma.mxdb_va;
575 
576 	return (B_TRUE);
577 }
578 
579 static void
580 mlxcx_cmd_in_header_init(mlxcx_cmd_t *cmd, mlxcx_cmd_in_t *in,
581     mlxcx_cmd_op_t op, uint16_t mod)
582 {
583 	ASSERT3U(op, <=, UINT16_MAX);
584 	in->mci_opcode = to_be16(op);
585 	in->mci_op_mod = to_be16(mod);
586 	cmd->mlcmd_op = op;
587 }
588 
589 static boolean_t
590 mlxcx_cmd_mbox_alloc(mlxcx_t *mlxp, list_t *listp, uint8_t nblocks)
591 {
592 	uint8_t i;
593 	ddi_device_acc_attr_t acc;
594 	ddi_dma_attr_t attr;
595 
596 	mlxcx_dma_acc_attr(mlxp, &acc);
597 	mlxcx_dma_page_attr(mlxp, &attr);
598 
599 	for (i = 0; i < nblocks; i++) {
600 		mlxcx_cmd_mbox_t *mbox;
601 
602 		mbox = kmem_zalloc(sizeof (*mbox), KM_SLEEP);
603 		if (!mlxcx_dma_alloc(mlxp, &mbox->mlbox_dma, &attr, &acc,
604 		    B_TRUE, sizeof (mlxcx_cmd_mailbox_t), B_TRUE)) {
605 			mlxcx_warn(mlxp, "failed to allocate mailbox dma "
606 			    "buffer");
607 			kmem_free(mbox, sizeof (*mbox));
608 			/*
609 			 * mlxcx_cmd_fini will clean up any mboxes that we
610 			 * already placed onto listp.
611 			 */
612 			return (B_FALSE);
613 		}
614 		mbox->mlbox_data = (void *)mbox->mlbox_dma.mxdb_va;
615 		list_insert_tail(listp, mbox);
616 	}
617 
618 	return (B_TRUE);
619 }
620 
621 static void
622 mlxcx_cmd_mbox_free(mlxcx_cmd_mbox_t *mbox)
623 {
624 	mlxcx_dma_free(&mbox->mlbox_dma);
625 	kmem_free(mbox, sizeof (mlxcx_cmd_mbox_t));
626 }
627 
628 static void
629 mlxcx_cmd_fini(mlxcx_t *mlxp, mlxcx_cmd_t *cmd)
630 {
631 	mlxcx_cmd_mbox_t *mbox;
632 
633 	while ((mbox = list_remove_head(&cmd->mlcmd_mbox_out)) != NULL) {
634 		mlxcx_cmd_mbox_free(mbox);
635 	}
636 	list_destroy(&cmd->mlcmd_mbox_out);
637 	while ((mbox = list_remove_head(&cmd->mlcmd_mbox_in)) != NULL) {
638 		mlxcx_cmd_mbox_free(mbox);
639 	}
640 	list_destroy(&cmd->mlcmd_mbox_in);
641 	id_free(mlxp->mlx_cmd.mcmd_tokens, cmd->mlcmd_token);
642 	cv_destroy(&cmd->mlcmd_cv);
643 	mutex_destroy(&cmd->mlcmd_lock);
644 }
645 
646 static void
647 mlxcx_cmd_init(mlxcx_t *mlxp, mlxcx_cmd_t *cmd)
648 {
649 	bzero(cmd, sizeof (*cmd));
650 	mutex_init(&cmd->mlcmd_lock, NULL, MUTEX_DRIVER, NULL);
651 	cv_init(&cmd->mlcmd_cv, NULL, CV_DRIVER, NULL);
652 	cmd->mlcmd_token = id_alloc(mlxp->mlx_cmd.mcmd_tokens);
653 	list_create(&cmd->mlcmd_mbox_in, sizeof (mlxcx_cmd_mbox_t),
654 	    offsetof(mlxcx_cmd_mbox_t, mlbox_node));
655 	list_create(&cmd->mlcmd_mbox_out, sizeof (mlxcx_cmd_mbox_t),
656 	    offsetof(mlxcx_cmd_mbox_t, mlbox_node));
657 }
658 
659 static void
660 mlxcx_cmd_prep_input(mlxcx_cmd_ent_t *ent, mlxcx_cmd_t *cmd)
661 {
662 	uint32_t rem = cmd->mlcmd_inlen;
663 	uint8_t i;
664 	const void *in = cmd->mlcmd_in;
665 	uint32_t copy;
666 	mlxcx_cmd_mbox_t *mbox;
667 	const ddi_dma_cookie_t *ck;
668 
669 	copy = MIN(MLXCX_CMD_INLINE_INPUT_LEN, rem);
670 	bcopy(in, ent->mce_input, copy);
671 
672 	rem -= copy;
673 	in += copy;
674 
675 	if (rem == 0) {
676 		ent->mce_in_mbox = to_be64(0);
677 		VERIFY3U(cmd->mlcmd_nboxes_in, ==, 0);
678 		return;
679 	}
680 
681 	mbox = list_head(&cmd->mlcmd_mbox_in);
682 	ck = mlxcx_dma_cookie_one(&mbox->mlbox_dma);
683 	ent->mce_in_mbox = to_be64(ck->dmac_laddress);
684 	for (i = 0; mbox != NULL;
685 	    mbox = list_next(&cmd->mlcmd_mbox_in, mbox), i++) {
686 		mlxcx_cmd_mbox_t *next;
687 		mlxcx_cmd_mailbox_t *mp = mbox->mlbox_data;
688 
689 		copy = MIN(MLXCX_CMD_MAILBOX_LEN, rem);
690 		bcopy(in, mp->mlxb_data, copy);
691 		rem -= copy;
692 		in += copy;
693 
694 		mp->mlxb_token = cmd->mlcmd_token;
695 		mp->mlxb_blockno = to_be32(i);
696 
697 		next = list_next(&cmd->mlcmd_mbox_in, mbox);
698 		if (next == NULL) {
699 			mp->mlxb_nextp = to_be64(0);
700 		} else {
701 			ck = mlxcx_dma_cookie_one(&next->mlbox_dma);
702 			mp->mlxb_nextp = to_be64(ck->dmac_laddress);
703 		}
704 		MLXCX_DMA_SYNC(mbox->mlbox_dma, DDI_DMA_SYNC_FORDEV);
705 	}
706 	VERIFY3U(i, ==, cmd->mlcmd_nboxes_in);
707 	VERIFY0(rem);
708 }
709 
710 static void
711 mlxcx_cmd_prep_output(mlxcx_cmd_ent_t *ent, mlxcx_cmd_t *cmd)
712 {
713 	uint8_t i;
714 	mlxcx_cmd_mbox_t *mbox;
715 	const ddi_dma_cookie_t *ck;
716 
717 	if (cmd->mlcmd_nboxes_out == 0) {
718 		ent->mce_out_mbox = to_be64(0);
719 		return;
720 	}
721 
722 	mbox = list_head(&cmd->mlcmd_mbox_out);
723 	ck = mlxcx_dma_cookie_one(&mbox->mlbox_dma);
724 	ent->mce_out_mbox = to_be64(ck->dmac_laddress);
725 	for (i = 0, mbox = list_head(&cmd->mlcmd_mbox_out); mbox != NULL;
726 	    mbox = list_next(&cmd->mlcmd_mbox_out, mbox), i++) {
727 		mlxcx_cmd_mbox_t *next;
728 		mlxcx_cmd_mailbox_t *mp = mbox->mlbox_data;
729 
730 		mp->mlxb_token = cmd->mlcmd_token;
731 		mp->mlxb_blockno = to_be32(i);
732 
733 		next = list_next(&cmd->mlcmd_mbox_out, mbox);
734 		if (next == NULL) {
735 			mp->mlxb_nextp = to_be64(0);
736 		} else {
737 			ck = mlxcx_dma_cookie_one(&next->mlbox_dma);
738 			mp->mlxb_nextp = to_be64(ck->dmac_laddress);
739 		}
740 		MLXCX_DMA_SYNC(mbox->mlbox_dma, DDI_DMA_SYNC_FORDEV);
741 	}
742 	VERIFY3U(i, ==, cmd->mlcmd_nboxes_out);
743 }
744 
745 static void
746 mlxcx_cmd_copy_output(mlxcx_cmd_ent_t *ent, mlxcx_cmd_t *cmd)
747 {
748 	void *out = cmd->mlcmd_out;
749 	uint32_t rem = cmd->mlcmd_outlen;
750 	uint32_t copy;
751 	mlxcx_cmd_mbox_t *mbox;
752 
753 	copy = MIN(rem, MLXCX_CMD_INLINE_OUTPUT_LEN);
754 	bcopy(ent->mce_output, out, copy);
755 	out += copy;
756 	rem -= copy;
757 
758 	if (rem == 0) {
759 		VERIFY0(cmd->mlcmd_nboxes_out);
760 		return;
761 	}
762 
763 	for (mbox = list_head(&cmd->mlcmd_mbox_out); mbox != NULL;
764 	    mbox = list_next(&cmd->mlcmd_mbox_out, mbox)) {
765 		MLXCX_DMA_SYNC(mbox->mlbox_dma, DDI_DMA_SYNC_FORKERNEL);
766 		copy = MIN(MLXCX_CMD_MAILBOX_LEN, rem);
767 		bcopy(mbox->mlbox_data->mlxb_data, out, copy);
768 		out += copy;
769 		rem -= copy;
770 	}
771 	VERIFY0(rem);
772 }
773 
774 static void
775 mlxcx_cmd_taskq(void *arg)
776 {
777 	mlxcx_cmd_t *cmd = arg;
778 	mlxcx_t *mlxp = cmd->mlcmd_mlxp;
779 	mlxcx_cmd_queue_t *cmdq = &mlxp->mlx_cmd;
780 	mlxcx_cmd_ent_t *ent;
781 	uint_t poll;
782 
783 	ASSERT3S(cmd->mlcmd_op, !=, 0);
784 
785 	mutex_enter(&cmdq->mcmd_lock);
786 	while (cmdq->mcmd_status == MLXCX_CMD_QUEUE_S_BUSY) {
787 		cv_wait(&cmdq->mcmd_cv, &cmdq->mcmd_lock);
788 	}
789 
790 	if (cmdq->mcmd_status != MLXCX_CMD_QUEUE_S_IDLE) {
791 		mutex_exit(&cmdq->mcmd_lock);
792 
793 		mutex_enter(&cmd->mlcmd_lock);
794 		cmd->mlcmd_state = MLXCX_CMD_S_ERROR;
795 		cv_broadcast(&cmd->mlcmd_cv);
796 		mutex_exit(&cmd->mlcmd_lock);
797 		return;
798 	}
799 
800 	cmdq->mcmd_status = MLXCX_CMD_QUEUE_S_BUSY;
801 	ent = cmdq->mcmd_ent;
802 	mutex_exit(&cmdq->mcmd_lock);
803 
804 	/*
805 	 * Command queue is currently ours as we set busy.
806 	 */
807 	bzero(ent, sizeof (*ent));
808 	ent->mce_type = MLXCX_CMD_TRANSPORT_PCI;
809 	ent->mce_in_length = to_be32(cmd->mlcmd_inlen);
810 	ent->mce_out_length = to_be32(cmd->mlcmd_outlen);
811 	ent->mce_token = cmd->mlcmd_token;
812 	ent->mce_sig = 0;
813 	ent->mce_status = MLXCX_CMD_HW_OWNED;
814 	mlxcx_cmd_prep_input(ent, cmd);
815 	mlxcx_cmd_prep_output(ent, cmd);
816 	MLXCX_DMA_SYNC(cmdq->mcmd_dma, DDI_DMA_SYNC_FORDEV);
817 
818 	/* This assumes we only ever use the first command */
819 	mlxcx_put32(mlxp, MLXCX_ISS_CMD_DOORBELL, 1);
820 
821 	for (poll = 0; poll < mlxcx_cmd_tries; poll++) {
822 		delay(drv_usectohz(mlxcx_cmd_delay));
823 		MLXCX_DMA_SYNC(cmdq->mcmd_dma, DDI_DMA_SYNC_FORKERNEL);
824 		if ((ent->mce_status & MLXCX_CMD_HW_OWNED) == 0)
825 			break;
826 	}
827 
828 	/*
829 	 * Command is done (or timed out). Save relevant data. Once we broadcast
830 	 * on the CV and drop the lock, we must not touch the cmd again.
831 	 */
832 	mutex_enter(&cmd->mlcmd_lock);
833 
834 	if (poll == mlxcx_cmd_tries) {
835 		cmd->mlcmd_status = MLXCX_CMD_R_TIMEOUT;
836 		cmd->mlcmd_state = MLXCX_CMD_S_ERROR;
837 		mlxcx_fm_ereport(mlxp, DDI_FM_DEVICE_NO_RESPONSE);
838 	} else {
839 		cmd->mlcmd_status = MLXCX_CMD_STATUS(ent->mce_status);
840 		cmd->mlcmd_state = MLXCX_CMD_S_DONE;
841 		if (cmd->mlcmd_status == 0) {
842 			mlxcx_cmd_copy_output(ent, cmd);
843 		}
844 	}
845 	cv_broadcast(&cmd->mlcmd_cv);
846 	mutex_exit(&cmd->mlcmd_lock);
847 
848 	mutex_enter(&cmdq->mcmd_lock);
849 	cmdq->mcmd_status = MLXCX_CMD_QUEUE_S_IDLE;
850 	cv_broadcast(&cmdq->mcmd_cv);
851 	mutex_exit(&cmdq->mcmd_lock);
852 }
853 
854 static boolean_t
855 mlxcx_cmd_send(mlxcx_t *mlxp, mlxcx_cmd_t *cmd, const void *in, uint32_t inlen,
856     void *out, uint32_t outlen)
857 {
858 	if (inlen > MLXCX_CMD_INLINE_INPUT_LEN) {
859 		uint32_t need = inlen - MLXCX_CMD_INLINE_INPUT_LEN;
860 		uint8_t nblocks;
861 
862 		if (need / MLXCX_CMD_MAILBOX_LEN + 1 > UINT8_MAX) {
863 			mlxcx_warn(mlxp, "requested too many input blocks for "
864 			    "%u byte input len", inlen);
865 			return (B_FALSE);
866 		}
867 
868 		nblocks = need / MLXCX_CMD_MAILBOX_LEN + 1;
869 		if (!mlxcx_cmd_mbox_alloc(mlxp, &cmd->mlcmd_mbox_in, nblocks)) {
870 			mlxcx_warn(mlxp, "failed to allocate %u blocks of "
871 			    "input mailbox", nblocks);
872 			return (B_FALSE);
873 		}
874 		cmd->mlcmd_nboxes_in = nblocks;
875 	}
876 
877 	if (outlen > MLXCX_CMD_INLINE_OUTPUT_LEN) {
878 		uint32_t need = outlen - MLXCX_CMD_INLINE_OUTPUT_LEN;
879 		uint8_t nblocks;
880 
881 		if (need / MLXCX_CMD_MAILBOX_LEN + 1 > UINT8_MAX) {
882 			mlxcx_warn(mlxp, "requested too many output blocks for "
883 			    "%u byte output len", outlen);
884 			return (B_FALSE);
885 		}
886 
887 		nblocks = need / MLXCX_CMD_MAILBOX_LEN + 1;
888 		if (!mlxcx_cmd_mbox_alloc(mlxp, &cmd->mlcmd_mbox_out,
889 		    nblocks)) {
890 			mlxcx_warn(mlxp, "failed to allocate %u blocks of "
891 			    "output mailbox", nblocks);
892 			return (B_FALSE);
893 		}
894 		cmd->mlcmd_nboxes_out = nblocks;
895 	}
896 
897 	cmd->mlcmd_in = in;
898 	cmd->mlcmd_inlen = inlen;
899 	cmd->mlcmd_out = out;
900 	cmd->mlcmd_outlen = outlen;
901 	cmd->mlcmd_mlxp = mlxp;
902 
903 	/*
904 	 * Now that all allocations have been done, all that remains is for us
905 	 * to dispatch the request to process this to the taskq for it to be
906 	 * processed.
907 	 */
908 	if (ddi_taskq_dispatch(mlxp->mlx_cmd.mcmd_taskq, mlxcx_cmd_taskq, cmd,
909 	    DDI_SLEEP) != DDI_SUCCESS) {
910 		mlxcx_warn(mlxp, "failed to submit command to taskq");
911 		return (B_FALSE);
912 	}
913 
914 	return (B_TRUE);
915 }
916 
917 static void
918 mlxcx_cmd_wait(mlxcx_cmd_t *cmd)
919 {
920 	mutex_enter(&cmd->mlcmd_lock);
921 	while (cmd->mlcmd_state == 0) {
922 		cv_wait(&cmd->mlcmd_cv, &cmd->mlcmd_lock);
923 	}
924 	mutex_exit(&cmd->mlcmd_lock);
925 }
926 
927 static boolean_t
928 mlxcx_cmd_evaluate(mlxcx_t *mlxp, mlxcx_cmd_t *cmd)
929 {
930 	mlxcx_cmd_out_t *out;
931 
932 	if ((cmd->mlcmd_state & MLXCX_CMD_S_ERROR) != 0) {
933 		mlxcx_warn(mlxp, "command %s (0x%x) failed due to an internal "
934 		    "driver error",
935 		    mlxcx_cmd_opcode_string(cmd->mlcmd_op),
936 		    cmd->mlcmd_op);
937 		return (B_FALSE);
938 	}
939 
940 	if (cmd->mlcmd_status != 0) {
941 		mlxcx_warn(mlxp, "command %s (0x%x) failed with command queue "
942 		    "error 0x%x",
943 		    mlxcx_cmd_opcode_string(cmd->mlcmd_op),
944 		    cmd->mlcmd_op, cmd->mlcmd_status);
945 		return (B_FALSE);
946 	}
947 
948 	out = cmd->mlcmd_out;
949 	if (out->mco_status != MLXCX_CMD_R_OK) {
950 		mlxcx_warn(mlxp, "command %s 0x%x failed with status code %s "
951 		    "(0x%x)", mlxcx_cmd_opcode_string(cmd->mlcmd_op),
952 		    cmd->mlcmd_op, mlxcx_cmd_response_string(out->mco_status),
953 		    out->mco_status);
954 		return (B_FALSE);
955 	}
956 
957 	return (B_TRUE);
958 }
959 
960 boolean_t
961 mlxcx_cmd_disable_hca(mlxcx_t *mlxp)
962 {
963 	mlxcx_cmd_t cmd;
964 	mlxcx_cmd_disable_hca_in_t in;
965 	mlxcx_cmd_disable_hca_out_t out;
966 	boolean_t ret;
967 
968 	bzero(&in, sizeof (in));
969 	bzero(&out, sizeof (out));
970 
971 	mlxcx_cmd_init(mlxp, &cmd);
972 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_disable_hca_head,
973 	    MLXCX_OP_DISABLE_HCA, 0);
974 	in.mlxi_disable_hca_func = MLXCX_FUNCTION_SELF;
975 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
976 		mlxcx_cmd_fini(mlxp, &cmd);
977 		return (B_FALSE);
978 	}
979 	mlxcx_cmd_wait(&cmd);
980 
981 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
982 	mlxcx_cmd_fini(mlxp, &cmd);
983 	return (ret);
984 }
985 
986 boolean_t
987 mlxcx_cmd_enable_hca(mlxcx_t *mlxp)
988 {
989 	mlxcx_cmd_t cmd;
990 	mlxcx_cmd_enable_hca_in_t in;
991 	mlxcx_cmd_enable_hca_out_t out;
992 	boolean_t ret;
993 
994 	bzero(&in, sizeof (in));
995 	bzero(&out, sizeof (out));
996 
997 	mlxcx_cmd_init(mlxp, &cmd);
998 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_enable_hca_head,
999 	    MLXCX_OP_ENABLE_HCA, 0);
1000 	in.mlxi_enable_hca_func = MLXCX_FUNCTION_SELF;
1001 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1002 		mlxcx_cmd_fini(mlxp, &cmd);
1003 		return (B_FALSE);
1004 	}
1005 	mlxcx_cmd_wait(&cmd);
1006 
1007 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1008 	mlxcx_cmd_fini(mlxp, &cmd);
1009 	return (ret);
1010 }
1011 
1012 boolean_t
1013 mlxcx_cmd_query_issi(mlxcx_t *mlxp, uint32_t *issip)
1014 {
1015 	mlxcx_cmd_t cmd;
1016 	mlxcx_cmd_query_issi_in_t in;
1017 	mlxcx_cmd_query_issi_out_t out;
1018 	boolean_t ret;
1019 
1020 	bzero(&in, sizeof (in));
1021 	bzero(&out, sizeof (out));
1022 
1023 	mlxcx_cmd_init(mlxp, &cmd);
1024 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_query_issi_head,
1025 	    MLXCX_OP_QUERY_ISSI, 0);
1026 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1027 		mlxcx_cmd_fini(mlxp, &cmd);
1028 		return (B_FALSE);
1029 	}
1030 	mlxcx_cmd_wait(&cmd);
1031 
1032 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1033 	if (ret) {
1034 		*issip = out.mlxo_supported_issi;
1035 	} else if (cmd.mlcmd_status == 0 &&
1036 	    out.mlxo_query_issi_head.mco_status == MLXCX_CMD_R_BAD_OP) {
1037 		/*
1038 		 * The PRM says that if we get a bad operation, that means this
1039 		 * command isn't supported so it only supports version 1 of the
1040 		 * ISSI, which means bit zero should be set.
1041 		 */
1042 		ret = B_TRUE;
1043 		*issip = 1;
1044 	}
1045 	mlxcx_cmd_fini(mlxp, &cmd);
1046 	return (ret);
1047 }
1048 
1049 boolean_t
1050 mlxcx_cmd_set_issi(mlxcx_t *mlxp, uint16_t issi)
1051 {
1052 	mlxcx_cmd_t cmd;
1053 	mlxcx_cmd_set_issi_in_t in;
1054 	mlxcx_cmd_set_issi_out_t out;
1055 	boolean_t ret;
1056 
1057 	bzero(&in, sizeof (in));
1058 	bzero(&out, sizeof (out));
1059 
1060 	mlxcx_cmd_init(mlxp, &cmd);
1061 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_set_issi_head,
1062 	    MLXCX_OP_SET_ISSI, 0);
1063 	in.mlxi_set_issi_current = to_be16(issi);
1064 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1065 		mlxcx_cmd_fini(mlxp, &cmd);
1066 		return (B_FALSE);
1067 	}
1068 	mlxcx_cmd_wait(&cmd);
1069 
1070 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1071 	mlxcx_cmd_fini(mlxp, &cmd);
1072 	return (ret);
1073 }
1074 
1075 boolean_t
1076 mlxcx_cmd_query_pages(mlxcx_t *mlxp, uint_t type, int32_t *npages)
1077 {
1078 	mlxcx_cmd_t cmd;
1079 	mlxcx_cmd_query_pages_in_t in;
1080 	mlxcx_cmd_query_pages_out_t out;
1081 	boolean_t ret;
1082 
1083 	switch (type) {
1084 	case MLXCX_QUERY_PAGES_OPMOD_BOOT:
1085 	case MLXCX_QUERY_PAGES_OPMOD_INIT:
1086 	case MLXCX_QUERY_PAGES_OPMOD_REGULAR:
1087 		break;
1088 	default:
1089 		mlxcx_warn(mlxp, "!passed invalid type to query pages: %u",
1090 		    type);
1091 		return (B_FALSE);
1092 	}
1093 
1094 	bzero(&in, sizeof (in));
1095 	bzero(&out, sizeof (out));
1096 
1097 	mlxcx_cmd_init(mlxp, &cmd);
1098 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_query_pages_head,
1099 	    MLXCX_OP_QUERY_PAGES, type);
1100 	in.mlxi_query_pages_func = MLXCX_FUNCTION_SELF;
1101 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1102 		mlxcx_cmd_fini(mlxp, &cmd);
1103 		return (B_FALSE);
1104 	}
1105 	mlxcx_cmd_wait(&cmd);
1106 
1107 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1108 	if (ret) {
1109 		*npages = from_be32(out.mlxo_query_pages_npages);
1110 	}
1111 	mlxcx_cmd_fini(mlxp, &cmd);
1112 
1113 	return (ret);
1114 }
1115 
1116 boolean_t
1117 mlxcx_cmd_give_pages(mlxcx_t *mlxp, uint_t type, int32_t npages,
1118     mlxcx_dev_page_t **pages)
1119 {
1120 	mlxcx_cmd_t cmd;
1121 	mlxcx_cmd_manage_pages_in_t in;
1122 	mlxcx_cmd_manage_pages_out_t out;
1123 	size_t insize, outsize;
1124 	boolean_t ret;
1125 	uint32_t i;
1126 	uint64_t pa;
1127 	const ddi_dma_cookie_t *ck;
1128 
1129 	switch (type) {
1130 	case MLXCX_MANAGE_PAGES_OPMOD_ALLOC_FAIL:
1131 		if (npages != 0) {
1132 			mlxcx_warn(mlxp, "passed non-zero number of pages (%d) "
1133 			    "but asked to fail page allocation", npages);
1134 			return (B_FALSE);
1135 		}
1136 		break;
1137 	case MLXCX_MANAGE_PAGES_OPMOD_GIVE_PAGES:
1138 		if (npages <= 0 || npages > MLXCX_MANAGE_PAGES_MAX_PAGES) {
1139 			mlxcx_warn(mlxp, "passed invalid number of pages (%d) "
1140 			    "to give pages", npages);
1141 			return (B_FALSE);
1142 		}
1143 		break;
1144 	default:
1145 		mlxcx_warn(mlxp, "!passed invalid type to give pages: %u",
1146 		    type);
1147 		return (B_FALSE);
1148 	}
1149 
1150 	bzero(&in, sizeof (in));
1151 	bzero(&out, sizeof (out));
1152 	insize = offsetof(mlxcx_cmd_manage_pages_in_t, mlxi_manage_pages_pas) +
1153 	    npages * sizeof (uint64_t);
1154 	outsize = offsetof(mlxcx_cmd_manage_pages_out_t, mlxo_manage_pages_pas);
1155 
1156 	mlxcx_cmd_init(mlxp, &cmd);
1157 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_manage_pages_head,
1158 	    MLXCX_OP_MANAGE_PAGES, type);
1159 	in.mlxi_manage_pages_func = MLXCX_FUNCTION_SELF;
1160 	in.mlxi_manage_pages_npages = to_be32(npages);
1161 	for (i = 0; i < npages; i++) {
1162 		ck = mlxcx_dma_cookie_one(&pages[i]->mxdp_dma);
1163 		pa = ck->dmac_laddress;
1164 		ASSERT3U(pa & 0xfff, ==, 0);
1165 		ASSERT3U(ck->dmac_size, ==, MLXCX_HW_PAGE_SIZE);
1166 		in.mlxi_manage_pages_pas[i] = to_be64(pa);
1167 	}
1168 
1169 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, insize, &out, outsize)) {
1170 		mlxcx_cmd_fini(mlxp, &cmd);
1171 		return (B_FALSE);
1172 	}
1173 	mlxcx_cmd_wait(&cmd);
1174 
1175 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1176 	mlxcx_cmd_fini(mlxp, &cmd);
1177 
1178 	return (ret);
1179 }
1180 
1181 boolean_t
1182 mlxcx_cmd_return_pages(mlxcx_t *mlxp, int32_t nreq, uint64_t *pas,
1183     int32_t *nret)
1184 {
1185 	mlxcx_cmd_t cmd;
1186 	mlxcx_cmd_manage_pages_in_t in;
1187 	mlxcx_cmd_manage_pages_out_t out;
1188 	size_t insize, outsize;
1189 	boolean_t ret;
1190 	uint32_t i;
1191 
1192 	if (nreq <= 0) {
1193 		mlxcx_warn(mlxp, "passed invalid number of pages (%d) "
1194 		    "to return pages", nreq);
1195 		return (B_FALSE);
1196 	}
1197 	VERIFY3S(nreq, <=, MLXCX_MANAGE_PAGES_MAX_PAGES);
1198 
1199 	bzero(&in, sizeof (in));
1200 	bzero(&out, sizeof (out));
1201 	insize = offsetof(mlxcx_cmd_manage_pages_in_t, mlxi_manage_pages_pas);
1202 	outsize = offsetof(mlxcx_cmd_manage_pages_out_t,
1203 	    mlxo_manage_pages_pas) + nreq * sizeof (uint64_t);
1204 
1205 	mlxcx_cmd_init(mlxp, &cmd);
1206 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_manage_pages_head,
1207 	    MLXCX_OP_MANAGE_PAGES, MLXCX_MANAGE_PAGES_OPMOD_RETURN_PAGES);
1208 	in.mlxi_manage_pages_func = MLXCX_FUNCTION_SELF;
1209 	in.mlxi_manage_pages_npages = to_be32(nreq);
1210 
1211 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, insize, &out, outsize)) {
1212 		mlxcx_cmd_fini(mlxp, &cmd);
1213 		return (B_FALSE);
1214 	}
1215 	mlxcx_cmd_wait(&cmd);
1216 
1217 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1218 	if (ret) {
1219 		*nret = from_be32(out.mlxo_manage_pages_npages);
1220 		for (i = 0; i < *nret; i++) {
1221 			pas[i] = from_be64(out.mlxo_manage_pages_pas[i]);
1222 		}
1223 	}
1224 	mlxcx_cmd_fini(mlxp, &cmd);
1225 
1226 	return (ret);
1227 }
1228 
1229 boolean_t
1230 mlxcx_cmd_query_hca_cap(mlxcx_t *mlxp, mlxcx_hca_cap_type_t type,
1231     mlxcx_hca_cap_mode_t mode, mlxcx_hca_cap_t *capp)
1232 {
1233 	mlxcx_cmd_t cmd;
1234 	mlxcx_cmd_query_hca_cap_in_t in;
1235 	mlxcx_cmd_query_hca_cap_out_t *out;
1236 	boolean_t ret;
1237 	uint16_t opmode;
1238 
1239 	bzero(&in, sizeof (in));
1240 	out = kmem_zalloc(sizeof (mlxcx_cmd_query_hca_cap_out_t), KM_SLEEP);
1241 	mlxcx_cmd_init(mlxp, &cmd);
1242 
1243 	opmode = type << 1 | mode;
1244 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_query_hca_cap_head,
1245 	    MLXCX_OP_QUERY_HCA_CAP, opmode);
1246 
1247 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), out, sizeof (*out))) {
1248 		mlxcx_cmd_fini(mlxp, &cmd);
1249 		kmem_free(out, sizeof (mlxcx_cmd_query_hca_cap_out_t));
1250 		return (B_FALSE);
1251 	}
1252 	mlxcx_cmd_wait(&cmd);
1253 
1254 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1255 	if (ret) {
1256 		capp->mhc_mode = mode;
1257 		capp->mhc_type = type;
1258 		ASSERT3U(sizeof (out->mlxo_query_hca_cap_data), ==,
1259 		    sizeof (capp->mhc_bulk));
1260 		bcopy(out->mlxo_query_hca_cap_data, capp->mhc_bulk,
1261 		    sizeof (capp->mhc_bulk));
1262 	}
1263 	mlxcx_cmd_fini(mlxp, &cmd);
1264 
1265 	kmem_free(out, sizeof (mlxcx_cmd_query_hca_cap_out_t));
1266 	return (B_TRUE);
1267 }
1268 
1269 boolean_t
1270 mlxcx_cmd_init_hca(mlxcx_t *mlxp)
1271 {
1272 	mlxcx_cmd_t cmd;
1273 	mlxcx_cmd_init_hca_in_t in;
1274 	mlxcx_cmd_init_hca_out_t out;
1275 	boolean_t ret;
1276 
1277 	bzero(&in, sizeof (in));
1278 	bzero(&out, sizeof (out));
1279 
1280 	mlxcx_cmd_init(mlxp, &cmd);
1281 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_init_hca_head,
1282 	    MLXCX_OP_INIT_HCA, 0);
1283 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1284 		mlxcx_cmd_fini(mlxp, &cmd);
1285 		return (B_FALSE);
1286 	}
1287 	mlxcx_cmd_wait(&cmd);
1288 
1289 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1290 	mlxcx_cmd_fini(mlxp, &cmd);
1291 	return (ret);
1292 }
1293 
1294 boolean_t
1295 mlxcx_cmd_set_driver_version(mlxcx_t *mlxp, const char *version)
1296 {
1297 	mlxcx_cmd_t cmd;
1298 	mlxcx_cmd_set_driver_version_in_t in;
1299 	mlxcx_cmd_set_driver_version_out_t out;
1300 	boolean_t ret;
1301 
1302 	bzero(&in, sizeof (in));
1303 	bzero(&out, sizeof (out));
1304 
1305 	mlxcx_cmd_init(mlxp, &cmd);
1306 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_set_driver_version_head,
1307 	    MLXCX_OP_SET_DRIVER_VERSION, 0);
1308 	VERIFY3U(strlcpy(in.mlxi_set_driver_version_version, version,
1309 	    sizeof (in.mlxi_set_driver_version_version)), <=,
1310 	    sizeof (in.mlxi_set_driver_version_version));
1311 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1312 		mlxcx_cmd_fini(mlxp, &cmd);
1313 		return (B_FALSE);
1314 	}
1315 	mlxcx_cmd_wait(&cmd);
1316 
1317 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1318 	mlxcx_cmd_fini(mlxp, &cmd);
1319 	return (ret);
1320 }
1321 
1322 boolean_t
1323 mlxcx_cmd_alloc_uar(mlxcx_t *mlxp, mlxcx_uar_t *mlup)
1324 {
1325 	mlxcx_cmd_t cmd;
1326 	mlxcx_cmd_alloc_uar_in_t in;
1327 	mlxcx_cmd_alloc_uar_out_t out;
1328 	boolean_t ret;
1329 	size_t i;
1330 
1331 	bzero(&in, sizeof (in));
1332 	bzero(&out, sizeof (out));
1333 
1334 	mlxcx_cmd_init(mlxp, &cmd);
1335 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_alloc_uar_head,
1336 	    MLXCX_OP_ALLOC_UAR, 0);
1337 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1338 		mlxcx_cmd_fini(mlxp, &cmd);
1339 		return (B_FALSE);
1340 	}
1341 	mlxcx_cmd_wait(&cmd);
1342 
1343 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1344 	if (ret) {
1345 		mlup->mlu_allocated = B_TRUE;
1346 		mlup->mlu_num = from_be24(out.mlxo_alloc_uar_uar);
1347 		VERIFY3U(mlup->mlu_num, >, 0);
1348 		mlup->mlu_base = mlup->mlu_num * MLXCX_HW_PAGE_SIZE;
1349 
1350 		for (i = 0; i < MLXCX_BF_PER_UAR; ++i) {
1351 			mlup->mlu_bf[i].mbf_even = mlup->mlu_base +
1352 			    MLXCX_BF_BASE + MLXCX_BF_SIZE * 2 * i;
1353 			mlup->mlu_bf[i].mbf_odd = mlup->mlu_bf[i].mbf_even +
1354 			    MLXCX_BF_SIZE;
1355 		}
1356 	}
1357 	mlxcx_cmd_fini(mlxp, &cmd);
1358 	return (ret);
1359 }
1360 
1361 boolean_t
1362 mlxcx_cmd_dealloc_uar(mlxcx_t *mlxp, mlxcx_uar_t *mlup)
1363 {
1364 	mlxcx_cmd_t cmd;
1365 	mlxcx_cmd_dealloc_uar_in_t in;
1366 	mlxcx_cmd_dealloc_uar_out_t out;
1367 	boolean_t ret;
1368 
1369 	bzero(&in, sizeof (in));
1370 	bzero(&out, sizeof (out));
1371 
1372 	mlxcx_cmd_init(mlxp, &cmd);
1373 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_dealloc_uar_head,
1374 	    MLXCX_OP_DEALLOC_UAR, 0);
1375 	VERIFY(mlup->mlu_allocated);
1376 	in.mlxi_dealloc_uar_uar = to_be24(mlup->mlu_num);
1377 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1378 		mlxcx_cmd_fini(mlxp, &cmd);
1379 		return (B_FALSE);
1380 	}
1381 	mlxcx_cmd_wait(&cmd);
1382 
1383 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1384 	if (ret) {
1385 		mlup->mlu_allocated = B_FALSE;
1386 		mlup->mlu_num = 0;
1387 	}
1388 	mlxcx_cmd_fini(mlxp, &cmd);
1389 	return (ret);
1390 }
1391 
1392 boolean_t
1393 mlxcx_cmd_alloc_pd(mlxcx_t *mlxp, mlxcx_pd_t *mlpd)
1394 {
1395 	mlxcx_cmd_t cmd;
1396 	mlxcx_cmd_alloc_pd_in_t in;
1397 	mlxcx_cmd_alloc_pd_out_t out;
1398 	boolean_t ret;
1399 
1400 	bzero(&in, sizeof (in));
1401 	bzero(&out, sizeof (out));
1402 
1403 	mlxcx_cmd_init(mlxp, &cmd);
1404 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_alloc_pd_head,
1405 	    MLXCX_OP_ALLOC_PD, 0);
1406 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1407 		mlxcx_cmd_fini(mlxp, &cmd);
1408 		return (B_FALSE);
1409 	}
1410 	mlxcx_cmd_wait(&cmd);
1411 
1412 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1413 	if (ret) {
1414 		mlpd->mlpd_allocated = B_TRUE;
1415 		mlpd->mlpd_num = from_be24(out.mlxo_alloc_pd_pdn);
1416 	}
1417 	mlxcx_cmd_fini(mlxp, &cmd);
1418 	return (ret);
1419 }
1420 
1421 boolean_t
1422 mlxcx_cmd_dealloc_pd(mlxcx_t *mlxp, mlxcx_pd_t *mlpd)
1423 {
1424 	mlxcx_cmd_t cmd;
1425 	mlxcx_cmd_dealloc_pd_in_t in;
1426 	mlxcx_cmd_dealloc_pd_out_t out;
1427 	boolean_t ret;
1428 
1429 	bzero(&in, sizeof (in));
1430 	bzero(&out, sizeof (out));
1431 
1432 	mlxcx_cmd_init(mlxp, &cmd);
1433 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_dealloc_pd_head,
1434 	    MLXCX_OP_DEALLOC_PD, 0);
1435 	VERIFY(mlpd->mlpd_allocated);
1436 	in.mlxi_dealloc_pd_pdn = to_be24(mlpd->mlpd_num);
1437 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1438 		mlxcx_cmd_fini(mlxp, &cmd);
1439 		return (B_FALSE);
1440 	}
1441 	mlxcx_cmd_wait(&cmd);
1442 
1443 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1444 	if (ret) {
1445 		mlpd->mlpd_allocated = B_FALSE;
1446 		mlpd->mlpd_num = 0;
1447 	}
1448 	mlxcx_cmd_fini(mlxp, &cmd);
1449 	return (ret);
1450 }
1451 
1452 boolean_t
1453 mlxcx_cmd_alloc_tdom(mlxcx_t *mlxp, mlxcx_tdom_t *mltd)
1454 {
1455 	mlxcx_cmd_t cmd;
1456 	mlxcx_cmd_alloc_tdom_in_t in;
1457 	mlxcx_cmd_alloc_tdom_out_t out;
1458 	boolean_t ret;
1459 
1460 	bzero(&in, sizeof (in));
1461 	bzero(&out, sizeof (out));
1462 
1463 	mlxcx_cmd_init(mlxp, &cmd);
1464 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_alloc_tdom_head,
1465 	    MLXCX_OP_ALLOC_TRANSPORT_DOMAIN, 0);
1466 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1467 		mlxcx_cmd_fini(mlxp, &cmd);
1468 		return (B_FALSE);
1469 	}
1470 	mlxcx_cmd_wait(&cmd);
1471 
1472 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1473 	if (ret) {
1474 		mltd->mltd_allocated = B_TRUE;
1475 		mltd->mltd_num = from_be24(out.mlxo_alloc_tdom_tdomn);
1476 	}
1477 	mlxcx_cmd_fini(mlxp, &cmd);
1478 	return (ret);
1479 }
1480 
1481 boolean_t
1482 mlxcx_cmd_dealloc_tdom(mlxcx_t *mlxp, mlxcx_tdom_t *mltd)
1483 {
1484 	mlxcx_cmd_t cmd;
1485 	mlxcx_cmd_dealloc_tdom_in_t in;
1486 	mlxcx_cmd_dealloc_tdom_out_t out;
1487 	boolean_t ret;
1488 
1489 	bzero(&in, sizeof (in));
1490 	bzero(&out, sizeof (out));
1491 
1492 	mlxcx_cmd_init(mlxp, &cmd);
1493 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_dealloc_tdom_head,
1494 	    MLXCX_OP_DEALLOC_TRANSPORT_DOMAIN, 0);
1495 	VERIFY(mltd->mltd_allocated);
1496 	in.mlxi_dealloc_tdom_tdomn = to_be24(mltd->mltd_num);
1497 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1498 		mlxcx_cmd_fini(mlxp, &cmd);
1499 		return (B_FALSE);
1500 	}
1501 	mlxcx_cmd_wait(&cmd);
1502 
1503 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1504 	if (ret) {
1505 		mltd->mltd_allocated = B_FALSE;
1506 		mltd->mltd_num = 0;
1507 	}
1508 	mlxcx_cmd_fini(mlxp, &cmd);
1509 	return (ret);
1510 }
1511 
1512 boolean_t
1513 mlxcx_cmd_teardown_hca(mlxcx_t *mlxp)
1514 {
1515 	mlxcx_cmd_t cmd;
1516 	mlxcx_cmd_teardown_hca_in_t in;
1517 	mlxcx_cmd_teardown_hca_out_t out;
1518 	boolean_t ret;
1519 
1520 	bzero(&in, sizeof (in));
1521 	bzero(&out, sizeof (out));
1522 
1523 	mlxcx_cmd_init(mlxp, &cmd);
1524 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_teardown_hca_head,
1525 	    MLXCX_OP_TEARDOWN_HCA, 0);
1526 	in.mlxi_teardown_hca_profile = to_be16(MLXCX_TEARDOWN_HCA_GRACEFUL);
1527 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1528 		mlxcx_cmd_fini(mlxp, &cmd);
1529 		return (B_FALSE);
1530 	}
1531 	mlxcx_cmd_wait(&cmd);
1532 
1533 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1534 	mlxcx_cmd_fini(mlxp, &cmd);
1535 	return (ret);
1536 }
1537 
1538 boolean_t
1539 mlxcx_cmd_query_nic_vport_ctx(mlxcx_t *mlxp, mlxcx_port_t *mlp)
1540 {
1541 	mlxcx_cmd_t cmd;
1542 	mlxcx_cmd_query_nic_vport_ctx_in_t in;
1543 	mlxcx_cmd_query_nic_vport_ctx_out_t out;
1544 	boolean_t ret;
1545 	const mlxcx_nic_vport_ctx_t *ctx;
1546 
1547 	bzero(&in, sizeof (in));
1548 	bzero(&out, sizeof (out));
1549 
1550 	ASSERT(mutex_owned(&mlp->mlp_mtx));
1551 	mlxcx_cmd_init(mlxp, &cmd);
1552 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_query_nic_vport_ctx_head,
1553 	    MLXCX_OP_QUERY_NIC_VPORT_CONTEXT, MLXCX_VPORT_TYPE_VNIC);
1554 
1555 	in.mlxi_query_nic_vport_ctx_vport_number = to_be16(mlp->mlp_num);
1556 
1557 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1558 		mlxcx_cmd_fini(mlxp, &cmd);
1559 		return (B_FALSE);
1560 	}
1561 	mlxcx_cmd_wait(&cmd);
1562 
1563 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1564 	if (ret) {
1565 		ctx = &out.mlxo_query_nic_vport_ctx_context;
1566 		mlp->mlp_guid = from_be64(ctx->mlnvc_port_guid);
1567 		mlp->mlp_mtu = from_be16(ctx->mlnvc_mtu);
1568 		bcopy(ctx->mlnvc_permanent_address, mlp->mlp_mac_address,
1569 		    sizeof (mlp->mlp_mac_address));
1570 		mlp->mlp_wqe_min_inline = get_bits64(ctx->mlnvc_flags,
1571 		    MLXCX_VPORT_CTX_MIN_WQE_INLINE);
1572 	}
1573 	mlxcx_cmd_fini(mlxp, &cmd);
1574 	return (ret);
1575 }
1576 
1577 static const char *
1578 mlxcx_reg_name(mlxcx_register_id_t rid)
1579 {
1580 	switch (rid) {
1581 	case MLXCX_REG_PMTU:
1582 		return ("PMTU");
1583 	case MLXCX_REG_PAOS:
1584 		return ("PAOS");
1585 	case MLXCX_REG_PTYS:
1586 		return ("PTYS");
1587 	case MLXCX_REG_MSGI:
1588 		return ("MSGI");
1589 	case MLXCX_REG_PMAOS:
1590 		return ("PMAOS");
1591 	case MLXCX_REG_MLCR:
1592 		return ("MLCR");
1593 	case MLXCX_REG_MCIA:
1594 		return ("MCIA");
1595 	case MLXCX_REG_PPCNT:
1596 		return ("PPCNT");
1597 	default:
1598 		return ("???");
1599 	}
1600 }
1601 
1602 boolean_t
1603 mlxcx_cmd_access_register(mlxcx_t *mlxp, mlxcx_cmd_reg_opmod_t opmod,
1604     mlxcx_register_id_t rid, mlxcx_register_data_t *data)
1605 {
1606 	mlxcx_cmd_t cmd;
1607 	mlxcx_cmd_access_register_in_t in;
1608 	mlxcx_cmd_access_register_out_t out;
1609 	boolean_t ret;
1610 	size_t dsize, insize, outsize;
1611 
1612 	bzero(&in, sizeof (in));
1613 	bzero(&out, sizeof (out));
1614 
1615 	mlxcx_cmd_init(mlxp, &cmd);
1616 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_access_register_head,
1617 	    MLXCX_OP_ACCESS_REG, opmod);
1618 
1619 	in.mlxi_access_register_register_id = to_be16(rid);
1620 
1621 	switch (rid) {
1622 	case MLXCX_REG_PMTU:
1623 		dsize = sizeof (mlxcx_reg_pmtu_t);
1624 		break;
1625 	case MLXCX_REG_PAOS:
1626 		dsize = sizeof (mlxcx_reg_paos_t);
1627 		break;
1628 	case MLXCX_REG_PTYS:
1629 		dsize = sizeof (mlxcx_reg_ptys_t);
1630 		break;
1631 	case MLXCX_REG_MLCR:
1632 		dsize = sizeof (mlxcx_reg_mlcr_t);
1633 		break;
1634 	case MLXCX_REG_PMAOS:
1635 		dsize = sizeof (mlxcx_reg_pmaos_t);
1636 		break;
1637 	case MLXCX_REG_MCIA:
1638 		dsize = sizeof (mlxcx_reg_mcia_t);
1639 		break;
1640 	case MLXCX_REG_PPCNT:
1641 		dsize = sizeof (mlxcx_reg_ppcnt_t);
1642 		break;
1643 	default:
1644 		dsize = 0;
1645 		VERIFY(0);
1646 		return (B_FALSE);
1647 	}
1648 	insize = dsize + offsetof(mlxcx_cmd_access_register_in_t,
1649 	    mlxi_access_register_data);
1650 	outsize = dsize + offsetof(mlxcx_cmd_access_register_out_t,
1651 	    mlxo_access_register_data);
1652 
1653 	bcopy(data, &in.mlxi_access_register_data, dsize);
1654 
1655 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, insize, &out, outsize)) {
1656 		mlxcx_cmd_fini(mlxp, &cmd);
1657 		return (B_FALSE);
1658 	}
1659 	mlxcx_cmd_wait(&cmd);
1660 
1661 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1662 	if (ret) {
1663 		bcopy(&out.mlxo_access_register_data, data, dsize);
1664 	} else {
1665 		mlxcx_warn(mlxp, "failed OP_ACCESS_REG was for register "
1666 		    "%04x (%s)", rid, mlxcx_reg_name(rid));
1667 	}
1668 	mlxcx_cmd_fini(mlxp, &cmd);
1669 	return (ret);
1670 }
1671 
1672 boolean_t
1673 mlxcx_cmd_query_port_mtu(mlxcx_t *mlxp, mlxcx_port_t *mlp)
1674 {
1675 	mlxcx_register_data_t data;
1676 	boolean_t ret;
1677 
1678 	/*
1679 	 * Since we modify the port here we require that the caller is holding
1680 	 * the port mutex.
1681 	 */
1682 	ASSERT(mutex_owned(&mlp->mlp_mtx));
1683 	bzero(&data, sizeof (data));
1684 	data.mlrd_pmtu.mlrd_pmtu_local_port = mlp->mlp_num + 1;
1685 
1686 	ret = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ,
1687 	    MLXCX_REG_PMTU, &data);
1688 
1689 	if (ret) {
1690 		mlp->mlp_mtu = from_be16(data.mlrd_pmtu.mlrd_pmtu_admin_mtu);
1691 		mlp->mlp_max_mtu = from_be16(data.mlrd_pmtu.mlrd_pmtu_max_mtu);
1692 	}
1693 
1694 	return (ret);
1695 }
1696 
1697 boolean_t
1698 mlxcx_cmd_query_module_status(mlxcx_t *mlxp, uint_t id,
1699     mlxcx_module_status_t *pstatus, mlxcx_module_error_type_t *perr)
1700 {
1701 	mlxcx_register_data_t data;
1702 	boolean_t ret;
1703 
1704 	bzero(&data, sizeof (data));
1705 	ASSERT3U(id, <, 0xff);
1706 	data.mlrd_pmaos.mlrd_pmaos_module = (uint8_t)id;
1707 
1708 	ret = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ,
1709 	    MLXCX_REG_PMAOS, &data);
1710 
1711 	if (ret) {
1712 		if (pstatus != NULL)
1713 			*pstatus = data.mlrd_pmaos.mlrd_pmaos_oper_status;
1714 		if (perr != NULL)
1715 			*perr = data.mlrd_pmaos.mlrd_pmaos_error_type;
1716 	}
1717 
1718 	return (ret);
1719 }
1720 
1721 boolean_t
1722 mlxcx_cmd_set_port_mtu(mlxcx_t *mlxp, mlxcx_port_t *mlp)
1723 {
1724 	mlxcx_register_data_t data;
1725 	boolean_t ret;
1726 
1727 	ASSERT(mutex_owned(&mlp->mlp_mtx));
1728 	bzero(&data, sizeof (data));
1729 	data.mlrd_pmtu.mlrd_pmtu_local_port = mlp->mlp_num + 1;
1730 	data.mlrd_pmtu.mlrd_pmtu_admin_mtu = to_be16(mlp->mlp_mtu);
1731 
1732 	ret = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_WRITE,
1733 	    MLXCX_REG_PMTU, &data);
1734 
1735 	return (ret);
1736 }
1737 
1738 boolean_t
1739 mlxcx_cmd_set_port_led(mlxcx_t *mlxp, mlxcx_port_t *mlp, uint16_t sec)
1740 {
1741 	mlxcx_register_data_t data;
1742 	boolean_t ret;
1743 
1744 	ASSERT(mutex_owned(&mlp->mlp_mtx));
1745 	bzero(&data, sizeof (data));
1746 	data.mlrd_mlcr.mlrd_mlcr_local_port = mlp->mlp_num + 1;
1747 	set_bits8(&data.mlrd_mlcr.mlrd_mlcr_flags, MLXCX_MLCR_LED_TYPE,
1748 	    MLXCX_LED_TYPE_PORT);
1749 	data.mlrd_mlcr.mlrd_mlcr_beacon_duration = to_be16(sec);
1750 
1751 	ret = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_WRITE,
1752 	    MLXCX_REG_MLCR, &data);
1753 
1754 	return (ret);
1755 }
1756 
1757 boolean_t
1758 mlxcx_cmd_query_port_status(mlxcx_t *mlxp, mlxcx_port_t *mlp)
1759 {
1760 	mlxcx_register_data_t data;
1761 	boolean_t ret;
1762 
1763 	ASSERT(mutex_owned(&mlp->mlp_mtx));
1764 	bzero(&data, sizeof (data));
1765 	data.mlrd_paos.mlrd_paos_local_port = mlp->mlp_num + 1;
1766 
1767 	ret = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ,
1768 	    MLXCX_REG_PAOS, &data);
1769 
1770 	if (ret) {
1771 		mlp->mlp_admin_status = data.mlrd_paos.mlrd_paos_admin_status;
1772 		mlp->mlp_oper_status = data.mlrd_paos.mlrd_paos_oper_status;
1773 	}
1774 
1775 	return (ret);
1776 }
1777 
1778 boolean_t
1779 mlxcx_cmd_query_port_speed(mlxcx_t *mlxp, mlxcx_port_t *mlp)
1780 {
1781 	mlxcx_register_data_t data;
1782 	boolean_t ret;
1783 
1784 	ASSERT(mutex_owned(&mlp->mlp_mtx));
1785 	bzero(&data, sizeof (data));
1786 	data.mlrd_ptys.mlrd_ptys_local_port = mlp->mlp_num + 1;
1787 	set_bit8(&data.mlrd_ptys.mlrd_ptys_proto_mask,
1788 	    MLXCX_PTYS_PROTO_MASK_ETH);
1789 
1790 	ret = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ,
1791 	    MLXCX_REG_PTYS, &data);
1792 
1793 	if (ret) {
1794 		if (get_bit8(data.mlrd_ptys.mlrd_ptys_autoneg_flags,
1795 		    MLXCX_AUTONEG_DISABLE)) {
1796 			mlp->mlp_autoneg = B_FALSE;
1797 		} else {
1798 			mlp->mlp_autoneg = B_TRUE;
1799 		}
1800 		mlp->mlp_max_proto =
1801 		    from_bits32(data.mlrd_ptys.mlrd_ptys_proto_cap);
1802 		mlp->mlp_admin_proto =
1803 		    from_bits32(data.mlrd_ptys.mlrd_ptys_proto_admin);
1804 		mlp->mlp_oper_proto =
1805 		    from_bits32(data.mlrd_ptys.mlrd_ptys_proto_oper);
1806 	}
1807 
1808 	return (ret);
1809 }
1810 
1811 boolean_t
1812 mlxcx_cmd_modify_nic_vport_ctx(mlxcx_t *mlxp, mlxcx_port_t *mlp,
1813     mlxcx_modify_nic_vport_ctx_fields_t fields)
1814 {
1815 	mlxcx_cmd_t cmd;
1816 	mlxcx_cmd_modify_nic_vport_ctx_in_t in;
1817 	mlxcx_cmd_modify_nic_vport_ctx_out_t out;
1818 	boolean_t ret;
1819 	mlxcx_nic_vport_ctx_t *ctx;
1820 
1821 	ASSERT(mutex_owned(&mlp->mlp_mtx));
1822 	bzero(&in, sizeof (in));
1823 	bzero(&out, sizeof (out));
1824 
1825 	mlxcx_cmd_init(mlxp, &cmd);
1826 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_modify_nic_vport_ctx_head,
1827 	    MLXCX_OP_MODIFY_NIC_VPORT_CONTEXT, MLXCX_VPORT_TYPE_VNIC);
1828 
1829 	in.mlxi_modify_nic_vport_ctx_vport_number = to_be16(mlp->mlp_num);
1830 	in.mlxi_modify_nic_vport_ctx_field_select = to_be32(fields);
1831 
1832 	ctx = &in.mlxi_modify_nic_vport_ctx_context;
1833 	if (fields & MLXCX_MODIFY_NIC_VPORT_CTX_PROMISC) {
1834 		set_bit16(&ctx->mlnvc_promisc_list_type,
1835 		    MLXCX_VPORT_PROMISC_ALL);
1836 	}
1837 	if (fields & MLXCX_MODIFY_NIC_VPORT_CTX_MTU) {
1838 		ctx->mlnvc_mtu = to_be16(mlp->mlp_mtu);
1839 	}
1840 
1841 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1842 		mlxcx_cmd_fini(mlxp, &cmd);
1843 		return (B_FALSE);
1844 	}
1845 	mlxcx_cmd_wait(&cmd);
1846 
1847 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1848 	if (ret) {
1849 		if (fields & MLXCX_MODIFY_NIC_VPORT_CTX_PROMISC) {
1850 			mlp->mlp_flags |= MLXCX_PORT_VPORT_PROMISC;
1851 		}
1852 	}
1853 	mlxcx_cmd_fini(mlxp, &cmd);
1854 	return (ret);
1855 }
1856 
1857 boolean_t
1858 mlxcx_cmd_create_eq(mlxcx_t *mlxp, mlxcx_event_queue_t *mleq)
1859 {
1860 	mlxcx_cmd_t cmd;
1861 	mlxcx_cmd_create_eq_in_t in;
1862 	mlxcx_cmd_create_eq_out_t out;
1863 	boolean_t ret;
1864 	mlxcx_eventq_ctx_t *ctx;
1865 	size_t rem, insize;
1866 	const ddi_dma_cookie_t *c;
1867 	uint64_t pa, npages;
1868 
1869 	bzero(&in, sizeof (in));
1870 	bzero(&out, sizeof (out));
1871 
1872 	ASSERT(mutex_owned(&mleq->mleq_mtx));
1873 	VERIFY(mleq->mleq_state & MLXCX_EQ_ALLOC);
1874 	VERIFY0(mleq->mleq_state & MLXCX_EQ_CREATED);
1875 
1876 	mlxcx_cmd_init(mlxp, &cmd);
1877 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_create_eq_head,
1878 	    MLXCX_OP_CREATE_EQ, 0);
1879 
1880 	ctx = &in.mlxi_create_eq_context;
1881 	ctx->mleqc_uar_page = to_be24(mleq->mleq_uar->mlu_num);
1882 	ctx->mleqc_log_eq_size = mleq->mleq_entshift;
1883 	ctx->mleqc_intr = mleq->mleq_intr_index;
1884 
1885 	in.mlxi_create_eq_event_bitmask = to_be64(mleq->mleq_events);
1886 
1887 	npages = 0;
1888 	c = NULL;
1889 	while ((c = mlxcx_dma_cookie_iter(&mleq->mleq_dma, c)) != NULL) {
1890 		pa = c->dmac_laddress;
1891 		rem = c->dmac_size;
1892 		while (rem > 0) {
1893 			ASSERT3U(pa & 0xfff, ==, 0);
1894 			ASSERT3U(rem, >=, MLXCX_HW_PAGE_SIZE);
1895 			in.mlxi_create_eq_pas[npages++] = to_be64(pa);
1896 			rem -= MLXCX_HW_PAGE_SIZE;
1897 			pa += MLXCX_HW_PAGE_SIZE;
1898 		}
1899 	}
1900 	ASSERT3U(npages, <=, MLXCX_CREATE_QUEUE_MAX_PAGES);
1901 
1902 	insize = offsetof(mlxcx_cmd_create_eq_in_t, mlxi_create_eq_pas) +
1903 	    sizeof (uint64_t) * npages;
1904 
1905 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, insize, &out, sizeof (out))) {
1906 		mlxcx_cmd_fini(mlxp, &cmd);
1907 		return (B_FALSE);
1908 	}
1909 	mlxcx_cmd_wait(&cmd);
1910 
1911 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1912 	if (ret) {
1913 		mleq->mleq_state |= MLXCX_EQ_CREATED;
1914 		mleq->mleq_num = out.mlxo_create_eq_eqn;
1915 	}
1916 	mlxcx_cmd_fini(mlxp, &cmd);
1917 	return (ret);
1918 }
1919 
1920 boolean_t
1921 mlxcx_cmd_query_eq(mlxcx_t *mlxp, mlxcx_event_queue_t *mleq,
1922     mlxcx_eventq_ctx_t *ctxp)
1923 {
1924 	mlxcx_cmd_t cmd;
1925 	mlxcx_cmd_query_eq_in_t in;
1926 	mlxcx_cmd_query_eq_out_t out;
1927 	boolean_t ret;
1928 
1929 	bzero(&in, sizeof (in));
1930 	bzero(&out, sizeof (out));
1931 
1932 	ASSERT(mutex_owned(&mleq->mleq_mtx));
1933 	VERIFY(mleq->mleq_state & MLXCX_EQ_ALLOC);
1934 	VERIFY(mleq->mleq_state & MLXCX_EQ_CREATED);
1935 
1936 	mlxcx_cmd_init(mlxp, &cmd);
1937 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_query_eq_head,
1938 	    MLXCX_OP_QUERY_EQ, 0);
1939 
1940 	in.mlxi_query_eq_eqn = mleq->mleq_num;
1941 
1942 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1943 		mlxcx_cmd_fini(mlxp, &cmd);
1944 		return (B_FALSE);
1945 	}
1946 	mlxcx_cmd_wait(&cmd);
1947 
1948 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1949 	if (ret) {
1950 		bcopy(&out.mlxo_query_eq_context, ctxp,
1951 		    sizeof (mlxcx_eventq_ctx_t));
1952 	}
1953 	mlxcx_cmd_fini(mlxp, &cmd);
1954 	return (ret);
1955 }
1956 
1957 boolean_t
1958 mlxcx_cmd_destroy_eq(mlxcx_t *mlxp, mlxcx_event_queue_t *mleq)
1959 {
1960 	mlxcx_cmd_t cmd;
1961 	mlxcx_cmd_destroy_eq_in_t in;
1962 	mlxcx_cmd_destroy_eq_out_t out;
1963 	boolean_t ret;
1964 
1965 	bzero(&in, sizeof (in));
1966 	bzero(&out, sizeof (out));
1967 
1968 	ASSERT(mutex_owned(&mleq->mleq_mtx));
1969 	VERIFY(mleq->mleq_state & MLXCX_EQ_ALLOC);
1970 	VERIFY(mleq->mleq_state & MLXCX_EQ_CREATED);
1971 
1972 	mlxcx_cmd_init(mlxp, &cmd);
1973 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_destroy_eq_head,
1974 	    MLXCX_OP_DESTROY_EQ, 0);
1975 
1976 	in.mlxi_destroy_eq_eqn = mleq->mleq_num;
1977 
1978 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
1979 		mlxcx_cmd_fini(mlxp, &cmd);
1980 		return (B_FALSE);
1981 	}
1982 	mlxcx_cmd_wait(&cmd);
1983 
1984 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
1985 	if (ret) {
1986 		mleq->mleq_state |= MLXCX_EQ_DESTROYED;
1987 	}
1988 	mlxcx_cmd_fini(mlxp, &cmd);
1989 	return (ret);
1990 }
1991 
1992 boolean_t
1993 mlxcx_cmd_query_special_ctxs(mlxcx_t *mlxp)
1994 {
1995 	mlxcx_cmd_t cmd;
1996 	mlxcx_cmd_query_special_ctxs_in_t in;
1997 	mlxcx_cmd_query_special_ctxs_out_t out;
1998 	boolean_t ret;
1999 
2000 	bzero(&in, sizeof (in));
2001 	bzero(&out, sizeof (out));
2002 
2003 	mlxcx_cmd_init(mlxp, &cmd);
2004 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_query_special_ctxs_head,
2005 	    MLXCX_OP_QUERY_SPECIAL_CONTEXTS, 0);
2006 
2007 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2008 		mlxcx_cmd_fini(mlxp, &cmd);
2009 		return (B_FALSE);
2010 	}
2011 	mlxcx_cmd_wait(&cmd);
2012 
2013 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2014 	if (ret) {
2015 		mlxp->mlx_rsvd_lkey = from_be32(
2016 		    out.mlxo_query_special_ctxs_resd_lkey);
2017 	}
2018 	mlxcx_cmd_fini(mlxp, &cmd);
2019 	return (ret);
2020 }
2021 
2022 boolean_t
2023 mlxcx_cmd_create_cq(mlxcx_t *mlxp, mlxcx_completion_queue_t *mlcq)
2024 {
2025 	mlxcx_cmd_t cmd;
2026 	mlxcx_cmd_create_cq_in_t in;
2027 	mlxcx_cmd_create_cq_out_t out;
2028 	boolean_t ret;
2029 	mlxcx_completionq_ctx_t *ctx;
2030 	size_t rem, insize;
2031 	const ddi_dma_cookie_t *c;
2032 	uint64_t pa, npages;
2033 
2034 	bzero(&in, sizeof (in));
2035 	bzero(&out, sizeof (out));
2036 
2037 	ASSERT(mutex_owned(&mlcq->mlcq_mtx));
2038 	VERIFY(mlcq->mlcq_state & MLXCX_CQ_ALLOC);
2039 	VERIFY0(mlcq->mlcq_state & MLXCX_CQ_CREATED);
2040 
2041 	mlxcx_cmd_init(mlxp, &cmd);
2042 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_create_cq_head,
2043 	    MLXCX_OP_CREATE_CQ, 0);
2044 
2045 	ctx = &in.mlxi_create_cq_context;
2046 	ctx->mlcqc_uar_page = to_be24(mlcq->mlcq_uar->mlu_num);
2047 	ctx->mlcqc_log_cq_size = mlcq->mlcq_entshift;
2048 	ctx->mlcqc_eqn = mlcq->mlcq_eq->mleq_num;
2049 	ctx->mlcqc_cq_period = to_be16(mlcq->mlcq_cqemod_period_usec);
2050 	ctx->mlcqc_cq_max_count = to_be16(mlcq->mlcq_cqemod_count);
2051 
2052 	c = mlxcx_dma_cookie_one(&mlcq->mlcq_doorbell_dma);
2053 	ctx->mlcqc_dbr_addr = to_be64(c->dmac_laddress);
2054 	ASSERT3U(c->dmac_size, >=, sizeof (mlxcx_completionq_doorbell_t));
2055 
2056 	npages = 0;
2057 	c = NULL;
2058 	while ((c = mlxcx_dma_cookie_iter(&mlcq->mlcq_dma, c)) != NULL) {
2059 		pa = c->dmac_laddress;
2060 		rem = c->dmac_size;
2061 		while (rem > 0) {
2062 			ASSERT3U(pa & 0xfff, ==, 0);
2063 			ASSERT3U(rem, >=, MLXCX_HW_PAGE_SIZE);
2064 			in.mlxi_create_cq_pas[npages++] = to_be64(pa);
2065 			rem -= MLXCX_HW_PAGE_SIZE;
2066 			pa += MLXCX_HW_PAGE_SIZE;
2067 		}
2068 	}
2069 	ASSERT3U(npages, <=, MLXCX_CREATE_QUEUE_MAX_PAGES);
2070 
2071 	insize = offsetof(mlxcx_cmd_create_cq_in_t, mlxi_create_cq_pas) +
2072 	    sizeof (uint64_t) * npages;
2073 
2074 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, insize, &out, sizeof (out))) {
2075 		mlxcx_cmd_fini(mlxp, &cmd);
2076 		return (B_FALSE);
2077 	}
2078 	mlxcx_cmd_wait(&cmd);
2079 
2080 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2081 	if (ret) {
2082 		mlcq->mlcq_state |= MLXCX_CQ_CREATED;
2083 		mlcq->mlcq_num = from_be24(out.mlxo_create_cq_cqn);
2084 	}
2085 	mlxcx_cmd_fini(mlxp, &cmd);
2086 	return (ret);
2087 }
2088 
2089 boolean_t
2090 mlxcx_cmd_query_rq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq,
2091     mlxcx_rq_ctx_t *ctxp)
2092 {
2093 	mlxcx_cmd_t cmd;
2094 	mlxcx_cmd_query_rq_in_t in;
2095 	mlxcx_cmd_query_rq_out_t out;
2096 	boolean_t ret;
2097 
2098 	bzero(&in, sizeof (in));
2099 	bzero(&out, sizeof (out));
2100 
2101 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
2102 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
2103 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_CREATED);
2104 	ASSERT3S(mlwq->mlwq_type, ==, MLXCX_WQ_TYPE_RECVQ);
2105 
2106 	mlxcx_cmd_init(mlxp, &cmd);
2107 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_query_rq_head,
2108 	    MLXCX_OP_QUERY_RQ, 0);
2109 
2110 	in.mlxi_query_rq_rqn = to_be24(mlwq->mlwq_num);
2111 
2112 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2113 		mlxcx_cmd_fini(mlxp, &cmd);
2114 		return (B_FALSE);
2115 	}
2116 	mlxcx_cmd_wait(&cmd);
2117 
2118 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2119 	if (ret) {
2120 		bcopy(&out.mlxo_query_rq_context, ctxp,
2121 		    sizeof (mlxcx_rq_ctx_t));
2122 	}
2123 	mlxcx_cmd_fini(mlxp, &cmd);
2124 	return (ret);
2125 }
2126 
2127 boolean_t
2128 mlxcx_cmd_query_sq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq,
2129     mlxcx_sq_ctx_t *ctxp)
2130 {
2131 	mlxcx_cmd_t cmd;
2132 	mlxcx_cmd_query_sq_in_t in;
2133 	mlxcx_cmd_query_sq_out_t out;
2134 	boolean_t ret;
2135 
2136 	bzero(&in, sizeof (in));
2137 	bzero(&out, sizeof (out));
2138 
2139 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
2140 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
2141 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_CREATED);
2142 	ASSERT3S(mlwq->mlwq_type, ==, MLXCX_WQ_TYPE_SENDQ);
2143 
2144 	mlxcx_cmd_init(mlxp, &cmd);
2145 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_query_sq_head,
2146 	    MLXCX_OP_QUERY_SQ, 0);
2147 
2148 	in.mlxi_query_sq_sqn = to_be24(mlwq->mlwq_num);
2149 
2150 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2151 		mlxcx_cmd_fini(mlxp, &cmd);
2152 		return (B_FALSE);
2153 	}
2154 	mlxcx_cmd_wait(&cmd);
2155 
2156 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2157 	if (ret) {
2158 		bcopy(&out.mlxo_query_sq_context, ctxp,
2159 		    sizeof (mlxcx_sq_ctx_t));
2160 	}
2161 	mlxcx_cmd_fini(mlxp, &cmd);
2162 	return (ret);
2163 }
2164 
2165 boolean_t
2166 mlxcx_cmd_query_cq(mlxcx_t *mlxp, mlxcx_completion_queue_t *mlcq,
2167     mlxcx_completionq_ctx_t *ctxp)
2168 {
2169 	mlxcx_cmd_t cmd;
2170 	mlxcx_cmd_query_cq_in_t in;
2171 	mlxcx_cmd_query_cq_out_t out;
2172 	boolean_t ret;
2173 
2174 	bzero(&in, sizeof (in));
2175 	bzero(&out, sizeof (out));
2176 
2177 	ASSERT(mutex_owned(&mlcq->mlcq_mtx));
2178 	VERIFY(mlcq->mlcq_state & MLXCX_CQ_ALLOC);
2179 	VERIFY(mlcq->mlcq_state & MLXCX_CQ_CREATED);
2180 
2181 	mlxcx_cmd_init(mlxp, &cmd);
2182 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_query_cq_head,
2183 	    MLXCX_OP_QUERY_CQ, 0);
2184 
2185 	in.mlxi_query_cq_cqn = to_be24(mlcq->mlcq_num);
2186 
2187 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2188 		mlxcx_cmd_fini(mlxp, &cmd);
2189 		return (B_FALSE);
2190 	}
2191 	mlxcx_cmd_wait(&cmd);
2192 
2193 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2194 	if (ret) {
2195 		bcopy(&out.mlxo_query_cq_context, ctxp,
2196 		    sizeof (mlxcx_completionq_ctx_t));
2197 	}
2198 	mlxcx_cmd_fini(mlxp, &cmd);
2199 	return (ret);
2200 }
2201 
2202 boolean_t
2203 mlxcx_cmd_destroy_cq(mlxcx_t *mlxp, mlxcx_completion_queue_t *mlcq)
2204 {
2205 	mlxcx_cmd_t cmd;
2206 	mlxcx_cmd_destroy_cq_in_t in;
2207 	mlxcx_cmd_destroy_cq_out_t out;
2208 	boolean_t ret;
2209 
2210 	bzero(&in, sizeof (in));
2211 	bzero(&out, sizeof (out));
2212 
2213 	ASSERT(mutex_owned(&mlcq->mlcq_mtx));
2214 	VERIFY(mlcq->mlcq_state & MLXCX_CQ_ALLOC);
2215 	VERIFY(mlcq->mlcq_state & MLXCX_CQ_CREATED);
2216 
2217 	mlxcx_cmd_init(mlxp, &cmd);
2218 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_destroy_cq_head,
2219 	    MLXCX_OP_DESTROY_CQ, 0);
2220 
2221 	in.mlxi_destroy_cq_cqn = to_be24(mlcq->mlcq_num);
2222 
2223 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2224 		mlxcx_cmd_fini(mlxp, &cmd);
2225 		return (B_FALSE);
2226 	}
2227 	mlxcx_cmd_wait(&cmd);
2228 
2229 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2230 	if (ret) {
2231 		mlcq->mlcq_state |= MLXCX_CQ_DESTROYED;
2232 	}
2233 	mlxcx_cmd_fini(mlxp, &cmd);
2234 	return (ret);
2235 }
2236 
2237 boolean_t
2238 mlxcx_cmd_create_rq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq)
2239 {
2240 	mlxcx_cmd_t cmd;
2241 	mlxcx_cmd_create_rq_in_t in;
2242 	mlxcx_cmd_create_rq_out_t out;
2243 	boolean_t ret;
2244 	mlxcx_rq_ctx_t *ctx;
2245 	size_t rem, insize;
2246 	const ddi_dma_cookie_t *c;
2247 	uint64_t pa, npages;
2248 
2249 	bzero(&in, sizeof (in));
2250 	bzero(&out, sizeof (out));
2251 
2252 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
2253 	VERIFY3U(mlwq->mlwq_type, ==, MLXCX_WQ_TYPE_RECVQ);
2254 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
2255 	VERIFY0(mlwq->mlwq_state & MLXCX_WQ_CREATED);
2256 
2257 	mlxcx_cmd_init(mlxp, &cmd);
2258 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_create_rq_head,
2259 	    MLXCX_OP_CREATE_RQ, 0);
2260 
2261 	ctx = &in.mlxi_create_rq_context;
2262 
2263 	set_bit32(&ctx->mlrqc_flags, MLXCX_RQ_FLAGS_RLKEY);
2264 	set_bit32(&ctx->mlrqc_flags, MLXCX_RQ_FLAGS_FLUSH_IN_ERROR);
2265 	set_bit32(&ctx->mlrqc_flags, MLXCX_RQ_FLAGS_VLAN_STRIP_DISABLE);
2266 	ctx->mlrqc_cqn = to_be24(mlwq->mlwq_cq->mlcq_num);
2267 
2268 	set_bits32(&ctx->mlrqc_wq.mlwqc_flags, MLXCX_WORKQ_CTX_TYPE,
2269 	    MLXCX_WORKQ_TYPE_CYCLIC);
2270 	ctx->mlrqc_wq.mlwqc_pd = to_be24(mlwq->mlwq_pd->mlpd_num);
2271 	ctx->mlrqc_wq.mlwqc_log_wq_sz = mlwq->mlwq_entshift;
2272 	ctx->mlrqc_wq.mlwqc_log_wq_stride = MLXCX_RECVQ_STRIDE_SHIFT;
2273 
2274 	c = mlxcx_dma_cookie_one(&mlwq->mlwq_doorbell_dma);
2275 	ctx->mlrqc_wq.mlwqc_dbr_addr = to_be64(c->dmac_laddress);
2276 	ASSERT3U(c->dmac_size, >=, sizeof (mlxcx_workq_doorbell_t));
2277 
2278 	npages = 0;
2279 	c = NULL;
2280 	while ((c = mlxcx_dma_cookie_iter(&mlwq->mlwq_dma, c)) != NULL) {
2281 		pa = c->dmac_laddress;
2282 		rem = c->dmac_size;
2283 		while (rem > 0) {
2284 			ASSERT3U(pa & 0xfff, ==, 0);
2285 			ASSERT3U(rem, >=, MLXCX_HW_PAGE_SIZE);
2286 			ctx->mlrqc_wq.mlwqc_pas[npages++] = to_be64(pa);
2287 			rem -= MLXCX_HW_PAGE_SIZE;
2288 			pa += MLXCX_HW_PAGE_SIZE;
2289 		}
2290 	}
2291 	ASSERT3U(npages, <=, MLXCX_WORKQ_CTX_MAX_ADDRESSES);
2292 
2293 	insize = offsetof(mlxcx_cmd_create_rq_in_t, mlxi_create_rq_context) +
2294 	    offsetof(mlxcx_rq_ctx_t, mlrqc_wq) +
2295 	    offsetof(mlxcx_workq_ctx_t, mlwqc_pas) +
2296 	    sizeof (uint64_t) * npages;
2297 
2298 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, insize, &out, sizeof (out))) {
2299 		mlxcx_cmd_fini(mlxp, &cmd);
2300 		return (B_FALSE);
2301 	}
2302 	mlxcx_cmd_wait(&cmd);
2303 
2304 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2305 	if (ret) {
2306 		mlwq->mlwq_state |= MLXCX_WQ_CREATED;
2307 		mlwq->mlwq_num = from_be24(out.mlxo_create_rq_rqn);
2308 	}
2309 	mlxcx_cmd_fini(mlxp, &cmd);
2310 	return (ret);
2311 }
2312 
2313 boolean_t
2314 mlxcx_cmd_start_rq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq)
2315 {
2316 	mlxcx_cmd_t cmd;
2317 	mlxcx_cmd_modify_rq_in_t in;
2318 	mlxcx_cmd_modify_rq_out_t out;
2319 	boolean_t ret;
2320 	ddi_fm_error_t err;
2321 
2322 	bzero(&in, sizeof (in));
2323 	bzero(&out, sizeof (out));
2324 
2325 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
2326 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
2327 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_CREATED);
2328 	VERIFY0(mlwq->mlwq_state & MLXCX_WQ_STARTED);
2329 
2330 	/*
2331 	 * Before starting the queue, we have to be sure that it is
2332 	 * empty and the doorbell and counters are set to 0.
2333 	 */
2334 	ASSERT(mutex_owned(&mlwq->mlwq_cq->mlcq_mtx));
2335 	ASSERT(list_is_empty(&mlwq->mlwq_cq->mlcq_buffers));
2336 	ASSERT(list_is_empty(&mlwq->mlwq_cq->mlcq_buffers_b));
2337 
2338 	mlwq->mlwq_doorbell->mlwqd_recv_counter = to_be16(0);
2339 	MLXCX_DMA_SYNC(mlwq->mlwq_doorbell_dma, DDI_DMA_SYNC_FORDEV);
2340 	ddi_fm_dma_err_get(mlwq->mlwq_doorbell_dma.mxdb_dma_handle, &err,
2341 	    DDI_FME_VERSION);
2342 	if (err.fme_status != DDI_FM_OK)
2343 		return (B_FALSE);
2344 	mlwq->mlwq_pc = 0;
2345 
2346 	mlxcx_cmd_init(mlxp, &cmd);
2347 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_modify_rq_head,
2348 	    MLXCX_OP_MODIFY_RQ, 0);
2349 
2350 	in.mlxi_modify_rq_rqn = to_be24(mlwq->mlwq_num);
2351 
2352 	/* From state */
2353 	set_bits8(&in.mlxi_modify_rq_state, MLXCX_CMD_MODIFY_RQ_STATE,
2354 	    MLXCX_RQ_STATE_RST);
2355 	/* To state */
2356 	set_bits32(&in.mlxi_modify_rq_context.mlrqc_flags, MLXCX_RQ_STATE,
2357 	    MLXCX_RQ_STATE_RDY);
2358 
2359 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2360 		mlxcx_cmd_fini(mlxp, &cmd);
2361 		return (B_FALSE);
2362 	}
2363 	mlxcx_cmd_wait(&cmd);
2364 
2365 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2366 	if (ret) {
2367 		mlwq->mlwq_state |= MLXCX_WQ_STARTED;
2368 	}
2369 	mlxcx_cmd_fini(mlxp, &cmd);
2370 	return (ret);
2371 }
2372 
2373 boolean_t
2374 mlxcx_cmd_stop_rq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq)
2375 {
2376 	mlxcx_cmd_t cmd;
2377 	mlxcx_cmd_modify_rq_in_t in;
2378 	mlxcx_cmd_modify_rq_out_t out;
2379 	boolean_t ret;
2380 
2381 	bzero(&in, sizeof (in));
2382 	bzero(&out, sizeof (out));
2383 
2384 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
2385 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
2386 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_CREATED);
2387 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_STARTED);
2388 
2389 	mlxcx_cmd_init(mlxp, &cmd);
2390 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_modify_rq_head,
2391 	    MLXCX_OP_MODIFY_RQ, 0);
2392 
2393 	in.mlxi_modify_rq_rqn = to_be24(mlwq->mlwq_num);
2394 
2395 	/* From state */
2396 	set_bits8(&in.mlxi_modify_rq_state, MLXCX_CMD_MODIFY_RQ_STATE,
2397 	    MLXCX_RQ_STATE_RDY);
2398 	/* To state */
2399 	set_bits32(&in.mlxi_modify_rq_context.mlrqc_flags, MLXCX_RQ_STATE,
2400 	    MLXCX_RQ_STATE_RST);
2401 
2402 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2403 		mlxcx_cmd_fini(mlxp, &cmd);
2404 		return (B_FALSE);
2405 	}
2406 	mlxcx_cmd_wait(&cmd);
2407 
2408 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2409 	if (ret) {
2410 		mlwq->mlwq_state &= ~MLXCX_WQ_STARTED;
2411 	}
2412 	mlxcx_cmd_fini(mlxp, &cmd);
2413 	return (ret);
2414 }
2415 
2416 boolean_t
2417 mlxcx_cmd_destroy_rq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq)
2418 {
2419 	mlxcx_cmd_t cmd;
2420 	mlxcx_cmd_destroy_rq_in_t in;
2421 	mlxcx_cmd_destroy_rq_out_t out;
2422 	boolean_t ret;
2423 
2424 	bzero(&in, sizeof (in));
2425 	bzero(&out, sizeof (out));
2426 
2427 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
2428 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
2429 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_CREATED);
2430 	VERIFY0(mlwq->mlwq_state & MLXCX_WQ_STARTED);
2431 
2432 	mlxcx_cmd_init(mlxp, &cmd);
2433 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_destroy_rq_head,
2434 	    MLXCX_OP_DESTROY_RQ, 0);
2435 
2436 	in.mlxi_destroy_rq_rqn = to_be24(mlwq->mlwq_num);
2437 
2438 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2439 		mlxcx_cmd_fini(mlxp, &cmd);
2440 		return (B_FALSE);
2441 	}
2442 	mlxcx_cmd_wait(&cmd);
2443 
2444 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2445 	if (ret) {
2446 		mlwq->mlwq_state |= MLXCX_WQ_DESTROYED;
2447 	}
2448 	mlxcx_cmd_fini(mlxp, &cmd);
2449 	return (ret);
2450 }
2451 
2452 boolean_t
2453 mlxcx_cmd_create_tir(mlxcx_t *mlxp, mlxcx_tir_t *mltir)
2454 {
2455 	mlxcx_cmd_t cmd;
2456 	mlxcx_cmd_create_tir_in_t in;
2457 	mlxcx_cmd_create_tir_out_t out;
2458 	mlxcx_tir_ctx_t *ctx;
2459 	boolean_t ret;
2460 
2461 	bzero(&in, sizeof (in));
2462 	bzero(&out, sizeof (out));
2463 
2464 	VERIFY0(mltir->mltir_state & MLXCX_TIR_CREATED);
2465 
2466 	mlxcx_cmd_init(mlxp, &cmd);
2467 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_create_tir_head,
2468 	    MLXCX_OP_CREATE_TIR, 0);
2469 
2470 	ctx = &in.mlxi_create_tir_context;
2471 	ctx->mltirc_transport_domain = to_be24(mltir->mltir_tdom->mltd_num);
2472 	set_bits8(&ctx->mltirc_disp_type, MLXCX_TIR_CTX_DISP_TYPE,
2473 	    mltir->mltir_type);
2474 	switch (mltir->mltir_type) {
2475 	case MLXCX_TIR_INDIRECT:
2476 		VERIFY(mltir->mltir_rqtable != NULL);
2477 		VERIFY(mltir->mltir_rqtable->mlrqt_state & MLXCX_RQT_CREATED);
2478 		ctx->mltirc_indirect_table =
2479 		    to_be24(mltir->mltir_rqtable->mlrqt_num);
2480 		set_bits8(&ctx->mltirc_hash_lb, MLXCX_TIR_RX_HASH_FN,
2481 		    mltir->mltir_hash_fn);
2482 		bcopy(mltir->mltir_toeplitz_key,
2483 		    ctx->mltirc_rx_hash_toeplitz_key,
2484 		    sizeof (ctx->mltirc_rx_hash_toeplitz_key));
2485 		set_bits32(&ctx->mltirc_rx_hash_fields_outer,
2486 		    MLXCX_RX_HASH_L3_TYPE, mltir->mltir_l3_type);
2487 		set_bits32(&ctx->mltirc_rx_hash_fields_outer,
2488 		    MLXCX_RX_HASH_L4_TYPE, mltir->mltir_l4_type);
2489 		set_bits32(&ctx->mltirc_rx_hash_fields_outer,
2490 		    MLXCX_RX_HASH_FIELDS, mltir->mltir_hash_fields);
2491 		break;
2492 	case MLXCX_TIR_DIRECT:
2493 		VERIFY(mltir->mltir_rq != NULL);
2494 		VERIFY(mltir->mltir_rq->mlwq_state & MLXCX_WQ_CREATED);
2495 		ctx->mltirc_inline_rqn = to_be24(mltir->mltir_rq->mlwq_num);
2496 		break;
2497 	default:
2498 		VERIFY(0);
2499 	}
2500 
2501 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2502 		mlxcx_cmd_fini(mlxp, &cmd);
2503 		return (B_FALSE);
2504 	}
2505 	mlxcx_cmd_wait(&cmd);
2506 
2507 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2508 	if (ret) {
2509 		mltir->mltir_state |= MLXCX_TIR_CREATED;
2510 		mltir->mltir_num = from_be24(out.mlxo_create_tir_tirn);
2511 	}
2512 	mlxcx_cmd_fini(mlxp, &cmd);
2513 	return (ret);
2514 }
2515 
2516 boolean_t
2517 mlxcx_cmd_destroy_tir(mlxcx_t *mlxp, mlxcx_tir_t *mltir)
2518 {
2519 	mlxcx_cmd_t cmd;
2520 	mlxcx_cmd_destroy_tir_in_t in;
2521 	mlxcx_cmd_destroy_tir_out_t out;
2522 	boolean_t ret;
2523 
2524 	bzero(&in, sizeof (in));
2525 	bzero(&out, sizeof (out));
2526 
2527 	VERIFY(mltir->mltir_state & MLXCX_TIR_CREATED);
2528 	VERIFY0(mltir->mltir_state & MLXCX_TIR_DESTROYED);
2529 
2530 	mlxcx_cmd_init(mlxp, &cmd);
2531 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_destroy_tir_head,
2532 	    MLXCX_OP_DESTROY_TIR, 0);
2533 
2534 	in.mlxi_destroy_tir_tirn = to_be24(mltir->mltir_num);
2535 
2536 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2537 		mlxcx_cmd_fini(mlxp, &cmd);
2538 		return (B_FALSE);
2539 	}
2540 	mlxcx_cmd_wait(&cmd);
2541 
2542 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2543 	if (ret) {
2544 		mltir->mltir_state |= MLXCX_TIR_DESTROYED;
2545 	}
2546 	mlxcx_cmd_fini(mlxp, &cmd);
2547 	return (ret);
2548 }
2549 
2550 boolean_t
2551 mlxcx_cmd_create_tis(mlxcx_t *mlxp, mlxcx_tis_t *mltis)
2552 {
2553 	mlxcx_cmd_t cmd;
2554 	mlxcx_cmd_create_tis_in_t in;
2555 	mlxcx_cmd_create_tis_out_t out;
2556 	mlxcx_tis_ctx_t *ctx;
2557 	boolean_t ret;
2558 
2559 	bzero(&in, sizeof (in));
2560 	bzero(&out, sizeof (out));
2561 
2562 	VERIFY0(mltis->mltis_state & MLXCX_TIS_CREATED);
2563 
2564 	mlxcx_cmd_init(mlxp, &cmd);
2565 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_create_tis_head,
2566 	    MLXCX_OP_CREATE_TIS, 0);
2567 
2568 	ctx = &in.mlxi_create_tis_context;
2569 	ctx->mltisc_transport_domain = to_be24(mltis->mltis_tdom->mltd_num);
2570 
2571 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2572 		mlxcx_cmd_fini(mlxp, &cmd);
2573 		return (B_FALSE);
2574 	}
2575 	mlxcx_cmd_wait(&cmd);
2576 
2577 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2578 	if (ret) {
2579 		mltis->mltis_state |= MLXCX_TIS_CREATED;
2580 		mltis->mltis_num = from_be24(out.mlxo_create_tis_tisn);
2581 	}
2582 	mlxcx_cmd_fini(mlxp, &cmd);
2583 	return (ret);
2584 }
2585 
2586 boolean_t
2587 mlxcx_cmd_destroy_tis(mlxcx_t *mlxp, mlxcx_tis_t *mltis)
2588 {
2589 	mlxcx_cmd_t cmd;
2590 	mlxcx_cmd_destroy_tis_in_t in;
2591 	mlxcx_cmd_destroy_tis_out_t out;
2592 	boolean_t ret;
2593 
2594 	bzero(&in, sizeof (in));
2595 	bzero(&out, sizeof (out));
2596 
2597 	VERIFY(mltis->mltis_state & MLXCX_TIR_CREATED);
2598 	VERIFY0(mltis->mltis_state & MLXCX_TIR_DESTROYED);
2599 
2600 	mlxcx_cmd_init(mlxp, &cmd);
2601 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_destroy_tis_head,
2602 	    MLXCX_OP_DESTROY_TIS, 0);
2603 
2604 	in.mlxi_destroy_tis_tisn = to_be24(mltis->mltis_num);
2605 
2606 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2607 		mlxcx_cmd_fini(mlxp, &cmd);
2608 		return (B_FALSE);
2609 	}
2610 	mlxcx_cmd_wait(&cmd);
2611 
2612 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2613 	if (ret) {
2614 		mltis->mltis_state |= MLXCX_TIS_DESTROYED;
2615 	}
2616 	mlxcx_cmd_fini(mlxp, &cmd);
2617 	return (ret);
2618 }
2619 
2620 boolean_t
2621 mlxcx_cmd_create_flow_table(mlxcx_t *mlxp, mlxcx_flow_table_t *mlft)
2622 {
2623 	mlxcx_cmd_t cmd;
2624 	mlxcx_cmd_create_flow_table_in_t in;
2625 	mlxcx_cmd_create_flow_table_out_t out;
2626 	mlxcx_flow_table_ctx_t *ctx;
2627 	boolean_t ret;
2628 
2629 	bzero(&in, sizeof (in));
2630 	bzero(&out, sizeof (out));
2631 
2632 	ASSERT(mutex_owned(&mlft->mlft_mtx));
2633 	VERIFY0(mlft->mlft_state & MLXCX_FLOW_TABLE_CREATED);
2634 
2635 	mlxcx_cmd_init(mlxp, &cmd);
2636 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_create_flow_table_head,
2637 	    MLXCX_OP_CREATE_FLOW_TABLE, 0);
2638 
2639 	in.mlxi_create_flow_table_vport_number =
2640 	    to_be16(mlft->mlft_port->mlp_num);
2641 	in.mlxi_create_flow_table_table_type = mlft->mlft_type;
2642 	ctx = &in.mlxi_create_flow_table_context;
2643 	ctx->mlftc_log_size = mlft->mlft_entshift;
2644 	ctx->mlftc_level = mlft->mlft_level;
2645 
2646 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2647 		mlxcx_cmd_fini(mlxp, &cmd);
2648 		return (B_FALSE);
2649 	}
2650 	mlxcx_cmd_wait(&cmd);
2651 
2652 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2653 	if (ret) {
2654 		mlft->mlft_num = from_be24(out.mlxo_create_flow_table_table_id);
2655 		mlft->mlft_state |= MLXCX_FLOW_TABLE_CREATED;
2656 	}
2657 	mlxcx_cmd_fini(mlxp, &cmd);
2658 	return (ret);
2659 }
2660 
2661 boolean_t
2662 mlxcx_cmd_destroy_flow_table(mlxcx_t *mlxp, mlxcx_flow_table_t *mlft)
2663 {
2664 	mlxcx_cmd_t cmd;
2665 	mlxcx_cmd_destroy_flow_table_in_t in;
2666 	mlxcx_cmd_destroy_flow_table_out_t out;
2667 	boolean_t ret;
2668 
2669 	bzero(&in, sizeof (in));
2670 	bzero(&out, sizeof (out));
2671 
2672 	ASSERT(mutex_owned(&mlft->mlft_mtx));
2673 	VERIFY(mlft->mlft_state & MLXCX_FLOW_TABLE_CREATED);
2674 	VERIFY0(mlft->mlft_state & MLXCX_FLOW_TABLE_DESTROYED);
2675 
2676 	mlxcx_cmd_init(mlxp, &cmd);
2677 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_destroy_flow_table_head,
2678 	    MLXCX_OP_DESTROY_FLOW_TABLE, 0);
2679 
2680 	in.mlxi_destroy_flow_table_vport_number =
2681 	    to_be16(mlft->mlft_port->mlp_num);
2682 	in.mlxi_destroy_flow_table_table_type = mlft->mlft_type;
2683 	in.mlxi_destroy_flow_table_table_id = to_be24(mlft->mlft_num);
2684 
2685 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2686 		mlxcx_cmd_fini(mlxp, &cmd);
2687 		return (B_FALSE);
2688 	}
2689 	mlxcx_cmd_wait(&cmd);
2690 
2691 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2692 	if (ret) {
2693 		mlft->mlft_state |= MLXCX_FLOW_TABLE_DESTROYED;
2694 	}
2695 	mlxcx_cmd_fini(mlxp, &cmd);
2696 	return (ret);
2697 }
2698 
2699 boolean_t
2700 mlxcx_cmd_set_flow_table_root(mlxcx_t *mlxp, mlxcx_flow_table_t *mlft)
2701 {
2702 	mlxcx_cmd_t cmd;
2703 	mlxcx_cmd_set_flow_table_root_in_t in;
2704 	mlxcx_cmd_set_flow_table_root_out_t out;
2705 	boolean_t ret;
2706 
2707 	bzero(&in, sizeof (in));
2708 	bzero(&out, sizeof (out));
2709 
2710 	ASSERT(mutex_owned(&mlft->mlft_mtx));
2711 	VERIFY(mlft->mlft_state & MLXCX_FLOW_TABLE_CREATED);
2712 	VERIFY0(mlft->mlft_state & MLXCX_FLOW_TABLE_DESTROYED);
2713 
2714 	mlxcx_cmd_init(mlxp, &cmd);
2715 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_set_flow_table_root_head,
2716 	    MLXCX_OP_SET_FLOW_TABLE_ROOT, 0);
2717 
2718 	in.mlxi_set_flow_table_root_vport_number =
2719 	    to_be16(mlft->mlft_port->mlp_num);
2720 	in.mlxi_set_flow_table_root_table_type = mlft->mlft_type;
2721 	in.mlxi_set_flow_table_root_table_id = to_be24(mlft->mlft_num);
2722 
2723 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2724 		mlxcx_cmd_fini(mlxp, &cmd);
2725 		return (B_FALSE);
2726 	}
2727 	mlxcx_cmd_wait(&cmd);
2728 
2729 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2730 	if (ret) {
2731 		mlft->mlft_state |= MLXCX_FLOW_TABLE_ROOT;
2732 	}
2733 	mlxcx_cmd_fini(mlxp, &cmd);
2734 	return (ret);
2735 }
2736 
2737 boolean_t
2738 mlxcx_cmd_create_flow_group(mlxcx_t *mlxp, mlxcx_flow_group_t *mlfg)
2739 {
2740 	mlxcx_cmd_t cmd;
2741 	mlxcx_cmd_create_flow_group_in_t in;
2742 	mlxcx_cmd_create_flow_group_out_t out;
2743 	boolean_t ret;
2744 	const mlxcx_flow_table_t *mlft;
2745 	mlxcx_flow_header_match_t *hdrs;
2746 	mlxcx_flow_params_match_t *params;
2747 
2748 	bzero(&in, sizeof (in));
2749 	bzero(&out, sizeof (out));
2750 
2751 	mlft = mlfg->mlfg_table;
2752 	ASSERT(mutex_owned(&mlft->mlft_mtx));
2753 	VERIFY(mlft->mlft_state & MLXCX_FLOW_TABLE_CREATED);
2754 	VERIFY0(mlft->mlft_state & MLXCX_FLOW_TABLE_DESTROYED);
2755 	VERIFY0(mlfg->mlfg_state & MLXCX_FLOW_GROUP_CREATED);
2756 
2757 	mlxcx_cmd_init(mlxp, &cmd);
2758 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_create_flow_group_head,
2759 	    MLXCX_OP_CREATE_FLOW_GROUP, 0);
2760 
2761 	in.mlxi_create_flow_group_vport_number =
2762 	    to_be16(mlft->mlft_port->mlp_num);
2763 	in.mlxi_create_flow_group_table_type = mlft->mlft_type;
2764 	in.mlxi_create_flow_group_table_id = to_be24(mlft->mlft_num);
2765 	in.mlxi_create_flow_group_start_flow_index =
2766 	    to_be32(mlfg->mlfg_start_idx);
2767 	in.mlxi_create_flow_group_end_flow_index =
2768 	    to_be32(mlfg->mlfg_start_idx + (mlfg->mlfg_size - 1));
2769 
2770 	hdrs = &in.mlxi_create_flow_group_match_criteria.mlfm_outer_headers;
2771 	params = &in.mlxi_create_flow_group_match_criteria.mlfm_misc_parameters;
2772 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_SMAC) {
2773 		in.mlxi_create_flow_group_match_criteria_en |=
2774 		    MLXCX_FLOW_GROUP_MATCH_OUTER_HDRS;
2775 		(void) memset(&hdrs->mlfh_smac, 0xff, sizeof (hdrs->mlfh_smac));
2776 	}
2777 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_DMAC) {
2778 		in.mlxi_create_flow_group_match_criteria_en |=
2779 		    MLXCX_FLOW_GROUP_MATCH_OUTER_HDRS;
2780 		(void) memset(&hdrs->mlfh_dmac, 0xff, sizeof (hdrs->mlfh_dmac));
2781 	}
2782 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_VLAN) {
2783 		in.mlxi_create_flow_group_match_criteria_en |=
2784 		    MLXCX_FLOW_GROUP_MATCH_OUTER_HDRS;
2785 		set_bit24(&hdrs->mlfh_tcp_ip_flags, MLXCX_FLOW_HDR_CVLAN_TAG);
2786 		set_bit24(&hdrs->mlfh_tcp_ip_flags, MLXCX_FLOW_HDR_SVLAN_TAG);
2787 	}
2788 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_VID) {
2789 		ASSERT(mlfg->mlfg_mask & MLXCX_FLOW_MATCH_VLAN);
2790 		set_bits16(&hdrs->mlfh_first_vid_flags,
2791 		    MLXCX_FLOW_HDR_FIRST_VID, UINT16_MAX);
2792 	}
2793 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_VER) {
2794 		in.mlxi_create_flow_group_match_criteria_en |=
2795 		    MLXCX_FLOW_GROUP_MATCH_OUTER_HDRS;
2796 		set_bits24(&hdrs->mlfh_tcp_ip_flags, MLXCX_FLOW_HDR_IP_VERSION,
2797 		    UINT32_MAX);
2798 	}
2799 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_SRCIP) {
2800 		ASSERT(mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_VER);
2801 		(void) memset(&hdrs->mlfh_src_ip, 0xff,
2802 		    sizeof (hdrs->mlfh_src_ip));
2803 	}
2804 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_DSTIP) {
2805 		ASSERT(mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_VER);
2806 		(void) memset(&hdrs->mlfh_src_ip, 0xff,
2807 		    sizeof (hdrs->mlfh_dst_ip));
2808 	}
2809 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_PROTO) {
2810 		in.mlxi_create_flow_group_match_criteria_en |=
2811 		    MLXCX_FLOW_GROUP_MATCH_OUTER_HDRS;
2812 		hdrs->mlfh_ip_protocol = UINT8_MAX;
2813 	}
2814 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_SRCIP) {
2815 		ASSERT(mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_VER);
2816 		(void) memset(&hdrs->mlfh_src_ip, 0xff,
2817 		    sizeof (hdrs->mlfh_src_ip));
2818 	}
2819 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_DSTIP) {
2820 		ASSERT(mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_VER);
2821 		(void) memset(&hdrs->mlfh_src_ip, 0xff,
2822 		    sizeof (hdrs->mlfh_dst_ip));
2823 	}
2824 
2825 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_SQN) {
2826 		in.mlxi_create_flow_group_match_criteria_en |=
2827 		    MLXCX_FLOW_GROUP_MATCH_MISC_PARAMS;
2828 		params->mlfp_source_sqn = to_be24(UINT32_MAX);
2829 	}
2830 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_VXLAN) {
2831 		in.mlxi_create_flow_group_match_criteria_en |=
2832 		    MLXCX_FLOW_GROUP_MATCH_MISC_PARAMS;
2833 		params->mlfp_vxlan_vni = to_be24(UINT32_MAX);
2834 	}
2835 
2836 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2837 		mlxcx_cmd_fini(mlxp, &cmd);
2838 		return (B_FALSE);
2839 	}
2840 	mlxcx_cmd_wait(&cmd);
2841 
2842 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2843 	if (ret) {
2844 		mlfg->mlfg_state |= MLXCX_FLOW_GROUP_CREATED;
2845 		mlfg->mlfg_num = from_be24(out.mlxo_create_flow_group_group_id);
2846 	}
2847 	mlxcx_cmd_fini(mlxp, &cmd);
2848 	return (ret);
2849 }
2850 
2851 boolean_t
2852 mlxcx_cmd_destroy_flow_group(mlxcx_t *mlxp, mlxcx_flow_group_t *mlfg)
2853 {
2854 	mlxcx_cmd_t cmd;
2855 	mlxcx_cmd_destroy_flow_group_in_t in;
2856 	mlxcx_cmd_destroy_flow_group_out_t out;
2857 	boolean_t ret;
2858 	const mlxcx_flow_table_t *mlft;
2859 
2860 	bzero(&in, sizeof (in));
2861 	bzero(&out, sizeof (out));
2862 
2863 	mlft = mlfg->mlfg_table;
2864 	ASSERT(mutex_owned(&mlft->mlft_mtx));
2865 	VERIFY(mlft->mlft_state & MLXCX_FLOW_TABLE_CREATED);
2866 	VERIFY0(mlft->mlft_state & MLXCX_FLOW_TABLE_DESTROYED);
2867 	VERIFY(mlfg->mlfg_state & MLXCX_FLOW_GROUP_CREATED);
2868 	VERIFY0(mlfg->mlfg_state & MLXCX_FLOW_GROUP_DESTROYED);
2869 
2870 	mlxcx_cmd_init(mlxp, &cmd);
2871 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_destroy_flow_group_head,
2872 	    MLXCX_OP_DESTROY_FLOW_GROUP, 0);
2873 
2874 	in.mlxi_destroy_flow_group_vport_number =
2875 	    to_be16(mlft->mlft_port->mlp_num);
2876 	in.mlxi_destroy_flow_group_table_type = mlft->mlft_type;
2877 	in.mlxi_destroy_flow_group_table_id = to_be24(mlft->mlft_num);
2878 	in.mlxi_destroy_flow_group_group_id = to_be32(mlfg->mlfg_num);
2879 
2880 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
2881 		mlxcx_cmd_fini(mlxp, &cmd);
2882 		return (B_FALSE);
2883 	}
2884 	mlxcx_cmd_wait(&cmd);
2885 
2886 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
2887 	if (ret) {
2888 		mlfg->mlfg_state |= MLXCX_FLOW_GROUP_DESTROYED;
2889 	}
2890 	mlxcx_cmd_fini(mlxp, &cmd);
2891 	return (ret);
2892 }
2893 
2894 boolean_t
2895 mlxcx_cmd_set_flow_table_entry(mlxcx_t *mlxp, mlxcx_flow_entry_t *mlfe)
2896 {
2897 	mlxcx_cmd_t cmd;
2898 	mlxcx_cmd_set_flow_table_entry_in_t in;
2899 	mlxcx_cmd_set_flow_table_entry_out_t out;
2900 	boolean_t ret;
2901 	size_t insize;
2902 	mlxcx_flow_entry_ctx_t *ctx;
2903 	const mlxcx_flow_table_t *mlft;
2904 	mlxcx_flow_group_t *mlfg;
2905 	mlxcx_flow_dest_t *d;
2906 	uint_t i;
2907 	mlxcx_flow_header_match_t *hdrs;
2908 	mlxcx_flow_params_match_t *params;
2909 	mlxcx_cmd_set_flow_table_entry_opmod_t opmod;
2910 
2911 	bzero(&in, sizeof (in));
2912 	bzero(&out, sizeof (out));
2913 
2914 	mlft = mlfe->mlfe_table;
2915 	ASSERT(mutex_owned(&mlft->mlft_mtx));
2916 	VERIFY(mlft->mlft_state & MLXCX_FLOW_TABLE_CREATED);
2917 	VERIFY0(mlft->mlft_state & MLXCX_FLOW_TABLE_DESTROYED);
2918 
2919 	mlfg = mlfe->mlfe_group;
2920 	VERIFY(mlfg->mlfg_state & MLXCX_FLOW_GROUP_CREATED);
2921 	VERIFY0(mlfg->mlfg_state & MLXCX_FLOW_GROUP_DESTROYED);
2922 
2923 	opmod = MLXCX_CMD_FLOW_ENTRY_SET_NEW;
2924 	if (mlfe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED) {
2925 		ASSERT(mlfe->mlfe_state & MLXCX_FLOW_ENTRY_DIRTY);
2926 		opmod = MLXCX_CMD_FLOW_ENTRY_MODIFY;
2927 	}
2928 
2929 	mlxcx_cmd_init(mlxp, &cmd);
2930 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_set_flow_table_entry_head,
2931 	    MLXCX_OP_SET_FLOW_TABLE_ENTRY, opmod);
2932 
2933 	in.mlxi_set_flow_table_entry_vport_number =
2934 	    to_be16(mlft->mlft_port->mlp_num);
2935 	in.mlxi_set_flow_table_entry_table_type = mlft->mlft_type;
2936 	in.mlxi_set_flow_table_entry_table_id = to_be24(mlft->mlft_num);
2937 	in.mlxi_set_flow_table_entry_flow_index = to_be32(mlfe->mlfe_index);
2938 
2939 	if (mlfe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED) {
2940 		set_bit8(&in.mlxi_set_flow_table_entry_modify_bitmask,
2941 		    MLXCX_CMD_FLOW_ENTRY_SET_ACTION);
2942 		set_bit8(&in.mlxi_set_flow_table_entry_modify_bitmask,
2943 		    MLXCX_CMD_FLOW_ENTRY_SET_DESTINATION);
2944 	}
2945 
2946 	ctx = &in.mlxi_set_flow_table_entry_context;
2947 	ctx->mlfec_group_id = to_be32(mlfg->mlfg_num);
2948 
2949 	insize = offsetof(mlxcx_cmd_set_flow_table_entry_in_t,
2950 	    mlxi_set_flow_table_entry_context) +
2951 	    offsetof(mlxcx_flow_entry_ctx_t, mlfec_destination);
2952 
2953 	ctx->mlfec_action = to_be16(mlfe->mlfe_action);
2954 
2955 	switch (mlfe->mlfe_action) {
2956 	case MLXCX_FLOW_ACTION_ALLOW:
2957 	case MLXCX_FLOW_ACTION_DROP:
2958 		break;
2959 	case MLXCX_FLOW_ACTION_FORWARD:
2960 		ASSERT3U(mlfe->mlfe_ndest, <=, MLXCX_FLOW_MAX_DESTINATIONS);
2961 		ASSERT3U(mlfe->mlfe_ndest, <=,
2962 		    mlxp->mlx_caps->mlc_max_rx_fe_dest);
2963 		ctx->mlfec_destination_list_size = to_be24(mlfe->mlfe_ndest);
2964 		for (i = 0; i < mlfe->mlfe_ndest; ++i) {
2965 			insize += sizeof (mlxcx_flow_dest_t);
2966 			d = &ctx->mlfec_destination[i];
2967 			if (mlfe->mlfe_dest[i].mlfed_tir != NULL) {
2968 				d->mlfd_destination_type = MLXCX_FLOW_DEST_TIR;
2969 				d->mlfd_destination_id = to_be24(
2970 				    mlfe->mlfe_dest[i].mlfed_tir->mltir_num);
2971 			} else if (mlfe->mlfe_dest[i].mlfed_flow != NULL) {
2972 				d->mlfd_destination_type =
2973 				    MLXCX_FLOW_DEST_FLOW_TABLE;
2974 				d->mlfd_destination_id = to_be24(
2975 				    mlfe->mlfe_dest[i].mlfed_flow->mlft_num);
2976 			} else {
2977 				/* Invalid flow entry destination */
2978 				VERIFY(0);
2979 			}
2980 		}
2981 		break;
2982 	case MLXCX_FLOW_ACTION_COUNT:
2983 		/* We don't support count actions yet. */
2984 		VERIFY(0);
2985 		break;
2986 	case MLXCX_FLOW_ACTION_ENCAP:
2987 	case MLXCX_FLOW_ACTION_DECAP:
2988 		/* We don't support encap/decap actions yet. */
2989 		VERIFY(0);
2990 		break;
2991 	}
2992 
2993 	hdrs = &ctx->mlfec_match_value.mlfm_outer_headers;
2994 	params = &ctx->mlfec_match_value.mlfm_misc_parameters;
2995 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_SMAC) {
2996 		bcopy(mlfe->mlfe_smac, hdrs->mlfh_smac,
2997 		    sizeof (hdrs->mlfh_smac));
2998 	}
2999 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_DMAC) {
3000 		bcopy(mlfe->mlfe_dmac, hdrs->mlfh_dmac,
3001 		    sizeof (hdrs->mlfh_dmac));
3002 	}
3003 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_VLAN) {
3004 		switch (mlfe->mlfe_vlan_type) {
3005 		case MLXCX_VLAN_TYPE_CVLAN:
3006 			set_bit24(&hdrs->mlfh_tcp_ip_flags,
3007 			    MLXCX_FLOW_HDR_CVLAN_TAG);
3008 			break;
3009 		case MLXCX_VLAN_TYPE_SVLAN:
3010 			set_bit24(&hdrs->mlfh_tcp_ip_flags,
3011 			    MLXCX_FLOW_HDR_SVLAN_TAG);
3012 			break;
3013 		default:
3014 			break;
3015 		}
3016 	}
3017 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_VID) {
3018 		ASSERT(mlfg->mlfg_mask & MLXCX_FLOW_MATCH_VLAN);
3019 		set_bits16(&hdrs->mlfh_first_vid_flags,
3020 		    MLXCX_FLOW_HDR_FIRST_VID, mlfe->mlfe_vid);
3021 	}
3022 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_VER) {
3023 		set_bits24(&hdrs->mlfh_tcp_ip_flags, MLXCX_FLOW_HDR_IP_VERSION,
3024 		    mlfe->mlfe_ip_version);
3025 	}
3026 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_SRCIP) {
3027 		ASSERT(mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_VER);
3028 		bcopy(mlfe->mlfe_srcip, hdrs->mlfh_src_ip,
3029 		    sizeof (hdrs->mlfh_src_ip));
3030 	}
3031 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_DSTIP) {
3032 		ASSERT(mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_VER);
3033 		bcopy(mlfe->mlfe_dstip, hdrs->mlfh_src_ip,
3034 		    sizeof (hdrs->mlfh_dst_ip));
3035 	}
3036 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_IP_PROTO) {
3037 		hdrs->mlfh_ip_protocol = mlfe->mlfe_ip_proto;
3038 	}
3039 
3040 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_SQN) {
3041 		params->mlfp_source_sqn = to_be24(mlfe->mlfe_sqn);
3042 	}
3043 	if (mlfg->mlfg_mask & MLXCX_FLOW_MATCH_VXLAN) {
3044 		params->mlfp_vxlan_vni = to_be24(mlfe->mlfe_vxlan_vni);
3045 	}
3046 
3047 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, insize, &out, sizeof (out))) {
3048 		mlxcx_cmd_fini(mlxp, &cmd);
3049 		return (B_FALSE);
3050 	}
3051 	mlxcx_cmd_wait(&cmd);
3052 
3053 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
3054 	if (ret) {
3055 		mlfe->mlfe_state |= MLXCX_FLOW_ENTRY_CREATED;
3056 		mlfe->mlfe_state &= ~MLXCX_FLOW_ENTRY_DIRTY;
3057 		mlfg->mlfg_state |= MLXCX_FLOW_GROUP_BUSY;
3058 	}
3059 	mlxcx_cmd_fini(mlxp, &cmd);
3060 	return (ret);
3061 }
3062 
3063 boolean_t
3064 mlxcx_cmd_delete_flow_table_entry(mlxcx_t *mlxp, mlxcx_flow_entry_t *mlfe)
3065 {
3066 	mlxcx_cmd_t cmd;
3067 	mlxcx_cmd_delete_flow_table_entry_in_t in;
3068 	mlxcx_cmd_delete_flow_table_entry_out_t out;
3069 	boolean_t ret;
3070 	const mlxcx_flow_table_t *mlft;
3071 
3072 	bzero(&in, sizeof (in));
3073 	bzero(&out, sizeof (out));
3074 
3075 	mlft = mlfe->mlfe_table;
3076 	ASSERT(mutex_owned(&mlft->mlft_mtx));
3077 	VERIFY(mlft->mlft_state & MLXCX_FLOW_TABLE_CREATED);
3078 	VERIFY0(mlft->mlft_state & MLXCX_FLOW_TABLE_DESTROYED);
3079 
3080 	mlxcx_cmd_init(mlxp, &cmd);
3081 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_delete_flow_table_entry_head,
3082 	    MLXCX_OP_DELETE_FLOW_TABLE_ENTRY, 0);
3083 
3084 	in.mlxi_delete_flow_table_entry_vport_number =
3085 	    to_be16(mlft->mlft_port->mlp_num);
3086 	in.mlxi_delete_flow_table_entry_table_type = mlft->mlft_type;
3087 	in.mlxi_delete_flow_table_entry_table_id = to_be24(mlft->mlft_num);
3088 	in.mlxi_delete_flow_table_entry_flow_index = to_be32(mlfe->mlfe_index);
3089 
3090 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
3091 		mlxcx_cmd_fini(mlxp, &cmd);
3092 		return (B_FALSE);
3093 	}
3094 	mlxcx_cmd_wait(&cmd);
3095 
3096 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
3097 	if (ret) {
3098 		/*
3099 		 * Note that flow entries have a different lifecycle to most
3100 		 * other things we create -- we have to be able to re-use them
3101 		 * after they have been deleted, since they exist at a fixed
3102 		 * position in their flow table.
3103 		 *
3104 		 * So we clear the CREATED bit here for them to let us call
3105 		 * create_flow_table_entry() on the same entry again later.
3106 		 */
3107 		mlfe->mlfe_state &= ~MLXCX_FLOW_ENTRY_CREATED;
3108 		mlfe->mlfe_state |= MLXCX_FLOW_ENTRY_DELETED;
3109 	}
3110 	mlxcx_cmd_fini(mlxp, &cmd);
3111 	return (ret);
3112 }
3113 
3114 boolean_t
3115 mlxcx_cmd_create_sq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq)
3116 {
3117 	mlxcx_cmd_t cmd;
3118 	mlxcx_cmd_create_sq_in_t in;
3119 	mlxcx_cmd_create_sq_out_t out;
3120 	boolean_t ret;
3121 	mlxcx_sq_ctx_t *ctx;
3122 	size_t rem, insize;
3123 	const ddi_dma_cookie_t *c;
3124 	uint64_t pa, npages;
3125 
3126 	bzero(&in, sizeof (in));
3127 	bzero(&out, sizeof (out));
3128 
3129 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
3130 	VERIFY3U(mlwq->mlwq_type, ==, MLXCX_WQ_TYPE_SENDQ);
3131 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
3132 	VERIFY0(mlwq->mlwq_state & MLXCX_WQ_CREATED);
3133 
3134 	mlxcx_cmd_init(mlxp, &cmd);
3135 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_create_sq_head,
3136 	    MLXCX_OP_CREATE_SQ, 0);
3137 
3138 	ctx = &in.mlxi_create_sq_context;
3139 
3140 	set_bit32(&ctx->mlsqc_flags, MLXCX_SQ_FLAGS_RLKEY);
3141 	set_bit32(&ctx->mlsqc_flags, MLXCX_SQ_FLAGS_FLUSH_IN_ERROR);
3142 	set_bits32(&ctx->mlsqc_flags, MLXCX_SQ_MIN_WQE_INLINE,
3143 	    mlwq->mlwq_inline_mode);
3144 	ctx->mlsqc_cqn = to_be24(mlwq->mlwq_cq->mlcq_num);
3145 
3146 	VERIFY(mlwq->mlwq_tis != NULL);
3147 	ctx->mlsqc_tis_lst_sz = to_be16(1);
3148 	ctx->mlsqc_tis_num = to_be24(mlwq->mlwq_tis->mltis_num);
3149 
3150 	set_bits32(&ctx->mlsqc_wq.mlwqc_flags, MLXCX_WORKQ_CTX_TYPE,
3151 	    MLXCX_WORKQ_TYPE_CYCLIC);
3152 	ctx->mlsqc_wq.mlwqc_pd = to_be24(mlwq->mlwq_pd->mlpd_num);
3153 	ctx->mlsqc_wq.mlwqc_uar_page = to_be24(mlwq->mlwq_uar->mlu_num);
3154 	ctx->mlsqc_wq.mlwqc_log_wq_sz = mlwq->mlwq_entshift;
3155 	ctx->mlsqc_wq.mlwqc_log_wq_stride = MLXCX_SENDQ_STRIDE_SHIFT;
3156 
3157 	c = mlxcx_dma_cookie_one(&mlwq->mlwq_doorbell_dma);
3158 	ctx->mlsqc_wq.mlwqc_dbr_addr = to_be64(c->dmac_laddress);
3159 	ASSERT3U(c->dmac_size, >=, sizeof (mlxcx_workq_doorbell_t));
3160 
3161 	npages = 0;
3162 	c = NULL;
3163 	while ((c = mlxcx_dma_cookie_iter(&mlwq->mlwq_dma, c)) != NULL) {
3164 		pa = c->dmac_laddress;
3165 		rem = c->dmac_size;
3166 		while (rem > 0) {
3167 			ASSERT3U(pa & 0xfff, ==, 0);
3168 			ASSERT3U(rem, >=, MLXCX_HW_PAGE_SIZE);
3169 			ctx->mlsqc_wq.mlwqc_pas[npages++] = to_be64(pa);
3170 			rem -= MLXCX_HW_PAGE_SIZE;
3171 			pa += MLXCX_HW_PAGE_SIZE;
3172 		}
3173 	}
3174 	ASSERT3U(npages, <=, MLXCX_WORKQ_CTX_MAX_ADDRESSES);
3175 
3176 	insize = offsetof(mlxcx_cmd_create_sq_in_t, mlxi_create_sq_context) +
3177 	    offsetof(mlxcx_sq_ctx_t, mlsqc_wq) +
3178 	    offsetof(mlxcx_workq_ctx_t, mlwqc_pas) +
3179 	    sizeof (uint64_t) * npages;
3180 
3181 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, insize, &out, sizeof (out))) {
3182 		mlxcx_cmd_fini(mlxp, &cmd);
3183 		return (B_FALSE);
3184 	}
3185 	mlxcx_cmd_wait(&cmd);
3186 
3187 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
3188 	if (ret) {
3189 		mlwq->mlwq_state |= MLXCX_WQ_CREATED;
3190 		mlwq->mlwq_num = from_be24(out.mlxo_create_sq_sqn);
3191 	}
3192 	mlxcx_cmd_fini(mlxp, &cmd);
3193 	return (ret);
3194 }
3195 
3196 boolean_t
3197 mlxcx_cmd_start_sq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq)
3198 {
3199 	mlxcx_cmd_t cmd;
3200 	mlxcx_cmd_modify_sq_in_t in;
3201 	mlxcx_cmd_modify_sq_out_t out;
3202 	boolean_t ret;
3203 	ddi_fm_error_t err;
3204 
3205 	bzero(&in, sizeof (in));
3206 	bzero(&out, sizeof (out));
3207 
3208 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
3209 	ASSERT(mlwq->mlwq_cq != NULL);
3210 
3211 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
3212 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_CREATED);
3213 	VERIFY0(mlwq->mlwq_state & MLXCX_WQ_STARTED);
3214 
3215 	/*
3216 	 * Before starting the queue, we have to be sure that it is
3217 	 * empty and the doorbell and counters are set to 0.
3218 	 */
3219 	ASSERT(mutex_owned(&mlwq->mlwq_cq->mlcq_mtx));
3220 	ASSERT(list_is_empty(&mlwq->mlwq_cq->mlcq_buffers));
3221 	ASSERT(list_is_empty(&mlwq->mlwq_cq->mlcq_buffers_b));
3222 
3223 	mlwq->mlwq_doorbell->mlwqd_recv_counter = to_be16(0);
3224 	MLXCX_DMA_SYNC(mlwq->mlwq_doorbell_dma, DDI_DMA_SYNC_FORDEV);
3225 	ddi_fm_dma_err_get(mlwq->mlwq_doorbell_dma.mxdb_dma_handle, &err,
3226 	    DDI_FME_VERSION);
3227 	if (err.fme_status != DDI_FM_OK)
3228 		return (B_FALSE);
3229 	mlwq->mlwq_pc = 0;
3230 
3231 	mlxcx_cmd_init(mlxp, &cmd);
3232 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_modify_sq_head,
3233 	    MLXCX_OP_MODIFY_SQ, 0);
3234 
3235 	in.mlxi_modify_sq_sqn = to_be24(mlwq->mlwq_num);
3236 
3237 	/* From state */
3238 	set_bits8(&in.mlxi_modify_sq_state, MLXCX_CMD_MODIFY_SQ_STATE,
3239 	    MLXCX_SQ_STATE_RST);
3240 	/* To state */
3241 	set_bits32(&in.mlxi_modify_sq_context.mlsqc_flags, MLXCX_SQ_STATE,
3242 	    MLXCX_SQ_STATE_RDY);
3243 
3244 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
3245 		mlxcx_cmd_fini(mlxp, &cmd);
3246 		return (B_FALSE);
3247 	}
3248 	mlxcx_cmd_wait(&cmd);
3249 
3250 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
3251 	if (ret) {
3252 		mlwq->mlwq_state |= MLXCX_WQ_STARTED;
3253 	}
3254 	mlxcx_cmd_fini(mlxp, &cmd);
3255 	return (ret);
3256 }
3257 
3258 boolean_t
3259 mlxcx_cmd_stop_sq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq)
3260 {
3261 	mlxcx_cmd_t cmd;
3262 	mlxcx_cmd_modify_sq_in_t in;
3263 	mlxcx_cmd_modify_sq_out_t out;
3264 	boolean_t ret;
3265 
3266 	bzero(&in, sizeof (in));
3267 	bzero(&out, sizeof (out));
3268 
3269 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
3270 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
3271 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_CREATED);
3272 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_STARTED);
3273 
3274 	mlxcx_cmd_init(mlxp, &cmd);
3275 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_modify_sq_head,
3276 	    MLXCX_OP_MODIFY_SQ, 0);
3277 
3278 	in.mlxi_modify_sq_sqn = to_be24(mlwq->mlwq_num);
3279 
3280 	/* From state */
3281 	set_bits8(&in.mlxi_modify_sq_state, MLXCX_CMD_MODIFY_SQ_STATE,
3282 	    MLXCX_SQ_STATE_RDY);
3283 	/* To state */
3284 	set_bits32(&in.mlxi_modify_sq_context.mlsqc_flags, MLXCX_SQ_STATE,
3285 	    MLXCX_SQ_STATE_RST);
3286 
3287 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
3288 		mlxcx_cmd_fini(mlxp, &cmd);
3289 		return (B_FALSE);
3290 	}
3291 	mlxcx_cmd_wait(&cmd);
3292 
3293 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
3294 	if (ret) {
3295 		mlwq->mlwq_state &= ~MLXCX_WQ_STARTED;
3296 	}
3297 	mlxcx_cmd_fini(mlxp, &cmd);
3298 	return (ret);
3299 }
3300 
3301 boolean_t
3302 mlxcx_cmd_destroy_sq(mlxcx_t *mlxp, mlxcx_work_queue_t *mlwq)
3303 {
3304 	mlxcx_cmd_t cmd;
3305 	mlxcx_cmd_destroy_sq_in_t in;
3306 	mlxcx_cmd_destroy_sq_out_t out;
3307 	boolean_t ret;
3308 
3309 	bzero(&in, sizeof (in));
3310 	bzero(&out, sizeof (out));
3311 
3312 	ASSERT(mutex_owned(&mlwq->mlwq_mtx));
3313 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_ALLOC);
3314 	VERIFY(mlwq->mlwq_state & MLXCX_WQ_CREATED);
3315 	VERIFY0(mlwq->mlwq_state & MLXCX_WQ_STARTED);
3316 
3317 	mlxcx_cmd_init(mlxp, &cmd);
3318 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_destroy_sq_head,
3319 	    MLXCX_OP_DESTROY_SQ, 0);
3320 
3321 	in.mlxi_destroy_sq_sqn = to_be24(mlwq->mlwq_num);
3322 
3323 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
3324 		mlxcx_cmd_fini(mlxp, &cmd);
3325 		return (B_FALSE);
3326 	}
3327 	mlxcx_cmd_wait(&cmd);
3328 
3329 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
3330 	if (ret) {
3331 		mlwq->mlwq_state |= MLXCX_WQ_DESTROYED;
3332 	}
3333 	mlxcx_cmd_fini(mlxp, &cmd);
3334 	return (ret);
3335 }
3336 
3337 boolean_t
3338 mlxcx_cmd_create_rqt(mlxcx_t *mlxp, mlxcx_rqtable_t *mlrqt)
3339 {
3340 	mlxcx_cmd_t cmd;
3341 	mlxcx_cmd_create_rqt_in_t in;
3342 	mlxcx_cmd_create_rqt_out_t out;
3343 	mlxcx_rqtable_ctx_t *ctx;
3344 	boolean_t ret;
3345 	uint_t i;
3346 
3347 	bzero(&in, sizeof (in));
3348 	bzero(&out, sizeof (out));
3349 
3350 	VERIFY0(mlrqt->mlrqt_state & MLXCX_RQT_CREATED);
3351 
3352 	mlxcx_cmd_init(mlxp, &cmd);
3353 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_create_rqt_head,
3354 	    MLXCX_OP_CREATE_RQT, 0);
3355 
3356 	ctx = &in.mlxi_create_rqt_context;
3357 	ASSERT3U(mlrqt->mlrqt_max, <=, MLXCX_RQT_MAX_RQ_REFS);
3358 	ASSERT3U(mlrqt->mlrqt_max, <=, mlxp->mlx_caps->mlc_max_rqt_size);
3359 	ctx->mlrqtc_max_size = to_be16(mlrqt->mlrqt_max);
3360 	ctx->mlrqtc_actual_size = to_be16(mlrqt->mlrqt_used);
3361 	for (i = 0; i < mlrqt->mlrqt_used; ++i) {
3362 		ctx->mlrqtc_rqref[i].mlrqtr_rqn = to_be24(
3363 		    mlrqt->mlrqt_rq[i]->mlwq_num);
3364 	}
3365 
3366 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
3367 		mlxcx_cmd_fini(mlxp, &cmd);
3368 		return (B_FALSE);
3369 	}
3370 	mlxcx_cmd_wait(&cmd);
3371 
3372 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
3373 	if (ret) {
3374 		mlrqt->mlrqt_num = from_be24(out.mlxo_create_rqt_rqtn);
3375 		mlrqt->mlrqt_state |= MLXCX_RQT_CREATED;
3376 		mlrqt->mlrqt_state &= ~MLXCX_RQT_DIRTY;
3377 	}
3378 	mlxcx_cmd_fini(mlxp, &cmd);
3379 	return (ret);
3380 }
3381 
3382 boolean_t
3383 mlxcx_cmd_destroy_rqt(mlxcx_t *mlxp, mlxcx_rqtable_t *mlrqt)
3384 {
3385 	mlxcx_cmd_t cmd;
3386 	mlxcx_cmd_destroy_rqt_in_t in;
3387 	mlxcx_cmd_destroy_rqt_out_t out;
3388 	boolean_t ret;
3389 
3390 	bzero(&in, sizeof (in));
3391 	bzero(&out, sizeof (out));
3392 
3393 	VERIFY(mlrqt->mlrqt_state & MLXCX_RQT_CREATED);
3394 	VERIFY0(mlrqt->mlrqt_state & MLXCX_RQT_DESTROYED);
3395 
3396 	mlxcx_cmd_init(mlxp, &cmd);
3397 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_destroy_rqt_head,
3398 	    MLXCX_OP_DESTROY_RQT, 0);
3399 
3400 	in.mlxi_destroy_rqt_rqtn = to_be24(mlrqt->mlrqt_num);
3401 
3402 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
3403 		mlxcx_cmd_fini(mlxp, &cmd);
3404 		return (B_FALSE);
3405 	}
3406 	mlxcx_cmd_wait(&cmd);
3407 
3408 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
3409 	if (ret) {
3410 		mlrqt->mlrqt_state |= MLXCX_RQT_DESTROYED;
3411 	}
3412 	mlxcx_cmd_fini(mlxp, &cmd);
3413 	return (ret);
3414 }
3415 
3416 boolean_t
3417 mlxcx_cmd_set_int_mod(mlxcx_t *mlxp, uint_t intr, uint_t min_delay)
3418 {
3419 	mlxcx_cmd_t cmd;
3420 	mlxcx_cmd_config_int_mod_in_t in;
3421 	mlxcx_cmd_config_int_mod_out_t out;
3422 	boolean_t ret;
3423 
3424 	bzero(&in, sizeof (in));
3425 	bzero(&out, sizeof (out));
3426 
3427 	mlxcx_cmd_init(mlxp, &cmd);
3428 	mlxcx_cmd_in_header_init(&cmd, &in.mlxi_config_int_mod_head,
3429 	    MLXCX_OP_CONFIG_INT_MODERATION, MLXCX_CMD_CONFIG_INT_MOD_WRITE);
3430 
3431 	in.mlxi_config_int_mod_int_vector = to_be16(intr);
3432 	in.mlxi_config_int_mod_min_delay = to_be16(min_delay);
3433 
3434 	if (!mlxcx_cmd_send(mlxp, &cmd, &in, sizeof (in), &out, sizeof (out))) {
3435 		mlxcx_cmd_fini(mlxp, &cmd);
3436 		return (B_FALSE);
3437 	}
3438 	mlxcx_cmd_wait(&cmd);
3439 
3440 	ret = mlxcx_cmd_evaluate(mlxp, &cmd);
3441 	mlxcx_cmd_fini(mlxp, &cmd);
3442 	return (ret);
3443 }
3444 
3445 /*
3446  * CTASSERTs here are for the structs in mlxcx_reg.h, to check they match
3447  * against offsets from the PRM.
3448  *
3449  * They're not in the header file, to avoid them being used by multiple .c
3450  * files.
3451  */
3452 
3453 CTASSERT(offsetof(mlxcx_eventq_ent_t, mleqe_unknown_data) == 0x20);
3454 CTASSERT(offsetof(mlxcx_eventq_ent_t, mleqe_signature) == 0x3c + 2);
3455 CTASSERT(sizeof (mlxcx_eventq_ent_t) == 64);
3456 
3457 CTASSERT(offsetof(mlxcx_completionq_error_ent_t, mlcqee_byte_cnt) == 0x2C);
3458 CTASSERT(offsetof(mlxcx_completionq_error_ent_t, mlcqee_wqe_opcode) == 0x38);
3459 
3460 CTASSERT(sizeof (mlxcx_completionq_error_ent_t) ==
3461     sizeof (mlxcx_completionq_ent_t));
3462 CTASSERT(sizeof (mlxcx_wqe_control_seg_t) == (1 << 4));
3463 
3464 CTASSERT(offsetof(mlxcx_wqe_eth_seg_t, mles_inline_headers) == 0x0e);
3465 CTASSERT(sizeof (mlxcx_wqe_eth_seg_t) == (1 << 5));
3466 
3467 CTASSERT(sizeof (mlxcx_wqe_data_seg_t) == (1 << 4));
3468 
3469 CTASSERT(sizeof (mlxcx_sendq_ent_t) == (1 << MLXCX_SENDQ_STRIDE_SHIFT));
3470 
3471 CTASSERT(sizeof (mlxcx_sendq_bf_t) == (1 << MLXCX_SENDQ_STRIDE_SHIFT));
3472 
3473 CTASSERT(sizeof (mlxcx_sendq_extra_ent_t) == (1 << MLXCX_SENDQ_STRIDE_SHIFT));
3474 
3475 CTASSERT(sizeof (mlxcx_recvq_ent_t) == (1 << MLXCX_RECVQ_STRIDE_SHIFT));
3476 
3477 CTASSERT(offsetof(mlxcx_workq_ctx_t, mlwqc_dbr_addr) == 0x10);
3478 CTASSERT(offsetof(mlxcx_workq_ctx_t, mlwqc_pas) == 0xc0);
3479 
3480 CTASSERT(offsetof(mlxcx_rq_ctx_t, mlrqc_cqn) == 0x09);
3481 CTASSERT(offsetof(mlxcx_rq_ctx_t, mlrqc_wq) == 0x30);
3482 
3483 CTASSERT(offsetof(mlxcx_sq_ctx_t, mlsqc_cqn) == 0x09);
3484 CTASSERT(offsetof(mlxcx_sq_ctx_t, mlsqc_tis_lst_sz) == 0x20);
3485 CTASSERT(offsetof(mlxcx_sq_ctx_t, mlsqc_tis_num) == 0x2d);
3486 CTASSERT(offsetof(mlxcx_sq_ctx_t, mlsqc_wq) == 0x30);
3487 
3488 CTASSERT(sizeof (mlxcx_tis_ctx_t) == 0xa0);
3489 CTASSERT(offsetof(mlxcx_tis_ctx_t, mltisc_transport_domain) == 0x25);
3490 
3491 CTASSERT(offsetof(mlxcx_rqtable_ctx_t, mlrqtc_max_size) == 0x16);
3492 CTASSERT(offsetof(mlxcx_rqtable_ctx_t, mlrqtc_rqref) == 0xF0);
3493 
3494 CTASSERT(offsetof(mlxcx_cmd_create_eq_in_t, mlxi_create_eq_event_bitmask) ==
3495     0x58);
3496 CTASSERT(offsetof(mlxcx_cmd_create_eq_in_t, mlxi_create_eq_pas) == 0x110);
3497 CTASSERT(offsetof(mlxcx_cmd_create_eq_in_t, mlxi_create_eq_context) == 0x10);
3498 
3499 CTASSERT(offsetof(mlxcx_cmd_create_tir_in_t, mlxi_create_tir_context) == 0x20);
3500 
3501 CTASSERT(offsetof(mlxcx_cmd_create_tis_in_t, mlxi_create_tis_context) == 0x20);
3502 
3503 CTASSERT(offsetof(mlxcx_cmd_query_special_ctxs_out_t,
3504     mlxo_query_special_ctxs_resd_lkey) == 0x0c);
3505 
3506 CTASSERT(offsetof(mlxcx_cmd_query_cq_out_t, mlxo_query_cq_context) == 0x10);
3507 CTASSERT(offsetof(mlxcx_cmd_query_cq_out_t, mlxo_query_cq_pas) == 0x110);
3508 
3509 CTASSERT(offsetof(mlxcx_cmd_query_rq_out_t, mlxo_query_rq_context) == 0x20);
3510 
3511 CTASSERT(offsetof(mlxcx_cmd_create_sq_in_t, mlxi_create_sq_context) == 0x20);
3512 
3513 CTASSERT(offsetof(mlxcx_cmd_modify_sq_in_t, mlxi_modify_sq_context) == 0x20);
3514 
3515 CTASSERT(offsetof(mlxcx_cmd_query_sq_out_t, mlxo_query_sq_context) == 0x20);
3516 
3517 CTASSERT(offsetof(mlxcx_cmd_create_rqt_in_t, mlxi_create_rqt_context) == 0x20);
3518 
3519 CTASSERT(offsetof(mlxcx_reg_pmtu_t, mlrd_pmtu_oper_mtu) == 0x0C);
3520 
3521 CTASSERT(sizeof (mlxcx_reg_ptys_t) == 64);
3522 CTASSERT(offsetof(mlxcx_reg_ptys_t, mlrd_ptys_proto_cap) == 0x0c);
3523 CTASSERT(offsetof(mlxcx_reg_ptys_t, mlrd_ptys_proto_admin) == 0x18);
3524 CTASSERT(offsetof(mlxcx_reg_ptys_t, mlrd_ptys_proto_partner_advert) == 0x30);
3525 
3526 CTASSERT(offsetof(mlxcx_reg_mcia_t, mlrd_mcia_data) == 0x10);
3527 
3528 CTASSERT(offsetof(mlxcx_ppcnt_ieee_802_3_t,
3529     mlppc_ieee_802_3_in_range_len_err) == 0x50);
3530 CTASSERT(offsetof(mlxcx_ppcnt_ieee_802_3_t,
3531     mlppc_ieee_802_3_pause_tx) == 0x90);
3532 
3533 CTASSERT(sizeof (mlxcx_reg_ppcnt_t) == 256);
3534 CTASSERT(offsetof(mlxcx_reg_ppcnt_t, mlrd_ppcnt_data) == 0x08);
3535 
3536 CTASSERT(offsetof(mlxcx_cmd_access_register_in_t,
3537     mlxi_access_register_argument) == 0x0C);
3538 CTASSERT(offsetof(mlxcx_cmd_access_register_in_t,
3539     mlxi_access_register_data) == 0x10);
3540 
3541 CTASSERT(offsetof(mlxcx_cmd_access_register_out_t,
3542     mlxo_access_register_data) == 0x10);
3543