Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  be_cmds.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2005 - 2016 Broadcom
 * All rights reserved.
 *
 * Contact Information:
 * linux-drivers@emulex.com
 *
 * Emulex
 * 3333 Susan Street
 * Costa Mesa, CA 92626
 */


#include <linux/module.h>
#include "be.h"
#include "be_cmds.h"

const char * const be_misconfig_evt_port_state[] = {
 "Physical Link is functional",
 "Optics faulted/incorrectly installed/not installed - Reseat optics. If issue not resolved, replace.",
 "Optics of two types installed – Remove one optic or install matching pair of optics.",
 "Incompatible optics – Replace with compatible optics for card to function.",
 "Unqualified optics – Replace with Avago optics for Warranty and Technical Support.",
 "Uncertified optics – Replace with Avago-certified optics to enable link operation."
};

static char *be_port_misconfig_evt_severity[] = {
 "KERN_WARN",
 "KERN_INFO",
 "KERN_ERR",
 "KERN_WARN"
};

static char *phy_state_oper_desc[] = {
 "Link is non-operational",
 "Link is operational",
 ""
};

static struct be_cmd_priv_map cmd_priv_map[] = {
 {
  OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG,
  CMD_SUBSYSTEM_ETH,
  BE_PRIV_LNKMGMT | BE_PRIV_VHADM |
  BE_PRIV_DEVCFG | BE_PRIV_DEVSEC
 },
 {
  OPCODE_COMMON_GET_FLOW_CONTROL,
  CMD_SUBSYSTEM_COMMON,
  BE_PRIV_LNKQUERY | BE_PRIV_VHADM |
  BE_PRIV_DEVCFG | BE_PRIV_DEVSEC
 },
 {
  OPCODE_COMMON_SET_FLOW_CONTROL,
  CMD_SUBSYSTEM_COMMON,
  BE_PRIV_LNKMGMT | BE_PRIV_VHADM |
  BE_PRIV_DEVCFG | BE_PRIV_DEVSEC
 },
 {
  OPCODE_ETH_GET_PPORT_STATS,
  CMD_SUBSYSTEM_ETH,
  BE_PRIV_LNKMGMT | BE_PRIV_VHADM |
  BE_PRIV_DEVCFG | BE_PRIV_DEVSEC
 },
 {
  OPCODE_COMMON_GET_PHY_DETAILS,
  CMD_SUBSYSTEM_COMMON,
  BE_PRIV_LNKMGMT | BE_PRIV_VHADM |
  BE_PRIV_DEVCFG | BE_PRIV_DEVSEC
 },
 {
  OPCODE_LOWLEVEL_HOST_DDR_DMA,
  CMD_SUBSYSTEM_LOWLEVEL,
  BE_PRIV_DEVCFG | BE_PRIV_DEVSEC
 },
 {
  OPCODE_LOWLEVEL_LOOPBACK_TEST,
  CMD_SUBSYSTEM_LOWLEVEL,
  BE_PRIV_DEVCFG | BE_PRIV_DEVSEC
 },
 {
  OPCODE_LOWLEVEL_SET_LOOPBACK_MODE,
  CMD_SUBSYSTEM_LOWLEVEL,
  BE_PRIV_DEVCFG | BE_PRIV_DEVSEC
 },
 {
  OPCODE_COMMON_SET_HSW_CONFIG,
  CMD_SUBSYSTEM_COMMON,
  BE_PRIV_DEVCFG | BE_PRIV_VHADM |
  BE_PRIV_DEVSEC
 },
 {
  OPCODE_COMMON_GET_EXT_FAT_CAPABILITIES,
  CMD_SUBSYSTEM_COMMON,
  BE_PRIV_DEVCFG
 }
};

static bool be_cmd_allowed(struct be_adapter *adapter, u8 opcode, u8 subsystem)
{
 int i;
 int num_entries = ARRAY_SIZE(cmd_priv_map);
 u32 cmd_privileges = adapter->cmd_privileges;

 for (i = 0; i < num_entries; i++)
  if (opcode == cmd_priv_map[i].opcode &&
      subsystem == cmd_priv_map[i].subsystem)
   if (!(cmd_privileges & cmd_priv_map[i].priv_mask))
    return false;

 return true;
}

static inline void *embedded_payload(struct be_mcc_wrb *wrb)
{
 return wrb->payload.embedded_payload;
}

static int be_mcc_notify(struct be_adapter *adapter)
{
 struct be_queue_info *mccq = &adapter->mcc_obj.q;
 u32 val = 0;

 if (be_check_error(adapter, BE_ERROR_ANY))
  return -EIO;

 val |= mccq->id & DB_MCCQ_RING_ID_MASK;
 val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;

 wmb();
 iowrite32(val, adapter->db + DB_MCCQ_OFFSET);

 return 0;
}

/* To check if valid bit is set, check the entire word as we don't know
 * the endianness of the data (old entry is host endian while a new entry is
 * little endian)
 */

static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
{
 u32 flags;

 if (compl->flags != 0) {
  flags = le32_to_cpu(compl->flags);
  if (flags & CQE_FLAGS_VALID_MASK) {
   compl->flags = flags;
   return true;
  }
 }
 return false;
}

/* Need to reset the entire word that houses the valid bit */
static inline void be_mcc_compl_use(struct be_mcc_compl *compl)
{
 compl->flags = 0;
}

static struct be_cmd_resp_hdr *be_decode_resp_hdr(u32 tag0, u32 tag1)
{
 unsigned long addr;

 addr = tag1;
 addr = ((addr << 16) << 16) | tag0;
 return (void *)addr;
}

static bool be_skip_err_log(u8 opcode, u16 base_status, u16 addl_status)
{
 if (base_status == MCC_STATUS_NOT_SUPPORTED ||
     base_status == MCC_STATUS_ILLEGAL_REQUEST ||
     addl_status == MCC_ADDL_STATUS_TOO_MANY_INTERFACES ||
     addl_status == MCC_ADDL_STATUS_INSUFFICIENT_VLANS ||
     (opcode == OPCODE_COMMON_WRITE_FLASHROM &&
     (base_status == MCC_STATUS_ILLEGAL_FIELD ||
      addl_status == MCC_ADDL_STATUS_FLASH_IMAGE_CRC_MISMATCH)))
  return true;
 else
  return false;
}

/* Place holder for all the async MCC cmds wherein the caller is not in a busy
 * loop (has not issued be_mcc_notify_wait())
 */

static void be_async_cmd_process(struct be_adapter *adapter,
     struct be_mcc_compl *compl,
     struct be_cmd_resp_hdr *resp_hdr)
{
 enum mcc_base_status base_status = base_status(compl->status);
 u8 opcode = 0, subsystem = 0;

 if (resp_hdr) {
  opcode = resp_hdr->opcode;
  subsystem = resp_hdr->subsystem;
 }

 if (opcode == OPCODE_LOWLEVEL_LOOPBACK_TEST &&
     subsystem == CMD_SUBSYSTEM_LOWLEVEL) {
  complete(&adapter->et_cmd_compl);
  return;
 }

 if (opcode == OPCODE_LOWLEVEL_SET_LOOPBACK_MODE &&
     subsystem == CMD_SUBSYSTEM_LOWLEVEL) {
  complete(&adapter->et_cmd_compl);
  return;
 }

 if ((opcode == OPCODE_COMMON_WRITE_FLASHROM ||
      opcode == OPCODE_COMMON_WRITE_OBJECT) &&
     subsystem == CMD_SUBSYSTEM_COMMON) {
  adapter->flash_status = compl->status;
  complete(&adapter->et_cmd_compl);
  return;
 }

 if ((opcode == OPCODE_ETH_GET_STATISTICS ||
      opcode == OPCODE_ETH_GET_PPORT_STATS) &&
     subsystem == CMD_SUBSYSTEM_ETH &&
     base_status == MCC_STATUS_SUCCESS) {
  be_parse_stats(adapter);
  adapter->stats_cmd_sent = false;
  return;
 }

 if (opcode == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES &&
     subsystem == CMD_SUBSYSTEM_COMMON) {
  if (base_status == MCC_STATUS_SUCCESS) {
   struct be_cmd_resp_get_cntl_addnl_attribs *resp =
       (void *)resp_hdr;
   adapter->hwmon_info.be_on_die_temp =
      resp->on_die_temperature;
  } else {
   adapter->be_get_temp_freq = 0;
   adapter->hwmon_info.be_on_die_temp =
      BE_INVALID_DIE_TEMP;
  }
  return;
 }
}

static int be_mcc_compl_process(struct be_adapter *adapter,
    struct be_mcc_compl *compl)
{
 enum mcc_base_status base_status;
 enum mcc_addl_status addl_status;
 struct be_cmd_resp_hdr *resp_hdr;
 u8 opcode = 0, subsystem = 0;

 /* Just swap the status to host endian; mcc tag is opaquely copied
 * from mcc_wrb
 */

 be_dws_le_to_cpu(compl, 4);

 base_status = base_status(compl->status);
 addl_status = addl_status(compl->status);

 resp_hdr = be_decode_resp_hdr(compl->tag0, compl->tag1);
 if (resp_hdr) {
  opcode = resp_hdr->opcode;
  subsystem = resp_hdr->subsystem;
 }

 be_async_cmd_process(adapter, compl, resp_hdr);

 if (base_status != MCC_STATUS_SUCCESS &&
     !be_skip_err_log(opcode, base_status, addl_status)) {
  if (base_status == MCC_STATUS_UNAUTHORIZED_REQUEST ||
      addl_status == MCC_ADDL_STATUS_INSUFFICIENT_PRIVILEGES) {
   dev_warn(&adapter->pdev->dev,
     "VF is not privileged to issue opcode %d-%d\n",
     opcode, subsystem);
  } else {
   dev_err(&adapter->pdev->dev,
    "opcode %d-%d failed:status %d-%d\n",
    opcode, subsystem, base_status, addl_status);
  }
 }
 return compl->status;
}

/* Link state evt is a string of bytes; no need for endian swapping */
static void be_async_link_state_process(struct be_adapter *adapter,
     struct be_mcc_compl *compl)
{
 struct be_async_event_link_state *evt =
   (struct be_async_event_link_state *)compl;

 /* When link status changes, link speed must be re-queried from FW */
 adapter->phy.link_speed = -1;

 /* On BEx the FW does not send a separate link status
 * notification for physical and logical link.
 * On other chips just process the logical link
 * status notification
 */

 if (!BEx_chip(adapter) &&
     !(evt->port_link_status & LOGICAL_LINK_STATUS_MASK))
  return;

 /* For the initial link status do not rely on the ASYNC event as
 * it may not be received in some cases.
 */

 if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT)
  be_link_status_update(adapter,
          evt->port_link_status & LINK_STATUS_MASK);
}

static void be_async_port_misconfig_event_process(struct be_adapter *adapter,
        struct be_mcc_compl *compl)
{
 struct be_async_event_misconfig_port *evt =
   (struct be_async_event_misconfig_port *)compl;
 u32 sfp_misconfig_evt_word1 = le32_to_cpu(evt->event_data_word1);
 u32 sfp_misconfig_evt_word2 = le32_to_cpu(evt->event_data_word2);
 u8 phy_oper_state = PHY_STATE_OPER_MSG_NONE;
 struct device *dev = &adapter->pdev->dev;
 u8 msg_severity = DEFAULT_MSG_SEVERITY;
 u8 phy_state_info;
 u8 new_phy_state;

 new_phy_state =
  (sfp_misconfig_evt_word1 >> (adapter->hba_port_num * 8)) & 0xff;

 if (new_phy_state == adapter->phy_state)
  return;

 adapter->phy_state = new_phy_state;

 /* for older fw that doesn't populate link effect data */
 if (!sfp_misconfig_evt_word2)
  goto log_message;

 phy_state_info =
  (sfp_misconfig_evt_word2 >> (adapter->hba_port_num * 8)) & 0xff;

 if (phy_state_info & PHY_STATE_INFO_VALID) {
  msg_severity = (phy_state_info & PHY_STATE_MSG_SEVERITY) >> 1;

  if (be_phy_unqualified(new_phy_state))
   phy_oper_state = (phy_state_info & PHY_STATE_OPER);
 }

log_message:
 /* Log an error message that would allow a user to determine
 * whether the SFPs have an issue
 */

 if (be_phy_state_unknown(new_phy_state))
  dev_printk(be_port_misconfig_evt_severity[msg_severity], dev,
      "Port %c: Unrecognized Optics state: 0x%x. %s",
      adapter->port_name,
      new_phy_state,
      phy_state_oper_desc[phy_oper_state]);
 else
  dev_printk(be_port_misconfig_evt_severity[msg_severity], dev,
      "Port %c: %s %s",
      adapter->port_name,
      be_misconfig_evt_port_state[new_phy_state],
      phy_state_oper_desc[phy_oper_state]);

 /* Log Vendor name and part no. if a misconfigured SFP is detected */
 if (be_phy_misconfigured(new_phy_state))
  adapter->flags |= BE_FLAGS_PHY_MISCONFIGURED;
}

/* Grp5 CoS Priority evt */
static void be_async_grp5_cos_priority_process(struct be_adapter *adapter,
            struct be_mcc_compl *compl)
{
 struct be_async_event_grp5_cos_priority *evt =
   (struct be_async_event_grp5_cos_priority *)compl;

 if (evt->valid) {
  adapter->vlan_prio_bmap = evt->available_priority_bmap;
  adapter->recommended_prio_bits =
   evt->reco_default_priority << VLAN_PRIO_SHIFT;
 }
}

/* Grp5 QOS Speed evt: qos_link_speed is in units of 10 Mbps */
static void be_async_grp5_qos_speed_process(struct be_adapter *adapter,
         struct be_mcc_compl *compl)
{
 struct be_async_event_grp5_qos_link_speed *evt =
   (struct be_async_event_grp5_qos_link_speed *)compl;

 if (adapter->phy.link_speed >= 0 &&
     evt->physical_port == adapter->port_num)
  adapter->phy.link_speed = le16_to_cpu(evt->qos_link_speed) * 10;
}

/*Grp5 PVID evt*/
static void be_async_grp5_pvid_state_process(struct be_adapter *adapter,
          struct be_mcc_compl *compl)
{
 struct be_async_event_grp5_pvid_state *evt =
   (struct be_async_event_grp5_pvid_state *)compl;

 if (evt->enabled) {
  adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK;
  dev_info(&adapter->pdev->dev, "LPVID: %d\n", adapter->pvid);
 } else {
  adapter->pvid = 0;
 }
}

#define MGMT_ENABLE_MASK 0x4
static void be_async_grp5_fw_control_process(struct be_adapter *adapter,
          struct be_mcc_compl *compl)
{
 struct be_async_fw_control *evt = (struct be_async_fw_control *)compl;
 u32 evt_dw1 = le32_to_cpu(evt->event_data_word1);

 if (evt_dw1 & MGMT_ENABLE_MASK) {
  adapter->flags |= BE_FLAGS_OS2BMC;
  adapter->bmc_filt_mask = le32_to_cpu(evt->event_data_word2);
 } else {
  adapter->flags &= ~BE_FLAGS_OS2BMC;
 }
}

static void be_async_grp5_evt_process(struct be_adapter *adapter,
          struct be_mcc_compl *compl)
{
 u8 event_type = (compl->flags >> ASYNC_EVENT_TYPE_SHIFT) &
    ASYNC_EVENT_TYPE_MASK;

 switch (event_type) {
 case ASYNC_EVENT_COS_PRIORITY:
  be_async_grp5_cos_priority_process(adapter, compl);
  break;
 case ASYNC_EVENT_QOS_SPEED:
  be_async_grp5_qos_speed_process(adapter, compl);
  break;
 case ASYNC_EVENT_PVID_STATE:
  be_async_grp5_pvid_state_process(adapter, compl);
  break;
 /* Async event to disable/enable os2bmc and/or mac-learning */
 case ASYNC_EVENT_FW_CONTROL:
  be_async_grp5_fw_control_process(adapter, compl);
  break;
 default:
  break;
 }
}

static void be_async_dbg_evt_process(struct be_adapter *adapter,
         struct be_mcc_compl *cmp)
{
 u8 event_type = 0;
 struct be_async_event_qnq *evt = (struct be_async_event_qnq *)cmp;

 event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) &
   ASYNC_EVENT_TYPE_MASK;

 switch (event_type) {
 case ASYNC_DEBUG_EVENT_TYPE_QNQ:
  if (evt->valid)
   adapter->qnq_vid = le16_to_cpu(evt->vlan_tag);
  adapter->flags |= BE_FLAGS_QNQ_ASYNC_EVT_RCVD;
 break;
 default:
  dev_warn(&adapter->pdev->dev, "Unknown debug event 0x%x!\n",
    event_type);
 break;
 }
}

static void be_async_sliport_evt_process(struct be_adapter *adapter,
      struct be_mcc_compl *cmp)
{
 u8 event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) &
   ASYNC_EVENT_TYPE_MASK;

 if (event_type == ASYNC_EVENT_PORT_MISCONFIG)
  be_async_port_misconfig_event_process(adapter, cmp);
}

static inline bool is_link_state_evt(u32 flags)
{
 return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) ==
   ASYNC_EVENT_CODE_LINK_STATE;
}

static inline bool is_grp5_evt(u32 flags)
{
 return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) ==
   ASYNC_EVENT_CODE_GRP_5;
}

static inline bool is_dbg_evt(u32 flags)
{
 return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) ==
   ASYNC_EVENT_CODE_QNQ;
}

static inline bool is_sliport_evt(u32 flags)
{
 return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) ==
  ASYNC_EVENT_CODE_SLIPORT;
}

static void be_mcc_event_process(struct be_adapter *adapter,
     struct be_mcc_compl *compl)
{
 if (is_link_state_evt(compl->flags))
  be_async_link_state_process(adapter, compl);
 else if (is_grp5_evt(compl->flags))
  be_async_grp5_evt_process(adapter, compl);
 else if (is_dbg_evt(compl->flags))
  be_async_dbg_evt_process(adapter, compl);
 else if (is_sliport_evt(compl->flags))
  be_async_sliport_evt_process(adapter, compl);
}

static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
{
 struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq;
 struct be_mcc_compl *compl = queue_tail_node(mcc_cq);

 if (be_mcc_compl_is_new(compl)) {
  queue_tail_inc(mcc_cq);
  return compl;
 }
 return NULL;
}

void be_async_mcc_enable(struct be_adapter *adapter)
{
 spin_lock_bh(&adapter->mcc_cq_lock);

 be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, 0);
 adapter->mcc_obj.rearm_cq = true;

 spin_unlock_bh(&adapter->mcc_cq_lock);
}

void be_async_mcc_disable(struct be_adapter *adapter)
{
 spin_lock_bh(&adapter->mcc_cq_lock);

 adapter->mcc_obj.rearm_cq = false;
 be_cq_notify(adapter, adapter->mcc_obj.cq.id, false, 0);

 spin_unlock_bh(&adapter->mcc_cq_lock);
}

int be_process_mcc(struct be_adapter *adapter)
{
 struct be_mcc_compl *compl;
 int num = 0, status = 0;
 struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;

 spin_lock(&adapter->mcc_cq_lock);

 while ((compl = be_mcc_compl_get(adapter))) {
  if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
   be_mcc_event_process(adapter, compl);
  } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
   status = be_mcc_compl_process(adapter, compl);
   atomic_dec(&mcc_obj->q.used);
  }
  be_mcc_compl_use(compl);
  num++;
 }

 if (num)
  be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num);

 spin_unlock(&adapter->mcc_cq_lock);
 return status;
}

/* Wait till no more pending mcc requests are present */
static int be_mcc_wait_compl(struct be_adapter *adapter)
{
#define mcc_timeout  120000 /* 12s timeout */
 int i, status = 0;
 struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;

 for (i = 0; i < mcc_timeout; i++) {
  if (be_check_error(adapter, BE_ERROR_ANY))
   return -EIO;

  local_bh_disable();
  status = be_process_mcc(adapter);
  local_bh_enable();

  if (atomic_read(&mcc_obj->q.used) == 0)
   break;
  udelay(100);
 }
 if (i == mcc_timeout) {
  dev_err(&adapter->pdev->dev, "FW not responding\n");
  be_set_error(adapter, BE_ERROR_FW);
  return -EIO;
 }
 return status;
}

/* Notify MCC requests and wait for completion */
static int be_mcc_notify_wait(struct be_adapter *adapter)
{
 int status;
 struct be_mcc_wrb *wrb;
 struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
 u32 index = mcc_obj->q.head;
 struct be_cmd_resp_hdr *resp;

 index_dec(&index, mcc_obj->q.len);
 wrb = queue_index_node(&mcc_obj->q, index);

 resp = be_decode_resp_hdr(wrb->tag0, wrb->tag1);

 status = be_mcc_notify(adapter);
 if (status)
  goto out;

 status = be_mcc_wait_compl(adapter);
 if (status == -EIO)
  goto out;

 status = (resp->base_status |
    ((resp->addl_status & CQE_ADDL_STATUS_MASK) <<
     CQE_ADDL_STATUS_SHIFT));
out:
 return status;
}

static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
{
 int msecs = 0;
 u32 ready;

 do {
  if (be_check_error(adapter, BE_ERROR_ANY))
   return -EIO;

  ready = ioread32(db);
  if (ready == 0xffffffff)
   return -1;

  ready &= MPU_MAILBOX_DB_RDY_MASK;
  if (ready)
   break;

  if (msecs > 4000) {
   dev_err(&adapter->pdev->dev, "FW not responding\n");
   be_set_error(adapter, BE_ERROR_FW);
   be_detect_error(adapter);
   return -1;
  }

  msleep(1);
  msecs++;
 } while (true);

 return 0;
}

/* Insert the mailbox address into the doorbell in two steps
 * Polls on the mbox doorbell till a command completion (or a timeout) occurs
 */

static int be_mbox_notify_wait(struct be_adapter *adapter)
{
 int status;
 u32 val = 0;
 void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET;
 struct be_dma_mem *mbox_mem = &adapter->mbox_mem;
 struct be_mcc_mailbox *mbox = mbox_mem->va;
 struct be_mcc_compl *compl = &mbox->compl;

 /* wait for ready to be set */
 status = be_mbox_db_ready_wait(adapter, db);
 if (status != 0)
  return status;

 val |= MPU_MAILBOX_DB_HI_MASK;
 /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
 val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
 iowrite32(val, db);

 /* wait for ready to be set */
 status = be_mbox_db_ready_wait(adapter, db);
 if (status != 0)
  return status;

 val = 0;
 /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */
 val |= (u32)(mbox_mem->dma >> 4) << 2;
 iowrite32(val, db);

 status = be_mbox_db_ready_wait(adapter, db);
 if (status != 0)
  return status;

 /* A cq entry has been made now */
 if (be_mcc_compl_is_new(compl)) {
  status = be_mcc_compl_process(adapter, &mbox->compl);
  be_mcc_compl_use(compl);
  if (status)
   return status;
 } else {
  dev_err(&adapter->pdev->dev, "invalid mailbox completion\n");
  return -1;
 }
 return 0;
}

u16 be_POST_stage_get(struct be_adapter *adapter)
{
 u32 sem;

 if (BEx_chip(adapter))
  sem  = ioread32(adapter->csr + SLIPORT_SEMAPHORE_OFFSET_BEx);
 else
  pci_read_config_dword(adapter->pdev,
          SLIPORT_SEMAPHORE_OFFSET_SH, &sem);

 return sem & POST_STAGE_MASK;
}

static int lancer_wait_ready(struct be_adapter *adapter)
{
#define SLIPORT_READY_TIMEOUT 30
 u32 sliport_status;
 int i;

 for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) {
  sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
  if (sliport_status & SLIPORT_STATUS_RDY_MASK)
   return 0;

  if (sliport_status & SLIPORT_STATUS_ERR_MASK &&
      !(sliport_status & SLIPORT_STATUS_RN_MASK))
   return -EIO;

  msleep(1000);
 }

 return sliport_status ? : -1;
}

int be_fw_wait_ready(struct be_adapter *adapter)
{
 u16 stage;
 int status, timeout = 0;
 struct device *dev = &adapter->pdev->dev;

 if (lancer_chip(adapter)) {
  status = lancer_wait_ready(adapter);
  if (status) {
   stage = status;
   goto err;
  }
  return 0;
 }

 do {
  /* There's no means to poll POST state on BE2/3 VFs */
  if (BEx_chip(adapter) && be_virtfn(adapter))
   return 0;

  stage = be_POST_stage_get(adapter);
  if (stage == POST_STAGE_ARMFW_RDY)
   return 0;

  dev_info(dev, "Waiting for POST, %ds elapsed\n", timeout);
  if (msleep_interruptible(2000)) {
   dev_err(dev, "Waiting for POST aborted\n");
   return -EINTR;
  }
  timeout += 2;
 } while (timeout < 60);

err:
 dev_err(dev, "POST timeout; stage=%#x\n", stage);
 return -ETIMEDOUT;
}

static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
{
 return &wrb->payload.sgl[0];
}

static inline void fill_wrb_tags(struct be_mcc_wrb *wrb, unsigned long addr)
{
 wrb->tag0 = addr & 0xFFFFFFFF;
 wrb->tag1 = upper_32_bits(addr);
}

/* Don't touch the hdr after it's prepared */
/* mem will be NULL for embedded commands */
static void be_wrb_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
       u8 subsystem, u8 opcode, int cmd_len,
       struct be_mcc_wrb *wrb,
       struct be_dma_mem *mem)
{
 struct be_sge *sge;

 req_hdr->opcode = opcode;
 req_hdr->subsystem = subsystem;
 req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
 req_hdr->version = 0;
 fill_wrb_tags(wrb, (ulong)req_hdr);
 wrb->payload_length = cmd_len;
 if (mem) {
  wrb->embedded |= (1 & MCC_WRB_SGE_CNT_MASK) <<
   MCC_WRB_SGE_CNT_SHIFT;
  sge = nonembedded_sgl(wrb);
  sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma));
  sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF);
  sge->len = cpu_to_le32(mem->size);
 } else
  wrb->embedded |= MCC_WRB_EMBEDDED_MASK;
 be_dws_cpu_to_le(wrb, 8);
}

static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
          struct be_dma_mem *mem)
{
 int i, buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages);
 u64 dma = (u64)mem->dma;

 for (i = 0; i < buf_pages; i++) {
  pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF);
  pages[i].hi = cpu_to_le32(upper_32_bits(dma));
  dma += PAGE_SIZE_4K;
 }
}

static inline struct be_mcc_wrb *wrb_from_mbox(struct be_adapter *adapter)
{
 struct be_dma_mem *mbox_mem = &adapter->mbox_mem;
 struct be_mcc_wrb *wrb = &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb;

 memset(wrb, 0, sizeof(*wrb));
 return wrb;
}

static struct be_mcc_wrb *wrb_from_mccq(struct be_adapter *adapter)
{
 struct be_queue_info *mccq = &adapter->mcc_obj.q;
 struct be_mcc_wrb *wrb;

 if (!mccq->created)
  return NULL;

 if (atomic_read(&mccq->used) >= mccq->len)
  return NULL;

 wrb = queue_head_node(mccq);
 queue_head_inc(mccq);
 atomic_inc(&mccq->used);
 memset(wrb, 0, sizeof(*wrb));
 return wrb;
}

static bool use_mcc(struct be_adapter *adapter)
{
 return adapter->mcc_obj.q.created;
}

/* Must be used only in process context */
static int be_cmd_lock(struct be_adapter *adapter)
{
 if (use_mcc(adapter)) {
  spin_lock_bh(&adapter->mcc_lock);
  return 0;
 } else {
  return mutex_lock_interruptible(&adapter->mbox_lock);
 }
}

/* Must be used only in process context */
static void be_cmd_unlock(struct be_adapter *adapter)
{
 if (use_mcc(adapter))
  return spin_unlock_bh(&adapter->mcc_lock);
 else
  return mutex_unlock(&adapter->mbox_lock);
}

static struct be_mcc_wrb *be_cmd_copy(struct be_adapter *adapter,
          struct be_mcc_wrb *wrb)
{
 struct be_mcc_wrb *dest_wrb;

 if (use_mcc(adapter)) {
  dest_wrb = wrb_from_mccq(adapter);
  if (!dest_wrb)
   return NULL;
 } else {
  dest_wrb = wrb_from_mbox(adapter);
 }

 memcpy(dest_wrb, wrb, sizeof(*wrb));
 if (wrb->embedded & cpu_to_le32(MCC_WRB_EMBEDDED_MASK))
  fill_wrb_tags(dest_wrb, (ulong)embedded_payload(wrb));

 return dest_wrb;
}

/* Must be used only in process context */
static int be_cmd_notify_wait(struct be_adapter *adapter,
         struct be_mcc_wrb *wrb)
{
 struct be_mcc_wrb *dest_wrb;
 int status;

 status = be_cmd_lock(adapter);
 if (status)
  return status;

 dest_wrb = be_cmd_copy(adapter, wrb);
 if (!dest_wrb) {
  status = -EBUSY;
  goto unlock;
 }

 if (use_mcc(adapter))
  status = be_mcc_notify_wait(adapter);
 else
  status = be_mbox_notify_wait(adapter);

 if (!status)
  memcpy(wrb, dest_wrb, sizeof(*wrb));

unlock:
 be_cmd_unlock(adapter);
 return status;
}

/* Tell fw we're about to start firing cmds by writing a
 * special pattern across the wrb hdr; uses mbox
 */

int be_cmd_fw_init(struct be_adapter *adapter)
{
 u8 *wrb;
 int status;

 if (lancer_chip(adapter))
  return 0;

 if (mutex_lock_interruptible(&adapter->mbox_lock))
  return -1;

 wrb = (u8 *)wrb_from_mbox(adapter);
 *wrb++ = 0xFF;
 *wrb++ = 0x12;
 *wrb++ = 0x34;
 *wrb++ = 0xFF;
 *wrb++ = 0xFF;
 *wrb++ = 0x56;
 *wrb++ = 0x78;
 *wrb = 0xFF;

 status = be_mbox_notify_wait(adapter);

 mutex_unlock(&adapter->mbox_lock);
 return status;
}

/* Tell fw we're done with firing cmds by writing a
 * special pattern across the wrb hdr; uses mbox
 */

int be_cmd_fw_clean(struct be_adapter *adapter)
{
 u8 *wrb;
 int status;

 if (lancer_chip(adapter))
  return 0;

 if (mutex_lock_interruptible(&adapter->mbox_lock))
  return -1;

 wrb = (u8 *)wrb_from_mbox(adapter);
 *wrb++ = 0xFF;
 *wrb++ = 0xAA;
 *wrb++ = 0xBB;
 *wrb++ = 0xFF;
 *wrb++ = 0xFF;
 *wrb++ = 0xCC;
 *wrb++ = 0xDD;
 *wrb = 0xFF;

 status = be_mbox_notify_wait(adapter);

 mutex_unlock(&adapter->mbox_lock);
 return status;
}

int be_cmd_eq_create(struct be_adapter *adapter, struct be_eq_obj *eqo)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_eq_create *req;
 struct be_dma_mem *q_mem = &eqo->q.dma_mem;
 int status, ver = 0;

 if (mutex_lock_interruptible(&adapter->mbox_lock))
  return -1;

 wrb = wrb_from_mbox(adapter);
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_EQ_CREATE, sizeof(*req), wrb,
          NULL);

 /* Support for EQ_CREATEv2 available only SH-R onwards */
 if (!(BEx_chip(adapter) || lancer_chip(adapter)))
  ver = 2;

 req->hdr.version = ver;
 req->num_pages =  cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));

 AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1);
 /* 4byte eqe*/
 AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0);
 AMAP_SET_BITS(struct amap_eq_context, count, req->context,
        __ilog2_u32(eqo->q.len / 256));
 be_dws_cpu_to_le(req->context, sizeof(req->context));

 be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);

 status = be_mbox_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_eq_create *resp = embedded_payload(wrb);

  eqo->q.id = le16_to_cpu(resp->eq_id);
  eqo->msix_idx =
   (ver == 2) ? le16_to_cpu(resp->msix_idx) : eqo->idx;
  eqo->q.created = true;
 }

 mutex_unlock(&adapter->mbox_lock);
 return status;
}

/* Use MCC */
int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
     bool permanent, u32 if_handle, u32 pmac_id)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_mac_query *req;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req), wrb,
          NULL);
 req->type = MAC_ADDRESS_TYPE_NETWORK;
 if (permanent) {
  req->permanent = 1;
 } else {
  req->if_id = cpu_to_le16((u16)if_handle);
  req->pmac_id = cpu_to_le32(pmac_id);
  req->permanent = 0;
 }

 status = be_mcc_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_mac_query *resp = embedded_payload(wrb);

  memcpy(mac_addr, resp->mac.addr, ETH_ALEN);
 }

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Uses synchronous MCCQ */
int be_cmd_pmac_add(struct be_adapter *adapter, const u8 *mac_addr,
      u32 if_id, u32 *pmac_id, u32 domain)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_pmac_add *req;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req), wrb,
          NULL);

 req->hdr.domain = domain;
 req->if_id = cpu_to_le32(if_id);
 memcpy(req->mac_address, mac_addr, ETH_ALEN);

 status = be_mcc_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb);

  *pmac_id = le32_to_cpu(resp->pmac_id);
 }

err:
 spin_unlock_bh(&adapter->mcc_lock);

 if (base_status(status) == MCC_STATUS_UNAUTHORIZED_REQUEST)
  status = -EPERM;

 return status;
}

/* Uses synchronous MCCQ */
int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, int pmac_id, u32 dom)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_pmac_del *req;
 int status;

 if (pmac_id == -1)
  return 0;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req),
          wrb, NULL);

 req->hdr.domain = dom;
 req->if_id = cpu_to_le32(if_id);
 req->pmac_id = cpu_to_le32(pmac_id);

 status = be_mcc_notify_wait(adapter);

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Uses Mbox */
int be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq,
       struct be_queue_info *eq, bool no_delay, int coalesce_wm)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_cq_create *req;
 struct be_dma_mem *q_mem = &cq->dma_mem;
 void *ctxt;
 int status;

 if (mutex_lock_interruptible(&adapter->mbox_lock))
  return -1;

 wrb = wrb_from_mbox(adapter);
 req = embedded_payload(wrb);
 ctxt = &req->context;

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_CQ_CREATE, sizeof(*req), wrb,
          NULL);

 req->num_pages =  cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));

 if (BEx_chip(adapter)) {
  AMAP_SET_BITS(struct amap_cq_context_be, coalescwm, ctxt,
         coalesce_wm);
  AMAP_SET_BITS(struct amap_cq_context_be, nodelay,
         ctxt, no_delay);
  AMAP_SET_BITS(struct amap_cq_context_be, count, ctxt,
         __ilog2_u32(cq->len / 256));
  AMAP_SET_BITS(struct amap_cq_context_be, valid, ctxt, 1);
  AMAP_SET_BITS(struct amap_cq_context_be, eventable, ctxt, 1);
  AMAP_SET_BITS(struct amap_cq_context_be, eqid, ctxt, eq->id);
 } else {
  req->hdr.version = 2;
  req->page_size = 1; /* 1 for 4K */

  /* coalesce-wm field in this cmd is not relevant to Lancer.
 * Lancer uses COMMON_MODIFY_CQ to set this field
 */

  if (!lancer_chip(adapter))
   AMAP_SET_BITS(struct amap_cq_context_v2, coalescwm,
          ctxt, coalesce_wm);
  AMAP_SET_BITS(struct amap_cq_context_v2, nodelay, ctxt,
         no_delay);
  AMAP_SET_BITS(struct amap_cq_context_v2, count, ctxt,
         __ilog2_u32(cq->len / 256));
  AMAP_SET_BITS(struct amap_cq_context_v2, valid, ctxt, 1);
  AMAP_SET_BITS(struct amap_cq_context_v2, eventable, ctxt, 1);
  AMAP_SET_BITS(struct amap_cq_context_v2, eqid, ctxt, eq->id);
 }

 be_dws_cpu_to_le(ctxt, sizeof(req->context));

 be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);

 status = be_mbox_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_cq_create *resp = embedded_payload(wrb);

  cq->id = le16_to_cpu(resp->cq_id);
  cq->created = true;
 }

 mutex_unlock(&adapter->mbox_lock);

 return status;
}

static u32 be_encoded_q_len(int q_len)
{
 u32 len_encoded = fls(q_len); /* log2(len) + 1 */

 if (len_encoded == 16)
  len_encoded = 0;
 return len_encoded;
}

static int be_cmd_mccq_ext_create(struct be_adapter *adapter,
      struct be_queue_info *mccq,
      struct be_queue_info *cq)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_mcc_ext_create *req;
 struct be_dma_mem *q_mem = &mccq->dma_mem;
 void *ctxt;
 int status;

 if (mutex_lock_interruptible(&adapter->mbox_lock))
  return -1;

 wrb = wrb_from_mbox(adapter);
 req = embedded_payload(wrb);
 ctxt = &req->context;

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req), wrb,
          NULL);

 req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
 if (BEx_chip(adapter)) {
  AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1);
  AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt,
         be_encoded_q_len(mccq->len));
  AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id);
 } else {
  req->hdr.version = 1;
  req->cq_id = cpu_to_le16(cq->id);

  AMAP_SET_BITS(struct amap_mcc_context_v1, ring_size, ctxt,
         be_encoded_q_len(mccq->len));
  AMAP_SET_BITS(struct amap_mcc_context_v1, valid, ctxt, 1);
  AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_id,
         ctxt, cq->id);
  AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_valid,
         ctxt, 1);
 }

 /* Subscribe to Link State, Sliport Event and Group 5 Events
 * (bits 1, 5 and 17 set)
 */

 req->async_event_bitmap[0] =
   cpu_to_le32(BIT(ASYNC_EVENT_CODE_LINK_STATE) |
        BIT(ASYNC_EVENT_CODE_GRP_5) |
        BIT(ASYNC_EVENT_CODE_QNQ) |
        BIT(ASYNC_EVENT_CODE_SLIPORT));

 be_dws_cpu_to_le(ctxt, sizeof(req->context));

 be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);

 status = be_mbox_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb);

  mccq->id = le16_to_cpu(resp->id);
  mccq->created = true;
 }
 mutex_unlock(&adapter->mbox_lock);

 return status;
}

static int be_cmd_mccq_org_create(struct be_adapter *adapter,
      struct be_queue_info *mccq,
      struct be_queue_info *cq)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_mcc_create *req;
 struct be_dma_mem *q_mem = &mccq->dma_mem;
 void *ctxt;
 int status;

 if (mutex_lock_interruptible(&adapter->mbox_lock))
  return -1;

 wrb = wrb_from_mbox(adapter);
 req = embedded_payload(wrb);
 ctxt = &req->context;

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_MCC_CREATE, sizeof(*req), wrb,
          NULL);

 req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));

 AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1);
 AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt,
        be_encoded_q_len(mccq->len));
 AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id);

 be_dws_cpu_to_le(ctxt, sizeof(req->context));

 be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);

 status = be_mbox_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb);

  mccq->id = le16_to_cpu(resp->id);
  mccq->created = true;
 }

 mutex_unlock(&adapter->mbox_lock);
 return status;
}

int be_cmd_mccq_create(struct be_adapter *adapter,
         struct be_queue_info *mccq, struct be_queue_info *cq)
{
 int status;

 status = be_cmd_mccq_ext_create(adapter, mccq, cq);
 if (status && BEx_chip(adapter)) {
  dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 "
   "or newer to avoid conflicting priorities between NIC "
   "and FCoE traffic");
  status = be_cmd_mccq_org_create(adapter, mccq, cq);
 }
 return status;
}

int be_cmd_txq_create(struct be_adapter *adapter, struct be_tx_obj *txo)
{
 struct be_mcc_wrb wrb = {0};
 struct be_cmd_req_eth_tx_create *req;
 struct be_queue_info *txq = &txo->q;
 struct be_queue_info *cq = &txo->cq;
 struct be_dma_mem *q_mem = &txq->dma_mem;
 int status, ver = 0;

 req = embedded_payload(&wrb);
 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
          OPCODE_ETH_TX_CREATE, sizeof(*req), &wrb, NULL);

 if (lancer_chip(adapter)) {
  req->hdr.version = 1;
 } else if (BEx_chip(adapter)) {
  if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC)
   req->hdr.version = 2;
 } else { /* For SH */
  req->hdr.version = 2;
 }

 if (req->hdr.version > 0)
  req->if_id = cpu_to_le16(adapter->if_handle);
 req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
 req->ulp_num = BE_ULP1_NUM;
 req->type = BE_ETH_TX_RING_TYPE_STANDARD;
 req->cq_id = cpu_to_le16(cq->id);
 req->queue_size = be_encoded_q_len(txq->len);
 be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
 ver = req->hdr.version;

 status = be_cmd_notify_wait(adapter, &wrb);
 if (!status) {
  struct be_cmd_resp_eth_tx_create *resp = embedded_payload(&wrb);

  txq->id = le16_to_cpu(resp->cid);
  if (ver == 2)
   txo->db_offset = le32_to_cpu(resp->db_offset);
  else
   txo->db_offset = DB_TXULP1_OFFSET;
  txq->created = true;
 }

 return status;
}

/* Uses MCC */
int be_cmd_rxq_create(struct be_adapter *adapter,
        struct be_queue_info *rxq, u16 cq_id, u16 frag_size,
        u32 if_id, u32 rss, u8 *rss_id)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_eth_rx_create *req;
 struct be_dma_mem *q_mem = &rxq->dma_mem;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
          OPCODE_ETH_RX_CREATE, sizeof(*req), wrb, NULL);

 req->cq_id = cpu_to_le16(cq_id);
 req->frag_size = fls(frag_size) - 1;
 req->num_pages = 2;
 be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
 req->interface_id = cpu_to_le32(if_id);
 req->max_frame_size = cpu_to_le16(BE_MAX_JUMBO_FRAME_SIZE);
 req->rss_queue = cpu_to_le32(rss);

 status = be_mcc_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb);

  rxq->id = le16_to_cpu(resp->id);
  rxq->created = true;
  *rss_id = resp->rss_id;
 }

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Generic destroyer function for all types of queues
 * Uses Mbox
 */

int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
       int queue_type)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_q_destroy *req;
 u8 subsys = 0, opcode = 0;
 int status;

 if (mutex_lock_interruptible(&adapter->mbox_lock))
  return -1;

 wrb = wrb_from_mbox(adapter);
 req = embedded_payload(wrb);

 switch (queue_type) {
 case QTYPE_EQ:
  subsys = CMD_SUBSYSTEM_COMMON;
  opcode = OPCODE_COMMON_EQ_DESTROY;
  break;
 case QTYPE_CQ:
  subsys = CMD_SUBSYSTEM_COMMON;
  opcode = OPCODE_COMMON_CQ_DESTROY;
  break;
 case QTYPE_TXQ:
  subsys = CMD_SUBSYSTEM_ETH;
  opcode = OPCODE_ETH_TX_DESTROY;
  break;
 case QTYPE_RXQ:
  subsys = CMD_SUBSYSTEM_ETH;
  opcode = OPCODE_ETH_RX_DESTROY;
  break;
 case QTYPE_MCCQ:
  subsys = CMD_SUBSYSTEM_COMMON;
  opcode = OPCODE_COMMON_MCC_DESTROY;
  break;
 default:
  BUG();
 }

 be_wrb_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req), wrb,
          NULL);
 req->id = cpu_to_le16(q->id);

 status = be_mbox_notify_wait(adapter);
 q->created = false;

 mutex_unlock(&adapter->mbox_lock);
 return status;
}

/* Uses MCC */
int be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_q_destroy *req;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
          OPCODE_ETH_RX_DESTROY, sizeof(*req), wrb, NULL);
 req->id = cpu_to_le16(q->id);

 status = be_mcc_notify_wait(adapter);
 q->created = false;

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Create an rx filtering policy configuration on an i/f
 * Will use MBOX only if MCCQ has not been created.
 */

int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
       u32 *if_handle, u32 domain)
{
 struct be_mcc_wrb wrb = {0};
 struct be_cmd_req_if_create *req;
 int status;

 req = embedded_payload(&wrb);
 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_NTWK_INTERFACE_CREATE,
          sizeof(*req), &wrb, NULL);
 req->hdr.domain = domain;
 req->capability_flags = cpu_to_le32(cap_flags);
 req->enable_flags = cpu_to_le32(en_flags);
 req->pmac_invalid = true;

 status = be_cmd_notify_wait(adapter, &wrb);
 if (!status) {
  struct be_cmd_resp_if_create *resp = embedded_payload(&wrb);

  *if_handle = le32_to_cpu(resp->interface_id);

  /* Hack to retrieve VF's pmac-id on BE3 */
  if (BE3_chip(adapter) && be_virtfn(adapter))
   adapter->pmac_id[0] = le32_to_cpu(resp->pmac_id);
 }
 return status;
}

/* Uses MCCQ if available else MBOX */
int be_cmd_if_destroy(struct be_adapter *adapter, int interface_id, u32 domain)
{
 struct be_mcc_wrb wrb = {0};
 struct be_cmd_req_if_destroy *req;
 int status;

 if (interface_id == -1)
  return 0;

 req = embedded_payload(&wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_NTWK_INTERFACE_DESTROY,
          sizeof(*req), &wrb, NULL);
 req->hdr.domain = domain;
 req->interface_id = cpu_to_le32(interface_id);

 status = be_cmd_notify_wait(adapter, &wrb);
 return status;
}

/* Get stats is a non embedded command: the request is not embedded inside
 * WRB but is a separate dma memory block
 * Uses asynchronous MCC
 */

int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_hdr *hdr;
 int status = 0;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 hdr = nonemb_cmd->va;

 be_wrb_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH,
          OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size, wrb,
          nonemb_cmd);

 /* version 1 of the cmd is not supported only by BE2 */
 if (BE2_chip(adapter))
  hdr->version = 0;
 else if (BE3_chip(adapter) || lancer_chip(adapter))
  hdr->version = 1;
 else
  hdr->version = 2;

 status = be_mcc_notify(adapter);
 if (status)
  goto err;

 adapter->stats_cmd_sent = true;

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Lancer Stats */
int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
          struct be_dma_mem *nonemb_cmd)
{
 struct be_mcc_wrb *wrb;
 struct lancer_cmd_req_pport_stats *req;
 int status = 0;

 if (!be_cmd_allowed(adapter, OPCODE_ETH_GET_PPORT_STATS,
       CMD_SUBSYSTEM_ETH))
  return -EPERM;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = nonemb_cmd->va;

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
          OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size,
          wrb, nonemb_cmd);

 req->cmd_params.params.pport_num = cpu_to_le16(adapter->hba_port_num);
 req->cmd_params.params.reset_stats = 0;

 status = be_mcc_notify(adapter);
 if (status)
  goto err;

 adapter->stats_cmd_sent = true;

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

static int be_mac_to_link_speed(int mac_speed)
{
 switch (mac_speed) {
 case PHY_LINK_SPEED_ZERO:
  return 0;
 case PHY_LINK_SPEED_10MBPS:
  return 10;
 case PHY_LINK_SPEED_100MBPS:
  return 100;
 case PHY_LINK_SPEED_1GBPS:
  return 1000;
 case PHY_LINK_SPEED_10GBPS:
  return 10000;
 case PHY_LINK_SPEED_20GBPS:
  return 20000;
 case PHY_LINK_SPEED_25GBPS:
  return 25000;
 case PHY_LINK_SPEED_40GBPS:
  return 40000;
 }
 return 0;
}

/* Uses synchronous mcc
 * Returns link_speed in Mbps
 */

int be_cmd_link_status_query(struct be_adapter *adapter, u16 *link_speed,
        u8 *link_status, u32 dom)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_link_status *req;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 if (link_status)
  *link_status = LINK_DOWN;

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_NTWK_LINK_STATUS_QUERY,
          sizeof(*req), wrb, NULL);

 /* version 1 of the cmd is not supported only by BE2 */
 if (!BE2_chip(adapter))
  req->hdr.version = 1;

 req->hdr.domain = dom;

 status = be_mcc_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_link_status *resp = embedded_payload(wrb);

  if (link_speed) {
   *link_speed = resp->link_speed ?
          le16_to_cpu(resp->link_speed) * 10 :
          be_mac_to_link_speed(resp->mac_speed);

   if (!resp->logical_link_status)
    *link_speed = 0;
  }
  if (link_status)
   *link_status = resp->logical_link_status;
 }

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Uses synchronous mcc */
int be_cmd_get_die_temperature(struct be_adapter *adapter)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_get_cntl_addnl_attribs *req;
 int status = 0;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES,
          sizeof(*req), wrb, NULL);

 status = be_mcc_notify(adapter);
err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Uses synchronous mcc */
int be_cmd_get_fat_dump_len(struct be_adapter *adapter, u32 *dump_size)
{
 struct be_mcc_wrb wrb = {0};
 struct be_cmd_req_get_fat *req;
 int status;

 req = embedded_payload(&wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_MANAGE_FAT, sizeof(*req),
          &wrb, NULL);
 req->fat_operation = cpu_to_le32(QUERY_FAT);
 status = be_cmd_notify_wait(adapter, &wrb);
 if (!status) {
  struct be_cmd_resp_get_fat *resp = embedded_payload(&wrb);

  if (dump_size && resp->log_size)
   *dump_size = le32_to_cpu(resp->log_size) -
     sizeof(u32);
 }
 return status;
}

int be_cmd_get_fat_dump(struct be_adapter *adapter, u32 buf_len, void *buf)
{
 struct be_dma_mem get_fat_cmd;
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_get_fat *req;
 u32 offset = 0, total_size, buf_size,
    log_offset = sizeof(u32), payload_len;
 int status;

 if (buf_len == 0)
  return 0;

 total_size = buf_len;

 get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60 * 1024;
 get_fat_cmd.va = dma_alloc_coherent(&adapter->pdev->dev,
         get_fat_cmd.size,
         &get_fat_cmd.dma, GFP_ATOMIC);
 if (!get_fat_cmd.va)
  return -ENOMEM;

 spin_lock_bh(&adapter->mcc_lock);

 while (total_size) {
  buf_size = min(total_size, (u32)60 * 1024);
  total_size -= buf_size;

  wrb = wrb_from_mccq(adapter);
  if (!wrb) {
   status = -EBUSY;
   goto err;
  }
  req = get_fat_cmd.va;

  payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size;
  be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
           OPCODE_COMMON_MANAGE_FAT, payload_len,
           wrb, &get_fat_cmd);

  req->fat_operation = cpu_to_le32(RETRIEVE_FAT);
  req->read_log_offset = cpu_to_le32(log_offset);
  req->read_log_length = cpu_to_le32(buf_size);
  req->data_buffer_size = cpu_to_le32(buf_size);

  status = be_mcc_notify_wait(adapter);
  if (!status) {
   struct be_cmd_resp_get_fat *resp = get_fat_cmd.va;

   memcpy(buf + offset,
          resp->data_buffer,
          le32_to_cpu(resp->read_log_length));
  } else {
   dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n");
   goto err;
  }
  offset += buf_size;
  log_offset += buf_size;
 }
err:
 spin_unlock_bh(&adapter->mcc_lock);
 dma_free_coherent(&adapter->pdev->dev, get_fat_cmd.size,
     get_fat_cmd.va, get_fat_cmd.dma);
 return status;
}

/* Uses synchronous mcc */
int be_cmd_get_fw_ver(struct be_adapter *adapter)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_get_fw_version *req;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }

 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_GET_FW_VERSION, sizeof(*req), wrb,
          NULL);
 status = be_mcc_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb);

  strscpy(adapter->fw_ver, resp->firmware_version_string,
   sizeof(adapter->fw_ver));
  strscpy(adapter->fw_on_flash, resp->fw_on_flash_version_string,
   sizeof(adapter->fw_on_flash));
 }
err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* set the EQ delay interval of an EQ to specified value
 * Uses async mcc
 */

static int __be_cmd_modify_eqd(struct be_adapter *adapter,
          struct be_set_eqd *set_eqd, int num)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_modify_eq_delay *req;
 int status = 0, i;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req), wrb,
          NULL);

 req->num_eq = cpu_to_le32(num);
 for (i = 0; i < num; i++) {
  req->set_eqd[i].eq_id = cpu_to_le32(set_eqd[i].eq_id);
  req->set_eqd[i].phase = 0;
  req->set_eqd[i].delay_multiplier =
    cpu_to_le32(set_eqd[i].delay_multiplier);
 }

 status = be_mcc_notify(adapter);
err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
        int num)
{
 int num_eqs, i = 0;

 while (num) {
  num_eqs = min(num, 8);
  __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs);
  i += num_eqs;
  num -= num_eqs;
 }

 return 0;
}

/* Uses sycnhronous mcc */
int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
         u32 num, u32 domain)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_vlan_config *req;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req),
          wrb, NULL);
 req->hdr.domain = domain;

 req->interface_id = if_id;
 req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0;
 req->num_vlan = num;
 memcpy(req->normal_vlan, vtag_array,
        req->num_vlan * sizeof(vtag_array[0]));

 status = be_mcc_notify_wait(adapter);
err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
{
 struct be_mcc_wrb *wrb;
 struct be_dma_mem *mem = &adapter->rx_filter;
 struct be_cmd_req_rx_filter *req = mem->va;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 memset(req, 0, sizeof(*req));
 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req),
          wrb, mem);

 req->if_id = cpu_to_le32(adapter->if_handle);
 req->if_flags_mask = cpu_to_le32(flags);
 req->if_flags = (value == ON) ? req->if_flags_mask : 0;

 if (flags & BE_IF_FLAGS_MULTICAST) {
  int i;

  /* Reset mcast promisc mode if already set by setting mask
 * and not setting flags field
 */

  req->if_flags_mask |=
   cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS &
        be_if_cap_flags(adapter));
  req->mcast_num = cpu_to_le32(adapter->mc_count);
  for (i = 0; i < adapter->mc_count; i++)
   ether_addr_copy(req->mcast_mac[i].byte,
     adapter->mc_list[i].mac);
 }

 status = be_mcc_notify_wait(adapter);
err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
{
 struct device *dev = &adapter->pdev->dev;

 if ((flags & be_if_cap_flags(adapter)) != flags) {
  dev_warn(dev, "Cannot set rx filter flags 0x%x\n", flags);
  dev_warn(dev, "Interface is capable of 0x%x flags only\n",
    be_if_cap_flags(adapter));
 }
 flags &= be_if_cap_flags(adapter);
 if (!flags)
  return -ENOTSUPP;

 return __be_cmd_rx_filter(adapter, flags, value);
}

/* Uses synchrounous mcc */
int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_set_flow_control *req;
 int status;

 if (!be_cmd_allowed(adapter, OPCODE_COMMON_SET_FLOW_CONTROL,
       CMD_SUBSYSTEM_COMMON))
  return -EPERM;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req),
          wrb, NULL);

 req->hdr.version = 1;
 req->tx_flow_control = cpu_to_le16((u16)tx_fc);
 req->rx_flow_control = cpu_to_le16((u16)rx_fc);

 status = be_mcc_notify_wait(adapter);

err:
 spin_unlock_bh(&adapter->mcc_lock);

 if (base_status(status) == MCC_STATUS_FEATURE_NOT_SUPPORTED)
  return  -EOPNOTSUPP;

 return status;
}

/* Uses sycn mcc */
int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_get_flow_control *req;
 int status;

 if (!be_cmd_allowed(adapter, OPCODE_COMMON_GET_FLOW_CONTROL,
       CMD_SUBSYSTEM_COMMON))
  return -EPERM;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req),
          wrb, NULL);

 status = be_mcc_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_get_flow_control *resp =
      embedded_payload(wrb);

  *tx_fc = le16_to_cpu(resp->tx_flow_control);
  *rx_fc = le16_to_cpu(resp->rx_flow_control);
 }

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Uses mbox */
int be_cmd_query_fw_cfg(struct be_adapter *adapter)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_query_fw_cfg *req;
 int status;

 if (mutex_lock_interruptible(&adapter->mbox_lock))
  return -1;

 wrb = wrb_from_mbox(adapter);
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_QUERY_FIRMWARE_CONFIG,
          sizeof(*req), wrb, NULL);

 status = be_mbox_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb);

  adapter->port_num = le32_to_cpu(resp->phys_port);
  adapter->function_mode = le32_to_cpu(resp->function_mode);
  adapter->function_caps = le32_to_cpu(resp->function_caps);
  adapter->asic_rev = le32_to_cpu(resp->asic_revision) & 0xFF;
  dev_info(&adapter->pdev->dev,
    "FW config: function_mode=0x%x, function_caps=0x%x\n",
    adapter->function_mode, adapter->function_caps);
 }

 mutex_unlock(&adapter->mbox_lock);
 return status;
}

/* Uses mbox */
int be_cmd_reset_function(struct be_adapter *adapter)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_hdr *req;
 int status;

 if (lancer_chip(adapter)) {
  iowrite32(SLI_PORT_CONTROL_IP_MASK,
     adapter->db + SLIPORT_CONTROL_OFFSET);
  status = lancer_wait_ready(adapter);
  if (status)
   dev_err(&adapter->pdev->dev,
    "Adapter in non recoverable error\n");
  return status;
 }

 if (mutex_lock_interruptible(&adapter->mbox_lock))
  return -1;

 wrb = wrb_from_mbox(adapter);
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_FUNCTION_RESET, sizeof(*req), wrb,
          NULL);

 status = be_mbox_notify_wait(adapter);

 mutex_unlock(&adapter->mbox_lock);
 return status;
}

int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
        u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_rss_config *req;
 int status;

 if (!(be_if_cap_flags(adapter) & BE_IF_FLAGS_RSS))
  return 0;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
          OPCODE_ETH_RSS_CONFIG, sizeof(*req), wrb, NULL);

 req->if_id = cpu_to_le32(adapter->if_handle);
 req->enable_rss = cpu_to_le16(rss_hash_opts);
 req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1);

 if (!BEx_chip(adapter))
  req->hdr.version = 1;

 memcpy(req->cpu_table, rsstable, table_size);
 memcpy(req->hash, rss_hkey, RSS_HASH_KEY_LEN);
 be_dws_cpu_to_le(req->hash, sizeof(req->hash));

 status = be_mcc_notify_wait(adapter);
err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Uses sync mcc */
int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num,
       u8 bcn, u8 sts, u8 state)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_enable_disable_beacon *req;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_ENABLE_DISABLE_BEACON,
          sizeof(*req), wrb, NULL);

 req->port_num = port_num;
 req->beacon_state = state;
 req->beacon_duration = bcn;
 req->status_duration = sts;

 status = be_mcc_notify_wait(adapter);

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Uses sync mcc */
int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_get_beacon_state *req;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_GET_BEACON_STATE, sizeof(*req),
          wrb, NULL);

 req->port_num = port_num;

 status = be_mcc_notify_wait(adapter);
 if (!status) {
  struct be_cmd_resp_get_beacon_state *resp =
      embedded_payload(wrb);

  *state = resp->beacon_state;
 }

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/* Uses sync mcc */
int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
          u8 page_num, u32 off, u32 len, u8 *data)
{
 struct be_dma_mem cmd;
 struct be_mcc_wrb *wrb;
 struct be_cmd_req_port_type *req;
 int status;

 if (page_num > TR_PAGE_A2)
  return -EINVAL;

 cmd.size = sizeof(struct be_cmd_resp_port_type);
 cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma,
        GFP_ATOMIC);
 if (!cmd.va) {
  dev_err(&adapter->pdev->dev, "Memory allocation failed\n");
  return -ENOMEM;
 }

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = cmd.va;

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_READ_TRANSRECV_DATA,
          cmd.size, wrb, &cmd);

 req->port = cpu_to_le32(adapter->hba_port_num);
 req->page_num = cpu_to_le32(page_num);
 status = be_mcc_notify_wait(adapter);
 if (!status && len > 0) {
  struct be_cmd_resp_port_type *resp = cmd.va;

  memcpy(data, resp->page_data + off, len);
 }
err:
 spin_unlock_bh(&adapter->mcc_lock);
 dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma);
 return status;
}

static int lancer_cmd_write_object(struct be_adapter *adapter,
       struct be_dma_mem *cmd, u32 data_size,
       u32 data_offset, const char *obj_name,
       u32 *data_written, u8 *change_status,
       u8 *addn_status)
{
 struct be_mcc_wrb *wrb;
 struct lancer_cmd_req_write_object *req;
 struct lancer_cmd_resp_write_object *resp;
 void *ctxt = NULL;
 int status;

 spin_lock_bh(&adapter->mcc_lock);
 adapter->flash_status = 0;

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err_unlock;
 }

 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_WRITE_OBJECT,
          sizeof(struct lancer_cmd_req_write_object), wrb,
          NULL);

 ctxt = &req->context;
 AMAP_SET_BITS(struct amap_lancer_write_obj_context,
        write_length, ctxt, data_size);

 if (data_size == 0)
  AMAP_SET_BITS(struct amap_lancer_write_obj_context,
         eof, ctxt, 1);
 else
  AMAP_SET_BITS(struct amap_lancer_write_obj_context,
         eof, ctxt, 0);

 be_dws_cpu_to_le(ctxt, sizeof(req->context));
 req->write_offset = cpu_to_le32(data_offset);
 strscpy(req->object_name, obj_name, sizeof(req->object_name));
 req->descriptor_count = cpu_to_le32(1);
 req->buf_len = cpu_to_le32(data_size);
 req->addr_low = cpu_to_le32((cmd->dma +
         sizeof(struct lancer_cmd_req_write_object))
        & 0xFFFFFFFF);
 req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma +
    sizeof(struct lancer_cmd_req_write_object)));

 status = be_mcc_notify(adapter);
 if (status)
  goto err_unlock;

 spin_unlock_bh(&adapter->mcc_lock);

 if (!wait_for_completion_timeout(&adapter->et_cmd_compl,
      msecs_to_jiffies(60000)))
  status = -ETIMEDOUT;
 else
  status = adapter->flash_status;

 resp = embedded_payload(wrb);
 if (!status) {
  *data_written = le32_to_cpu(resp->actual_write_len);
  *change_status = resp->change_status;
 } else {
  *addn_status = resp->additional_status;
 }

 return status;

err_unlock:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

int be_cmd_query_cable_type(struct be_adapter *adapter)
{
 u8 page_data[PAGE_DATA_LEN];
 int status;

 status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
         0, PAGE_DATA_LEN, page_data);
 if (!status) {
  switch (adapter->phy.interface_type) {
  case PHY_TYPE_QSFP:
   adapter->phy.cable_type =
    page_data[QSFP_PLUS_CABLE_TYPE_OFFSET];
   break;
  case PHY_TYPE_SFP_PLUS_10GB:
   adapter->phy.cable_type =
    page_data[SFP_PLUS_CABLE_TYPE_OFFSET];
   break;
  default:
   adapter->phy.cable_type = 0;
   break;
  }
 }
 return status;
}

int be_cmd_query_sfp_info(struct be_adapter *adapter)
{
 u8 page_data[PAGE_DATA_LEN];
 int status;

 status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
         0, PAGE_DATA_LEN, page_data);
 if (!status) {
  strscpy(adapter->phy.vendor_name, page_data +
   SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
  strscpy(adapter->phy.vendor_pn,
   page_data + SFP_VENDOR_PN_OFFSET,
   SFP_VENDOR_NAME_LEN - 1);
 }

 return status;
}

static int lancer_cmd_delete_object(struct be_adapter *adapter,
        const char *obj_name)
{
 struct lancer_cmd_req_delete_object *req;
 struct be_mcc_wrb *wrb;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }

 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_DELETE_OBJECT,
          sizeof(*req), wrb, NULL);

 strscpy(req->object_name, obj_name, sizeof(req->object_name));

 status = be_mcc_notify_wait(adapter);
err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
      u32 data_size, u32 data_offset, const char *obj_name,
      u32 *data_read, u32 *eof, u8 *addn_status)
{
 struct be_mcc_wrb *wrb;
 struct lancer_cmd_req_read_object *req;
 struct lancer_cmd_resp_read_object *resp;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err_unlock;
 }

 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_READ_OBJECT,
          sizeof(struct lancer_cmd_req_read_object), wrb,
          NULL);

 req->desired_read_len = cpu_to_le32(data_size);
 req->read_offset = cpu_to_le32(data_offset);
 strcpy(req->object_name, obj_name);
 req->descriptor_count = cpu_to_le32(1);
 req->buf_len = cpu_to_le32(data_size);
 req->addr_low = cpu_to_le32((cmd->dma & 0xFFFFFFFF));
 req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma));

 status = be_mcc_notify_wait(adapter);

 resp = embedded_payload(wrb);
 if (!status) {
  *data_read = le32_to_cpu(resp->actual_read_len);
  *eof = le32_to_cpu(resp->eof);
 } else {
  *addn_status = resp->additional_status;
 }

err_unlock:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

static int be_cmd_write_flashrom(struct be_adapter *adapter,
     struct be_dma_mem *cmd, u32 flash_type,
     u32 flash_opcode, u32 img_offset, u32 buf_size)
{
 struct be_mcc_wrb *wrb;
 struct be_cmd_write_flashrom *req;
 int status;

 spin_lock_bh(&adapter->mcc_lock);
 adapter->flash_status = 0;

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err_unlock;
 }
 req = cmd->va;

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_WRITE_FLASHROM, cmd->size, wrb,
          cmd);

 req->params.op_type = cpu_to_le32(flash_type);
 if (flash_type == OPTYPE_OFFSET_SPECIFIED)
  req->params.offset = cpu_to_le32(img_offset);

 req->params.op_code = cpu_to_le32(flash_opcode);
 req->params.data_buf_size = cpu_to_le32(buf_size);

 status = be_mcc_notify(adapter);
 if (status)
  goto err_unlock;

 spin_unlock_bh(&adapter->mcc_lock);

 if (!wait_for_completion_timeout(&adapter->et_cmd_compl,
      msecs_to_jiffies(40000)))
  status = -ETIMEDOUT;
 else
  status = adapter->flash_status;

 return status;

err_unlock:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

static int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
    u16 img_optype, u32 img_offset, u32 crc_offset)
{
 struct be_cmd_read_flash_crc *req;
 struct be_mcc_wrb *wrb;
 int status;

 spin_lock_bh(&adapter->mcc_lock);

 wrb = wrb_from_mccq(adapter);
 if (!wrb) {
  status = -EBUSY;
  goto err;
 }
 req = embedded_payload(wrb);

 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
          OPCODE_COMMON_READ_FLASHROM, sizeof(*req),
          wrb, NULL);

 req->params.op_type = cpu_to_le32(img_optype);
 if (img_optype == OPTYPE_OFFSET_SPECIFIED)
  req->params.offset = cpu_to_le32(img_offset + crc_offset);
 else
  req->params.offset = cpu_to_le32(crc_offset);

 req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT);
 req->params.data_buf_size = cpu_to_le32(0x4);

 status = be_mcc_notify_wait(adapter);
 if (!status)
  memcpy(flashed_crc, req->crc, 4);

err:
 spin_unlock_bh(&adapter->mcc_lock);
 return status;
}

/*
 * Since the cookie is text, add a parsing-skipped space to keep it from
 * ever being matched on storage holding this source file.
 */

static const char flash_cookie[32] __nonstring = "*** SE FLAS" "H DIRECTORY *** ";

static bool phy_flashing_required(struct be_adapter *adapter)
{
 return (adapter->phy.phy_type == PHY_TYPE_TN_8022 &&
  adapter->phy.interface_type == PHY_TYPE_BASET_10GB);
}

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=94 G=95

¤ Dauer der Verarbeitung: 0.47 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge