xref: /freebsd/sys/dev/qlnx/qlnxe/qlnx_ioctl.c (revision 389e4940069316fe667ffa263fa7d6390d0a960f)
1 /*
2  * Copyright (c) 2017-2018 Cavium, Inc.
3  * All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions
7  *  are met:
8  *
9  *  1. Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  *  2. Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  *  POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 
29 /*
30  * File: qlnx_ioctl.c
31  * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include "qlnx_os.h"
38 #include "bcm_osal.h"
39 
40 #include "reg_addr.h"
41 #include "ecore_gtt_reg_addr.h"
42 #include "ecore.h"
43 #include "ecore_chain.h"
44 #include "ecore_status.h"
45 #include "ecore_hw.h"
46 #include "ecore_rt_defs.h"
47 #include "ecore_init_ops.h"
48 #include "ecore_int.h"
49 #include "ecore_cxt.h"
50 #include "ecore_spq.h"
51 #include "ecore_init_fw_funcs.h"
52 #include "ecore_sp_commands.h"
53 #include "ecore_dev_api.h"
54 #include "ecore_l2_api.h"
55 #include "ecore_mcp.h"
56 #include "ecore_hw_defs.h"
57 #include "mcp_public.h"
58 #include "ecore_iro.h"
59 #include "nvm_cfg.h"
60 #include "ecore_dev_api.h"
61 #include "ecore_dbg_fw_funcs.h"
62 
63 #include "qlnx_ioctl.h"
64 #include "qlnx_def.h"
65 #include "qlnx_ver.h"
66 #include <sys/smp.h>
67 
68 
69 static int qlnx_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
70                 struct thread *td);
71 
72 static struct cdevsw qlnx_cdevsw = {
73         .d_version = D_VERSION,
74         .d_ioctl = qlnx_eioctl,
75         .d_name = "qlnxioctl",
76 };
77 
78 int
79 qlnx_make_cdev(qlnx_host_t *ha)
80 {
81 	ha->ioctl_dev = make_dev(&qlnx_cdevsw,
82 				ha->ifp->if_dunit,
83 				UID_ROOT,
84 				GID_WHEEL,
85 				0600,
86 				"%s",
87 				if_name(ha->ifp));
88 
89 	if (ha->ioctl_dev == NULL)
90 		return (-1);
91 
92 	ha->ioctl_dev->si_drv1 = ha;
93 
94 	return (0);
95 }
96 
97 void
98 qlnx_del_cdev(qlnx_host_t *ha)
99 {
100 	if (ha->ioctl_dev != NULL)
101 		destroy_dev(ha->ioctl_dev);
102 	return;
103 }
104 
105 int
106 qlnx_grc_dump(qlnx_host_t *ha, uint32_t *num_dumped_dwords, int hwfn_index)
107 {
108 	int rval = EINVAL;
109 	struct ecore_hwfn *p_hwfn;
110 	struct ecore_ptt *p_ptt;
111 
112 	if (ha->grcdump_dwords[hwfn_index]) {
113 		/* the grcdump is already available */
114 		*num_dumped_dwords = ha->grcdump_dwords[hwfn_index];
115 		return (0);
116 	}
117 
118 	ecore_dbg_set_app_ver(ecore_dbg_get_fw_func_ver());
119 
120 	p_hwfn = &ha->cdev.hwfns[hwfn_index];
121 	p_ptt = ecore_ptt_acquire(p_hwfn);
122 
123 	if (!p_ptt) {
124 		QL_DPRINT1(ha,"ecore_ptt_acquire failed\n");
125 		return (rval);
126 	}
127 
128 	if ((rval = ecore_dbg_grc_dump(p_hwfn, p_ptt,
129 			ha->grcdump[hwfn_index],
130 			(ha->grcdump_size[hwfn_index] >> 2),
131 			num_dumped_dwords)) == DBG_STATUS_OK) {
132 	 	rval = 0;
133 		ha->grcdump_taken = 1;
134 	} else
135 		QL_DPRINT1(ha,"ecore_dbg_grc_dump failed [%d, 0x%x]\n",
136 			   hwfn_index, rval);
137 
138 	ecore_ptt_release(p_hwfn, p_ptt);
139 
140 	return (rval);
141 }
142 
143 static void
144 qlnx_get_grc_dump_size(qlnx_host_t *ha, qlnx_grcdump_t *grcdump)
145 {
146 	int i;
147 
148 	grcdump->pci_func = ha->pci_func;
149 
150 	for (i = 0; i < ha->cdev.num_hwfns; i++)
151 		grcdump->grcdump_size[i] = ha->grcdump_size[i];
152 
153 	return;
154 }
155 
156 static int
157 qlnx_get_grc_dump(qlnx_host_t *ha, qlnx_grcdump_t *grcdump)
158 {
159 	int		i;
160 	int		rval = 0;
161 	uint32_t	dwords = 0;
162 
163 	grcdump->pci_func = ha->pci_func;
164 
165 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
166 
167 		if ((ha->grcdump[i] == NULL) || (grcdump->grcdump[i] == NULL) ||
168 			(grcdump->grcdump_size[i] < ha->grcdump_size[i]))
169 			return (EINVAL);
170 
171 		rval = qlnx_grc_dump(ha, &dwords, i);
172 
173 		if (rval)
174 			break;
175 
176 		grcdump->grcdump_dwords[i] = dwords;
177 
178 		QL_DPRINT1(ha,"grcdump_dwords[%d] = 0x%x\n", i, dwords);
179 
180 		rval = copyout(ha->grcdump[i], grcdump->grcdump[i],
181 				ha->grcdump_size[i]);
182 
183 		if (rval)
184 			break;
185 
186 		ha->grcdump_dwords[i] = 0;
187 	}
188 
189 	ha->grcdump_taken = 0;
190 
191 	return (rval);
192 }
193 
194 int
195 qlnx_idle_chk(qlnx_host_t *ha, uint32_t *num_dumped_dwords, int hwfn_index)
196 {
197 	int rval = EINVAL;
198 	struct ecore_hwfn *p_hwfn;
199 	struct ecore_ptt *p_ptt;
200 
201 	if (ha->idle_chk_dwords[hwfn_index]) {
202 		/* the idle check is already available */
203 		*num_dumped_dwords = ha->idle_chk_dwords[hwfn_index];
204 		return (0);
205 	}
206 
207 	ecore_dbg_set_app_ver(ecore_dbg_get_fw_func_ver());
208 
209 	p_hwfn = &ha->cdev.hwfns[hwfn_index];
210 	p_ptt = ecore_ptt_acquire(p_hwfn);
211 
212 	if (!p_ptt) {
213 		QL_DPRINT1(ha,"ecore_ptt_acquire failed\n");
214 		return (rval);
215 	}
216 
217 	if ((rval = ecore_dbg_idle_chk_dump(p_hwfn, p_ptt,
218 			ha->idle_chk[hwfn_index],
219 			(ha->idle_chk_size[hwfn_index] >> 2),
220 			num_dumped_dwords)) == DBG_STATUS_OK) {
221 	 	rval = 0;
222 		ha->idle_chk_taken = 1;
223 	} else
224 		QL_DPRINT1(ha,"ecore_dbg_idle_chk_dump failed [%d, 0x%x]\n",
225 			   hwfn_index, rval);
226 
227 	ecore_ptt_release(p_hwfn, p_ptt);
228 
229 	return (rval);
230 }
231 
232 static void
233 qlnx_get_idle_chk_size(qlnx_host_t *ha, qlnx_idle_chk_t *idle_chk)
234 {
235 	int i;
236 
237 	idle_chk->pci_func = ha->pci_func;
238 
239 	for (i = 0; i < ha->cdev.num_hwfns; i++)
240 		idle_chk->idle_chk_size[i] = ha->idle_chk_size[i];
241 
242 	return;
243 }
244 
245 static int
246 qlnx_get_idle_chk(qlnx_host_t *ha, qlnx_idle_chk_t *idle_chk)
247 {
248 	int		i;
249 	int		rval = 0;
250 	uint32_t	dwords = 0;
251 
252 	idle_chk->pci_func = ha->pci_func;
253 
254 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
255 
256 		if ((ha->idle_chk[i] == NULL) ||
257 				(idle_chk->idle_chk[i] == NULL) ||
258 				(idle_chk->idle_chk_size[i] <
259 					ha->idle_chk_size[i]))
260 			return (EINVAL);
261 
262 		rval = qlnx_idle_chk(ha, &dwords, i);
263 
264 		if (rval)
265 			break;
266 
267 		idle_chk->idle_chk_dwords[i] = dwords;
268 
269 		QL_DPRINT1(ha,"idle_chk_dwords[%d] = 0x%x\n", i, dwords);
270 
271                	rval = copyout(ha->idle_chk[i], idle_chk->idle_chk[i],
272 				ha->idle_chk_size[i]);
273 
274 		if (rval)
275 			break;
276 
277 		ha->idle_chk_dwords[i] = 0;
278 	}
279 	ha->idle_chk_taken = 0;
280 
281 	return (rval);
282 }
283 
284 static uint32_t
285 qlnx_get_trace_cmd_size(qlnx_host_t *ha, int hwfn_index, uint16_t cmd)
286 {
287         int rval = -1;
288         struct ecore_hwfn *p_hwfn;
289         struct ecore_ptt *p_ptt;
290 	uint32_t num_dwords = 0;
291 
292         p_hwfn = &ha->cdev.hwfns[hwfn_index];
293         p_ptt = ecore_ptt_acquire(p_hwfn);
294 
295         if (!p_ptt) {
296                 QL_DPRINT1(ha, "ecore_ptt_acquire [%d, 0x%x]failed\n",
297                            hwfn_index, cmd);
298                 return (0);
299         }
300 
301 	switch (cmd) {
302 
303 	case QLNX_MCP_TRACE:
304         	rval = ecore_dbg_mcp_trace_get_dump_buf_size(p_hwfn,
305 				p_ptt, &num_dwords);
306 		break;
307 
308 	case QLNX_REG_FIFO:
309         	rval = ecore_dbg_reg_fifo_get_dump_buf_size(p_hwfn,
310 				p_ptt, &num_dwords);
311 		break;
312 
313 	case QLNX_IGU_FIFO:
314         	rval = ecore_dbg_igu_fifo_get_dump_buf_size(p_hwfn,
315 				p_ptt, &num_dwords);
316 		break;
317 
318 	case QLNX_PROTECTION_OVERRIDE:
319         	rval = ecore_dbg_protection_override_get_dump_buf_size(p_hwfn,
320 				p_ptt, &num_dwords);
321 		break;
322 
323 	case QLNX_FW_ASSERTS:
324         	rval = ecore_dbg_fw_asserts_get_dump_buf_size(p_hwfn,
325 				p_ptt, &num_dwords);
326 		break;
327 	}
328 
329         if (rval != DBG_STATUS_OK) {
330                 QL_DPRINT1(ha,"cmd = 0x%x failed [0x%x]\n", cmd, rval);
331 		num_dwords = 0;
332         }
333 
334         ecore_ptt_release(p_hwfn, p_ptt);
335 
336         return ((num_dwords * sizeof (uint32_t)));
337 }
338 
339 static void
340 qlnx_get_trace_size(qlnx_host_t *ha, qlnx_trace_t *trace)
341 {
342 	int i;
343 
344 	trace->pci_func = ha->pci_func;
345 
346 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
347 		trace->size[i] = qlnx_get_trace_cmd_size(ha, i, trace->cmd);
348 	}
349 
350 	return;
351 }
352 
353 static int
354 qlnx_get_trace(qlnx_host_t *ha, int hwfn_index, qlnx_trace_t *trace)
355 {
356         int rval = -1;
357         struct ecore_hwfn *p_hwfn;
358         struct ecore_ptt *p_ptt;
359 	uint32_t num_dwords = 0;
360 	void *buffer;
361 
362 	buffer = qlnx_zalloc(trace->size[hwfn_index]);
363 	if (buffer == NULL) {
364                 QL_DPRINT1(ha,"qlnx_zalloc [%d, 0x%x]failed\n",
365                            hwfn_index, trace->cmd);
366                 return (ENXIO);
367 	}
368 	ecore_dbg_set_app_ver(ecore_dbg_get_fw_func_ver());
369 
370         p_hwfn = &ha->cdev.hwfns[hwfn_index];
371         p_ptt = ecore_ptt_acquire(p_hwfn);
372 
373         if (!p_ptt) {
374                 QL_DPRINT1(ha, "ecore_ptt_acquire [%d, 0x%x]failed\n",
375                            hwfn_index, trace->cmd);
376                 return (ENXIO);
377         }
378 
379 	switch (trace->cmd) {
380 
381 	case QLNX_MCP_TRACE:
382         	rval = ecore_dbg_mcp_trace_dump(p_hwfn, p_ptt,
383 				buffer, (trace->size[hwfn_index] >> 2),
384 				&num_dwords);
385 		break;
386 
387 	case QLNX_REG_FIFO:
388         	rval = ecore_dbg_reg_fifo_dump(p_hwfn, p_ptt,
389 				buffer, (trace->size[hwfn_index] >> 2),
390 				&num_dwords);
391 		break;
392 
393 	case QLNX_IGU_FIFO:
394         	rval = ecore_dbg_igu_fifo_dump(p_hwfn, p_ptt,
395 				buffer, (trace->size[hwfn_index] >> 2),
396 				&num_dwords);
397 		break;
398 
399 	case QLNX_PROTECTION_OVERRIDE:
400         	rval = ecore_dbg_protection_override_dump(p_hwfn, p_ptt,
401 				buffer, (trace->size[hwfn_index] >> 2),
402 				&num_dwords);
403 		break;
404 
405 	case QLNX_FW_ASSERTS:
406         	rval = ecore_dbg_fw_asserts_dump(p_hwfn, p_ptt,
407 				buffer, (trace->size[hwfn_index] >> 2),
408 				&num_dwords);
409 		break;
410 	}
411 
412         if (rval != DBG_STATUS_OK) {
413                 QL_DPRINT1(ha,"cmd = 0x%x failed [0x%x]\n", trace->cmd, rval);
414 		num_dwords = 0;
415         }
416 
417         ecore_ptt_release(p_hwfn, p_ptt);
418 
419 	trace->dwords[hwfn_index] = num_dwords;
420 
421 	if (num_dwords) {
422                	rval = copyout(buffer, trace->buffer[hwfn_index],
423 				(num_dwords << 2));
424 	}
425 
426         return (rval);
427 }
428 
429 static int
430 qlnx_reg_rd_wr(qlnx_host_t *ha, qlnx_reg_rd_wr_t *reg_rd_wr)
431 {
432 	int			rval = 0;
433 	struct ecore_hwfn	*p_hwfn;
434 
435 	if (reg_rd_wr->hwfn_index >= QLNX_MAX_HW_FUNCS) {
436 		return (EINVAL);
437 	}
438 
439 	p_hwfn = &ha->cdev.hwfns[reg_rd_wr->hwfn_index];
440 
441 	switch (reg_rd_wr->cmd) {
442 
443 		case QLNX_REG_READ_CMD:
444 			if (reg_rd_wr->access_type == QLNX_REG_ACCESS_DIRECT) {
445 				reg_rd_wr->val = qlnx_reg_rd32(p_hwfn,
446 							reg_rd_wr->addr);
447 			}
448 			break;
449 
450 		case QLNX_REG_WRITE_CMD:
451 			if (reg_rd_wr->access_type == QLNX_REG_ACCESS_DIRECT) {
452 				qlnx_reg_wr32(p_hwfn, reg_rd_wr->addr,
453 					reg_rd_wr->val);
454 			}
455 			break;
456 
457 		default:
458 			rval = EINVAL;
459 			break;
460 	}
461 
462 	return (rval);
463 }
464 
465 static int
466 qlnx_rd_wr_pci_config(qlnx_host_t *ha, qlnx_pcicfg_rd_wr_t *pci_cfg_rd_wr)
467 {
468 	int rval = 0;
469 
470 	switch (pci_cfg_rd_wr->cmd) {
471 
472 		case QLNX_PCICFG_READ:
473 			pci_cfg_rd_wr->val = pci_read_config(ha->pci_dev,
474 						pci_cfg_rd_wr->reg,
475 						pci_cfg_rd_wr->width);
476 			break;
477 
478 		case QLNX_PCICFG_WRITE:
479 			pci_write_config(ha->pci_dev, pci_cfg_rd_wr->reg,
480 				pci_cfg_rd_wr->val, pci_cfg_rd_wr->width);
481 			break;
482 
483 		default:
484 			rval = EINVAL;
485 			break;
486 	}
487 
488 	return (rval);
489 }
490 
491 static void
492 qlnx_mac_addr(qlnx_host_t *ha, qlnx_perm_mac_addr_t *mac_addr)
493 {
494 	bzero(mac_addr->addr, sizeof(mac_addr->addr));
495 	snprintf(mac_addr->addr, sizeof(mac_addr->addr),
496 		"%02x:%02x:%02x:%02x:%02x:%02x",
497 		ha->primary_mac[0], ha->primary_mac[1], ha->primary_mac[2],
498 		ha->primary_mac[3], ha->primary_mac[4], ha->primary_mac[5]);
499 
500 	return;
501 }
502 
503 static int
504 qlnx_get_regs(qlnx_host_t *ha, qlnx_get_regs_t *regs)
505 {
506 	int		i;
507 	int		rval = 0;
508 	uint32_t	dwords = 0;
509 	uint8_t		*outb;
510 
511 	regs->reg_buf_len = 0;
512 	outb = regs->reg_buf;
513 
514 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
515 
516 		rval = qlnx_grc_dump(ha, &dwords, i);
517 
518 		if (rval)
519 			break;
520 
521 		regs->reg_buf_len += (dwords << 2);
522 
523 		rval = copyout(ha->grcdump[i], outb, ha->grcdump_size[i]);
524 
525 		if (rval)
526 			break;
527 
528 		ha->grcdump_dwords[i] = 0;
529 		outb += regs->reg_buf_len;
530 	}
531 
532 	ha->grcdump_taken = 0;
533 
534 	return (rval);
535 }
536 
537 extern char qlnx_name_str[];
538 extern char qlnx_ver_str[];
539 
540 static int
541 qlnx_drv_info(qlnx_host_t *ha, qlnx_drvinfo_t *drv_info)
542 {
543 	int i;
544 
545 	bzero(drv_info, sizeof(qlnx_drvinfo_t));
546 
547 	snprintf(drv_info->drv_name, sizeof(drv_info->drv_name), "%s",
548 		qlnx_name_str);
549 	snprintf(drv_info->drv_version, sizeof(drv_info->drv_version), "%s",
550 		qlnx_ver_str);
551 	snprintf(drv_info->mfw_version, sizeof(drv_info->mfw_version), "%s",
552 		ha->mfw_ver);
553 	snprintf(drv_info->stormfw_version, sizeof(drv_info->stormfw_version),
554 		"%s", ha->stormfw_ver);
555 
556 	drv_info->eeprom_dump_len = ha->flash_size;
557 
558 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
559 		drv_info->reg_dump_len += ha->grcdump_size[i];
560 	}
561 
562 	snprintf(drv_info->bus_info, sizeof(drv_info->bus_info),
563 		"%d:%d:%d", pci_get_bus(ha->pci_dev),
564 		pci_get_slot(ha->pci_dev), ha->pci_func);
565 
566 	return (0);
567 }
568 
569 static int
570 qlnx_dev_settings(qlnx_host_t *ha, qlnx_dev_setting_t *dev_info)
571 {
572 	struct ecore_hwfn *p_hwfn;
573 	struct qlnx_link_output if_link;
574 
575 	p_hwfn = &ha->cdev.hwfns[0];
576 
577 	qlnx_fill_link(p_hwfn, &if_link);
578 
579 	dev_info->supported = if_link.supported_caps;
580 	dev_info->advertising = if_link.advertised_caps;
581 	dev_info->speed = if_link.speed;
582 	dev_info->duplex = if_link.duplex;
583 	dev_info->port = ha->pci_func & 0x1;
584 	dev_info->autoneg = if_link.autoneg;
585 
586 	return (0);
587 }
588 
589 static int
590 qlnx_write_nvram(qlnx_host_t *ha, qlnx_nvram_t *nvram, uint32_t cmd)
591 {
592 	uint8_t *buf;
593 	int ret = 0;
594 
595 	if ((nvram->data == NULL) || (nvram->data_len == 0))
596 		return (EINVAL);
597 
598 	buf = qlnx_zalloc(nvram->data_len);
599 
600 	ret = copyin(nvram->data, buf, nvram->data_len);
601 
602 	QL_DPRINT9(ha, "issue cmd = 0x%x data = %p \
603 		 data_len = 0x%x ret = 0x%x exit\n",
604 		cmd, nvram->data, nvram->data_len, ret);
605 
606 	if (ret == 0) {
607 		ret = ecore_mcp_nvm_write(&ha->cdev, cmd,
608 			nvram->offset, buf, nvram->data_len);
609 	}
610 
611 	QL_DPRINT9(ha, "cmd = 0x%x data = %p \
612 		 data_len = 0x%x resp = 0x%x ret = 0x%x exit\n",
613 		cmd, nvram->data, nvram->data_len, ha->cdev.mcp_nvm_resp, ret);
614 
615 	free(buf, M_QLNXBUF);
616 
617 	return (ret);
618 }
619 
620 static int
621 qlnx_read_nvram(qlnx_host_t *ha, qlnx_nvram_t *nvram)
622 {
623 	uint8_t *buf;
624 	int ret = 0;
625 
626 	if ((nvram->data == NULL) || (nvram->data_len == 0))
627 		return (EINVAL);
628 
629 	buf = qlnx_zalloc(nvram->data_len);
630 
631 	ret = ecore_mcp_nvm_read(&ha->cdev, nvram->offset, buf,
632 		nvram->data_len);
633 
634 	QL_DPRINT9(ha, " data = %p data_len = 0x%x \
635 		 resp = 0x%x ret = 0x%x exit\n",
636 		nvram->data, nvram->data_len, ha->cdev.mcp_nvm_resp, ret);
637 
638 	if (ret == 0) {
639 		ret = copyout(buf, nvram->data, nvram->data_len);
640 	}
641 
642 	free(buf, M_QLNXBUF);
643 
644 	return (ret);
645 }
646 
647 static int
648 qlnx_get_nvram_resp(qlnx_host_t *ha, qlnx_nvram_t *nvram)
649 {
650 	uint8_t *buf;
651 	int ret = 0;
652 
653 	if ((nvram->data == NULL) || (nvram->data_len == 0))
654 		return (EINVAL);
655 
656 	buf = qlnx_zalloc(nvram->data_len);
657 
658 
659 	ret = ecore_mcp_nvm_resp(&ha->cdev, buf);
660 
661 	QL_DPRINT9(ha, "data = %p data_len = 0x%x \
662 		 resp = 0x%x ret = 0x%x exit\n",
663 		nvram->data, nvram->data_len, ha->cdev.mcp_nvm_resp, ret);
664 
665 	if (ret == 0) {
666 		ret = copyout(buf, nvram->data, nvram->data_len);
667 	}
668 
669 	free(buf, M_QLNXBUF);
670 
671 	return (ret);
672 }
673 
674 static int
675 qlnx_nvram(qlnx_host_t *ha, qlnx_nvram_t *nvram)
676 {
677 	int ret = 0;
678 
679 	switch (nvram->cmd) {
680 
681 	case QLNX_NVRAM_CMD_WRITE_NVRAM:
682 		ret = qlnx_write_nvram(ha, nvram, ECORE_NVM_WRITE_NVRAM);
683 		break;
684 
685 	case QLNX_NVRAM_CMD_PUT_FILE_DATA:
686 		ret = qlnx_write_nvram(ha, nvram, ECORE_PUT_FILE_DATA);
687 		break;
688 
689 	case QLNX_NVRAM_CMD_READ_NVRAM:
690 		ret = qlnx_read_nvram(ha, nvram);
691 		break;
692 
693 	case QLNX_NVRAM_CMD_SET_SECURE_MODE:
694 		ret = ecore_mcp_nvm_set_secure_mode(&ha->cdev, nvram->offset);
695 
696 		QL_DPRINT9(ha, "QLNX_NVRAM_CMD_SET_SECURE_MODE \
697 			 resp = 0x%x ret = 0x%x exit\n",
698 			 ha->cdev.mcp_nvm_resp, ret);
699 		break;
700 
701 	case QLNX_NVRAM_CMD_DEL_FILE:
702 		ret = ecore_mcp_nvm_del_file(&ha->cdev, nvram->offset);
703 
704 		QL_DPRINT9(ha, "QLNX_NVRAM_CMD_DEL_FILE \
705 			 resp = 0x%x ret = 0x%x exit\n",
706 			ha->cdev.mcp_nvm_resp, ret);
707 		break;
708 
709 	case QLNX_NVRAM_CMD_PUT_FILE_BEGIN:
710 		ret = ecore_mcp_nvm_put_file_begin(&ha->cdev, nvram->offset);
711 
712 		QL_DPRINT9(ha, "QLNX_NVRAM_CMD_PUT_FILE_BEGIN \
713 			 resp = 0x%x ret = 0x%x exit\n",
714 			ha->cdev.mcp_nvm_resp, ret);
715 		break;
716 
717 	case QLNX_NVRAM_CMD_GET_NVRAM_RESP:
718 		ret = qlnx_get_nvram_resp(ha, nvram);
719 		break;
720 
721 	default:
722 		ret = EINVAL;
723 		break;
724 	}
725 
726 	return (ret);
727 }
728 
729 static void
730 qlnx_storm_stats(qlnx_host_t *ha, qlnx_storm_stats_dump_t *s_stats)
731 {
732 	int i;
733 	int index;
734 	int ret;
735 	int stats_copied = 0;
736 
737 	s_stats->num_hwfns = ha->cdev.num_hwfns;
738 
739 //	if (ha->storm_stats_index < QLNX_STORM_STATS_SAMPLES_PER_HWFN)
740 //		return;
741 
742 	s_stats->num_samples = ha->storm_stats_index;
743 
744 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
745 
746 		index = (QLNX_STORM_STATS_SAMPLES_PER_HWFN * i);
747 
748 		if (s_stats->buffer[i]) {
749 
750 			ret = copyout(&ha->storm_stats[index],
751 					s_stats->buffer[i],
752 					QLNX_STORM_STATS_BYTES_PER_HWFN);
753 			if (ret) {
754 				printf("%s [%d]: failed\n", __func__, i);
755 			}
756 
757 			if (s_stats->num_samples ==
758 				QLNX_STORM_STATS_SAMPLES_PER_HWFN) {
759 
760 				bzero((void *)&ha->storm_stats[i],
761 					QLNX_STORM_STATS_BYTES_PER_HWFN);
762 
763 				stats_copied = 1;
764 			}
765 		}
766 	}
767 
768 	if (stats_copied)
769 		ha->storm_stats_index = 0;
770 
771 	return;
772 }
773 
774 
775 static int
776 qlnx_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
777 	struct thread *td)
778 {
779 	qlnx_host_t	*ha;
780 	int		rval = 0;
781 	struct ifnet	*ifp;
782 	qlnx_trace_t	*trace;
783 	int		i;
784 
785 	if ((ha = (qlnx_host_t *)dev->si_drv1) == NULL)
786 		return ENXIO;
787 
788 	ifp = ha->ifp;
789 
790 	switch (cmd) {
791 
792 	case QLNX_GRC_DUMP_SIZE:
793 		qlnx_get_grc_dump_size(ha, (qlnx_grcdump_t *)data);
794 		break;
795 
796 	case QLNX_GRC_DUMP:
797 		rval = qlnx_get_grc_dump(ha, (qlnx_grcdump_t *)data);
798 		break;
799 
800 	case QLNX_IDLE_CHK_SIZE:
801 		qlnx_get_idle_chk_size(ha, (qlnx_idle_chk_t *)data);
802 		break;
803 
804 	case QLNX_IDLE_CHK:
805 		rval = qlnx_get_idle_chk(ha, (qlnx_idle_chk_t *)data);
806 		break;
807 
808 	case QLNX_DRV_INFO:
809 		rval = qlnx_drv_info(ha, (qlnx_drvinfo_t *)data);
810 		break;
811 
812 	case QLNX_DEV_SETTING:
813 		rval = qlnx_dev_settings(ha, (qlnx_dev_setting_t *)data);
814 		break;
815 
816 	case QLNX_GET_REGS:
817 		rval = qlnx_get_regs(ha, (qlnx_get_regs_t *)data);
818 		break;
819 
820 	case QLNX_NVRAM:
821 		rval = qlnx_nvram(ha, (qlnx_nvram_t *)data);
822 		break;
823 
824 	case QLNX_RD_WR_REG:
825 		rval = qlnx_reg_rd_wr(ha, (qlnx_reg_rd_wr_t *)data);
826 		break;
827 
828 	case QLNX_RD_WR_PCICFG:
829 		rval = qlnx_rd_wr_pci_config(ha, (qlnx_pcicfg_rd_wr_t *)data);
830 		break;
831 
832 	case QLNX_MAC_ADDR:
833 		qlnx_mac_addr(ha, (qlnx_perm_mac_addr_t *)data);
834 		break;
835 
836 	case QLNX_STORM_STATS:
837 		qlnx_storm_stats(ha, (qlnx_storm_stats_dump_t *)data);
838 		break;
839 
840 	case QLNX_TRACE_SIZE:
841 		qlnx_get_trace_size(ha, (qlnx_trace_t *)data);
842 		break;
843 
844 	case QLNX_TRACE:
845 		trace = (qlnx_trace_t *)data;
846 
847 		for (i = 0; i < ha->cdev.num_hwfns; i++) {
848 
849 			if (trace->size[i] && trace->cmd && trace->buffer[i])
850 				rval = qlnx_get_trace(ha, i, trace);
851 
852 			if (rval)
853 				break;
854 		}
855 		break;
856 
857 	default:
858 		rval = EINVAL;
859 		break;
860 	}
861 
862 	return (rval);
863 }
864 
865