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