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