Move from upstream to broadcom driver.
Signed-off-by: Jerry Snitselaar <jerry.snitselaar@oracle.com>
/* 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 */
* 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
};
/*
*/
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
};
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;
#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
* @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;
struct io_bdt io_tbl;
dma_addr_t bd_tbl_dma;
struct bnx2i_cmd_request req;
+ u32 cpu;
};
* @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
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
*
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
*
* @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
* @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
*/
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;
int hba_shutdown_tmo;
int conn_teardown_tmo;
int conn_ctx_destroy_tmo;
+
/*
* PCI related info.
*/
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.
******************************************************************************/
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;
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[];
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,
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
--- /dev/null
+/* 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_ */
#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);
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];
/* 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;
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 =
(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;
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;
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);
}
+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
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;
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);
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);
}
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);
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);
LIST_HEAD(work_list);
set_user_nice(current, -20);
+ set_unfreezable(current);
while (!kthread_should_stop()) {
spin_lock_bh(&p->p_work_lock);
{
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,
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);
{
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;
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) {
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;
}
}
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);
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! "
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);
}
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");
* 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
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);
*/
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);
}
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;
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");
*
*/
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,
.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
};
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;
}
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");
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");
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);
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 ||
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);
{
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);
}
}
}
+/**
+ * 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
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;
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);
--- /dev/null
+/* 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
* 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
*/
* 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)
{
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
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;
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);
}
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);
}
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:
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);
}
cmd->conn = conn->dd_data;
cmd->scsi_cmd = NULL;
+
return bnx2i_iscsi_send_generic_request(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;
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;
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);
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
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
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);
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;
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;
}
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 &&
*/
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;
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 */
}
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) {
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;
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;
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.
.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 = {
.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,
.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,
*/
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);
}