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