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