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