aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/bnx2i
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/bnx2i')
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_constants.h8
-rw-r--r--drivers/scsi/bnx2i/57xx_iscsi_hsi.h43
-rw-r--r--drivers/scsi/bnx2i/Kconfig6
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h161
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c662
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c380
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c580
-rw-r--r--drivers/scsi/bnx2i/bnx2i_sysfs.c3
8 files changed, 1349 insertions, 494 deletions
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
index 2fceb19eb27..3d33767f2f2 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
@@ -1,12 +1,13 @@
/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 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 __57XX_ISCSI_CONSTANTS_H_
#define __57XX_ISCSI_CONSTANTS_H_
@@ -120,9 +121,12 @@
/* 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)
+#define ISCSI_KCQE_COMPLETION_STATUS_PARITY_ERR (0x81)
+
/* SQ/RQ/CQ DB structure sizes */
#define ISCSI_SQ_DB_SIZE (16)
-#define ISCSI_RQ_DB_SIZE (16)
+#define ISCSI_RQ_DB_SIZE (64)
#define ISCSI_CQ_DB_SIZE (80)
#define ISCSI_SQN_TO_NOTIFY_NOT_VALID 0xFFFF
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
index 36af1afef9b..7052a839b0e 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
@@ -1,12 +1,13 @@
/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 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 __57XX_ISCSI_HSI_LINUX_LE__
#define __57XX_ISCSI_HSI_LINUX_LE__
@@ -266,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
};
/*
@@ -274,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
};
@@ -574,8 +581,10 @@ struct iscsi_kwqe_init1 {
#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4
#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5)
#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5
-#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6)
-#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6
+#define ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE (0x1<<6)
+#define ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE_SHIFT 6
+#define ISCSI_KWQE_INIT1_RESERVED1 (0x1<<7)
+#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 7
u16 cq_num_wqes;
#elif defined(__LITTLE_ENDIAN)
u16 cq_num_wqes;
@@ -586,8 +595,10 @@ struct iscsi_kwqe_init1 {
#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4
#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5)
#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5
-#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6)
-#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6
+#define ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE (0x1<<6)
+#define ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE_SHIFT 6
+#define ISCSI_KWQE_INIT1_RESERVED1 (0x1<<7)
+#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 7
u8 cq_log_wqes_per_page;
#endif
#if defined(__BIG_ENDIAN)
@@ -706,8 +717,10 @@ struct iscsi_kwqe_conn_update {
#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2
#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3)
#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3
-#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4)
-#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4
+#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE (0x3<<4)
+#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE_SHIFT 4
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0x3<<6)
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 6
#elif defined(__LITTLE_ENDIAN)
u8 conn_flags;
#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0)
@@ -718,8 +731,10 @@ struct iscsi_kwqe_conn_update {
#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2
#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3)
#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3
-#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4)
-#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4
+#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE (0x3<<4)
+#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE_SHIFT 4
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0x3<<6)
+#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 6
u8 reserved2;
u8 max_outstanding_r2ts;
u8 session_error_recovery_level;
diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig
index 1e9f7141102..01cff1894b6 100644
--- a/drivers/scsi/bnx2i/Kconfig
+++ b/drivers/scsi/bnx2i/Kconfig
@@ -1,10 +1,12 @@
config SCSI_BNX2_ISCSI
tristate "Broadcom NetXtreme II iSCSI support"
+ depends on NET
+ depends on PCI
select SCSI_ISCSI_ATTRS
select NETDEVICES
- select NETDEV_1000
+ select ETHERNET
+ select NET_VENDOR_BROADCOM
select CNIC
- depends on PCI
---help---
This driver supports iSCSI offload for the Broadcom NetXtreme II
devices.
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index 6b624e767d3..c73bbcb63c0 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -1,6 +1,6 @@
/* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -9,6 +9,7 @@
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#ifndef _BNX2I_H_
@@ -21,11 +22,14 @@
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/in.h>
#include <linux/kfifo.h>
#include <linux/netdevice.h>
#include <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/cpu.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -36,10 +40,12 @@
#include <scsi/libiscsi.h>
#include <scsi/scsi_transport_iscsi.h>
-#include "../../net/cnic_if.h"
+#include "../../net/ethernet/broadcom/cnic_if.h"
#include "57xx_iscsi_hsi.h"
#include "57xx_iscsi_constants.h"
+#include "../../net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h"
+
#define BNX2_ISCSI_DRIVER_NAME "bnx2i"
#define BNX2I_MAX_ADAPTERS 8
@@ -58,16 +64,18 @@
#define MAX_PAGES_PER_CTRL_STRUCT_POOL 8
#define BNX2I_RESERVED_SLOW_PATH_CMD_SLOTS 4
+#define BNX2X_DB_SHIFT 3
+
/* 5706/08 hardware has limit on maximum buffer size per BD it can handle */
#define MAX_BD_LENGTH 65535
#define BD_SPLIT_SIZE 32768
/* min, max & default values for SQ/RQ/CQ size, configurable via' modparam */
-#define BNX2I_SQ_WQES_MIN 16
-#define BNX2I_570X_SQ_WQES_MAX 128
-#define BNX2I_5770X_SQ_WQES_MAX 512
-#define BNX2I_570X_SQ_WQES_DEFAULT 128
-#define BNX2I_5770X_SQ_WQES_DEFAULT 256
+#define BNX2I_SQ_WQES_MIN 16
+#define BNX2I_570X_SQ_WQES_MAX 128
+#define BNX2I_5770X_SQ_WQES_MAX 512
+#define BNX2I_570X_SQ_WQES_DEFAULT 128
+#define BNX2I_5770X_SQ_WQES_DEFAULT 128
#define BNX2I_570X_CQ_WQES_MAX 128
#define BNX2I_5770X_CQ_WQES_MAX 512
@@ -112,6 +120,7 @@
#define BNX2X_MAX_CQS 8
#define CNIC_ARM_CQE 1
+#define CNIC_ARM_CQE_FP 2
#define CNIC_DISARM_CQE 0
#define REG_RD(__hba, offset) \
@@ -119,6 +128,43 @@
#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) \
+ do { \
+ __hba->bnx2i_stats.field += len; \
+ } while (0)
+#endif
/**
* struct generic_pdu_resc - login pdu resource structure
@@ -198,10 +244,13 @@ struct io_bdt {
/**
* bnx2i_cmd - iscsi command structure
*
+ * @hdr: iSCSI header
+ * @conn: iscsi_conn pointer
* @scsi_cmd: SCSI-ML task pointer corresponding to this iscsi cmd
* @sg: SG list
* @io_tbl: buffer descriptor (BD) table
* @bd_tbl_dma: buffer descriptor (BD) table's dma address
+ * @req: bnx2i specific command request struct
*/
struct bnx2i_cmd {
struct iscsi_hdr hdr;
@@ -225,6 +274,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
+ * @work_cnt: keeps track of the number of outstanding work
*
* iSCSI connection structure
*/
@@ -248,6 +298,8 @@ struct bnx2i_conn {
*/
struct generic_pdu_resc gen_pdu;
u64 violation_notified;
+
+ atomic_t work_cnt;
};
@@ -275,6 +327,15 @@ 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 bnx2i_hba - bnx2i adapter structure
*
@@ -295,16 +356,21 @@ struct iscsi_cid_queue {
* @max_cqes: CQ size
* @num_ccell: number of command cells per connection
* @ofld_conns_active: active connection list
+ * @eh_wait: wait queue for the endpoint to shutdown
* @max_active_conns: max offload connections supported by this device
* @cid_que: iscsi cid queue
* @ep_rdwr_lock: read / write lock to synchronize various ep lists
* @ep_ofld_list: connection list for pending offload completion
+ * @ep_active_list: connection list for active offload endpoints
* @ep_destroy_list: connection list for pending offload completion
* @mp_bd_tbl: BD table to be used with middle path requests
* @mp_bd_dma: DMA address of 'mp_bd_tbl' memory buffer
* @dummy_buffer: Dummy buffer to be used with zero length scsicmd reqs
* @dummy_buf_dma: DMA address of 'dummy_buffer' memory buffer
* @lock: lock to synchonize access to hba structure
+ * @hba_shutdown_tmo: Timeout value to shutdown each connection
+ * @conn_teardown_tmo: Timeout value to tear down each connection
+ * @conn_ctx_destroy_tmo: Timeout value to destroy context of each connection
* @pci_did: PCI device ID
* @pci_vid: PCI vendor ID
* @pci_sdid: PCI subsystem device ID
@@ -323,6 +389,8 @@ 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: spin lock used by the statistic collector (32 bit)
+ * @stats: local iSCSI statistic collection place holder
*
* Adapter Data Structure
*/
@@ -332,6 +400,7 @@ struct bnx2i_hba {
struct pci_dev *pcidev;
struct net_device *netdev;
void __iomem *regview;
+ resource_size_t reg_base;
u32 age;
unsigned long cnic_dev_type;
@@ -352,7 +421,7 @@ struct bnx2i_hba {
#define ADAPTER_STATE_LINK_DOWN 2
#define ADAPTER_STATE_INIT_FAILED 31
unsigned int mtu_supported;
- #define BNX2I_MAX_MTU_SUPPORTED 1500
+ #define BNX2I_MAX_MTU_SUPPORTED 9000
struct Scsi_Host *shost;
@@ -369,6 +438,7 @@ struct bnx2i_hba {
rwlock_t ep_rdwr_lock;
struct list_head ep_ofld_list;
+ struct list_head ep_active_list;
struct list_head ep_destroy_list;
/*
@@ -383,6 +453,8 @@ struct bnx2i_hba {
struct mutex net_dev_lock;/* sync net device access */
int hba_shutdown_tmo;
+ int conn_teardown_tmo;
+ int conn_ctx_destroy_tmo;
/*
* PCI related info.
*/
@@ -405,6 +477,12 @@ 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;
};
@@ -466,7 +544,7 @@ struct bnx2i_5771x_cq_db {
struct bnx2i_5771x_sq_rq_db {
u16 prod_idx;
- u8 reserved0[14]; /* Pad structure size to 16 bytes */
+ u8 reserved0[62]; /* Pad structure size to 64 bytes */
};
@@ -502,8 +580,8 @@ struct bnx2i_5771x_dbell {
* @sq_mem_size: SQ size
* @sq_prod_qe: SQ producer entry pointer
* @sq_cons_qe: SQ consumer entry pointer
- * @sq_first_qe: virtaul address of first entry in SQ
- * @sq_last_qe: virtaul address of last entry in SQ
+ * @sq_first_qe: virtual address of first entry in SQ
+ * @sq_last_qe: virtual address of last entry in SQ
* @sq_prod_idx: SQ producer index
* @sq_cons_idx: SQ consumer index
* @sqe_left: number sq entry left
@@ -515,8 +593,8 @@ struct bnx2i_5771x_dbell {
* @cq_mem_size: CQ size
* @cq_prod_qe: CQ producer entry pointer
* @cq_cons_qe: CQ consumer entry pointer
- * @cq_first_qe: virtaul address of first entry in CQ
- * @cq_last_qe: virtaul address of last entry in CQ
+ * @cq_first_qe: virtual address of first entry in CQ
+ * @cq_last_qe: virtual address of last entry in CQ
* @cq_prod_idx: CQ producer index
* @cq_cons_idx: CQ consumer index
* @cqe_left: number cq entry left
@@ -530,8 +608,8 @@ struct bnx2i_5771x_dbell {
* @rq_mem_size: RQ size
* @rq_prod_qe: RQ producer entry pointer
* @rq_cons_qe: RQ consumer entry pointer
- * @rq_first_qe: virtaul address of first entry in RQ
- * @rq_last_qe: virtaul address of last entry in RQ
+ * @rq_first_qe: virtual address of first entry in RQ
+ * @rq_last_qe: virtual address of last entry in RQ
* @rq_prod_idx: RQ producer index
* @rq_cons_idx: RQ consumer index
* @rqe_left: number rq entry left
@@ -631,12 +709,15 @@ enum {
EP_STATE_CLEANUP_CMPL = 0x800,
EP_STATE_TCP_FIN_RCVD = 0x1000,
EP_STATE_TCP_RST_RCVD = 0x2000,
+ EP_STATE_LOGOUT_SENT = 0x4000,
+ EP_STATE_LOGOUT_RESP_RCVD = 0x8000,
EP_STATE_PG_OFLD_FAILED = 0x1000000,
EP_STATE_ULP_UPDATE_FAILED = 0x2000000,
EP_STATE_CLEANUP_FAILED = 0x4000000,
EP_STATE_OFLD_FAILED = 0x8000000,
EP_STATE_CONNECT_FAILED = 0x10000000,
EP_STATE_DISCONN_TIMEDOUT = 0x20000000,
+ EP_STATE_OFLD_FAILED_CID_BUSY = 0x80000000,
};
/**
@@ -645,13 +726,15 @@ enum {
* @link: list head to link elements
* @hba: adapter to which this connection belongs
* @conn: iscsi connection this EP is linked to
- * @sess: iscsi session this EP is linked to
+ * @cls_ep: associated iSCSI endpoint pointer
* @cm_sk: cnic sock struct
* @hba_age: age to detect if 'iscsid' issues ep_disconnect()
* after HBA reset is completed by bnx2i/cnic/bnx2
* modules
* @state: tracks offload connection state machine
- * @teardown_mode: indicates if conn teardown is abortive or orderly
+ * @timestamp: tracks the start time when the ep begins to connect
+ * @num_active_cmds: tracks the number of outstanding commands for this ep
+ * @ec_shift: the amount of shift as part of the event coal calc
* @qp: QP information
* @ids: contains chip allocated *context id* & driver assigned
* *iscsi cid*
@@ -664,11 +747,13 @@ struct bnx2i_endpoint {
struct list_head link;
struct bnx2i_hba *hba;
struct bnx2i_conn *conn;
+ struct iscsi_endpoint *cls_ep;
struct cnic_sock *cm_sk;
u32 hba_age;
u32 state;
unsigned long timestamp;
- int num_active_cmds;
+ atomic_t num_active_cmds;
+ u32 ec_shift;
struct qp_info qp;
struct ep_handles ids;
@@ -680,6 +765,19 @@ struct bnx2i_endpoint {
};
+struct bnx2i_work {
+ struct list_head list;
+ struct iscsi_session *session;
+ struct bnx2i_conn *bnx2i_conn;
+ struct cqe cqe;
+};
+
+struct bnx2i_percpu_s {
+ struct task_struct *iothread;
+ struct list_head work_list;
+ spinlock_t p_work_lock;
+};
+
/* Global variables */
extern unsigned int error_mask1, error_mask2;
@@ -702,15 +800,14 @@ extern struct device_attribute *bnx2i_dev_attributes[];
/*
* Function Prototypes
*/
-extern void bnx2i_identify_device(struct bnx2i_hba *hba);
-extern void bnx2i_register_device(struct bnx2i_hba *hba);
+extern void bnx2i_identify_device(struct bnx2i_hba *hba, struct cnic_dev *dev);
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 void bnx2i_reg_dev_all(void);
-extern void bnx2i_unreg_dev_all(void);
+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,
@@ -738,20 +835,22 @@ extern int bnx2i_send_iscsi_login(struct bnx2i_conn *conn,
struct iscsi_task *mtask);
extern int bnx2i_send_iscsi_tmf(struct bnx2i_conn *conn,
struct iscsi_task *mtask);
+extern int bnx2i_send_iscsi_text(struct bnx2i_conn *conn,
+ struct iscsi_task *mtask);
extern int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *conn,
struct bnx2i_cmd *cmnd);
extern int bnx2i_send_iscsi_nopout(struct bnx2i_conn *conn,
- struct iscsi_task *mtask, u32 ttt,
+ struct iscsi_task *mtask,
char *datap, int data_len, int unsol);
extern int bnx2i_send_iscsi_logout(struct bnx2i_conn *conn,
struct iscsi_task *mtask);
extern void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba,
struct bnx2i_cmd *cmd);
-extern void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba,
- struct bnx2i_endpoint *ep);
-extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn);
-extern void bnx2i_send_conn_destroy(struct bnx2i_hba *hba,
+extern int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba,
struct bnx2i_endpoint *ep);
+extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn);
+extern int bnx2i_send_conn_destroy(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep);
extern int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba,
struct bnx2i_endpoint *ep);
@@ -764,7 +863,9 @@ extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list(
struct bnx2i_hba *hba, u32 iscsi_cid);
extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep);
-extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);
+extern int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);
+
+extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep);
/* Debug related function prototypes */
extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn);
@@ -772,4 +873,8 @@ extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn);
extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn);
extern void bnx2i_print_recv_state(struct bnx2i_conn *conn);
+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);
#endif
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 3a66ca24c7b..d6d491c2f00 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1,6 +1,6 @@
/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -9,6 +9,7 @@
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include <linux/gfp.h>
@@ -16,6 +17,8 @@
#include <scsi/libiscsi.h>
#include "bnx2i.h"
+DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
+
/**
* bnx2i_get_cid_num - get cid from ep
* @ep: endpoint pointer
@@ -58,7 +61,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
* yield integral num of page buffers
*/
/* adjust SQ */
- num_elements_per_pg = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+ num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
if (hba->max_sqes < num_elements_per_pg)
hba->max_sqes = num_elements_per_pg;
else if (hba->max_sqes % num_elements_per_pg)
@@ -66,7 +69,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
~(num_elements_per_pg - 1);
/* adjust CQ */
- num_elements_per_pg = PAGE_SIZE / BNX2I_CQE_SIZE;
+ num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_CQE_SIZE;
if (hba->max_cqes < num_elements_per_pg)
hba->max_cqes = num_elements_per_pg;
else if (hba->max_cqes % num_elements_per_pg)
@@ -74,7 +77,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
~(num_elements_per_pg - 1);
/* adjust RQ */
- num_elements_per_pg = PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
+ num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
if (hba->max_rqes < num_elements_per_pg)
hba->max_rqes = num_elements_per_pg;
else if (hba->max_rqes % num_elements_per_pg)
@@ -123,40 +126,43 @@ static void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code)
/**
* bnx2i_arm_cq_event_coalescing - arms CQ to enable EQ notification
- * @ep: endpoint (transport indentifier) structure
+ * @ep: endpoint (transport identifier) structure
* @action: action, ARM or DISARM. For now only ARM_CQE is used
*
* Arm'ing CQ will enable chip to generate global EQ events inorder to interrupt
* the driver. EQ event is generated CQ index is hit or at least 1 CQ is
* outstanding and on chip timer expires
*/
-void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
+int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
{
struct bnx2i_5771x_cq_db *cq_db;
u16 cq_index;
- u16 next_index;
+ u16 next_index = 0;
u32 num_active_cmds;
-
/* Coalesce CQ entries only on 10G devices */
if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
- return;
+ return 0;
/* Do not update CQ DB multiple times before firmware writes
* '0xFFFF' to CQDB->SQN field. Deviation may cause spurious
* interrupts and other unwanted results
*/
cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt;
- if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF)
- return;
- if (action == CNIC_ARM_CQE) {
- num_active_cmds = ep->num_active_cmds;
+ if (action != CNIC_ARM_CQE_FP)
+ if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF)
+ return 0;
+
+ if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) {
+ num_active_cmds = atomic_read(&ep->num_active_cmds);
if (num_active_cmds <= event_coal_min)
next_index = 1;
- else
- next_index = event_coal_min +
- (num_active_cmds - event_coal_min) / event_coal_div;
+ else {
+ next_index = num_active_cmds >> ep->ec_shift;
+ if (next_index > num_active_cmds - event_coal_min)
+ next_index = num_active_cmds - event_coal_min;
+ }
if (!next_index)
next_index = 1;
cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1;
@@ -167,12 +173,13 @@ void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
cq_db->sqn[0] = cq_index;
}
+ return next_index;
}
/**
* bnx2i_get_rq_buf - copy RQ buffer contents to driver buffer
- * @conn: iscsi connection on which RQ event occured
+ * @conn: iscsi connection on which RQ event occurred
* @ptr: driver buffer to which RQ buffer contents is to
* be copied
* @len: length of valid data inside RQ buf
@@ -262,7 +269,7 @@ static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count)
struct bnx2i_5771x_sq_rq_db *sq_db;
struct bnx2i_endpoint *ep = bnx2i_conn->ep;
- ep->num_active_cmds++;
+ atomic_inc(&ep->num_active_cmds);
wmb(); /* flush SQ WQE memory before the doorbell is rung */
if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt;
@@ -325,11 +332,11 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
{
struct bnx2i_cmd *bnx2i_cmd;
struct bnx2i_login_request *login_wqe;
- struct iscsi_login *login_hdr;
+ struct iscsi_login_req *login_hdr;
u32 dword;
bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
- login_hdr = (struct iscsi_login *)task->hdr;
+ login_hdr = (struct iscsi_login_req *)task->hdr;
login_wqe = (struct bnx2i_login_request *)
bnx2i_conn->ep->qp.sq_prod_qe;
@@ -393,38 +400,44 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
bnx2i_conn->ep->qp.sq_prod_qe;
tmfabort_wqe->op_code = tmfabort_hdr->opcode;
- tmfabort_wqe->op_attr = 0;
- tmfabort_wqe->op_attr =
- ISCSI_TMF_REQUEST_ALWAYS_ONE | ISCSI_TM_FUNC_ABORT_TASK;
+ tmfabort_wqe->op_attr = tmfabort_hdr->flags;
tmfabort_wqe->itt = (mtask->itt | (ISCSI_TASK_TYPE_MPATH << 14));
tmfabort_wqe->reserved2 = 0;
tmfabort_wqe->cmd_sn = be32_to_cpu(tmfabort_hdr->cmdsn);
- ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt);
- if (!ctask || !ctask->sc)
- /*
- * the iscsi layer must have completed the cmd while this
- * was starting up.
- *
- * Note: In the case of a SCSI cmd timeout, the task's sc
- * is still active; hence ctask->sc != 0
- * In this case, the task must be aborted
- */
- return 0;
-
- ref_sc = ctask->sc;
-
- /* Retrieve LUN directly from the ref_sc */
- int_to_scsilun(ref_sc->device->lun, (struct scsi_lun *) scsi_lun);
+ switch (tmfabort_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) {
+ case ISCSI_TM_FUNC_ABORT_TASK:
+ case ISCSI_TM_FUNC_TASK_REASSIGN:
+ ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt);
+ if (!ctask || !ctask->sc)
+ /*
+ * the iscsi layer must have completed the cmd while
+ * was starting up.
+ *
+ * Note: In the case of a SCSI cmd timeout, the task's
+ * sc is still active; hence ctask->sc != 0
+ * In this case, the task must be aborted
+ */
+ return 0;
+
+ ref_sc = ctask->sc;
+ if (ref_sc->sc_data_direction == DMA_TO_DEVICE)
+ dword = (ISCSI_TASK_TYPE_WRITE <<
+ ISCSI_CMD_REQUEST_TYPE_SHIFT);
+ else
+ dword = (ISCSI_TASK_TYPE_READ <<
+ ISCSI_CMD_REQUEST_TYPE_SHIFT);
+ tmfabort_wqe->ref_itt = (dword |
+ (tmfabort_hdr->rtt & ISCSI_ITT_MASK));
+ break;
+ default:
+ tmfabort_wqe->ref_itt = RESERVED_ITT;
+ }
+ memcpy(scsi_lun, &tmfabort_hdr->lun, sizeof(struct scsi_lun));
tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]);
tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]);
- if (ref_sc->sc_data_direction == DMA_TO_DEVICE)
- dword = (ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT);
- else
- dword = (ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT);
- tmfabort_wqe->ref_itt = (dword | (tmfabort_hdr->rtt & ISCSI_ITT_MASK));
tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn);
tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma;
@@ -438,6 +451,56 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
}
/**
+ * bnx2i_send_iscsi_text - post iSCSI text WQE to hardware
+ * @conn: iscsi connection
+ * @mtask: driver command structure which is requesting
+ * a WQE to sent to chip for further processing
+ *
+ * prepare and post an iSCSI Text request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_text(struct bnx2i_conn *bnx2i_conn,
+ struct iscsi_task *mtask)
+{
+ struct bnx2i_cmd *bnx2i_cmd;
+ struct bnx2i_text_request *text_wqe;
+ struct iscsi_text *text_hdr;
+ u32 dword;
+
+ bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data;
+ text_hdr = (struct iscsi_text *)mtask->hdr;
+ text_wqe = (struct bnx2i_text_request *) bnx2i_conn->ep->qp.sq_prod_qe;
+
+ memset(text_wqe, 0, sizeof(struct bnx2i_text_request));
+
+ text_wqe->op_code = text_hdr->opcode;
+ text_wqe->op_attr = text_hdr->flags;
+ text_wqe->data_length = ntoh24(text_hdr->dlength);
+ text_wqe->itt = mtask->itt |
+ (ISCSI_TASK_TYPE_MPATH << ISCSI_TEXT_REQUEST_TYPE_SHIFT);
+ text_wqe->ttt = be32_to_cpu(text_hdr->ttt);
+
+ text_wqe->cmd_sn = be32_to_cpu(text_hdr->cmdsn);
+
+ text_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
+ text_wqe->resp_bd_list_addr_hi =
+ (u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32);
+
+ dword = ((1 << ISCSI_TEXT_REQUEST_NUM_RESP_BDS_SHIFT) |
+ (bnx2i_conn->gen_pdu.resp_buf_size <<
+ ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
+ text_wqe->resp_buffer = dword;
+ text_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
+ text_wqe->bd_list_addr_hi =
+ (u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
+ text_wqe->num_bds = 1;
+ text_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+ bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+ return 0;
+}
+
+
+/**
* bnx2i_send_iscsi_scsicmd - post iSCSI scsicmd request WQE to hardware
* @conn: iscsi connection
* @cmd: driver command structure which is requesting
@@ -464,7 +527,6 @@ int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn,
* @conn: iscsi connection
* @cmd: driver command structure which is requesting
* a WQE to sent to chip for further processing
- * @ttt: TTT to be used when building pdu header
* @datap: payload buffer pointer
* @data_len: payload data length
* @unsol: indicated whether nopout pdu is unsolicited pdu or
@@ -473,7 +535,7 @@ int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn,
* prepare and post a nopout request WQE to CNIC firmware
*/
int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
- struct iscsi_task *task, u32 ttt,
+ struct iscsi_task *task,
char *datap, int data_len, int unsol)
{
struct bnx2i_endpoint *ep = bnx2i_conn->ep;
@@ -484,21 +546,24 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
nopout_hdr = (struct iscsi_nopout *)task->hdr;
nopout_wqe = (struct bnx2i_nop_out_request *)ep->qp.sq_prod_qe;
+
+ memset(nopout_wqe, 0x00, sizeof(struct bnx2i_nop_out_request));
+
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, 8);
if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
- u32 tmp = nopout_hdr->lun[0];
+ u32 tmp = nopout_wqe->lun[0];
/* 57710 requires LUN field to be swapped */
- nopout_hdr->lun[0] = nopout_hdr->lun[1];
- nopout_hdr->lun[1] = tmp;
+ nopout_wqe->lun[0] = nopout_wqe->lun[1];
+ nopout_wqe->lun[1] = tmp;
}
nopout_wqe->itt = ((u16)task->itt |
(ISCSI_TASK_TYPE_MPATH <<
ISCSI_TMF_REQUEST_TYPE_SHIFT));
- nopout_wqe->ttt = ttt;
+ nopout_wqe->ttt = be32_to_cpu(nopout_hdr->ttt);
nopout_wqe->flags = 0;
if (!unsol)
nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION;
@@ -562,6 +627,8 @@ int bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn,
logout_wqe->num_bds = 1;
logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+ bnx2i_conn->ep->state = EP_STATE_LOGOUT_SENT;
+
bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
return 0;
}
@@ -689,15 +756,16 @@ void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
/**
* bnx2i_send_conn_destroy - initiates iscsi connection teardown process
* @hba: adapter structure pointer
- * @ep: endpoint (transport indentifier) structure
+ * @ep: endpoint (transport identifier) structure
*
* this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate
* iscsi connection context clean-up process
*/
-void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+int bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
struct kwqe *kwqe_arr[2];
struct iscsi_kwqe_conn_destroy conn_cleanup;
+ int rc = -EINVAL;
memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy));
@@ -714,19 +782,21 @@ void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
kwqe_arr[0] = (struct kwqe *) &conn_cleanup;
if (hba->cnic && hba->cnic->submit_kwqes)
- hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1);
+
+ return rc;
}
/**
* bnx2i_570x_send_conn_ofld_req - initiates iscsi conn context setup process
* @hba: adapter structure pointer
- * @ep: endpoint (transport indentifier) structure
+ * @ep: endpoint (transport identifier) structure
*
* 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
*/
-static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
- struct bnx2i_endpoint *ep)
+static int bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
{
struct kwqe *kwqe_arr[2];
struct iscsi_kwqe_conn_offload1 ofld_req1;
@@ -734,6 +804,7 @@ static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
dma_addr_t dma_addr;
int num_kwqes = 2;
u32 *ptbl;
+ int rc = -EINVAL;
ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
ofld_req1.hdr.flags =
@@ -771,19 +842,21 @@ static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba,
ofld_req2.num_additional_wqes = 0;
if (hba->cnic && hba->cnic->submit_kwqes)
- hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
}
/**
* bnx2i_5771x_send_conn_ofld_req - initiates iscsi connection context creation
* @hba: adapter structure pointer
- * @ep: endpoint (transport indentifier) structure
+ * @ep: endpoint (transport identifier) structure
*
* 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE
*/
-static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
- struct bnx2i_endpoint *ep)
+static int bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
{
struct kwqe *kwqe_arr[5];
struct iscsi_kwqe_conn_offload1 ofld_req1;
@@ -792,6 +865,7 @@ static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
dma_addr_t dma_addr;
int num_kwqes = 2;
u32 *ptbl;
+ int rc = -EINVAL;
ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1;
ofld_req1.hdr.flags =
@@ -837,29 +911,35 @@ static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba,
num_kwqes += 1;
if (hba->cnic && hba->cnic->submit_kwqes)
- hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
}
/**
* bnx2i_send_conn_ofld_req - initiates iscsi connection context setup process
*
* @hba: adapter structure pointer
- * @ep: endpoint (transport indentifier) structure
+ * @ep: endpoint (transport identifier) structure
*
* this routine prepares and posts CONN_OFLD_REQ1/2 KWQE
*/
-void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
+int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
+ int rc;
+
if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
- bnx2i_5771x_send_conn_ofld_req(hba, ep);
+ rc = bnx2i_5771x_send_conn_ofld_req(hba, ep);
else
- bnx2i_570x_send_conn_ofld_req(hba, ep);
+ rc = bnx2i_570x_send_conn_ofld_req(hba, ep);
+
+ return rc;
}
/**
* setup_qp_page_tables - iscsi QP page table setup function
- * @ep: endpoint (transport indentifier) structure
+ * @ep: endpoint (transport identifier) structure
*
* Sets up page tables for SQ/RQ/CQ, 1G/sec (5706/5708/5709) devices requires
* 64-bit address in big endian format. Whereas 10G/sec (57710) requires
@@ -879,7 +959,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
/* SQ page table */
memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size);
- num_pages = ep->qp.sq_mem_size / PAGE_SIZE;
+ num_pages = ep->qp.sq_mem_size / CNIC_PAGE_SIZE;
page = ep->qp.sq_phys;
if (cnic_dev_10g)
@@ -893,7 +973,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) ((u64) page >> 32);
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
} else {
/* PTE is written in big endian format for
* 5706/5708/5709 devices */
@@ -901,13 +981,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) page;
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
}
/* RQ page table */
memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size);
- num_pages = ep->qp.rq_mem_size / PAGE_SIZE;
+ num_pages = ep->qp.rq_mem_size / CNIC_PAGE_SIZE;
page = ep->qp.rq_phys;
if (cnic_dev_10g)
@@ -921,7 +1001,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) ((u64) page >> 32);
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
} else {
/* PTE is written in big endian format for
* 5706/5708/5709 devices */
@@ -929,13 +1009,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) page;
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
}
/* CQ page table */
memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size);
- num_pages = ep->qp.cq_mem_size / PAGE_SIZE;
+ num_pages = ep->qp.cq_mem_size / CNIC_PAGE_SIZE;
page = ep->qp.cq_phys;
if (cnic_dev_10g)
@@ -949,7 +1029,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) ((u64) page >> 32);
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
} else {
/* PTE is written in big endian format for
* 5706/5708/5709 devices */
@@ -957,7 +1037,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
ptbl++;
*ptbl = (u32) page;
ptbl++;
- page += PAGE_SIZE;
+ page += CNIC_PAGE_SIZE;
}
}
}
@@ -966,7 +1046,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
/**
* bnx2i_alloc_qp_resc - allocates required resources for QP.
* @hba: adapter structure pointer
- * @ep: endpoint (transport indentifier) structure
+ * @ep: endpoint (transport identifier) structure
*
* Allocate QP (transport layer for iSCSI connection) resources, DMA'able
* memory for SQ/RQ/CQ and page tables. EP structure elements such
@@ -984,11 +1064,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
/* Allocate page table memory for SQ which is page aligned */
ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE;
ep->qp.sq_mem_size =
- (ep->qp.sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.sq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.sq_pgtbl_size =
- (ep->qp.sq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (ep->qp.sq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
ep->qp.sq_pgtbl_size =
- (ep->qp.sq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.sq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.sq_pgtbl_virt =
dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
@@ -1021,11 +1101,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
/* Allocate page table memory for CQ which is page aligned */
ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE;
ep->qp.cq_mem_size =
- (ep->qp.cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.cq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.cq_pgtbl_size =
- (ep->qp.cq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (ep->qp.cq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
ep->qp.cq_pgtbl_size =
- (ep->qp.cq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.cq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.cq_pgtbl_virt =
dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
@@ -1064,11 +1144,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
/* Allocate page table memory for RQ which is page aligned */
ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE;
ep->qp.rq_mem_size =
- (ep->qp.rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.rq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.rq_pgtbl_size =
- (ep->qp.rq_mem_size / PAGE_SIZE) * sizeof(void *);
+ (ep->qp.rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
ep->qp.rq_pgtbl_size =
- (ep->qp.rq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ (ep->qp.rq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
ep->qp.rq_pgtbl_virt =
dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
@@ -1111,7 +1191,7 @@ mem_alloc_err:
/**
* bnx2i_free_qp_resc - free memory resources held by QP
* @hba: adapter structure pointer
- * @ep: endpoint (transport indentifier) structure
+ * @ep: endpoint (transport identifier) structure
*
* Free QP resources - SQ/RQ/CQ memory and page tables.
*/
@@ -1184,10 +1264,13 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
int rc = 0;
u64 mask64;
+ memset(&iscsi_init, 0x00, sizeof(struct iscsi_kwqe_init1));
+ memset(&iscsi_init2, 0x00, sizeof(struct iscsi_kwqe_init2));
+
bnx2i_adjust_qp_size(hba);
iscsi_init.flags =
- ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
+ (CNIC_PAGE_BITS - 8) << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
if (en_tcp_dack)
iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
iscsi_init.reserved0 = 0;
@@ -1200,19 +1283,20 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
iscsi_init.dummy_buffer_addr_hi =
(u32) ((u64) hba->dummy_buf_dma >> 32);
+ hba->num_ccell = hba->max_sqes >> 1;
hba->ctx_ccell_tasks =
((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
iscsi_init.num_ccells_per_conn = hba->num_ccell;
iscsi_init.num_tasks_per_conn = hba->max_sqes;
- iscsi_init.sq_wqes_per_page = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+ iscsi_init.sq_wqes_per_page = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
iscsi_init.sq_num_wqes = hba->max_sqes;
iscsi_init.cq_log_wqes_per_page =
- (u8) bnx2i_power_of2(PAGE_SIZE / BNX2I_CQE_SIZE);
+ (u8) bnx2i_power_of2(CNIC_PAGE_SIZE / BNX2I_CQE_SIZE);
iscsi_init.cq_num_wqes = hba->max_cqes;
iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE +
- (PAGE_SIZE - 1)) / PAGE_SIZE;
+ (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE +
- (PAGE_SIZE - 1)) / PAGE_SIZE;
+ (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE;
iscsi_init.rq_num_wqes = hba->max_rqes;
@@ -1231,14 +1315,18 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN) |
/* EMC */
(1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN));
- if (error_mask1)
+ if (error_mask1) {
iscsi_init2.error_bit_map[0] = error_mask1;
- else
+ mask64 ^= (u32)(mask64);
+ mask64 |= error_mask1;
+ } else
iscsi_init2.error_bit_map[0] = (u32) mask64;
- if (error_mask2)
+ if (error_mask2) {
iscsi_init2.error_bit_map[1] = error_mask2;
- else
+ mask64 &= 0xffffffff;
+ mask64 |= ((u64)error_mask2 << 32);
+ } else
iscsi_init2.error_bit_map[1] = (u32) (mask64 >> 32);
iscsi_error_mask = mask64;
@@ -1254,24 +1342,26 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
/**
* bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion.
- * @conn: iscsi connection
+ * @session: iscsi session
+ * @bnx2i_conn: bnx2i connection
* @cqe: pointer to newly DMA'ed CQE entry for processing
*
* process SCSI CMD Response CQE & complete the request to SCSI-ML
*/
-static int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
- struct bnx2i_conn *bnx2i_conn,
- struct cqe *cqe)
+int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
+ struct bnx2i_conn *bnx2i_conn,
+ 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;
- struct iscsi_cmd_rsp *hdr;
+ struct iscsi_scsi_rsp *hdr;
u32 datalen = 0;
resp_cqe = (struct bnx2i_cmd_response *)cqe;
- spin_lock(&session->lock);
+ spin_lock_bh(&session->back_lock);
task = iscsi_itt_to_task(conn,
resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
if (!task)
@@ -1281,20 +1371,30 @@ static 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);
- hdr = (struct iscsi_cmd_rsp *)task->hdr;
+ hdr = (struct iscsi_scsi_rsp *)task->hdr;
resp_cqe = (struct bnx2i_cmd_response *)cqe;
hdr->opcode = resp_cqe->op_code;
hdr->max_cmdsn = cpu_to_be32(resp_cqe->max_cmd_sn);
@@ -1332,7 +1432,7 @@ done:
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
conn->data, datalen);
fail:
- spin_unlock(&session->lock);
+ spin_unlock_bh(&session->back_lock);
return 0;
}
@@ -1357,7 +1457,7 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
int pad_len;
login = (struct bnx2i_login_response *) cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
login->itt & ISCSI_LOGIN_RESPONSE_INDEX);
if (!task)
@@ -1400,10 +1500,72 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
bnx2i_conn->gen_pdu.resp_buf,
bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
+
+/**
+ * bnx2i_process_text_resp - this function handles iscsi text response
+ * @session: iscsi session pointer
+ * @bnx2i_conn: iscsi connection pointer
+ * @cqe: pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI Text Response CQE& complete it to open-iscsi user daemon
+ */
+static int bnx2i_process_text_resp(struct iscsi_session *session,
+ struct bnx2i_conn *bnx2i_conn,
+ struct cqe *cqe)
+{
+ struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+ struct iscsi_task *task;
+ struct bnx2i_text_response *text;
+ struct iscsi_text_rsp *resp_hdr;
+ int pld_len;
+ int pad_len;
+
+ text = (struct bnx2i_text_response *) cqe;
+ spin_lock(&session->back_lock);
+ task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX);
+ if (!task)
+ goto done;
+
+ resp_hdr = (struct iscsi_text_rsp *)&bnx2i_conn->gen_pdu.resp_hdr;
+ memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+ resp_hdr->opcode = text->op_code;
+ resp_hdr->flags = text->response_flags;
+ resp_hdr->hlength = 0;
+
+ hton24(resp_hdr->dlength, text->data_length);
+ resp_hdr->itt = task->hdr->itt;
+ resp_hdr->ttt = cpu_to_be32(text->ttt);
+ resp_hdr->statsn = task->hdr->exp_statsn;
+ resp_hdr->exp_cmdsn = cpu_to_be32(text->exp_cmd_sn);
+ resp_hdr->max_cmdsn = cpu_to_be32(text->max_cmd_sn);
+ pld_len = text->data_length;
+ bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf +
+ pld_len;
+ pad_len = 0;
+ if (pld_len & 0x3)
+ pad_len = 4 - (pld_len % 4);
+
+ if (pad_len) {
+ int i = 0;
+ for (i = 0; i < pad_len; i++) {
+ bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0;
+ bnx2i_conn->gen_pdu.resp_wr_ptr++;
+ }
+ }
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
+ bnx2i_conn->gen_pdu.resp_buf,
+ bnx2i_conn->gen_pdu.resp_wr_ptr -
+ bnx2i_conn->gen_pdu.resp_buf);
+done:
+ spin_unlock(&session->back_lock);
+ return 0;
+}
+
+
/**
* bnx2i_process_tmf_resp - this function handles iscsi TMF response
* @session: iscsi session pointer
@@ -1422,7 +1584,7 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session,
struct iscsi_tm_rsp *resp_hdr;
tmf_cqe = (struct bnx2i_tmf_response *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX);
if (!task)
@@ -1438,7 +1600,7 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session,
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
done:
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1461,7 +1623,7 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
struct iscsi_logout_rsp *resp_hdr;
logout = (struct bnx2i_logout_response *) cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX);
if (!task)
@@ -1482,8 +1644,10 @@ 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);
+ spin_unlock(&session->back_lock);
return 0;
}
@@ -1504,12 +1668,12 @@ static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
struct iscsi_task *task;
nop_in = (struct bnx2i_nop_in_msg *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
if (task)
- iscsi_put_task(task);
- spin_unlock(&session->lock);
+ __iscsi_put_task(task);
+ spin_unlock(&session->back_lock);
}
/**
@@ -1544,13 +1708,11 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
struct iscsi_task *task;
struct bnx2i_nop_in_msg *nop_in;
struct iscsi_nopin *hdr;
- u32 itt;
int tgt_async_nop = 0;
nop_in = (struct bnx2i_nop_in_msg *)cqe;
- itt = nop_in->itt & ISCSI_NOP_IN_MSG_INDEX;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
memset(hdr, 0, sizeof(struct iscsi_hdr));
hdr->opcode = nop_in->op_code;
@@ -1558,7 +1720,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn);
hdr->ttt = cpu_to_be32(nop_in->ttt);
- if (itt == (u16) RESERVED_ITT) {
+ if (nop_in->itt == (u16) RESERVED_ITT) {
bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
hdr->itt = RESERVED_ITT;
tgt_async_nop = 1;
@@ -1566,16 +1728,17 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
}
/* this is a response to one of our nop-outs */
- task = iscsi_itt_to_task(conn, itt);
+ task = iscsi_itt_to_task(conn,
+ (itt_t) (nop_in->itt & ISCSI_NOP_IN_MSG_INDEX));
if (task) {
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, 8);
}
done:
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
return tgt_async_nop;
}
@@ -1608,13 +1771,13 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session,
return;
}
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr;
memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
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, 8);
resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn);
resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn);
@@ -1627,7 +1790,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session,
__iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
(struct iscsi_hdr *)resp_hdr, NULL, 0);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
}
@@ -1654,7 +1817,7 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session,
} else
bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr;
memset(hdr, 0, sizeof(struct iscsi_hdr));
hdr->opcode = reject->op_code;
@@ -1665,7 +1828,7 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session,
hdr->ffffffff = cpu_to_be32(RESERVED_ITT);
__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
reject->data_length);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
}
/**
@@ -1685,48 +1848,175 @@ static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session,
struct iscsi_task *task;
cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe;
- spin_lock(&session->lock);
+ spin_lock(&session->back_lock);
task = iscsi_itt_to_task(conn,
cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
if (!task)
printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n",
cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
- spin_unlock(&session->lock);
+ spin_unlock(&session->back_lock);
complete(&bnx2i_conn->cmd_cleanup_cmpl);
}
+/**
+ * bnx2i_percpu_io_thread - thread per cpu for ios
+ *
+ * @arg: ptr to bnx2i_percpu_info structure
+ */
+int bnx2i_percpu_io_thread(void *arg)
+{
+ struct bnx2i_percpu_s *p = arg;
+ struct bnx2i_work *work, *tmp;
+ LIST_HEAD(work_list);
+
+ set_user_nice(current, MIN_NICE);
+
+ while (!kthread_should_stop()) {
+ spin_lock_bh(&p->p_work_lock);
+ while (!list_empty(&p->work_list)) {
+ list_splice_init(&p->work_list, &work_list);
+ spin_unlock_bh(&p->p_work_lock);
+
+ list_for_each_entry_safe(work, tmp, &work_list, list) {
+ list_del_init(&work->list);
+ /* work allocated in the bh, freed here */
+ bnx2i_process_scsi_cmd_resp(work->session,
+ work->bnx2i_conn,
+ &work->cqe);
+ atomic_dec(&work->bnx2i_conn->work_cnt);
+ kfree(work);
+ }
+ spin_lock_bh(&p->p_work_lock);
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_bh(&p->p_work_lock);
+ schedule();
+ }
+ __set_current_state(TASK_RUNNING);
+
+ return 0;
+}
+
+
+/**
+ * bnx2i_queue_scsi_cmd_resp - queue cmd completion to the percpu thread
+ * @bnx2i_conn: bnx2i connection
+ *
+ * this function is called by generic KCQ handler to queue all pending cmd
+ * completion CQEs
+ *
+ * The implementation is to queue the cmd response based on the
+ * last recorded command for the given connection. The
+ * cpu_id gets recorded upon task_xmit. No out-of-order completion!
+ */
+static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
+ struct bnx2i_conn *bnx2i_conn,
+ struct bnx2i_nop_in_msg *cqe)
+{
+ struct bnx2i_work *bnx2i_work = NULL;
+ struct bnx2i_percpu_s *p = NULL;
+ struct iscsi_task *task;
+ struct scsi_cmnd *sc;
+ int rc = 0;
+ int cpu;
+
+ spin_lock(&session->back_lock);
+ task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
+ cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
+ if (!task || !task->sc) {
+ spin_unlock(&session->back_lock);
+ return -EINVAL;
+ }
+ sc = task->sc;
+
+ if (!blk_rq_cpu_valid(sc->request))
+ cpu = smp_processor_id();
+ else
+ cpu = sc->request->cpu;
+
+ spin_unlock(&session->back_lock);
+
+ p = &per_cpu(bnx2i_percpu, cpu);
+ spin_lock(&p->p_work_lock);
+ if (unlikely(!p->iothread)) {
+ rc = -EINVAL;
+ goto err;
+ }
+ /* Alloc and copy to the cqe */
+ bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC);
+ if (bnx2i_work) {
+ INIT_LIST_HEAD(&bnx2i_work->list);
+ bnx2i_work->session = session;
+ bnx2i_work->bnx2i_conn = bnx2i_conn;
+ memcpy(&bnx2i_work->cqe, cqe, sizeof(struct cqe));
+ list_add_tail(&bnx2i_work->list, &p->work_list);
+ atomic_inc(&bnx2i_conn->work_cnt);
+ wake_up_process(p->iothread);
+ spin_unlock(&p->p_work_lock);
+ goto done;
+ } else
+ rc = -ENOMEM;
+err:
+ spin_unlock(&p->p_work_lock);
+ bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, (struct cqe *)cqe);
+done:
+ return rc;
+}
+
/**
* bnx2i_process_new_cqes - process newly DMA'ed CQE's
- * @bnx2i_conn: iscsi connection
+ * @bnx2i_conn: bnx2i connection
*
* this function is called by generic KCQ handler to process all pending CQE's
*/
-static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
+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 qp_info *qp = &bnx2i_conn->ep->qp;
+ struct bnx2i_hba *hba = bnx2i_conn->hba;
+ struct qp_info *qp;
struct bnx2i_nop_in_msg *nopin;
int tgt_async_msg;
+ int cqe_cnt = 0;
+
+ if (bnx2i_conn->ep == NULL)
+ return 0;
+ qp = &bnx2i_conn->ep->qp;
+
+ if (!qp->cq_virt) {
+ printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!",
+ hba->netdev->name);
+ goto out;
+ }
while (1) {
nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe;
if (nopin->cq_req_sn != qp->cqe_exp_seq_sn)
break;
- if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx)))
+ if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx))) {
+ if (nopin->op_code == ISCSI_OP_NOOP_IN &&
+ nopin->itt == (u16) RESERVED_ITT) {
+ printk(KERN_ALERT "bnx2i: Unsolicited "
+ "NOP-In detected for suspended "
+ "connection dev=%s!\n",
+ hba->netdev->name);
+ bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
+ goto cqe_out;
+ }
break;
-
+ }
tgt_async_msg = 0;
switch (nopin->op_code) {
case ISCSI_OP_SCSI_CMD_RSP:
case ISCSI_OP_SCSI_DATA_IN:
- bnx2i_process_scsi_cmd_resp(session, bnx2i_conn,
- qp->cq_cons_qe);
- break;
+ /* 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);
+ goto done;
case ISCSI_OP_LOGIN_RSP:
bnx2i_process_login_resp(session, bnx2i_conn,
qp->cq_cons_qe);
@@ -1735,6 +2025,10 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
bnx2i_process_tmf_resp(session, bnx2i_conn,
qp->cq_cons_qe);
break;
+ case ISCSI_OP_TEXT_RSP:
+ bnx2i_process_text_resp(session, bnx2i_conn,
+ qp->cq_cons_qe);
+ break;
case ISCSI_OP_LOGOUT_RSP:
bnx2i_process_logout_resp(session, bnx2i_conn,
qp->cq_cons_qe);
@@ -1766,13 +2060,24 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
nopin->op_code);
}
- if (!tgt_async_msg)
- bnx2i_conn->ep->num_active_cmds--;
-
+ 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! "
+ "op 0x%x\n",
+ hba->netdev->name,
+ nopin->op_code);
+ else
+ atomic_dec(&bnx2i_conn->ep->num_active_cmds);
+ }
+cqe_out:
/* clear out in production version only, till beta keep opcode
* field intact, will be helpful in debugging (context dump)
* nopin->op_code = 0;
*/
+ cqe_cnt++;
qp->cqe_exp_seq_sn++;
if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1))
qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN;
@@ -1785,7 +2090,8 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
qp->cq_cons_idx++;
}
}
- bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
+out:
+ return cqe_cnt;
}
/**
@@ -1799,22 +2105,27 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
static void bnx2i_fastpath_notification(struct bnx2i_hba *hba,
struct iscsi_kcqe *new_cqe_kcqe)
{
- struct bnx2i_conn *conn;
+ struct bnx2i_conn *bnx2i_conn;
u32 iscsi_cid;
+ int nxt_idx;
iscsi_cid = new_cqe_kcqe->iscsi_conn_id;
- conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
+ bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
- if (!conn) {
+ if (!bnx2i_conn) {
printk(KERN_ALERT "cid #%x not valid\n", iscsi_cid);
return;
}
- if (!conn->ep) {
+ if (!bnx2i_conn->ep) {
printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid);
return;
}
- bnx2i_process_new_cqes(conn);
+ bnx2i_process_new_cqes(bnx2i_conn);
+ nxt_idx = bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep,
+ CNIC_ARM_CQE_FP);
+ if (nxt_idx && nxt_idx == bnx2i_process_new_cqes(bnx2i_conn))
+ bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP);
}
@@ -2149,11 +2460,24 @@ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba,
}
if (ofld_kcqe->completion_status) {
+ ep->state = EP_STATE_OFLD_FAILED;
if (ofld_kcqe->completion_status ==
ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE)
- printk(KERN_ALERT "bnx2i: unable to allocate"
- " iSCSI context resources\n");
- ep->state = EP_STATE_OFLD_FAILED;
+ printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - unable "
+ "to allocate iSCSI context resources\n",
+ hba->netdev->name);
+ else if (ofld_kcqe->completion_status ==
+ ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE)
+ printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
+ "opcode\n", hba->netdev->name);
+ else if (ofld_kcqe->completion_status ==
+ ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY)
+ /* error status code valid only for 5771x chipset */
+ ep->state = EP_STATE_OFLD_FAILED_CID_BUSY;
+ else
+ printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
+ "error code %d\n", hba->netdev->name,
+ ofld_kcqe->completion_status);
} else {
ep->state = EP_STATE_OFLD_COMPL;
cid_addr = ofld_kcqe->iscsi_conn_context_id;
@@ -2221,14 +2545,20 @@ 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
*
* Handles four netdev events, NETDEV_UP, NETDEV_DOWN,
* NETDEV_GOING_DOWN and NETDEV_CHANGE
*/
-static void bnx2i_indicate_netevent(void *context, unsigned long event)
+static void bnx2i_indicate_netevent(void *context, unsigned long event,
+ u16 vlan_id)
{
struct bnx2i_hba *hba = context;
+ /* Ignore all netevent coming from vlans */
+ if (vlan_id != 0)
+ return;
+
switch (event) {
case NETDEV_UP:
if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
@@ -2334,26 +2664,32 @@ static void bnx2i_cm_remote_close(struct cnic_sock *cm_sk)
static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk)
{
struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context;
+ u32 old_state = ep->state;
ep->state = EP_STATE_TCP_RST_RCVD;
- if (ep->conn)
- bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
+ if (old_state == EP_STATE_DISCONN_START)
+ wake_up_interruptible(&ep->ofld_wait);
+ else
+ if (ep->conn)
+ bnx2i_recovery_que_add_conn(ep->hba, ep->conn);
}
-static void bnx2i_send_nl_mesg(struct cnic_dev *dev, u32 msg_type,
- char *buf, u16 buflen)
+static int bnx2i_send_nl_mesg(void *context, u32 msg_type,
+ char *buf, u16 buflen)
{
- struct bnx2i_hba *hba;
+ struct bnx2i_hba *hba = context;
+ int rc;
- hba = bnx2i_find_hba_for_cnic(dev);
if (!hba)
- return;
+ return -ENODEV;
- if (iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
- msg_type, buf, buflen))
+ rc = iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport,
+ msg_type, buf, buflen);
+ if (rc)
printk(KERN_ALERT "bnx2i: private nl message send error\n");
+ return rc;
}
@@ -2375,6 +2711,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
};
@@ -2401,12 +2738,11 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
reg_base = pci_resource_start(ep->hba->pcidev,
BNX2X_DOORBELL_PCI_BAR);
- reg_off = PAGE_SIZE * (cid_num & 0x1FFFF) + DPM_TRIGER_TYPE;
+ reg_off = (1 << BNX2X_DB_SHIFT) * (cid_num & 0x1FFFF);
ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4);
goto arm_cq;
}
- reg_base = ep->hba->netdev->base_addr;
if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) &&
(ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) {
config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2);
@@ -2422,7 +2758,7 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
/* 5709 device in normal node and 5706/5708 devices */
reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
- ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off,
+ ep->qp.ctx_base = ioremap_nocache(ep->hba->reg_base + reg_off,
MB_KERNEL_CTX_SIZE);
if (!ep->qp.ctx_base)
return -ENOMEM;
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index af6a00a600f..80c03b452d6 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -1,6 +1,6 @@
/* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -9,6 +9,7 @@
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include "bnx2i.h"
@@ -17,17 +18,19 @@ 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.1.1"
-#define DRV_MODULE_RELDATE "Mar 24, 2010"
+#define DRV_MODULE_VERSION "2.7.6.2"
+#define DRV_MODULE_RELDATE "Jun 06, 2013"
-static char version[] __devinitdata =
+static char version[] =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
" v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
-MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711"
- " iSCSI Driver");
+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_VERSION(DRV_MODULE_VERSION);
@@ -37,7 +40,7 @@ unsigned int event_coal_min = 24;
module_param(event_coal_min, int, 0664);
MODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands");
-unsigned int event_coal_div = 1;
+unsigned int event_coal_div = 2;
module_param(event_coal_div, int, 0664);
MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor");
@@ -46,11 +49,11 @@ module_param(en_tcp_dack, int, 0664);
MODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK");
unsigned int error_mask1 = 0x00;
-module_param(error_mask1, int, 0664);
+module_param(error_mask1, uint, 0664);
MODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1");
unsigned int error_mask2 = 0x00;
-module_param(error_mask2, int, 0664);
+module_param(error_mask2, uint, 0664);
MODULE_PARM_DESC(error_mask2, "Config FW iSCSI Error Mask #2");
unsigned int sq_size;
@@ -63,37 +66,46 @@ MODULE_PARM_DESC(rq_size, "Configure RQ size");
u64 iscsi_error_mask = 0x00;
-static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) ;
+DEFINE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
+
+static int bnx2i_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu);
+/* notification function for CPU hotplug events */
+static struct notifier_block bnx2i_cpu_notifier = {
+ .notifier_call = bnx2i_cpu_callback,
+};
/**
* bnx2i_identify_device - identifies NetXtreme II device type
* @hba: Adapter structure pointer
+ * @cnic: Corresponding cnic device
*
* This function identifies the NX2 device type and sets appropriate
* queue mailbox register access method, 5709 requires driver to
* access MBOX regs using *bin* mode
*/
-void bnx2i_identify_device(struct bnx2i_hba *hba)
+void bnx2i_identify_device(struct bnx2i_hba *hba, struct cnic_dev *dev)
{
hba->cnic_dev_type = 0;
- if ((hba->pci_did == PCI_DEVICE_ID_NX2_5706) ||
- (hba->pci_did == PCI_DEVICE_ID_NX2_5706S))
- set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type);
- else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5708) ||
- (hba->pci_did == PCI_DEVICE_ID_NX2_5708S))
- set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type);
- else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5709) ||
- (hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) {
- set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
- hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
- } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 ||
- hba->pci_did == PCI_DEVICE_ID_NX2_57711 ||
- hba->pci_did == PCI_DEVICE_ID_NX2_57711E)
+ if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
+ if (hba->pci_did == PCI_DEVICE_ID_NX2_5706 ||
+ hba->pci_did == PCI_DEVICE_ID_NX2_5706S) {
+ set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type);
+ } else if (hba->pci_did == PCI_DEVICE_ID_NX2_5708 ||
+ hba->pci_did == PCI_DEVICE_ID_NX2_5708S) {
+ set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type);
+ } else if (hba->pci_did == PCI_DEVICE_ID_NX2_5709 ||
+ hba->pci_did == PCI_DEVICE_ID_NX2_5709S) {
+ set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
+ hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
+ }
+ } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type);
- else
+ } else {
printk(KERN_ALERT "bnx2i: unknown device, 0x%x\n",
hba->pci_did);
+ }
}
@@ -160,13 +172,51 @@ void bnx2i_start(void *handle)
struct bnx2i_hba *hba = handle;
int i = HZ;
+ /* On some bnx2x devices, it is possible that iSCSI is no
+ * longer supported after firmware is downloaded. In that
+ * case, the iscsi_init_msg will return failure.
+ */
+
bnx2i_send_fw_iscsi_init_msg(hba);
- while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--)
+ while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) &&
+ !test_bit(ADAPTER_STATE_INIT_FAILED, &hba->adapter_state) && i--)
msleep(BNX2I_INIT_POLL_TIME);
}
/**
+ * bnx2i_chip_cleanup - local routine to handle chip cleanup
+ * @hba: Adapter instance to register
+ *
+ * Driver checks if adapter still has any active connections before
+ * executing the cleanup process
+ */
+static void bnx2i_chip_cleanup(struct bnx2i_hba *hba)
+{
+ struct bnx2i_endpoint *bnx2i_ep;
+ struct list_head *pos, *tmp;
+
+ if (hba->ofld_conns_active) {
+ /* Stage to force the disconnection
+ * This is the case where the daemon is either slow or
+ * not present
+ */
+ printk(KERN_ALERT "bnx2i: (%s) chip cleanup for %d active "
+ "connections\n", hba->netdev->name,
+ hba->ofld_conns_active);
+ mutex_lock(&hba->net_dev_lock);
+ list_for_each_safe(pos, tmp, &hba->ep_active_list) {
+ bnx2i_ep = list_entry(pos, struct bnx2i_endpoint, link);
+ /* Clean up the chip only */
+ bnx2i_hw_ep_disconnect(bnx2i_ep);
+ bnx2i_ep->cm_sk = NULL;
+ }
+ mutex_unlock(&hba->net_dev_lock);
+ }
+}
+
+
+/**
* bnx2i_stop - cnic callback to shutdown adapter instance
* @handle: transparent handle pointing to adapter structure
*
@@ -176,105 +226,46 @@ void bnx2i_start(void *handle)
void bnx2i_stop(void *handle)
{
struct bnx2i_hba *hba = handle;
+ int conns_active;
+ int wait_delay = 1 * HZ;
/* check if cleanup happened in GOING_DOWN context */
- if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
- &hba->adapter_state))
+ if (!test_and_set_bit(ADAPTER_STATE_GOING_DOWN,
+ &hba->adapter_state)) {
iscsi_host_for_each_session(hba->shost,
bnx2i_drop_session);
-
+ wait_delay = hba->hba_shutdown_tmo;
+ }
+ /* Wait for inflight offload connection tasks to complete before
+ * proceeding. Forcefully terminate all connection recovery in
+ * progress at the earliest, either in bind(), send_pdu(LOGIN),
+ * or conn_start()
+ */
+ wait_event_interruptible_timeout(hba->eh_wait,
+ (list_empty(&hba->ep_ofld_list) &&
+ list_empty(&hba->ep_destroy_list)),
+ 2 * HZ);
/* Wait for all endpoints to be torn down, Chip will be reset once
* control returns to network driver. So it is required to cleanup and
* release all connection resources before returning from this routine.
*/
- wait_event_interruptible_timeout(hba->eh_wait,
- (hba->ofld_conns_active == 0),
- hba->hba_shutdown_tmo);
+ while (hba->ofld_conns_active) {
+ conns_active = hba->ofld_conns_active;
+ wait_event_interruptible_timeout(hba->eh_wait,
+ (hba->ofld_conns_active != conns_active),
+ wait_delay);
+ if (hba->ofld_conns_active == conns_active)
+ break;
+ }
+ bnx2i_chip_cleanup(hba);
+
/* 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);
}
-/**
- * bnx2i_register_device - register bnx2i adapter instance with the cnic driver
- * @hba: Adapter instance to register
- *
- * registers bnx2i adapter instance with the cnic driver while holding the
- * adapter structure lock
- */
-void bnx2i_register_device(struct bnx2i_hba *hba)
-{
- int rc;
-
- if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
- test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
- return;
- }
-
- rc = hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
-
- if (!rc)
- set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-}
-
-
-/**
- * bnx2i_reg_dev_all - registers all adapter instances with the cnic driver
- *
- * registers all bnx2i adapter instances with the cnic driver while holding
- * the global resource lock
- */
-void bnx2i_reg_dev_all(void)
-{
- struct bnx2i_hba *hba, *temp;
-
- mutex_lock(&bnx2i_dev_lock);
- list_for_each_entry_safe(hba, temp, &adapter_list, link)
- bnx2i_register_device(hba);
- mutex_unlock(&bnx2i_dev_lock);
-}
-
-
-/**
- * bnx2i_unreg_one_device - unregister adapter instance with the cnic driver
- * @hba: Adapter instance to unregister
- *
- * registers bnx2i adapter instance with the cnic driver while holding
- * the adapter structure lock
- */
-static void bnx2i_unreg_one_device(struct bnx2i_hba *hba)
-{
- if (hba->ofld_conns_active ||
- !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) ||
- test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state))
- return;
-
- hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
-
- /* ep_disconnect could come before NETDEV_DOWN, driver won't
- * see NETDEV_DOWN as it already unregistered itself.
- */
- hba->adapter_state = 0;
- clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-}
-
-/**
- * bnx2i_unreg_dev_all - unregisters all bnx2i instances with the cnic driver
- *
- * unregisters all bnx2i adapter instances with the cnic driver while holding
- * the global resource lock
- */
-void bnx2i_unreg_dev_all(void)
-{
- struct bnx2i_hba *hba, *temp;
-
- mutex_lock(&bnx2i_dev_lock);
- list_for_each_entry_safe(hba, temp, &adapter_list, link)
- bnx2i_unreg_one_device(hba);
- mutex_unlock(&bnx2i_dev_lock);
-}
-
/**
* bnx2i_init_one - initialize an adapter instance and allocate memory resources
@@ -290,6 +281,13 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
int rc;
mutex_lock(&bnx2i_dev_lock);
+ if (!cnic->max_iscsi_conn) {
+ printk(KERN_ALERT "bnx2i: dev %s does not support "
+ "iSCSI\n", hba->netdev->name);
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
hba->cnic = cnic;
rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
if (!rc) {
@@ -307,6 +305,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);
+out:
mutex_unlock(&bnx2i_dev_lock);
return rc;
@@ -371,6 +370,132 @@ 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;
+
+ strlcpy(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;
+
+ 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
+ *
+ * @cpu: cpu index for the online cpu
+ */
+static void bnx2i_percpu_thread_create(unsigned int cpu)
+{
+ struct bnx2i_percpu_s *p;
+ struct task_struct *thread;
+
+ p = &per_cpu(bnx2i_percpu, cpu);
+
+ thread = kthread_create_on_node(bnx2i_percpu_io_thread, (void *)p,
+ cpu_to_node(cpu),
+ "bnx2i_thread/%d", cpu);
+ /* bind thread to the cpu */
+ if (likely(!IS_ERR(thread))) {
+ kthread_bind(thread, cpu);
+ p->iothread = thread;
+ wake_up_process(thread);
+ }
+}
+
+
+static void bnx2i_percpu_thread_destroy(unsigned int cpu)
+{
+ struct bnx2i_percpu_s *p;
+ struct task_struct *thread;
+ struct bnx2i_work *work, *tmp;
+
+ /* Prevent any new work from being queued for this CPU */
+ p = &per_cpu(bnx2i_percpu, cpu);
+ spin_lock_bh(&p->p_work_lock);
+ thread = p->iothread;
+ p->iothread = NULL;
+
+ /* Free all work in the list */
+ list_for_each_entry_safe(work, tmp, &p->work_list, list) {
+ list_del_init(&work->list);
+ bnx2i_process_scsi_cmd_resp(work->session,
+ work->bnx2i_conn, &work->cqe);
+ kfree(work);
+ }
+
+ spin_unlock_bh(&p->p_work_lock);
+ if (thread)
+ kthread_stop(thread);
+}
+
+
+/**
+ * bnx2i_cpu_callback - Handler for CPU hotplug events
+ *
+ * @nfb: The callback data block
+ * @action: The event triggering the callback
+ * @hcpu: The index of the CPU that the event is for
+ *
+ * This creates or destroys per-CPU data for iSCSI
+ *
+ * Returns NOTIFY_OK always.
+ */
+static int bnx2i_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned cpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ printk(KERN_INFO "bnx2i: CPU %x online: Create Rx thread\n",
+ cpu);
+ bnx2i_percpu_thread_create(cpu);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ printk(KERN_INFO "CPU %x offline: Remove Rx thread\n", cpu);
+ bnx2i_percpu_thread_destroy(cpu);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+
+/**
* bnx2i_mod_init - module init entry point
*
* initialize any driver wide global data structures such as endpoint pool,
@@ -380,6 +505,8 @@ void bnx2i_ulp_exit(struct cnic_dev *dev)
static int __init bnx2i_mod_init(void)
{
int err;
+ unsigned cpu = 0;
+ struct bnx2i_percpu_s *p;
printk(KERN_INFO "%s", version);
@@ -402,6 +529,24 @@ static int __init bnx2i_mod_init(void)
goto unreg_xport;
}
+ /* Create percpu kernel threads to handle iSCSI I/O completions */
+ for_each_possible_cpu(cpu) {
+ p = &per_cpu(bnx2i_percpu, cpu);
+ INIT_LIST_HEAD(&p->work_list);
+ spin_lock_init(&p->p_work_lock);
+ p->iothread = NULL;
+ }
+
+ cpu_notifier_register_begin();
+
+ for_each_online_cpu(cpu)
+ bnx2i_percpu_thread_create(cpu);
+
+ /* Initialize per CPU interrupt thread */
+ __register_hotcpu_notifier(&bnx2i_cpu_notifier);
+
+ cpu_notifier_register_done();
+
return 0;
unreg_xport:
@@ -422,6 +567,7 @@ out:
static void __exit bnx2i_mod_exit(void)
{
struct bnx2i_hba *hba;
+ unsigned cpu = 0;
mutex_lock(&bnx2i_dev_lock);
while (!list_empty(&adapter_list)) {
@@ -430,6 +576,7 @@ static void __exit bnx2i_mod_exit(void)
adapter_count--;
if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+ bnx2i_chip_cleanup(hba);
hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
}
@@ -438,6 +585,15 @@ static void __exit bnx2i_mod_exit(void)
}
mutex_unlock(&bnx2i_dev_lock);
+ cpu_notifier_register_begin();
+
+ for_each_online_cpu(cpu)
+ bnx2i_percpu_thread_destroy(cpu);
+
+ __unregister_hotcpu_notifier(&bnx2i_cpu_notifier);
+
+ cpu_notifier_register_done();
+
iscsi_unregister_transport(&bnx2i_iscsi_transport);
cnic_unregister_driver(CNIC_ULP_ISCSI);
}
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index fa68ab34b99..166543f7ef5 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1,7 +1,7 @@
/*
* bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2006 - 2009 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
* Copyright (c) 2007, 2008 Mike Christie
*
@@ -10,6 +10,7 @@
* the Free Software Foundation.
*
* Written by: Anil Veerabhadrappa (anilgv@broadcom.com)
+ * Maintained by: Eddie Wai (eddie.wai@broadcom.com)
*/
#include <linux/slab.h>
@@ -26,6 +27,7 @@ static struct scsi_host_template bnx2i_host_template;
*/
static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */
+DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
static int bnx2i_adapter_ready(struct bnx2i_hba *hba)
{
@@ -378,6 +380,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
{
struct iscsi_endpoint *ep;
struct bnx2i_endpoint *bnx2i_ep;
+ u32 ec_div;
ep = iscsi_create_endpoint(sizeof(*bnx2i_ep));
if (!ep) {
@@ -386,11 +389,17 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
}
bnx2i_ep = ep->dd_data;
+ bnx2i_ep->cls_ep = ep;
INIT_LIST_HEAD(&bnx2i_ep->link);
bnx2i_ep->state = EP_STATE_IDLE;
bnx2i_ep->ep_iscsi_cid = (u16) -1;
bnx2i_ep->hba = hba;
bnx2i_ep->hba_age = hba->age;
+
+ ec_div = event_coal_div;
+ while (ec_div >>= 1)
+ bnx2i_ep->ec_shift += 1;
+
hba->ofld_conns_active++;
init_waitqueue_head(&bnx2i_ep->ofld_wait);
return ep;
@@ -410,7 +419,9 @@ static void bnx2i_free_ep(struct iscsi_endpoint *ep)
bnx2i_ep->state = EP_STATE_IDLE;
bnx2i_ep->hba->ofld_conns_active--;
- bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid);
+ if (bnx2i_ep->ep_iscsi_cid != (u16) -1)
+ bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid);
+
if (bnx2i_ep->conn) {
bnx2i_ep->conn->ep = NULL;
bnx2i_ep->conn = NULL;
@@ -514,7 +525,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
struct iscsi_bd *mp_bdt;
u64 addr;
- hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&hba->mp_bd_dma, GFP_KERNEL);
if (!hba->mp_bd_tbl) {
printk(KERN_ERR "unable to allocate Middle Path BDT\n");
@@ -522,11 +533,12 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
goto out;
}
- hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev,
+ CNIC_PAGE_SIZE,
&hba->dummy_buf_dma, GFP_KERNEL);
if (!hba->dummy_buffer) {
printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n");
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->mp_bd_tbl, hba->mp_bd_dma);
hba->mp_bd_tbl = NULL;
rc = -1;
@@ -537,7 +549,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
addr = (unsigned long) hba->dummy_buf_dma;
mp_bdt->buffer_addr_lo = addr & 0xffffffff;
mp_bdt->buffer_addr_hi = addr >> 32;
- mp_bdt->buffer_length = PAGE_SIZE;
+ mp_bdt->buffer_length = CNIC_PAGE_SIZE;
mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
ISCSI_BD_FIRST_IN_BD_CHAIN;
out:
@@ -554,12 +566,12 @@ out:
static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba)
{
if (hba->mp_bd_tbl) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->mp_bd_tbl, hba->mp_bd_dma);
hba->mp_bd_tbl = NULL;
}
if (hba->dummy_buffer) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->dummy_buffer, hba->dummy_buf_dma);
hba->dummy_buffer = NULL;
}
@@ -585,7 +597,7 @@ void bnx2i_drop_session(struct iscsi_cls_session *cls_session)
/**
* bnx2i_ep_destroy_list_add - add an entry to EP destroy list
* @hba: pointer to adapter instance
- * @ep: pointer to endpoint (transport indentifier) structure
+ * @ep: pointer to endpoint (transport identifier) structure
*
* EP destroy queue manager
*/
@@ -602,7 +614,7 @@ static int bnx2i_ep_destroy_list_add(struct bnx2i_hba *hba,
* bnx2i_ep_destroy_list_del - add an entry to EP destroy list
*
* @hba: pointer to adapter instance
- * @ep: pointer to endpoint (transport indentifier) structure
+ * @ep: pointer to endpoint (transport identifier) structure
*
* EP destroy queue manager
*/
@@ -619,7 +631,7 @@ static int bnx2i_ep_destroy_list_del(struct bnx2i_hba *hba,
/**
* bnx2i_ep_ofld_list_add - add an entry to ep offload pending list
* @hba: pointer to adapter instance
- * @ep: pointer to endpoint (transport indentifier) structure
+ * @ep: pointer to endpoint (transport identifier) structure
*
* pending conn offload completion queue manager
*/
@@ -635,7 +647,7 @@ static int bnx2i_ep_ofld_list_add(struct bnx2i_hba *hba,
/**
* bnx2i_ep_ofld_list_del - add an entry to ep offload pending list
* @hba: pointer to adapter instance
- * @ep: pointer to endpoint (transport indentifier) structure
+ * @ep: pointer to endpoint (transport identifier) structure
*
* pending conn offload completion queue manager
*/
@@ -678,7 +690,6 @@ bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid)
return ep;
}
-
/**
* bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list
* @hba: pointer to adapter instance
@@ -709,6 +720,38 @@ bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid)
}
/**
+ * bnx2i_ep_active_list_add - add an entry to ep active list
+ * @hba: pointer to adapter instance
+ * @ep: pointer to endpoint (transport identifier) structure
+ *
+ * current active conn queue manager
+ */
+static void bnx2i_ep_active_list_add(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
+{
+ write_lock_bh(&hba->ep_rdwr_lock);
+ list_add_tail(&ep->link, &hba->ep_active_list);
+ write_unlock_bh(&hba->ep_rdwr_lock);
+}
+
+
+/**
+ * bnx2i_ep_active_list_del - deletes an entry to ep active list
+ * @hba: pointer to adapter instance
+ * @ep: pointer to endpoint (transport identifier) structure
+ *
+ * current active conn queue manager
+ */
+static void bnx2i_ep_active_list_del(struct bnx2i_hba *hba,
+ struct bnx2i_endpoint *ep)
+{
+ write_lock_bh(&hba->ep_rdwr_lock);
+ list_del_init(&ep->link);
+ write_unlock_bh(&hba->ep_rdwr_lock);
+}
+
+
+/**
* bnx2i_setup_host_queue_size - assigns shost->can_queue param
* @hba: pointer to adapter instance
* @shost: scsi host pointer
@@ -766,16 +809,16 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
hba->pci_func = PCI_FUNC(hba->pcidev->devfn);
hba->pci_devno = PCI_SLOT(hba->pcidev->devfn);
- bnx2i_identify_device(hba);
+ bnx2i_identify_device(hba, cnic);
bnx2i_setup_host_queue_size(hba, shost);
+ hba->reg_base = pci_resource_start(hba->pcidev, 0);
if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
- hba->regview = ioremap_nocache(hba->netdev->base_addr,
- BNX2_MQ_CONFIG2);
+ hba->regview = pci_iomap(hba->pcidev, 0, BNX2_MQ_CONFIG2);
if (!hba->regview)
goto ioreg_map_err;
} else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
- hba->regview = ioremap_nocache(hba->netdev->base_addr, 4096);
+ hba->regview = pci_iomap(hba->pcidev, 0, 4096);
if (!hba->regview)
goto ioreg_map_err;
}
@@ -784,6 +827,7 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
goto mp_bdt_mem_err;
INIT_LIST_HEAD(&hba->ep_ofld_list);
+ INIT_LIST_HEAD(&hba->ep_active_list);
INIT_LIST_HEAD(&hba->ep_destroy_list);
rwlock_init(&hba->ep_rdwr_lock);
@@ -821,10 +865,20 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
spin_lock_init(&hba->lock);
mutex_init(&hba->net_dev_lock);
init_waitqueue_head(&hba->eh_wait);
- if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
- hba->hba_shutdown_tmo = 240 * HZ;
- else /* 5706/5708/5709 */
+ if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
hba->hba_shutdown_tmo = 30 * HZ;
+ hba->conn_teardown_tmo = 20 * HZ;
+ hba->conn_ctx_destroy_tmo = 6 * HZ;
+ } else { /* 5706/5708/5709 */
+ hba->hba_shutdown_tmo = 20 * HZ;
+ hba->conn_teardown_tmo = 10 * HZ;
+ hba->conn_ctx_destroy_tmo = 2 * HZ;
+ }
+
+#ifdef CONFIG_32BIT
+ spin_lock_init(&hba->stat_lock);
+#endif
+ memset(&hba->stats, 0, sizeof(struct iscsi_stats_info));
if (iscsi_host_add(shost, &hba->pcidev->dev))
goto free_dump_mem;
@@ -836,7 +890,7 @@ cid_que_err:
bnx2i_free_mp_bdt(hba);
mp_bdt_mem_err:
if (hba->regview) {
- iounmap(hba->regview);
+ pci_iounmap(hba->pcidev, hba->regview);
hba->regview = NULL;
}
ioreg_map_err:
@@ -857,11 +911,12 @@ void bnx2i_free_hba(struct bnx2i_hba *hba)
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);
pci_dev_put(hba->pcidev);
if (hba->regview) {
- iounmap(hba->regview);
+ pci_iounmap(hba->pcidev, hba->regview);
hba->regview = NULL;
}
bnx2i_free_mp_bdt(hba);
@@ -880,14 +935,14 @@ static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba,
struct bnx2i_conn *bnx2i_conn)
{
if (bnx2i_conn->gen_pdu.resp_bd_tbl) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
bnx2i_conn->gen_pdu.resp_bd_tbl,
bnx2i_conn->gen_pdu.resp_bd_dma);
bnx2i_conn->gen_pdu.resp_bd_tbl = NULL;
}
if (bnx2i_conn->gen_pdu.req_bd_tbl) {
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
bnx2i_conn->gen_pdu.req_bd_tbl,
bnx2i_conn->gen_pdu.req_bd_dma);
bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
@@ -944,13 +999,13 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf;
bnx2i_conn->gen_pdu.req_bd_tbl =
- dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL);
if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL)
goto login_req_bd_tbl_failure;
bnx2i_conn->gen_pdu.resp_bd_tbl =
- dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&bnx2i_conn->gen_pdu.resp_bd_dma,
GFP_KERNEL);
if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL)
@@ -959,7 +1014,7 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
return 0;
login_resp_bd_tbl_failure:
- dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
bnx2i_conn->gen_pdu.req_bd_tbl,
bnx2i_conn->gen_pdu.req_bd_dma);
bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
@@ -1039,11 +1094,9 @@ static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task)
buf = bnx2i_conn->gen_pdu.req_buf;
if (data_len)
rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task,
- RESERVED_ITT,
buf, data_len, 1);
else
rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task,
- RESERVED_ITT,
NULL, 0, 1);
break;
case ISCSI_OP_LOGOUT:
@@ -1052,6 +1105,9 @@ static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task)
case ISCSI_OP_SCSI_TMFUNC:
rc = bnx2i_send_iscsi_tmf(bnx2i_conn, task);
break;
+ case ISCSI_OP_TEXT:
+ rc = bnx2i_send_iscsi_text(bnx2i_conn, task);
+ break;
default:
iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
"send_gen: unsupported op 0x%x\n",
@@ -1114,10 +1170,10 @@ static void bnx2i_cleanup_task(struct iscsi_task *task)
if (task->state == ISCSI_TASK_ABRT_TMF) {
bnx2i_send_cmd_cleanup_req(hba, task->dd_data);
- spin_unlock_bh(&conn->session->lock);
+ spin_unlock_bh(&conn->session->back_lock);
wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl,
msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT));
- spin_lock_bh(&conn->session->lock);
+ spin_lock_bh(&conn->session->back_lock);
}
bnx2i_iscsi_unmap_sg_list(task->dd_data);
}
@@ -1131,12 +1187,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);
@@ -1163,7 +1225,11 @@ static int bnx2i_task_xmit(struct iscsi_task *task)
struct bnx2i_conn *bnx2i_conn = conn->dd_data;
struct scsi_cmnd *sc = task->sc;
struct bnx2i_cmd *cmd = task->dd_data;
- struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr;
+ struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr;
+
+ if (atomic_read(&bnx2i_conn->ep->num_active_cmds) + 1 >
+ hba->max_sqes)
+ return -ENOMEM;
/*
* If there is no scsi_cmnd this must be a mgmt task
@@ -1302,6 +1368,9 @@ bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid)
bnx2i_conn = conn->dd_data;
bnx2i_conn->cls_conn = cls_conn;
bnx2i_conn->hba = hba;
+
+ atomic_set(&bnx2i_conn->work_cnt, 0);
+
/* 'ep' ptr will be assigned in bind() call */
bnx2i_conn->ep = NULL;
init_completion(&bnx2i_conn->cmd_cleanup_cmpl);
@@ -1346,6 +1415,12 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
ep = iscsi_lookup_endpoint(transport_fd);
if (!ep)
return -EINVAL;
+ /*
+ * Forcefully terminate all in progress connection recovery at the
+ * earliest, either in bind(), send_pdu(LOGIN), or conn_start()
+ */
+ if (bnx2i_adapter_ready(hba))
+ return -EIO;
bnx2i_ep = ep->dd_data;
if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
@@ -1367,7 +1442,6 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
hba->netdev->name);
return -EEXIST;
}
-
bnx2i_ep->conn = bnx2i_conn;
bnx2i_conn->ep = bnx2i_ep;
bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid;
@@ -1400,43 +1474,71 @@ static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn)
struct bnx2i_conn *bnx2i_conn = conn->dd_data;
struct Scsi_Host *shost;
struct bnx2i_hba *hba;
+ struct bnx2i_work *work, *tmp;
+ unsigned cpu = 0;
+ struct bnx2i_percpu_s *p;
shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn));
hba = iscsi_host_priv(shost);
bnx2i_conn_free_login_resources(hba, bnx2i_conn);
+
+ if (atomic_read(&bnx2i_conn->work_cnt)) {
+ for_each_online_cpu(cpu) {
+ p = &per_cpu(bnx2i_percpu, cpu);
+ spin_lock_bh(&p->p_work_lock);
+ list_for_each_entry_safe(work, tmp,
+ &p->work_list, list) {
+ if (work->session == conn->session &&
+ work->bnx2i_conn == bnx2i_conn) {
+ list_del_init(&work->list);
+ kfree(work);
+ if (!atomic_dec_and_test(
+ &bnx2i_conn->work_cnt))
+ break;
+ }
+ }
+ spin_unlock_bh(&p->p_work_lock);
+ }
+ }
+
iscsi_conn_teardown(cls_conn);
}
/**
- * bnx2i_conn_get_param - return iscsi connection parameter to caller
- * @cls_conn: pointer to iscsi cls conn
+ * bnx2i_ep_get_param - return iscsi ep parameter to caller
+ * @ep: pointer to iscsi endpoint
* @param: parameter type identifier
* @buf: buffer pointer
*
- * returns iSCSI connection parameters
+ * returns iSCSI ep parameters
*/
-static int bnx2i_conn_get_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf)
+static int bnx2i_ep_get_param(struct iscsi_endpoint *ep,
+ enum iscsi_param param, char *buf)
{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct bnx2i_conn *bnx2i_conn = conn->dd_data;
- int len = 0;
+ struct bnx2i_endpoint *bnx2i_ep = ep->dd_data;
+ struct bnx2i_hba *hba = bnx2i_ep->hba;
+ int len = -ENOTCONN;
+
+ if (!hba)
+ return -ENOTCONN;
switch (param) {
case ISCSI_PARAM_CONN_PORT:
- if (bnx2i_conn->ep)
- len = sprintf(buf, "%hu\n",
- bnx2i_conn->ep->cm_sk->dst_port);
+ mutex_lock(&hba->net_dev_lock);
+ if (bnx2i_ep->cm_sk)
+ len = sprintf(buf, "%hu\n", bnx2i_ep->cm_sk->dst_port);
+ mutex_unlock(&hba->net_dev_lock);
break;
case ISCSI_PARAM_CONN_ADDRESS:
- if (bnx2i_conn->ep)
- len = sprintf(buf, "%pI4\n",
- &bnx2i_conn->ep->cm_sk->dst_ip);
+ mutex_lock(&hba->net_dev_lock);
+ if (bnx2i_ep->cm_sk)
+ len = sprintf(buf, "%pI4\n", &bnx2i_ep->cm_sk->dst_ip);
+ mutex_unlock(&hba->net_dev_lock);
break;
default:
- return iscsi_conn_get_param(cls_conn, param, buf);
+ return -ENOSYS;
}
return len;
@@ -1461,6 +1563,26 @@ static int bnx2i_host_get_param(struct Scsi_Host *shost,
case ISCSI_HOST_PARAM_NETDEV_NAME:
len = sprintf(buf, "%s\n", hba->netdev->name);
break;
+ case ISCSI_HOST_PARAM_IPADDRESS: {
+ struct list_head *active_list = &hba->ep_active_list;
+
+ read_lock_bh(&hba->ep_rdwr_lock);
+ if (!list_empty(&hba->ep_active_list)) {
+ struct bnx2i_endpoint *bnx2i_ep;
+ struct cnic_sock *csk;
+
+ bnx2i_ep = list_first_entry(active_list,
+ 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);
+ }
+ read_unlock_bh(&hba->ep_rdwr_lock);
+ break;
+ }
default:
return iscsi_host_get_param(shost, param, buf);
}
@@ -1542,8 +1664,6 @@ static struct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr)
struct bnx2i_hba *hba;
struct cnic_dev *cnic = NULL;
- bnx2i_reg_dev_all();
-
hba = get_adapter_list_head();
if (hba && hba->cnic)
cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI);
@@ -1576,30 +1696,38 @@ no_nx2_route:
/**
* bnx2i_tear_down_conn - tear down iscsi/tcp connection and free resources
* @hba: pointer to adapter instance
- * @ep: endpoint (transport indentifier) structure
+ * @ep: endpoint (transport identifier) structure
*
* destroys cm_sock structure and on chip iscsi context
*/
static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
struct bnx2i_endpoint *ep)
{
- if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
+ if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) && ep->cm_sk)
hba->cnic->cm_destroy(ep->cm_sk);
- if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state))
- ep->state = EP_STATE_DISCONN_COMPL;
-
if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) &&
ep->state == EP_STATE_DISCONN_TIMEDOUT) {
- printk(KERN_ALERT "bnx2i - ERROR - please submit GRC Dump,"
- " NW/PCIe trace, driver msgs to developers"
- " for analysis\n");
- return 1;
+ if (ep->conn && ep->conn->cls_conn &&
+ ep->conn->cls_conn->dd_data) {
+ struct iscsi_conn *conn = ep->conn->cls_conn->dd_data;
+
+ /* Must suspend all rx queue activity for this ep */
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
+ }
+ /* CONN_DISCONNECT timeout may or may not be an issue depending
+ * on what transcribed in TCP layer, different targets behave
+ * differently
+ */
+ printk(KERN_ALERT "bnx2i (%s): - WARN - CONN_DISCON timed out, "
+ "please submit GRC Dump, NW/PCIe trace, "
+ "driver msgs to developers for analysis\n",
+ hba->netdev->name);
}
ep->state = EP_STATE_CLEANUP_START;
init_timer(&ep->ofld_timer);
- ep->ofld_timer.expires = 10*HZ + jiffies;
+ ep->ofld_timer.expires = hba->conn_ctx_destroy_tmo + jiffies;
ep->ofld_timer.function = bnx2i_ep_ofld_timer;
ep->ofld_timer.data = (unsigned long) ep;
add_timer(&ep->ofld_timer);
@@ -1607,7 +1735,9 @@ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
bnx2i_ep_destroy_list_add(hba, ep);
/* destroy iSCSI context, wait for it to complete */
- bnx2i_send_conn_destroy(hba, ep);
+ if (bnx2i_send_conn_destroy(hba, ep))
+ ep->state = EP_STATE_CLEANUP_CMPL;
+
wait_event_interruptible(ep->ofld_wait,
(ep->state != EP_STATE_CLEANUP_START));
@@ -1654,8 +1784,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
if (shost) {
/* driver is given scsi host to work with */
hba = iscsi_host_priv(shost);
- /* Register the device with cnic if not already done so */
- bnx2i_register_device(hba);
} else
/*
* check if the given destination can be reached through
@@ -1663,11 +1791,16 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
*/
hba = bnx2i_check_route(dst_addr);
- if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) {
+ if (!hba) {
rc = -EINVAL;
- goto check_busy;
+ goto nohba;
}
+ mutex_lock(&hba->net_dev_lock);
+ if (bnx2i_adapter_ready(hba) || !hba->cid_que.cid_free_cnt) {
+ rc = -EPERM;
+ goto check_busy;
+ }
cnic = hba->cnic;
ep = bnx2i_alloc_ep(hba);
if (!ep) {
@@ -1676,24 +1809,21 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
}
bnx2i_ep = ep->dd_data;
- mutex_lock(&hba->net_dev_lock);
- if (bnx2i_adapter_ready(hba)) {
- rc = -EPERM;
- goto net_if_down;
- }
-
- bnx2i_ep->num_active_cmds = 0;
+ atomic_set(&bnx2i_ep->num_active_cmds, 0);
iscsi_cid = bnx2i_alloc_iscsi_cid(hba);
if (iscsi_cid == -1) {
- printk(KERN_ALERT "alloc_ep: unable to allocate iscsi cid\n");
+ printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate "
+ "iscsi cid\n", hba->netdev->name);
rc = -ENOMEM;
- goto iscsi_cid_err;
+ bnx2i_free_ep(ep);
+ goto check_busy;
}
bnx2i_ep->hba_age = hba->age;
rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep);
if (rc != 0) {
- printk(KERN_ALERT "bnx2i: ep_conn, alloc QP resc error\n");
+ printk(KERN_ALERT "bnx2i (%s): ep_conn - alloc QP resc error"
+ "\n", hba->netdev->name);
rc = -ENOMEM;
goto qp_resc_err;
}
@@ -1708,7 +1838,18 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
add_timer(&bnx2i_ep->ofld_timer);
- bnx2i_send_conn_ofld_req(hba, bnx2i_ep);
+ if (bnx2i_send_conn_ofld_req(hba, bnx2i_ep)) {
+ if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) {
+ printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n",
+ hba->netdev->name, bnx2i_ep->ep_iscsi_cid);
+ rc = -EBUSY;
+ } else
+ rc = -ENOSPC;
+ printk(KERN_ALERT "bnx2i (%s): unable to send conn offld kwqe"
+ "\n", hba->netdev->name);
+ bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
+ goto conn_failed;
+ }
/* Wait for CNIC hardware to setup conn context and return 'cid' */
wait_event_interruptible(bnx2i_ep->ofld_wait,
@@ -1721,7 +1862,12 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
bnx2i_ep_ofld_list_del(hba, bnx2i_ep);
if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) {
- rc = -ENOSPC;
+ if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) {
+ printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n",
+ hba->netdev->name, bnx2i_ep->ep_iscsi_cid);
+ rc = -EBUSY;
+ } else
+ rc = -ENOSPC;
goto conn_failed;
}
@@ -1729,7 +1875,8 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep);
if (rc) {
rc = -EINVAL;
- goto conn_failed;
+ /* Need to terminate and cleanup the connection */
+ goto release_ep;
}
bnx2i_ep->cm_sk->rcv_buf = 256 * 1024;
@@ -1754,29 +1901,31 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
goto conn_failed;
} else
rc = cnic->cm_connect(bnx2i_ep->cm_sk, &saddr);
-
if (rc)
goto release_ep;
+ bnx2i_ep_active_list_add(hba, bnx2i_ep);
+
if (bnx2i_map_ep_dbell_regs(bnx2i_ep))
- goto release_ep;
+ goto del_active_ep;
+
mutex_unlock(&hba->net_dev_lock);
return ep;
+del_active_ep:
+ bnx2i_ep_active_list_del(hba, bnx2i_ep);
release_ep:
if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
mutex_unlock(&hba->net_dev_lock);
return ERR_PTR(rc);
}
conn_failed:
-net_if_down:
-iscsi_cid_err:
bnx2i_free_qp_resc(hba, bnx2i_ep);
qp_resc_err:
bnx2i_free_ep(ep);
- mutex_unlock(&hba->net_dev_lock);
check_busy:
- bnx2i_unreg_dev_all();
+ mutex_unlock(&hba->net_dev_lock);
+nohba:
return ERR_PTR(rc);
}
@@ -1836,27 +1985,27 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
cnic_dev_10g = 1;
switch (bnx2i_ep->state) {
- case EP_STATE_CONNECT_START:
case EP_STATE_CLEANUP_FAILED:
case EP_STATE_OFLD_FAILED:
case EP_STATE_DISCONN_TIMEDOUT:
ret = 0;
break;
+ case EP_STATE_CONNECT_START:
+ case EP_STATE_CONNECT_FAILED:
case EP_STATE_CONNECT_COMPL:
case EP_STATE_ULP_UPDATE_START:
case EP_STATE_ULP_UPDATE_COMPL:
case EP_STATE_TCP_FIN_RCVD:
+ case EP_STATE_LOGOUT_SENT:
+ case EP_STATE_LOGOUT_RESP_RCVD:
case EP_STATE_ULP_UPDATE_FAILED:
ret = 1;
break;
case EP_STATE_TCP_RST_RCVD:
- ret = 0;
- break;
- case EP_STATE_CONNECT_FAILED:
if (cnic_dev_10g)
- ret = 1;
- else
ret = 0;
+ else
+ ret = 1;
break;
default:
ret = 0;
@@ -1866,9 +2015,102 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
}
+/*
+ * bnx2i_hw_ep_disconnect - executes TCP connection teardown process in the hw
+ * @ep: TCP connection (bnx2i endpoint) handle
+ *
+ * executes TCP connection teardown process
+ */
+int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
+{
+ struct bnx2i_hba *hba = bnx2i_ep->hba;
+ struct cnic_dev *cnic;
+ struct iscsi_session *session = NULL;
+ struct iscsi_conn *conn = NULL;
+ int ret = 0;
+ int close = 0;
+ int close_ret = 0;
+
+ if (!hba)
+ return 0;
+
+ cnic = hba->cnic;
+ if (!cnic)
+ return 0;
+
+ if (bnx2i_ep->state == EP_STATE_IDLE ||
+ bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT)
+ return 0;
+
+ if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
+ goto destroy_conn;
+
+ if (bnx2i_ep->conn) {
+ conn = bnx2i_ep->conn->cls_conn->dd_data;
+ session = conn->session;
+ }
+
+ init_timer(&bnx2i_ep->ofld_timer);
+ bnx2i_ep->ofld_timer.expires = hba->conn_teardown_tmo + jiffies;
+ bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
+ bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
+ add_timer(&bnx2i_ep->ofld_timer);
+
+ if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
+ goto out;
+
+ if (session) {
+ spin_lock_bh(&session->frwd_lock);
+ if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) {
+ if (session->state == ISCSI_STATE_LOGGING_OUT) {
+ if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
+ /* Logout sent, but no resp */
+ printk(KERN_ALERT "bnx2i (%s): WARNING"
+ " logout response was not "
+ "received!\n",
+ bnx2i_ep->hba->netdev->name);
+ } else if (bnx2i_ep->state ==
+ EP_STATE_LOGOUT_RESP_RCVD)
+ close = 1;
+ }
+ } else
+ close = 1;
+
+ spin_unlock_bh(&session->frwd_lock);
+ }
+
+ bnx2i_ep->state = EP_STATE_DISCONN_START;
+
+ if (close)
+ close_ret = cnic->cm_close(bnx2i_ep->cm_sk);
+ else
+ close_ret = cnic->cm_abort(bnx2i_ep->cm_sk);
+
+ if (close_ret)
+ printk(KERN_ALERT "bnx2i (%s): close/abort(%d) returned %d\n",
+ bnx2i_ep->hba->netdev->name, close, close_ret);
+ else
+ /* wait for option-2 conn teardown */
+ wait_event_interruptible(bnx2i_ep->ofld_wait,
+ bnx2i_ep->state != EP_STATE_DISCONN_START);
+
+ if (signal_pending(current))
+ flush_signals(current);
+ del_timer_sync(&bnx2i_ep->ofld_timer);
+
+destroy_conn:
+ bnx2i_ep_active_list_del(hba, bnx2i_ep);
+ if (bnx2i_tear_down_conn(hba, bnx2i_ep))
+ return -EINVAL;
+out:
+ bnx2i_ep->state = EP_STATE_IDLE;
+ return ret;
+}
+
+
/**
* bnx2i_ep_disconnect - executes TCP connection teardown process
- * @ep: TCP connection (endpoint) handle
+ * @ep: TCP connection (iscsi endpoint) handle
*
* executes TCP connection teardown process
*/
@@ -1876,9 +2118,7 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
{
struct bnx2i_endpoint *bnx2i_ep;
struct bnx2i_conn *bnx2i_conn = NULL;
- struct iscsi_session *session = NULL;
- struct iscsi_conn *conn;
- struct cnic_dev *cnic;
+ struct iscsi_conn *conn = NULL;
struct bnx2i_hba *hba;
bnx2i_ep = ep->dd_data;
@@ -1894,74 +2134,38 @@ 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;
- session = conn->session;
-
iscsi_suspend_queue(conn);
}
-
hba = bnx2i_ep->hba;
- if (bnx2i_ep->state == EP_STATE_IDLE)
- goto return_bnx2i_ep;
- cnic = hba->cnic;
mutex_lock(&hba->net_dev_lock);
- if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
- goto free_resc;
- if (bnx2i_ep->hba_age != hba->age)
- goto free_resc;
-
- if (!bnx2i_ep_tcp_conn_active(bnx2i_ep))
- goto destory_conn;
-
- bnx2i_ep->state = EP_STATE_DISCONN_START;
-
- init_timer(&bnx2i_ep->ofld_timer);
- bnx2i_ep->ofld_timer.expires = 10*HZ + jiffies;
- bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
- bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
- add_timer(&bnx2i_ep->ofld_timer);
-
- if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
- int close = 0;
+ if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT)
+ goto out;
- if (session) {
- spin_lock_bh(&session->lock);
- if (session->state == ISCSI_STATE_LOGGING_OUT)
- close = 1;
- spin_unlock_bh(&session->lock);
- }
- if (close)
- cnic->cm_close(bnx2i_ep->cm_sk);
- else
- cnic->cm_abort(bnx2i_ep->cm_sk);
- } else
+ if (bnx2i_ep->state == EP_STATE_IDLE)
goto free_resc;
- /* wait for option-2 conn teardown */
- wait_event_interruptible(bnx2i_ep->ofld_wait,
- bnx2i_ep->state != EP_STATE_DISCONN_START);
-
- if (signal_pending(current))
- flush_signals(current);
- del_timer_sync(&bnx2i_ep->ofld_timer);
+ if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) ||
+ (bnx2i_ep->hba_age != hba->age)) {
+ bnx2i_ep_active_list_del(hba, bnx2i_ep);
+ goto free_resc;
+ }
-destory_conn:
- if (bnx2i_tear_down_conn(hba, bnx2i_ep)) {
+ /* Do all chip cleanup here */
+ if (bnx2i_hw_ep_disconnect(bnx2i_ep)) {
mutex_unlock(&hba->net_dev_lock);
return;
}
free_resc:
- mutex_unlock(&hba->net_dev_lock);
bnx2i_free_qp_resc(hba, bnx2i_ep);
-return_bnx2i_ep:
+
if (bnx2i_conn)
bnx2i_conn->ep = NULL;
bnx2i_free_ep(ep);
-
- if (!hba->ofld_conns_active)
- bnx2i_unreg_dev_all();
+out:
+ mutex_unlock(&hba->net_dev_lock);
wake_up_interruptible(&hba->eh_wait);
}
@@ -1985,6 +2189,59 @@ static int bnx2i_nl_set_path(struct Scsi_Host *shost, struct iscsi_path *params)
return 0;
}
+static umode_t bnx2i_attr_is_visible(int param_type, int param)
+{
+ switch (param_type) {
+ case ISCSI_HOST_PARAM:
+ switch (param) {
+ case ISCSI_HOST_PARAM_NETDEV_NAME:
+ case ISCSI_HOST_PARAM_HWADDRESS:
+ case ISCSI_HOST_PARAM_IPADDRESS:
+ return S_IRUGO;
+ default:
+ return 0;
+ }
+ case ISCSI_PARAM:
+ switch (param) {
+ case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+ case ISCSI_PARAM_HDRDGST_EN:
+ case ISCSI_PARAM_DATADGST_EN:
+ case ISCSI_PARAM_CONN_ADDRESS:
+ case ISCSI_PARAM_CONN_PORT:
+ case ISCSI_PARAM_EXP_STATSN:
+ case ISCSI_PARAM_PERSISTENT_ADDRESS:
+ case ISCSI_PARAM_PERSISTENT_PORT:
+ case ISCSI_PARAM_PING_TMO:
+ case ISCSI_PARAM_RECV_TMO:
+ case ISCSI_PARAM_INITIAL_R2T_EN:
+ case ISCSI_PARAM_MAX_R2T:
+ case ISCSI_PARAM_IMM_DATA_EN:
+ case ISCSI_PARAM_FIRST_BURST:
+ case ISCSI_PARAM_MAX_BURST:
+ case ISCSI_PARAM_PDU_INORDER_EN:
+ case ISCSI_PARAM_DATASEQ_INORDER_EN:
+ case ISCSI_PARAM_ERL:
+ case ISCSI_PARAM_TARGET_NAME:
+ case ISCSI_PARAM_TPGT:
+ case ISCSI_PARAM_USERNAME:
+ case ISCSI_PARAM_PASSWORD:
+ case ISCSI_PARAM_USERNAME_IN:
+ case ISCSI_PARAM_PASSWORD_IN:
+ case ISCSI_PARAM_FAST_ABORT:
+ case ISCSI_PARAM_ABORT_TMO:
+ case ISCSI_PARAM_LU_RESET_TMO:
+ case ISCSI_PARAM_TGT_RESET_TMO:
+ case ISCSI_PARAM_IFACE_NAME:
+ case ISCSI_PARAM_INITIATOR_NAME:
+ return S_IRUGO;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
/*
* 'Scsi_Host_Template' structure and 'iscsi_tranport' structure template
@@ -1999,9 +2256,10 @@ static struct scsi_host_template bnx2i_host_template = {
.eh_device_reset_handler = iscsi_eh_device_reset,
.eh_target_reset_handler = iscsi_eh_recover_target,
.change_queue_depth = iscsi_change_queue_depth,
- .can_queue = 1024,
+ .target_alloc = iscsi_target_alloc,
+ .can_queue = 2048,
.max_sectors = 127,
- .cmd_per_lun = 32,
+ .cmd_per_lun = 128,
.this_id = -1,
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = ISCSI_MAX_BDS_PER_CMD,
@@ -2013,39 +2271,16 @@ struct iscsi_transport bnx2i_iscsi_transport = {
.name = "bnx2i",
.caps = CAP_RECOVERY_L0 | CAP_HDRDGST |
CAP_MULTI_R2T | CAP_DATADGST |
- CAP_DATA_PATH_OFFLOAD,
- .param_mask = ISCSI_MAX_RECV_DLENGTH |
- ISCSI_MAX_XMIT_DLENGTH |
- ISCSI_HDRDGST_EN |
- ISCSI_DATADGST_EN |
- ISCSI_INITIAL_R2T_EN |
- ISCSI_MAX_R2T |
- ISCSI_IMM_DATA_EN |
- ISCSI_FIRST_BURST |
- ISCSI_MAX_BURST |
- ISCSI_PDU_INORDER_EN |
- ISCSI_DATASEQ_INORDER_EN |
- ISCSI_ERL |
- ISCSI_CONN_PORT |
- ISCSI_CONN_ADDRESS |
- ISCSI_EXP_STATSN |
- ISCSI_PERSISTENT_PORT |
- ISCSI_PERSISTENT_ADDRESS |
- ISCSI_TARGET_NAME | ISCSI_TPGT |
- ISCSI_USERNAME | ISCSI_PASSWORD |
- ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
- ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
- ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |
- ISCSI_PING_TMO | ISCSI_RECV_TMO |
- ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
- .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME,
+ CAP_DATA_PATH_OFFLOAD |
+ CAP_TEXT_NEGO,
.create_session = bnx2i_session_create,
.destroy_session = bnx2i_session_destroy,
.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,
- .get_conn_param = bnx2i_conn_get_param,
+ .get_conn_param = iscsi_conn_get_param,
.get_session_param = iscsi_session_get_param,
.get_host_param = bnx2i_host_get_param,
.start_conn = bnx2i_conn_start,
@@ -2054,6 +2289,7 @@ 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,
diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c
index 96426b751eb..a0a3d9fe61f 100644
--- a/drivers/scsi/bnx2i/bnx2i_sysfs.c
+++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c
@@ -1,12 +1,13 @@
/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
*
- * Copyright (c) 2004 - 2009 Broadcom Corporation
+ * Copyright (c) 2004 - 2013 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)
*/
#include "bnx2i.h"