Blame SOURCES/open-iscsi-2.0.874-8-iscsiuio-Add-support-for-the-new-qedi-transport.patch

ae92e4
From 264e48a0bda2d6cd5d0607acd2669894ee95b3b5 Mon Sep 17 00:00:00 2001
ae92e4
From: Nilesh Javali <nilesh.javali@cavium.com>
ae92e4
Date: Fri, 11 Nov 2016 08:17:51 +0200
ae92e4
Subject: iscsiuio: Add support for the new qedi transport
ae92e4
ae92e4
Signed-off-by: Manish Rangankar <manish.rangankar@cavium.com>
ae92e4
Signed-off-by: Adheer Chandravanshi <adheer.chandravanshi@qlogic.com>
ae92e4
Signed-off-by: Nilesh Javali <nilesh.javali@cavium.com>
ae92e4
---
ae92e4
 iscsiuio/src/unix/libs/Makefile.am |    3 +-
ae92e4
 iscsiuio/src/unix/libs/cnic.c      |    9 +
ae92e4
 iscsiuio/src/unix/libs/cnic.h      |    2 +
ae92e4
 iscsiuio/src/unix/libs/qedi.c      | 1151 ++++++++++++++++++++++++++++++++++++
ae92e4
 iscsiuio/src/unix/libs/qedi.h      |  159 +++++
ae92e4
 iscsiuio/src/unix/nic.c            |    6 +-
ae92e4
 iscsiuio/src/unix/nic.h            |    1 +
ae92e4
 iscsiuio/src/unix/nic_utils.c      |  147 ++++-
ae92e4
 iscsiuio/src/unix/nic_utils.h      |    2 +
ae92e4
 iscsiuio/src/unix/options.h        |    1 +
ae92e4
 10 files changed, 1475 insertions(+), 6 deletions(-)
ae92e4
 create mode 100644 iscsiuio/src/unix/libs/qedi.c
ae92e4
 create mode 100644 iscsiuio/src/unix/libs/qedi.h
ae92e4
ae92e4
diff --git a/iscsiuio/src/unix/libs/Makefile.am b/iscsiuio/src/unix/libs/Makefile.am
ae92e4
index 890415f5a79a..737546b04917 100644
ae92e4
--- a/iscsiuio/src/unix/libs/Makefile.am
ae92e4
+++ b/iscsiuio/src/unix/libs/Makefile.am
ae92e4
@@ -10,4 +10,5 @@ noinst_LIBRARIES = lib_iscsiuio_hw_cnic.a
ae92e4
 lib_iscsiuio_hw_cnic_a_SOURCES =	../build_date.c \
ae92e4
 					cnic.c 		\
ae92e4
 					bnx2.c		\
ae92e4
-					bnx2x.c
ae92e4
+					bnx2x.c		\
ae92e4
+					qedi.c
ae92e4
diff --git a/iscsiuio/src/unix/libs/cnic.c b/iscsiuio/src/unix/libs/cnic.c
ae92e4
index 228c4b9e25b1..5d60f898ad57 100644
ae92e4
--- a/iscsiuio/src/unix/libs/cnic.c
ae92e4
+++ b/iscsiuio/src/unix/libs/cnic.c
ae92e4
@@ -55,6 +55,7 @@
ae92e4
 #include <sys/types.h>
ae92e4
 #include <sys/user.h>
ae92e4
 #include <sys/socket.h>
ae92e4
+#include <sys/mman.h>
ae92e4
 
ae92e4
 #include "uip_arp.h"
ae92e4
 #include "nic.h"
ae92e4
@@ -65,6 +66,7 @@
ae92e4
 #include "cnic.h"
ae92e4
 #include "iscsi_if.h"
ae92e4
 #include "ipv6_ndpc.h"
ae92e4
+#include "qedi.h"
ae92e4
 
ae92e4
 /*******************************************************************************
ae92e4
  * Constants
ae92e4
@@ -81,6 +83,13 @@ const char bnx2i_library_transport_name[] = "bnx2i";
ae92e4
 const size_t bnx2i_library_transport_name_size =
ae92e4
 			sizeof(bnx2i_library_transport_name);
ae92e4
 
ae92e4
+/*******************************************************************************
ae92e4
+ * Constants for qedi module
ae92e4
+ ******************************************************************************/
ae92e4
+const char qedi_library_transport_name[] = "qedi";
ae92e4
+const size_t qedi_library_transport_name_size =
ae92e4
+			sizeof(qedi_library_transport_name);
ae92e4
+
ae92e4
 /******************************************************************************
ae92e4
  * Netlink Functions
ae92e4
  ******************************************************************************/
ae92e4
diff --git a/iscsiuio/src/unix/libs/cnic.h b/iscsiuio/src/unix/libs/cnic.h
ae92e4
index 6244a94012c1..c86595c512b0 100644
ae92e4
--- a/iscsiuio/src/unix/libs/cnic.h
ae92e4
+++ b/iscsiuio/src/unix/libs/cnic.h
ae92e4
@@ -44,6 +44,8 @@
ae92e4
  ******************************************************************************/
ae92e4
 extern const char bnx2i_library_transport_name[];
ae92e4
 extern const size_t bnx2i_library_transport_name_size;
ae92e4
+extern const char qedi_library_transport_name[];
ae92e4
+extern const size_t qedi_library_transport_name_size;
ae92e4
 
ae92e4
 int cnic_nl_open();
ae92e4
 void cnic_nl_close();
ae92e4
diff --git a/iscsiuio/src/unix/libs/qedi.c b/iscsiuio/src/unix/libs/qedi.c
ae92e4
new file mode 100644
ae92e4
index 000000000000..c2096e59dad1
ae92e4
--- /dev/null
ae92e4
+++ b/iscsiuio/src/unix/libs/qedi.c
ae92e4
@@ -0,0 +1,1151 @@
ae92e4
+/*
ae92e4
+ * Copyright (c) 2016, Cavium Inc.
ae92e4
+ *
ae92e4
+ * All rights reserved.
ae92e4
+ *
ae92e4
+ * Redistribution and use in source and binary forms, with or without
ae92e4
+ * modification, are permitted provided that the following conditions
ae92e4
+ * are met:
ae92e4
+ * 1. Redistributions of source code must retain the above copyright
ae92e4
+ *    notice, this list of conditions and the following disclaimer.
ae92e4
+ * 2. Redistributions in binary form must reproduce the above copyright
ae92e4
+ *    notice, this list of conditions and the following disclaimer in the
ae92e4
+ *    documentation and/or other materials provided with the distribution.
ae92e4
+ * 3. All advertising materials mentioning features or use of this software
ae92e4
+ *    must display the following acknowledgement:
ae92e4
+ *      This product includes software developed by Adam Dunkels.
ae92e4
+ * 4. The name of the author may not be used to endorse or promote
ae92e4
+ *    products derived from this software without specific prior
ae92e4
+ *    written permission.
ae92e4
+ *
ae92e4
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
ae92e4
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
ae92e4
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ae92e4
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
ae92e4
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
ae92e4
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
ae92e4
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
ae92e4
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
ae92e4
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
ae92e4
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
ae92e4
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ae92e4
+ *
ae92e4
+ * qedi.c - qedi user space driver
ae92e4
+ * This file handles different qedi NIC operations,
ae92e4
+ * qedi_open - initializes all hardware resources under NIC device
ae92e4
+ * qedi_close - closes the NIC device
ae92e4
+ * qedi_read - reads data to the hardware
ae92e4
+ * qedi_write - writes data to the hardware
ae92e4
+ * qedi_start_xmit - sends a pkt of data on NIC device
ae92e4
+ * qedi_get_tx_pkt - gets a Tx pkt from NIC
ae92e4
+ * qedi_clear_tx_intr - clears the Tx interrupt
ae92e4
+ * NOTE: nic_t is used as NIC device,
ae92e4
+ * 	 qedi is not attached to netdev hence it is not mandatory
ae92e4
+ * 	 for netdev to be upd
ae92e4
+ */
ae92e4
+#include <errno.h>
ae92e4
+#include <stdio.h>
ae92e4
+#include <string.h>
ae92e4
+#include <arpa/inet.h>
ae92e4
+#include <linux/types.h>
ae92e4
+#include <linux/sockios.h>
ae92e4
+#include <linux/ethtool.h>
ae92e4
+#include <linux/netlink.h>
ae92e4
+#include <sys/mman.h>
ae92e4
+#include <sys/ioctl.h>
ae92e4
+#include <sys/types.h>
ae92e4
+#include <sys/stat.h>
ae92e4
+#include <sys/user.h>
ae92e4
+#include <fcntl.h>
ae92e4
+#include <unistd.h>
ae92e4
+
ae92e4
+#include "config.h"
ae92e4
+
ae92e4
+#include "build_date.h"
ae92e4
+#include "bnx2x.h"
ae92e4
+#include "qedi.h"
ae92e4
+#include "cnic.h"
ae92e4
+#include "logger.h"
ae92e4
+#include "nic.h"
ae92e4
+#include "nic_id.h"
ae92e4
+#include "nic_utils.h"
ae92e4
+#include "options.h"
ae92e4
+
ae92e4
+#define PFX	"qedi "
ae92e4
+
ae92e4
+extern int nl_sock;
ae92e4
+
ae92e4
+/*  Foward struct declarations */
ae92e4
+struct nic_ops qedi_op;
ae92e4
+
ae92e4
+/*******************************************************************************
ae92e4
+ * NIC Library Strings
ae92e4
+ ******************************************************************************/
ae92e4
+static const char library_name[] = "qedi";
ae92e4
+static const char library_version[] = PACKAGE_VERSION;
ae92e4
+static const char library_uio_name[] = "qedi_uio";
ae92e4
+
ae92e4
+/*  The name that should be returned from /sys/class/uio/uio0/name */
ae92e4
+static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name";
ae92e4
+static const char qedi_uio_sysfs_name[] = "qedi_uio";
ae92e4
+static const char qedi_host_mac_template[] =
ae92e4
+	"/sys/class/iscsi_host/host%i/hwaddress";
ae92e4
+
ae92e4
+struct qedi_driver_version qedi_version = {
ae92e4
+	QEDI_UNKNOWN_MAJOR_VERSION,
ae92e4
+	QEDI_UNKNOWN_MINOR_VERSION,
ae92e4
+	QEDI_UNKNOWN_SUB_MINOR_VERSION,
ae92e4
+};
ae92e4
+
ae92e4
+static int qedi_clear_tx_intr(nic_t *nic);
ae92e4
+
ae92e4
+/*******************************************************************************
ae92e4
+ * QEDI Library Functions
ae92e4
+ ******************************************************************************/
ae92e4
+/**
ae92e4
+ *  qedi_get_library_name() - Used to get the name of this NIC library
ae92e4
+ *  @param name - This function will return the pointer to this NIC
ae92e4
+ *                library name
ae92e4
+ *  @param name_size
ae92e4
+ */
ae92e4
+static void qedi_get_library_name(char **name, size_t *name_size)
ae92e4
+{
ae92e4
+	*name = (char *)library_name;
ae92e4
+	*name_size = sizeof(library_name);
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_get_library_version() - Used to get the version string of this
ae92e4
+ *                                NIC library
ae92e4
+ *  @param version - This function will return the pointer to this NIC
ae92e4
+ *                   library version string
ae92e4
+ *  @param version_size - This will be set with the version size
ae92e4
+ */
ae92e4
+static void qedi_get_library_version(char **version, size_t *version_size)
ae92e4
+{
ae92e4
+	*version = (char *)library_version;
ae92e4
+	*version_size = sizeof(library_version);
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_get_build_date() - Used to get the build date string of this library
ae92e4
+ *  @param version - This function will return the pointer to this NIC
ae92e4
+ *                   library build date string
ae92e4
+ *  @param version_size - This will be set with the build date string size
ae92e4
+ */
ae92e4
+static void qedi_get_build_date(char **build, size_t *build_size)
ae92e4
+{
ae92e4
+	*build = (char *)build_date;
ae92e4
+	*build_size = sizeof(build_date);
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_get_transport_name() - Used to get the transport name associated
ae92e4
+ *                              with this this NIC library
ae92e4
+ *  @param transport_name - This function will return the pointer to this NIC
ae92e4
+ *                          library's associated transport string
ae92e4
+ *  @param transport_name_size - This will be set with the transport name size
ae92e4
+ */
ae92e4
+static void qedi_get_transport_name(char **transport_name,
ae92e4
+				    size_t *transport_name_size)
ae92e4
+{
ae92e4
+	*transport_name = (char *)qedi_library_transport_name;
ae92e4
+	*transport_name_size = qedi_library_transport_name_size;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_get_uio_name() - Used to get the uio name associated with this this
ae92e4
+ *                        NIC library
ae92e4
+ *  @param uio_name - This function will return the pointer to this NIC
ae92e4
+ *                    library's associated uio string
ae92e4
+ *  @param transport_name_size - This will be set with the uio name size
ae92e4
+ */
ae92e4
+static void qedi_get_uio_name(char **uio_name, size_t *uio_name_size)
ae92e4
+{
ae92e4
+	*uio_name = (char *)library_uio_name;
ae92e4
+	*uio_name_size = sizeof(library_uio_name);
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_get_ops() - Used to get the NIC library op table
ae92e4
+ *  @param op - The op table of this NIC library
ae92e4
+ */
ae92e4
+struct nic_ops *qedi_get_ops()
ae92e4
+{
ae92e4
+	return &qedi_op;
ae92e4
+}
ae92e4
+
ae92e4
+/*******************************************************************************
ae92e4
+ * qedi Utility Functions
ae92e4
+ ******************************************************************************/
ae92e4
+/*******************************************************************************
ae92e4
+ * Utility Functions Used to read register from the qedi device
ae92e4
+ ******************************************************************************/
ae92e4
+static void qedi_set_drv_version_unknown(qedi_t *bp)
ae92e4
+{
ae92e4
+	bp->version.major = QEDI_UNKNOWN_MAJOR_VERSION;
ae92e4
+	bp->version.minor = QEDI_UNKNOWN_MINOR_VERSION;
ae92e4
+	bp->version.sub_minor = QEDI_UNKNOWN_SUB_MINOR_VERSION;
ae92e4
+}
ae92e4
+
ae92e4
+/* Return: 1 = Unknown, 0 = Known */
ae92e4
+static int qedi_is_drv_version_unknown(struct qedi_driver_version *version)
ae92e4
+{
ae92e4
+	if ((version->major == (uint16_t)QEDI_UNKNOWN_MAJOR_VERSION) &&
ae92e4
+	    (version->minor == (uint16_t)QEDI_UNKNOWN_MINOR_VERSION) &&
ae92e4
+	    (version->sub_minor == (uint16_t)QEDI_UNKNOWN_SUB_MINOR_VERSION)) {
ae92e4
+		return 1;
ae92e4
+	}
ae92e4
+
ae92e4
+	return 0;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ * qedi_get_drv_version() - Used to determine the driver version
ae92e4
+ * @param bp - Device used to determine qedi driver version
ae92e4
+ */
ae92e4
+static int qedi_get_drv_version(qedi_t *bp)
ae92e4
+{
ae92e4
+	nic_t *nic = bp->parent;
ae92e4
+
ae92e4
+	/*
ae92e4
+	 * CAPABILITIES: Get the iscsi driver version from qedi
ae92e4
+	 * This may be obtained from sysfs
ae92e4
+	 */
ae92e4
+	LOG_INFO(PFX "%s: qedi driver using version %d.%d.%d",
ae92e4
+		 nic->log_name,
ae92e4
+		 bp->version.major, bp->version.minor, bp->version.sub_minor);
ae92e4
+
ae92e4
+	return 0;
ae92e4
+}
ae92e4
+
ae92e4
+/******************************************************************************/
ae92e4
+
ae92e4
+/**
ae92e4
+ * qedi_get_chip_id() - Used to retrieve the chip ID from the nic
ae92e4
+ * @param dev - Device used to determin NIC type
ae92e4
+ * @return Chip ID read from the MISC ID register
ae92e4
+ */
ae92e4
+static int qedi_get_chip_id(qedi_t *bp)
ae92e4
+{
ae92e4
+	/* int val, id; */
ae92e4
+
ae92e4
+	/* Get the chip revision id and number. */
ae92e4
+	/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
ae92e4
+	/*
ae92e4
+	 * CAPABILITIES: Get the CHIP info from qedi through sysfs or uio struct.
ae92e4
+	 */
ae92e4
+	return 0;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_uio_verify()
ae92e4
+ *
ae92e4
+ */
ae92e4
+static int qedi_uio_verify(nic_t *nic)
ae92e4
+{
ae92e4
+	char *raw = NULL, *raw_tmp;
ae92e4
+	uint32_t raw_size = 0;
ae92e4
+	char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8];
ae92e4
+	int rc = 0;
ae92e4
+
ae92e4
+	/*  Build the path to determine uio name */
ae92e4
+	snprintf(temp_path, sizeof(temp_path),
ae92e4
+		 cnic_uio_sysfs_name_tempate, nic->uio_minor);
ae92e4
+
ae92e4
+	rc = capture_file(&raw, &raw_size, temp_path);
ae92e4
+	if (rc != 0)
ae92e4
+		goto error;
ae92e4
+
ae92e4
+	/* sanitize name string by replacing newline with null termination */
ae92e4
+	raw_tmp = raw;
ae92e4
+	while (*raw_tmp != '\n')
ae92e4
+		raw_tmp++;
ae92e4
+	*raw_tmp = '\0';
ae92e4
+
ae92e4
+	if (strncmp(raw, qedi_uio_sysfs_name,
ae92e4
+		    sizeof(qedi_uio_sysfs_name)) != 0) {
ae92e4
+		LOG_ERR(PFX "%s: uio names not equal: expecting %s got %s from %s",
ae92e4
+			nic->log_name, qedi_uio_sysfs_name, raw, temp_path);
ae92e4
+		rc = -EIO;
ae92e4
+	}
ae92e4
+
ae92e4
+	free(raw);
ae92e4
+
ae92e4
+	LOG_INFO(PFX "%s: Verified is a qedi_uio device", nic->log_name);
ae92e4
+
ae92e4
+error:
ae92e4
+	return rc;
ae92e4
+}
ae92e4
+
ae92e4
+static int qedi_get_mac_addr(qedi_t *bp)
ae92e4
+{
ae92e4
+	nic_t *nic = bp->parent;
ae92e4
+	char *raw = NULL, *raw_tmp;
ae92e4
+	uint32_t raw_size = 0;
ae92e4
+	char temp_path[sizeof(qedi_host_mac_template) + 8];
ae92e4
+	int rc = 0;
ae92e4
+
ae92e4
+	/*  Build the path to determine mac address */
ae92e4
+	snprintf(temp_path, sizeof(temp_path),
ae92e4
+		 qedi_host_mac_template, nic->host_no);
ae92e4
+
ae92e4
+	rc = capture_file(&raw, &raw_size, temp_path);
ae92e4
+	if (rc != 0)
ae92e4
+		goto error;
ae92e4
+
ae92e4
+	/* sanitize name string by replacing newline with null termination */
ae92e4
+	raw_tmp = raw;
ae92e4
+	while (*raw_tmp != '\n')
ae92e4
+		raw_tmp++;
ae92e4
+	*raw_tmp = '\0';
ae92e4
+
ae92e4
+	rc = sscanf(raw, "%02x:%02x:%02x:%02x:%02x:%02x",
ae92e4
+	       (uint32_t *)&nic->mac_addr[0], (uint32_t *)&nic->mac_addr[1],
ae92e4
+	       (uint32_t *)&nic->mac_addr[2], (uint32_t *)&nic->mac_addr[3],
ae92e4
+	       (uint32_t *)&nic->mac_addr[4], (uint32_t *)&nic->mac_addr[5]);
ae92e4
+	if (rc != 1) {
ae92e4
+		LOG_WARN(PFX "%s: Could not parse mac_addr",
ae92e4
+			nic->log_name);
ae92e4
+		rc = -ENODEV;
ae92e4
+		goto error;
ae92e4
+	}
ae92e4
+
ae92e4
+error:
ae92e4
+	if (raw)
ae92e4
+		free(raw);
ae92e4
+	return rc;
ae92e4
+}
ae92e4
+
ae92e4
+/*******************************************************************************
ae92e4
+ * qedi Utility Functions to get to the hardware consumer indexes
ae92e4
+ ******************************************************************************/
ae92e4
+
ae92e4
+static __u32 qedi_get_rx(qedi_t *bp)
ae92e4
+{
ae92e4
+	return ((struct qedi_uio_ctrl *)bp->uctrl_map)->host_rx_cons;
ae92e4
+}
ae92e4
+
ae92e4
+static __u32 qedi_get_tx(qedi_t *bp)
ae92e4
+{
ae92e4
+	return ((struct qedi_uio_ctrl *)bp->uctrl_map)->hw_tx_cons;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_free() - Used to free a qedi structure
ae92e4
+ */
ae92e4
+static void qedi_free(nic_t *nic)
ae92e4
+{
ae92e4
+	if (nic->priv)
ae92e4
+		free(nic->priv);
ae92e4
+	nic->priv = NULL;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_alloc() - Used to allocate a qedi structure
ae92e4
+ */
ae92e4
+static qedi_t *qedi_alloc(nic_t *nic)
ae92e4
+{
ae92e4
+	qedi_t *bp = malloc(sizeof(*bp));
ae92e4
+
ae92e4
+	if (!bp) {
ae92e4
+		LOG_ERR(PFX "%s: Could not allocate QEDI space",
ae92e4
+			nic->log_name);
ae92e4
+		return NULL;
ae92e4
+	}
ae92e4
+
ae92e4
+	/*  Clear out the CNIC contents */
ae92e4
+	memset(bp, 0, sizeof(*bp));
ae92e4
+
ae92e4
+	bp->parent = nic;
ae92e4
+	nic->priv = (void *)bp;
ae92e4
+	get_iscsi_transport_handle(nic, &nic->transport_handle);
ae92e4
+	qedi_set_drv_version_unknown(bp);
ae92e4
+
ae92e4
+	return bp;
ae92e4
+}
ae92e4
+
ae92e4
+int uio_get_map_offset(nic_t *nic, uint8_t map, uint32_t *offset)
ae92e4
+{
ae92e4
+	char *raw = NULL;
ae92e4
+	uint32_t raw_size = 0;
ae92e4
+	ssize_t elements_read;
ae92e4
+	char temp_path[sizeof(UIO_OFFSET_TMPL) + 8];
ae92e4
+	int rc = 0;
ae92e4
+
ae92e4
+	/*  Capture RX buffer size */
ae92e4
+	snprintf(temp_path, sizeof(temp_path),
ae92e4
+		 UIO_OFFSET_TMPL, nic->uio_minor, map);
ae92e4
+
ae92e4
+	rc = capture_file(&raw, &raw_size, temp_path);
ae92e4
+	if (rc != 0)
ae92e4
+		goto error;
ae92e4
+
ae92e4
+	elements_read = sscanf(raw, "0x%x", offset);
ae92e4
+	if (elements_read != 1) {
ae92e4
+		LOG_ERR(PFX "%s: Couldn't get the offset from %s",
ae92e4
+			nic->log_name, temp_path);
ae92e4
+		rc = -EIO;
ae92e4
+		goto error;
ae92e4
+	}
ae92e4
+
ae92e4
+	rc = 0;
ae92e4
+error:
ae92e4
+	if (raw)
ae92e4
+		free(raw);
ae92e4
+
ae92e4
+	return rc;
ae92e4
+}
ae92e4
+
ae92e4
+int uio_get_map_info(nic_t *nic, uint8_t map, char *attr, uint32_t *val)
ae92e4
+{
ae92e4
+	char *raw = NULL;
ae92e4
+	uint32_t raw_size = 0;
ae92e4
+	ssize_t elements_read;
ae92e4
+	char temp_path[sizeof(UIO_ATTR_TMPL) + 8];
ae92e4
+	int rc = 0;
ae92e4
+
ae92e4
+	/*  Capture RX buffer size */
ae92e4
+	snprintf(temp_path, sizeof(temp_path),
ae92e4
+		 UIO_ATTR_TMPL, nic->uio_minor, map, attr);
ae92e4
+
ae92e4
+	rc = capture_file(&raw, &raw_size, temp_path);
ae92e4
+	if (rc != 0)
ae92e4
+		goto error;
ae92e4
+
ae92e4
+	elements_read = sscanf(raw, "0x%x", val);
ae92e4
+	if (elements_read != 1) {
ae92e4
+		LOG_ERR(PFX "%s: Couldn't get the offset from %s",
ae92e4
+			nic->log_name, temp_path);
ae92e4
+		rc = -EIO;
ae92e4
+		goto error;
ae92e4
+	}
ae92e4
+
ae92e4
+	rc = 0;
ae92e4
+error:
ae92e4
+	if (raw)
ae92e4
+		free(raw);
ae92e4
+
ae92e4
+	return rc;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ * qedi_open() - This will initialize all the hardware resources underneath
ae92e4
+ *               a struct cnic_uio device
ae92e4
+ * @param dev - The struct cnic_uio device to attach the hardware with
ae92e4
+ * @return 0 on success, on failure a errno will be returned
ae92e4
+ */
ae92e4
+static int qedi_open(nic_t *nic)
ae92e4
+{
ae92e4
+	qedi_t *bp = NULL;
ae92e4
+	struct stat uio_stat;
ae92e4
+	int i, rc;
ae92e4
+	int count;
ae92e4
+	uint32_t bus;
ae92e4
+	uint32_t slot;
ae92e4
+	uint32_t func;
ae92e4
+	uint32_t offset;
ae92e4
+
ae92e4
+	/*  Sanity Check: validate the parameters */
ae92e4
+	if (!nic) {
ae92e4
+		LOG_ERR(PFX "nic == NULL");
ae92e4
+		return -EINVAL;
ae92e4
+	}
ae92e4
+
ae92e4
+	if ((nic->priv) != NULL &&
ae92e4
+	    (((qedi_t *)(nic->priv))->flags & QEDI_OPENED)) {
ae92e4
+		return 0;
ae92e4
+	}
ae92e4
+
ae92e4
+	if (nic->host_no == INVALID_HOST_NO) {
ae92e4
+		rc = sscanf(nic->config_device_name, "host%d", &nic->host_no);
ae92e4
+		if (rc != 1) {
ae92e4
+			LOG_WARN(PFX "%s: Could not parse for host number",
ae92e4
+				 nic->config_device_name);
ae92e4
+			rc = -ENODEV;
ae92e4
+			goto open_error;
ae92e4
+		}
ae92e4
+	}
ae92e4
+
ae92e4
+	bp = qedi_alloc(nic);
ae92e4
+	if (!bp)
ae92e4
+		return -ENOMEM;
ae92e4
+
ae92e4
+	if (qedi_is_drv_version_unknown(&qedi_version)) {
ae92e4
+		/* If version is unknown, go read from ethtool */
ae92e4
+		rc = qedi_get_drv_version(bp);
ae92e4
+		if (rc)
ae92e4
+			goto open_error;
ae92e4
+	} else {
ae92e4
+		/* Version is not unknown, just use it */
ae92e4
+		qedi_version.major = bp->version.major;
ae92e4
+		qedi_version.minor = bp->version.minor;
ae92e4
+		qedi_version.sub_minor = bp->version.sub_minor;
ae92e4
+	}
ae92e4
+
ae92e4
+	count = 0;
ae92e4
+	while ((nic->fd < 0) && count < 15) {
ae92e4
+		/*  udev might not have created the file yet */
ae92e4
+		pthread_mutex_unlock(&nic->nic_mutex);
ae92e4
+		sleep(1);
ae92e4
+		pthread_mutex_lock(&nic->nic_mutex);
ae92e4
+
ae92e4
+		nic->fd = open(nic->uio_device_name, O_RDWR | O_NONBLOCK);
ae92e4
+		if (nic->fd != INVALID_FD) {
ae92e4
+			LOG_ERR(PFX "%s: uio device has been brought up via pid: %d on fd: %d",
ae92e4
+				nic->uio_device_name, getpid(), nic->fd);
ae92e4
+
ae92e4
+			rc = qedi_uio_verify(nic);
ae92e4
+			if (rc != 0)
ae92e4
+				continue;
ae92e4
+
ae92e4
+			break;
ae92e4
+		} else {
ae92e4
+			LOG_WARN(PFX "%s: Could not open device: %s, [%s]",
ae92e4
+				 nic->log_name, nic->uio_device_name,
ae92e4
+				 strerror(errno));
ae92e4
+
ae92e4
+			manually_trigger_uio_event(nic, nic->uio_minor);
ae92e4
+
ae92e4
+			/*  udev might not have created the file yet */
ae92e4
+			pthread_mutex_unlock(&nic->nic_mutex);
ae92e4
+			sleep(1);
ae92e4
+			pthread_mutex_lock(&nic->nic_mutex);
ae92e4
+
ae92e4
+			count++;
ae92e4
+		}
ae92e4
+	}
ae92e4
+	if (fstat(nic->fd, &uio_stat) < 0) {
ae92e4
+		LOG_ERR(PFX "%s: Could not fstat device", nic->log_name);
ae92e4
+		rc = -ENODEV;
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+	nic->uio_minor = minor(uio_stat.st_rdev);
ae92e4
+
ae92e4
+	/*
ae92e4
+	 * CAPABILITIES: acquire the rx buffer size and rx ring size from qedi
ae92e4
+	 */
ae92e4
+
ae92e4
+	bp->rx_ring_size = RX_RING_SIZE;
ae92e4
+	bp->rx_buffer_size = PKT_BUF_SIZE;
ae92e4
+
ae92e4
+	LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d",
ae92e4
+		  nic->log_name, bp->rx_ring_size, bp->rx_buffer_size);
ae92e4
+
ae92e4
+	/* Determine the number of UIO events that have already occurred */
ae92e4
+	rc = detemine_initial_uio_events(nic, &nic->intr_count);
ae92e4
+	if (rc != 0) {
ae92e4
+		LOG_ERR(PFX "Could not get the no. of initial UIO events");
ae92e4
+		nic->intr_count = 0;
ae92e4
+	}
ae92e4
+
ae92e4
+	/* Allocate space for rx pkt ring */
ae92e4
+	bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size);
ae92e4
+	if (!bp->rx_pkt_ring) {
ae92e4
+		LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring",
ae92e4
+			nic->log_name);
ae92e4
+		rc = errno;
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+
ae92e4
+	/*
ae92e4
+	 * Map the uio struct and packet buffer
ae92e4
+	 */
ae92e4
+	offset = 0;
ae92e4
+	rc = uio_get_map_info(nic, QEDI_UCTRL_MAP_REG, "size", &offset);
ae92e4
+	if (rc) {
ae92e4
+		LOG_INFO(PFX "Failed to get the map size rc=%d", rc);
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+	LOG_INFO(PFX "uctrl map size=%u", offset);
ae92e4
+
ae92e4
+	offset = 0;
ae92e4
+	rc = uio_get_map_info(nic, QEDI_RING_MAP_REG, "size", &offset);
ae92e4
+	if (rc) {
ae92e4
+		LOG_INFO(PFX "Failed to get the map size rc=%d", rc);
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+	LOG_INFO(PFX "ring map size=%u", offset);
ae92e4
+
ae92e4
+	offset = 0;
ae92e4
+	rc = uio_get_map_info(nic, QEDI_BUF_MAP_REG, "size", &offset);
ae92e4
+	if (rc) {
ae92e4
+		LOG_INFO(PFX "Failed to get the map size rc=%d", rc);
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+	LOG_INFO(PFX "buf map size=%u", offset);
ae92e4
+
ae92e4
+	offset = 0;
ae92e4
+	rc = uio_get_map_offset(nic, QEDI_UCTRL_MAP_REG, &offset);
ae92e4
+	if (rc) {
ae92e4
+		LOG_INFO(PFX "Failed to get the map offset rc=%d", rc);
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+
ae92e4
+	bp->uctrl_map = mmap(NULL, sizeof(struct qedi_uio_ctrl),
ae92e4
+			    PROT_READ | PROT_WRITE,
ae92e4
+			    MAP_SHARED | MAP_LOCKED,
ae92e4
+			    nic->fd, (off_t)0);
ae92e4
+	if (bp->uctrl_map == MAP_FAILED) {
ae92e4
+		LOG_INFO(PFX "%s: Could not mmap uio ctrl struct: %s",
ae92e4
+			 nic->log_name, strerror(errno));
ae92e4
+		bp->uctrl_map = NULL;
ae92e4
+		rc = errno;
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+
ae92e4
+	bp->uctrl_map_offset = offset;
ae92e4
+	bp->uctrl_map += offset;
ae92e4
+
ae92e4
+	bp->rx_comp_ring = mmap(NULL, nic->page_size,
ae92e4
+			   PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED,
ae92e4
+			   nic->fd, (off_t)nic->page_size);
ae92e4
+	if (bp->rx_comp_ring == MAP_FAILED) {
ae92e4
+		LOG_INFO(PFX "%s: Could not mmap rx_comp_ring: %s",
ae92e4
+			 nic->log_name, strerror(errno));
ae92e4
+		bp->rx_comp_ring = NULL;
ae92e4
+		rc = errno;
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+
ae92e4
+	bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size,
ae92e4
+			PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED,
ae92e4
+			nic->fd, (off_t)2 * nic->page_size);
ae92e4
+	if (bp->bufs == MAP_FAILED) {
ae92e4
+		LOG_INFO(PFX "%s: Could not mmap pkt buffers: %s",
ae92e4
+			 nic->log_name, strerror(errno));
ae92e4
+		bp->bufs = NULL;
ae92e4
+		rc = errno;
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+
ae92e4
+	/*
ae92e4
+	 * Get all CHIP related info from qedi
ae92e4
+	 */
ae92e4
+	bp->chip_id = qedi_get_chip_id(bp);
ae92e4
+	LOG_DEBUG(PFX "Chip ID: %x", bp->chip_id);
ae92e4
+
ae92e4
+	rc = get_bus_slot_func_num(nic, &bus, &slot, &func);
ae92e4
+	if (rc != 0) {
ae92e4
+		LOG_INFO(PFX "%s: Couldn't determine bus:slot.func",
ae92e4
+			 nic->log_name);
ae92e4
+		goto open_error;
ae92e4
+	}
ae92e4
+
ae92e4
+	/*
ae92e4
+	 * Get all function, pfid, client_id and cid info from qedi
ae92e4
+	 */
ae92e4
+	LOG_INFO(PFX "%s: func 0x%x, pfid 0x%x, client_id 0x%x, cid 0x%x",
ae92e4
+		 nic->log_name, bp->func, bp->pfid, bp->client_id, bp->cid);
ae92e4
+
ae92e4
+	bp->get_rx_cons = qedi_get_rx;
ae92e4
+	bp->get_tx_cons = qedi_get_tx;
ae92e4
+	bp->tx_cons = 0;
ae92e4
+	bp->tx_prod = 0;
ae92e4
+	bp->tx_bd_prod = 0;
ae92e4
+	bp->tx_pkt = bp->bufs;
ae92e4
+	bp->rx_pkts = bp->bufs + bp->rx_buffer_size;
ae92e4
+
ae92e4
+	bp->rx_index = 0;
ae92e4
+	bp->rx_cons = 0;
ae92e4
+	bp->rx_bd_cons = 0;
ae92e4
+	bp->rx_prod = 127;
ae92e4
+	bp->rx_bd_prod = bp->rx_ring_size;
ae92e4
+
ae92e4
+	for (i = 0; i < bp->rx_ring_size; i++) {
ae92e4
+		void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1));
ae92e4
+
ae92e4
+		bp->rx_pkt_ring[i] = ptr;
ae92e4
+	}
ae92e4
+
ae92e4
+	qedi_get_mac_addr(bp);
ae92e4
+	LOG_INFO(PFX "%s:  Using mac address: %02x:%02x:%02x:%02x:%02x:%02x",
ae92e4
+		 nic->log_name,
ae92e4
+		 nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2],
ae92e4
+		 nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]);
ae92e4
+
ae92e4
+	qedi_get_library_name(&nic->library_name, (size_t *)&count);
ae92e4
+	LOG_INFO("%s: qedi initialized", nic->log_name);
ae92e4
+
ae92e4
+	bp->flags |= QEDI_OPENED;
ae92e4
+
ae92e4
+	return 0;
ae92e4
+
ae92e4
+open_error:
ae92e4
+
ae92e4
+	if (bp->bufs) {
ae92e4
+		munmap(bp->bufs, (bp->rx_ring_size + 1) * bp->rx_buffer_size);
ae92e4
+		bp->bufs = NULL;
ae92e4
+	}
ae92e4
+
ae92e4
+	if (bp->rx_comp_ring) {
ae92e4
+		munmap(bp->rx_comp_ring, nic->page_size);
ae92e4
+		bp->rx_comp_ring = NULL;
ae92e4
+	}
ae92e4
+
ae92e4
+	if (bp->uctrl_map) {
ae92e4
+		bp->uctrl_map -= bp->uctrl_map_offset;
ae92e4
+		munmap(bp->uctrl_map, sizeof(struct qedi_uio_ctrl));
ae92e4
+		bp->uctrl_map = NULL;
ae92e4
+	}
ae92e4
+
ae92e4
+	if (bp->rx_pkt_ring) {
ae92e4
+		free(bp->rx_pkt_ring);
ae92e4
+		bp->rx_pkt_ring = NULL;
ae92e4
+	}
ae92e4
+
ae92e4
+	if (nic->fd != INVALID_FD) {
ae92e4
+		close(nic->fd);
ae92e4
+		nic->fd = INVALID_FD;
ae92e4
+	}
ae92e4
+
ae92e4
+	qedi_free(nic);
ae92e4
+
ae92e4
+	return rc;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_uio_close_resources() - Used to free resource for the NIC/CNIC
ae92e4
+ *  @param nic - NIC device to free resource
ae92e4
+ *  @param graceful - whether to wait to close gracefully
ae92e4
+ *  @return 0 on success, <0 on failure
ae92e4
+ */
ae92e4
+static int qedi_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful)
ae92e4
+{
ae92e4
+	qedi_t *bp = (qedi_t *)nic->priv;
ae92e4
+	int rc = 0;
ae92e4
+
ae92e4
+	/*  Check if there is an assoicated qedi device */
ae92e4
+	if (!bp) {
ae92e4
+		LOG_WARN(PFX "%s: when closing resources there is no assoicated qedi",
ae92e4
+			 nic->log_name);
ae92e4
+		return -EIO;
ae92e4
+	}
ae92e4
+
ae92e4
+	/*  Clean up allocated memory */
ae92e4
+
ae92e4
+	if (bp->rx_pkt_ring) {
ae92e4
+		free(bp->rx_pkt_ring);
ae92e4
+		bp->rx_pkt_ring = NULL;
ae92e4
+	}
ae92e4
+
ae92e4
+	/*  Clean up mapped registers */
ae92e4
+	if (bp->bufs) {
ae92e4
+		rc = munmap(bp->bufs,
ae92e4
+			    (bp->rx_ring_size + 1) * bp->rx_buffer_size);
ae92e4
+		if (rc != 0)
ae92e4
+			LOG_ERR(PFX "%s: Couldn't unmap bufs", nic->log_name);
ae92e4
+		bp->bufs = NULL;
ae92e4
+	}
ae92e4
+
ae92e4
+	if (bp->rx_comp_ring) {
ae92e4
+		rc = munmap(bp->rx_comp_ring, nic->page_size);
ae92e4
+		if (rc != 0)
ae92e4
+			LOG_ERR(PFX "%s: Couldn't unmap ring", nic->log_name);
ae92e4
+		bp->rx_comp_ring = NULL;
ae92e4
+	}
ae92e4
+
ae92e4
+	if (bp->uctrl_map) {
ae92e4
+		bp->uctrl_map -= bp->uctrl_map_offset;
ae92e4
+		rc = munmap(bp->uctrl_map, sizeof(struct qedi_uio_ctrl));
ae92e4
+		if (rc != 0) {
ae92e4
+			LOG_ERR(PFX "%s: Couldn't unmap uio ctrl",
ae92e4
+				nic->log_name);
ae92e4
+		}
ae92e4
+		bp->uctrl_map = NULL;
ae92e4
+	}
ae92e4
+
ae92e4
+	if (nic->fd != INVALID_FD) {
ae92e4
+		rc = close(nic->fd);
ae92e4
+		if (rc != 0) {
ae92e4
+			LOG_ERR(PFX
ae92e4
+				 "%s: Couldn't close uio file descriptor: %d",
ae92e4
+				 nic->log_name, nic->fd);
ae92e4
+		} else {
ae92e4
+			LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d",
ae92e4
+				  nic->log_name, nic->fd);
ae92e4
+		}
ae92e4
+
ae92e4
+		nic->fd = INVALID_FD;
ae92e4
+	} else {
ae92e4
+		LOG_ERR(PFX "%s: Invalid uio file descriptor: %d",
ae92e4
+			nic->log_name, nic->fd);
ae92e4
+	}
ae92e4
+
ae92e4
+	qedi_set_drv_version_unknown(bp);
ae92e4
+
ae92e4
+	LOG_INFO(PFX "%s: Closed all resources", nic->log_name);
ae92e4
+
ae92e4
+	return 0;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_close() - Used to close the NIC device
ae92e4
+ *  @param nic - NIC device to close
ae92e4
+ *  @param graceful - whether to wait to close gracefully
ae92e4
+ *  @return 0 if successful, <0 if there is an error
ae92e4
+ */
ae92e4
+static int qedi_close(nic_t *nic, NIC_SHUTDOWN_T graceful)
ae92e4
+{
ae92e4
+	/*  Sanity Check: validate the parameters */
ae92e4
+	if (!nic) {
ae92e4
+		LOG_ERR(PFX "%s: nic == NULL", __func__);
ae92e4
+		return -EINVAL;
ae92e4
+	}
ae92e4
+	if (!nic->priv) {
ae92e4
+		LOG_ERR(PFX "%s: nic->priv == NULL", __func__);
ae92e4
+		return -EINVAL;
ae92e4
+	}
ae92e4
+
ae92e4
+	LOG_INFO(PFX "Closing NIC device: %s", nic->log_name);
ae92e4
+
ae92e4
+	qedi_uio_close_resources(nic, graceful);
ae92e4
+	qedi_free(nic);
ae92e4
+
ae92e4
+	return 0;
ae92e4
+}
ae92e4
+
ae92e4
+static void qedi_prepare_xmit_packet(nic_t *nic,
ae92e4
+				     nic_interface_t *nic_iface,
ae92e4
+				     struct packet *pkt)
ae92e4
+{
ae92e4
+	qedi_t *bp = (qedi_t *)nic->priv;
ae92e4
+	struct uip_vlan_eth_hdr *eth_vlan = (struct uip_vlan_eth_hdr *)pkt->buf;
ae92e4
+	struct uip_eth_hdr *eth = (struct uip_eth_hdr *)bp->tx_pkt;
ae92e4
+
ae92e4
+	if (eth_vlan->tpid == htons(UIP_ETHTYPE_8021Q)) {
ae92e4
+		memcpy(bp->tx_pkt, pkt->buf, sizeof(struct uip_eth_hdr));
ae92e4
+		eth->type = eth_vlan->type;
ae92e4
+		pkt->buf_size -= (sizeof(struct uip_vlan_eth_hdr) -
ae92e4
+				  sizeof(struct uip_eth_hdr));
ae92e4
+		memcpy(bp->tx_pkt + sizeof(struct uip_eth_hdr),
ae92e4
+		       pkt->buf + sizeof(struct uip_vlan_eth_hdr),
ae92e4
+		       pkt->buf_size - sizeof(struct uip_eth_hdr));
ae92e4
+	} else {
ae92e4
+		memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size);
ae92e4
+	}
ae92e4
+
ae92e4
+	msync(bp->tx_pkt, pkt->buf_size, MS_SYNC);
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_get_tx_pkt() - This function is used to a TX packet from the NIC
ae92e4
+ *  @param nic - The NIC device to send the packet
ae92e4
+ */
ae92e4
+void *qedi_get_tx_pkt(nic_t *nic)
ae92e4
+{
ae92e4
+	qedi_t *bp = (qedi_t *)nic->priv;
ae92e4
+
ae92e4
+	return bp->tx_pkt;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_start_xmit() - This function is used to send a packet of data
ae92e4
+ *  @param nic - The NIC device to send the packet
ae92e4
+ *  @param len - the length of the TX packet
ae92e4
+ *
ae92e4
+ */
ae92e4
+void qedi_start_xmit(nic_t *nic, size_t len, u16_t vlan_id)
ae92e4
+{
ae92e4
+	qedi_t *bp = (qedi_t *)nic->priv;
ae92e4
+	uint8_t *ubuf;
ae92e4
+	struct iscsi_uevent *ev;
ae92e4
+	struct iscsi_path *path_data;
ae92e4
+	struct qedi_uio_ctrl *uctrl;
ae92e4
+	int rc = 0;
ae92e4
+	uint16_t buflen;
ae92e4
+
ae92e4
+	uctrl = (struct qedi_uio_ctrl *)bp->uctrl_map;
ae92e4
+
ae92e4
+	buflen = sizeof(struct iscsi_uevent) + sizeof(struct iscsi_path);
ae92e4
+	ubuf = calloc(1, NLMSG_SPACE(buflen));
ae92e4
+	if (!ubuf) {
ae92e4
+		LOG_ERR(PFX "%s: alloc failed for uevent buf", __func__);
ae92e4
+		return;
ae92e4
+	}
ae92e4
+
ae92e4
+	memset(ubuf, 0, NLMSG_SPACE(buflen));
ae92e4
+
ae92e4
+	/*  prepare the iscsi_uevent buffer */
ae92e4
+	ev = (struct iscsi_uevent *)ubuf;
ae92e4
+	ev->type = ISCSI_UEVENT_PATH_UPDATE;
ae92e4
+	ev->transport_handle = nic->transport_handle;
ae92e4
+	ev->u.set_path.host_no = nic->host_no;
ae92e4
+
ae92e4
+	/*  Prepare the iscsi_path buffer */
ae92e4
+	path_data = (struct iscsi_path *)(ubuf + sizeof(struct iscsi_uevent));
ae92e4
+	path_data->handle = QEDI_PATH_HANDLE;
ae92e4
+	path_data->vlan_id = vlan_id;
ae92e4
+	uctrl->host_tx_pkt_len = len;
ae92e4
+
ae92e4
+	rc = __kipc_call(nl_sock, ev, buflen);
ae92e4
+	if (rc > 0) {
ae92e4
+		bp->tx_prod++;
ae92e4
+		uctrl->host_tx_prod++;
ae92e4
+		msync(uctrl, sizeof(struct qedi_uio_ctrl), MS_SYNC);
ae92e4
+		LOG_PACKET(PFX "%s: sent %d bytes using bp->tx_prod: %d",
ae92e4
+			   nic->log_name, len, bp->tx_prod);
ae92e4
+	} else {
ae92e4
+		LOG_ERR(PFX "Pkt transmission failed: %d", rc);
ae92e4
+		pthread_mutex_unlock(&nic->xmit_mutex);
ae92e4
+	}
ae92e4
+
ae92e4
+	free(ubuf);
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_write() - Used to write the data to the hardware
ae92e4
+ *  @param nic - NIC hardware to read from
ae92e4
+ *  @param pkt - The packet which will hold the data to be sent on the wire
ae92e4
+ *  @return 0 if successful, <0 if failed
ae92e4
+ */
ae92e4
+int qedi_write(nic_t *nic, nic_interface_t *nic_iface, packet_t *pkt)
ae92e4
+{
ae92e4
+	qedi_t *bp;
ae92e4
+	struct uip_stack *uip;
ae92e4
+	int i = 0;
ae92e4
+
ae92e4
+	/* Sanity Check: validate the parameters */
ae92e4
+	if (!nic || !nic_iface || !pkt) {
ae92e4
+		LOG_ERR(PFX "%s: qedi_write() nic == 0x%p || nic_iface == 0x%p || pkt == 0x%x",
ae92e4
+			nic, nic_iface, pkt);
ae92e4
+		return -EINVAL;
ae92e4
+	}
ae92e4
+	bp = (qedi_t *)nic->priv;
ae92e4
+	uip = &nic_iface->ustack;
ae92e4
+
ae92e4
+	if (pkt->buf_size == 0) {
ae92e4
+		LOG_ERR(PFX "%s: Trying to transmitted 0 sized packet",
ae92e4
+			nic->log_name);
ae92e4
+		return -EINVAL;
ae92e4
+	}
ae92e4
+
ae92e4
+	/*  Try to wait for a TX completion */
ae92e4
+	for (i = 0; i < 15; i++) {
ae92e4
+		struct timespec sleep_req = {.tv_sec = 0, .tv_nsec = 5000000 },
ae92e4
+		    sleep_rem;
ae92e4
+
ae92e4
+		if (qedi_clear_tx_intr(nic) == 0)
ae92e4
+			break;
ae92e4
+
ae92e4
+		nanosleep(&sleep_req, &sleep_rem);
ae92e4
+	}
ae92e4
+
ae92e4
+	if (pthread_mutex_trylock(&nic->xmit_mutex) != 0) {
ae92e4
+		LOG_PACKET(PFX "%s: Dropped previous transmitted packet",
ae92e4
+			   nic->log_name);
ae92e4
+		return -EINVAL;
ae92e4
+	}
ae92e4
+
ae92e4
+	qedi_prepare_xmit_packet(nic, nic_iface, pkt);
ae92e4
+	qedi_start_xmit(nic, pkt->buf_size,
ae92e4
+			(nic_iface->vlan_priority << 12) |
ae92e4
+			nic_iface->vlan_id);
ae92e4
+
ae92e4
+	/* bump up the tx stats */
ae92e4
+	nic->stats.tx.packets++;
ae92e4
+	nic->stats.tx.bytes += uip->uip_len;
ae92e4
+
ae92e4
+	LOG_PACKET(PFX "%s: transmitted %d bytes dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d",
ae92e4
+		   nic->log_name, pkt->buf_size,
ae92e4
+		   bp->tx_cons, bp->tx_prod, bp->tx_bd_prod);
ae92e4
+
ae92e4
+	return 0;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
+ *  qedi_read() - Used to read the data from the hardware
ae92e4
+ *  @param nic - NIC hardware to read from
ae92e4
+ *  @param pkt - The packet which will hold the data
ae92e4
+ *  @return 0 if successful, < 0 if failed
ae92e4
+ */
ae92e4
+static int qedi_read(nic_t *nic, packet_t *pkt)
ae92e4
+{
ae92e4
+	qedi_t *bp;
ae92e4
+	void *rx_pkt;
ae92e4
+	int rc = 0;
ae92e4
+	uint32_t sw_cons, bd_cons;
ae92e4
+	uint32_t hw_prod;
ae92e4
+	uint32_t rx_pkt_idx;
ae92e4
+	int len;
ae92e4
+	struct qedi_rx_bd *rx_bd;
ae92e4
+	struct qedi_uio_ctrl *uctrl;
ae92e4
+	uint16_t vlan_id;
ae92e4
+
ae92e4
+	/* Sanity Check: validate the parameters */
ae92e4
+	if (!nic || !pkt) {
ae92e4
+		LOG_ERR(PFX "%s: qedi_read() nic == 0x%p || pkt == 0x%x",
ae92e4
+			nic, pkt);
ae92e4
+		return -EINVAL;
ae92e4
+	}
ae92e4
+
ae92e4
+	bp = (qedi_t *)nic->priv;
ae92e4
+	msync(bp->uctrl_map, sizeof(struct qedi_uio_ctrl), MS_SYNC);
ae92e4
+	msync(bp->rx_comp_ring, nic->page_size, MS_SYNC);
ae92e4
+	uctrl = (struct qedi_uio_ctrl *)bp->uctrl_map;
ae92e4
+	hw_prod = uctrl->hw_rx_prod;
ae92e4
+	sw_cons = uctrl->host_rx_cons;
ae92e4
+	bd_cons = uctrl->host_rx_bd_cons;
ae92e4
+	rx_bd = bp->rx_comp_ring + (bd_cons * sizeof(*rx_bd));
ae92e4
+	len = rx_bd->rx_pkt_len;
ae92e4
+	rx_pkt_idx = rx_bd->rx_pkt_index;
ae92e4
+	vlan_id = rx_bd->vlan_id;
ae92e4
+
ae92e4
+	if (sw_cons != hw_prod) {
ae92e4
+		LOG_DEBUG(PFX "%s: clearing rx interrupt: %d %d",
ae92e4
+			  nic->log_name, sw_cons, hw_prod);
ae92e4
+		rc = 1;
ae92e4
+		rx_pkt = bp->rx_pkts + (bp->rx_buffer_size * rx_pkt_idx);
ae92e4
+
ae92e4
+		if (len > 0) {
ae92e4
+			msync(rx_pkt, len, MS_SYNC);
ae92e4
+			/*  Copy the data */
ae92e4
+			memcpy(pkt->buf, rx_pkt, len);
ae92e4
+			pkt->buf_size = len;
ae92e4
+			if (vlan_id) {
ae92e4
+				pkt->vlan_tag = vlan_id;
ae92e4
+				pkt->flags |= VLAN_TAGGED;
ae92e4
+			} else {
ae92e4
+				pkt->vlan_tag = 0;
ae92e4
+			}
ae92e4
+
ae92e4
+			LOG_DEBUG(PFX "%s: processing packet length: %d",
ae92e4
+				  nic->log_name, len);
ae92e4
+
ae92e4
+			/* bump up the recv stats */
ae92e4
+			nic->stats.rx.packets++;
ae92e4
+			nic->stats.rx.bytes += pkt->buf_size;
ae92e4
+		} else {
ae92e4
+			rc = 0;
ae92e4
+		}
ae92e4
+
ae92e4
+		sw_cons = (sw_cons + 1) % RX_RING_SIZE;
ae92e4
+		bd_cons = (bd_cons + 1) % QEDI_NUM_RX_BD;
ae92e4
+		uctrl->host_rx_cons_cnt++;
ae92e4
+	}
ae92e4
+
ae92e4
+	uctrl->host_rx_bd_cons = bd_cons;
ae92e4
+	uctrl->host_rx_cons = sw_cons;
ae92e4
+
ae92e4
+	msync(uctrl, sizeof(struct qedi_uio_ctrl), MS_SYNC);
ae92e4
+	msync(bp->rx_comp_ring, nic->page_size, MS_SYNC);
ae92e4
+	return rc;
ae92e4
+}
ae92e4
+
ae92e4
+/*******************************************************************************
ae92e4
+ * Clearing TX interrupts
ae92e4
+ ******************************************************************************/
ae92e4
+/**
ae92e4
+ *  qedi_clear_tx_intr() - This routine is called when a TX interrupt occurs
ae92e4
+ *  @param nic - the nic the interrupt occurred on
ae92e4
+ *  @return  0 on success
ae92e4
+ */
ae92e4
+
ae92e4
+static int qedi_clear_tx_intr(nic_t *nic)
ae92e4
+{
ae92e4
+	qedi_t *bp;
ae92e4
+	uint32_t hw_cons;
ae92e4
+	struct qedi_uio_ctrl *uctrl;
ae92e4
+
ae92e4
+	/* Sanity check: ensure the parameters passed in are valid */
ae92e4
+	if (unlikely(!nic)) {
ae92e4
+		LOG_ERR(PFX "%s: nic == NULL", __func__);
ae92e4
+		return -EINVAL;
ae92e4
+	}
ae92e4
+
ae92e4
+	bp = (qedi_t *)nic->priv;
ae92e4
+	uctrl = (struct qedi_uio_ctrl *)bp->uctrl_map;
ae92e4
+	msync(bp->uctrl_map, sizeof(struct qedi_uio_ctrl), MS_SYNC);
ae92e4
+	hw_cons = uctrl->hw_tx_cons;
ae92e4
+
ae92e4
+	if (bp->tx_cons == hw_cons) {
ae92e4
+		if (bp->tx_cons == bp->tx_prod) {
ae92e4
+			/* Make sure the xmit_mutex lock is unlock */
ae92e4
+			if (pthread_mutex_trylock(&nic->xmit_mutex))
ae92e4
+				LOG_ERR(PFX "qedi tx lock with prod == cons");
ae92e4
+
ae92e4
+			pthread_mutex_unlock(&nic->xmit_mutex);
ae92e4
+			return 0;
ae92e4
+		}
ae92e4
+		return -EAGAIN;
ae92e4
+	}
ae92e4
+
ae92e4
+	LOG_PACKET(PFX "%s: clearing tx interrupt [%d %d]",
ae92e4
+		   nic->log_name, bp->tx_cons, hw_cons);
ae92e4
+	bp->tx_cons = hw_cons;
ae92e4
+
ae92e4
+	/* There is a queued TX packet that needs to be sent out.  The usual
ae92e4
+	 * case is when stack will send an ARP packet out before sending the
ae92e4
+	 * intended packet
ae92e4
+	 */
ae92e4
+	if (nic->tx_packet_queue) {
ae92e4
+		packet_t *pkt;
ae92e4
+		int i;
ae92e4
+
ae92e4
+		LOG_PACKET(PFX "%s: sending queued tx packet", nic->log_name);
ae92e4
+		pkt = nic_dequeue_tx_packet(nic);
ae92e4
+
ae92e4
+		/* Got a TX packet buffer of the TX queue and put it onto
ae92e4
+		 * the hardware
ae92e4
+		 */
ae92e4
+		if (pkt) {
ae92e4
+			qedi_prepare_xmit_packet(nic, pkt->nic_iface, pkt);
ae92e4
+
ae92e4
+			qedi_start_xmit(nic, pkt->buf_size,
ae92e4
+					(pkt->nic_iface->vlan_priority << 12) |
ae92e4
+					pkt->nic_iface->vlan_id);
ae92e4
+
ae92e4
+			LOG_PACKET(PFX "%s: transmitted queued packet %d bytes, dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d",
ae92e4
+				   nic->log_name, pkt->buf_size,
ae92e4
+				   bp->tx_cons, bp->tx_prod, bp->tx_bd_prod);
ae92e4
+
ae92e4
+			return 0;
ae92e4
+		}
ae92e4
+
ae92e4
+		/* Try to wait for a TX completion */
ae92e4
+		for (i = 0; i < 15; i++) {
ae92e4
+			struct timespec sleep_req = {.tv_sec = 0,
ae92e4
+				.tv_nsec = 5000000
ae92e4
+			}, sleep_rem;
ae92e4
+
ae92e4
+			hw_cons = uctrl->hw_tx_cons;
ae92e4
+			if (bp->tx_cons != hw_cons) {
ae92e4
+				LOG_PACKET(PFX
ae92e4
+					   "%s: clearing tx interrupt [%d %d]",
ae92e4
+					   nic->log_name, bp->tx_cons, hw_cons);
ae92e4
+				bp->tx_cons = hw_cons;
ae92e4
+
ae92e4
+				break;
ae92e4
+			}
ae92e4
+
ae92e4
+			nanosleep(&sleep_req, &sleep_rem);
ae92e4
+		}
ae92e4
+	}
ae92e4
+
ae92e4
+	pthread_mutex_unlock(&nic->xmit_mutex);
ae92e4
+
ae92e4
+	return 0;
ae92e4
+}
ae92e4
+
ae92e4
+/*******************************************************************************
ae92e4
+ * qedi NIC op's table
ae92e4
+ ******************************************************************************/
ae92e4
+struct nic_ops qedi_op = {
ae92e4
+	.description = "qedi",
ae92e4
+	.open = qedi_open,
ae92e4
+	.close = qedi_close,
ae92e4
+	.write = qedi_write,
ae92e4
+	.get_tx_pkt = qedi_get_tx_pkt,
ae92e4
+	.start_xmit = qedi_start_xmit,
ae92e4
+	.read = qedi_read,
ae92e4
+	.clear_tx_intr = qedi_clear_tx_intr,
ae92e4
+	.handle_iscsi_path_req = cnic_handle_iscsi_path_req,
ae92e4
+
ae92e4
+	.lib_ops = {
ae92e4
+		    .get_library_name = qedi_get_library_name,
ae92e4
+		    .get_library_version = qedi_get_library_version,
ae92e4
+		    .get_build_date = qedi_get_build_date,
ae92e4
+		    .get_transport_name = qedi_get_transport_name,
ae92e4
+		    .get_uio_name = qedi_get_uio_name,
ae92e4
+		    },
ae92e4
+};
ae92e4
diff --git a/iscsiuio/src/unix/libs/qedi.h b/iscsiuio/src/unix/libs/qedi.h
ae92e4
new file mode 100644
ae92e4
index 000000000000..7e0140adb2ba
ae92e4
--- /dev/null
ae92e4
+++ b/iscsiuio/src/unix/libs/qedi.h
ae92e4
@@ -0,0 +1,159 @@
ae92e4
+/*
ae92e4
+ * Copyright (c) 2016, Cavium Inc.
ae92e4
+ *
ae92e4
+ * All rights reserved.
ae92e4
+ *
ae92e4
+ * Redistribution and use in source and binary forms, with or without
ae92e4
+ * modification, are permitted provided that the following conditions
ae92e4
+ * are met:
ae92e4
+ * 1. Redistributions of source code must retain the above copyright
ae92e4
+ *    notice, this list of conditions and the following disclaimer.
ae92e4
+ * 2. Redistributions in binary form must reproduce the above copyright
ae92e4
+ *    notice, this list of conditions and the following disclaimer in the
ae92e4
+ *    documentation and/or other materials provided with the distribution.
ae92e4
+ * 3. All advertising materials mentioning features or use of this software
ae92e4
+ *    must display the following acknowledgement:
ae92e4
+ *      This product includes software developed by Adam Dunkels.
ae92e4
+ * 4. The name of the author may not be used to endorse or promote
ae92e4
+ *    products derived from this software without specific prior
ae92e4
+ *    written permission.
ae92e4
+ *
ae92e4
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
ae92e4
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
ae92e4
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ae92e4
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
ae92e4
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
ae92e4
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
ae92e4
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
ae92e4
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
ae92e4
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
ae92e4
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
ae92e4
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ae92e4
+ *
ae92e4
+ * qedi.h - qedi user space driver
ae92e4
+ *
ae92e4
+ */
ae92e4
+#ifndef __QEDI_H__
ae92e4
+#define __QEDI_H__
ae92e4
+
ae92e4
+#include "nic.h"
ae92e4
+
ae92e4
+#define RX_RING_SIZE	15
ae92e4
+#define PKT_BUF_SIZE 0X400
ae92e4
+#define QEDI_PAGE_SIZE 4096
ae92e4
+
ae92e4
+#define QEDI_UNKNOWN_MAJOR_VERSION	-1
ae92e4
+#define QEDI_UNKNOWN_MINOR_VERSION	-1
ae92e4
+#define QEDI_UNKNOWN_SUB_MINOR_VERSION	-1
ae92e4
+struct qedi_driver_version {
ae92e4
+	uint16_t major;
ae92e4
+	uint16_t minor;
ae92e4
+	uint16_t sub_minor;
ae92e4
+};
ae92e4
+
ae92e4
+#define QEDI_UCTRL_MAP_REG	0
ae92e4
+#define QEDI_RING_MAP_REG	1
ae92e4
+#define QEDI_BUF_MAP_REG	2
ae92e4
+#define UIO_ATTR_TMPL	"/sys/class/uio/uio%u/maps/map%u/%s"
ae92e4
+#define UIO_ADDR_TMPL	"/sys/class/uio/uio%u/maps/map%u/addr"
ae92e4
+#define UIO_OFFSET_TMPL	"/sys/class/uio/uio%u/maps/map%u/offset"
ae92e4
+#define UIO_SIZE_TMPL	"/sys/class/uio/uio%u/maps/map%u/size"
ae92e4
+
ae92e4
+struct qedi_uio_ctrl {
ae92e4
+	/* meta data */
ae92e4
+	__u32 uio_hsi_version;
ae92e4
+
ae92e4
+	/* user writes */
ae92e4
+	__u32 host_tx_prod;
ae92e4
+	__u32 host_rx_cons;
ae92e4
+	__u32 host_rx_bd_cons;
ae92e4
+	__u32 host_tx_pkt_len;
ae92e4
+	__u32 host_rx_cons_cnt;
ae92e4
+
ae92e4
+	/* driver writes */
ae92e4
+	__u32 hw_tx_cons;
ae92e4
+	__u32 hw_rx_prod;
ae92e4
+	__u32 hw_rx_bd_prod;
ae92e4
+	__u32 hw_rx_prod_cnt;
ae92e4
+
ae92e4
+	/* other */
ae92e4
+	__u8 mac_addr[6];
ae92e4
+	__u8 reserve[2];
ae92e4
+};
ae92e4
+
ae92e4
+struct qedi_rx_bd {
ae92e4
+	__u32 rx_pkt_index;
ae92e4
+	__u32 rx_pkt_len;
ae92e4
+	__u16 vlan_id;
ae92e4
+};
ae92e4
+
ae92e4
+#define QEDI_RX_DESC_CNT	(QEDI_PAGE_SIZE / sizeof(struct qedi_rx_bd))
ae92e4
+#define QEDI_MAX_RX_DESC_CNT	(QEDI_RX_DESC_CNT - 1)
ae92e4
+#define QEDI_NUM_RX_BD		(QEDI_RX_DESC_CNT * 1)
ae92e4
+#define QEDI_MAX_RX_BD		(QEDI_NUM_RX_BD - 1)
ae92e4
+
ae92e4
+#define QEDI_NEXT_RX_IDX(x)	((((x) & (QEDI_MAX_RX_DESC_CNT)) ==     \
ae92e4
+				  (QEDI_MAX_RX_DESC_CNT - 1)) ?         \
ae92e4
+				 (x) + 2 : (x) + 1)
ae92e4
+
ae92e4
+#define QEDI_PATH_HANDLE	0xFE0000000
ae92e4
+
ae92e4
+typedef struct qedi {
ae92e4
+	nic_t *parent;
ae92e4
+
ae92e4
+	struct qedi_driver_version version;
ae92e4
+
ae92e4
+	uint16_t flags;
ae92e4
+#define CNIC_UIO_UNITIALIZED		0x0001
ae92e4
+#define CNIC_UIO_INITIALIZED		0x0002
ae92e4
+#define CNIC_UIO_ENABLED		0x0004
ae92e4
+#define CNIC_UIO_DISABLED		0x0008
ae92e4
+#define CNIC_UIO_IPv6_ENABLED		0x0010
ae92e4
+#define CNIC_UIO_ADDED_MULICAST		0x0020
ae92e4
+#define CNIC_UIO_MSIX_ENABLED		0x0200
ae92e4
+#define CNIC_UIO_TX_HAS_SENT		0x0400
ae92e4
+#define QEDI_OPENED			0x0800
ae92e4
+
ae92e4
+	__u32 chip_id;
ae92e4
+	int func;
ae92e4
+	int port;
ae92e4
+	int pfid;
ae92e4
+	__u32 cid;
ae92e4
+	__u32 client_id;
ae92e4
+
ae92e4
+	__u32 tx_prod;
ae92e4
+	__u32 tx_bd_prod;
ae92e4
+	__u32 tx_cons;
ae92e4
+	__u8 tx_vlan_tag_bit;
ae92e4
+
ae92e4
+	__u32 rx_prod;
ae92e4
+	__u32 rx_bd_prod;
ae92e4
+	__u32 rx_cons;
ae92e4
+	__u32 rx_bd_cons;
ae92e4
+	__u32 rx_hw_prod;
ae92e4
+
ae92e4
+	 __u32 (*get_rx_cons)(struct qedi *);
ae92e4
+	 __u32 (*get_tx_cons)(struct qedi *);
ae92e4
+
ae92e4
+	/* RX ring parameters */
ae92e4
+	uint32_t rx_ring_size;
ae92e4
+	uint32_t rx_buffer_size;
ae92e4
+
ae92e4
+	void *bufs; /* Pointer to the mapped buffer space */
ae92e4
+	void *uctrl_map; /* UIO control structure */
ae92e4
+	uint32_t uctrl_map_offset; /* UIO control structure mmap offset */
ae92e4
+
ae92e4
+	uint32_t rx_index;
ae92e4
+	void *rx_comp_ring;
ae92e4
+	void **rx_pkt_ring;
ae92e4
+	void *tx_pkt;
ae92e4
+	void *rx_pkts;
ae92e4
+} qedi_t;
ae92e4
+
ae92e4
+/******************************************************************************
ae92e4
+ *  qedi Function Declarations
ae92e4
+ ******************************************************************************/
ae92e4
+void qedi_start_xmit(nic_t *nic, size_t len, u16_t vlan_id);
ae92e4
+struct nic_ops *qedi_get_ops();
ae92e4
+
ae92e4
+#endif /* __QEDI_H__ */
ae92e4
diff --git a/iscsiuio/src/unix/nic.c b/iscsiuio/src/unix/nic.c
ae92e4
index 8825f00b7216..a5f714a91923 100644
ae92e4
--- a/iscsiuio/src/unix/nic.c
ae92e4
+++ b/iscsiuio/src/unix/nic.c
ae92e4
@@ -65,6 +65,7 @@
ae92e4
 
ae92e4
 #include "bnx2.h"
ae92e4
 #include "bnx2x.h"
ae92e4
+#include "qedi.h"
ae92e4
 #include "ipv6.h"
ae92e4
 
ae92e4
 /******************************************************************************
ae92e4
@@ -180,7 +181,7 @@ error:
ae92e4
 }
ae92e4
 
ae92e4
 static struct nic_ops *(*nic_get_ops[]) () = {
ae92e4
-bnx2_get_ops, bnx2x_get_ops,};
ae92e4
+bnx2_get_ops, bnx2x_get_ops, qedi_get_ops};
ae92e4
 
ae92e4
 int load_all_nic_libraries()
ae92e4
 {
ae92e4
@@ -404,6 +405,7 @@ nic_t *nic_init()
ae92e4
 	memset(nic, 0, sizeof(*nic));
ae92e4
 	nic->uio_minor = -1;
ae92e4
 	nic->fd = INVALID_FD;
ae92e4
+	nic->host_no = INVALID_HOST_NO;
ae92e4
 	nic->next = NULL;
ae92e4
 	nic->thread = INVALID_THREAD;
ae92e4
 	nic->enable_thread = INVALID_THREAD;
ae92e4
@@ -1070,6 +1072,8 @@ int process_packets(nic_t *nic,
ae92e4
 		}
ae92e4
 nic_iface_present:
ae92e4
 		pkt->nic_iface = nic_iface;
ae92e4
+		LOG_DEBUG(PFX "%s: found nic iface, type=0x%x, bufsize=%d",
ae92e4
+			  nic->log_name, type, pkt->buf_size);
ae92e4
 
ae92e4
 		ustack = &nic_iface->ustack;
ae92e4
 
ae92e4
diff --git a/iscsiuio/src/unix/nic.h b/iscsiuio/src/unix/nic.h
ae92e4
index ec157815a375..2c41e6e3c25a 100644
ae92e4
--- a/iscsiuio/src/unix/nic.h
ae92e4
+++ b/iscsiuio/src/unix/nic.h
ae92e4
@@ -334,6 +334,7 @@ typedef struct nic {
ae92e4
 
ae92e4
 	/* The thread used to perform ping */
ae92e4
 	pthread_t ping_thread;
ae92e4
+	uint64_t transport_handle;
ae92e4
 } nic_t;
ae92e4
 
ae92e4
 /******************************************************************************
ae92e4
diff --git a/iscsiuio/src/unix/nic_utils.c b/iscsiuio/src/unix/nic_utils.c
ae92e4
index 0daffd2fcb6d..6e580f862eea 100644
ae92e4
--- a/iscsiuio/src/unix/nic_utils.c
ae92e4
+++ b/iscsiuio/src/unix/nic_utils.c
ae92e4
@@ -81,6 +81,10 @@ static const char iscsi_host_path_netdev_template[] =
ae92e4
 	"/sys/class/iscsi_host/host%d/netdev";
ae92e4
 static const char cnic_uio_sysfs_resc_template[] =
ae92e4
 	"/sys/class/uio/uio%i/device/resource%i";
ae92e4
+static const char iscsi_transport_handle_template[] =
ae92e4
+	"/sys/class/iscsi_transport/%s/handle";
ae92e4
+static const char eth_pfx[] = "eth";
ae92e4
+static const char host_pfx[] = "host";
ae92e4
 
ae92e4
 /**
ae92e4
  *  manually_trigger_uio_event() - If the uio file node doesn't exist then
ae92e4
@@ -250,6 +254,7 @@ int nic_discover_iscsi_hosts()
ae92e4
 				strncpy(nic->eth_device_name, raw, raw_size);
ae92e4
 				nic->config_device_name = nic->eth_device_name;
ae92e4
 				nic->log_name = nic->eth_device_name;
ae92e4
+				nic->host_no = host_no;
ae92e4
 
ae92e4
 				if (nic_fill_name(nic) != 0) {
ae92e4
 					free(nic);
ae92e4
@@ -557,6 +562,102 @@ error:
ae92e4
 }
ae92e4
 
ae92e4
 /**
ae92e4
+ *  from_uio_find_associated_host() - Given the uio minor number
ae92e4
+ *      this function will try to find the assoicated iscsi host
ae92e4
+ *  @param uio_minor - minor number of the UIO device
ae92e4
+ *  @param name - char buffer which will be filled if successful
ae92e4
+ *  @param name_size - size of the name buffer
ae92e4
+ *  @return >0 minor number <0 an error
ae92e4
+ */
ae92e4
+static int from_uio_find_associated_host(nic_t *nic, int uio_minor,
ae92e4
+					 char *name, size_t name_size)
ae92e4
+{
ae92e4
+	char *path;
ae92e4
+	int rc;
ae92e4
+	int count;
ae92e4
+	struct dirent **files;
ae92e4
+	char *parsed_name;
ae92e4
+	int i;
ae92e4
+	int path_iterator;
ae92e4
+	char *search_paths[] = { "/sys/class/uio/uio%i/device/" };
ae92e4
+	int path_to[] = { 5, 1 };
ae92e4
+	int (*search_filters[]) (const struct dirent *) = { filter_host_name, };
ae92e4
+	char *(*extract_name[]) (struct dirent **files) = {  extract_none, };
ae92e4
+	int extract_name_offset[] = { 0 };
ae92e4
+
ae92e4
+	path = malloc(PATH_MAX);
ae92e4
+	if (!path) {
ae92e4
+		LOG_ERR(PFX "Could not allocate memory for path");
ae92e4
+		rc = -ENOMEM;
ae92e4
+		goto error;
ae92e4
+	}
ae92e4
+
ae92e4
+	for (path_iterator = 0;
ae92e4
+	     path_iterator < sizeof(search_paths) / sizeof(search_paths[0]);
ae92e4
+	     path_iterator++) {
ae92e4
+		/*  Build the path to determine uio name */
ae92e4
+		rc = sprintf(path, search_paths[path_iterator], uio_minor);
ae92e4
+
ae92e4
+		wait_for_file_node_timed(nic, path, path_to[path_iterator]);
ae92e4
+
ae92e4
+		count = scandir(path, &files,
ae92e4
+				search_filters[path_iterator], alphasort);
ae92e4
+
ae92e4
+		switch (count) {
ae92e4
+		case 1:
ae92e4
+			parsed_name = (*extract_name[path_iterator]) (files);
ae92e4
+			if (!parsed_name) {
ae92e4
+				LOG_WARN(PFX "Couldn't find delimiter in: %s",
ae92e4
+					 files[0]->d_name);
ae92e4
+
ae92e4
+				break;
ae92e4
+			}
ae92e4
+
ae92e4
+			strncpy(name,
ae92e4
+				parsed_name +
ae92e4
+				extract_name_offset[path_iterator], name_size);
ae92e4
+
ae92e4
+			free(files[0]);
ae92e4
+			free(files);
ae92e4
+
ae92e4
+			rc = 0;
ae92e4
+			break;
ae92e4
+
ae92e4
+		case 0:
ae92e4
+			rc = -EINVAL;
ae92e4
+			break;
ae92e4
+
ae92e4
+		case -1:
ae92e4
+			LOG_WARN(PFX "Error when scanning path: %s[%s]",
ae92e4
+				 path, strerror(errno));
ae92e4
+			rc = -EINVAL;
ae92e4
+			break;
ae92e4
+
ae92e4
+		default:
ae92e4
+			LOG_WARN(PFX
ae92e4
+				 "Too many entries when looking for device: %s",
ae92e4
+				 path);
ae92e4
+
ae92e4
+			/*  Cleanup the scandir() call */
ae92e4
+			for (i = 0; i < count; i++)
ae92e4
+				free(files[i]);
ae92e4
+			free(files);
ae92e4
+
ae92e4
+			rc = -EINVAL;
ae92e4
+			break;
ae92e4
+		}
ae92e4
+
ae92e4
+		if (rc == 0)
ae92e4
+			break;
ae92e4
+	}
ae92e4
+
ae92e4
+error:
ae92e4
+	free(path);
ae92e4
+
ae92e4
+	return rc;
ae92e4
+}
ae92e4
+
ae92e4
+/**
ae92e4
  *  filter_uio_name() - This is the callback used by scandir when looking for
ae92e4
  *                      the number of uio entries
ae92e4
  */
ae92e4
@@ -652,10 +753,16 @@ int from_phys_name_find_assoicated_uio_device(nic_t *nic)
ae92e4
 			continue;
ae92e4
 		}
ae92e4
 
ae92e4
-		rc = from_uio_find_associated_eth_device(nic,
ae92e4
-							 uio_minor,
ae92e4
-							 eth_name,
ae92e4
-							 sizeof(eth_name));
ae92e4
+		if (!memcmp(host_pfx, nic->config_device_name,
ae92e4
+			    strlen(host_pfx))) {
ae92e4
+			rc = from_uio_find_associated_host(nic, uio_minor,
ae92e4
+							   eth_name,
ae92e4
+							   sizeof(eth_name));
ae92e4
+		} else {
ae92e4
+			rc = from_uio_find_associated_eth_device(nic, uio_minor,
ae92e4
+								 eth_name,
ae92e4
+								 sizeof(eth_name));
ae92e4
+		}
ae92e4
 		if (rc != 0) {
ae92e4
 			LOG_WARN("uio minor: %d not valid [%D]", uio_minor, rc);
ae92e4
 			continue;
ae92e4
@@ -1124,6 +1231,38 @@ int detemine_initial_uio_events(nic_t *nic, uint32_t *num_of_events)
ae92e4
 
ae92e4
 	rc = 0;
ae92e4
 error:
ae92e4
+	if (raw)
ae92e4
+		free(raw);
ae92e4
+
ae92e4
+	return rc;
ae92e4
+}
ae92e4
+
ae92e4
+int get_iscsi_transport_handle(nic_t *nic, uint64_t *handle)
ae92e4
+{
ae92e4
+	char *raw = NULL;
ae92e4
+	uint32_t raw_size = 0;
ae92e4
+	ssize_t elements_read;
ae92e4
+	char temp_path[sizeof(iscsi_transport_handle_template) + 8];
ae92e4
+	int rc;
ae92e4
+
ae92e4
+	/*  Capture RX buffer size */
ae92e4
+	snprintf(temp_path, sizeof(temp_path),
ae92e4
+		 iscsi_transport_handle_template, nic->library_name);
ae92e4
+
ae92e4
+	rc = capture_file(&raw, &raw_size, temp_path);
ae92e4
+	if (rc != 0)
ae92e4
+		goto error;
ae92e4
+
ae92e4
+	elements_read = sscanf(raw, "%lu", handle);
ae92e4
+	if (elements_read != 1) {
ae92e4
+		LOG_ERR(PFX "%s: Couldn't parse transport handle from %s",
ae92e4
+			nic->log_name, temp_path);
ae92e4
+		rc = -EIO;
ae92e4
+		goto error;
ae92e4
+	}
ae92e4
+
ae92e4
+	rc = 0;
ae92e4
+error:
ae92e4
 	if (raw != NULL)
ae92e4
 		free(raw);
ae92e4
 
ae92e4
diff --git a/iscsiuio/src/unix/nic_utils.h b/iscsiuio/src/unix/nic_utils.h
ae92e4
index d5c1b580f340..e4cf5c13177e 100644
ae92e4
--- a/iscsiuio/src/unix/nic_utils.h
ae92e4
+++ b/iscsiuio/src/unix/nic_utils.h
ae92e4
@@ -99,4 +99,6 @@ void dump_packet_to_log(struct nic_interface *iface,
ae92e4
 int determine_file_size_read(const char *filepath);
ae92e4
 int capture_file(char **raw, uint32_t *raw_size, const char *path);
ae92e4
 
ae92e4
+int get_iscsi_transport_handle(nic_t *nic, uint64_t *handle);
ae92e4
+
ae92e4
 #endif /* __NIC_UTILS_H__ */
ae92e4
diff --git a/iscsiuio/src/unix/options.h b/iscsiuio/src/unix/options.h
ae92e4
index df03255f7a87..63b86357aafa 100644
ae92e4
--- a/iscsiuio/src/unix/options.h
ae92e4
+++ b/iscsiuio/src/unix/options.h
ae92e4
@@ -87,6 +87,7 @@
ae92e4
 
ae92e4
 #define INVALID_FD	-1
ae92e4
 #define INVALID_THREAD	-1
ae92e4
+#define INVALID_HOST_NO	-1
ae92e4
 
ae92e4
 struct options {
ae92e4
 	char debug;
ae92e4
-- 
ae92e4
2.9.3
ae92e4