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