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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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