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