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 (c) 2009-2012 Emulex. All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 
  29 /*
  30  * Source file containing the implementation of MBOX
  31  * and related helper functions
  32  */
  33 
  34 #include <oce_impl.h>
  35 
  36 extern int pow10[];
  37 
  38 static ddi_dma_attr_t oce_sgl_dma_attr = {
  39         DMA_ATTR_V0,            /* version number */
  40         0x0000000000000000ull,  /* low address */
  41         0xFFFFFFFFFFFFFFFFull,  /* high address */
  42         0x0000000000010000ull,  /* dma counter max */
  43         0x1000,                 /* alignment 4K for mbx bufs */
  44         0x1,                    /* burst sizes */
  45         0x00000004,             /* minimum transfer size */
  46         0x00000000FFFFFFFFull,  /* maximum transfer size */
  47         0xFFFFFFFFFFFFFFFFull,  /* maximum segment size */
  48         MAX_MBX_SGE,            /* scatter/gather list length */
  49         0x00000001,             /* granularity */
  50         0                       /* DMA flags */
  51 };
  52 
  53 static int oce_mbox_issue_bootstrap(struct oce_dev *dev, struct oce_mbx *mbx,
  54     uint32_t tmo_sec);
  55 static uint32_t oce_enqueue_mq_mbox(struct oce_dev *dev, struct oce_mbx *mbx,
  56     uint32_t tmo_sec);
  57 static struct oce_mbx_ctx *oce_init_mq_ctx(struct oce_dev *dev,
  58     struct oce_mbx *mbx);
  59 static void oce_destroy_mq_ctx(struct oce_mbx_ctx *mbctx);
  60 
  61 /*
  62  * common inline function to fill an ioctl request header
  63  *
  64  * hdr - pointer to a buffer where the header will be initialized
  65  * dom - domain
  66  * port - port number
  67  * opcode - command code for this MBX
  68  * timeout - timeout in seconds
  69  * pyld_len - length of the command buffer described by this header
  70  *
  71  * return none
  72  */
  73 void
  74 mbx_common_req_hdr_init(struct mbx_hdr *hdr,
  75     uint8_t dom, uint8_t port,
  76     uint8_t subsys, uint8_t opcode,
  77     uint32_t timeout, uint32_t pyld_len, uint8_t version)
  78 {
  79         ASSERT(hdr != NULL);
  80 
  81         hdr->u0.req.opcode = opcode;
  82         hdr->u0.req.subsystem = subsys;
  83         hdr->u0.req.port_number = port;
  84         hdr->u0.req.domain = dom;
  85 
  86         hdr->u0.req.timeout = timeout;
  87         hdr->u0.req.request_length = pyld_len - sizeof (struct mbx_hdr);
  88         hdr->u0.req.version = version;
  89 } /* mbx_common_req_hdr_init */
  90 
  91 /*
  92  * function to initialize the hw with host endian information
  93  *
  94  * dev - software handle to the device
  95  *
  96  * return 0 on success, ETIMEDOUT on failure
  97  */
  98 int
  99 oce_mbox_init(struct oce_dev *dev)
 100 {
 101         struct oce_bmbx *mbx;
 102         uint8_t *ptr;
 103         int ret = 0;
 104 
 105         ASSERT(dev != NULL);
 106 
 107         mbx = (struct oce_bmbx *)DBUF_VA(dev->bmbx);
 108         ptr = (uint8_t *)&mbx->mbx;
 109 
 110         /* Endian Signature */
 111         *ptr++ = 0xFF;
 112         *ptr++ = 0x12;
 113         *ptr++ = 0x34;
 114         *ptr++ = 0xFF;
 115         *ptr++ = 0xFF;
 116         *ptr++ = 0x56;
 117         *ptr++ = 0x78;
 118         *ptr   = 0xFF;
 119 
 120         ret = oce_mbox_dispatch(dev, 0);
 121         if (ret != 0)
 122                 oce_log(dev, CE_NOTE, MOD_CONFIG,
 123                     "Failed to set endianess %d", ret);
 124 
 125         return (ret);
 126 } /* oce_mbox_init */
 127 
 128 /*
 129  * function to reset the hw with host endian information
 130  *
 131  * dev - software handle to the device
 132  *
 133  * return 0 on success, ETIMEDOUT on failure
 134  */
 135 int
 136 oce_mbox_fini(struct oce_dev *dev)
 137 {
 138         struct oce_bmbx *mbx;
 139         uint8_t *ptr;
 140         int ret = 0;
 141 
 142         ASSERT(dev != NULL);
 143 
 144         mbx = (struct oce_bmbx *)DBUF_VA(dev->bmbx);
 145         ptr = (uint8_t *)&mbx->mbx;
 146 
 147         /* Endian Signature */
 148         *ptr++ = 0xFF;
 149         *ptr++ = 0xAA;
 150         *ptr++ = 0xBB;
 151         *ptr++ = 0xFF;
 152         *ptr++ = 0xFF;
 153         *ptr++ = 0xCC;
 154         *ptr++ = 0xDD;
 155         *ptr   = 0xFF;
 156 
 157         ret = oce_mbox_dispatch(dev, 0);
 158         if (ret != 0)
 159                 oce_log(dev, CE_NOTE, MOD_CONFIG,
 160                     "Failed to reset endianess %d", ret);
 161 
 162         return (ret);
 163 } /* oce_mbox_fini */
 164 
 165 /*
 166  * function to wait till we get a mbox ready after writing to the
 167  * mbox doorbell
 168  *
 169  * dev - software handle to the device
 170  *
 171  * return 0=ready, ETIMEDOUT=>not ready but timed out
 172  */
 173 int
 174 oce_mbox_wait(struct oce_dev *dev, uint32_t tmo_sec)
 175 {
 176         clock_t tmo;
 177         clock_t now, tstamp;
 178         pd_mpu_mbox_db_t mbox_db;
 179 
 180         tmo = (tmo_sec > 0) ? drv_usectohz(tmo_sec * 1000000) :
 181             drv_usectohz(DEFAULT_MQ_MBOX_TIMEOUT);
 182 
 183         /* Add the default timeout to wait for a mailbox to complete */
 184         tmo += drv_usectohz(MBX_READY_TIMEOUT);
 185 
 186         tstamp = ddi_get_lbolt();
 187         for (;;) {
 188                 now = ddi_get_lbolt();
 189                 if ((now - tstamp) >= tmo) {
 190                         tmo = 0;
 191                         break;
 192                 }
 193 
 194                 mbox_db.dw0 = OCE_DB_READ32(dev, PD_MPU_MBOX_DB);
 195                 if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) {
 196                         ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 197                         oce_fm_ereport(dev, DDI_FM_DEVICE_INVAL_STATE);
 198                         return (EIO);
 199                 }
 200 
 201                 if (mbox_db.bits.ready) {
 202                         return (0);
 203                 }
 204                         drv_usecwait(5);
 205         }
 206 
 207         return (ETIMEDOUT);
 208 } /* oce_mbox_wait */
 209 
 210 /*
 211  * function to dispatch a mailbox command present in the mq mbox
 212  *
 213  * dev - software handle to the device
 214  *
 215  * return 0 on success, ETIMEDOUT on failure
 216  */
 217 int
 218 oce_mbox_dispatch(struct oce_dev *dev, uint32_t tmo_sec)
 219 {
 220         pd_mpu_mbox_db_t mbox_db;
 221         uint32_t pa;
 222         int ret;
 223 
 224         /* sync the bmbx */
 225         DBUF_SYNC(dev->bmbx, 0, 0, DDI_DMA_SYNC_FORDEV);
 226 
 227         /* write 30 bits of address hi dword */
 228         pa = (uint32_t)(DBUF_PA(dev->bmbx) >> 34);
 229         bzero(&mbox_db, sizeof (pd_mpu_mbox_db_t));
 230         mbox_db.bits.ready = 0;
 231         mbox_db.bits.hi = 1;
 232         mbox_db.bits.address = pa;
 233 
 234         /* wait for mbox ready */
 235         ret = oce_mbox_wait(dev, tmo_sec);
 236         if (ret != 0) {
 237                 return (ret);
 238         }
 239 
 240         /* ring the doorbell */
 241         OCE_DB_WRITE32(dev, PD_MPU_MBOX_DB, mbox_db.dw0);
 242 
 243         if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) {
 244                 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 245                 return (EIO);
 246         }
 247 
 248         /* wait for mbox ready */
 249         ret = oce_mbox_wait(dev, tmo_sec);
 250         if (ret != 0) {
 251                 oce_log(dev, CE_NOTE, MOD_CONFIG,
 252                     "BMBX TIMED OUT PROGRAMMING HI ADDR: %d", ret);
 253                 /* if mbx times out, hw is in invalid state */
 254                 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 255                 oce_fm_ereport(dev, DDI_FM_DEVICE_INVAL_STATE);
 256                 return (ret);
 257         }
 258 
 259         /* now write 30 bits of address lo dword */
 260         pa = (uint32_t)(DBUF_PA(dev->bmbx) >> 4) & 0x3fffffff;
 261         mbox_db.bits.ready = 0;
 262         mbox_db.bits.hi = 0;
 263         mbox_db.bits.address = pa;
 264 
 265         /* ring the doorbell */
 266         OCE_DB_WRITE32(dev, PD_MPU_MBOX_DB, mbox_db.dw0);
 267         if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) {
 268                 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 269                 return (EIO);
 270         }
 271 
 272         /* wait for mbox ready */
 273         ret = oce_mbox_wait(dev, tmo_sec);
 274 
 275         if (ret != 0) {
 276                 oce_log(dev, CE_NOTE, MOD_CONFIG,
 277                     "BMBX TIMED OUT PROGRAMMING LO ADDR: %d", ret);
 278                 return (ret);
 279         }
 280 
 281         /* sync */
 282         DBUF_SYNC(dev->bmbx, 0, 0, DDI_DMA_SYNC_FORKERNEL);
 283         if (oce_fm_check_dma_handle(dev, DBUF_DHDL(dev->bmbx)) != DDI_FM_OK) {
 284                 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 285                 return (EIO);
 286         }
 287         return (ret);
 288 } /* oce_mbox_dispatch */
 289 
 290 /*
 291  * function to post a MBX to the bootstrap mbox
 292  *
 293  * dev - software handle to the device
 294  * mbx - pointer to the MBX to send
 295  * tmo - timeout in seconds
 296  *
 297  * return 0 on success, ETIMEDOUT on failure
 298  */
 299 int
 300 oce_mbox_issue_bootstrap(struct oce_dev *dev, struct oce_mbx *mbx,
 301         uint32_t tmo)
 302 {
 303         struct oce_mbx *mb_mbx = NULL;
 304         struct oce_mq_cqe *mb_cqe = NULL;
 305         struct oce_bmbx *mb = NULL;
 306         int ret = 0;
 307         uint32_t status = 0;
 308 
 309         mutex_enter(&dev->bmbx_lock);
 310         mb = (struct oce_bmbx *)DBUF_VA(dev->bmbx);
 311         mb_mbx = &mb->mbx;
 312 
 313         /* copy mbx into mbox */
 314         bcopy(mbx, mb_mbx, sizeof (struct oce_mbx));
 315 
 316         /* now dispatch */
 317         ret = oce_mbox_dispatch(dev, tmo);
 318         if (ret != 0) {
 319                 mutex_exit(&dev->bmbx_lock);
 320                 return (ret);
 321         }
 322 
 323         /* sync */
 324         DBUF_SYNC(dev->bmbx, 0, 0, DDI_DMA_SYNC_FORKERNEL);
 325         ret = oce_fm_check_dma_handle(dev, DBUF_DHDL(dev->bmbx));
 326         if (ret != DDI_FM_OK) {
 327                 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 328                 mutex_exit(&dev->bmbx_lock);
 329                 return (EIO);
 330         }
 331 
 332         /*
 333          * the command completed successfully. Now get the
 334          * completion queue entry
 335          */
 336         mb_cqe = &mb->cqe;
 337         DW_SWAP(u32ptr(&mb_cqe->u0.dw[0]), sizeof (struct oce_mq_cqe));
 338 
 339         /* copy mbox mbx back */
 340         bcopy(mb_mbx, mbx, sizeof (struct oce_mbx));
 341 
 342         /* check mbox status */
 343         status  = mb_cqe->u0.s.completion_status << 16 |
 344             mb_cqe->u0.s.extended_status;
 345         mutex_exit(&dev->bmbx_lock);
 346         return (status);
 347 } /* oce_mbox_issue_bootstrap */
 348 
 349 /*
 350  * function to get the firmware version
 351  *
 352  * dev - software handle to the device
 353  *
 354  * return 0 on success, EIO on failure
 355  */
 356 int
 357 oce_get_fw_version(struct oce_dev *dev, uint32_t mode)
 358 {
 359         struct oce_mbx mbx;
 360         struct mbx_get_common_fw_version *fwcmd;
 361         int ret = 0;
 362 
 363         bzero(&mbx, sizeof (struct oce_mbx));
 364 
 365         /* initialize the ioctl header */
 366         fwcmd = (struct mbx_get_common_fw_version *)&mbx.payload;
 367         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 368             MBX_SUBSYSTEM_COMMON,
 369             OPCODE_GET_COMMON_FW_VERSION,
 370             MBX_TIMEOUT_SEC,
 371             sizeof (struct mbx_get_common_fw_version), 0);
 372 
 373         /* fill rest of mbx */
 374         mbx.u0.s.embedded = 1;
 375         mbx.payload_length = sizeof (struct mbx_get_common_fw_version);
 376         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
 377 
 378         /* now post the command */
 379         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 380         if (ret != 0) {
 381                 return (ret);
 382         }
 383 
 384         bcopy(fwcmd->params.rsp.fw_ver_str, dev->fw_version, 32);
 385 
 386         oce_log(dev, CE_NOTE, MOD_CONFIG, "%s %s",
 387             fwcmd->params.rsp.fw_ver_str,
 388             fwcmd->params.rsp.fw_on_flash_ver_str);
 389 
 390         return (0);
 391 } /* oce_get_fw_version */
 392 
 393 /*
 394  * function to invoke f/w reset via. mailbox
 395  * does not hold bootstap lock called by quiesce
 396  *
 397  * dev - software handle to the device
 398  *
 399  * return 0 on success, ETIMEDOUT on failure
 400  *
 401  */
 402 int
 403 oce_reset_fun(struct oce_dev *dev)
 404 {
 405         struct oce_mbx *mbx;
 406         struct oce_bmbx *mb;
 407         struct ioctl_common_function_reset *fwcmd;
 408 
 409         mb = (struct oce_bmbx *)DBUF_VA(dev->bmbx);
 410         mbx = &mb->mbx;
 411         bzero(mbx, sizeof (struct oce_mbx));
 412         /* initialize the ioctl header */
 413         fwcmd = (struct ioctl_common_function_reset *)&mbx->payload;
 414         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 415             MBX_SUBSYSTEM_COMMON,
 416             OPCODE_COMMON_FUNCTION_RESET,
 417             MBX_TIMEOUT_SEC,
 418             sizeof (struct ioctl_common_function_reset), 0);
 419 
 420         /* fill rest of mbx */
 421         mbx->u0.s.embedded = 1;
 422         mbx->payload_length = sizeof (struct ioctl_common_function_reset);
 423         DW_SWAP(u32ptr(mbx), mbx->payload_length + OCE_BMBX_RHDR_SZ);
 424 
 425         return (oce_mbox_dispatch(dev, 0));
 426 } /* oce_reset_fun */
 427 
 428 /*
 429  * function to read the mac address associated with an interface
 430  *
 431  * dev - software handle to the device
 432  * if_id - interface id to read the address from
 433  * perm - set to 1 if reading the factory mac address. In this case
 434  *      if_id is ignored
 435  * type - type of the mac address, whether network or storage
 436  * mac - [OUTPUT] pointer to a buffer containing the mac address
 437  *          when the command succeeds
 438  *
 439  * return 0 on success, EIO on failure
 440  */
 441 int
 442 oce_read_mac_addr(struct oce_dev *dev, uint32_t if_id, uint8_t perm,
 443     uint8_t type, struct mac_address_format *mac, uint32_t mode)
 444 {
 445         struct oce_mbx mbx;
 446         struct mbx_query_common_iface_mac *fwcmd;
 447         int ret = 0;
 448 
 449         bzero(&mbx, sizeof (struct oce_mbx));
 450         /* initialize the ioctl header */
 451         fwcmd = (struct mbx_query_common_iface_mac *)&mbx.payload;
 452         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 453             MBX_SUBSYSTEM_COMMON,
 454             OPCODE_QUERY_COMMON_IFACE_MAC,
 455             MBX_TIMEOUT_SEC,
 456             sizeof (struct mbx_query_common_iface_mac), 0);
 457 
 458         /* fill the command */
 459         fwcmd->params.req.permanent = perm;
 460         if (perm)
 461                 fwcmd->params.req.if_id = (uint16_t)if_id;
 462         else
 463                 fwcmd->params.req.if_id = 0;
 464         fwcmd->params.req.type = type;
 465 
 466         /* fill rest of mbx */
 467         mbx.u0.s.embedded = 1;
 468         mbx.payload_length = sizeof (struct mbx_query_common_iface_mac);
 469         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
 470 
 471         /* now post the command */
 472         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 473         if (ret != 0) {
 474                 return (ret);
 475         }
 476 
 477         /* get the response */
 478         oce_log(dev, CE_NOTE, MOD_CONFIG,
 479             "MAC addr size = 0x%x",
 480             LE_16(fwcmd->params.rsp.mac.size_of_struct));
 481         oce_log(dev, CE_NOTE, MOD_CONFIG,
 482             "MAC_ADDR:0x%x:0x%x:0x%x:0x%x:0x%x:0x%x",
 483             fwcmd->params.rsp.mac.mac_addr[0],
 484             fwcmd->params.rsp.mac.mac_addr[1],
 485             fwcmd->params.rsp.mac.mac_addr[2],
 486             fwcmd->params.rsp.mac.mac_addr[3],
 487             fwcmd->params.rsp.mac.mac_addr[4],
 488             fwcmd->params.rsp.mac.mac_addr[5]);
 489 
 490         /* copy the mac addres in the output parameter */
 491         mac->size_of_struct = LE_16(fwcmd->params.rsp.mac.size_of_struct);
 492         bcopy(&fwcmd->params.rsp.mac.mac_addr[0], &mac->mac_addr[0],
 493             mac->size_of_struct);
 494 
 495         return (0);
 496 } /* oce_read_mac_addr */
 497 
 498 /*
 499  * function to create an interface using the OPCODE_CREATE_COMMON_IFACE
 500  * command
 501  *
 502  * dev - software handle to the device
 503  * cap_flags - capability flags
 504  * en_flags - enable capability flags
 505  * vlan_tag - optional vlan tag to associate with the if
 506  * mac_addr - pointer to a buffer containing the mac address
 507  * if_id - [OUTPUT] pointer to an integer to hold the ID of the
 508  *          interface created
 509  *
 510  * return 0 on success, EIO on failure
 511  */
 512 int
 513 oce_if_create(struct oce_dev *dev, uint32_t cap_flags, uint32_t en_flags,
 514     uint16_t vlan_tag, uint8_t *mac_addr,
 515     uint32_t *if_id, uint32_t mode)
 516 {
 517         struct oce_mbx mbx;
 518         struct mbx_create_common_iface *fwcmd;
 519         int ret = 0;
 520 
 521         bzero(&mbx, sizeof (struct oce_mbx));
 522 
 523         /* initialize the ioctl header */
 524         fwcmd = (struct mbx_create_common_iface *)&mbx.payload;
 525         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 526             MBX_SUBSYSTEM_COMMON,
 527             OPCODE_CREATE_COMMON_IFACE,
 528             MBX_TIMEOUT_SEC,
 529             sizeof (struct mbx_create_common_iface), 0);
 530         DW_SWAP(u32ptr(&fwcmd->hdr), sizeof (struct mbx_hdr));
 531 
 532         /* fill the command */
 533         fwcmd->params.req.version   = 0;
 534         fwcmd->params.req.cap_flags = LE_32(cap_flags);
 535         fwcmd->params.req.enable_flags   = LE_32(en_flags);
 536         if (mac_addr != NULL) {
 537                 bcopy(mac_addr, &fwcmd->params.req.mac_addr[0],
 538                     ETHERADDRL);
 539                 fwcmd->params.req.vlan_tag.u0.normal.vtag = LE_16(vlan_tag);
 540                 fwcmd->params.req.mac_invalid = B_FALSE;
 541         } else {
 542                 fwcmd->params.req.mac_invalid = B_TRUE;
 543         }
 544 
 545         /* fill rest of mbx */
 546         mbx.u0.s.embedded = 1;
 547         mbx.payload_length = sizeof (struct mbx_create_common_iface);
 548         DW_SWAP(u32ptr(&mbx), OCE_BMBX_RHDR_SZ);
 549 
 550         /* now post the command */
 551         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 552         if (ret != 0) {
 553                 return (ret);
 554         }
 555 
 556         /* get response */
 557         *if_id = LE_32(fwcmd->params.rsp.if_id);
 558         oce_log(dev, CE_NOTE, MOD_CONFIG,
 559             "IF_ID = 0x%x", *if_id);
 560 
 561         /* If asked to set mac addr save the pmac handle */
 562         if (mac_addr != NULL) {
 563                 dev->pmac_id = LE_32(fwcmd->params.rsp.pmac_id);
 564                 oce_log(dev, CE_NOTE, MOD_CONFIG,
 565                     "PMAC_ID = 0x%x", dev->pmac_id);
 566         }
 567         return (0);
 568 } /* oce_if_create */
 569 
 570 /*
 571  * function to delete an interface
 572  *
 573  * dev - software handle to the device
 574  * if_id - ID of the interface to delete
 575  *
 576  * return 0 on success, EIO on failure
 577  */
 578 int
 579 oce_if_del(struct oce_dev *dev, uint32_t if_id, uint32_t mode)
 580 {
 581         struct oce_mbx mbx;
 582         struct mbx_destroy_common_iface *fwcmd;
 583         int ret = 0;
 584 
 585         bzero(&mbx, sizeof (struct oce_mbx));
 586         /* initialize the ioctl header */
 587         fwcmd = (struct mbx_destroy_common_iface *)&mbx.payload;
 588         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 589             MBX_SUBSYSTEM_COMMON,
 590             OPCODE_DESTROY_COMMON_IFACE,
 591             MBX_TIMEOUT_SEC,
 592             sizeof (struct mbx_destroy_common_iface), 0);
 593 
 594         /* fill the command */
 595         fwcmd->params.req.if_id = if_id;
 596 
 597         /* fill rest of mbx */
 598         mbx.u0.s.embedded = 1;
 599         mbx.payload_length = sizeof (struct mbx_destroy_common_iface);
 600         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
 601 
 602         /* post the command */
 603         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 604         return (ret);
 605 } /* oce_if_del */
 606 
 607 /*
 608  * function to query the link status from the hardware
 609  *
 610  * dev - software handle to the device
 611  * link_status - [OUT] pointer to the structure returning the link attributes
 612  *
 613  * return 0 on success, EIO on failure
 614  */
 615 int
 616 oce_get_link_status(struct oce_dev *dev, link_state_t *link_status,
 617     int32_t *link_speed, uint8_t *link_duplex, uint8_t cmd_ver, uint32_t mode)
 618 {
 619         struct oce_mbx mbx;
 620         struct mbx_query_common_link_status *fwcmd;
 621         int ret = 0;
 622 
 623         bzero(&mbx, sizeof (struct oce_mbx));
 624 
 625         /* initialize the ioctl header */
 626         fwcmd = (struct mbx_query_common_link_status *)&mbx.payload;
 627         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 628             MBX_SUBSYSTEM_COMMON,
 629             OPCODE_QUERY_COMMON_LINK_STATUS,
 630             MBX_TIMEOUT_SEC,
 631             sizeof (struct mbx_query_common_link_status), cmd_ver);
 632 
 633         /* fill rest of mbx */
 634         mbx.u0.s.embedded = 1;
 635         mbx.payload_length = sizeof (struct mbx_query_common_link_status);
 636         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
 637 
 638         /* post the command */
 639         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 640         if (ret != 0) {
 641                 oce_log(dev, CE_NOTE, MOD_CONFIG,
 642                     "Failed to query link status: 0x%x", ret);
 643                 return (ret);
 644         }
 645 
 646         /* interpret response */
 647         *link_status  = (LE_32(fwcmd->params.rsp.logical_link_status) ==
 648             NTWK_LOGICAL_LINK_UP) ? LINK_STATE_UP : LINK_STATE_DOWN;
 649         *link_speed = (fwcmd->params.rsp.qos_link_speed != 0) ?
 650             LE_16(fwcmd->params.rsp.qos_link_speed) * 10:
 651             pow10[fwcmd->params.rsp.mac_speed];
 652         *link_duplex = fwcmd->params.rsp.mac_duplex;
 653 
 654         return (0);
 655 } /* oce_get_link_status */
 656 
 657 /*
 658  * function to configure the rx filter on the interface
 659  *
 660  * dev - software handle to the device
 661  * filter - mbx command containing the filter parameters
 662  *
 663  * return 0 on success, EIO on failure
 664  */
 665 int
 666 oce_set_rx_filter(struct oce_dev *dev,
 667     struct mbx_set_common_ntwk_rx_filter *filter, uint32_t mode)
 668 {
 669         struct oce_mbx mbx;
 670         struct mbx_set_common_ntwk_rx_filter *fwcmd;
 671         int ret;
 672 
 673         bzero(&mbx, sizeof (struct oce_mbx));
 674         fwcmd = (struct mbx_set_common_ntwk_rx_filter *)&mbx.payload;
 675         /* fill the command */
 676         bcopy(filter, fwcmd, sizeof (struct mbx_set_common_ntwk_rx_filter));
 677 
 678         /* initialize the ioctl header */
 679         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 680             MBX_SUBSYSTEM_COMMON,
 681             OPCODE_COMMON_NTWK_RX_FILTER,
 682             MBX_TIMEOUT_SEC,
 683             sizeof (struct mbx_set_common_ntwk_rx_filter), 0);
 684 
 685         /* fill rest of mbx */
 686         mbx.u0.s.embedded = 1;
 687         mbx.payload_length = sizeof (struct mbx_set_common_ntwk_rx_filter);
 688         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
 689 
 690         /* post the command */
 691         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 692         if (ret != 0) {
 693                 oce_log(dev, CE_NOTE, MOD_CONFIG,
 694                     "Set RX filter failed: 0x%x", ret);
 695         }
 696 
 697         return (ret);
 698 } /* oce_set_rx_filter */
 699 
 700 /*
 701  * function to send the mbx command to update the mcast table with fw
 702  *
 703  * dev - software handle to the device
 704  * mca_table - array of mcast address to update
 705  * mca_cnt - number of elements in mca_table
 706  * enable_promisc - flag to enable/disable mcast-promiscuous mode
 707  *
 708  * return 0 on success, EIO on failure
 709  */
 710 int
 711 oce_set_multicast_table(struct oce_dev *dev, uint32_t if_id,
 712     struct ether_addr *mca_table, uint16_t mca_cnt, boolean_t promisc,
 713     uint32_t mode)
 714 {
 715         struct oce_mbx mbx;
 716         struct  mbx_set_common_iface_multicast *fwcmd;
 717         int ret;
 718 
 719         bzero(&mbx, sizeof (struct oce_mbx));
 720         fwcmd = (struct mbx_set_common_iface_multicast *)&mbx.payload;
 721 
 722         /* initialize the ioctl header */
 723         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 724             MBX_SUBSYSTEM_COMMON,
 725             OPCODE_SET_COMMON_IFACE_MULTICAST,
 726             MBX_TIMEOUT_SEC,
 727             sizeof (struct mbx_set_common_iface_multicast), 0);
 728 
 729         /* fill the command */
 730         fwcmd->params.req.if_id = (uint8_t)if_id;
 731         if (mca_table != NULL) {
 732                 bcopy(mca_table, &fwcmd->params.req.mac[0],
 733                     mca_cnt * ETHERADDRL);
 734         }
 735         fwcmd->params.req.num_mac = LE_16(mca_cnt);
 736         fwcmd->params.req.promiscuous = (uint8_t)promisc;
 737 
 738         /* fill rest of mbx */
 739         mbx.u0.s.embedded = B_TRUE;
 740         mbx.payload_length = sizeof (struct mbx_set_common_iface_multicast);
 741         /* Swap only MBX header + BOOTSTRAP HDR */
 742         DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + OCE_MBX_RRHDR_SZ));
 743 
 744         /* post the command */
 745         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 746 
 747         return (ret);
 748 } /* oce_set_multicast_table */
 749 
 750 /*
 751  * function to query the fw attributes from the hw
 752  *
 753  * dev - software handle to the device
 754  *
 755  * return 0 on success, EIO on failure
 756  */
 757 int
 758 oce_get_fw_config(struct oce_dev *dev, uint32_t mode)
 759 {
 760         struct oce_mbx mbx;
 761         struct mbx_common_query_fw_config *fwcmd;
 762         struct mbx_common_set_drvfn_capab *capab;
 763         int ret = 0;
 764 
 765         bzero(&mbx, sizeof (struct oce_mbx));
 766         /* initialize the ioctl header */
 767         fwcmd = (struct mbx_common_query_fw_config *)&mbx.payload;
 768         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 769             MBX_SUBSYSTEM_COMMON,
 770             OPCODE_QUERY_COMMON_FIRMWARE_CONFIG,
 771             MBX_TIMEOUT_SEC,
 772             sizeof (struct mbx_common_query_fw_config), 0);
 773 
 774         /* fill rest of mbx */
 775         mbx.u0.s.embedded = 1;
 776         mbx.payload_length = sizeof (struct mbx_common_query_fw_config);
 777         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
 778 
 779         /* now post the command */
 780         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 781 
 782         if (ret != 0) {
 783                 oce_log(dev, CE_WARN, MOD_CONFIG,
 784                     "Failed to query fw config: 0x%x", ret);
 785                 return (ret);
 786         }
 787 
 788         /* swap and copy into buffer */
 789         DW_SWAP(u32ptr(fwcmd), sizeof (struct mbx_common_query_fw_config));
 790 
 791         dev->config_number = fwcmd->params.rsp.config_number;
 792         dev->asic_revision = fwcmd->params.rsp.asic_revision;
 793         dev->port_id = fwcmd->params.rsp.port_id;
 794         dev->function_mode = fwcmd->params.rsp.function_mode;
 795 
 796         /* get the max rings alloted for this function */
 797         if (fwcmd->params.rsp.ulp[0].mode & ULP_NIC_MODE) {
 798                 dev->max_tx_rings = fwcmd->params.rsp.ulp[0].wq_count;
 799                 dev->max_rx_rings = fwcmd->params.rsp.ulp[0].rq_count;
 800         } else {
 801                 dev->max_tx_rings = fwcmd->params.rsp.ulp[1].wq_count;
 802                 dev->max_rx_rings = fwcmd->params.rsp.ulp[1].rq_count;
 803         }
 804         dev->function_caps = fwcmd->params.rsp.function_caps;
 805 
 806         if (!LANCER_CHIP(dev)) {
 807                 bzero(&mbx, sizeof (struct oce_mbx));
 808                 /* initialize the ioctl header */
 809                 capab = (struct mbx_common_set_drvfn_capab *)&mbx.payload;
 810                 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 811                     MBX_SUBSYSTEM_COMMON,
 812                     OPCODE_COMMON_SET_DRIVER_FUNCTION_CAPABILITIES,
 813                     MBX_TIMEOUT_SEC,
 814                     sizeof (struct mbx_common_set_drvfn_capab), 0);
 815 
 816                 /* fill rest of mbx */
 817                 mbx.u0.s.embedded = 1;
 818                 mbx.payload_length =
 819                     sizeof (struct mbx_common_set_drvfn_capab);
 820 
 821                 capab->params.request.valid_capability_flags =
 822                     DRVFN_CAPAB_BE3_NATIVE;
 823                 capab->params.request.capability_flags = DRVFN_CAPAB_BE3_NATIVE;
 824 
 825                 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
 826 
 827                 /* now post the command */
 828                 ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 829 
 830                 if (ret != 0) {
 831                         if ((OCE_MBX_STATUS(fwcmd) ==
 832                             MGMT_STATUS_ILLEGAL_REQUEST) &&
 833                             OCE_MBX_ADDL_STATUS(fwcmd) ==
 834                             MGMT_ADDI_STATUS_INVALID_OPCODE) {
 835                                 /*
 836                                  * run in legacy mode
 837                                  */
 838                                 dev->rx_rings_per_group =
 839                                     min(dev->rx_rings_per_group,
 840                                     MAX_RING_PER_GROUP_LEGACY);
 841                         } else {
 842                                 return (ret);
 843                         }
 844                 } else {
 845                         /* swap and copy into buffer */
 846                         dev->drvfn_caps =
 847                             LE_32(capab->params.response.capability_flags);
 848                 }
 849 
 850                 if (!(dev->drvfn_caps & DRVFN_CAPAB_BE3_NATIVE))
 851                         dev->rx_rings_per_group = min(dev->rx_rings_per_group,
 852                             MAX_RING_PER_GROUP_LEGACY);
 853         }
 854         oce_log(dev, CE_NOTE, MOD_CONFIG,
 855             "drvfn_caps = 0x%x, function_caps = 0x%x",
 856             dev->drvfn_caps, dev->function_caps);
 857 
 858         return (0);
 859 } /* oce_get_fw_config */
 860 
 861 /*
 862  * function to retrieve statistic counters from the hardware
 863  *
 864  * dev - software handle to the device
 865  *
 866  * return 0 on success, EIO on failure
 867  */
 868 int
 869 oce_get_hw_stats(struct oce_dev *dev, uint32_t mode)
 870 {
 871         struct oce_mbx mbx;
 872         struct mbx_get_nic_stats *fwcmd =
 873             (struct mbx_get_nic_stats *)DBUF_VA(dev->stats_dbuf);
 874         int ret = 0;
 875 
 876         bzero(&mbx, sizeof (struct oce_mbx));
 877         bzero(fwcmd, sizeof (struct mbx_get_nic_stats));
 878 
 879         /* initialize the ioctl header */
 880         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 881             MBX_SUBSYSTEM_NIC,
 882             OPCODE_GET_NIC_STATS,
 883             MBX_TIMEOUT_SEC,
 884             sizeof (struct mbx_get_nic_stats), 0);
 885 
 886         if (dev->chip_rev == OC_CNA_GEN3)
 887                 fwcmd->hdr.u0.req.version = 1;
 888         DW_SWAP(u32ptr(fwcmd), sizeof (struct mbx_get_nic_stats));
 889 
 890         /* fill rest of mbx */
 891         mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(DBUF_PA(dev->stats_dbuf));
 892         mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(DBUF_PA(dev->stats_dbuf));
 893         mbx.payload.u0.u1.sgl[0].length = sizeof (struct mbx_get_nic_stats);
 894         mbx.payload_length = sizeof (struct mbx_get_nic_stats);
 895 
 896         mbx.u0.s.embedded = 0;
 897         mbx.u0.s.sge_count = 1;
 898 
 899         DW_SWAP(u32ptr(&mbx), sizeof (struct oce_mq_sge) + OCE_BMBX_RHDR_SZ);
 900 
 901         /* sync for device */
 902         DBUF_SYNC(dev->stats_dbuf, 0, 0, DDI_DMA_SYNC_FORDEV);
 903 
 904         /* now post the command */
 905         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 906         /* sync the stats */
 907         DBUF_SYNC(dev->stats_dbuf, 0, 0, DDI_DMA_SYNC_FORKERNEL);
 908 
 909         /* Check the mailbox status and command completion status */
 910         if (ret != 0) {
 911                 oce_log(dev, CE_WARN, MOD_CONFIG,
 912                     "Failed to get stats: 0x%x", ret);
 913                 return (ret);
 914         }
 915 
 916         DW_SWAP(u32ptr(&fwcmd->params.rsp), sizeof (struct mbx_get_nic_stats));
 917         return (0);
 918 } /* oce_get_hw_stats */
 919 
 920 /*
 921  * function to retrieve statistic counters from Lancer hardware
 922  *
 923  * dev - software handle to the device
 924  *
 925  * return 0 on success, EIO on failure
 926  */
 927 int
 928 oce_get_pport_stats(struct oce_dev *dev, uint32_t mode)
 929 {
 930         struct oce_mbx mbx;
 931         struct mbx_get_pport_stats *fwcmd;
 932         int ret = 0;
 933 
 934         bzero(&mbx, sizeof (struct oce_mbx));
 935         /* initialize the ioctl header */
 936 
 937         fwcmd = (struct mbx_get_pport_stats *)DBUF_VA(dev->stats_dbuf);
 938 
 939         bzero(&fwcmd->params, sizeof (fwcmd->params));
 940 
 941         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 942             MBX_SUBSYSTEM_NIC,
 943             OPCODE_NIC_GET_PPORT_STATS,
 944             MBX_TIMEOUT_SEC,
 945             sizeof (struct mbx_get_nic_stats), 0);
 946         fwcmd->params.req.arg.pport_num = dev->port_id;
 947         DW_SWAP(u32ptr(fwcmd), sizeof (struct mbx_get_pport_stats));
 948 
 949         /* fill rest of mbx */
 950         mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(DBUF_PA(dev->stats_dbuf));
 951         mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(DBUF_PA(dev->stats_dbuf));
 952         mbx.payload.u0.u1.sgl[0].length = sizeof (struct mbx_get_nic_stats);
 953         mbx.payload_length = sizeof (struct mbx_get_pport_stats);
 954 
 955         mbx.u0.s.embedded = 0;
 956         mbx.u0.s.sge_count = 1;
 957 
 958         DW_SWAP(u32ptr(&mbx), sizeof (struct oce_mq_sge) + OCE_BMBX_RHDR_SZ);
 959 
 960 
 961         /* sync for device */
 962         DBUF_SYNC(dev->stats_dbuf, 0, 0, DDI_DMA_SYNC_FORDEV);
 963 
 964         /* now post the command */
 965         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
 966         /* sync the stats */
 967         DBUF_SYNC(dev->stats_dbuf, 0, 0, DDI_DMA_SYNC_FORKERNEL);
 968 
 969         /* Check the mailbox status and command completion status */
 970         if (ret != 0) {
 971                 return (ret);
 972         }
 973 
 974         DW_SWAP(u32ptr(&fwcmd->params.rsp), sizeof (struct mbx_get_nic_stats));
 975         return (0);
 976 } /* oce_get_pport_stats */
 977 
 978 /*
 979  * function to set the number of vectors with the cev
 980  *
 981  * dev - software handle to the device
 982  * num_vectors - number of MSI messages
 983  *
 984  * return 0 on success, EIO on failure
 985  */
 986 int
 987 oce_num_intr_vectors_set(struct oce_dev *dev, uint32_t num_vectors,
 988     uint32_t mode)
 989 {
 990         struct oce_mbx mbx;
 991         struct mbx_common_cev_modify_msi_messages *fwcmd;
 992         int ret = 0;
 993 
 994         bzero(&mbx, sizeof (struct oce_mbx));
 995         /* initialize the ioctl header */
 996         fwcmd = (struct mbx_common_cev_modify_msi_messages *)&mbx.payload;
 997         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
 998             MBX_SUBSYSTEM_COMMON,
 999             OPCODE_COMMON_CEV_MODIFY_MSI_MESSAGES,
1000             MBX_TIMEOUT_SEC,
1001             sizeof (struct mbx_common_cev_modify_msi_messages), 0);
1002 
1003         /* fill the command */
1004         fwcmd->params.req.num_msi_msgs = LE_32(num_vectors);
1005 
1006         /* fill rest of mbx */
1007         mbx.u0.s.embedded = 1;
1008         mbx.payload_length =
1009             sizeof (struct mbx_common_cev_modify_msi_messages);
1010         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1011 
1012         /* post the command */
1013         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
1014 
1015         return (ret);
1016 } /* oce_num_intr_vectors_set */
1017 
1018 /*
1019  * function to set flow control capability in the hardware
1020  *
1021  * dev - software handle to the device
1022  * flow_control - flow control flags to set
1023  *
1024  * return 0 on success, EIO on failure
1025  */
1026 int
1027 oce_set_flow_control(struct oce_dev *dev, uint32_t flow_control, uint32_t mode)
1028 {
1029         struct oce_mbx mbx;
1030         struct mbx_common_get_set_flow_control *fwcmd =
1031             (struct mbx_common_get_set_flow_control *)&mbx.payload;
1032         int ret;
1033 
1034         bzero(&mbx, sizeof (struct oce_mbx));
1035         /* initialize the ioctl header */
1036         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1037             MBX_SUBSYSTEM_COMMON,
1038             OPCODE_SET_COMMON_FLOW_CONTROL,
1039             MBX_TIMEOUT_SEC,
1040             sizeof (struct mbx_common_get_set_flow_control), 0);
1041 
1042         /* fill command */
1043         if (flow_control & OCE_FC_TX)
1044                 fwcmd->tx_flow_control = 1;
1045 
1046         if (flow_control & OCE_FC_RX)
1047                 fwcmd->rx_flow_control = 1;
1048 
1049         /* fill rest of mbx */
1050         mbx.u0.s.embedded = 1;
1051         mbx.payload_length = sizeof (struct mbx_common_get_set_flow_control);
1052         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1053 
1054         /* post the command */
1055         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
1056         if (ret != 0) {
1057                 oce_log(dev, CE_NOTE, MOD_CONFIG,
1058                     "Set flow control failed: 0x%x", ret);
1059         }
1060 
1061         return (ret);
1062 } /* oce_set_flow_control */
1063 
1064 /*
1065  * function to get the current flow control setting with the hardware
1066  *
1067  * dev - software handle to the device
1068  * flow_control - [OUT] pointer to location where flow_control setting
1069  * is returned
1070  *
1071  * return 0 on success, EIO on failure
1072  */
1073 int
1074 oce_get_flow_control(struct oce_dev *dev, uint32_t *flow_control, uint32_t mode)
1075 {
1076         struct oce_mbx mbx;
1077         struct mbx_common_get_set_flow_control *fwcmd;
1078         int ret;
1079 
1080         DEV_LOCK(dev);
1081         if (dev->suspended) {
1082                 DEV_UNLOCK(dev);
1083                 return (EIO);
1084         }
1085         DEV_UNLOCK(dev);
1086 
1087         bzero(&mbx, sizeof (struct oce_mbx));
1088         fwcmd = (struct mbx_common_get_set_flow_control *)&mbx.payload;
1089 
1090         /* initialize the ioctl header */
1091         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1092             MBX_SUBSYSTEM_COMMON,
1093             OPCODE_GET_COMMON_FLOW_CONTROL,
1094             MBX_TIMEOUT_SEC,
1095             sizeof (struct mbx_common_get_set_flow_control), 0);
1096 
1097         /* fill rest of mbx */
1098         mbx.u0.s.embedded = 1;
1099         mbx.payload_length = sizeof (struct mbx_common_get_set_flow_control);
1100         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1101 
1102         /* post the command */
1103         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
1104 
1105         if (ret != 0) {
1106                 return (ret);
1107         }
1108 
1109         /* get the flow control */
1110         DW_SWAP(u32ptr(fwcmd),
1111             sizeof (struct mbx_common_get_set_flow_control));
1112         *flow_control = 0;
1113         if (fwcmd->tx_flow_control)
1114                 *flow_control |= OCE_FC_TX;
1115 
1116         if (fwcmd->rx_flow_control)
1117                 *flow_control |= OCE_FC_RX;
1118 
1119         return (0);
1120 } /* oce_get_flow_control */
1121 
1122 /*
1123  * function to enable/disable device promiscuous mode
1124  *
1125  * dev - software handle to the device
1126  * enable - enable/disable flag
1127  *
1128  * return 0 on success, EIO on failure
1129  */
1130 int
1131 oce_set_promiscuous(struct oce_dev *dev, boolean_t enable, uint32_t mode)
1132 {
1133         struct oce_mbx mbx;
1134         struct mbx_set_common_iface_rx_filter *fwcmd;
1135         int ret = 0;
1136 
1137         bzero(&mbx, sizeof (struct oce_mbx));
1138 
1139         fwcmd = (struct mbx_set_common_iface_rx_filter *)&mbx.payload;
1140 
1141         /* initialize the ioctl header */
1142         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1143             MBX_SUBSYSTEM_COMMON,
1144             OPCODE_COMMON_NTWK_RX_FILTER,
1145             MBX_TIMEOUT_SEC,
1146             sizeof (struct mbx_set_common_iface_rx_filter), 0);
1147         /* fill rest of mbx */
1148         mbx.u0.s.embedded = 1;
1149         mbx.payload_length = sizeof (struct mbx_set_common_iface_rx_filter);
1150 
1151         fwcmd->params.req.if_id = dev->if_id;
1152         /*
1153          * Not setting VLAN promiscuous as the
1154          * interface is always in  VLAN VLAN prmoiscuous
1155          */
1156         fwcmd->params.req.if_flags_mask = MBX_RX_IFACE_FLAGS_PROMISCUOUS;
1157         if (enable)
1158                 fwcmd->params.req.if_flags = MBX_RX_IFACE_FLAGS_PROMISCUOUS;
1159 
1160         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1161 
1162         /* post the command */
1163         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
1164 
1165         return (ret);
1166 }
1167 
1168 /*
1169  * function to add a unicast address to an interface
1170  *
1171  * dev - software handle to the device
1172  * mac - unicast address
1173  *
1174  * return 0 on success, EIO on failure
1175  */
1176 int
1177 oce_add_mac(struct oce_dev *dev, uint32_t if_id,
1178     const uint8_t *mac, uint32_t *pmac_id, uint32_t mode)
1179 {
1180         struct oce_mbx mbx;
1181         struct mbx_add_common_iface_mac *fwcmd;
1182         int ret;
1183 
1184         bzero(&mbx, sizeof (struct oce_mbx));
1185         fwcmd = (struct mbx_add_common_iface_mac *)&mbx.payload;
1186         fwcmd->params.req.if_id = LE_32(if_id);
1187         bcopy(mac, &fwcmd->params.req.mac_address[0], ETHERADDRL);
1188 
1189         /* initialize the ioctl header */
1190         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1191             MBX_SUBSYSTEM_COMMON,
1192             OPCODE_ADD_COMMON_IFACE_MAC,
1193             MBX_TIMEOUT_SEC,
1194             sizeof (struct mbx_add_common_iface_mac), 0);
1195 
1196         /* fill rest of mbx */
1197         mbx.u0.s.embedded = 1;
1198         mbx.payload_length = sizeof (struct mbx_add_common_iface_mac);
1199         DW_SWAP(u32ptr(&mbx), OCE_BMBX_RHDR_SZ + OCE_MBX_RRHDR_SZ);
1200 
1201         /* post the command */
1202         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
1203 
1204         if (ret != 0) {
1205                 return (ret);
1206         }
1207 
1208         *pmac_id = LE_32(fwcmd->params.rsp.pmac_id);
1209         return (0);
1210 }
1211 
1212 /*
1213  * function to delete an unicast address associated with an interface
1214  *
1215  * dev - software handle to the device
1216  * pmac_id - handle to the address added using ace_add_mac
1217  *
1218  * return 0 on success, EIO on failure
1219  */
1220 int
1221 oce_del_mac(struct oce_dev *dev,  uint32_t if_id, uint32_t *pmac_id,
1222     uint32_t mode)
1223 {
1224         struct oce_mbx mbx;
1225         struct mbx_del_common_iface_mac *fwcmd;
1226         int ret;
1227 
1228         bzero(&mbx, sizeof (struct oce_mbx));
1229         fwcmd = (struct mbx_del_common_iface_mac *)&mbx.payload;
1230         fwcmd->params.req.if_id = if_id;
1231         fwcmd->params.req.pmac_id = *pmac_id;
1232 
1233         /* initialize the ioctl header */
1234         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1235             MBX_SUBSYSTEM_COMMON,
1236             OPCODE_DEL_COMMON_IFACE_MAC,
1237             MBX_TIMEOUT_SEC,
1238             sizeof (struct mbx_add_common_iface_mac), 0);
1239 
1240         /* fill rest of mbx */
1241         mbx.u0.s.embedded = 1;
1242         mbx.payload_length = sizeof (struct mbx_del_common_iface_mac);
1243         DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1244 
1245         /* post the command */
1246         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
1247 
1248         return (ret);
1249 }
1250 
1251 
1252 /*
1253  * function to send the mbx command to configure vlan
1254  *
1255  * dev - software handle to the device
1256  * vtag_arr - array of vlan tags
1257  * vtag_cnt - number of elements in array
1258  * untagged - boolean TRUE/FLASE
1259  * enable_promisc - flag to enable/disable VLAN promiscuous mode
1260  *
1261  * return 0 on success, EIO on failure
1262  */
1263 int
1264 oce_config_vlan(struct oce_dev *dev, uint32_t if_id,
1265     struct normal_vlan *vtag_arr, uint8_t vtag_cnt,
1266     boolean_t untagged, boolean_t enable_promisc, uint32_t mode)
1267 {
1268         struct oce_mbx mbx;
1269         struct  mbx_common_config_vlan *fwcmd;
1270         int ret;
1271 
1272         bzero(&mbx, sizeof (struct oce_mbx));
1273         fwcmd = (struct mbx_common_config_vlan *)&mbx.payload;
1274 
1275         /* initialize the ioctl header */
1276         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1277             MBX_SUBSYSTEM_COMMON,
1278             OPCODE_COMMON_NTWK_VLAN_CONFIG,
1279             MBX_TIMEOUT_SEC,
1280             sizeof (struct mbx_common_config_vlan), 0);
1281 
1282         fwcmd->params.req.if_id      = (uint8_t)if_id;
1283         fwcmd->params.req.promisc = (uint8_t)enable_promisc;
1284         fwcmd->params.req.untagged = (uint8_t)untagged;
1285         fwcmd->params.req.num_vlans = vtag_cnt;
1286 
1287         /* Set the vlan tag filter on hw */
1288         if (!enable_promisc) {
1289                 bcopy(fwcmd->params.req.tags.normal_vlans, vtag_arr,
1290                     vtag_cnt * sizeof (struct normal_vlan));
1291         }
1292 
1293         /* fill rest of mbx */
1294         mbx.u0.s.embedded = B_TRUE;
1295         mbx.payload_length = sizeof (struct mbx_common_config_vlan);
1296         DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + mbx.payload_length));
1297 
1298         /* post the command */
1299         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
1300 
1301         return (ret);
1302 } /* oce_config_vlan */
1303 
1304 
1305 /*
1306  * function to enable or disable the link
1307  *
1308  * dev - software handle to the device
1309  * mca_table - array of mcast address to update
1310  * mca_cnt - number of elements in mca_table
1311  * enable_promisc - flag to enable/disable mcast-promiscuous mode
1312  *
1313  * return 0 on success, EIO on failure
1314  */
1315 int
1316 oce_config_link(struct oce_dev *dev, boolean_t enable, uint32_t mode)
1317 {
1318         struct oce_mbx mbx;
1319         struct  mbx_common_func_link_cfg *fwcmd;
1320         int ret;
1321 
1322         bzero(&mbx, sizeof (struct oce_mbx));
1323         fwcmd = (struct mbx_common_func_link_cfg *)&mbx.payload;
1324 
1325         /* initialize the ioctl header */
1326         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1327             MBX_SUBSYSTEM_COMMON,
1328             OPCODE_COMMON_FUNCTION_LINK_CONFIG,
1329             MBX_TIMEOUT_SEC,
1330             sizeof (struct mbx_common_func_link_cfg), 0);
1331 
1332         fwcmd->params.req.enable = enable;
1333 
1334         /* fill rest of mbx */
1335         mbx.u0.s.embedded = B_TRUE;
1336         mbx.payload_length = sizeof (struct mbx_common_func_link_cfg);
1337         DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + mbx.payload_length));
1338 
1339         /* post the command */
1340         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
1341 
1342         return (ret);
1343 } /* oce_config_link */
1344 
1345 int
1346 oce_config_rss(struct oce_dev *dev, uint16_t if_id, char *hkey, char *itbl,
1347     int  tbl_sz, uint16_t rss_type, uint8_t flush, uint32_t mode)
1348 {
1349         struct oce_mbx mbx;
1350         struct mbx_config_nic_rss *fwcmd;
1351         int i;
1352         int ret = 0;
1353 
1354         bzero(&mbx, sizeof (struct oce_mbx));
1355         fwcmd = (struct mbx_config_nic_rss *)&mbx.payload;
1356 
1357         /* initialize the ioctl header */
1358         mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1359             MBX_SUBSYSTEM_NIC,
1360             OPCODE_CONFIG_NIC_RSS,
1361             MBX_TIMEOUT_SEC,
1362             sizeof (struct mbx_config_nic_rss), 0);
1363         fwcmd->params.req.enable_rss = LE_16(rss_type);
1364         fwcmd->params.req.flush = flush;
1365         fwcmd->params.req.if_id = LE_32(if_id);
1366 
1367         if (hkey != NULL) {
1368                 bcopy(hkey, fwcmd->params.req.hash, OCE_HKEY_SIZE);
1369         }
1370 
1371 
1372         /* Fill the indirection table */
1373         for (i = 0; i < tbl_sz; i++) {
1374                 fwcmd->params.req.cputable[i] = itbl[i];
1375         }
1376 
1377         fwcmd->params.req.cpu_tbl_sz_log2 = LE_16(OCE_LOG2(tbl_sz));
1378 
1379         /* fill rest of mbx */
1380         mbx.u0.s.embedded = B_TRUE;
1381         mbx.payload_length = sizeof (struct mbx_config_nic_rss);
1382         DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + OCE_MBX_RRHDR_SZ));
1383 
1384         /* post the command */
1385         ret = oce_issue_mbox_cmd(dev, &mbx, MBX_TIMEOUT_SEC, mode);
1386 
1387         return (ret);
1388 }
1389 
1390 /*
1391  * function to post a MBX to the mbox
1392  *
1393  * dev - software handle to the device
1394  * mbx - pointer to the MBX to send
1395  *
1396  * return 0 on success, error value on failure
1397  */
1398 int
1399 oce_issue_mbox_cmd(struct oce_dev *dev, struct oce_mbx *mbx,
1400     uint32_t tmo_sec, uint32_t flag)
1401 {
1402 
1403         struct oce_mq *mq;
1404         if (dev == NULL) {
1405                 oce_log(dev, CE_WARN, MOD_CONFIG,
1406                     "dev is null 0x%p", (void *)dev);
1407                 return (EINVAL);
1408         }
1409         mq = dev->mq;
1410 
1411         if ((dev->mq == NULL) || (mq->qstate != QCREATED) ||
1412             !(dev->state & STATE_INTR_ENABLED)) {
1413                 /* Force bootstrap mode if MQ is not created or intr disabled */
1414                 if (flag == MBX_ASYNC_MQ) {
1415                         oce_log(dev, CE_NOTE, MOD_CONFIG,
1416                             "Forcing bootstrap mode DEV STATE %x\n",
1417                             dev->state);
1418                         flag = MBX_BOOTSTRAP;
1419 
1420                 }
1421         }
1422         /* invoke appropriate functions depending on flag */
1423         switch (flag) {
1424         case MBX_BOOTSTRAP:
1425                 return (oce_mbox_issue_bootstrap(dev, mbx, tmo_sec));
1426         case MBX_ASYNC_MQ:
1427                 return (oce_enqueue_mq_mbox(dev, mbx, tmo_sec));
1428         default:
1429                 return (EINVAL);
1430         }
1431 
1432 }
1433 
1434 static struct oce_mbx_ctx *
1435 oce_init_mq_ctx(struct oce_dev *dev, struct oce_mbx *mbx)
1436 {
1437         struct oce_mbx_ctx *mbctx;
1438         mbctx = kmem_zalloc(sizeof (struct oce_mbx_ctx), KM_SLEEP);
1439 
1440         mbctx->mbx = mbx;
1441         cv_init(&mbctx->cond_var, NULL, CV_DRIVER, NULL);
1442         mutex_init(&mbctx->cv_lock, NULL, MUTEX_DRIVER,
1443             DDI_INTR_PRI(dev->intr_pri));
1444         mbx->tag[0] = ADDR_LO((uintptr_t)mbctx);
1445         mbx->tag[1] = ADDR_HI((uint64_t)(uintptr_t)mbctx);
1446         return (mbctx);
1447 }
1448 
1449 static void
1450 oce_destroy_mq_ctx(struct oce_mbx_ctx *mbctx)
1451 {
1452         cv_destroy(&mbctx->cond_var);
1453         mutex_destroy(&mbctx->cv_lock);
1454         kmem_free(mbctx, sizeof (struct oce_mbx_ctx));
1455 }
1456 
1457 static uint32_t
1458 oce_enqueue_mq_mbox(struct oce_dev *dev, struct oce_mbx *mbx, uint32_t tmo_sec)
1459 {
1460         struct oce_mbx_ctx *mbctx;
1461         uint32_t status;
1462 
1463         _NOTE(ARGUNUSED(tmo_sec));
1464 
1465         mbctx = oce_init_mq_ctx(dev, mbx);
1466 
1467         if (mbctx == NULL) {
1468                 return (EIO);
1469         }
1470         mutex_enter(&mbctx->cv_lock);
1471         mbctx->mbx_status = MBX_BUSY;
1472         if (oce_issue_mq_mbox(dev, mbx) != MBX_SUCCESS) {
1473                 mutex_exit(&mbctx->cv_lock);
1474                 oce_destroy_mq_ctx(mbctx);
1475                 return (EIO);
1476         }
1477         while (mbctx->mbx_status & MBX_BUSY) {
1478                 cv_wait(&mbctx->cond_var, &mbctx->cv_lock);
1479         }
1480         status = mbctx->compl_status;
1481         mutex_exit(&mbctx->cv_lock);
1482         oce_destroy_mq_ctx(mbctx);
1483         return (status);
1484 }
1485 
1486 /*
1487  * function called from the gld ioctl entry point to send a mbx to fw
1488  *
1489  * dev - software handle to the device
1490  * mp - mblk_t containing the user data
1491  * payload_len = [OUT] pointer to return the length of the payload written
1492  *
1493  * return 0 on Success
1494  */
1495 int
1496 oce_issue_mbox_passthru(struct oce_dev *dev, queue_t *wq, mblk_t *mp,
1497     uint32_t *rsp_len)
1498 {
1499         int ret = 0;
1500         struct oce_mbx mbx;
1501         struct mbx_hdr hdr = {0};
1502         struct mbx_hdr *rsp_hdr = NULL;
1503         boolean_t is_embedded = B_FALSE;
1504         int32_t payload_length = 0;
1505         int offset = 0;
1506         mblk_t *tmp = NULL;
1507         uint32_t tmo;
1508         oce_dma_buf_t dbuf = {0};
1509 
1510         _NOTE(ARGUNUSED(wq));
1511 
1512         bzero(&mbx, sizeof (struct oce_mbx));
1513 
1514         /* initialize the response len */
1515         *rsp_len = 0;
1516 
1517         /* copy and swap the request header */
1518         bcopy(mp->b_cont->b_rptr, &hdr, sizeof (struct mbx_hdr));
1519         DW_SWAP(u32ptr(&hdr), sizeof (struct mbx_hdr));
1520 
1521         payload_length = hdr.u0.req.request_length +
1522             sizeof (struct mbx_hdr);
1523         is_embedded = (payload_length <= sizeof (struct oce_mbx_payload));
1524 
1525         /* get the timeout from the command header */
1526         tmo = hdr.u0.req.timeout;
1527 
1528         oce_log(dev, CE_NOTE, MOD_CONFIG,
1529             "Mailbox command: opcode=%d, subsystem=%d, timeout=%d",
1530             hdr.u0.req.opcode, hdr.u0.req.subsystem, tmo);
1531 
1532         if (!is_embedded) {
1533                 ddi_dma_cookie_t cookie;
1534                 int alloc_len = 0;
1535                 int num_buf = 0;
1536 
1537                 /* Calculate memory size to alloc */
1538                 alloc_len = msgdsize(mp->b_cont);
1539 
1540                 /* allocate the DMA memory */
1541                 ret = oce_alloc_dma_buffer(dev, &dbuf, alloc_len,
1542                     &oce_sgl_dma_attr, DDI_DMA_CONSISTENT|DDI_DMA_RDWR);
1543                 if (ret != DDI_SUCCESS) {
1544                         return (ENOMEM);
1545                 }
1546 
1547                 for (tmp = mp->b_cont; tmp != NULL; tmp = tmp->b_cont) {
1548                         bcopy((caddr_t)tmp->b_rptr, DBUF_VA(dbuf) + offset,
1549                             MBLKL(tmp));
1550                         offset += MBLKL(tmp);
1551                 }
1552 
1553                 cookie = dbuf.cookie;
1554                 for (num_buf = 0; num_buf < dbuf.ncookies; num_buf++) {
1555                         /* fill the mbx sglist */
1556                         mbx.payload.u0.u1.sgl[num_buf].pa_lo =
1557                             LE_32(ADDR_LO(cookie.dmac_laddress));
1558                         mbx.payload.u0.u1.sgl[num_buf].pa_hi =
1559                             LE_32(ADDR_HI(cookie.dmac_laddress));
1560                         mbx.payload.u0.u1.sgl[num_buf].length =
1561                             LE_32((uint32_t)cookie.dmac_size);
1562 
1563                         if (dbuf.ncookies > 1) {
1564                                 (void) ddi_dma_nextcookie(DBUF_DHDL(dbuf),
1565                                     &cookie);
1566                         }
1567                 }
1568                 mbx.u0.s.embedded = 0;
1569                 mbx.payload_length = alloc_len;
1570                 mbx.u0.s.sge_count = dbuf.ncookies;
1571                 oce_log(dev, CE_NOTE, MOD_CONFIG,
1572                     "sg count %d, payload_length = %d",
1573                     dbuf.ncookies, alloc_len);
1574 
1575         } else {
1576                 /* fill rest of mbx */
1577                 mbx.u0.s.embedded = 1;
1578                 mbx.payload_length = payload_length;
1579                 bcopy(mp->b_cont->b_rptr, &mbx.payload, payload_length);
1580         }
1581 
1582         /* swap the bootstrap header only */
1583         OCE_DW_SWAP(u32ptr(&mbx), OCE_BMBX_RHDR_SZ);
1584 
1585         /* now post the command */
1586         ret = oce_issue_mbox_cmd(dev, &mbx, tmo, MBX_ASYNC_MQ);
1587 
1588         if (ret != DDI_SUCCESS) {
1589                 goto fail;
1590         }
1591 
1592         /* Copy the response back only if this is an embedded mbx cmd */
1593         if (is_embedded) {
1594                 rsp_hdr = (struct mbx_hdr *)&mbx.payload;
1595         } else {
1596                 /* sync */
1597                 (void) ddi_dma_sync(DBUF_DHDL(dbuf), 0, 0,
1598                     DDI_DMA_SYNC_FORKERNEL);
1599                 if (oce_fm_check_dma_handle(dev, DBUF_DHDL(dbuf)) !=
1600                     DDI_FM_OK) {
1601                         ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
1602                         ret = EIO;
1603                         goto fail;
1604                 }
1605 
1606                 /* Get the mailbox header from SG list */
1607                 rsp_hdr = (struct mbx_hdr *)DBUF_VA(dbuf);
1608         }
1609         payload_length = LE_32(rsp_hdr->u0.rsp.actual_rsp_length)
1610             + sizeof (struct mbx_hdr);
1611         *rsp_len = payload_length;
1612 
1613         oce_log(dev, CE_NOTE, MOD_CONFIG,
1614             "Response Len %d status=0x%x, addnl_status=0x%x", payload_length,
1615             rsp_hdr->u0.rsp.status, rsp_hdr->u0.rsp.additional_status);
1616 
1617         for (tmp = mp->b_cont, offset = 0; tmp != NULL && payload_length > 0;
1618             tmp = tmp->b_cont) {
1619                 bcopy((caddr_t)rsp_hdr + offset, tmp->b_rptr, MBLKL(tmp));
1620                 offset += MBLKL(tmp);
1621                 payload_length -= MBLKL(tmp);
1622         }
1623 fail:
1624         oce_free_dma_buffer(dev, &dbuf);
1625         return (ret);
1626 }