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