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