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