]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
bnx2i: update to broadcom 2.7.4.1f driver
authorJerry Snitselaar <jerry.snitselaar@oracle.com>
Thu, 8 Nov 2012 17:58:23 +0000 (10:58 -0700)
committerJerry Snitselaar <jerry.snitselaar@oracle.com>
Thu, 8 Nov 2012 17:58:23 +0000 (10:58 -0700)
Move from upstream to broadcom driver.

Signed-off-by: Jerry Snitselaar <jerry.snitselaar@oracle.com>
drivers/scsi/bnx2i/57xx_iscsi_constants.h
drivers/scsi/bnx2i/57xx_iscsi_hsi.h
drivers/scsi/bnx2i/bnx2i.h
drivers/scsi/bnx2i/bnx2i_compat.h [new file with mode: 0644]
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/bnx2i/bnx2i_init.c
drivers/scsi/bnx2i/bnx2i_ioctl.h [new file with mode: 0644]
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/bnx2i/bnx2i_sysfs.c

index 25093a04123b2284b281a0bb169d625e923bd757..09c2c102109048529cf28027db800d5df21ffd58 100644 (file)
 /* additional LOM specific iSCSI license not installed */
 #define ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED              (0x51)
 
-#define ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY                          (0x80)
+/* Driver internal error code */
+#define ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY                           (0x80)
 #define ISCSI_KCQE_COMPLETION_STATUS_PARITY_ERR                         (0x81)
 
 /* SQ/RQ/CQ DB structure sizes */
index dc0a08e69c8213a9f173236617ff973c3f924264..1f3f73117a07738c21c521b709849cf0b84e28fb 100644 (file)
@@ -267,7 +267,13 @@ struct bnx2i_cmd_request {
  * task statistics for write response
  */
 struct bnx2i_write_resp_task_stat {
-       u32 num_data_ins;
+#if defined(__BIG_ENDIAN)
+       u16 num_r2ts;
+       u16 num_data_outs;
+#elif defined(__LITTLE_ENDIAN)
+       u16 num_data_outs;
+       u16 num_r2ts;
+#endif
 };
 
 /*
@@ -275,11 +281,11 @@ struct bnx2i_write_resp_task_stat {
  */
 struct bnx2i_read_resp_task_stat {
 #if defined(__BIG_ENDIAN)
-       u16 num_data_outs;
-       u16 num_r2ts;
+       u16 reserved;
+       u16 num_data_ins;
 #elif defined(__LITTLE_ENDIAN)
-       u16 num_r2ts;
-       u16 num_data_outs;
+       u16 num_data_ins;
+       u16 reserved;
 #endif
 };
 
@@ -543,11 +549,11 @@ struct iscsi_kwqe_header {
 struct iscsi_kwqe_init1 {
 #if defined(__BIG_ENDIAN)
        struct iscsi_kwqe_header hdr;
-       u8 reserved0;
+       u8 hsi_version;
        u8 num_cqs;
 #elif defined(__LITTLE_ENDIAN)
        u8 num_cqs;
-       u8 reserved0;
+       u8 hsi_version;
        struct iscsi_kwqe_header hdr;
 #endif
        u32 dummy_buffer_addr_lo;
index 14f086718e2717519b15c883fc16be6c0a525a4e..d76b9c64c00d1218df10618f19a5b040d8f44855 100644 (file)
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi.h>
-#include <scsi/iscsi_proto.h>
-#include <scsi/libiscsi.h>
-#include <scsi/scsi_transport_iscsi.h>
+
+#include "bnx2i_compat.h"
 
 #include "../../net/cnic_if.h"
+
 #include "57xx_iscsi_hsi.h"
 #include "57xx_iscsi_constants.h"
 
+#include "../../net/bnx2x/bnx2x_mfw_req.h"
+
 #define BNX2_ISCSI_DRIVER_NAME         "bnx2i"
+#ifndef PCI_DEVICE_ID_NX2_5709
+#define PCI_DEVICE_ID_NX2_5709         0x1639
+#endif
+#ifndef PCI_DEVICE_ID_NX2_5709S
+#define PCI_DEVICE_ID_NX2_5709S                0x163a
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57710
+#define PCI_DEVICE_ID_NX2_57710                0x164e
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57711
+#define PCI_DEVICE_ID_NX2_57711                0x164f
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57711E
+#define PCI_DEVICE_ID_NX2_57711E       0x1650
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57712
+#define PCI_DEVICE_ID_NX2_57712                0x1662
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57712_MF
+#define PCI_DEVICE_ID_NX2_57712_MF     0x1663
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57712_VF
+#define PCI_DEVICE_ID_NX2_57712_VF     0x166f
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57800
+#define PCI_DEVICE_ID_NX2_57800                0x168a
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57800_MF
+#define PCI_DEVICE_ID_NX2_57800_MF     0x16a5
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57800_VF
+#define PCI_DEVICE_ID_NX2_57800_VF     0x16a9
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57810
+#define PCI_DEVICE_ID_NX2_57810                0x168e
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57810_MF
+#define PCI_DEVICE_ID_NX2_57810_MF     0x16ae
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57810_VF
+#define PCI_DEVICE_ID_NX2_57810_VF     0x16af
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57840
+#define PCI_DEVICE_ID_NX2_57840                0x168d
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57840_MF
+#define PCI_DEVICE_ID_NX2_57840_MF     0x16ab
+#endif
+
+#ifndef PCI_DEVICE_ID_NX2_57840_VF
+#define PCI_DEVICE_ID_NX2_57840_VF     0x16ad
+#endif
 
 #define BNX2I_MAX_ADAPTERS             8
 
 #define REG_WR(__hba, offset, val)                     \
                writel(val, __hba->regview + offset)
 
+#ifdef CONFIG_32BIT
+#define GET_STATS_64(__hba, dst, field)                                \
+       do {                                                    \
+               spin_lock_bh(&__hba->stat_lock);                \
+               dst->field##_lo = __hba->stats.field##_lo;      \
+               dst->field##_hi = __hba->stats.field##_hi;      \
+               spin_unlock_bh(&__hba->stat_lock);              \
+       } while (0)
+
+#define ADD_STATS_64(__hba, field, len)                                \
+       do {                                                    \
+               if (spin_trylock(&__hba->stat_lock)) {          \
+                       if (__hba->stats.field##_lo + len <     \
+                           __hba->stats.field##_lo)            \
+                               __hba->stats.field##_hi++;      \
+                       __hba->stats.field##_lo += len;         \
+                       spin_unlock(&__hba->stat_lock);         \
+               }                                               \
+       } while (0)
+
+#else
+#define GET_STATS_64(__hba, dst, field)                                \
+       do {                                                    \
+               u64 val, *out;                                  \
+                                                               \
+               val = __hba->bnx2i_stats.field;                 \
+               out = (u64 *)&__hba->stats.field##_lo;          \
+               *out = cpu_to_le64(val);                        \
+               out = (u64 *)&dst->field##_lo;                  \
+               *out = cpu_to_le64(val);                        \
+       } while (0)
+
+#define ADD_STATS_64(__hba, field, len)                                \
+       __hba->bnx2i_stats.field += len
+
+#endif
 
 /**
  * struct generic_pdu_resc - login pdu resource structure
@@ -212,6 +317,7 @@ struct io_bdt {
  * @io_tbl:             buffer descriptor (BD) table
  * @bd_tbl_dma:         buffer descriptor (BD) table's dma address
  * @req:                bnx2i specific command request struct
+ * @cpu:                CPU number of the specific cmd; for completion purposes
  */
 struct bnx2i_cmd {
        struct iscsi_hdr hdr;
@@ -221,6 +327,7 @@ struct bnx2i_cmd {
        struct io_bdt io_tbl;
        dma_addr_t bd_tbl_dma;
        struct bnx2i_cmd_request req;
+       u32 cpu;
 };
 
 
@@ -235,6 +342,7 @@ struct bnx2i_cmd {
  * @gen_pdu:               login/nopout/logout pdu resources
  * @violation_notified:    bit mask used to track iscsi error/warning messages
  *                         already printed out
+ * @prev_sess_state:       keeps track of the connections previous session state
  * @work_cnt:              keeps track of the number of outstanding work
  *
  * iSCSI connection structure
@@ -260,11 +368,12 @@ struct bnx2i_conn {
        struct generic_pdu_resc gen_pdu;
        u64 violation_notified;
 
+       int prev_sess_state;
+
        atomic_t work_cnt;
 };
 
 
-
 /**
  * struct iscsi_cid_queue - Per adapter iscsi cid queue
  *
@@ -288,6 +397,29 @@ struct iscsi_cid_queue {
        struct bnx2i_conn **conn_cid_tbl;
 };
 
+struct bnx2i_stats_info {
+       u64 rx_pdus;
+       u64 rx_bytes;
+       u64 tx_pdus;
+       u64 tx_bytes;
+};
+
+struct iscsi_login_stats_info {
+       u32 successful_logins;                  /* Total login successes */
+       u32 login_failures;                     /* Total login failures */
+       u32 login_negotiation_failures;         /* Text negotiation failed */
+       u32 login_authentication_failures;      /* login Authentication failed */
+       u32 login_redirect_responses;           /* Target redirects to another portal */
+       u32 connection_timeouts;                /* TCP connection timeouts */
+       u32 session_failures;                   /* Errors resulting in sess recovery */
+       u32 digest_errors;                      /* Errors resulting in digest errors */
+};
+
+struct bnx2i_iface {
+       struct list_head link;
+       struct iscsi_iface *iface;
+};
+
 /**
  * struct bnx2i_hba - bnx2i adapter structure
  *
@@ -306,6 +438,11 @@ struct iscsi_cid_queue {
  * @max_sqes:              SQ size
  * @max_rqes:              RQ size
  * @max_cqes:              CQ size
+ * @err_rec_task:          error handling worker
+ * @conn_recov_list:       conn list which are queued for recovery
+ * @conn_recov_prod_idx:   producer index to manage conn recovery list
+ * @conn_recov_cons_idx:   producer index to manage conn recovery list
+ * @conn_recov_max_idx:    max index to manage conn recovery list
  * @num_ccell:             number of command cells per connection
  * @ofld_conns_active:     active connection list
  * @eh_wait:               wait queue for the endpoint to shutdown
@@ -341,6 +478,11 @@ struct iscsi_cid_queue {
  * @ctx_ccell_tasks:       captures number of ccells and tasks supported by
  *                         currently offloaded connection, used to decode
  *                         context memory
+ * @stat_lock:             statistic lock to maintain coherency
+ * @stats:                 iSCSI statistic structure memory
+ * @login_stats:           iSCSI login statistic structure memory
+ * @iface_ipv4_list:       bnx2i_iface struct list for IPv4
+ * @iface_ipv6_list:       bnx2i_iface struct list for IPv6
  *
  * Adapter Data Structure
  */
@@ -378,6 +520,13 @@ struct bnx2i_hba {
        u32 max_sqes;
        u32 max_rqes;
        u32 max_cqes;
+
+       struct work_struct err_rec_task;
+       struct iscsi_conn **conn_recov_list;
+       int conn_recov_prod_idx;
+       int conn_recov_cons_idx;
+       int conn_recov_max_idx;
+
        u32 num_ccell;
 
        int ofld_conns_active;
@@ -405,6 +554,7 @@ struct bnx2i_hba {
        int hba_shutdown_tmo;
        int conn_teardown_tmo;
        int conn_ctx_destroy_tmo;
+
        /*
         * PCI related info.
         */
@@ -427,9 +577,20 @@ struct bnx2i_hba {
        u32 num_sess_opened;
        u32 num_conn_opened;
        unsigned int ctx_ccell_tasks;
+
+#ifdef CONFIG_32BIT
+       spinlock_t stat_lock;
+#endif
+       struct bnx2i_stats_info bnx2i_stats;
+       struct iscsi_stats_info stats;
+       struct iscsi_login_stats_info login_stats;
+
+       struct list_head iface_ipv4_list;
+       struct list_head iface_ipv6_list;
 };
 
 
+
 /*******************************************************************************
  *     QP [ SQ / RQ / CQ ] info.
  ******************************************************************************/
@@ -727,8 +888,10 @@ struct bnx2i_percpu_s {
 extern unsigned int error_mask1, error_mask2;
 extern u64 iscsi_error_mask;
 extern unsigned int en_tcp_dack;
+extern unsigned int time_stamps;
 extern unsigned int event_coal_div;
 extern unsigned int event_coal_min;
+extern unsigned int tcp_buf_size;
 
 extern struct scsi_transport_template *bnx2i_scsi_xport_template;
 extern struct iscsi_transport bnx2i_iscsi_transport;
@@ -736,6 +899,8 @@ extern struct cnic_ulp_ops bnx2i_cnic_cb;
 
 extern unsigned int sq_size;
 extern unsigned int rq_size;
+extern unsigned int last_active_tcp_port;
+extern unsigned int cmd_cmpl_per_work;
 
 extern struct device_attribute *bnx2i_dev_attributes[];
 
@@ -750,6 +915,8 @@ extern void bnx2i_ulp_init(struct cnic_dev *dev);
 extern void bnx2i_ulp_exit(struct cnic_dev *dev);
 extern void bnx2i_start(void *handle);
 extern void bnx2i_stop(void *handle);
+extern int bnx2i_get_stats(void *handle);
+
 extern struct bnx2i_hba *get_adapter_list_head(void);
 
 struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba,
@@ -819,4 +986,5 @@ extern int bnx2i_percpu_io_thread(void *arg);
 extern int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
                                       struct bnx2i_conn *bnx2i_conn,
                                       struct cqe *cqe);
+extern void bnx2i_add_stats(u32 *lo, u32 *hi, u32 length);
 #endif
diff --git a/drivers/scsi/bnx2i/bnx2i_compat.h b/drivers/scsi/bnx2i/bnx2i_compat.h
new file mode 100644 (file)
index 0000000..469b847
--- /dev/null
@@ -0,0 +1,217 @@
+/* bnx2i_compat.h: Broadcom NetXtreme II iSCSI compatible header.
+ *
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Eddie Wai (eddie.wai@broadcom.com)
+ */
+
+#ifndef _BNX2I_COMPAT_H_
+#define _BNX2I_COMPAT_H_
+
+/* Common */
+#define __RHELS_DISTRO__       \
+       (defined(__RHELS_DISTRO_5__) || defined(__RHELS_DISTRO_6__))
+
+#define __DISTRO__             \
+       (defined(__SLES_DISTRO__) || defined(__RHELS_DISTRO__))
+
+#if (defined(_EP_CONNECT_IFACE_NUM_))
+#define bnx2i_ep_connect(shost, dst_addr, non_blocking, iface_num) \
+       bnx2i_ep_connect(shost, dst_addr, non_blocking, iface_num)
+
+#define        bnx2i_offload_mesg(shost, transport, msg_type, buf, buflen, iface_num) \
+       iscsi_offload_mesg(shost, transport, msg_type, buf, buflen, iface_num)
+#else
+#define bnx2i_ep_connect(shost, dst_addr, non_blocking, iface_num) \
+       bnx2i_ep_connect(shost, dst_addr, non_blocking)
+
+#define        bnx2i_offload_mesg(shost, transport, msg_type, buf, buflen, iface_num) \
+       iscsi_offload_mesg(shost, transport, msg_type, buf, buflen)
+#endif
+
+
+#if (defined(__RHELS_DISTRO_5__))
+/********************************* RHEL 5.X ***********************************/
+/* Common for RHEL5 */
+#include <scsi/iscsi_if2.h>
+#include <scsi/iscsi_proto2.h>
+#include <scsi/scsi_transport_iscsi2.h>
+#include <scsi/libiscsi2.h>
+
+#define iscsi_create_endpoint(a) iscsi2_create_endpoint(a)
+#define iscsi_destroy_endpoint(a) iscsi2_destroy_endpoint(a)
+#define iscsi_session_failure(a,b) iscsi2_session_failure(a,b)
+#define iscsi_host_alloc(a,b,c) iscsi2_host_alloc(a,b,c)
+#define iscsi_host_add(a,b) iscsi2_host_add(a,b)
+#define iscsi_host_for_each_session(a,b) iscsi2_host_for_each_session(a,b)
+#define iscsi_host_remove(a) iscsi2_host_remove(a)
+#define iscsi_host_free(a) iscsi2_host_free(a)
+#if (__RHELS_DISTRO_5__ > 0x0504)
+#define iscsi_session_setup(a,b,c,d,e,f,g) iscsi2_session_setup(a,b,c,d,e,f,g)
+#else
+#define iscsi_session_setup(a,b,c,d,e,f,g) iscsi2_session_setup(a,b,c,e,f,g)
+#endif
+#define iscsi_session_teardown(a) iscsi2_session_teardown(a)
+#define iscsi_session_recovery_timedout iscsi2_session_recovery_timedout
+#define iscsi_session_get_param iscsi2_session_get_param
+#define iscsi_conn_setup(a,b,c) iscsi2_conn_setup(a,b,c)
+#define iscsi_conn_bind(a,b,c) iscsi2_conn_bind(a,b,c)
+#define iscsi_conn_start(a) iscsi2_conn_start(a)
+#define iscsi_conn_send_pdu iscsi2_conn_send_pdu
+#define iscsi_conn_stop iscsi2_conn_stop
+#define iscsi_conn_failure(a,b) iscsi2_conn_failure(a,b)
+#define iscsi_conn_teardown(a) iscsi2_conn_teardown(a)
+#define iscsi_conn_error_event(a,b) iscsi2_conn_error_event(a,b)
+#define iscsi_lookup_endpoint(a) iscsi2_lookup_endpoint(a)
+#define iscsi_conn_get_param(a,b,c) iscsi2_conn_get_param(a,b,c)
+#define iscsi_host_get_param(a,b,c) iscsi2_host_get_param(a,b,c)
+#define iscsi_host_for_each_session(a,b) iscsi2_host_for_each_session(a,b)
+#define iscsi_register_transport(a) iscsi2_register_transport(a)
+#define iscsi_unregister_transport(a) iscsi2_unregister_transport(a)
+
+/* TODO: Setting the ISCSI_SUSPEND_BIT w/o bh lock! */
+#define iscsi_suspend_queue(a) iscsi2_suspend_tx(a)
+
+#define iscsi_queuecommand iscsi2_queuecommand
+#define iscsi_eh_abort iscsi2_eh_abort
+#define iscsi_eh_device_reset iscsi2_eh_device_reset
+#define iscsi_change_queue_depth iscsi2_change_queue_depth
+
+#define iscsi_set_param iscsi2_set_param
+
+#define __iscsi_complete_pdu(a,b,c,d) __iscsi2_complete_pdu(a,b,c,d)
+#define iscsi_put_task(a) iscsi2_put_task(a)
+
+static inline ssize_t sysfs_format_mac(char *buf, const unsigned char *addr,
+                                      int len)
+{
+       int i;
+       char *cp = buf;
+
+       for (i = 0; i < len; i++)
+               cp += sprintf(cp, "%02x%c", addr[i],
+                             i == (len - 1) ? '\n' : ':');
+       return cp - buf;
+}
+
+#define FORMAT_IP(buf, fstr, src, len)                         \
+       do {                                                    \
+               u8 *ip = (u8 *)&src[0];                         \
+               len = sprintf(buf, "%d.%d.%d.%d",               \
+                             ip[0], ip[1], ip[2], ip[3]);      \
+       } while (0)
+
+#define FORMAT_IP6(buf, fstr, src, len)                                \
+       do {                                                    \
+               u16 *ip = (u16 *)&src[0];                       \
+               len = sprintf(buf, "%04x:%04x:%04x:%04x:"       \
+                                  "%04x:%04x:%04x:%04x\n",     \
+                                  htons(ip[0]), htons(ip[1]),  \
+                                  htons(ip[2]), htons(ip[3]),  \
+                                  htons(ip[4]), htons(ip[5]),  \
+                                  htons(ip[6]), htons(ip[7])); \
+       } while (0)
+
+#define scsi_for_each_sg(cmd, sg, nseg, __i)                    \
+        for (__i = 0, sg = scsi_sglist(cmd); __i < (nseg); __i++, (sg)++)
+
+#define set_unfreezable(cur)           \
+        cur->flags |= PF_NOFREEZE;
+
+#define kthread_create_on_node(io_thread, arg, node, str, cpu) \
+       kthread_create(io_thread, arg, str, cpu)
+
+/* RHEL5.x Version Specifics */
+
+#if (__RHELS_DISTRO_5__ < 0x0508)
+#define rounddown_pow_of_two(n)        (roundup_pow_of_two(n) << 1)
+#endif
+
+/* End of __RHELS_DISTRO_5__ */
+
+
+#elif (defined(__RHELS_DISTRO_6__))
+/********************************* RHEL 6.X ***********************************/
+/* Common for RHEL6 */
+#include <scsi/iscsi_if.h>
+#include <scsi/iscsi_proto.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/libiscsi.h>
+
+#define FORMAT_IP(buf, fstr, src, len)         \
+       do {                                    \
+               len = sprintf(buf, fstr, src);  \
+       } while (0)
+
+#define FORMAT_IP6(buf, fstr, src, len) FORMAT_IP(buf, fstr, src, len)
+
+#define kthread_create_on_node(io_thread, arg, node, str, cpu) \
+       kthread_create(io_thread, arg, str, cpu)
+
+/* RHEL6.X Version Specifics */
+#define set_unfreezable(cur)
+
+/* End of __RHELS_DISTRO_6__ */
+
+
+#elif (defined(__SLES_DISTRO__))
+/********************************* SLES11SPX **********************************/
+/* Common for SLES11 */
+#include <scsi/iscsi_if.h>
+#include <scsi/iscsi_proto.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/libiscsi.h>
+
+#define FORMAT_IP(buf, fstr, src, len)         \
+       do {                                    \
+               len = sprintf(buf, fstr, src);  \
+       } while (0)
+
+#define FORMAT_IP6(buf, fstr, src, len) FORMAT_IP(buf, fstr, src, len)
+
+#define kthread_create_on_node(io_thread, arg, node, str, cpu) \
+       kthread_create(io_thread, arg, str, cpu)
+
+#if (__SLES_DISTRO__ < 0x1102)
+/* SLES11sp1 specific */
+#define set_unfreezable(cur)           \
+        cur->flags |= PF_NOFREEZE;
+#else
+/* SLES11sp2+ specific */
+#define iscsi_cmd      iscsi_scsi_req
+#define iscsi_cmd_rsp  iscsi_scsi_rsp
+#define iscsi_login    iscsi_login_req
+
+#define set_unfreezable(cur)
+#endif
+
+/* End of __SLES_DISTRO__ */
+
+#else /* Upstream kernel */
+/********************************* Upstream **********************************/
+/* Common for all upstream kernels */
+#include <scsi/iscsi_if.h>
+#include <scsi/iscsi_proto.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/libiscsi.h>
+
+#define FORMAT_IP(buf, fstr, src, len)         \
+       do {                                    \
+               len = sprintf(buf, fstr, src);  \
+       } while (0)
+
+#define FORMAT_IP6(buf, fstr, src, len) FORMAT_IP(buf, fstr, src, len)
+
+#define kthread_create_on_node(io_thread, arg, node, str, cpu) \
+       kthread_create(io_thread, arg, str, cpu)
+
+#define set_unfreezable(cur)
+
+#endif /* End of Upstream kernel */
+
+
+#endif /* _BNX2I_COMPAT_H_ */
index 970d184ecb9a1123cde40937e62e9c98e270eb0e..8d451bf54a216d53c9978fb2ab979eddb833754d 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/gfp.h>
 #include <scsi/scsi_tcq.h>
-#include <scsi/libiscsi.h>
 #include "bnx2i.h"
 
 DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
@@ -551,7 +550,7 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
 
        nopout_wqe->op_code = nopout_hdr->opcode;
        nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL;
-       memcpy(nopout_wqe->lun, &nopout_hdr->lun, 8);
+       memcpy(nopout_wqe->lun, &nopout_hdr->lun, sizeof(struct scsi_lun));
 
        if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
                u32 tmp = nopout_wqe->lun[0];
@@ -657,8 +656,11 @@ void bnx2i_update_iscsi_conn(struct iscsi_conn *conn)
        /* 5771x requires conn context id to be passed as is */
        if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_conn->ep->hba->cnic_dev_type))
                update_wqe->context_id = bnx2i_conn->ep->ep_cid;
-       else
+       else {
                update_wqe->context_id = (bnx2i_conn->ep->ep_cid >> 7);
+               /* Added for OOO l5_cid to context cid association */
+               update_wqe->reserved2 = bnx2i_conn->ep->ep_iscsi_cid;
+       }
        update_wqe->conn_flags = 0;
        if (conn->hdrdgst_en)
                update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST;
@@ -1273,7 +1275,6 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
                ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
        if (en_tcp_dack)
                iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
-       iscsi_init.reserved0 = 0;
        iscsi_init.num_cqs = 1;
        iscsi_init.hdr.op_code = ISCSI_KWQE_OPCODE_INIT1;
        iscsi_init.hdr.flags =
@@ -1317,7 +1318,7 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
                (1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN));
        if (error_mask1) {
                iscsi_init2.error_bit_map[0] = error_mask1;
-               mask64 &= (u32)(~mask64);
+               mask64 ^= (u32) mask64;
                mask64 |= error_mask1;
        } else
                iscsi_init2.error_bit_map[0] = (u32) mask64;
@@ -1353,6 +1354,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
                                struct cqe *cqe)
 {
        struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+       struct bnx2i_hba *hba = bnx2i_conn->hba;
        struct bnx2i_cmd_response *resp_cqe;
        struct bnx2i_cmd *bnx2i_cmd;
        struct iscsi_task *task;
@@ -1370,16 +1372,26 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
 
        if (bnx2i_cmd->req.op_attr & ISCSI_CMD_REQUEST_READ) {
                conn->datain_pdus_cnt +=
-                       resp_cqe->task_stat.read_stat.num_data_outs;
+                       resp_cqe->task_stat.read_stat.num_data_ins;
                conn->rxdata_octets +=
                        bnx2i_cmd->req.total_data_transfer_length;
+               ADD_STATS_64(hba, rx_pdus,
+                            resp_cqe->task_stat.read_stat.num_data_ins);
+               ADD_STATS_64(hba, rx_bytes,
+                            bnx2i_cmd->req.total_data_transfer_length);
        } else {
                conn->dataout_pdus_cnt +=
-                       resp_cqe->task_stat.read_stat.num_data_outs;
+                       resp_cqe->task_stat.write_stat.num_data_outs;
                conn->r2t_pdus_cnt +=
-                       resp_cqe->task_stat.read_stat.num_r2ts;
+                       resp_cqe->task_stat.write_stat.num_r2ts;
                conn->txdata_octets +=
                        bnx2i_cmd->req.total_data_transfer_length;
+               ADD_STATS_64(hba, tx_pdus,
+                            resp_cqe->task_stat.write_stat.num_data_outs);
+               ADD_STATS_64(hba, tx_bytes,
+                            bnx2i_cmd->req.total_data_transfer_length);
+               ADD_STATS_64(hba, rx_pdus,
+                            resp_cqe->task_stat.write_stat.num_r2ts);
        }
        bnx2i_iscsi_unmap_sg_list(bnx2i_cmd);
 
@@ -1426,6 +1438,45 @@ fail:
 }
 
 
+static void bnx2i_login_stats(struct bnx2i_hba *hba, u8 status_class,
+                             u8 status_detail)
+{
+       switch (status_class) {
+       case ISCSI_STATUS_CLS_SUCCESS:
+               hba->login_stats.successful_logins++;
+               break;
+       case ISCSI_STATUS_CLS_REDIRECT: 
+               switch (status_detail) {
+               case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP:
+               case ISCSI_LOGIN_STATUS_TGT_MOVED_PERM:
+                       hba->login_stats.login_redirect_responses++;
+                       break;
+               default:
+                       hba->login_stats.login_failures++;
+                       break;
+               }
+               break;
+       case ISCSI_STATUS_CLS_INITIATOR_ERR:
+               hba->login_stats.login_failures++;
+               switch (status_detail) {
+               case ISCSI_LOGIN_STATUS_AUTH_FAILED:
+               case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN:
+                       hba->login_stats.login_authentication_failures++;
+                       break;
+               default:
+                       /* Not sure, but treating all other class2 errors as
+                          login negotiation failure */
+                       hba->login_stats.login_negotiation_failures++;
+                       break;
+               }
+               break;
+       default:
+               hba->login_stats.login_failures++;
+               break;
+       }
+}
+
+
 /**
  * bnx2i_process_login_resp - this function handles iscsi login response
  * @session:           iscsi session pointer
@@ -1470,6 +1521,10 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
        resp_hdr->status_class = login->status_class;
        resp_hdr->status_detail = login->status_detail;
        pld_len = login->data_length;
+
+       bnx2i_login_stats(bnx2i_conn->hba, login->status_class,
+                         login->status_detail);
+
        bnx2i_conn->gen_pdu.resp_wr_ptr =
                                        bnx2i_conn->gen_pdu.resp_buf + pld_len;
 
@@ -1633,7 +1688,6 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
        resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
 
        __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
-
        bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
 done:
        spin_unlock(&session->lock);
@@ -1660,8 +1714,11 @@ static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
        spin_lock(&session->lock);
        task = iscsi_itt_to_task(conn,
                                 nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
-       if (task)
-               __iscsi_put_task(task);
+       if (task) {
+               spin_unlock(&session->lock);
+               iscsi_put_task(task);
+               spin_lock(&session->lock);
+       }
        spin_unlock(&session->lock);
 }
 
@@ -1723,7 +1780,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
                hdr->flags = ISCSI_FLAG_CMD_FINAL;
                hdr->itt = task->hdr->itt;
                hdr->ttt = cpu_to_be32(nop_in->ttt);
-               memcpy(&hdr->lun, nop_in->lun, 8);
+               memcpy(&hdr->lun, nop_in->lun, sizeof(struct scsi_lun));
        }
 done:
        __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
@@ -1766,7 +1823,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session,
        resp_hdr->opcode = async_cqe->op_code;
        resp_hdr->flags = 0x80;
 
-       memcpy(&resp_hdr->lun, async_cqe->lun, 8);
+       memcpy(&resp_hdr->lun, async_cqe->lun, sizeof(struct scsi_lun));
        resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn);
        resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn);
 
@@ -1860,6 +1917,7 @@ int bnx2i_percpu_io_thread(void *arg)
        LIST_HEAD(work_list);
 
        set_user_nice(current, -20);
+       set_unfreezable(current);
 
        while (!kthread_should_stop()) {
                spin_lock_bh(&p->p_work_lock);
@@ -1905,10 +1963,11 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
 {
        struct bnx2i_work *bnx2i_work = NULL;
        struct bnx2i_percpu_s *p = NULL;
+       struct bnx2i_cmd *bnx2i_cmd;
+       //struct scsi_cmnd *sc;
        struct iscsi_task *task;
-       struct scsi_cmnd *sc;
-       int rc = 0;
        int cpu;
+       int rc = 0;
 
        spin_lock(&session->lock);
        task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
@@ -1917,12 +1976,16 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
                spin_unlock(&session->lock);
                return -EINVAL;
        }
+       bnx2i_cmd = task->dd_data;
+       cpu = bnx2i_cmd->cpu;
+       /* Avoid using sc->request->cpu for now as the blk layer has a bug
        sc = task->sc;
-
-       if (!blk_rq_cpu_valid(sc->request))
-               cpu = smp_processor_id();
-       else
+       if (!blk_rq_cpu_valid(sc->request)) {
+               cpu = get_cpu();
+               put_cpu();
+       else
                cpu = sc->request->cpu;
+       */
 
        spin_unlock(&session->lock);
 
@@ -1964,6 +2027,7 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
 {
        struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
+       struct bnx2i_hba *hba = bnx2i_conn->hba;
        struct qp_info *qp;
        struct bnx2i_nop_in_msg *nopin;
        int tgt_async_msg;
@@ -1976,7 +2040,7 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
 
        if (!qp->cq_virt) {
                printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!",
-                       bnx2i_conn->hba->netdev->name);
+                      hba->netdev->name);
                goto out;
        }
        while (1) {
@@ -1990,7 +2054,7 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
                                printk(KERN_ALERT "bnx2i: Unsolicited "
                                        "NOP-In detected for suspended "
                                        "connection dev=%s!\n",
-                                       bnx2i_conn->hba->netdev->name);
+                                       hba->netdev->name);
                                bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
                                goto cqe_out;
                        }
@@ -1998,13 +2062,15 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
                }
                tgt_async_msg = 0;
 
+               /* Rx PDU/data length count */
+
                switch (nopin->op_code) {
                case ISCSI_OP_SCSI_CMD_RSP:
                case ISCSI_OP_SCSI_DATA_IN:
                        /* Run the kthread engine only for data cmds
                           All other cmds will be completed in this bh! */
                        bnx2i_queue_scsi_cmd_resp(session, bnx2i_conn, nopin);
-                       break;
+                       goto done;
                case ISCSI_OP_LOGIN_RSP:
                        bnx2i_process_login_resp(session, bnx2i_conn,
                                                 qp->cq_cons_qe);
@@ -2047,6 +2113,10 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
                        printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
                                          nopin->op_code);
                }
+
+               ADD_STATS_64(hba, rx_pdus, 1);
+               ADD_STATS_64(hba, rx_bytes, nopin->data_length);
+done:
                if (!tgt_async_msg) {
                        if (!atomic_read(&bnx2i_conn->ep->num_active_cmds))
                                printk(KERN_ALERT "bnx2i (%s): no active cmd! "
@@ -2158,8 +2228,26 @@ static void bnx2i_process_update_conn_cmpl(struct bnx2i_hba *hba,
 static void bnx2i_recovery_que_add_conn(struct bnx2i_hba *hba,
                                        struct bnx2i_conn *bnx2i_conn)
 {
-       iscsi_conn_failure(bnx2i_conn->cls_conn->dd_data,
-                          ISCSI_ERR_CONN_FAILED);
+       int prod_idx = hba->conn_recov_prod_idx;
+       struct iscsi_conn *conn;
+
+       if (!hba)
+               return;
+
+       hba->login_stats.session_failures++;
+       spin_lock(&hba->lock);
+
+       conn = bnx2i_conn->cls_conn->dd_data;
+
+        hba->conn_recov_list[prod_idx] = conn;
+        if (hba->conn_recov_max_idx == hba->conn_recov_prod_idx)
+                hba->conn_recov_prod_idx = 0;
+        else
+                hba->conn_recov_prod_idx++;
+
+       spin_unlock(&hba->lock);
+
+       schedule_work(&hba->err_rec_task);
 }
 
 
@@ -2236,9 +2324,11 @@ static void bnx2i_process_iscsi_error(struct bnx2i_hba *hba,
        switch (iscsi_err->completion_status) {
        case ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR:
                strcpy(additional_notice, "hdr digest err");
+               hba->login_stats.digest_errors++;
                break;
        case ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR:
                strcpy(additional_notice, "data digest err");
+               hba->login_stats.digest_errors++;
                break;
        case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE:
                strcpy(additional_notice, "wrong opcode rcvd");
@@ -2529,7 +2619,7 @@ static void bnx2i_indicate_kcqe(void *context, struct kcqe *kcqe[],
  * bnx2i_indicate_netevent - Generic netdev event handler
  * @context:   adapter structure pointer
  * @event:     event type
- * @vlan_id:   vlans id - associated vlan id with this event
+ * @vlan_id:   vlan id - associated vlan id with this event
  *
  * Handles four netdev events, NETDEV_UP, NETDEV_DOWN,
  *     NETDEV_GOING_DOWN and NETDEV_CHANGE
@@ -2538,24 +2628,73 @@ static void bnx2i_indicate_netevent(void *context, unsigned long event,
                                    u16 vlan_id)
 {
        struct bnx2i_hba *hba = context;
+       struct bnx2i_conn *bnx2i_conn;
+       struct iscsi_conn *conn;
+       struct iscsi_session *session;
+       int conns_active, i;
+       unsigned long flags;
 
        /* Ignore all netevent coming from vlans */
-       if (vlan_id != 0)
+       if (vlan_id)
                return;
 
        switch (event) {
        case NETDEV_UP:
-               if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
-                       bnx2i_send_fw_iscsi_init_msg(hba);
                break;
        case NETDEV_DOWN:
+               for (i = 0; i < hba->max_active_conns; i++) { 
+                       bnx2i_conn = bnx2i_get_conn_from_id(hba, i);
+                       if (bnx2i_conn) {
+                               conn = bnx2i_conn->cls_conn->dd_data;
+                               session = conn->session;
+                               spin_lock_irqsave(&session->lock, flags);
+                               if (session->state == ISCSI_STATE_FAILED)
+                                       session->state =
+                                               bnx2i_conn->prev_sess_state;
+                               spin_unlock_irqrestore(&session->lock, flags);
+                       }
+               }
+               iscsi_host_for_each_session(hba->shost,
+                                           bnx2i_drop_session);
+               while (hba->ofld_conns_active) {
+                       conns_active = hba->ofld_conns_active;
+
+                       wait_event_interruptible_timeout(hba->eh_wait,
+                               (hba->ofld_conns_active != conns_active),
+                               hba->hba_shutdown_tmo);
+                       if (hba->ofld_conns_active == conns_active)
+                               break;
+               }
+               /* This flag should be cleared last so that ep_disconnect()
+                * gracefully cleans up connection context
+                */
                clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
                clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+               if (hba->ofld_conns_active)
+                       printk(KERN_ERR "bnx2i (%s): NETDEV_DOWN with %d "
+                               "active conns\n", hba->netdev->name,
+                               hba->ofld_conns_active);
                break;
+
        case NETDEV_GOING_DOWN:
                set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
-               iscsi_host_for_each_session(hba->shost,
-                                           bnx2i_drop_session);
+               /* Suspend all data transmissions */
+               for (i = 0; i < hba->max_active_conns; i++) { 
+                       bnx2i_conn = bnx2i_get_conn_from_id(hba, i);
+                       if (bnx2i_conn) {
+                               conn = bnx2i_conn->cls_conn->dd_data;
+                               session = conn->session;
+                               spin_lock_irqsave(&session->lock, flags);
+                               bnx2i_conn->prev_sess_state = session->state;
+                               if (conn->stop_stage == 0)
+                                       session->state = ISCSI_STATE_FAILED;
+                               spin_unlock_irqrestore(&session->lock, flags);
+                               iscsi_suspend_queue(conn);
+                               set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
+                               iscsi_conn_error_event(bnx2i_conn->cls_conn,
+                                                      ISCSI_ERR_CONN_FAILED);
+                       }
+               }
                break;
        case NETDEV_CHANGE:
                bnx2i_get_link_state(hba);
@@ -2575,16 +2714,19 @@ static void bnx2i_indicate_netevent(void *context, unsigned long event,
  */
 static void bnx2i_cm_connect_cmpl(struct cnic_sock *cm_sk)
 {
-       struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+       struct bnx2i_endpoint *bnx2i_ep =
+                               (struct bnx2i_endpoint *) cm_sk->context;
 
-       if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
-               ep->state = EP_STATE_CONNECT_FAILED;
+       if (test_bit(ADAPTER_STATE_GOING_DOWN, &bnx2i_ep->hba->adapter_state))
+               bnx2i_ep->state = EP_STATE_CONNECT_FAILED;
        else if (test_bit(SK_F_OFFLD_COMPLETE, &cm_sk->flags))
-               ep->state = EP_STATE_CONNECT_COMPL;
-       else
-               ep->state = EP_STATE_CONNECT_FAILED;
-
-       wake_up_interruptible(&ep->ofld_wait);
+               bnx2i_ep->state = EP_STATE_CONNECT_COMPL;
+       else {
+               /* For option2 connection, treat all failures as timeouts */
+               bnx2i_ep->hba->login_stats.connection_timeouts++;
+               bnx2i_ep->state = EP_STATE_CONNECT_FAILED;
+       }
+       wake_up_interruptible(&bnx2i_ep->ofld_wait);
 }
 
 
@@ -2660,7 +2802,7 @@ static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk)
 
 
 static int bnx2i_send_nl_mesg(void *context, u32 msg_type,
-                             char *buf, u16 buflen)
+                             char *buf, u16 buflen, u32 iface_num)
 {
        struct bnx2i_hba *hba = context;
        int rc;
@@ -2668,8 +2810,8 @@ static int bnx2i_send_nl_mesg(void *context, u32 msg_type,
        if (!hba)
                return -ENODEV;
 
-       rc = iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
-                               msg_type, buf, buflen);
+       rc = bnx2i_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
+                               msg_type, buf, buflen, iface_num);
        if (rc)
                printk(KERN_ALERT "bnx2i: private nl message send error\n");
 
@@ -2683,6 +2825,7 @@ static int bnx2i_send_nl_mesg(void *context, u32 msg_type,
  *
  */
 struct cnic_ulp_ops bnx2i_cnic_cb = {
+       .version = CNIC_ULP_OPS_VER,
        .cnic_init = bnx2i_ulp_init,
        .cnic_exit = bnx2i_ulp_exit,
        .cnic_start = bnx2i_start,
@@ -2695,6 +2838,7 @@ struct cnic_ulp_ops bnx2i_cnic_cb = {
        .cm_remote_close = bnx2i_cm_remote_close,
        .cm_remote_abort = bnx2i_cm_remote_abort,
        .iscsi_nl_send_msg = bnx2i_send_nl_mesg,
+       .cnic_get_stats = bnx2i_get_stats,
        .owner = THIS_MODULE
 };
 
@@ -2744,10 +2888,10 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
 
        ep->qp.ctx_base = ioremap_nocache(ep->hba->reg_base + reg_off,
                                          MB_KERNEL_CTX_SIZE);
+arm_cq:
        if (!ep->qp.ctx_base)
                return -ENOMEM;
 
-arm_cq:
        bnx2i_arm_cq_event_coalescing(ep, CNIC_ARM_CQE);
        return 0;
 }
index 8b6816706ee526639f3c71c3f3c65883f080d7da..e3622d811bf818b0b39f799c01ee685821261d8d 100644 (file)
@@ -18,17 +18,15 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
 static u32 adapter_count;
 
 #define DRV_MODULE_NAME                "bnx2i"
-#define DRV_MODULE_VERSION     "2.7.2.2"
-#define DRV_MODULE_RELDATE     "Apr 25, 2012"
+#define DRV_MODULE_VERSION     "2.7.4.1f"
+#define DRV_MODULE_RELDATE     "Aug 27, 2012"
 
 static char version[] __devinitdata =
                "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
                " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
-
 MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com> and "
              "Eddie Wai <eddie.wai@broadcom.com>");
-
 MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711/57712"
                   "/57800/57810/57840 iSCSI Driver");
 MODULE_LICENSE("GPL");
@@ -48,6 +46,10 @@ unsigned int en_tcp_dack = 1;
 module_param(en_tcp_dack, int, 0664);
 MODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK");
 
+unsigned int time_stamps = 0x00;
+module_param(time_stamps, int, 0664);
+MODULE_PARM_DESC(time_stamps, "Enable TCP TimeStamps");
+
 unsigned int error_mask1 = 0x00;
 module_param(error_mask1, uint, 0664);
 MODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1");
@@ -64,6 +66,14 @@ unsigned int rq_size = BNX2I_RQ_WQES_DEFAULT;
 module_param(rq_size, int, 0664);
 MODULE_PARM_DESC(rq_size, "Configure RQ size");
 
+unsigned int tcp_buf_size = 64;
+module_param(tcp_buf_size, int, 0664);
+MODULE_PARM_DESC(tcp_buf_size, "TCP send/receive buffer size");
+unsigned int last_active_tcp_port = 0x00;
+module_param(last_active_tcp_port, int, 0664);
+MODULE_PARM_DESC(last_active_tcp_port, "Display last tcp src port info");
+
 u64 iscsi_error_mask = 0x00;
 
 DEFINE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
@@ -101,7 +111,8 @@ void bnx2i_identify_device(struct bnx2i_hba *hba)
                   hba->pci_did == PCI_DEVICE_ID_NX2_57711    ||
                   hba->pci_did == PCI_DEVICE_ID_NX2_57711E   ||
                   hba->pci_did == PCI_DEVICE_ID_NX2_57712    ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57712E   ||
+                  hba->pci_did == PCI_DEVICE_ID_NX2_57712_VF ||
+                  hba->pci_did == PCI_DEVICE_ID_NX2_57712_MF ||
                   hba->pci_did == PCI_DEVICE_ID_NX2_57800    ||
                   hba->pci_did == PCI_DEVICE_ID_NX2_57800_MF ||
                   hba->pci_did == PCI_DEVICE_ID_NX2_57800_VF ||
@@ -316,6 +327,7 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
        else
                printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc);
 
+       set_bit(CNIC_F_ISCSI_OOO_ENABLE, &cnic->flags);
 out:
        mutex_unlock(&bnx2i_dev_lock);
 
@@ -335,17 +347,26 @@ void bnx2i_ulp_init(struct cnic_dev *dev)
 {
        struct bnx2i_hba *hba;
 
+       if (dev->version != CNIC_DEV_VER) {
+               printk(KERN_WARNING "bnx2i init: cnic not compatible, "
+                               "expecting: 0x%x got: 0x%x\n",
+                               CNIC_DEV_VER, dev->version);
+               return;
+       }
+
        /* Allocate a HBA structure for this device */
        hba = bnx2i_alloc_hba(dev);
        if (!hba) {
-               printk(KERN_ERR "bnx2i init: hba initialization failed\n");
+               printk(KERN_ERR "bnx2i init: (%s) hba initialization failed\n",
+                       dev->netdev->name);
                return;
        }
 
        /* Get PCI related information and update hba struct members */
        clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
        if (bnx2i_init_one(hba, dev)) {
-               printk(KERN_ERR "bnx2i - hba %p init failed\n", hba);
+               printk(KERN_ERR "bnx2i init: (%s) hba %p init failed\n",
+                       dev->netdev->name, hba);
                bnx2i_free_hba(hba);
        }
 }
@@ -380,6 +401,47 @@ void bnx2i_ulp_exit(struct cnic_dev *dev)
 }
 
 
+/**
+ * bnx2i_get_stats - Retrieve various statistic from iSCSI offload
+ * @handle:            bnx2i_hba
+ *
+ * function callback exported via bnx2i - cnic driver interface to
+ *     retrieve various iSCSI offload related statistics.
+ */
+int bnx2i_get_stats(void *handle)
+{
+       struct bnx2i_hba *hba = handle;
+       struct iscsi_stats_info *stats;
+
+       if (!hba)
+               return -EINVAL;
+
+       stats = (struct iscsi_stats_info *)hba->cnic->stats_addr;
+
+       if (!stats)
+               return -ENOMEM;
+
+       memcpy(stats->version, DRV_MODULE_VERSION, sizeof(stats->version));
+       memcpy(stats->mac_add1 + 2, hba->cnic->mac_addr, ETH_ALEN);
+
+       stats->max_frame_size = hba->netdev->mtu;
+       stats->txq_size = hba->max_sqes;
+       stats->rxq_size = hba->max_cqes;
+
+       /* Loop through all ep to get the cqe_left average */
+       stats->txq_avg_depth = 0;
+       stats->rxq_avg_depth = 0;
+
+       GET_STATS_64(hba, stats, rx_pdus);
+       GET_STATS_64(hba, stats, rx_bytes);
+
+       GET_STATS_64(hba, stats, tx_pdus);
+       GET_STATS_64(hba, stats, tx_bytes);
+
+       return 0;
+}
+
+
 /**
  * bnx2i_percpu_thread_create - Create a receive thread for an
  *                             online CPU
@@ -494,7 +556,7 @@ static int __init bnx2i_mod_init(void)
                goto out;
        }
 
-       err = cnic_register_driver(CNIC_ULP_ISCSI, &bnx2i_cnic_cb);
+       err = cnic_register_driver2(CNIC_ULP_ISCSI, &bnx2i_cnic_cb);
        if (err) {
                printk(KERN_ERR "Could not register bnx2i cnic driver.\n");
                goto unreg_xport;
@@ -558,7 +620,7 @@ static void __exit bnx2i_mod_exit(void)
                bnx2i_percpu_thread_destroy(cpu);
 
        iscsi_unregister_transport(&bnx2i_iscsi_transport);
-       cnic_unregister_driver(CNIC_ULP_ISCSI);
+       cnic_unregister_driver2(CNIC_ULP_ISCSI);
 }
 
 module_init(bnx2i_mod_init);
diff --git a/drivers/scsi/bnx2i/bnx2i_ioctl.h b/drivers/scsi/bnx2i/bnx2i_ioctl.h
new file mode 100644 (file)
index 0000000..66ffdad
--- /dev/null
@@ -0,0 +1,47 @@
+/* bnx2i_ioctl.h: Broadcom NetXtreme II iSCSI driver.
+ *
+ * Copyright (c) 2006 - 2012 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
+ */
+#ifndef _BNX2I_IOCTL_H
+#define _BNX2I_IOCTL_H
+
+#define MAX_SIG_SIZE           32
+#define MAX_XPORT_NAME         16
+#define MAX_DEV_NAME_SIZE      16
+
+#define BNX2I_MGMT_SIGNATURE   "bnx2i-mgmt:1.0"
+
+
+
+struct bnx2i_ioctl_header {
+       char signature[MAX_SIG_SIZE];
+       char xport_name[MAX_XPORT_NAME];
+       char dev_name[MAX_DEV_NAME_SIZE];
+};
+
+
+struct bnx2i_get_port_count {
+       struct bnx2i_ioctl_header hdr;
+       unsigned int port_count;
+};
+
+struct bnx2i_set_port_num {
+        struct bnx2i_ioctl_header hdr;
+        unsigned int num_ports;
+        unsigned short tcp_port[1];
+};
+
+
+#define BNX2I_IOCTL_GET_PORT_REQ       \
+               _IOWR('I', 101, struct bnx2i_get_port_count)
+#define BNX2I_IOCTL_SET_TCP_PORT       \
+               _IOWR('I', 102, struct bnx2i_set_port_num)
+
+#endif
index e5fd7ab7cb3a2b202dae1f8e85193852404822c2..f33c2b63ceb0ba642f0e9ecdfc4cf3f5a004f965 100644 (file)
  * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
  */
 
-#include <linux/slab.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/libiscsi.h>
 #include "bnx2i.h"
+#include <linux/ethtool.h>
+#include <scsi/scsi_transport.h>
+#include <net/netlink.h>
+
+#include <linux/version.h>
 
 struct scsi_transport_template *bnx2i_scsi_xport_template;
 struct iscsi_transport bnx2i_iscsi_transport;
 static struct scsi_host_template bnx2i_host_template;
 
+#if defined(INIT_DELAYED_WORK_DEFERRABLE) || defined(INIT_WORK_NAR)
+static void conn_err_recovery_task(struct work_struct *work);
+#else
+static void conn_err_recovery_task(void *data);
+#endif
+
+static void bnx2i_withdraw_conn_recovery(struct bnx2i_hba *hba,
+                                        struct iscsi_conn *conn);
 /*
  * Global endpoint resource info
  */
@@ -372,9 +382,6 @@ static void bnx2i_release_free_cid_que(struct bnx2i_hba *hba)
  * bnx2i_alloc_ep - allocates ep structure from global pool
  * @hba:       pointer to adapter instance
  *
- * routine allocates a free endpoint structure from global pool and
- *     a tcp port to be used for this connection.  Global resource lock,
- *     'bnx2i_resc_lock' is held while accessing shared global data structures
  */
 static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
 {
@@ -593,6 +600,22 @@ void bnx2i_drop_session(struct iscsi_cls_session *cls_session)
        iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
 }
 
+/**
+ * bnx2i_invalid_host - notifies iscsid of host invalidation (prep for host
+ *                     removal)
+ * @hba:       adapter instance pointer
+ * @session:   iscsi session pointer
+ *
+ * This notifies iscsid to invalidate the host
+ *
+ * This relies on caller using the iscsi class iterator so the object
+ * is refcounted and does not disapper from under us.
+ */
+void bnx2i_invalid_host(struct iscsi_cls_session *cls_session)
+{
+       iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_INVALID_HOST);
+}
+
 /**
  * bnx2i_ep_destroy_list_add - add an entry to EP destroy list
  * @hba:       pointer to adapter instance
@@ -874,6 +897,28 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
                hba->conn_ctx_destroy_tmo = 2 * HZ;
        }
 
+#if defined(INIT_DELAYED_WORK_DEFERRABLE) || defined(INIT_WORK_NAR)
+       INIT_WORK(&hba->err_rec_task, conn_err_recovery_task);
+#else
+       INIT_WORK(&hba->err_rec_task, conn_err_recovery_task, hba);
+#endif
+       hba->conn_recov_prod_idx = 0;
+       hba->conn_recov_cons_idx = 0;
+       hba->conn_recov_max_idx = 0;
+       hba->conn_recov_list = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!hba->conn_recov_list)
+               goto free_dump_mem;
+       hba->conn_recov_max_idx = PAGE_SIZE / sizeof (struct iscsi_conn *) - 1;
+
+#ifdef CONFIG_32BIT
+       spin_lock_init(&hba->stat_lock);
+#endif
+       memset(&hba->stats, 0, sizeof(struct iscsi_stats_info));
+       memset(&hba->login_stats, 0, sizeof(struct iscsi_login_stats_info));
+
+       INIT_LIST_HEAD(&hba->iface_ipv4_list);
+       INIT_LIST_HEAD(&hba->iface_ipv6_list);
+
        if (iscsi_host_add(shost, &hba->pcidev->dev))
                goto free_dump_mem;
        return hba;
@@ -902,8 +947,42 @@ ioreg_map_err:
 void bnx2i_free_hba(struct bnx2i_hba *hba)
 {
        struct Scsi_Host *shost = hba->shost;
-
+       struct iscsi_host *ihost = shost_priv(shost);
+#define MAX_FREE_HBA_RETRY 10
+       int i = MAX_FREE_HBA_RETRY, rc = 0;
+#if ((defined(__SLES_DISTRO__) && (__SLES_DISTRO__ > 0x1102)) || \
+     (defined(__RHELS_DISTRO_5__) && (__RHELS_DISTRO_5__ > 0x0508)) || \
+     (defined(__RHELS_DISTRO_6__) && (__RHELS_DISTRO_6__ > 0x0602)) || \
+     (!defined(__DISTRO__) && LINUX_VERSION_CODE > 0x020628))
+       struct list_head *pos, *q;
+       struct bnx2i_iface *bnx2i_iface;
+#endif
+
+       /* Before calling host_remove, we must ensure that all sessions
+        * are currently down via the ihost->num_session parameter
+        */
+       while (i--) {
+               iscsi_host_for_each_session(hba->shost,
+                                           bnx2i_invalid_host);
+               /* 10s timeout */
+               rmb();
+               rc = wait_event_interruptible_timeout(hba->eh_wait,
+                                                     ihost->num_sessions == 0,
+                                                     msecs_to_jiffies(10000));
+               rmb();
+               if (ihost->num_sessions) {
+                       printk(KERN_ALERT "bnx2i: %s free_hba retry with "
+                               "num_sessions = %d\n", hba->netdev->name,
+                               ihost->num_sessions);
+               } else {
+                       printk(KERN_ALERT "bnx2i: %s free_hba done after %d "
+                               "retries\n", hba->netdev->name,
+                               (MAX_FREE_HBA_RETRY - 1) - i);
+                       break;
+               }
+       }
        iscsi_host_remove(shost);
+
        INIT_LIST_HEAD(&hba->ep_ofld_list);
        INIT_LIST_HEAD(&hba->ep_active_list);
        INIT_LIST_HEAD(&hba->ep_destroy_list);
@@ -915,6 +994,37 @@ void bnx2i_free_hba(struct bnx2i_hba *hba)
        }
        bnx2i_free_mp_bdt(hba);
        bnx2i_release_free_cid_que(hba);
+
+       if (hba->conn_recov_list) {
+               kfree(hba->conn_recov_list);
+               hba->conn_recov_list = NULL;
+       }
+
+#if ((defined(__SLES_DISTRO__) && (__SLES_DISTRO__ > 0x1102)) || \
+     (defined(__RHELS_DISTRO_5__) && (__RHELS_DISTRO_5__ > 0x0508)) || \
+     (defined(__RHELS_DISTRO_6__) && (__RHELS_DISTRO_6__ > 0x0602)) || \
+     (!defined(__DISTRO__) && LINUX_VERSION_CODE > 0x020628))
+       list_for_each_safe(pos, q, &hba->iface_ipv4_list) {
+               bnx2i_iface = list_entry(pos, struct bnx2i_iface, link);
+               if (bnx2i_iface) {
+                       if (bnx2i_iface->iface)
+                               iscsi_destroy_iface(bnx2i_iface->iface);
+                       list_del(pos);
+                       kfree(bnx2i_iface);
+               }
+       }
+       INIT_LIST_HEAD(&hba->iface_ipv4_list);
+       list_for_each_safe(pos, q, &hba->iface_ipv6_list) {
+               bnx2i_iface = list_entry(pos, struct bnx2i_iface, link);
+               if (bnx2i_iface) {
+                       if (bnx2i_iface->iface)
+                               iscsi_destroy_iface(bnx2i_iface->iface);
+                       list_del(pos);
+                       kfree(bnx2i_iface);
+               }
+       }
+       INIT_LIST_HEAD(&hba->iface_ipv6_list);
+#endif
        iscsi_host_free(shost);
 }
 
@@ -1078,6 +1188,22 @@ static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task)
        char *buf;
        int data_len;
 
+       /*
+        * Forcefully terminate all in progress connection recovery at the
+        * earliest, either in bind(), send_pdu(LOGIN), or conn_start() 
+        */
+       if (bnx2i_adapter_ready(bnx2i_conn->ep->hba)) {
+               if ((task->hdr->opcode & ISCSI_OPCODE_MASK) ==
+                   ISCSI_OP_NOOP_OUT)
+                       /* This is a WA to indicate to libiscsi that the nopout
+                        * request was sent successfully without actually
+                        * submitting to the hardware.  
+                        * Just silently drop the nopout request
+                        */
+                       return 0;
+               else
+                       return -EIO;
+       }
        bnx2i_iscsi_prep_generic_pdu_bd(bnx2i_conn);
        switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
        case ISCSI_OP_LOGIN:
@@ -1181,12 +1307,18 @@ static int
 bnx2i_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
 {
        struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+       struct bnx2i_hba *hba = bnx2i_conn->hba;
        struct bnx2i_cmd *cmd = task->dd_data;
 
        memset(bnx2i_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN);
 
        bnx2i_setup_cmd_wqe_template(cmd);
        bnx2i_conn->gen_pdu.req_buf_size = task->data_count;
+
+       /* Tx PDU/data length count */
+       ADD_STATS_64(hba, tx_pdus, 1);
+       ADD_STATS_64(hba, tx_bytes, task->data_count);
+
        if (task->data_count) {
                memcpy(bnx2i_conn->gen_pdu.req_buf, task->data,
                       task->data_count);
@@ -1195,6 +1327,7 @@ bnx2i_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
        }
        cmd->conn = conn->dd_data;
        cmd->scsi_cmd = NULL;
+
        return bnx2i_iscsi_send_generic_request(task);
 }
 
@@ -1214,17 +1347,28 @@ static int bnx2i_task_xmit(struct iscsi_task *task)
        struct scsi_cmnd *sc = task->sc;
        struct bnx2i_cmd *cmd = task->dd_data;
        struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr;
+       u32 cpu;
 
+       /* If the number of outstanding cmds exceeds max_sqes, bail */
        if (atomic_read(&bnx2i_conn->ep->num_active_cmds) + 1  >
-           hba->max_sqes)
+           hba->max_sqes) {
+               printk(KERN_ERR "bnx2i: cmds full=%d max=%d\n",
+                      atomic_read(&bnx2i_conn->ep->num_active_cmds),
+                                  hba->max_sqes);
                return -ENOMEM;
-
+       }
        /*
         * If there is no scsi_cmnd this must be a mgmt task
         */
        if (!sc)
                return bnx2i_mtask_xmit(conn, task);
 
+       /* Keep track of the CPU number for the respective scsi cmds */
+       /* Avoid sc->request->cpu for now as the blk layer code has a bug */
+       cpu = get_cpu();
+       put_cpu();
+       cmd->cpu = cpu;
+
        bnx2i_setup_cmd_wqe_template(cmd);
        cmd->req.op_code = ISCSI_OP_SCSI_CMD;
        cmd->conn = bnx2i_conn;
@@ -1430,6 +1574,13 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
                                  hba->netdev->name);
                return -EEXIST;
        }
+       if (bnx2i_conn->ep) {
+               printk(KERN_ALERT "bnx2i: Binding to an existing endpoint "
+                       "detected.  Disconnecting the old...\n");
+               mutex_lock(&hba->net_dev_lock);
+               bnx2i_hw_ep_disconnect(bnx2i_conn->ep);
+               mutex_unlock(&hba->net_dev_lock);
+       }
        bnx2i_ep->conn = bnx2i_conn;
        bnx2i_conn->ep = bnx2i_ep;
        bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid;
@@ -1471,6 +1622,8 @@ static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn)
 
        bnx2i_conn_free_login_resources(hba, bnx2i_conn);
 
+       bnx2i_withdraw_conn_recovery(hba, conn);
+
        if (atomic_read(&bnx2i_conn->work_cnt)) {
                for_each_online_cpu(cpu) {
                        p = &per_cpu(bnx2i_percpu, cpu);
@@ -1493,6 +1646,54 @@ static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn)
        iscsi_conn_teardown(cls_conn);
 }
 
+#if ((!defined(__SLES_DISTRO__) || (__SLES_DISTRO__ < 0x1102)) && \
+     (!defined(__RHELS_DISTRO_5__) || (__RHELS_DISTRO_5__ < 0x0509)) && \
+     (!defined(__RHELS_DISTRO_6__) || (__RHELS_DISTRO_6__ < 0x0602)) && \
+     (defined(__DISTRO__) || LINUX_VERSION_CODE < 0x020626))
+/**
+ * bnx2i_conn_get_param - return iscsi connection parameter to caller
+ * @cls_conn:  pointer to iscsi cls conn
+ * @param:     parameter type identifier
+ * @buf:       buffer pointer
+ *
+ * returns iSCSI connection parameters
+ */
+static int bnx2i_conn_get_param(struct iscsi_cls_conn *cls_conn,
+                               enum iscsi_param param, char *buf)
+{
+       struct iscsi_conn *conn = cls_conn->dd_data;
+       struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+       struct bnx2i_hba *hba;
+       int len = 0;
+
+       switch (param) {
+       case ISCSI_PARAM_CONN_PORT:
+       case ISCSI_PARAM_CONN_ADDRESS:
+               /* iscsi_conn is protected by the caller */
+               if (!(bnx2i_conn && bnx2i_conn->hba))
+                       break;
+               hba = bnx2i_conn->hba;
+               /* lock ep to conn/cm_sk */
+               mutex_lock(&hba->net_dev_lock);
+               if (!(bnx2i_conn->ep && bnx2i_conn->ep->cm_sk))
+                       goto out;
+
+               if (param == ISCSI_PARAM_CONN_PORT)
+                       len = sprintf(buf, "%hu\n",
+                                     bnx2i_conn->ep->cm_sk->dst_port);
+               else
+                       len = sprintf(buf, "%pI4\n",
+                                     &bnx2i_conn->ep->cm_sk->dst_ip);
+out:
+               mutex_unlock(&hba->net_dev_lock);
+               break;
+       default:
+               len = iscsi_conn_get_param(cls_conn, param, buf);
+       }
+       return len;
+}
+
+#else
 
 /**
  * bnx2i_ep_get_param - return iscsi ep parameter to caller
@@ -1528,9 +1729,155 @@ static int bnx2i_ep_get_param(struct iscsi_endpoint *ep,
        default:
                return -ENOSYS;
        }
+       return len;
+}
+#endif
+
+#if ((defined(__SLES_DISTRO__) && (__SLES_DISTRO__ > 0x1102)) || \
+     (defined(__RHELS_DISTRO_5__) && (__RHELS_DISTRO_5__ > 0x0508)) || \
+     (defined(__RHELS_DISTRO_6__) && (__RHELS_DISTRO_6__ > 0x0602)) || \
+     (!defined(__DISTRO__) && LINUX_VERSION_CODE > 0x020628))
+/**
+ * bnx2i_set_iface_param - sets iface related parameters
+ * @shost:     scsi host pointer
+ * @data:      iface data string
+ * @len:       length
+ */
+static int bnx2i_set_iface_param(struct Scsi_Host *shost,
+                                void *data, u32 len)
+{
+       struct bnx2i_hba *hba = iscsi_host_priv(shost);
+       struct iscsi_iface_param_info *iface_param = NULL;
+       struct nlattr *attr;
+       u32 rem = len;
+       struct bnx2i_iface *bnx2i_iface;
+       struct iscsi_iface *iface;
+       struct list_head *pos, *q, *ip_list;
 
+       if (!hba)
+               return 0;
+
+       nla_for_each_attr(attr, data, len, rem) {
+               iface_param = nla_data(attr);
+
+               if (iface_param->param_type != ISCSI_NET_PARAM)
+                       continue;
+
+               /* Ignore all other param request */
+               if (iface_param->param != ISCSI_NET_PARAM_IFACE_ENABLE)
+                       continue;
+
+               switch (iface_param->iface_type) {
+               case ISCSI_IFACE_TYPE_IPV4:
+                       ip_list = &hba->iface_ipv4_list;
+                       break;
+               case ISCSI_IFACE_TYPE_IPV6:
+                       ip_list = &hba->iface_ipv6_list;
+                       break;
+               default:
+                       printk(KERN_ERR "bnx2i: Invalid iface type\n");
+                       continue;
+               }
+               list_for_each_safe(pos, q, ip_list) {
+                       bnx2i_iface = list_entry(pos,
+                                                struct bnx2i_iface,
+                                                link);
+                       if (bnx2i_iface->iface->iface_num ==
+                           iface_param->iface_num) {
+                               /* iface found, delete */
+                               if (bnx2i_iface->iface) {
+                                       iscsi_destroy_iface(bnx2i_iface->iface);
+                                       list_del(pos);
+                                       kfree(bnx2i_iface);
+                               }
+                               break;
+                       }
+               }
+               if (iface_param->value[0] != ISCSI_IFACE_ENABLE)
+                       goto done;
+
+               /* Allocate for the new bnx2i iface entry */
+               bnx2i_iface = kmalloc(sizeof(struct bnx2i_iface), GFP_ATOMIC);
+               if (!bnx2i_iface) {
+                       printk(KERN_ERR "bnx2i: bnx2i_iface alloc failed\n");
+                       return -ENOMEM;
+               }
+               iface = iscsi_create_iface(shost,
+                                          &bnx2i_iscsi_transport,
+                                          iface_param->iface_type,
+                                          iface_param->iface_num, 0);
+               if (!iface) {
+                       printk(KERN_ERR "bnx2i: iscsi_iface create failed\n");
+                       kfree(bnx2i_iface);
+                       return -ENOMEM;
+               }
+               bnx2i_iface->iface = iface;
+               list_add_tail(&bnx2i_iface->link, ip_list);
+       }
+done:
+       return 0;
+}
+
+
+/**
+* bnx2i_get_iface_param - gets iface related parameters
+* @shost:      scsi host pointer
+* @data:       iface data string
+* @len:                length
+*/
+static int bnx2i_get_iface_param(struct iscsi_iface *iface,
+                                enum iscsi_param_type param_type,
+                                int param, char *buf)
+{
+       struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
+       struct bnx2i_hba *hba = iscsi_host_priv(shost);
+       struct list_head *active_list;
+       int len = 0;
+
+       if (param_type != ISCSI_NET_PARAM)
+               return -ENOSYS;
+
+       if (!hba)
+               return -ENOSYS;
+
+       switch (param) {
+       case ISCSI_NET_PARAM_IPV4_ADDR:
+       case ISCSI_NET_PARAM_IPV6_ADDR:
+               read_lock_bh(&hba->ep_rdwr_lock);
+               active_list = &hba->ep_active_list;
+               if (!list_empty(active_list)) {
+                       struct bnx2i_endpoint *bnx2i_ep;
+                       struct cnic_sock *csk;
+
+                       list_for_each_entry(bnx2i_ep, active_list, link) {
+                               csk = bnx2i_ep->cm_sk;
+                               if (!csk)
+                                       continue;
+                               if (csk->iface_num != iface->iface_num)
+                                       continue;
+                               /* IPv4 */
+                               if (!test_bit(SK_F_IPV6, &csk->flags) &&
+                                   iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
+                                       FORMAT_IP(buf, "%pI4\n", csk->src_ip,
+                                                 len);
+                                       break;
+                               } else if (test_bit(SK_F_IPV6, &csk->flags) &&
+                                   iface->iface_type == ISCSI_IFACE_TYPE_IPV6) {
+                                       FORMAT_IP6(buf, "%pI6\n", csk->src_ip,
+                                                  len);
+                                       break;
+                               }
+                       }
+               }
+               read_unlock_bh(&hba->ep_rdwr_lock);
+               break;
+       default:
+               break;
+       }
        return len;
 }
+#endif
+
 
 /**
  * bnx2i_host_get_param - returns host (adapter) related parameters
@@ -1544,6 +1891,11 @@ static int bnx2i_host_get_param(struct Scsi_Host *shost,
        struct bnx2i_hba *hba = iscsi_host_priv(shost);
        int len = 0;
 
+       /* Return len = 0 if the hba or the cnic has already been 
+          unregistered */
+       if (!(hba && hba->cnic))
+               return len;
+
        switch (param) {
        case ISCSI_HOST_PARAM_HWADDRESS:
                len = sysfs_format_mac(buf, hba->cnic->mac_addr, 6);
@@ -1563,10 +1915,14 @@ static int bnx2i_host_get_param(struct Scsi_Host *shost,
                                                    struct bnx2i_endpoint,
                                                    link);
                        csk = bnx2i_ep->cm_sk;
-                       if (test_bit(SK_F_IPV6, &csk->flags))
-                               len = sprintf(buf, "%pI6\n", csk->src_ip);
-                       else
-                               len = sprintf(buf, "%pI4\n", csk->src_ip);
+                       if (csk) {
+                               if (!test_bit(SK_F_IPV6, &csk->flags))
+                                       FORMAT_IP(buf, "%pI4\n", csk->src_ip,
+                                                 len);
+                               else
+                                       FORMAT_IP6(buf, "%pI6\n", csk->src_ip,
+                                                  len);
+                       }
                }
                read_unlock_bh(&hba->ep_rdwr_lock);
                break;
@@ -1607,6 +1963,9 @@ static int bnx2i_conn_start(struct iscsi_cls_conn *cls_conn)
                flush_signals(current);
        del_timer_sync(&bnx2i_conn->ep->ofld_timer);
 
+       if (bnx2i_conn->ep->state != EP_STATE_ULP_UPDATE_COMPL)
+               return -EBUSY;
+
        iscsi_conn_start(cls_conn);
        return 0;
 }
@@ -1691,9 +2050,10 @@ no_nx2_route:
 static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
                                 struct bnx2i_endpoint *ep)
 {
-       if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) && ep->cm_sk)
+       if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) && ep->cm_sk) {
                hba->cnic->cm_destroy(ep->cm_sk);
-
+               ep->cm_sk = NULL;
+       }
        if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) &&
            ep->state == EP_STATE_DISCONN_TIMEDOUT) {
                if (ep->conn && ep->conn->cls_conn &&
@@ -1757,7 +2117,7 @@ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
  */
 static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
                                               struct sockaddr *dst_addr,
-                                              int non_blocking)
+                                              int non_blocking, u32 iface_num)
 {
        u32 iscsi_cid = BNX2I_CID_RESERVED;
        struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr;
@@ -1768,6 +2128,9 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
        struct cnic_sockaddr saddr;
        struct iscsi_endpoint *ep;
        int rc = 0;
+#ifndef _EP_CONNECT_IFACE_NUM_
+       u32 iface_num = -1;
+#endif
 
        if (shost) {
                /* driver is given scsi host to work with */
@@ -1860,16 +2223,21 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
        }
 
        rc = cnic->cm_create(cnic, CNIC_ULP_ISCSI, bnx2i_ep->ep_cid,
-                            iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep);
+                            iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep, iface_num);
        if (rc) {
                rc = -EINVAL;
                /* Need to terminate and cleanup the connection */
                goto release_ep;
        }
 
-       bnx2i_ep->cm_sk->rcv_buf = 256 * 1024;
-       bnx2i_ep->cm_sk->snd_buf = 256 * 1024;
-       clear_bit(SK_TCP_TIMESTAMP, &bnx2i_ep->cm_sk->tcp_flags);
+       /* Supply Window size to be 4 bytes aligned */
+       bnx2i_ep->cm_sk->rcv_buf = (tcp_buf_size * 1024 - 1) & ~0x03;
+       bnx2i_ep->cm_sk->snd_buf = (tcp_buf_size * 1024 - 1) & ~0x03;
+
+        if (!en_tcp_dack)
+                bnx2i_ep->cm_sk->tcp_flags |= SK_TCP_NO_DELAY_ACK;
+        if (time_stamps)
+                bnx2i_ep->cm_sk->tcp_flags |= SK_TCP_TIMESTAMP;
 
        memset(&saddr, 0, sizeof(saddr));
        if (dst_addr->sa_family == AF_INET) {
@@ -1896,6 +2264,8 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
 
        if (bnx2i_map_ep_dbell_regs(bnx2i_ep))
                goto del_active_ep;
+        
+       last_active_tcp_port = be16_to_cpu(bnx2i_ep->cm_sk->src_port);
 
        mutex_unlock(&hba->net_dev_lock);
        return ep;
@@ -2122,15 +2492,16 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
        if (bnx2i_ep->conn) {
                bnx2i_conn = bnx2i_ep->conn;
                conn = bnx2i_conn->cls_conn->dd_data;
+
                iscsi_suspend_queue(conn);
        }
        hba = bnx2i_ep->hba;
 
        mutex_lock(&hba->net_dev_lock);
 
-       if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT)
+       if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT) {
                goto out;
-
+       }
        if (bnx2i_ep->state == EP_STATE_IDLE)
                goto free_resc;
 
@@ -2226,11 +2597,102 @@ static mode_t bnx2i_attr_is_visible(int param_type, int param)
                default:
                        return 0;
                }
+       case ISCSI_NET_PARAM:
+               switch (param) {
+               case ISCSI_NET_PARAM_IPV4_ADDR:
+               case ISCSI_NET_PARAM_IPV4_SUBNET:
+               case ISCSI_NET_PARAM_IPV4_GW:
+               case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
+               case ISCSI_NET_PARAM_IFACE_ENABLE:
+               case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
+               case ISCSI_NET_PARAM_IPV6_ADDR:
+               case ISCSI_NET_PARAM_IPV6_ROUTER:
+               case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
+               case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
+               case ISCSI_NET_PARAM_VLAN_ID:
+               case ISCSI_NET_PARAM_VLAN_PRIORITY:
+               case ISCSI_NET_PARAM_VLAN_ENABLED:
+               case ISCSI_NET_PARAM_MTU:
+               case ISCSI_NET_PARAM_PORT:
+                       return S_IRUGO;
+               default:
+                       return 0;
+               }
        }
 
        return 0;
 }
 
+/**
+ * conn_err_recovery_task - does recovery on all queued sessions
+ *
+ * @work:               pointer to work struct
+ *
+ * iSCSI Session recovery queue manager
+ */
+static void
+#if defined(INIT_DELAYED_WORK_DEFERRABLE) || defined(INIT_WORK_NAR)
+conn_err_recovery_task(struct work_struct *work)
+#else
+conn_err_recovery_task(void *data)
+#endif
+{
+#if defined(INIT_DELAYED_WORK_DEFERRABLE) || defined(INIT_WORK_NAR)
+       struct bnx2i_hba *hba = container_of(work, struct bnx2i_hba,
+                                            err_rec_task);
+#else
+       struct bnx2i_hba *hba = data;
+#endif
+       int cons_idx = hba->conn_recov_cons_idx;
+       unsigned int long flags;
+       struct iscsi_conn *conn;
+       struct iscsi_session *sess = NULL;
+
+       spin_lock_irqsave(&hba->lock, flags);
+       while (hba->conn_recov_prod_idx != cons_idx) {
+               conn = hba->conn_recov_list[cons_idx];
+               if (cons_idx == hba->conn_recov_max_idx)
+                       cons_idx = 0;
+               else
+                       cons_idx++;
+               spin_unlock_irqrestore(&hba->lock, flags);
+               if (conn)
+                       sess = conn->session;
+               if (sess) {
+                       spin_lock_bh(&sess->lock);
+                       if (sess->state != ISCSI_STATE_LOGGING_OUT) {
+                               spin_unlock_bh(&sess->lock);
+                               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+                       } else
+                               spin_unlock_bh(&sess->lock);
+               }
+               spin_lock_irqsave(&hba->lock, flags);
+       }
+       hba->conn_recov_cons_idx = cons_idx;
+       spin_unlock_irqrestore(&hba->lock, flags);
+}
+
+
+static void bnx2i_withdraw_conn_recovery(struct bnx2i_hba *hba,
+                                        struct iscsi_conn *conn)
+{
+        int cons_idx = hba->conn_recov_cons_idx;
+        unsigned int long flags;
+
+        spin_lock_irqsave(&hba->lock, flags);
+        while (hba->conn_recov_prod_idx != cons_idx) {
+                if (conn == hba->conn_recov_list[cons_idx]) {
+                        hba->conn_recov_list[cons_idx] = NULL;
+                        break;
+                }
+                if (cons_idx == hba->conn_recov_max_idx)
+                        cons_idx = 0;
+                else
+                        cons_idx++;
+        }
+        spin_unlock_irqrestore(&hba->lock, flags);
+}
+
 /*
  * 'Scsi_Host_Template' structure and 'iscsi_tranport' structure template
  * used while registering with the scsi host and iSCSI transport module.
@@ -2242,16 +2704,25 @@ static struct scsi_host_template bnx2i_host_template = {
        .queuecommand           = iscsi_queuecommand,
        .eh_abort_handler       = iscsi_eh_abort,
        .eh_device_reset_handler = iscsi_eh_device_reset,
+#if (LINUX_VERSION_CODE >= 0x020622)
        .eh_target_reset_handler = iscsi_eh_recover_target,
+#endif
        .change_queue_depth     = iscsi_change_queue_depth,
+#if ((defined(__RHELS_DISTRO_6__) && (__RHELS_DISTRO_6__ > 0x0600)) || \
+     (defined(__SLES_DISTRO__) && (__SLES_DISTRO__ > 0x1101)))
        .target_alloc           = iscsi_target_alloc,
+#endif
        .can_queue              = 2048,
        .max_sectors            = 127,
        .cmd_per_lun            = 128,
        .this_id                = -1,
        .use_clustering         = ENABLE_CLUSTERING,
        .sg_tablesize           = ISCSI_MAX_BDS_PER_CMD,
+#if (defined(__RHELS_DISTRO_5__))
+       .sdev_attrs             = bnx2i_dev_attributes,
+#else
        .shost_attrs            = bnx2i_dev_attributes,
+#endif
 };
 
 struct iscsi_transport bnx2i_iscsi_transport = {
@@ -2266,9 +2737,24 @@ struct iscsi_transport bnx2i_iscsi_transport = {
        .create_conn            = bnx2i_conn_create,
        .bind_conn              = bnx2i_conn_bind,
        .destroy_conn           = bnx2i_conn_destroy,
-       .attr_is_visible        = bnx2i_attr_is_visible,
        .set_param              = iscsi_set_param,
+       .attr_is_visible        = bnx2i_attr_is_visible,
+#if ((!defined(__SLES_DISTRO__) || (__SLES_DISTRO__ < 0x1102)) && \
+     (!defined(__RHELS_DISTRO_5__) || (__RHELS_DISTRO_5__ < 0x0509)) && \
+     (!defined(__RHELS_DISTRO_6__) || (__RHELS_DISTRO_6__ < 0x0602)) && \
+     (defined(__DISTRO__) || LINUX_VERSION_CODE < 0x020626))
+       .get_conn_param         = bnx2i_conn_get_param,
+#else
        .get_conn_param         = iscsi_conn_get_param,
+       .get_ep_param           = bnx2i_ep_get_param,
+#endif
+#if ((defined(__SLES_DISTRO__) && (__SLES_DISTRO__ > 0x1102)) || \
+     (defined(__RHELS_DISTRO_5__) && (__RHELS_DISTRO_5__ > 0x0508)) || \
+     (defined(__RHELS_DISTRO_6__) && (__RHELS_DISTRO_6__ > 0x0602)) || \
+     (!defined(__DISTRO__) && LINUX_VERSION_CODE > 0x020628))
+       .set_iface_param        = bnx2i_set_iface_param,
+       .get_iface_param        = bnx2i_get_iface_param,
+#endif
        .get_session_param      = iscsi_session_get_param,
        .get_host_param         = bnx2i_host_get_param,
        .start_conn             = bnx2i_conn_start,
@@ -2277,7 +2763,6 @@ struct iscsi_transport bnx2i_iscsi_transport = {
        .xmit_task              = bnx2i_task_xmit,
        .get_stats              = bnx2i_conn_get_stats,
        /* TCP connect - disconnect - option-2 interface calls */
-       .get_ep_param           = bnx2i_ep_get_param,
        .ep_connect             = bnx2i_ep_connect,
        .ep_poll                = bnx2i_ep_poll,
        .ep_disconnect          = bnx2i_ep_disconnect,
index c61cf7a4365830d9c1646fd066440d21cb527ace..5f42f7365a3e723a8cb69f68e21d438799745674 100644 (file)
  */
 static inline struct bnx2i_hba *bnx2i_dev_to_hba(struct device *dev)
 {
+#if (defined(__RHELS_DISTRO_5__))
+       /* TODO: is the shost_gendev what we want here?  or
+                do we want the actual class_dev */
+       struct Scsi_Host *shost = dev_to_shost(dev);
+#else
        struct Scsi_Host *shost = class_to_shost(dev);
+#endif
        return iscsi_host_priv(shost);
 }