qlnx_ioctl.c revision 323213
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: stable/11/sys/dev/qlnx/qlnxe/qlnx_ioctl.c 323213 2017-09-06 07:15:21Z rlibby $");
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
69static int qlnx_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
70                struct thread *td);
71
72static struct cdevsw qlnx_cdevsw = {
73        .d_version = D_VERSION,
74        .d_ioctl = qlnx_eioctl,
75        .d_name = "qlnxioctl",
76};
77
78int
79qlnx_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
97void
98qlnx_del_cdev(qlnx_host_t *ha)
99{
100	if (ha->ioctl_dev != NULL)
101		destroy_dev(ha->ioctl_dev);
102	return;
103}
104
105int
106qlnx_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
143static void
144qlnx_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
156static int
157qlnx_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
194int
195qlnx_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
232static void
233qlnx_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
245static int
246qlnx_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
284static uint32_t
285qlnx_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
339static void
340qlnx_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
353static int
354qlnx_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
429static int
430qlnx_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
465static int
466qlnx_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
491static void
492qlnx_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
503static int
504qlnx_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
537extern char qlnx_name_str[];
538extern char qlnx_ver_str[];
539
540static int
541qlnx_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
569static int
570qlnx_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
589static int
590qlnx_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
620static int
621qlnx_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
647static int
648qlnx_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
674static int
675qlnx_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
729static void
730qlnx_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
775static int
776qlnx_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