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