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