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