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