xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/oce/oce_mbx.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Emulex.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Source file containing the implementation of MBOX
29  * and related helper functions
30  */
31 
32 #include <oce_impl.h>
33 
34 static ddi_dma_attr_t oce_sgl_dma_attr = {
35 	DMA_ATTR_V0,		/* version number */
36 	0x0000000000000000ull,	/* low address */
37 	0xFFFFFFFFFFFFFFFFull,	/* high address */
38 	0x0000000000010000ull,	/* dma counter max */
39 	0x1000,			/* alignment 4K for mbx bufs */
40 	0x1,			/* burst sizes */
41 	0x00000004,		/* minimum transfer size */
42 	0x00000000FFFFFFFFull,	/* maximum transfer size */
43 	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
44 	MAX_MBX_SGE,		/* scatter/gather list length */
45 	0x00000001,		/* granularity */
46 	0			/* DMA flags */
47 };
48 
49 static ddi_device_acc_attr_t oce_sgl_buf_accattr = {
50 	DDI_DEVICE_ATTR_V0,
51 	DDI_NEVERSWAP_ACC,
52 	DDI_STRICTORDER_ACC,
53 };
54 
55 /*
56  * common inline function to fill an ioctl request header
57  *
58  * hdr - pointer to a buffer where the header will be initialized
59  * dom - domain
60  * port - port number
61  * opcode - command code for this MBX
62  * timeout - timeout in seconds
63  * pyld_len - length of the command buffer described by this header
64  *
65  * return none
66  */
67 void
68 mbx_common_req_hdr_init(struct mbx_hdr *hdr,
69     uint8_t dom, uint8_t port,
70     uint8_t subsys, uint8_t opcode,
71     uint32_t timeout, uint32_t pyld_len)
72 {
73 	ASSERT(hdr != NULL);
74 
75 	hdr->u0.req.opcode = opcode;
76 	hdr->u0.req.subsystem = subsys;
77 	hdr->u0.req.port_number = port;
78 	hdr->u0.req.domain = dom;
79 
80 	hdr->u0.req.timeout = timeout;
81 	hdr->u0.req.request_length = pyld_len - sizeof (struct mbx_hdr);
82 } /* mbx_common_req_hdr_init */
83 
84 /*
85  * function to initialize the hw with host endian information
86  *
87  * dev - software handle to the device
88  *
89  * return 0 on success, ETIMEDOUT on failure
90  */
91 int
92 oce_mbox_init(struct oce_dev *dev)
93 {
94 	struct oce_bmbx *mbx;
95 	uint8_t *ptr;
96 	int ret = 0;
97 
98 	ASSERT(dev != NULL);
99 
100 	mbx = (struct oce_bmbx *)DBUF_VA(dev->bmbx);
101 	ptr = (uint8_t *)&mbx->mbx;
102 
103 	/* Endian Signature */
104 	*ptr++ = 0xff;
105 	*ptr++ = 0x12;
106 	*ptr++ = 0x34;
107 	*ptr++ = 0xff;
108 	*ptr++ = 0xff;
109 	*ptr++ = 0x56;
110 	*ptr++ = 0x78;
111 	*ptr   = 0xff;
112 
113 	ret = oce_mbox_dispatch(dev, 0);
114 	if (ret != 0)
115 		oce_log(dev, CE_NOTE, MOD_CONFIG,
116 		    "Failed to set endian %d", ret);
117 
118 	return (ret);
119 } /* oce_mbox_init */
120 
121 /*
122  * function to wait till we get a mbox ready after writing to the
123  * mbox doorbell
124  *
125  * dev - software handle to the device
126  *
127  * return 0=ready, ETIMEDOUT=>not ready but timed out
128  */
129 int
130 oce_mbox_wait(struct oce_dev *dev, uint32_t tmo_sec)
131 {
132 	clock_t tmo = (tmo_sec > 0) ? drv_usectohz(tmo_sec * 1000000) :
133 	    drv_usectohz(DEFAULT_MQ_MBOX_TIMEOUT);
134 	clock_t now, tstamp;
135 	pd_mpu_mbox_db_t mbox_db;
136 
137 	tstamp = ddi_get_lbolt();
138 	do {
139 		now = ddi_get_lbolt();
140 		if ((now - tstamp) >= tmo) {
141 			tmo = 0;
142 			break;
143 		}
144 
145 		mbox_db.dw0 = OCE_DB_READ32(dev, PD_MPU_MBOX_DB);
146 		if (!mbox_db.bits.ready) {
147 			drv_usecwait(5);
148 		} else break;
149 	} while (!mbox_db.bits.ready);
150 
151 	return ((tmo > 0) ? 0 : ETIMEDOUT);
152 } /* oce_mbox_wait */
153 
154 /*
155  * function to dispatch a mailbox command present in the mq mbox
156  *
157  * dev - software handle to the device
158  *
159  * return 0 on success, ETIMEDOUT on failure
160  */
161 int
162 oce_mbox_dispatch(struct oce_dev *dev, uint32_t tmo_sec)
163 {
164 	pd_mpu_mbox_db_t mbox_db;
165 	uint32_t pa;
166 	int ret;
167 
168 	/* write 30 bits of address hi dword */
169 	pa = (uint32_t)(DBUF_PA(dev->bmbx) >> 34);
170 	mbox_db.bits.ready = 0;
171 	mbox_db.bits.hi = 1;
172 	mbox_db.bits.address = pa;
173 
174 	/* wait for mbox ready */
175 	ret = oce_mbox_wait(dev, tmo_sec);
176 	if (ret != 0) {
177 		return (ret);
178 	}
179 
180 	/* ring the doorbell */
181 	OCE_DB_WRITE32(dev, PD_MPU_MBOX_DB, mbox_db.dw0);
182 
183 	/* wait for mbox ready */
184 	ret = oce_mbox_wait(dev, tmo_sec);
185 	if (ret != 0) {
186 		return (ret);
187 	}
188 
189 	/* now write 30 bits of address lo dword */
190 	pa = (uint32_t)(DBUF_PA(dev->bmbx) >> 4) & 0x3fffffff;
191 	mbox_db.bits.ready = 0;
192 	mbox_db.bits.hi = 0;
193 	mbox_db.bits.address = pa;
194 
195 	/* ring the doorbell */
196 	OCE_DB_WRITE32(dev, PD_MPU_MBOX_DB, mbox_db.dw0);
197 
198 	/* wait for mbox ready */
199 	ret = oce_mbox_wait(dev, tmo_sec);
200 	if (ret != 0) {
201 		oce_log(dev, CE_NOTE, MOD_CONFIG,
202 		    "bmbx timed out: %d", ret);
203 		/* if mbx times out, hw is in invalid state */
204 		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
205 		oce_fm_ereport(dev, DDI_FM_DEVICE_INVAL_STATE);
206 	}
207 
208 	return (ret);
209 } /* oce_mbox_dispatch */
210 
211 /*
212  * function to post a MBX to the mbox
213  *
214  * dev - software handle to the device
215  * mbx - pointer to the MBX to send
216  * mbxctx - pointer to the mbx context structure
217  *
218  * return 0 on success, ETIMEDOUT on failure
219  */
220 int
221 oce_mbox_post(struct oce_dev *dev, struct oce_mbx *mbx,
222     struct oce_mbx_ctx *mbxctx)
223 {
224 	struct oce_mbx *mb_mbx = NULL;
225 	struct oce_mq_cqe *mb_cqe = NULL;
226 	struct oce_bmbx *mb = NULL;
227 	int ret = 0;
228 	uint32_t tmo = 0;
229 
230 	mutex_enter(&dev->bmbx_lock);
231 
232 	mb = (struct oce_bmbx *)DBUF_VA(dev->bmbx);
233 	mb_mbx = &mb->mbx;
234 
235 	/* get the tmo */
236 	tmo = mbx->tag[0];
237 	mbx->tag[0] = 0;
238 
239 	/* copy mbx into mbox */
240 	bcopy(mbx, mb_mbx, sizeof (struct oce_mbx));
241 
242 	/* now dispatch */
243 	ret = oce_mbox_dispatch(dev, tmo);
244 	if (ret != 0) {
245 		int fm_status;
246 
247 		oce_log(dev, CE_NOTE, MOD_CONFIG,
248 		    "Failure in mbox dispatch: tag=0x%x:0x%x",
249 		    mbx->tag[0], mbx->tag[1]);
250 
251 		fm_status = oce_fm_check_dma_handle(dev, DBUF_DHDL(dev->bmbx));
252 		if (fm_status != DDI_FM_OK) {
253 			ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
254 			mutex_exit(&dev->bmbx_lock);
255 			return (EIO);
256 		}
257 		mutex_exit(&dev->bmbx_lock);
258 		return (ret);
259 	}
260 
261 	/* sync */
262 	(void) ddi_dma_sync(DBUF_DHDL(dev->bmbx), 0, 0,
263 	    DDI_DMA_SYNC_FORKERNEL);
264 	ret = oce_fm_check_dma_handle(dev, DBUF_DHDL(dev->bmbx));
265 	if (ret != DDI_FM_OK) {
266 		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
267 		mutex_exit(&dev->bmbx_lock);
268 		return (EIO);
269 	}
270 
271 	/*
272 	 * the command completed successfully. Now get the
273 	 * completion queue entry
274 	 */
275 	mb_cqe = &mb->cqe;
276 	DW_SWAP(u32ptr(&mb_cqe->u0.dw[0]), sizeof (struct oce_mq_cqe));
277 
278 	/* check mbox status */
279 	if (mb_cqe->u0.s.completion_status != 0) {
280 		oce_log(dev, CE_WARN, MOD_CONFIG,
281 		    "MBOX Command Failed with Status: %d %d",
282 		    mb_cqe->u0.s.completion_status,
283 		    mb_cqe->u0.s.extended_status);
284 		mutex_exit(&dev->bmbx_lock);
285 		return (EIO);
286 	}
287 
288 	/* copy mbox mbx back */
289 	bcopy(mb_mbx, mbx, sizeof (struct oce_mbx));
290 	/*
291 	 * store the mbx context in the cqe tag section so that
292 	 * the upper layer handling the cqe can associate the mbx
293 	 * with the response
294 	 */
295 	if (mbxctx) {
296 		/* save context */
297 		mbxctx->mbx = mb_mbx;
298 		bcopy(&mbxctx, mb_cqe->u0.s.mq_tag,
299 		    sizeof (struct oce_mbx_ctx *));
300 	}
301 
302 	mutex_exit(&dev->bmbx_lock);
303 	return (0);
304 } /* oce_mbox_post */
305 
306 /*
307  * function to get the firmware version
308  *
309  * dev - software handle to the device
310  *
311  * return 0 on success, EIO on failure
312  */
313 int
314 oce_get_fw_version(struct oce_dev *dev)
315 {
316 	struct oce_mbx mbx;
317 	struct mbx_get_common_fw_version *fwcmd;
318 	int ret = 0;
319 
320 	bzero(&mbx, sizeof (struct oce_mbx));
321 
322 	/* initialize the ioctl header */
323 	fwcmd = (struct mbx_get_common_fw_version *)&mbx.payload;
324 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
325 	    MBX_SUBSYSTEM_COMMON,
326 	    OPCODE_GET_COMMON_FW_VERSION,
327 	    MBX_TIMEOUT_SEC,
328 	    sizeof (struct mbx_get_common_fw_version));
329 
330 	/* fill rest of mbx */
331 	mbx.u0.s.embedded = 1;
332 	mbx.payload_length = sizeof (struct mbx_get_common_fw_version);
333 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
334 
335 	/* now post the command */
336 	ret = oce_mbox_post(dev, &mbx, NULL);
337 
338 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
339 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
340 		oce_log(dev, CE_WARN, MOD_CONFIG,
341 		    "Failed to get firmware version:"
342 		    "CMD COMPLETION STATUS:(%d)"
343 		    "MBX COMMAND  COMPLETION STATUS:(%d)"
344 		    "MBX COMMAND  COMPLETION ADDL STATUS:(%d)",
345 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
346 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
347 		return (ret);
348 	}
349 	bcopy(fwcmd->params.rsp.fw_ver_str, dev->fw_version, 32);
350 
351 	oce_log(dev, CE_NOTE, MOD_CONFIG, "%s %s",
352 	    fwcmd->params.rsp.fw_ver_str,
353 	    fwcmd->params.rsp.fw_on_flash_ver_str);
354 
355 	return (0);
356 } /* oce_get_fw_version */
357 
358 /*
359  * function to invoke f/w reset via. mailbox
360  * does not hold bootstap lock called by quiesce
361  *
362  * dev - software handle to the device
363  *
364  * return 0 on success, ETIMEDOUT on failure
365  *
366  */
367 int
368 oce_reset_fun(struct oce_dev *dev)
369 {
370 	struct oce_mbx *mbx;
371 	struct oce_bmbx *mb;
372 	struct ioctl_common_function_reset *fwcmd;
373 
374 	mb = (struct oce_bmbx *)DBUF_VA(dev->bmbx);
375 	mbx = &mb->mbx;
376 	bzero(mbx, sizeof (struct oce_mbx));
377 	/* initialize the ioctl header */
378 	fwcmd = (struct ioctl_common_function_reset *)&mbx->payload;
379 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
380 	    MBX_SUBSYSTEM_COMMON,
381 	    OPCODE_COMMON_FUNCTION_RESET,
382 	    MBX_TIMEOUT_SEC,
383 	    sizeof (struct ioctl_common_function_reset));
384 
385 	/* fill rest of mbx */
386 	mbx->u0.s.embedded = 1;
387 	mbx->payload_length = sizeof (struct ioctl_common_function_reset);
388 	DW_SWAP(u32ptr(&mbx), mbx->payload_length + OCE_BMBX_RHDR_SZ);
389 
390 	return (oce_mbox_dispatch(dev, 0));
391 } /* oce_reset_fun */
392 
393 /*
394  * function to read the mac address associated with an interface
395  *
396  * dev - software handle to the device
397  * if_id - interface id to read the address from
398  * perm - set to 1 if reading the factory mac address. In this case
399  *	if_id is ignored
400  * type - type of the mac address, whether network or storage
401  * mac - [OUTPUT] pointer to a buffer containing the mac address
402  *	    when the command succeeds
403  *
404  * return 0 on success, EIO on failure
405  */
406 int
407 oce_read_mac_addr(struct oce_dev *dev, uint16_t if_id, uint8_t perm,
408     uint8_t type, struct mac_address_format *mac)
409 {
410 	struct oce_mbx mbx;
411 	struct mbx_query_common_iface_mac *fwcmd;
412 	int ret = 0;
413 
414 	bzero(&mbx, sizeof (struct oce_mbx));
415 	/* initialize the ioctl header */
416 	fwcmd = (struct mbx_query_common_iface_mac *)&mbx.payload;
417 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
418 	    MBX_SUBSYSTEM_COMMON,
419 	    OPCODE_QUERY_COMMON_IFACE_MAC,
420 	    MBX_TIMEOUT_SEC,
421 	    sizeof (struct mbx_query_common_iface_mac));
422 
423 	/* fill the command */
424 	fwcmd->params.req.permanent = perm;
425 	if (perm)
426 		fwcmd->params.req.if_id = if_id;
427 	else
428 		fwcmd->params.req.if_id = 0;
429 	fwcmd->params.req.type = type;
430 
431 	/* fill rest of mbx */
432 	mbx.u0.s.embedded = 1;
433 	mbx.payload_length = sizeof (struct mbx_query_common_iface_mac);
434 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
435 
436 	/* now post the command */
437 	ret = oce_mbox_post(dev, &mbx, NULL);
438 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
439 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
440 		oce_log(dev, CE_WARN, MOD_CONFIG,
441 		    "Failed to read MAC:"
442 		    "CMD COMPLETION STATUS:(%d)"
443 		    "MBX COMMAND  COMPLETION STATUS:(%d)"
444 		    "MBX COMMAND  COMPLETION ADDL STATUS:(%d)",
445 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
446 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
447 		return (ret);
448 	}
449 
450 	/* get the response */
451 	oce_log(dev, CE_NOTE, MOD_CONFIG,
452 	    "MAC addr size = 0x%x",
453 	    LE_16(fwcmd->params.rsp.mac.size_of_struct));
454 	oce_log(dev, CE_NOTE, MOD_CONFIG,
455 	    "MAC_ADDR:0x%x:0x%x:0x%x:0x%x:0x%x:0x%x",
456 	    fwcmd->params.rsp.mac.mac_addr[0],
457 	    fwcmd->params.rsp.mac.mac_addr[1],
458 	    fwcmd->params.rsp.mac.mac_addr[2],
459 	    fwcmd->params.rsp.mac.mac_addr[3],
460 	    fwcmd->params.rsp.mac.mac_addr[4],
461 	    fwcmd->params.rsp.mac.mac_addr[5]);
462 
463 	/* copy the mac addres in the output parameter */
464 	mac->size_of_struct = LE_16(fwcmd->params.rsp.mac.size_of_struct);
465 	bcopy(&fwcmd->params.rsp.mac.mac_addr[0], &mac->mac_addr[0],
466 	    mac->size_of_struct);
467 
468 	return (0);
469 } /* oce_read_mac_addr */
470 
471 /*
472  * function to create an interface using the OPCODE_CREATE_COMMON_IFACE
473  * command
474  *
475  * dev - software handle to the device
476  * cap_flags - capability flags
477  * en_flags - enable capability flags
478  * vlan_tag - optional vlan tag to associate with the if
479  * mac_addr - pointer to a buffer containing the mac address
480  * if_id - [OUTPUT] pointer to an integer to hold the ID of the
481  *	    interface created
482  *
483  * return 0 on success, EIO on failure
484  */
485 int
486 oce_if_create(struct oce_dev *dev, uint32_t cap_flags, uint32_t en_flags,
487     uint16_t vlan_tag, uint8_t *mac_addr,
488     uint32_t *if_id)
489 {
490 	struct oce_mbx mbx;
491 	struct mbx_create_common_iface *fwcmd;
492 	int ret = 0;
493 
494 	bzero(&mbx, sizeof (struct oce_mbx));
495 
496 	/* initialize the ioctl header */
497 	fwcmd = (struct mbx_create_common_iface *)&mbx.payload;
498 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
499 	    MBX_SUBSYSTEM_COMMON,
500 	    OPCODE_CREATE_COMMON_IFACE,
501 	    MBX_TIMEOUT_SEC,
502 	    sizeof (struct mbx_create_common_iface));
503 	DW_SWAP(u32ptr(&fwcmd->hdr), sizeof (struct mbx_hdr));
504 
505 	/* fill the command */
506 	fwcmd->params.req.version   = 0;
507 	fwcmd->params.req.cap_flags = LE_32(cap_flags);
508 	fwcmd->params.req.enable_flags   = LE_32(en_flags);
509 	if (mac_addr != NULL) {
510 		bcopy(mac_addr, &fwcmd->params.req.mac_addr[0],
511 		    ETHERADDRL);
512 		fwcmd->params.req.vlan_tag.u0.normal.vtag = LE_16(vlan_tag);
513 		fwcmd->params.req.mac_invalid = B_FALSE;
514 	} else {
515 		fwcmd->params.req.mac_invalid = B_TRUE;
516 	}
517 
518 	/* fill rest of mbx */
519 	mbx.u0.s.embedded = 1;
520 	mbx.payload_length = sizeof (struct mbx_create_common_iface);
521 	DW_SWAP(u32ptr(&mbx), OCE_BMBX_RHDR_SZ);
522 
523 	/* now post the command */
524 	ret = oce_mbox_post(dev, &mbx, NULL);
525 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
526 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
527 		oce_log(dev, CE_WARN, MOD_CONFIG,
528 		    "Failed to create interface:"
529 		    "CMD COMPLETION STATUS(%d)"
530 		    "MBX COMMAND  COMPLETION STATUS(%d)"
531 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
532 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
533 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
534 		return (ret);
535 	}
536 
537 	/* get response */
538 	*if_id = LE_32(fwcmd->params.rsp.if_id);
539 	oce_log(dev, CE_NOTE, MOD_CONFIG,
540 	    "IF_ID = 0x%x", *if_id);
541 
542 	/* If asked to set mac addr save the pmac handle */
543 	if (mac_addr != NULL) {
544 		dev->pmac_id = LE_32(fwcmd->params.rsp.pmac_id);
545 		oce_log(dev, CE_NOTE, MOD_CONFIG,
546 		    "PMAC_ID = 0x%x", dev->pmac_id);
547 	}
548 	return (0);
549 } /* oce_if_create */
550 
551 /*
552  * function to delete an interface
553  *
554  * dev - software handle to the device
555  * if_id - ID of the interface to delete
556  *
557  * return 0 on success, EIO on failure
558  */
559 int
560 oce_if_del(struct oce_dev *dev, uint32_t if_id)
561 {
562 	struct oce_mbx mbx;
563 	struct mbx_destroy_common_iface *fwcmd;
564 	int ret = 0;
565 
566 	bzero(&mbx, sizeof (struct oce_mbx));
567 	/* initialize the ioctl header */
568 	fwcmd = (struct mbx_destroy_common_iface *)&mbx.payload;
569 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
570 	    MBX_SUBSYSTEM_COMMON,
571 	    OPCODE_DESTROY_COMMON_IFACE,
572 	    MBX_TIMEOUT_SEC,
573 	    sizeof (struct mbx_destroy_common_iface));
574 
575 	/* fill the command */
576 	fwcmd->params.req.if_id = if_id;
577 
578 	/* fill rest of mbx */
579 	mbx.u0.s.embedded = 1;
580 	mbx.payload_length = sizeof (struct mbx_destroy_common_iface);
581 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
582 
583 	/* post the command */
584 	ret = oce_mbox_post(dev, &mbx, NULL);
585 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
586 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
587 		oce_log(dev, CE_WARN, MOD_CONFIG,
588 		    "Failed to delete the interface:"
589 		    "CMD COMPLETION STATUS(%d)"
590 		    "MBX COMMAND  COMPLETION STATUS(%d)"
591 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
592 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
593 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
594 		return (ret);
595 	}
596 	return (0);
597 } /* oce_if_del */
598 
599 /*
600  * function to query the link status from the hardware
601  *
602  * dev - software handle to the device
603  * link_status - [OUT] pointer to the structure returning the link attributes
604  *
605  * return 0 on success, EIO on failure
606  */
607 int
608 oce_get_link_status(struct oce_dev *dev, struct link_status *link)
609 {
610 	struct oce_mbx mbx;
611 	struct mbx_query_common_link_status *fwcmd;
612 	int ret = 0;
613 
614 	bzero(&mbx, sizeof (struct oce_mbx));
615 
616 	/* initialize the ioctl header */
617 	fwcmd = (struct mbx_query_common_link_status *)&mbx.payload;
618 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
619 	    MBX_SUBSYSTEM_COMMON,
620 	    OPCODE_QUERY_COMMON_LINK_STATUS,
621 	    MBX_TIMEOUT_SEC,
622 	    sizeof (struct mbx_query_common_link_status));
623 
624 	/* fill rest of mbx */
625 	mbx.u0.s.embedded = 1;
626 	mbx.payload_length = sizeof (struct mbx_query_common_link_status);
627 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
628 
629 	/* post the command */
630 	ret = oce_mbox_post(dev, &mbx, NULL);
631 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
632 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
633 		oce_log(dev, CE_WARN, MOD_CONFIG,
634 		    "Failed to get the link status:"
635 		    "CMD COMPLETION STATUS(%d)"
636 		    "MBX COMMAND  COMPLETION STATUS(%d)"
637 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
638 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
639 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
640 		return (ret);
641 	}
642 
643 	/* interpret response */
644 	bcopy(&fwcmd->params.rsp, link, 8);
645 	return (0);
646 } /* oce_get_link_status */
647 
648 /*
649  * function to configure the rx filter on the interface
650  *
651  * dev - software handle to the device
652  * filter - mbx command containing the filter parameters
653  *
654  * return 0 on success, EIO on failure
655  */
656 int
657 oce_set_rx_filter(struct oce_dev *dev,
658     struct mbx_set_common_ntwk_rx_filter *filter)
659 {
660 	struct oce_mbx mbx;
661 	struct mbx_set_common_ntwk_rx_filter *fwcmd;
662 	int ret;
663 
664 	bzero(&mbx, sizeof (struct oce_mbx));
665 	fwcmd = (struct mbx_set_common_ntwk_rx_filter *)&mbx.payload;
666 	/* fill the command */
667 	bcopy(filter, fwcmd, sizeof (struct mbx_set_common_ntwk_rx_filter));
668 
669 	/* initialize the ioctl header */
670 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
671 	    MBX_SUBSYSTEM_COMMON,
672 	    OPCODE_COMMON_NTWK_RX_FILTER,
673 	    MBX_TIMEOUT_SEC,
674 	    sizeof (struct mbx_set_common_ntwk_rx_filter));
675 
676 	/* fill rest of mbx */
677 	mbx.u0.s.embedded = 1;
678 	mbx.payload_length = sizeof (struct mbx_set_common_ntwk_rx_filter);
679 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
680 
681 	/* post the command */
682 	ret = oce_mbox_post(dev, &mbx, NULL);
683 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
684 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
685 		oce_log(dev, CE_WARN, MOD_CONFIG,
686 		    "Failed to set rx filter:"
687 		    "CMD COMPLETION STATUS(%d)"
688 		    "MBX COMMAND  COMPLETION STATUS(%d)"
689 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
690 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
691 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
692 		return (ret);
693 	}
694 
695 	return (0);
696 } /* oce_set_rx_filter */
697 
698 /*
699  * function to send the mbx command to update the mcast table with fw
700  *
701  * dev - software handle to the device
702  * mca_table - array of mcast address to update
703  * mca_cnt - number of elements in mca_table
704  * enable_promisc - flag to enable/disable mcast-promiscuous mode
705  *
706  * return 0 on success, EIO on failure
707  */
708 int
709 oce_set_multicast_table(struct oce_dev *dev, struct ether_addr *mca_table,
710     uint8_t mca_cnt, boolean_t enable_promisc)
711 {
712 	struct oce_mbx mbx;
713 	struct  mbx_set_common_iface_multicast *fwcmd;
714 	int ret;
715 
716 	bzero(&mbx, sizeof (struct oce_mbx));
717 	fwcmd = (struct mbx_set_common_iface_multicast *)&mbx.payload;
718 
719 	/* initialize the ioctl header */
720 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
721 	    MBX_SUBSYSTEM_COMMON,
722 	    OPCODE_SET_COMMON_IFACE_MULTICAST,
723 	    MBX_TIMEOUT_SEC,
724 	    sizeof (struct mbx_set_common_iface_multicast));
725 
726 	/* fill the command */
727 	bcopy(mca_table, &fwcmd->params.req.mac[0], mca_cnt * ETHERADDRL);
728 	fwcmd->params.req.if_id = (uint8_t)dev->if_id;
729 	fwcmd->params.req.num_mac = LE_16(mca_cnt);
730 	fwcmd->params.req.promiscuous = (uint8_t)enable_promisc;
731 
732 	/* fill rest of mbx */
733 	mbx.u0.s.embedded = B_TRUE;
734 	mbx.payload_length = sizeof (struct mbx_set_common_iface_multicast);
735 	/* Swap only MBX header + BOOTSTRAP HDR */
736 	DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + OCE_MBX_RRHDR_SZ));
737 
738 	/* post the command */
739 	ret = oce_mbox_post(dev, &mbx, NULL);
740 	/* Check command req and mbx status */
741 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
742 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
743 		oce_log(dev, CE_WARN, MOD_CONFIG,
744 		    "Failed to set multicast table:"
745 		    "CMD COMPLETION STATUS(%d)"
746 		    "MBX COMMAND  COMPLETION STATUS(%d)"
747 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
748 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
749 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
750 		return (ret);
751 	}
752 	return (0);
753 } /* oce_set_multicast_table */
754 
755 /*
756  * function to query the fw attributes from the hw
757  *
758  * dev - software handle to the device
759  *
760  * return 0 on success, EIO on failure
761  */
762 int
763 oce_get_fw_config(struct oce_dev *dev)
764 {
765 	struct oce_mbx mbx;
766 	struct mbx_common_query_fw_config *fwcmd;
767 	int ret = 0;
768 
769 	bzero(&mbx, sizeof (struct oce_mbx));
770 	/* initialize the ioctl header */
771 	fwcmd = (struct mbx_common_query_fw_config *)&mbx.payload;
772 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
773 	    MBX_SUBSYSTEM_COMMON,
774 	    OPCODE_QUERY_COMMON_FIRMWARE_CONFIG,
775 	    MBX_TIMEOUT_SEC,
776 	    sizeof (struct mbx_common_query_fw_config));
777 
778 	/* fill rest of mbx */
779 	mbx.u0.s.embedded = 1;
780 	mbx.payload_length = sizeof (struct mbx_common_query_fw_config);
781 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
782 
783 	/* now post the command */
784 	ret = oce_mbox_post(dev, &mbx, NULL);
785 	/* Check the mailbox return status and mbx command response status */
786 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
787 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
788 		oce_log(dev, CE_WARN, MOD_CONFIG,
789 		    "Failed to get firmware configuration:"
790 		    "CMD COMPLETION STATUS(%d)"
791 		    "MBX COMMAND  COMPLETION STATUS(%d)"
792 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
793 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
794 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
795 		return (ret);
796 	}
797 
798 	/* swap and copy into buffer */
799 	DW_SWAP(u32ptr(fwcmd), sizeof (struct mbx_common_query_fw_config));
800 
801 	dev->config_number = fwcmd->params.rsp.config_number;
802 	dev->asic_revision = fwcmd->params.rsp.asic_revision;
803 	dev->port_id = fwcmd->params.rsp.port_id;
804 	dev->function_mode = fwcmd->params.rsp.function_mode;
805 
806 	return (0);
807 } /* oce_get_fw_config */
808 
809 /*
810  * function to retrieve statistic counters from the hardware
811  *
812  * dev - software handle to the device
813  *
814  * return 0 on success, EIO on failure
815  */
816 int
817 oce_get_hw_stats(struct oce_dev *dev)
818 {
819 	struct oce_mbx mbx;
820 	struct mbx_get_nic_stats *fwcmd = dev->hw_stats;
821 	int ret = 0;
822 
823 	bzero(&mbx, sizeof (struct oce_mbx));
824 	/* initialize the ioctl header */
825 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
826 	    MBX_SUBSYSTEM_NIC,
827 	    OPCODE_GET_NIC_STATS,
828 	    MBX_TIMEOUT_SEC,
829 	    sizeof (struct mbx_get_nic_stats));
830 	DW_SWAP(u32ptr(fwcmd), sizeof (struct mbx_get_nic_stats));
831 
832 	/* fill rest of mbx */
833 	mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(DBUF_PA(dev->stats_dbuf));
834 	mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(DBUF_PA(dev->stats_dbuf));
835 	mbx.payload.u0.u1.sgl[0].length = sizeof (struct mbx_get_nic_stats);
836 	mbx.payload_length = sizeof (struct mbx_get_nic_stats);
837 
838 	mbx.u0.s.embedded = 0;
839 	mbx.u0.s.sge_count = 1;
840 
841 	DW_SWAP(u32ptr(&mbx), sizeof (struct oce_mq_sge) + OCE_BMBX_RHDR_SZ);
842 
843 	/* now post the command */
844 	ret = oce_mbox_post(dev, &mbx, NULL);
845 	/* Check the mailbox status and command completion status */
846 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
847 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
848 		oce_log(dev, CE_WARN, MOD_CONFIG,
849 		    "Failed to get hardware status:"
850 		    "CMD COMPLETION STATUS(%d)"
851 		    "MBX COMMAND  COMPLETION STATUS(%d)"
852 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
853 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
854 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
855 		return (ret);
856 	}
857 
858 	DW_SWAP(u32ptr(dev->hw_stats), sizeof (struct mbx_get_nic_stats));
859 	return (0);
860 } /* oce_get_hw_stats */
861 
862 /*
863  * function to set the number of vectors with the cev
864  *
865  * dev - software handle to the device
866  * num_vectors - number of MSI messages
867  *
868  * return 0 on success, EIO on failure
869  */
870 int
871 oce_num_intr_vectors_set(struct oce_dev *dev, uint32_t num_vectors)
872 {
873 	struct oce_mbx mbx;
874 	struct mbx_common_cev_modify_msi_messages *fwcmd;
875 	int ret = 0;
876 
877 	bzero(&mbx, sizeof (struct oce_mbx));
878 	/* initialize the ioctl header */
879 	fwcmd = (struct mbx_common_cev_modify_msi_messages *)&mbx.payload;
880 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
881 	    MBX_SUBSYSTEM_COMMON,
882 	    OPCODE_COMMON_CEV_MODIFY_MSI_MESSAGES,
883 	    MBX_TIMEOUT_SEC,
884 	    sizeof (struct mbx_common_cev_modify_msi_messages));
885 
886 	/* fill the command */
887 	fwcmd->params.req.num_msi_msgs = LE_32(num_vectors);
888 
889 	/* fill rest of mbx */
890 	mbx.u0.s.embedded = 1;
891 	mbx.payload_length =
892 	    sizeof (struct mbx_common_cev_modify_msi_messages);
893 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
894 
895 	/* post the command */
896 	ret = oce_mbox_post(dev, &mbx, NULL);
897 	/* Check the mailbox status and command completion status */
898 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
899 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
900 		oce_log(dev, CE_WARN, MOD_CONFIG,
901 		    "Failed to set interrupt vectors:"
902 		    "CMD COMPLETION STATUS(%d)"
903 		    "MBX COMMAND  COMPLETION STATUS(%d)"
904 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
905 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
906 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
907 		return (ret);
908 	}
909 
910 	return (0);
911 } /* oce_num_intr_vectors_set */
912 
913 /*
914  * function to set flow control capability in the hardware
915  *
916  * dev - software handle to the device
917  * flow_control - flow control flags to set
918  *
919  * return 0 on success, EIO on failure
920  */
921 int
922 oce_set_flow_control(struct oce_dev *dev, uint32_t flow_control)
923 {
924 	struct oce_mbx mbx;
925 	struct mbx_common_get_set_flow_control *fwcmd =
926 	    (struct mbx_common_get_set_flow_control *)&mbx.payload;
927 	int ret;
928 
929 	bzero(&mbx, sizeof (struct oce_mbx));
930 	/* initialize the ioctl header */
931 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
932 	    MBX_SUBSYSTEM_COMMON,
933 	    OPCODE_SET_COMMON_FLOW_CONTROL,
934 	    MBX_TIMEOUT_SEC,
935 	    sizeof (struct mbx_common_get_set_flow_control));
936 
937 	/* fill command */
938 	if (flow_control & OCE_FC_TX)
939 		fwcmd->tx_flow_control = 1;
940 
941 	if (flow_control & OCE_FC_RX)
942 		fwcmd->rx_flow_control = 1;
943 
944 	/* fill rest of mbx */
945 	mbx.u0.s.embedded = 1;
946 	mbx.payload_length = sizeof (struct mbx_common_get_set_flow_control);
947 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
948 
949 	/* post the command */
950 	ret = oce_mbox_post(dev, &mbx, NULL);
951 
952 	/* Check the command completion and mbx response status */
953 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
954 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
955 		oce_log(dev, CE_WARN, MOD_CONFIG,
956 		    "Failed to set flow control:"
957 		    "CMD COMPLETION STATUS(%d)"
958 		    "MBX COMMAND  COMPLETION STATUS(%d)"
959 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
960 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
961 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
962 		return (ret);
963 	}
964 
965 	return (0);
966 } /* oce_set_flow_control */
967 
968 /*
969  * function to get the current flow control setting with the hardware
970  *
971  * dev - software handle to the device
972  * flow_control - [OUT] pointer to location where flow_control setting
973  * is returned
974  *
975  * return 0 on success, EIO on failure
976  */
977 int
978 oce_get_flow_control(struct oce_dev *dev, uint32_t *flow_control)
979 {
980 	struct oce_mbx mbx;
981 	struct mbx_common_get_set_flow_control *fwcmd;
982 	int ret;
983 
984 	DEV_LOCK(dev);
985 	if (dev->suspended) {
986 		DEV_UNLOCK(dev);
987 		return (EIO);
988 	}
989 	DEV_UNLOCK(dev);
990 
991 	bzero(&mbx, sizeof (struct oce_mbx));
992 	fwcmd = (struct mbx_common_get_set_flow_control *)&mbx.payload;
993 
994 	/* initialize the ioctl header */
995 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
996 	    MBX_SUBSYSTEM_COMMON,
997 	    OPCODE_GET_COMMON_FLOW_CONTROL,
998 	    MBX_TIMEOUT_SEC,
999 	    sizeof (struct mbx_common_get_set_flow_control));
1000 
1001 	/* fill rest of mbx */
1002 	mbx.u0.s.embedded = 1;
1003 	mbx.payload_length = sizeof (struct mbx_common_get_set_flow_control);
1004 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1005 
1006 	/* post the command */
1007 	ret = oce_mbox_post(dev, &mbx, NULL);
1008 
1009 	/* Check the command completion and mbx response status */
1010 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
1011 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
1012 		oce_log(dev, CE_WARN, MOD_CONFIG,
1013 		    "Failed to get flow control value:"
1014 		    "CMD COMPLETION STATUS(%d)"
1015 		    "MBX COMMAND  COMPLETION STATUS(%d)"
1016 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
1017 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
1018 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
1019 		return (ret);
1020 	}
1021 
1022 	/* get the flow control */
1023 	DW_SWAP(u32ptr(fwcmd),
1024 	    sizeof (struct mbx_common_get_set_flow_control));
1025 	*flow_control = 0;
1026 	if (fwcmd->tx_flow_control)
1027 		*flow_control |= OCE_FC_TX;
1028 
1029 	if (fwcmd->rx_flow_control)
1030 		*flow_control |= OCE_FC_RX;
1031 
1032 	return (0);
1033 } /* oce_get_flow_control */
1034 
1035 /*
1036  * function to enable/disable device promiscuous mode
1037  *
1038  * dev - software handle to the device
1039  * enable - enable/disable flag
1040  *
1041  * return 0 on success, EIO on failure
1042  */
1043 int
1044 oce_set_promiscuous(struct oce_dev *dev, boolean_t enable)
1045 {
1046 	struct oce_mbx mbx;
1047 	struct mbx_config_nic_promiscuous *fwcmd;
1048 	int ret;
1049 
1050 	bzero(&mbx, sizeof (struct oce_mbx));
1051 
1052 	fwcmd = (struct mbx_config_nic_promiscuous *)&mbx.payload;
1053 
1054 	if (dev->port_id == 0) {
1055 		fwcmd->params.req.port0_promisc = (uint8_t)enable;
1056 
1057 	} else {
1058 		fwcmd->params.req.port1_promisc = (uint8_t)enable;
1059 	}
1060 
1061 	/* initialize the ioctl header */
1062 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1063 	    MBX_SUBSYSTEM_NIC,
1064 	    OPCODE_CONFIG_NIC_PROMISCUOUS,
1065 	    MBX_TIMEOUT_SEC,
1066 	    sizeof (struct mbx_config_nic_promiscuous));
1067 	/* fill rest of mbx */
1068 	mbx.u0.s.embedded = 1;
1069 	mbx.payload_length = sizeof (struct mbx_config_nic_promiscuous);
1070 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1071 
1072 	/* post the command */
1073 	ret = oce_mbox_post(dev, &mbx, NULL);
1074 
1075 	/* Check the command completion and mbx response status */
1076 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
1077 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
1078 		oce_log(dev, CE_WARN, MOD_CONFIG,
1079 		    "Failed to change promiscuous setting:"
1080 		    "CMD COMPLETION STATUS(%d)"
1081 		    "MBX COMMAND  COMPLETION STATUS(%d)"
1082 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
1083 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
1084 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
1085 		return (ret);
1086 	}
1087 	return (0);
1088 }
1089 
1090 /*
1091  * function to add a unicast address to an interface
1092  *
1093  * dev - software handle to the device
1094  * mac - unicast address
1095  *
1096  * return 0 on success, EIO on failure
1097  */
1098 int
1099 oce_add_mac(struct oce_dev *dev, const uint8_t *mac, uint32_t *pmac_id)
1100 {
1101 	struct oce_mbx mbx;
1102 	struct mbx_add_common_iface_mac *fwcmd;
1103 	int ret;
1104 
1105 	bzero(&mbx, sizeof (struct oce_mbx));
1106 	fwcmd = (struct mbx_add_common_iface_mac *)&mbx.payload;
1107 	fwcmd->params.req.if_id = LE_32(dev->if_id);
1108 	bcopy(mac, &fwcmd->params.req.mac_address[0], ETHERADDRL);
1109 
1110 	/* initialize the ioctl header */
1111 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1112 	    MBX_SUBSYSTEM_COMMON,
1113 	    OPCODE_ADD_COMMON_IFACE_MAC,
1114 	    MBX_TIMEOUT_SEC,
1115 	    sizeof (struct mbx_add_common_iface_mac));
1116 
1117 	/* fill rest of mbx */
1118 	mbx.u0.s.embedded = 1;
1119 	mbx.payload_length = sizeof (struct mbx_add_common_iface_mac);
1120 	DW_SWAP(u32ptr(&mbx), OCE_BMBX_RHDR_SZ + OCE_MBX_RRHDR_SZ);
1121 
1122 	/* post the command */
1123 	ret = oce_mbox_post(dev, &mbx, NULL);
1124 
1125 	/* Check the command completion and mbx response status */
1126 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
1127 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
1128 		oce_log(dev, CE_WARN, MOD_CONFIG,
1129 		    "Failed to add MAC:"
1130 		    "CMD COMPLETION STATUS(%d)"
1131 		    "MBX COMMAND  COMPLETION STATUS(%d)"
1132 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
1133 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
1134 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
1135 		return (ret);
1136 	}
1137 	*pmac_id = LE_32(fwcmd->params.rsp.pmac_id);
1138 	return (0);
1139 }
1140 
1141 /*
1142  * function to delete an unicast address associated with an interface
1143  *
1144  * dev - software handle to the device
1145  * pmac_id - handle to the address added using ace_add_mac
1146  *
1147  * return 0 on success, EIO on failure
1148  */
1149 int
1150 oce_del_mac(struct oce_dev *dev,  uint32_t *pmac_id)
1151 {
1152 	struct oce_mbx mbx;
1153 	struct mbx_del_common_iface_mac *fwcmd;
1154 	int ret;
1155 
1156 	bzero(&mbx, sizeof (struct oce_mbx));
1157 	fwcmd = (struct mbx_del_common_iface_mac *)&mbx.payload;
1158 	fwcmd->params.req.if_id = dev->if_id;
1159 	fwcmd->params.req.pmac_id = *pmac_id;
1160 
1161 	/* initialize the ioctl header */
1162 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1163 	    MBX_SUBSYSTEM_COMMON,
1164 	    OPCODE_DEL_COMMON_IFACE_MAC,
1165 	    MBX_TIMEOUT_SEC,
1166 	    sizeof (struct mbx_add_common_iface_mac));
1167 
1168 	/* fill rest of mbx */
1169 	mbx.u0.s.embedded = 1;
1170 	mbx.payload_length = sizeof (struct mbx_del_common_iface_mac);
1171 	DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1172 
1173 	/* post the command */
1174 	ret = oce_mbox_post(dev, &mbx, NULL);
1175 
1176 	/* Check the command completion and mbx response status */
1177 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
1178 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
1179 		oce_log(dev, CE_WARN, MOD_CONFIG,
1180 		    "Failed to delete MAC:"
1181 		    "CMD COMPLETION STATUS(%d)"
1182 		    "MBX COMMAND  COMPLETION STATUS(%d)"
1183 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
1184 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
1185 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
1186 		return (ret);
1187 	}
1188 
1189 	return (0);
1190 }
1191 
1192 
1193 /*
1194  * function to send the mbx command to configure vlan
1195  *
1196  * dev - software handle to the device
1197  * vtag_arr - array of vlan tags
1198  * vtag_cnt - number of elements in array
1199  * untagged - boolean TRUE/FLASE
1200  * enable_promisc - flag to enable/disable VLAN promiscuous mode
1201  *
1202  * return 0 on success, EIO on failure
1203  */
1204 int
1205 oce_config_vlan(struct oce_dev *dev, uint8_t if_id,
1206     struct normal_vlan *vtag_arr, uint8_t vtag_cnt,
1207     boolean_t untagged, boolean_t enable_promisc)
1208 {
1209 	struct oce_mbx mbx;
1210 	struct  mbx_common_config_vlan *fwcmd;
1211 	int ret;
1212 
1213 	bzero(&mbx, sizeof (struct oce_mbx));
1214 	fwcmd = (struct mbx_common_config_vlan *)&mbx.payload;
1215 
1216 	/* initialize the ioctl header */
1217 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1218 	    MBX_SUBSYSTEM_COMMON,
1219 	    OPCODE_CONFIG_COMMON_IFACE_VLAN,
1220 	    MBX_TIMEOUT_SEC,
1221 	    sizeof (struct mbx_common_config_vlan));
1222 
1223 	fwcmd->params.req.if_id	= if_id;
1224 	fwcmd->params.req.promisc = (uint8_t)enable_promisc;
1225 	fwcmd->params.req.untagged = (uint8_t)untagged;
1226 	fwcmd->params.req.num_vlans = vtag_cnt;
1227 
1228 	/* Set the vlan tag filter on hw */
1229 	if (!enable_promisc) {
1230 		bcopy(fwcmd->params.req.tags.normal_vlans, vtag_arr,
1231 		    vtag_cnt * sizeof (struct normal_vlan));
1232 	}
1233 
1234 	/* fill rest of mbx */
1235 	mbx.u0.s.embedded = B_TRUE;
1236 	mbx.payload_length = sizeof (struct mbx_common_config_vlan);
1237 	DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + mbx.payload_length));
1238 
1239 	/* post the command */
1240 	ret = oce_mbox_post(dev, &mbx, NULL);
1241 
1242 	/* Check command req and mbx status */
1243 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
1244 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
1245 		oce_log(dev, CE_WARN, MOD_CONFIG,
1246 		    "Failed to configure VLAN:"
1247 		    "CMD COMPLETION STATUS(%d)"
1248 		    "MBX COMMAND  COMPLETION STATUS(%d)"
1249 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
1250 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
1251 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
1252 		return (ret);
1253 	}
1254 	return (0);
1255 } /* oce_config_vlan */
1256 
1257 
1258 /*
1259  * function to enable or disable the link
1260  *
1261  * dev - software handle to the device
1262  * mca_table - array of mcast address to update
1263  * mca_cnt - number of elements in mca_table
1264  * enable_promisc - flag to enable/disable mcast-promiscuous mode
1265  *
1266  * return 0 on success, EIO on failure
1267  */
1268 int
1269 oce_config_link(struct oce_dev *dev, boolean_t enable)
1270 {
1271 	struct oce_mbx mbx;
1272 	struct  mbx_common_func_link_cfg *fwcmd;
1273 	int ret;
1274 
1275 	bzero(&mbx, sizeof (struct oce_mbx));
1276 	fwcmd = (struct mbx_common_func_link_cfg *)&mbx.payload;
1277 
1278 	/* initialize the ioctl header */
1279 	mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1280 	    MBX_SUBSYSTEM_COMMON,
1281 	    OPCODE_COMMON_FUNCTION_LINK_CONFIG,
1282 	    MBX_TIMEOUT_SEC,
1283 	    sizeof (struct mbx_common_config_vlan));
1284 
1285 	fwcmd->params.req.enable = enable;
1286 
1287 	/* fill rest of mbx */
1288 	mbx.u0.s.embedded = B_TRUE;
1289 	mbx.payload_length = sizeof (struct mbx_common_func_link_cfg);
1290 	DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + mbx.payload_length));
1291 
1292 	/* post the command */
1293 	ret = oce_mbox_post(dev, &mbx, NULL);
1294 
1295 	/* Check command req and mbx status */
1296 	if ((ret != 0) || OCE_MBX_STATUS(&fwcmd->hdr) != 0 ||
1297 	    OCE_MBX_ADDL_STATUS(&fwcmd->hdr) != 0) {
1298 		oce_log(dev, CE_WARN, MOD_CONFIG,
1299 		    "Failed to configure the link:"
1300 		    "CMD COMPLETION STATUS(%d)"
1301 		    "MBX COMMAND  COMPLETION STATUS(%d)"
1302 		    "MBX COMMAND  COMPLETION ADDL STATUS(%d)",
1303 		    ret, OCE_MBX_STATUS(&fwcmd->hdr),
1304 		    OCE_MBX_ADDL_STATUS(&fwcmd->hdr));
1305 		return (ret);
1306 	}
1307 	return (0);
1308 } /* oce_config_link */
1309 
1310 
1311 /*
1312  * function called from the gld ioctl entry point to send a mbx to fw
1313  *
1314  * dev - software handle to the device
1315  * mp - mblk_t containing the user data
1316  * payload_len = [OUT] pointer to return the length of the payload written
1317  *
1318  * return 0 on Success
1319  */
1320 int
1321 oce_issue_mbox(struct oce_dev *dev, queue_t *wq, mblk_t *mp,
1322     uint32_t *payload_len)
1323 {
1324 	int ret;
1325 	struct oce_mbx mbx;
1326 	struct mbx_hdr hdr;
1327 	ddi_dma_handle_t dma_handle;
1328 	boolean_t is_embedded = B_FALSE;
1329 	uint32_t payload_length;
1330 	int num_buf = 0;
1331 	int alloc_len;
1332 	caddr_t sg_va;
1333 	ddi_acc_handle_t acc_handle;
1334 	size_t actual_len;
1335 
1336 	_NOTE(ARGUNUSED(wq));
1337 
1338 	bzero(&mbx, sizeof (struct oce_mbx));
1339 
1340 	bcopy(mp->b_cont->b_rptr, &hdr, sizeof (struct mbx_hdr));
1341 	DW_SWAP(u32ptr(&hdr), sizeof (struct mbx_hdr));
1342 
1343 	payload_length = hdr.u0.req.request_length +
1344 	    sizeof (struct mbx_hdr);
1345 
1346 	is_embedded = (payload_length <= sizeof (struct oce_mbx_payload));
1347 
1348 	alloc_len = MBLKL(mp->b_cont);
1349 
1350 	oce_log(dev, CE_NOTE, MOD_CONFIG, "Mailbox: "
1351 	    "DW[0] 0x%x DW[1] 0x%x DW[2]0x%x DW[3]0x%x,"
1352 	    "MBLKL(%lu)  ALLOCLEN(%d)",
1353 	    hdr.u0.dw[0], hdr.u0.dw[1],
1354 	    hdr.u0.dw[2], hdr.u0.dw[3],
1355 	    MBLKL(mp->b_cont), alloc_len);
1356 
1357 	if (hdr.u0.req.opcode == OPCODE_WRITE_COMMON_FLASHROM) {
1358 		struct mbx_common_read_write_flashrom *fwcmd =
1359 		    (struct mbx_common_read_write_flashrom *)
1360 		    mp->b_cont->b_rptr;
1361 
1362 		if (dev->cookie != 0 && dev->cookie != hdr.u0.req.rsvd0)
1363 			return (EINVAL);
1364 
1365 		if (dev->cookie == 0)
1366 			dev->cookie = hdr.u0.req.rsvd0;
1367 		hdr.u0.req.rsvd0 = 0;
1368 
1369 		/* get the timeout from the command header */
1370 		mbx.tag[0] = hdr.u0.req.timeout;
1371 
1372 		oce_log(dev, CE_NOTE, MOD_CONFIG, "Mailbox params:"
1373 		    "OPCODE(%d) OPTYPE = %d  SIZE = %d  OFFSET = %d",
1374 		    fwcmd->flash_op_code, fwcmd->flash_op_type,
1375 		    fwcmd->data_buffer_size, fwcmd->data_offset);
1376 	}
1377 
1378 	if (!is_embedded) {
1379 		mblk_t *mp_w = mp->b_cont;
1380 		ddi_dma_cookie_t cookie;
1381 		uint32_t count = 0;
1382 
1383 		/* allocate dma handle */
1384 		ret = ddi_dma_alloc_handle(dev->dip,
1385 		    &oce_sgl_dma_attr, DDI_DMA_DONTWAIT, NULL,
1386 		    &dma_handle);
1387 		if (ret != DDI_SUCCESS) {
1388 			oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
1389 			    "Failed to alloc DMA handle");
1390 			ret = ENOMEM;
1391 			goto fail;
1392 		}
1393 
1394 		/* allocate the DMA-able memory */
1395 		ret = ddi_dma_mem_alloc(dma_handle, alloc_len,
1396 		    &oce_sgl_buf_accattr,
1397 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1398 		    DDI_DMA_DONTWAIT,
1399 		    NULL, &sg_va, &actual_len, &acc_handle);
1400 		if (ret != DDI_SUCCESS) {
1401 			oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
1402 			    "Failed to alloc DMA memory");
1403 			ret = ENOMEM;
1404 			goto dma_alloc_fail;
1405 		}
1406 
1407 		bcopy((caddr_t)mp_w->b_rptr, sg_va, MBLKL(mp->b_cont));
1408 
1409 		/* bind mblk mem to handle */
1410 		ret = ddi_dma_addr_bind_handle(
1411 		    dma_handle,
1412 		    (struct as *)0, sg_va,
1413 		    MBLKL(mp_w),
1414 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1415 		    DDI_DMA_DONTWAIT, NULL, &cookie, &count);
1416 		if (ret != DDI_DMA_MAPPED) {
1417 			ret = ENOMEM;
1418 			oce_log(dev, CE_NOTE, MOD_CONFIG,
1419 			    "Failed to bind DMA handle ret code: %d",
1420 			    ret);
1421 			goto dma_bind_fail;
1422 		}
1423 
1424 		for (num_buf = 0; num_buf < count; num_buf++) {
1425 			/* fill the mbx sglist */
1426 			mbx.payload.u0.u1.sgl[num_buf].pa_lo =
1427 			    ADDR_LO(cookie.dmac_laddress);
1428 			mbx.payload.u0.u1.sgl[num_buf].pa_hi =
1429 			    ADDR_HI(cookie.dmac_laddress);
1430 			mbx.payload.u0.u1.sgl[num_buf].length =
1431 			    (uint32_t)cookie.dmac_size;
1432 			mbx.payload_length +=
1433 			    mbx.payload.u0.u1.sgl[num_buf].length;
1434 			mbx.u0.s.sge_count++;
1435 
1436 			if (count > 1)
1437 				(void) ddi_dma_nextcookie(dma_handle, &cookie);
1438 		}
1439 		mbx.u0.s.embedded = 0;
1440 
1441 		DW_SWAP(u32ptr(&mbx), OCE_BMBX_RHDR_SZ +
1442 		    (sizeof (struct oce_mq_sge) * count));
1443 	} else {
1444 		/* fill rest of mbx */
1445 		mbx.u0.s.embedded = 1;
1446 		mbx.payload_length = payload_length;
1447 		bcopy(mp->b_cont->b_rptr, &mbx.payload, payload_length);
1448 
1449 		DW_SWAP(u32ptr(&mbx), OCE_BMBX_RHDR_SZ);
1450 	}
1451 
1452 	/* now post the command */
1453 	ret = oce_mbox_post(dev, &mbx, NULL);
1454 
1455 	bcopy(mp->b_cont->b_rptr, &hdr, sizeof (struct mbx_hdr));
1456 	DW_SWAP(u32ptr(&hdr), sizeof (struct mbx_hdr));
1457 
1458 	if (ret != DDI_SUCCESS) {
1459 		oce_log(dev, CE_WARN, MOD_CONFIG,
1460 		    "Failed to post the mailbox: %d", ret);
1461 
1462 		*payload_len = hdr.u0.rsp.rsp_length +
1463 		    sizeof (struct mbx_hdr);
1464 		if (is_embedded) {
1465 			bcopy(&mbx.payload, mp->b_cont->b_rptr,
1466 			    MBLKL(mp->b_cont));
1467 			goto fail;
1468 		} else {
1469 			(void) ddi_dma_sync(dma_handle, 0, 0,
1470 			    DDI_DMA_SYNC_FORKERNEL);
1471 			bcopy(sg_va, mp->b_cont->b_rptr,
1472 			    sizeof (struct mbx_hdr));
1473 			goto post_fail;
1474 		}
1475 	}
1476 
1477 	if (hdr.u0.req.opcode == OPCODE_WRITE_COMMON_FLASHROM) {
1478 		struct mbx_common_read_write_flashrom *fwcmd =
1479 		    (struct mbx_common_read_write_flashrom *)
1480 		    mp->b_cont->b_rptr;
1481 
1482 		if (LE_32(fwcmd->flash_op_code) == MGMT_FLASHROM_OPCODE_FLASH)
1483 			dev->cookie = 0;
1484 	}
1485 
1486 	payload_length = hdr.u0.rsp.rsp_length + sizeof (struct mbx_hdr);
1487 
1488 	/* Copy the response back only if this is an embedded mbx cmd */
1489 	if (is_embedded) {
1490 		bcopy(&mbx.payload, mp->b_cont->b_rptr,
1491 		    min(payload_length, MBLKL(mp->b_cont)));
1492 	} else {
1493 		/* sync */
1494 		(void) ddi_dma_sync(dma_handle, 0, 0,
1495 		    DDI_DMA_SYNC_FORKERNEL);
1496 
1497 		/* copy back from kernel allocated buffer to user buffer  */
1498 		bcopy(sg_va, mp->b_cont->b_rptr, MBLKL(mp->b_cont));
1499 
1500 		/* unbind and free dma handles */
1501 		(void) ddi_dma_unbind_handle(dma_handle);
1502 		ddi_dma_mem_free(&acc_handle);
1503 		ddi_dma_free_handle(&dma_handle);
1504 	}
1505 
1506 	*payload_len = payload_length;
1507 
1508 	return (0);
1509 
1510 post_fail:
1511 	(void) ddi_dma_unbind_handle(dma_handle);
1512 
1513 dma_bind_fail:
1514 	ddi_dma_mem_free(&acc_handle);
1515 
1516 dma_alloc_fail:
1517 	ddi_dma_free_handle(&dma_handle);
1518 
1519 fail:
1520 alloc_err:
1521 	if (hdr.u0.req.opcode == OPCODE_WRITE_COMMON_FLASHROM) {
1522 		dev->cookie = 0;
1523 	}
1524 	return (ret);
1525 }
1526