xref: /freebsd/sys/dev/bnxt/bnxt_en/bnxt_mgmt.c (revision 9d87ca8b9f60bdec0bbc1733920df250a08beb0c)
1 /*
2  * Broadcom NetXtreme-C/E network driver.
3  *
4  * Copyright (c) 2022 Broadcom, All Rights Reserved.
5  * The term Broadcom refers to Broadcom Limited and/or its subsidiaries
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "bnxt_mgmt.h"
30 #include "bnxt.h"
31 #include "bnxt_hwrm.h"
32 #include "bnxt_coredump.h"
33 #include "bnxt_log.h"
34 #include <dev/pci/pcireg.h>
35 #include <dev/pci/pcivar.h>
36 #include <sys/endian.h>
37 #include <sys/lock.h>
38 
39 /* Function prototypes */
40 static d_open_t      bnxt_mgmt_open;
41 static d_close_t     bnxt_mgmt_close;
42 static d_ioctl_t     bnxt_mgmt_ioctl;
43 
44 /* Character device entry points */
45 static struct cdevsw bnxt_mgmt_cdevsw = {
46 	.d_version = D_VERSION,
47 	.d_open = bnxt_mgmt_open,
48 	.d_close = bnxt_mgmt_close,
49 	.d_ioctl = bnxt_mgmt_ioctl,
50 	.d_name = "bnxt_mgmt",
51 };
52 
53 /* Global vars */
54 static struct cdev *bnxt_mgmt_dev;
55 struct sx	mgmt_lock;
56 
57 MALLOC_DEFINE(M_BNXT, "bnxt_mgmt_buffer", "buffer for bnxt_mgmt module");
58 
59 
60 static uint32_t
61 bnxt_get_driver_coredump_len(struct bnxt_softc *softc)
62 {
63 
64 	uint32_t type, i, j, n;
65 	uint32_t buf_size = 0;
66 	int ctx_page_count = 0;
67 	int segment_len = 0;
68 	int driver_segment_record_len = 0;
69 	uint32_t dump_len = 0;
70 	int record_len = sizeof(struct bnxt_driver_segment_record);
71 	struct bnxt_ctx_mem_info *ctx = softc->ctx_mem;
72 
73 	if (!ctx)
74 		return (dump_len);
75 
76 	for (type = BNXT_CTX_SRT_TRACE; type <= BNXT_CTX_ROCE_HWRM_TRACE;
77 	     type++) {
78 		struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
79 		struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info;
80 
81 		if (!ctx_pg)
82 			continue;
83 
84 		if (ctxm->instance_bmap)
85 			n = bitcount32(ctxm->instance_bmap);
86 		else
87 			n = 1;
88 
89 		for (i = 0; i < n; i++) {
90 			struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem;
91 
92 			if (ctx_pg->nr_pages > MAX_CTX_PAGES ||
93 			    ctx_pg->ctx_pg_tbl) {
94 				int k = 0, nr_tbls = rmem->nr_pages;
95 
96 				for (k = 0; k < nr_tbls; k++) {
97 					struct bnxt_ctx_pg_info *pg_tbl;
98 					struct bnxt_ring_mem_info *rmem2;
99 
100 					pg_tbl = ctx_pg->ctx_pg_tbl[k];
101 					if (!pg_tbl)
102 						continue;
103 					rmem2 = &pg_tbl->ring_mem;
104 					for (j = 0; j < rmem2->nr_pages; j++) {
105 						if (!rmem2->pg_arr[j].idi_vaddr)
106 							continue;
107 						ctx_page_count++;
108 					}
109 				}
110 			} else {
111 				struct bnxt_ring_mem_info *rmem2 = rmem;
112 
113 				for (j = 0; j < rmem2->nr_pages; j++) {
114 					if (!rmem2->pg_arr[j].idi_vaddr)
115 						continue;
116 					ctx_page_count++;
117 				}
118 			}
119 		}
120 		segment_len += 64;
121 		driver_segment_record_len += record_len;
122 	}
123 
124 	buf_size = driver_segment_record_len + segment_len +
125 	    (ctx_page_count * 4096);
126 
127 	return (buf_size);
128 }
129 
130 inline void
131 bnxt_bs_trace_check_wrapping(struct bnxt_bs_trace_info *bs_trace,
132     u32 offset)
133 {
134         if (!bs_trace->wrapped &&
135             *bs_trace->magic_byte != BNXT_TRACE_BUF_MAGIC_BYTE)
136                 bs_trace->wrapped = 1;
137         bs_trace->last_offset = offset;
138 }
139 
140 
141 
142 static int
143 bnxt_hwrm_dbg_log_buffer_flush(struct bnxt_softc *bp, u16 type, u32 flags,
144     u32 *offset)
145 {
146         int  status = 0;
147 
148         hwrm_dbg_log_buffer_flush_input_t buff_flush_req;
149         hwrm_dbg_log_buffer_flush_output_t *buff_flush_resp =
150             (hwrm_dbg_log_buffer_flush_output_t *)(void *)
151             bp->hwrm_cmd_resp.idi_vaddr;
152         bnxt_hwrm_cmd_hdr_init(bp, &buff_flush_req, HWRM_DBG_LOG_BUFFER_FLUSH);
153         buff_flush_req.type = type;
154         buff_flush_req.flags = flags;
155 
156         status = hwrm_send_message(bp, &buff_flush_req, sizeof(buff_flush_req));
157         if (!status)
158                 *offset = buff_flush_resp->current_buffer_offset;
159         return (status);
160 }
161 
162 static void
163 bnxt_fill_driver_segment_record(struct bnxt_softc *bp,
164     struct bnxt_driver_segment_record *drv_seg_rec,
165     struct bnxt_ctx_mem_type *ctxm, uint16_t type)
166 {
167         struct bnxt_bs_trace_info *bs_trace = &bp->bs_trace[type];
168         uint32_t offset;
169 
170         if (bnxt_hwrm_dbg_log_buffer_flush(bp, type, 0, &offset) == 0) {
171                 bnxt_bs_trace_check_wrapping(bs_trace, offset);
172         }
173         drv_seg_rec->max_entries = ctxm->max_entries;
174         drv_seg_rec->entry_size = ctxm->entry_size;
175         drv_seg_rec->offset = bs_trace->last_offset;
176         drv_seg_rec->wrapped = bs_trace->wrapped;
177 }
178 
179 static void
180 bnxt_retrieve_driver_coredump(struct bnxt_softc *softc, void *buf,
181     uint16_t type, uint32_t *seg_len)
182 {
183 	struct bnxt_driver_segment_record drv_seg_rec = {0};
184 	struct bnxt_ctx_mem_info *ctx = softc->ctx_mem;
185 	struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
186 	struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info;
187 	uint32_t dump_len, data_offset, record_len, seg_hdr_len;
188 	uint32_t i, j, k, n = 1, nr_tbls;
189 
190 	dump_len = 0;
191 
192 	record_len = sizeof(struct bnxt_driver_segment_record);
193 	seg_hdr_len = sizeof(struct bnxt_coredump_segment_hdr);
194 	data_offset = seg_hdr_len + record_len;
195 
196 	bnxt_fill_driver_segment_record(softc, &drv_seg_rec, ctxm,
197 	    (type - BNXT_CTX_SRT_TRACE));
198 
199 	for (i = 0; i < n; i++) {
200 		struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem;
201 
202 		if (ctx_pg->nr_pages > MAX_CTX_PAGES || ctx_pg->ctx_pg_tbl) {
203 			nr_tbls = rmem->nr_pages;
204 			for (j = 0; j < nr_tbls; j++) {
205 				struct bnxt_ctx_pg_info *pg_tbl;
206 				struct bnxt_ring_mem_info *rmem2;
207 
208 				pg_tbl = ctx_pg->ctx_pg_tbl[j];
209 				if (!pg_tbl)
210 					continue;
211 				rmem2 = &pg_tbl->ring_mem;
212 				for (k = 0; k < rmem2->nr_pages; k++) {
213 					if (!rmem2->pg_arr[k].idi_vaddr)
214 						continue;
215 					memcpy((uint8_t *)buf + data_offset,
216 					    rmem2->pg_arr[k].idi_vaddr,
217 					    rmem2->page_size);
218 					data_offset += rmem2->page_size;
219 					dump_len += rmem2->page_size;
220 				}
221 			}
222 		} else {
223 			for (k = 0; k < rmem->nr_pages; k++) {
224 				if (!rmem->pg_arr[k].idi_vaddr)
225 					continue;
226 				memcpy((uint8_t *)buf + data_offset,
227 				    rmem->pg_arr[k].idi_vaddr,
228 				    rmem->page_size);
229 				data_offset += rmem->page_size;
230 				dump_len += rmem->page_size;
231 			}
232 		}
233 	}
234 	memcpy((uint8_t *)buf + seg_hdr_len, &drv_seg_rec, record_len);
235 	*seg_len = dump_len + record_len;
236 }
237 
238 void
239 bnxt_get_ctx_coredump(struct bnxt_softc *softc, void *buf)
240 {
241 	struct bnxt_ctx_mem_info *ctx = softc->ctx_mem;
242 	struct bnxt_coredump_segment_hdr seg_hdr;
243 	uint32_t type = 0, i = 0;
244 	uint32_t seg_hdr_len = 0;
245 
246 	seg_hdr_len = sizeof(seg_hdr);
247 	for (type = BNXT_CTX_SRT_TRACE, i = DRV_SRT_TRACE_SEG_ID;
248 	     type <= BNXT_CTX_ROCE_HWRM_TRACE; type++, i++) {
249 		struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
250 		uint16_t comp_id = DRV_COREDUMP_COMP_ID;
251 		uint16_t seg_id = i;
252 		uint32_t seg_len = 0;
253 
254 		ctxm = &ctx->ctx_arr[type];
255 
256 		if (!(ctxm->flags & BNXT_CTX_MEM_TYPE_VALID) ||
257 		    !ctxm->mem_valid)
258 			continue;
259 
260 		bnxt_retrieve_driver_coredump(softc, buf, type, &seg_len);
261 
262 		bnxt_fill_coredump_seg_hdr(softc, &seg_hdr, NULL, seg_len,
263 		    0, 0, 0, comp_id, seg_id);
264 
265 		memcpy((uint8_t *)buf, &seg_hdr, seg_hdr_len);
266 		buf = (uint8_t *)buf + seg_hdr_len + seg_len;
267 	}
268 }
269 
270 /* DDR Crash Dump IOCTL handler */
271 static int
272 bnxt_mgmt_crash_dump(struct cdev *dev, u_long cmd, caddr_t data,
273 		       int flag, struct thread *td)
274 {
275 	struct bnxt_softc *softc = NULL;
276 	struct bnxt_mgmt_crash_dump mgmt_crash_dump = {0};
277 	void *user_ptr;
278 	int ret = 0;
279 	void *dump_buf = NULL;
280 	uint32_t dump_len;
281 
282 	memcpy(&user_ptr, data, sizeof(user_ptr));
283 	if (copyin(user_ptr, &mgmt_crash_dump, sizeof(mgmt_crash_dump))) {
284 		printf("%s: %s:%d Failed to copy data from user\n",
285 			DRIVER_NAME, __func__, __LINE__);
286 		return (-EFAULT);
287 	}
288 	softc = bnxt_find_dev(mgmt_crash_dump.hdr.domain,
289 			      mgmt_crash_dump.hdr.bus,
290 			      mgmt_crash_dump.hdr.devfn, NULL);
291 	if (!softc) {
292 		printf("%s: %s:%d unable to find softc reference\n",
293 			DRIVER_NAME, __func__, __LINE__);
294 		return (-ENODEV);
295 	}
296 
297 	switch (mgmt_crash_dump.op) {
298 	case BNXT_MGMT_SET_DUMP_FLAG:
299 		if (mgmt_crash_dump.req.set_flag.dump_flag >
300 		    BNXT_DUMP_LIVE_WITH_CTX_L1_CACHE) {
301 			device_printf(softc->dev,
302 			    "Supports only Live(0), Crash(1), Driver(2), "
303 			    "Live with cached context(3) dumps.\n");
304 			ret = -EINVAL;
305 			break;
306 		}
307 
308 		if (mgmt_crash_dump.req.set_flag.dump_flag == BNXT_DUMP_CRASH) {
309 			if (softc->fw_dbg_cap & BNXT_FW_DBG_CAP_CRASHDUMP_SOC) {
310 				device_printf(softc->dev,
311 				    "Cannot collect crash dump as TEE is not supported.\n");
312 				ret = -ENOTSUP;
313 				break;
314 			} else if (!(softc->fw_dbg_cap &
315 				     BNXT_FW_DBG_CAP_CRASHDUMP_HOST)) {
316 				device_printf(softc->dev,
317 				    "FW does not support crash dump collection.\n");
318 				ret = -ENOTSUP;
319 				break;
320 			}
321 		}
322 
323 		softc->dump_flag = mgmt_crash_dump.req.set_flag.dump_flag;
324 		break;
325 
326 	case BNXT_MGMT_GET_DUMP_FLAG:
327 		if (softc->hwrm_spec_code < 0x10801) {
328 			ret = -ENOTSUP;
329 			break;
330 		}
331 
332 		/* Build FW version - same as Linux bnxt_get_dump_flag() */
333 		mgmt_crash_dump.req.get_flag.version =
334 			(softc->ver_resp.hwrm_fw_maj_8b << 24) |
335 			(softc->ver_resp.hwrm_fw_min_8b << 16) |
336 			(softc->ver_resp.hwrm_fw_bld_8b << 8) |
337 			(softc->ver_resp.hwrm_fw_rsvd_8b);
338 
339 		mgmt_crash_dump.req.get_flag.dump_flag = softc->dump_flag;
340 		mgmt_crash_dump.req.get_flag.dump_len =
341 			bnxt_get_coredump_length(softc, softc->dump_flag);
342 		break;
343 
344 	case BNXT_MGMT_GET_DUMP_DATA:
345 		if (softc->hwrm_spec_code < 0x10801) {
346 			ret = -ENOTSUP;
347 			break;
348 		}
349 
350 		dump_len = bnxt_get_coredump_length(softc,
351 			mgmt_crash_dump.req.get_data.dump_flag);
352 		if (dump_len == 0) {
353 			device_printf(softc->dev, "No dump data available\n");
354 			ret = -ENOENT;
355 			break;
356 		}
357 
358 		if (mgmt_crash_dump.req.get_data.buffer_size < dump_len) {
359 			device_printf(softc->dev,
360 			    "Buffer too small: need %u bytes, got %zu bytes\n",
361 			    dump_len, mgmt_crash_dump.req.get_data.buffer_size);
362 			mgmt_crash_dump.req.get_data.dump_len = dump_len;
363 			ret = -ENOSPC;
364 			break;
365 		}
366 
367 		dump_buf = malloc(dump_len, M_BNXT, M_WAITOK);
368 		if (!dump_buf) {
369 			ret = -ENOMEM;
370 			break;
371 		}
372 
373 		ret = bnxt_get_coredump(softc,
374 		    mgmt_crash_dump.req.get_data.dump_flag,
375 		    dump_buf, &dump_len);
376 		if (ret) {
377 			device_printf(softc->dev,
378 			    "Failed to get coredump: %d\n", ret);
379 			free(dump_buf, M_BNXT);
380 			break;
381 		}
382 
383 		if (copyout(dump_buf,
384 		    mgmt_crash_dump.req.get_data.dump_buffer, dump_len)) {
385 			device_printf(softc->dev,
386 			    "%s:%d Failed to copy dump data to user\n",
387 			    __func__, __LINE__);
388 			ret = -EFAULT;
389 			free(dump_buf, M_BNXT);
390 			break;
391 		}
392 
393 		mgmt_crash_dump.req.get_data.dump_len = dump_len;
394 		mgmt_crash_dump.req.get_data.dump_flag = softc->dump_flag;
395 		free(dump_buf, M_BNXT);
396 		break;
397 
398 	default:
399 		device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
400 			      __func__, __LINE__, mgmt_crash_dump.op);
401 		ret = -EFAULT;
402 		break;
403 	}
404 
405 	if (!ret && copyout(&mgmt_crash_dump, user_ptr,
406 	    sizeof(mgmt_crash_dump))) {
407 		device_printf(softc->dev,
408 		    "%s:%d Failed to copy response to user\n",
409 		    __func__, __LINE__);
410 		ret = -EFAULT;
411 	}
412 
413 	return (ret);
414 }
415 
416 /*
417  * This function is called by the kld[un]load(2) system calls to
418  * determine what actions to take when a module is loaded or unloaded.
419  */
420 static int
421 bnxt_mgmt_loader(struct module *m, int what, void *arg)
422 {
423 	int error = 0;
424 
425 	switch (what) {
426 	case MOD_LOAD:
427 		error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
428 		    &bnxt_mgmt_dev,
429 		    &bnxt_mgmt_cdevsw,
430 		    0,
431 		    UID_ROOT,
432 		    GID_WHEEL,
433 		    0600,
434 		    "bnxt_mgmt");
435 		if (error != 0) {
436 			printf("%s: %s:%s:%d Failed to create the"
437 			       "bnxt_mgmt device node\n", DRIVER_NAME,
438 			       __FILE__, __func__, __LINE__);
439 			return (error);
440 		}
441 
442 		sx_init(&mgmt_lock, "BNXT MGMT Lock");
443 
444 		break;
445 	case MOD_UNLOAD:
446 		sx_destroy(&mgmt_lock);
447 		destroy_dev(bnxt_mgmt_dev);
448 		break;
449 	default:
450 		error = EOPNOTSUPP;
451 		break;
452 	}
453 
454 	return (error);
455 }
456 
457 static int
458 bnxt_mgmt_process_dcb(struct cdev *dev, u_long cmd, caddr_t data,
459 		       int flag, struct thread *td)
460 {
461 	struct bnxt_softc *softc = NULL;
462 	struct bnxt_mgmt_dcb mgmt_dcb = {};
463 	void *user_ptr;
464 	int ret = 0;
465 
466 	memcpy(&user_ptr, data, sizeof(user_ptr));
467 	if (copyin(user_ptr, &mgmt_dcb, sizeof(mgmt_dcb))) {
468 		printf("%s: %s:%d Failed to copy data from user\n",
469 			DRIVER_NAME, __func__, __LINE__);
470 		return -EFAULT;
471 	}
472 	softc = bnxt_find_dev(mgmt_dcb.hdr.domain, mgmt_dcb.hdr.bus,
473 			      mgmt_dcb.hdr.devfn, NULL);
474 	if (!softc) {
475 		printf("%s: %s:%d unable to find softc reference\n",
476 			DRIVER_NAME, __func__, __LINE__);
477 		return -ENODEV;
478 	}
479 
480 	switch (mgmt_dcb.op) {
481 	case BNXT_MGMT_DCB_GET_ETS:
482 		bnxt_dcb_ieee_getets(softc, &mgmt_dcb.req.ets);
483 		break;
484 	case BNXT_MGMT_DCB_SET_ETS:
485 		bnxt_dcb_ieee_setets(softc, &mgmt_dcb.req.ets);
486 		break;
487 	case BNXT_MGMT_DCB_GET_PFC:
488 		bnxt_dcb_ieee_getpfc(softc, &mgmt_dcb.req.pfc);
489 		break;
490 	case BNXT_MGMT_DCB_SET_PFC:
491 		bnxt_dcb_ieee_setpfc(softc, &mgmt_dcb.req.pfc);
492 		break;
493 	case BNXT_MGMT_DCB_SET_APP:
494 		bnxt_dcb_ieee_setapp(softc, &mgmt_dcb.req.app_tlv.app[0]);
495 		break;
496 	case BNXT_MGMT_DCB_DEL_APP:
497 		bnxt_dcb_ieee_delapp(softc, &mgmt_dcb.req.app_tlv.app[0]);
498 		break;
499 	case BNXT_MGMT_DCB_LIST_APP:
500 		bnxt_dcb_ieee_listapp(softc, &mgmt_dcb.req.app_tlv.app[0],
501 				      nitems(mgmt_dcb.req.app_tlv.app),
502 				      &mgmt_dcb.req.app_tlv.num_app);
503 		break;
504 	default:
505 		device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
506 			      __func__, __LINE__, mgmt_dcb.op);
507 		ret = -EFAULT;
508 		goto end;
509 	}
510 
511 	if (copyout(&mgmt_dcb, user_ptr, sizeof(mgmt_dcb))) {
512 		device_printf(softc->dev, "%s:%d Failed to copy response to user\n",
513 			      __func__, __LINE__);
514 		ret = -EFAULT;
515 		goto end;
516 	}
517 
518 end:
519 	return ret;
520 }
521 
522 static int
523 bnxt_mgmt_process_hwrm(struct cdev *dev, u_long cmd, caddr_t data,
524 		       int flag, struct thread *td)
525 {
526 	struct bnxt_softc *softc = NULL;
527 	struct bnxt_mgmt_req mgmt_req = {};
528 	struct bnxt_mgmt_fw_msg msg_temp, *msg, *msg2 = NULL;
529 	void *user_ptr, *req, *resp;
530 	int ret = 0, num_allocated = 0, i;
531 	uint16_t num_ind = 0;
532 
533 	memcpy(&user_ptr, data, sizeof(user_ptr));
534 	if (copyin(user_ptr, &mgmt_req, sizeof(struct bnxt_mgmt_req))) {
535 		printf("%s: %s:%d Failed to copy data from user\n",
536 			DRIVER_NAME, __func__, __LINE__);
537 		return -EFAULT;
538 	}
539 	softc = bnxt_find_dev(mgmt_req.hdr.domain, mgmt_req.hdr.bus,
540 			      mgmt_req.hdr.devfn, NULL);
541 	if (!softc) {
542 		printf("%s: %s:%d unable to find softc reference\n",
543 			DRIVER_NAME, __func__, __LINE__);
544 		return -ENODEV;
545 	}
546 
547 	if (copyin((void*)mgmt_req.req.hreq, &msg_temp, sizeof(msg_temp))) {
548 		device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
549 			      __func__, __LINE__);
550 		return -EFAULT;
551 	}
552 
553 	if (msg_temp.len_req > BNXT_MGMT_MAX_HWRM_REQ_LENGTH ||
554 			msg_temp.len_resp > BNXT_MGMT_MAX_HWRM_RESP_LENGTH) {
555 		device_printf(softc->dev, "%s:%d Invalid length\n",
556 			      __func__, __LINE__);
557 		return -EINVAL;
558 	}
559 
560 	if (msg_temp.num_dma_indications > MAX_NUM_DMA_INDICATIONS) {
561 		device_printf(softc->dev, "%s:%d Max num_dma_indications "
562 			      "supported is %d\n", __func__, __LINE__,
563 			      MAX_NUM_DMA_INDICATIONS);
564 		return -EINVAL;
565 	}
566 
567 	req = malloc(msg_temp.len_req, M_BNXT, M_WAITOK | M_ZERO);
568 	resp = malloc(msg_temp.len_resp, M_BNXT, M_WAITOK | M_ZERO);
569 
570 	if (copyin((void *)msg_temp.usr_req, req, msg_temp.len_req)) {
571 		device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
572 			      __func__, __LINE__);
573 		ret = -EFAULT;
574 		goto end;
575 	}
576 
577 	msg = &msg_temp;
578 	num_ind = msg_temp.num_dma_indications;
579 	if (num_ind) {
580 		int size;
581 		void *dma_ptr;
582 		uint64_t *dmap;
583 
584 		size = sizeof(struct bnxt_mgmt_fw_msg) +
585 			     (num_ind * sizeof(struct dma_info));
586 
587 		msg2 = malloc(size, M_BNXT, M_WAITOK | M_ZERO);
588 
589 		if (copyin((void *)mgmt_req.req.hreq, msg2, size)) {
590 			device_printf(softc->dev, "%s:%d Failed to copy"
591 				      "data from user\n", __func__, __LINE__);
592 			ret = -EFAULT;
593 			goto end;
594 		}
595 		msg = msg2;
596 
597 		for (i = 0; i < num_ind; i++) {
598 
599 			if (msg->dma[i].length == 0) {
600 				device_printf(softc->dev,
601 					"%s:%d i:%d Invalid DMA memory length\n",
602 					__func__, __LINE__, i);
603 				ret = -ENOMEM;
604 				goto end;
605 			}
606 
607 			memset(&softc->mgmt_dma_data[i], 0, sizeof(struct iflib_dma_info));
608 
609 			ret = iflib_dma_alloc(softc->ctx, msg->dma[i].length, &softc->mgmt_dma_data[i],
610 				BUS_DMA_WAITOK);
611 			if (ret) {
612 				device_printf(softc->dev,
613 					"%s:%d iflib_dma_alloc failed with ret = 0x%x\n",
614 					__func__, __LINE__, ret);
615 				ret = -ENOMEM;
616 				goto end;
617 			}
618 
619 			num_allocated++;
620 			if (!(msg->dma[i].read_or_write)) {
621 				if (copyin((void *)msg->dma[i].data,
622 				    softc->mgmt_dma_data[i].idi_vaddr,
623 				    msg->dma[i].length)) {
624 					device_printf(softc->dev,
625 						"%s:%d Failed to copy data from user\n",
626 						__func__, __LINE__);
627 					ret = -EFAULT;
628 					goto end;
629 				}
630 			}
631 			dma_ptr = (void *) ((uint64_t) req + msg->dma[i].offset);
632 			dmap = dma_ptr;
633 			*dmap = htole64(softc->mgmt_dma_data[i].idi_paddr);
634 		}
635 	}
636 
637 	ret = bnxt_hwrm_passthrough(softc, req, msg->len_req, resp, msg->len_resp, msg->timeout);
638 	if (ret)
639 		goto end;
640 
641 	for (i = 0; i < num_ind; i++) {
642 		if ((msg->dma[i].read_or_write)) {
643 			if (copyout(softc->mgmt_dma_data[i].idi_vaddr,
644 			    (void *)msg->dma[i].data,
645 			    msg->dma[i].length)) {
646 				device_printf(softc->dev,
647 					"%s:%d Failed to copy data to user\n",
648 					__func__, __LINE__);
649 				ret = -EFAULT;
650 				goto end;
651 			}
652 		}
653 	}
654 
655 	if (copyout(resp, (void *) msg->usr_resp, msg->len_resp)) {
656 		device_printf(softc->dev, "%s:%d Failed to copy response to user\n",
657 			      __func__, __LINE__);
658 		ret = -EFAULT;
659 		goto end;
660 	}
661 
662 end:
663 	if (req)
664 		free(req, M_BNXT);
665 	if (resp)
666 		free(resp, M_BNXT);
667 	if (msg2)
668 		free(msg2, M_BNXT);
669 	if (num_allocated) {
670 		for (i = 0; i < num_allocated; i++)
671 			if (softc->mgmt_dma_data[i].idi_paddr)
672 				iflib_dma_free(&softc->mgmt_dma_data[i]);
673 	}
674 	return ret;
675 }
676 
677 static int
678 bnxt_mgmt_get_dev_info(struct cdev *dev, u_long cmd, caddr_t data,
679 		       int flag, struct thread *td)
680 {
681 	struct bnxt_softc *softc = NULL;
682 	struct bnxt_dev_info dev_info;
683 	void *user_ptr;
684 	uint32_t dev_sn_lo, dev_sn_hi;
685 	int dev_sn_offset = 0;
686 	char dsn[16];
687 	uint16_t lnk;
688 	int capreg;
689 
690 	memcpy(&user_ptr, data, sizeof(user_ptr));
691 	if (copyin(user_ptr, &dev_info, sizeof(dev_info))) {
692 		printf("%s: %s:%d Failed to copy data from user\n",
693 			DRIVER_NAME, __func__, __LINE__);
694 		return -EFAULT;
695 	}
696 
697 	softc = bnxt_find_dev(0, 0, 0, dev_info.nic_info.dev_name);
698 	if (!softc) {
699 		printf("%s: %s:%d unable to find softc reference\n",
700 			DRIVER_NAME, __func__, __LINE__);
701 		return -ENODEV;
702 	}
703 
704 	strncpy(dev_info.nic_info.driver_version, bnxt_driver_version, 64);
705 	strncpy(dev_info.nic_info.driver_name, device_get_name(softc->dev), 64);
706 	dev_info.pci_info.domain_no = softc->domain;
707 	dev_info.pci_info.bus_no = softc->bus;
708 	dev_info.pci_info.device_no = softc->slot;
709 	dev_info.pci_info.function_no = softc->function;
710 	dev_info.pci_info.vendor_id = pci_get_vendor(softc->dev);
711 	dev_info.pci_info.device_id = pci_get_device(softc->dev);
712 	dev_info.pci_info.sub_system_vendor_id = pci_get_subvendor(softc->dev);
713 	dev_info.pci_info.sub_system_device_id = pci_get_subdevice(softc->dev);
714 	dev_info.pci_info.revision = pci_read_config(softc->dev, PCIR_REVID, 1);
715 	dev_info.pci_info.chip_rev_id = (dev_info.pci_info.device_id << 16);
716 	dev_info.pci_info.chip_rev_id |= dev_info.pci_info.revision;
717 	if (pci_find_extcap(softc->dev, PCIZ_SERNUM, &dev_sn_offset)) {
718 		device_printf(softc->dev, "%s:%d device serial number is not found"
719 			      "or not supported\n", __func__, __LINE__);
720 	} else {
721 		dev_sn_lo = pci_read_config(softc->dev, dev_sn_offset + 4, 4);
722 		dev_sn_hi = pci_read_config(softc->dev, dev_sn_offset + 8, 4);
723 		snprintf(dsn, sizeof(dsn), "%02x%02x%02x%02x%02x%02x%02x%02x",
724 			 (dev_sn_lo & 0x000000FF),
725 			 (dev_sn_lo >> 8) & 0x0000FF,
726 			 (dev_sn_lo >> 16) & 0x00FF,
727 			 (dev_sn_lo >> 24 ) & 0xFF,
728 			 (dev_sn_hi & 0x000000FF),
729 			 (dev_sn_hi >> 8) & 0x0000FF,
730 			 (dev_sn_hi >> 16) & 0x00FF,
731 			 (dev_sn_hi >> 24 ) & 0xFF);
732 		strncpy(dev_info.nic_info.device_serial_number, dsn, sizeof(dsn));
733 	}
734 
735 	if_t ifp = iflib_get_ifp(softc->ctx);
736 	dev_info.nic_info.mtu = if_getmtu(ifp);
737 	memcpy(dev_info.nic_info.mac, softc->func.mac_addr, ETHER_ADDR_LEN);
738 
739 	if (pci_find_cap(softc->dev, PCIY_EXPRESS, &capreg)) {
740 		device_printf(softc->dev, "%s:%d pci link capability is not found"
741 			      "or not supported\n", __func__, __LINE__);
742 	} else {
743 		lnk = pci_read_config(softc->dev, capreg + PCIER_LINK_STA, 2);
744 		dev_info.nic_info.pci_link_speed = (lnk & PCIEM_LINK_STA_SPEED);
745 		dev_info.nic_info.pci_link_width = (lnk & PCIEM_LINK_STA_WIDTH) >> 4;
746 	}
747 
748 	if (copyout(&dev_info, user_ptr, sizeof(dev_info))) {
749 		device_printf(softc->dev, "%s:%d Failed to copy data to user\n",
750 			      __func__, __LINE__);
751 		return (-EFAULT);
752 	}
753 
754 	return (0);
755 }
756 
757 static int
758 bnxt_mgmt_drv_dump(struct cdev *dev, u_long cmd, caddr_t data,
759 		       int flag, struct thread *td)
760 {
761 	struct bnxt_softc *softc = NULL;
762 	void *buf = NULL;
763 	struct bnxt_logger *logger = NULL, *lg_tmp;
764 	int buf_sz = 0;
765 	struct bnxt_mgmt_drv_dump mgmt_drv_dump = {};
766 	void *user_ptr;
767 	int ret = 0, offset = 0;
768 
769 	memcpy(&user_ptr, data, sizeof(user_ptr));
770 	if (copyin(user_ptr, &mgmt_drv_dump, sizeof(mgmt_drv_dump))) {
771 		printf("%s: %s:%d Failed to copy data from user\n",
772 			DRIVER_NAME, __func__, __LINE__);
773 		return (-EFAULT);
774 	}
775 	softc = bnxt_find_dev(mgmt_drv_dump.hdr.domain, mgmt_drv_dump.hdr.bus,
776 			      mgmt_drv_dump.hdr.devfn, NULL);
777 	if (!softc) {
778 		printf("%s: %s:%d unable to find softc reference\n",
779 			DRIVER_NAME, __func__, __LINE__);
780 		return (-ENODEV);
781 	}
782 
783 	switch (mgmt_drv_dump.op) {
784 	case BNXT_MGMT_GET_DRV_DUMP_SIZE:
785 		mtx_lock(&softc->log_lock);
786 		TAILQ_FOREACH_SAFE(logger, &softc->loggers_list, list, lg_tmp)
787 			buf_sz += logger->buffer_size;
788 		mtx_unlock(&softc->log_lock);
789 
790 		mgmt_drv_dump.buf_size = buf_sz +
791 		    bnxt_get_driver_coredump_len(softc);
792 		if (copyout(&mgmt_drv_dump, user_ptr, sizeof(mgmt_drv_dump))) {
793 			device_printf(softc->dev,
794 			    "%s:%d Failed to copy response to user\n",
795 			    __func__, __LINE__);
796 			ret = -EFAULT;
797 		}
798 		break;
799 	case BNXT_MGMT_GET_DRV_DUMP:
800 		buf = malloc(mgmt_drv_dump.buf_size, M_BNXT, M_WAITOK);
801 		/*Dump the driver logs */
802 		memset(buf, 0, mgmt_drv_dump.buf_size);
803 		offset = bnxt_start_logging_driver_coredump(softc, buf);
804 
805 		if (!offset) {
806 			device_printf(softc->dev,
807 			    "%s:%d Drivers logs are empty\n",
808 			    __func__, __LINE__);
809 		}
810 
811 		/* Dump the ctx logs*/
812 		if (softc->ctx_mem)
813 			bnxt_get_ctx_coredump(softc, (uint8_t *)buf + offset);
814 
815 		if (copyout(buf, mgmt_drv_dump.buf, mgmt_drv_dump.buf_size)) {
816 			device_printf(softc->dev,
817 			    "%s:%d Failed to copy response to user\n",
818 			    __func__, __LINE__);
819 			ret = -EFAULT;
820 		}
821 
822 		free(buf, M_BNXT);
823 		break;
824 	default:
825 		device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
826 			      __func__, __LINE__, mgmt_drv_dump.op);
827 		ret = -EFAULT;
828 	}
829 
830 	return (ret);
831 }
832 
833 /*
834  * IOCTL entry point.
835  */
836 static int
837 bnxt_mgmt_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
838 		struct thread *td)
839 {
840 	int ret = 0;
841 
842 	switch(cmd) {
843 	case IO_BNXT_MGMT_OPCODE_GET_DEV_INFO:
844 	case IOW_BNXT_MGMT_OPCODE_GET_DEV_INFO:
845 		ret = bnxt_mgmt_get_dev_info(dev, cmd, data, flag, td);
846 		break;
847 	case IO_BNXT_MGMT_OPCODE_PASSTHROUGH_HWRM:
848 	case IOW_BNXT_MGMT_OPCODE_PASSTHROUGH_HWRM:
849 		sx_xlock(&mgmt_lock);
850 		ret = bnxt_mgmt_process_hwrm(dev, cmd, data, flag, td);
851 		sx_xunlock(&mgmt_lock);
852 		break;
853 	case IO_BNXT_MGMT_OPCODE_DCB_OPS:
854 	case IOW_BNXT_MGMT_OPCODE_DCB_OPS:
855 		ret = bnxt_mgmt_process_dcb(dev, cmd, data, flag, td);
856 		break;
857 	case IO_BNXT_MGMT_OPCODE_DRV_DUMP:
858 	case IOW_BNXT_MGMT_OPCODE_DRV_DUMP:
859 		ret = bnxt_mgmt_drv_dump(dev, cmd, data, flag, td);
860 		break;
861 	case IO_BNXT_MGMT_OPCODE_CRASH_DUMP:
862 	case IOW_BNXT_MGMT_OPCODE_CRASH_DUMP:
863 		ret = bnxt_mgmt_crash_dump(dev, cmd, data, flag, td);
864 		break;
865 	default:
866 		printf("%s: Unknown command 0x%lx\n", DRIVER_NAME, cmd);
867 		ret = -EINVAL;
868 		break;
869 	}
870 
871 	return (ret);
872 }
873 
874 static int
875 bnxt_mgmt_close(struct cdev *dev, int flags, int devtype, struct thread *td)
876 {
877 	return (0);
878 }
879 
880 static int
881 bnxt_mgmt_open(struct cdev *dev, int flags, int devtype, struct thread *td)
882 {
883 	return (0);
884 }
885 
886 DEV_MODULE(bnxt_mgmt, bnxt_mgmt_loader, NULL);
887 
888