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