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
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
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
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
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
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
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
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
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],
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
|
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],
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 }
|