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