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