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