oce_mbx.c revision 12d61dab3304980e691068219eaaab6398744a2e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Emulex. All rights reserved.
* Use is subject to license terms.
*/
/*
* Source file containing the implementation of MBOX
* and related helper functions
*/
#include <oce_impl.h>
static ddi_dma_attr_t oce_sgl_dma_attr = {
DMA_ATTR_V0, /* version number */
0x0000000000000000ull, /* low address */
0xFFFFFFFFFFFFFFFFull, /* high address */
0x0000000000010000ull, /* dma counter max */
0x1000, /* alignment 4K for mbx bufs */
0x1, /* burst sizes */
0x00000004, /* minimum transfer size */
0x00000000FFFFFFFFull, /* maximum transfer size */
0xFFFFFFFFFFFFFFFFull, /* maximum segment size */
MAX_MBX_SGE, /* scatter/gather list length */
0x00000001, /* granularity */
0 /* DMA flags */
};
static ddi_device_acc_attr_t oce_sgl_buf_accattr = {
};
/*
* common inline function to fill an ioctl request header
*
* hdr - pointer to a buffer where the header will be initialized
* dom - domain
* port - port number
* opcode - command code for this MBX
* timeout - timeout in seconds
* pyld_len - length of the command buffer described by this header
*
* return none
*/
void
{
} /* mbx_common_req_hdr_init */
/*
* function to initialize the hw with host endian information
*
* dev - software handle to the device
*
* return 0 on success, ETIMEDOUT on failure
*/
int
{
int ret = 0;
/* Endian Signature */
*ptr++ = 0xff;
*ptr++ = 0x12;
*ptr++ = 0x34;
*ptr++ = 0xff;
*ptr++ = 0xff;
*ptr++ = 0x56;
*ptr++ = 0x78;
*ptr = 0xff;
if (ret != 0)
"Failed to set endian %d", ret);
return (ret);
} /* oce_mbox_init */
/*
* function to wait till we get a mbox ready after writing to the
* mbox doorbell
*
* dev - software handle to the device
*
* return 0=ready, ETIMEDOUT=>not ready but timed out
*/
int
{
tstamp = ddi_get_lbolt();
for (;;) {
now = ddi_get_lbolt();
tmo = 0;
break;
}
}
return (0);
}
drv_usecwait(5);
}
return (ETIMEDOUT);
} /* oce_mbox_wait */
/*
* function to dispatch a mailbox command present in the mq mbox
*
* dev - software handle to the device
*
* return 0 on success, ETIMEDOUT on failure
*/
int
{
int ret;
/* sync the bmbx */
/* write 30 bits of address hi dword */
/* wait for mbox ready */
if (ret != 0) {
return (ret);
}
/* ring the doorbell */
}
/* wait for mbox ready */
if (ret != 0) {
"BMBX TIMED OUT PROGRAMMING HI ADDR: %d", ret);
/* if mbx times out, hw is in invalid state */
return (ret);
}
/* now write 30 bits of address lo dword */
/* ring the doorbell */
}
/* wait for mbox ready */
/* sync */
return (EIO);
}
return (ret);
} /* oce_mbox_dispatch */
/*
* function to post a MBX to the mbox
*
* dev - software handle to the device
* mbx - pointer to the MBX to send
* mbxctx - pointer to the mbx context structure
*
* return 0 on success, ETIMEDOUT on failure
*/
int
struct oce_mbx_ctx *mbxctx)
{
int ret = 0;
/* get the tmo */
/* copy mbx into mbox */
/* now dispatch */
if (ret != 0) {
return (ret);
}
/* sync */
return (EIO);
}
/*
* the command completed successfully. Now get the
* completion queue entry
*/
/* check mbox status */
"MBOX Failed with Status: %d %d",
return (EIO);
}
/* copy mbox mbx back */
/*
* store the mbx context in the cqe tag section so that
* the upper layer handling the cqe can associate the mbx
* with the response
*/
if (mbxctx) {
/* save context */
sizeof (struct oce_mbx_ctx *));
}
return (0);
} /* oce_mbox_post */
/*
* function to get the firmware version
*
* dev - software handle to the device
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_get_common_fw_version *fwcmd;
int ret = 0;
/* initialize the ioctl header */
sizeof (struct mbx_get_common_fw_version));
/* fill rest of mbx */
/* now post the command */
if (ret != 0) {
return (ret);
}
return (0);
} /* oce_get_fw_version */
/*
* function to invoke f/w reset via. mailbox
* does not hold bootstap lock called by quiesce
*
* dev - software handle to the device
*
* return 0 on success, ETIMEDOUT on failure
*
*/
int
{
struct ioctl_common_function_reset *fwcmd;
/* initialize the ioctl header */
sizeof (struct ioctl_common_function_reset));
/* fill rest of mbx */
return (oce_mbox_dispatch(dev, 0));
} /* oce_reset_fun */
/*
* function to read the mac address associated with an interface
*
* dev - software handle to the device
* if_id - interface id to read the address from
* perm - set to 1 if reading the factory mac address. In this case
* if_id is ignored
* type - type of the mac address, whether network or storage
* mac - [OUTPUT] pointer to a buffer containing the mac address
* when the command succeeds
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_query_common_iface_mac *fwcmd;
int ret = 0;
/* initialize the ioctl header */
sizeof (struct mbx_query_common_iface_mac));
/* fill the command */
if (perm)
else
/* fill rest of mbx */
/* now post the command */
if (ret != 0) {
return (ret);
}
/* get the response */
"MAC addr size = 0x%x",
"MAC_ADDR:0x%x:0x%x:0x%x:0x%x:0x%x:0x%x",
/* copy the mac addres in the output parameter */
return (0);
} /* oce_read_mac_addr */
/*
* function to create an interface using the OPCODE_CREATE_COMMON_IFACE
* command
*
* dev - software handle to the device
* cap_flags - capability flags
* en_flags - enable capability flags
* vlan_tag - optional vlan tag to associate with the if
* mac_addr - pointer to a buffer containing the mac address
* if_id - [OUTPUT] pointer to an integer to hold the ID of the
* interface created
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_create_common_iface *fwcmd;
int ret = 0;
/* initialize the ioctl header */
sizeof (struct mbx_create_common_iface));
/* fill the command */
} else {
}
/* fill rest of mbx */
/* now post the command */
if (ret != 0) {
return (ret);
}
/* get response */
"IF_ID = 0x%x", *if_id);
/* If asked to set mac addr save the pmac handle */
}
return (0);
} /* oce_if_create */
/*
* function to delete an interface
*
* dev - software handle to the device
* if_id - ID of the interface to delete
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_destroy_common_iface *fwcmd;
int ret = 0;
/* initialize the ioctl header */
sizeof (struct mbx_destroy_common_iface));
/* fill the command */
/* fill rest of mbx */
/* post the command */
return (ret);
} /* oce_if_del */
/*
* function to query the link status from the hardware
*
* dev - software handle to the device
* link_status - [OUT] pointer to the structure returning the link attributes
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_query_common_link_status *fwcmd;
int ret = 0;
/* initialize the ioctl header */
sizeof (struct mbx_query_common_link_status));
/* fill rest of mbx */
/* post the command */
if (ret != 0) {
return (ret);
}
/* interpret response */
return (0);
} /* oce_get_link_status */
/*
* function to configure the rx filter on the interface
*
* dev - software handle to the device
* filter - mbx command containing the filter parameters
*
* return 0 on success, EIO on failure
*/
int
struct mbx_set_common_ntwk_rx_filter *filter)
{
struct mbx_set_common_ntwk_rx_filter *fwcmd;
int ret;
/* fill the command */
/* initialize the ioctl header */
sizeof (struct mbx_set_common_ntwk_rx_filter));
/* fill rest of mbx */
/* post the command */
return (ret);
} /* oce_set_rx_filter */
/*
* function to send the mbx command to update the mcast table with fw
*
* dev - software handle to the device
* mca_table - array of mcast address to update
* mca_cnt - number of elements in mca_table
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_set_common_iface_multicast *fwcmd;
int ret;
/* initialize the ioctl header */
sizeof (struct mbx_set_common_iface_multicast));
/* fill the command */
mca_cnt * ETHERADDRL);
}
/* fill rest of mbx */
/* Swap only MBX header + BOOTSTRAP HDR */
/* post the command */
return (ret);
} /* oce_set_multicast_table */
/*
* function to query the fw attributes from the hw
*
* dev - software handle to the device
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_common_query_fw_config *fwcmd;
int ret = 0;
/* initialize the ioctl header */
sizeof (struct mbx_common_query_fw_config));
/* fill rest of mbx */
/* now post the command */
if (ret != 0) {
return (ret);
}
/* swap and copy into buffer */
return (0);
} /* oce_get_fw_config */
/*
* function to retrieve statistic counters from the hardware
*
* dev - software handle to the device
*
* return 0 on success, EIO on failure
*/
int
{
int ret = 0;
/* initialize the ioctl header */
sizeof (struct mbx_get_nic_stats));
/* fill rest of mbx */
/* sync for device */
/* now post the command */
/* sync the stats */
/* Check the mailbox status and command completion status */
if (ret != 0) {
return (ret);
}
return (0);
} /* oce_get_hw_stats */
/*
* function to set the number of vectors with the cev
*
* dev - software handle to the device
* num_vectors - number of MSI messages
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_common_cev_modify_msi_messages *fwcmd;
int ret = 0;
/* initialize the ioctl header */
sizeof (struct mbx_common_cev_modify_msi_messages));
/* fill the command */
/* fill rest of mbx */
sizeof (struct mbx_common_cev_modify_msi_messages);
/* post the command */
return (ret);
} /* oce_num_intr_vectors_set */
/*
* function to set flow control capability in the hardware
*
* dev - software handle to the device
* flow_control - flow control flags to set
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_common_get_set_flow_control *fwcmd =
int ret;
/* initialize the ioctl header */
sizeof (struct mbx_common_get_set_flow_control));
/* fill command */
if (flow_control & OCE_FC_TX)
if (flow_control & OCE_FC_RX)
/* fill rest of mbx */
/* post the command */
return (ret);
} /* oce_set_flow_control */
/*
* function to get the current flow control setting with the hardware
*
* dev - software handle to the device
* flow_control - [OUT] pointer to location where flow_control setting
* is returned
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_common_get_set_flow_control *fwcmd;
int ret;
return (EIO);
}
/* initialize the ioctl header */
sizeof (struct mbx_common_get_set_flow_control));
/* fill rest of mbx */
/* post the command */
if (ret != 0) {
return (ret);
}
/* get the flow control */
sizeof (struct mbx_common_get_set_flow_control));
*flow_control = 0;
if (fwcmd->tx_flow_control)
*flow_control |= OCE_FC_TX;
if (fwcmd->rx_flow_control)
*flow_control |= OCE_FC_RX;
return (0);
} /* oce_get_flow_control */
/*
*
* dev - software handle to the device
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_config_nic_promiscuous *fwcmd;
int ret;
} else {
}
/* initialize the ioctl header */
sizeof (struct mbx_config_nic_promiscuous));
/* fill rest of mbx */
/* post the command */
return (ret);
}
/*
* function to add a unicast address to an interface
*
* dev - software handle to the device
* mac - unicast address
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_add_common_iface_mac *fwcmd;
int ret;
/* initialize the ioctl header */
sizeof (struct mbx_add_common_iface_mac));
/* fill rest of mbx */
/* post the command */
if (ret != 0) {
return (ret);
}
return (0);
}
/*
* function to delete an unicast address associated with an interface
*
* dev - software handle to the device
* pmac_id - handle to the address added using ace_add_mac
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_del_common_iface_mac *fwcmd;
int ret;
/* initialize the ioctl header */
sizeof (struct mbx_add_common_iface_mac));
/* fill rest of mbx */
/* post the command */
return (ret);
}
/*
* function to send the mbx command to configure vlan
*
* dev - software handle to the device
* vtag_arr - array of vlan tags
* vtag_cnt - number of elements in array
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_common_config_vlan *fwcmd;
int ret;
/* initialize the ioctl header */
sizeof (struct mbx_common_config_vlan));
/* Set the vlan tag filter on hw */
if (!enable_promisc) {
vtag_cnt * sizeof (struct normal_vlan));
}
/* fill rest of mbx */
/* post the command */
return (ret);
} /* oce_config_vlan */
/*
* function to enable or disable the link
*
* dev - software handle to the device
* mca_table - array of mcast address to update
* mca_cnt - number of elements in mca_table
*
* return 0 on success, EIO on failure
*/
int
{
struct mbx_common_func_link_cfg *fwcmd;
int ret;
/* initialize the ioctl header */
sizeof (struct mbx_common_config_vlan));
/* fill rest of mbx */
/* post the command */
return (ret);
} /* oce_config_link */
/*
* function called from the gld ioctl entry point to send a mbx to fw
*
* dev - software handle to the device
* mp - mblk_t containing the user data
* payload_len = [OUT] pointer to return the length of the payload written
*
* return 0 on Success
*/
int
{
int ret;
int num_buf = 0;
int alloc_len;
sizeof (struct mbx_hdr);
"DW[0] 0x%x DW[1] 0x%x DW[2]0x%x DW[3]0x%x,"
"MBLKL(%lu) ALLOCLEN(%d)",
struct mbx_common_read_write_flashrom *fwcmd =
(struct mbx_common_read_write_flashrom *)
return (EINVAL);
/* get the timeout from the command header */
"OPCODE(%d) OPTYPE = %d SIZE = %d OFFSET = %d",
}
if (!is_embedded) {
/* allocate dma handle */
&dma_handle);
if (ret != DDI_SUCCESS) {
"Failed to alloc DMA handle");
goto fail;
}
/* allocate the DMA-able memory */
if (ret != DDI_SUCCESS) {
"Failed to alloc DMA memory");
goto dma_alloc_fail;
}
/* bind mblk mem to handle */
if (ret != DDI_DMA_MAPPED) {
"Failed to bind DMA handle ret code: %d",
ret);
goto dma_bind_fail;
}
/* fill the mbx sglist */
if (count > 1)
}
(sizeof (struct oce_mq_sge) * count));
} else {
/* fill rest of mbx */
}
/* now post the command */
if (ret != DDI_SUCCESS) {
"Failed to post the mailbox: %d", ret);
sizeof (struct mbx_hdr);
if (is_embedded) {
goto fail;
} else {
(void) ddi_dma_sync(dma_handle, 0, 0,
DDI_FM_OK) {
}
sizeof (struct mbx_hdr));
goto post_fail;
}
}
struct mbx_common_read_write_flashrom *fwcmd =
(struct mbx_common_read_write_flashrom *)
}
/* Copy the response back only if this is an embedded mbx cmd */
if (is_embedded) {
} else {
/* sync */
(void) ddi_dma_sync(dma_handle, 0, 0,
}
/* copy back from kernel allocated buffer to user buffer */
/* unbind and free dma handles */
(void) ddi_dma_unbind_handle(dma_handle);
}
return (0);
(void) ddi_dma_unbind_handle(dma_handle);
fail:
}
return (ret);
}