M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,990 @@
#ifndef __57XX_FCOE_HSI_LINUX_LE__
#define __57XX_FCOE_HSI_LINUX_LE__
/*
* common data for all protocols
*/
struct b577xx_doorbell_hdr {
u8 header;
#define B577XX_DOORBELL_HDR_RX (0x1<<0)
#define B577XX_DOORBELL_HDR_RX_SHIFT 0
#define B577XX_DOORBELL_HDR_DB_TYPE (0x1<<1)
#define B577XX_DOORBELL_HDR_DB_TYPE_SHIFT 1
#define B577XX_DOORBELL_HDR_DPM_SIZE (0x3<<2)
#define B577XX_DOORBELL_HDR_DPM_SIZE_SHIFT 2
#define B577XX_DOORBELL_HDR_CONN_TYPE (0xF<<4)
#define B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT 4
};
/*
* doorbell message sent to the chip
*/
struct b577xx_doorbell {
#if defined(__BIG_ENDIAN)
u16 zero_fill2;
u8 zero_fill1;
struct b577xx_doorbell_hdr header;
#elif defined(__LITTLE_ENDIAN)
struct b577xx_doorbell_hdr header;
u8 zero_fill1;
u16 zero_fill2;
#endif
};
/*
* doorbell message sent to the chip
*/
struct b577xx_doorbell_set_prod {
#if defined(__BIG_ENDIAN)
u16 prod;
u8 zero_fill1;
struct b577xx_doorbell_hdr header;
#elif defined(__LITTLE_ENDIAN)
struct b577xx_doorbell_hdr header;
u8 zero_fill1;
u16 prod;
#endif
};
struct regpair {
__le32 lo;
__le32 hi;
};
/*
* ABTS info $$KEEP_ENDIANNESS$$
*/
struct fcoe_abts_info {
__le16 aborted_task_id;
__le16 reserved0;
__le32 reserved1;
};
/*
* Fixed size structure in order to plant it in Union structure
* $$KEEP_ENDIANNESS$$
*/
struct fcoe_abts_rsp_union {
u8 r_ctl;
u8 rsrv[3];
__le32 abts_rsp_payload[7];
};
/*
* 4 regs size $$KEEP_ENDIANNESS$$
*/
struct fcoe_bd_ctx {
__le32 buf_addr_hi;
__le32 buf_addr_lo;
__le16 buf_len;
__le16 rsrv0;
__le16 flags;
__le16 rsrv1;
};
/*
* FCoE cached sges context $$KEEP_ENDIANNESS$$
*/
struct fcoe_cached_sge_ctx {
struct regpair cur_buf_addr;
__le16 cur_buf_rem;
__le16 second_buf_rem;
struct regpair second_buf_addr;
};
/*
* Cleanup info $$KEEP_ENDIANNESS$$
*/
struct fcoe_cleanup_info {
__le16 cleaned_task_id;
__le16 rolled_tx_seq_cnt;
__le32 rolled_tx_data_offset;
};
/*
* Fcp RSP flags $$KEEP_ENDIANNESS$$
*/
struct fcoe_fcp_rsp_flags {
u8 flags;
#define FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID (0x1<<0)
#define FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID_SHIFT 0
#define FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID (0x1<<1)
#define FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID_SHIFT 1
#define FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER (0x1<<2)
#define FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER_SHIFT 2
#define FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER (0x1<<3)
#define FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER_SHIFT 3
#define FCOE_FCP_RSP_FLAGS_FCP_CONF_REQ (0x1<<4)
#define FCOE_FCP_RSP_FLAGS_FCP_CONF_REQ_SHIFT 4
#define FCOE_FCP_RSP_FLAGS_FCP_BIDI_FLAGS (0x7<<5)
#define FCOE_FCP_RSP_FLAGS_FCP_BIDI_FLAGS_SHIFT 5
};
/*
* Fcp RSP payload $$KEEP_ENDIANNESS$$
*/
struct fcoe_fcp_rsp_payload {
struct regpair reserved0;
__le32 fcp_resid;
u8 scsi_status_code;
struct fcoe_fcp_rsp_flags fcp_flags;
__le16 retry_delay_timer;
__le32 fcp_rsp_len;
__le32 fcp_sns_len;
};
/*
* Fixed size structure in order to plant it in Union structure
* $$KEEP_ENDIANNESS$$
*/
struct fcoe_fcp_rsp_union {
struct fcoe_fcp_rsp_payload payload;
struct regpair reserved0;
};
/*
* FC header $$KEEP_ENDIANNESS$$
*/
struct fcoe_fc_hdr {
u8 s_id[3];
u8 cs_ctl;
u8 d_id[3];
u8 r_ctl;
__le16 seq_cnt;
u8 df_ctl;
u8 seq_id;
u8 f_ctl[3];
u8 type;
__le32 parameters;
__le16 rx_id;
__le16 ox_id;
};
/*
* FC header union $$KEEP_ENDIANNESS$$
*/
struct fcoe_mp_rsp_union {
struct fcoe_fc_hdr fc_hdr;
__le32 mp_payload_len;
__le32 rsrv;
};
/*
* Completion information $$KEEP_ENDIANNESS$$
*/
union fcoe_comp_flow_info {
struct fcoe_fcp_rsp_union fcp_rsp;
struct fcoe_abts_rsp_union abts_rsp;
struct fcoe_mp_rsp_union mp_rsp;
__le32 opaque[8];
};
/*
* External ABTS info $$KEEP_ENDIANNESS$$
*/
struct fcoe_ext_abts_info {
__le32 rsrv0[6];
struct fcoe_abts_info ctx;
};
/*
* External cleanup info $$KEEP_ENDIANNESS$$
*/
struct fcoe_ext_cleanup_info {
__le32 rsrv0[6];
struct fcoe_cleanup_info ctx;
};
/*
* Fcoe FW Tx sequence context $$KEEP_ENDIANNESS$$
*/
struct fcoe_fw_tx_seq_ctx {
__le32 data_offset;
__le16 seq_cnt;
__le16 rsrv0;
};
/*
* Fcoe external FW Tx sequence context $$KEEP_ENDIANNESS$$
*/
struct fcoe_ext_fw_tx_seq_ctx {
__le32 rsrv0[6];
struct fcoe_fw_tx_seq_ctx ctx;
};
/*
* FCoE multiple sges context $$KEEP_ENDIANNESS$$
*/
struct fcoe_mul_sges_ctx {
struct regpair cur_sge_addr;
__le16 cur_sge_off;
u8 cur_sge_idx;
u8 sgl_size;
};
/*
* FCoE external multiple sges context $$KEEP_ENDIANNESS$$
*/
struct fcoe_ext_mul_sges_ctx {
struct fcoe_mul_sges_ctx mul_sgl;
struct regpair rsrv0;
};
/*
* FCP CMD payload $$KEEP_ENDIANNESS$$
*/
struct fcoe_fcp_cmd_payload {
__le32 opaque[8];
};
/*
* Fcp xfr rdy payload $$KEEP_ENDIANNESS$$
*/
struct fcoe_fcp_xfr_rdy_payload {
__le32 burst_len;
__le32 data_ro;
};
/*
* FC frame $$KEEP_ENDIANNESS$$
*/
struct fcoe_fc_frame {
struct fcoe_fc_hdr fc_hdr;
__le32 reserved0[2];
};
/*
* FCoE KCQ CQE parameters $$KEEP_ENDIANNESS$$
*/
union fcoe_kcqe_params {
__le32 reserved0[4];
};
/*
* FCoE KCQ CQE $$KEEP_ENDIANNESS$$
*/
struct fcoe_kcqe {
__le32 fcoe_conn_id;
__le32 completion_status;
__le32 fcoe_conn_context_id;
union fcoe_kcqe_params params;
__le16 qe_self_seq;
u8 op_code;
u8 flags;
#define FCOE_KCQE_RESERVED0 (0x7<<0)
#define FCOE_KCQE_RESERVED0_SHIFT 0
#define FCOE_KCQE_RAMROD_COMPLETION (0x1<<3)
#define FCOE_KCQE_RAMROD_COMPLETION_SHIFT 3
#define FCOE_KCQE_LAYER_CODE (0x7<<4)
#define FCOE_KCQE_LAYER_CODE_SHIFT 4
#define FCOE_KCQE_LINKED_WITH_NEXT (0x1<<7)
#define FCOE_KCQE_LINKED_WITH_NEXT_SHIFT 7
};
/*
* FCoE KWQE header $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_header {
u8 op_code;
u8 flags;
#define FCOE_KWQE_HEADER_RESERVED0 (0xF<<0)
#define FCOE_KWQE_HEADER_RESERVED0_SHIFT 0
#define FCOE_KWQE_HEADER_LAYER_CODE (0x7<<4)
#define FCOE_KWQE_HEADER_LAYER_CODE_SHIFT 4
#define FCOE_KWQE_HEADER_RESERVED1 (0x1<<7)
#define FCOE_KWQE_HEADER_RESERVED1_SHIFT 7
};
/*
* FCoE firmware init request 1 $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_init1 {
__le16 num_tasks;
struct fcoe_kwqe_header hdr;
__le32 task_list_pbl_addr_lo;
__le32 task_list_pbl_addr_hi;
__le32 dummy_buffer_addr_lo;
__le32 dummy_buffer_addr_hi;
__le16 sq_num_wqes;
__le16 rq_num_wqes;
__le16 rq_buffer_log_size;
__le16 cq_num_wqes;
__le16 mtu;
u8 num_sessions_log;
u8 flags;
#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE (0xF<<0)
#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT 0
#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC (0x7<<4)
#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC_SHIFT 4
#define FCOE_KWQE_INIT1_RESERVED1 (0x1<<7)
#define FCOE_KWQE_INIT1_RESERVED1_SHIFT 7
};
/*
* FCoE firmware init request 2 $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_init2 {
u8 hsi_major_version;
u8 hsi_minor_version;
struct fcoe_kwqe_header hdr;
__le32 hash_tbl_pbl_addr_lo;
__le32 hash_tbl_pbl_addr_hi;
__le32 t2_hash_tbl_addr_lo;
__le32 t2_hash_tbl_addr_hi;
__le32 t2_ptr_hash_tbl_addr_lo;
__le32 t2_ptr_hash_tbl_addr_hi;
__le32 free_list_count;
};
/*
* FCoE firmware init request 3 $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_init3 {
__le16 reserved0;
struct fcoe_kwqe_header hdr;
__le32 error_bit_map_lo;
__le32 error_bit_map_hi;
u8 perf_config;
u8 reserved21[3];
__le32 reserved2[4];
};
/*
* FCoE connection offload request 1 $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_conn_offload1 {
__le16 fcoe_conn_id;
struct fcoe_kwqe_header hdr;
__le32 sq_addr_lo;
__le32 sq_addr_hi;
__le32 rq_pbl_addr_lo;
__le32 rq_pbl_addr_hi;
__le32 rq_first_pbe_addr_lo;
__le32 rq_first_pbe_addr_hi;
__le16 rq_prod;
__le16 reserved0;
};
/*
* FCoE connection offload request 2 $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_conn_offload2 {
__le16 tx_max_fc_pay_len;
struct fcoe_kwqe_header hdr;
__le32 cq_addr_lo;
__le32 cq_addr_hi;
__le32 xferq_addr_lo;
__le32 xferq_addr_hi;
__le32 conn_db_addr_lo;
__le32 conn_db_addr_hi;
__le32 reserved1;
};
/*
* FCoE connection offload request 3 $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_conn_offload3 {
__le16 vlan_tag;
#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID (0xFFF<<0)
#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT 0
#define FCOE_KWQE_CONN_OFFLOAD3_CFI (0x1<<12)
#define FCOE_KWQE_CONN_OFFLOAD3_CFI_SHIFT 12
#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY (0x7<<13)
#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT 13
struct fcoe_kwqe_header hdr;
u8 s_id[3];
u8 tx_max_conc_seqs_c3;
u8 d_id[3];
u8 flags;
#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS (0x1<<0)
#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT 0
#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES (0x1<<1)
#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT 1
#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT (0x1<<2)
#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT 2
#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ (0x1<<3)
#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT 3
#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID (0x1<<4)
#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT 4
#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID (0x1<<5)
#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID_SHIFT 5
#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0 (0x1<<6)
#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0_SHIFT 6
#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG (0x1<<7)
#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT 7
__le32 reserved;
__le32 confq_first_pbe_addr_lo;
__le32 confq_first_pbe_addr_hi;
__le16 tx_total_conc_seqs;
__le16 rx_max_fc_pay_len;
__le16 rx_total_conc_seqs;
u8 rx_max_conc_seqs_c3;
u8 rx_open_seqs_exch_c3;
};
/*
* FCoE connection offload request 4 $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_conn_offload4 {
u8 e_d_tov_timer_val;
u8 reserved2;
struct fcoe_kwqe_header hdr;
u8 src_mac_addr_lo[2];
u8 src_mac_addr_mid[2];
u8 src_mac_addr_hi[2];
u8 dst_mac_addr_hi[2];
u8 dst_mac_addr_lo[2];
u8 dst_mac_addr_mid[2];
__le32 lcq_addr_lo;
__le32 lcq_addr_hi;
__le32 confq_pbl_base_addr_lo;
__le32 confq_pbl_base_addr_hi;
};
/*
* FCoE connection enable request $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_conn_enable_disable {
__le16 reserved0;
struct fcoe_kwqe_header hdr;
u8 src_mac_addr_lo[2];
u8 src_mac_addr_mid[2];
u8 src_mac_addr_hi[2];
u16 vlan_tag;
#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID (0xFFF<<0)
#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT 0
#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI (0x1<<12)
#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI_SHIFT 12
#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY (0x7<<13)
#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT 13
u8 dst_mac_addr_lo[2];
u8 dst_mac_addr_mid[2];
u8 dst_mac_addr_hi[2];
__le16 reserved1;
u8 s_id[3];
u8 vlan_flag;
u8 d_id[3];
u8 reserved3;
__le32 context_id;
__le32 conn_id;
__le32 reserved4;
};
/*
* FCoE connection destroy request $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_conn_destroy {
__le16 reserved0;
struct fcoe_kwqe_header hdr;
__le32 context_id;
__le32 conn_id;
__le32 reserved1[5];
};
/*
* FCoe destroy request $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_destroy {
__le16 reserved0;
struct fcoe_kwqe_header hdr;
__le32 reserved1[7];
};
/*
* FCoe statistics request $$KEEP_ENDIANNESS$$
*/
struct fcoe_kwqe_stat {
__le16 reserved0;
struct fcoe_kwqe_header hdr;
__le32 stat_params_addr_lo;
__le32 stat_params_addr_hi;
__le32 reserved1[5];
};
/*
* FCoE KWQ WQE $$KEEP_ENDIANNESS$$
*/
union fcoe_kwqe {
struct fcoe_kwqe_init1 init1;
struct fcoe_kwqe_init2 init2;
struct fcoe_kwqe_init3 init3;
struct fcoe_kwqe_conn_offload1 conn_offload1;
struct fcoe_kwqe_conn_offload2 conn_offload2;
struct fcoe_kwqe_conn_offload3 conn_offload3;
struct fcoe_kwqe_conn_offload4 conn_offload4;
struct fcoe_kwqe_conn_enable_disable conn_enable_disable;
struct fcoe_kwqe_conn_destroy conn_destroy;
struct fcoe_kwqe_destroy destroy;
struct fcoe_kwqe_stat statistics;
};
/*
* TX SGL context $$KEEP_ENDIANNESS$$
*/
union fcoe_sgl_union_ctx {
struct fcoe_cached_sge_ctx cached_sge;
struct fcoe_ext_mul_sges_ctx sgl;
__le32 opaque[5];
};
/*
* Data-In/ELS/BLS information $$KEEP_ENDIANNESS$$
*/
struct fcoe_read_flow_info {
union fcoe_sgl_union_ctx sgl_ctx;
__le32 rsrv0[3];
};
/*
* Fcoe stat context $$KEEP_ENDIANNESS$$
*/
struct fcoe_s_stat_ctx {
u8 flags;
#define FCOE_S_STAT_CTX_ACTIVE (0x1<<0)
#define FCOE_S_STAT_CTX_ACTIVE_SHIFT 0
#define FCOE_S_STAT_CTX_ACK_ABORT_SEQ_COND (0x1<<1)
#define FCOE_S_STAT_CTX_ACK_ABORT_SEQ_COND_SHIFT 1
#define FCOE_S_STAT_CTX_ABTS_PERFORMED (0x1<<2)
#define FCOE_S_STAT_CTX_ABTS_PERFORMED_SHIFT 2
#define FCOE_S_STAT_CTX_SEQ_TIMEOUT (0x1<<3)
#define FCOE_S_STAT_CTX_SEQ_TIMEOUT_SHIFT 3
#define FCOE_S_STAT_CTX_P_RJT (0x1<<4)
#define FCOE_S_STAT_CTX_P_RJT_SHIFT 4
#define FCOE_S_STAT_CTX_ACK_EOFT (0x1<<5)
#define FCOE_S_STAT_CTX_ACK_EOFT_SHIFT 5
#define FCOE_S_STAT_CTX_RSRV1 (0x3<<6)
#define FCOE_S_STAT_CTX_RSRV1_SHIFT 6
};
/*
* Fcoe rx seq context $$KEEP_ENDIANNESS$$
*/
struct fcoe_rx_seq_ctx {
u8 seq_id;
struct fcoe_s_stat_ctx s_stat;
__le16 seq_cnt;
__le32 low_exp_ro;
__le32 high_exp_ro;
};
/*
* Fcoe rx_wr union context $$KEEP_ENDIANNESS$$
*/
union fcoe_rx_wr_union_ctx {
struct fcoe_read_flow_info read_info;
union fcoe_comp_flow_info comp_info;
__le32 opaque[8];
};
/*
* FCoE SQ element $$KEEP_ENDIANNESS$$
*/
struct fcoe_sqe {
__le16 wqe;
#define FCOE_SQE_TASK_ID (0x7FFF<<0)
#define FCOE_SQE_TASK_ID_SHIFT 0
#define FCOE_SQE_TOGGLE_BIT (0x1<<15)
#define FCOE_SQE_TOGGLE_BIT_SHIFT 15
};
/*
* 14 regs $$KEEP_ENDIANNESS$$
*/
struct fcoe_tce_tx_only {
union fcoe_sgl_union_ctx sgl_ctx;
__le32 rsrv0;
};
/*
* 32 bytes (8 regs) used for TX only purposes $$KEEP_ENDIANNESS$$
*/
union fcoe_tx_wr_rx_rd_union_ctx {
struct fcoe_fc_frame tx_frame;
struct fcoe_fcp_cmd_payload fcp_cmd;
struct fcoe_ext_cleanup_info cleanup;
struct fcoe_ext_abts_info abts;
struct fcoe_ext_fw_tx_seq_ctx tx_seq;
__le32 opaque[8];
};
/*
* tce_tx_wr_rx_rd_const $$KEEP_ENDIANNESS$$
*/
struct fcoe_tce_tx_wr_rx_rd_const {
u8 init_flags;
#define FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE (0x7<<0)
#define FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT 0
#define FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE (0x1<<3)
#define FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT 3
#define FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE (0x1<<4)
#define FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT 4
#define FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE (0x3<<5)
#define FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT 5
#define FCOE_TCE_TX_WR_RX_RD_CONST_SUPPORT_REC_TOV (0x1<<7)
#define FCOE_TCE_TX_WR_RX_RD_CONST_SUPPORT_REC_TOV_SHIFT 7
u8 tx_flags;
#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_VALID (0x1<<0)
#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_VALID_SHIFT 0
#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE (0xF<<1)
#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT 1
#define FCOE_TCE_TX_WR_RX_RD_CONST_RSRV1 (0x1<<5)
#define FCOE_TCE_TX_WR_RX_RD_CONST_RSRV1_SHIFT 5
#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_SEQ_INIT (0x1<<6)
#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_SEQ_INIT_SHIFT 6
#define FCOE_TCE_TX_WR_RX_RD_CONST_RSRV2 (0x1<<7)
#define FCOE_TCE_TX_WR_RX_RD_CONST_RSRV2_SHIFT 7
__le16 rsrv3;
__le32 verify_tx_seq;
};
/*
* tce_tx_wr_rx_rd $$KEEP_ENDIANNESS$$
*/
struct fcoe_tce_tx_wr_rx_rd {
union fcoe_tx_wr_rx_rd_union_ctx union_ctx;
struct fcoe_tce_tx_wr_rx_rd_const const_ctx;
};
/*
* tce_rx_wr_tx_rd_const $$KEEP_ENDIANNESS$$
*/
struct fcoe_tce_rx_wr_tx_rd_const {
__le32 data_2_trns;
__le32 init_flags;
#define FCOE_TCE_RX_WR_TX_RD_CONST_CID (0xFFFFFF<<0)
#define FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT 0
#define FCOE_TCE_RX_WR_TX_RD_CONST_RSRV0 (0xFF<<24)
#define FCOE_TCE_RX_WR_TX_RD_CONST_RSRV0_SHIFT 24
};
/*
* tce_rx_wr_tx_rd_var $$KEEP_ENDIANNESS$$
*/
struct fcoe_tce_rx_wr_tx_rd_var {
__le16 rx_flags;
#define FCOE_TCE_RX_WR_TX_RD_VAR_RSRV1 (0xF<<0)
#define FCOE_TCE_RX_WR_TX_RD_VAR_RSRV1_SHIFT 0
#define FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE (0x7<<4)
#define FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT 4
#define FCOE_TCE_RX_WR_TX_RD_VAR_CONF_REQ (0x1<<7)
#define FCOE_TCE_RX_WR_TX_RD_VAR_CONF_REQ_SHIFT 7
#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE (0xF<<8)
#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE_SHIFT 8
#define FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME (0x1<<12)
#define FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT 12
#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_SEQ_INIT (0x1<<13)
#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_SEQ_INIT_SHIFT 13
#define FCOE_TCE_RX_WR_TX_RD_VAR_RSRV2 (0x1<<14)
#define FCOE_TCE_RX_WR_TX_RD_VAR_RSRV2_SHIFT 14
#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_VALID (0x1<<15)
#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_VALID_SHIFT 15
__le16 rx_id;
struct fcoe_fcp_xfr_rdy_payload fcp_xfr_rdy;
};
/*
* tce_rx_wr_tx_rd $$KEEP_ENDIANNESS$$
*/
struct fcoe_tce_rx_wr_tx_rd {
struct fcoe_tce_rx_wr_tx_rd_const const_ctx;
struct fcoe_tce_rx_wr_tx_rd_var var_ctx;
};
/*
* tce_rx_only $$KEEP_ENDIANNESS$$
*/
struct fcoe_tce_rx_only {
struct fcoe_rx_seq_ctx rx_seq_ctx;
union fcoe_rx_wr_union_ctx union_ctx;
};
/*
* task_ctx_entry $$KEEP_ENDIANNESS$$
*/
struct fcoe_task_ctx_entry {
struct fcoe_tce_tx_only txwr_only;
struct fcoe_tce_tx_wr_rx_rd txwr_rxrd;
struct fcoe_tce_rx_wr_tx_rd rxwr_txrd;
struct fcoe_tce_rx_only rxwr_only;
};
/*
* FCoE XFRQ element $$KEEP_ENDIANNESS$$
*/
struct fcoe_xfrqe {
__le16 wqe;
#define FCOE_XFRQE_TASK_ID (0x7FFF<<0)
#define FCOE_XFRQE_TASK_ID_SHIFT 0
#define FCOE_XFRQE_TOGGLE_BIT (0x1<<15)
#define FCOE_XFRQE_TOGGLE_BIT_SHIFT 15
};
/*
* fcoe rx doorbell message sent to the chip $$KEEP_ENDIANNESS$$
*/
struct b577xx_fcoe_rx_doorbell {
struct b577xx_doorbell_hdr hdr;
u8 params;
#define B577XX_FCOE_RX_DOORBELL_NEGATIVE_ARM (0x1F<<0)
#define B577XX_FCOE_RX_DOORBELL_NEGATIVE_ARM_SHIFT 0
#define B577XX_FCOE_RX_DOORBELL_OPCODE (0x7<<5)
#define B577XX_FCOE_RX_DOORBELL_OPCODE_SHIFT 5
__le16 doorbell_cq_cons;
};
/*
* FCoE CONFQ element $$KEEP_ENDIANNESS$$
*/
struct fcoe_confqe {
__le16 ox_id;
__le16 rx_id;
__le32 param;
};
/*
* FCoE conection data base
*/
struct fcoe_conn_db {
#if defined(__BIG_ENDIAN)
u16 rsrv0;
u16 rq_prod;
#elif defined(__LITTLE_ENDIAN)
u16 rq_prod;
u16 rsrv0;
#endif
u32 rsrv1;
struct regpair cq_arm;
};
/*
* FCoE CQ element $$KEEP_ENDIANNESS$$
*/
struct fcoe_cqe {
__le16 wqe;
#define FCOE_CQE_CQE_INFO (0x3FFF<<0)
#define FCOE_CQE_CQE_INFO_SHIFT 0
#define FCOE_CQE_CQE_TYPE (0x1<<14)
#define FCOE_CQE_CQE_TYPE_SHIFT 14
#define FCOE_CQE_TOGGLE_BIT (0x1<<15)
#define FCOE_CQE_TOGGLE_BIT_SHIFT 15
};
/*
* FCoE error/warning reporting entry $$KEEP_ENDIANNESS$$
*/
struct fcoe_partial_err_report_entry {
__le32 err_warn_bitmap_lo;
__le32 err_warn_bitmap_hi;
__le32 tx_buf_off;
__le32 rx_buf_off;
};
/*
* FCoE error/warning reporting entry $$KEEP_ENDIANNESS$$
*/
struct fcoe_err_report_entry {
struct fcoe_partial_err_report_entry data;
struct fcoe_fc_hdr fc_hdr;
};
/*
* FCoE hash table entry (32 bytes) $$KEEP_ENDIANNESS$$
*/
struct fcoe_hash_table_entry {
u8 s_id_0;
u8 s_id_1;
u8 s_id_2;
u8 d_id_0;
u8 d_id_1;
u8 d_id_2;
__le16 dst_mac_addr_hi;
__le16 dst_mac_addr_mid;
__le16 dst_mac_addr_lo;
__le16 src_mac_addr_hi;
__le16 vlan_id;
__le16 src_mac_addr_lo;
__le16 src_mac_addr_mid;
u8 vlan_flag;
u8 reserved0;
__le16 reserved1;
__le32 reserved2;
__le32 field_id;
#define FCOE_HASH_TABLE_ENTRY_CID (0xFFFFFF<<0)
#define FCOE_HASH_TABLE_ENTRY_CID_SHIFT 0
#define FCOE_HASH_TABLE_ENTRY_RESERVED3 (0x7F<<24)
#define FCOE_HASH_TABLE_ENTRY_RESERVED3_SHIFT 24
#define FCOE_HASH_TABLE_ENTRY_VALID (0x1<<31)
#define FCOE_HASH_TABLE_ENTRY_VALID_SHIFT 31
};
/*
* FCoE LCQ element $$KEEP_ENDIANNESS$$
*/
struct fcoe_lcqe {
__le32 wqe;
#define FCOE_LCQE_TASK_ID (0xFFFF<<0)
#define FCOE_LCQE_TASK_ID_SHIFT 0
#define FCOE_LCQE_LCQE_TYPE (0xFF<<16)
#define FCOE_LCQE_LCQE_TYPE_SHIFT 16
#define FCOE_LCQE_RESERVED (0xFF<<24)
#define FCOE_LCQE_RESERVED_SHIFT 24
};
/*
* FCoE pending work request CQE $$KEEP_ENDIANNESS$$
*/
struct fcoe_pend_wq_cqe {
__le16 wqe;
#define FCOE_PEND_WQ_CQE_TASK_ID (0x3FFF<<0)
#define FCOE_PEND_WQ_CQE_TASK_ID_SHIFT 0
#define FCOE_PEND_WQ_CQE_CQE_TYPE (0x1<<14)
#define FCOE_PEND_WQ_CQE_CQE_TYPE_SHIFT 14
#define FCOE_PEND_WQ_CQE_TOGGLE_BIT (0x1<<15)
#define FCOE_PEND_WQ_CQE_TOGGLE_BIT_SHIFT 15
};
/*
* FCoE RX statistics parameters section#0 $$KEEP_ENDIANNESS$$
*/
struct fcoe_rx_stat_params_section0 {
__le32 fcoe_rx_pkt_cnt;
__le32 fcoe_rx_byte_cnt;
};
/*
* FCoE RX statistics parameters section#1 $$KEEP_ENDIANNESS$$
*/
struct fcoe_rx_stat_params_section1 {
__le32 fcoe_ver_cnt;
__le32 fcoe_rx_drop_pkt_cnt;
};
/*
* FCoE RX statistics parameters section#2 $$KEEP_ENDIANNESS$$
*/
struct fcoe_rx_stat_params_section2 {
__le32 fc_crc_cnt;
__le32 eofa_del_cnt;
__le32 miss_frame_cnt;
__le32 seq_timeout_cnt;
__le32 drop_seq_cnt;
__le32 fcoe_rx_drop_pkt_cnt;
__le32 fcp_rx_pkt_cnt;
__le32 reserved0;
};
/*
* FCoE TX statistics parameters $$KEEP_ENDIANNESS$$
*/
struct fcoe_tx_stat_params {
__le32 fcoe_tx_pkt_cnt;
__le32 fcoe_tx_byte_cnt;
__le32 fcp_tx_pkt_cnt;
__le32 reserved0;
};
/*
* FCoE statistics parameters $$KEEP_ENDIANNESS$$
*/
struct fcoe_statistics_params {
struct fcoe_tx_stat_params tx_stat;
struct fcoe_rx_stat_params_section0 rx_stat0;
struct fcoe_rx_stat_params_section1 rx_stat1;
struct fcoe_rx_stat_params_section2 rx_stat2;
};
/*
* FCoE t2 hash table entry (64 bytes) $$KEEP_ENDIANNESS$$
*/
struct fcoe_t2_hash_table_entry {
struct fcoe_hash_table_entry data;
struct regpair next;
struct regpair reserved0[3];
};
/*
* FCoE unsolicited CQE $$KEEP_ENDIANNESS$$
*/
struct fcoe_unsolicited_cqe {
__le16 wqe;
#define FCOE_UNSOLICITED_CQE_SUBTYPE (0x3<<0)
#define FCOE_UNSOLICITED_CQE_SUBTYPE_SHIFT 0
#define FCOE_UNSOLICITED_CQE_PKT_LEN (0xFFF<<2)
#define FCOE_UNSOLICITED_CQE_PKT_LEN_SHIFT 2
#define FCOE_UNSOLICITED_CQE_CQE_TYPE (0x1<<14)
#define FCOE_UNSOLICITED_CQE_CQE_TYPE_SHIFT 14
#define FCOE_UNSOLICITED_CQE_TOGGLE_BIT (0x1<<15)
#define FCOE_UNSOLICITED_CQE_TOGGLE_BIT_SHIFT 15
};
#endif /* __57XX_FCOE_HSI_LINUX_LE__ */
+12
View File
@@ -0,0 +1,12 @@
config SCSI_BNX2X_FCOE
tristate "Broadcom NetXtreme II FCoE support"
depends on PCI
select NETDEVICES
select ETHERNET
select NET_VENDOR_BROADCOM
select LIBFC
select LIBFCOE
select CNIC
---help---
This driver supports FCoE offload for the Broadcom NetXtreme II
devices.
+3
View File
@@ -0,0 +1,3 @@
obj-$(CONFIG_SCSI_BNX2X_FCOE) += bnx2fc.o
bnx2fc-y := bnx2fc_els.o bnx2fc_fcoe.o bnx2fc_hwi.o bnx2fc_io.o bnx2fc_tgt.o
+554
View File
@@ -0,0 +1,554 @@
#ifndef _BNX2FC_H_
#define _BNX2FC_H_
/* bnx2fc.h: Broadcom NetXtreme II Linux FCoE offload driver.
*
* Copyright (c) 2008 - 2011 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: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/kthread.h>
#include <linux/crc32.h>
#include <linux/cpu.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
#include <linux/log2.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/io.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_tcq.h>
#include <scsi/libfc.h>
#include <scsi/libfcoe.h>
#include <scsi/fc_encode.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/fc/fc_fip.h>
#include <scsi/fc/fc_fc2.h>
#include <scsi/fc_frame.h>
#include <scsi/fc/fc_fcoe.h>
#include <scsi/fc/fc_fcp.h>
#include "57xx_hsi_bnx2fc.h"
#include "bnx2fc_debug.h"
#include "../../net/ethernet/broadcom/cnic_if.h"
#include "bnx2fc_constants.h"
#define BNX2FC_NAME "bnx2fc"
#define BNX2FC_VERSION "1.0.10"
#define PFX "bnx2fc: "
#define BNX2X_DOORBELL_PCI_BAR 2
#define BNX2FC_MAX_BD_LEN 0xffff
#define BNX2FC_BD_SPLIT_SZ 0x8000
#define BNX2FC_MAX_BDS_PER_CMD 256
#define BNX2FC_SQ_WQES_MAX 256
#define BNX2FC_SCSI_MAX_SQES ((3 * BNX2FC_SQ_WQES_MAX) / 8)
#define BNX2FC_TM_MAX_SQES ((BNX2FC_SQ_WQES_MAX) / 2)
#define BNX2FC_ELS_MAX_SQES (BNX2FC_TM_MAX_SQES - 1)
#define BNX2FC_RQ_WQES_MAX 16
#define BNX2FC_CQ_WQES_MAX (BNX2FC_SQ_WQES_MAX + BNX2FC_RQ_WQES_MAX)
#define BNX2FC_NUM_MAX_SESS 1024
#define BNX2FC_NUM_MAX_SESS_LOG (ilog2(BNX2FC_NUM_MAX_SESS))
#define BNX2FC_MAX_OUTSTANDING_CMNDS 2048
#define BNX2FC_CAN_QUEUE BNX2FC_MAX_OUTSTANDING_CMNDS
#define BNX2FC_ELSTM_XIDS BNX2FC_CAN_QUEUE
#define BNX2FC_MIN_PAYLOAD 256
#define BNX2FC_MAX_PAYLOAD 2048
#define BNX2FC_MFS \
(BNX2FC_MAX_PAYLOAD + sizeof(struct fc_frame_header))
#define BNX2FC_MINI_JUMBO_MTU 2500
#define BNX2FC_RQ_BUF_SZ 256
#define BNX2FC_RQ_BUF_LOG_SZ (ilog2(BNX2FC_RQ_BUF_SZ))
#define BNX2FC_SQ_WQE_SIZE (sizeof(struct fcoe_sqe))
#define BNX2FC_CQ_WQE_SIZE (sizeof(struct fcoe_cqe))
#define BNX2FC_RQ_WQE_SIZE (BNX2FC_RQ_BUF_SZ)
#define BNX2FC_XFERQ_WQE_SIZE (sizeof(struct fcoe_xfrqe))
#define BNX2FC_CONFQ_WQE_SIZE (sizeof(struct fcoe_confqe))
#define BNX2FC_5771X_DB_PAGE_SIZE 128
#define BNX2FC_MAX_TASKS \
(BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS)
#define BNX2FC_TASK_SIZE 128
#define BNX2FC_TASKS_PER_PAGE (PAGE_SIZE/BNX2FC_TASK_SIZE)
#define BNX2FC_TASK_CTX_ARR_SZ (BNX2FC_MAX_TASKS/BNX2FC_TASKS_PER_PAGE)
#define BNX2FC_MAX_ROWS_IN_HASH_TBL 8
#define BNX2FC_HASH_TBL_CHUNK_SIZE (16 * 1024)
#define BNX2FC_MAX_SEQS 255
#define BNX2FC_MAX_RETRY_CNT 3
#define BNX2FC_MAX_RPORT_RETRY_CNT 255
#define BNX2FC_READ (1 << 1)
#define BNX2FC_WRITE (1 << 0)
#define BNX2FC_MIN_XID 0
#define BNX2FC_MAX_XID \
(BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS - 1)
#define FCOE_MAX_NUM_XIDS 0x2000
#define FCOE_MIN_XID (BNX2FC_MAX_XID + 1)
#define FCOE_MAX_XID (FCOE_MIN_XID + FCOE_MAX_NUM_XIDS - 1)
#define FCOE_XIDS_PER_CPU (FCOE_MIN_XID + (512 * nr_cpu_ids) - 1)
#define BNX2FC_MAX_LUN 0xFFFF
#define BNX2FC_MAX_FCP_TGT 256
#define BNX2FC_MAX_CMD_LEN 16
#define BNX2FC_TM_TIMEOUT 60 /* secs */
#define BNX2FC_IO_TIMEOUT 20000UL /* msecs */
#define BNX2FC_WAIT_CNT 1200
#define BNX2FC_FW_TIMEOUT (3 * HZ)
#define PORT_MAX 2
#define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status)
/* FC FCP Status */
#define FC_GOOD 0
#define BNX2FC_RNID_HBA 0x7
#define SRR_RETRY_COUNT 5
#define REC_RETRY_COUNT 1
#define BNX2FC_NUM_ERR_BITS 63
#define BNX2FC_RELOGIN_WAIT_TIME 200
#define BNX2FC_RELOGIN_WAIT_CNT 10
/* bnx2fc driver uses only one instance of fcoe_percpu_s */
extern struct fcoe_percpu_s bnx2fc_global;
extern struct workqueue_struct *bnx2fc_wq;
struct bnx2fc_percpu_s {
struct task_struct *iothread;
struct list_head work_list;
spinlock_t fp_work_lock;
};
struct bnx2fc_hba {
struct list_head list;
struct cnic_dev *cnic;
struct pci_dev *pcidev;
struct net_device *phys_dev;
unsigned long reg_with_cnic;
#define BNX2FC_CNIC_REGISTERED 1
struct bnx2fc_cmd_mgr *cmd_mgr;
spinlock_t hba_lock;
struct mutex hba_mutex;
unsigned long adapter_state;
#define ADAPTER_STATE_UP 0
#define ADAPTER_STATE_GOING_DOWN 1
#define ADAPTER_STATE_LINK_DOWN 2
#define ADAPTER_STATE_READY 3
unsigned long flags;
#define BNX2FC_FLAG_FW_INIT_DONE 0
#define BNX2FC_FLAG_DESTROY_CMPL 1
u32 next_conn_id;
struct fcoe_task_ctx_entry **task_ctx;
dma_addr_t *task_ctx_dma;
struct regpair *task_ctx_bd_tbl;
dma_addr_t task_ctx_bd_dma;
int hash_tbl_segment_count;
void **hash_tbl_segments;
void *hash_tbl_pbl;
dma_addr_t hash_tbl_pbl_dma;
struct fcoe_t2_hash_table_entry *t2_hash_tbl;
dma_addr_t t2_hash_tbl_dma;
char *t2_hash_tbl_ptr;
dma_addr_t t2_hash_tbl_ptr_dma;
char *dummy_buffer;
dma_addr_t dummy_buf_dma;
/* Active list of offloaded sessions */
struct bnx2fc_rport **tgt_ofld_list;
/* statistics */
struct fcoe_statistics_params *stats_buffer;
dma_addr_t stats_buf_dma;
struct completion stat_req_done;
/*destroy handling */
struct timer_list destroy_timer;
wait_queue_head_t destroy_wait;
/* linkdown handling */
wait_queue_head_t shutdown_wait;
int wait_for_link_down;
int num_ofld_sess;
struct list_head vports;
};
struct bnx2fc_interface {
struct list_head list;
unsigned long if_flags;
#define BNX2FC_CTLR_INIT_DONE 0
struct bnx2fc_hba *hba;
struct net_device *netdev;
struct packet_type fcoe_packet_type;
struct packet_type fip_packet_type;
struct workqueue_struct *timer_work_queue;
struct kref kref;
struct fcoe_ctlr ctlr;
u8 vlan_enabled;
int vlan_id;
bool enabled;
};
#define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_interface, ctlr)
struct bnx2fc_lport {
struct list_head list;
struct fc_lport *lport;
};
struct bnx2fc_cmd_mgr {
struct bnx2fc_hba *hba;
u16 next_idx;
struct list_head *free_list;
spinlock_t *free_list_lock;
struct io_bdt **io_bdt_pool;
struct bnx2fc_cmd **cmds;
};
struct bnx2fc_rport {
struct fcoe_port *port;
struct fc_rport *rport;
struct fc_rport_priv *rdata;
void __iomem *ctx_base;
#define DPM_TRIGER_TYPE 0x40
u32 io_timeout;
u32 fcoe_conn_id;
u32 context_id;
u32 sid;
int dev_type;
unsigned long flags;
#define BNX2FC_FLAG_SESSION_READY 0x1
#define BNX2FC_FLAG_OFFLOADED 0x2
#define BNX2FC_FLAG_DISABLED 0x3
#define BNX2FC_FLAG_DESTROYED 0x4
#define BNX2FC_FLAG_OFLD_REQ_CMPL 0x5
#define BNX2FC_FLAG_CTX_ALLOC_FAILURE 0x6
#define BNX2FC_FLAG_UPLD_REQ_COMPL 0x7
#define BNX2FC_FLAG_EXPL_LOGO 0x8
u8 src_addr[ETH_ALEN];
u32 max_sqes;
u32 max_rqes;
u32 max_cqes;
atomic_t free_sqes;
struct b577xx_doorbell_set_prod sq_db;
struct b577xx_fcoe_rx_doorbell rx_db;
struct fcoe_sqe *sq;
dma_addr_t sq_dma;
u16 sq_prod_idx;
u8 sq_curr_toggle_bit;
u32 sq_mem_size;
struct fcoe_cqe *cq;
dma_addr_t cq_dma;
u16 cq_cons_idx;
u8 cq_curr_toggle_bit;
u32 cq_mem_size;
void *rq;
dma_addr_t rq_dma;
u32 rq_prod_idx;
u32 rq_cons_idx;
u32 rq_mem_size;
void *rq_pbl;
dma_addr_t rq_pbl_dma;
u32 rq_pbl_size;
struct fcoe_xfrqe *xferq;
dma_addr_t xferq_dma;
u32 xferq_mem_size;
struct fcoe_confqe *confq;
dma_addr_t confq_dma;
u32 confq_mem_size;
void *confq_pbl;
dma_addr_t confq_pbl_dma;
u32 confq_pbl_size;
struct fcoe_conn_db *conn_db;
dma_addr_t conn_db_dma;
u32 conn_db_mem_size;
struct fcoe_sqe *lcq;
dma_addr_t lcq_dma;
u32 lcq_mem_size;
void *ofld_req[4];
dma_addr_t ofld_req_dma[4];
void *enbl_req;
dma_addr_t enbl_req_dma;
spinlock_t tgt_lock;
spinlock_t cq_lock;
atomic_t num_active_ios;
u32 flush_in_prog;
unsigned long timestamp;
struct list_head free_task_list;
struct bnx2fc_cmd *pending_queue[BNX2FC_SQ_WQES_MAX+1];
struct list_head active_cmd_queue;
struct list_head els_queue;
struct list_head io_retire_queue;
struct list_head active_tm_queue;
struct timer_list ofld_timer;
wait_queue_head_t ofld_wait;
struct timer_list upld_timer;
wait_queue_head_t upld_wait;
};
struct bnx2fc_mp_req {
u8 tm_flags;
u32 req_len;
void *req_buf;
dma_addr_t req_buf_dma;
struct fcoe_bd_ctx *mp_req_bd;
dma_addr_t mp_req_bd_dma;
struct fc_frame_header req_fc_hdr;
u32 resp_len;
void *resp_buf;
dma_addr_t resp_buf_dma;
struct fcoe_bd_ctx *mp_resp_bd;
dma_addr_t mp_resp_bd_dma;
struct fc_frame_header resp_fc_hdr;
};
struct bnx2fc_els_cb_arg {
struct bnx2fc_cmd *aborted_io_req;
struct bnx2fc_cmd *io_req;
u16 l2_oxid;
u32 offset;
enum fc_rctl r_ctl;
};
/* bnx2fc command structure */
struct bnx2fc_cmd {
struct list_head link;
u8 on_active_queue;
u8 on_tmf_queue;
u8 cmd_type;
#define BNX2FC_SCSI_CMD 1
#define BNX2FC_TASK_MGMT_CMD 2
#define BNX2FC_ABTS 3
#define BNX2FC_ELS 4
#define BNX2FC_CLEANUP 5
#define BNX2FC_SEQ_CLEANUP 6
u8 io_req_flags;
struct kref refcount;
struct fcoe_port *port;
struct bnx2fc_rport *tgt;
struct scsi_cmnd *sc_cmd;
struct bnx2fc_cmd_mgr *cmd_mgr;
struct bnx2fc_mp_req mp_req;
void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg);
struct bnx2fc_els_cb_arg *cb_arg;
struct delayed_work timeout_work; /* timer for ULP timeouts */
struct completion tm_done;
int wait_for_comp;
u16 xid;
struct fcoe_err_report_entry err_entry;
struct fcoe_task_ctx_entry *task;
struct io_bdt *bd_tbl;
struct fcp_rsp *rsp;
size_t data_xfer_len;
unsigned long req_flags;
#define BNX2FC_FLAG_ISSUE_RRQ 0x1
#define BNX2FC_FLAG_ISSUE_ABTS 0x2
#define BNX2FC_FLAG_ABTS_DONE 0x3
#define BNX2FC_FLAG_TM_COMPL 0x4
#define BNX2FC_FLAG_TM_TIMEOUT 0x5
#define BNX2FC_FLAG_IO_CLEANUP 0x6
#define BNX2FC_FLAG_RETIRE_OXID 0x7
#define BNX2FC_FLAG_EH_ABORT 0x8
#define BNX2FC_FLAG_IO_COMPL 0x9
#define BNX2FC_FLAG_ELS_DONE 0xa
#define BNX2FC_FLAG_ELS_TIMEOUT 0xb
#define BNX2FC_FLAG_CMD_LOST 0xc
#define BNX2FC_FLAG_SRR_SENT 0xd
u8 rec_retry;
u8 srr_retry;
u32 srr_offset;
u8 srr_rctl;
u32 fcp_resid;
u32 fcp_rsp_len;
u32 fcp_sns_len;
u8 cdb_status; /* SCSI IO status */
u8 fcp_status; /* FCP IO status */
u8 fcp_rsp_code;
u8 scsi_comp_flags;
};
struct io_bdt {
struct bnx2fc_cmd *io_req;
struct fcoe_bd_ctx *bd_tbl;
dma_addr_t bd_tbl_dma;
u16 bd_valid;
};
struct bnx2fc_work {
struct list_head list;
struct bnx2fc_rport *tgt;
u16 wqe;
};
struct bnx2fc_unsol_els {
struct fc_lport *lport;
struct fc_frame *fp;
struct bnx2fc_hba *hba;
struct work_struct unsol_els_work;
};
struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt);
struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type);
void bnx2fc_cmd_release(struct kref *ref);
int bnx2fc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd);
int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba);
int bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba);
int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
struct bnx2fc_rport *tgt);
int bnx2fc_send_session_disable_req(struct fcoe_port *port,
struct bnx2fc_rport *tgt);
int bnx2fc_send_session_destroy_req(struct bnx2fc_hba *hba,
struct bnx2fc_rport *tgt);
int bnx2fc_map_doorbell(struct bnx2fc_rport *tgt);
void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[],
u32 num_cqe);
int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba);
void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba);
int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba);
void bnx2fc_free_fw_resc(struct bnx2fc_hba *hba);
struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
u16 min_xid, u16 max_xid);
void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr);
void bnx2fc_get_link_state(struct bnx2fc_hba *hba);
char *bnx2fc_get_next_rqe(struct bnx2fc_rport *tgt, u8 num_items);
void bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items);
int bnx2fc_get_paged_crc_eof(struct sk_buff *skb, int tlen);
int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req);
int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp);
int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp);
int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp);
int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req);
int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req);
void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req,
unsigned int timer_msec);
int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req);
void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req,
struct fcoe_task_ctx_entry *task,
u16 orig_xid);
void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnup_req,
struct fcoe_task_ctx_entry *task,
struct bnx2fc_cmd *orig_io_req,
u32 offset);
void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req,
struct fcoe_task_ctx_entry *task);
void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
struct fcoe_task_ctx_entry *task);
void bnx2fc_add_2_sq(struct bnx2fc_rport *tgt, u16 xid);
void bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt);
int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd);
int bnx2fc_eh_host_reset(struct scsi_cmnd *sc_cmd);
int bnx2fc_eh_target_reset(struct scsi_cmnd *sc_cmd);
int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd);
void bnx2fc_rport_event_handler(struct fc_lport *lport,
struct fc_rport_priv *rport,
enum fc_rport_event event);
void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
struct fcoe_task_ctx_entry *task,
u8 num_rq);
void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
struct fcoe_task_ctx_entry *task,
u8 num_rq);
void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
struct fcoe_task_ctx_entry *task,
u8 num_rq);
void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
struct fcoe_task_ctx_entry *task,
u8 num_rq);
void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
struct fcoe_task_ctx_entry *task,
u8 num_rq);
void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req,
struct fcp_cmnd *fcp_cmnd);
void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt);
struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did,
struct fc_frame *fp, unsigned int op,
void (*resp)(struct fc_seq *,
struct fc_frame *,
void *),
void *arg, u32 timeout);
void bnx2fc_arm_cq(struct bnx2fc_rport *tgt);
int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt);
void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe);
struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
u32 port_id);
void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
unsigned char *buf,
u32 frame_len, u16 l2_oxid);
int bnx2fc_send_stat_req(struct bnx2fc_hba *hba);
int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, struct bnx2fc_cmd *io_req);
int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req);
int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl);
void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnup_req,
struct fcoe_task_ctx_entry *task,
u8 rx_state);
int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset,
enum fc_rctl r_ctl);
#endif
@@ -0,0 +1,274 @@
#ifndef __BNX2FC_CONSTANTS_H_
#define __BNX2FC_CONSTANTS_H_
/**
* This file defines HSI constants for the FCoE flows
*/
/* Current FCoE HSI version number composed of two fields (16 bit) */
/* Implies on a change broken previous HSI */
#define FCOE_HSI_MAJOR_VERSION (2)
/* Implies on a change which does not broken previous HSI */
#define FCOE_HSI_MINOR_VERSION (1)
/* KWQ/KCQ FCoE layer code */
#define FCOE_KWQE_LAYER_CODE (7)
/* KWQ (kernel work queue) request op codes */
#define FCOE_KWQE_OPCODE_INIT1 (0)
#define FCOE_KWQE_OPCODE_INIT2 (1)
#define FCOE_KWQE_OPCODE_INIT3 (2)
#define FCOE_KWQE_OPCODE_OFFLOAD_CONN1 (3)
#define FCOE_KWQE_OPCODE_OFFLOAD_CONN2 (4)
#define FCOE_KWQE_OPCODE_OFFLOAD_CONN3 (5)
#define FCOE_KWQE_OPCODE_OFFLOAD_CONN4 (6)
#define FCOE_KWQE_OPCODE_ENABLE_CONN (7)
#define FCOE_KWQE_OPCODE_DISABLE_CONN (8)
#define FCOE_KWQE_OPCODE_DESTROY_CONN (9)
#define FCOE_KWQE_OPCODE_DESTROY (10)
#define FCOE_KWQE_OPCODE_STAT (11)
/* KCQ (kernel completion queue) response op codes */
#define FCOE_KCQE_OPCODE_INIT_FUNC (0x10)
#define FCOE_KCQE_OPCODE_DESTROY_FUNC (0x11)
#define FCOE_KCQE_OPCODE_STAT_FUNC (0x12)
#define FCOE_KCQE_OPCODE_OFFLOAD_CONN (0x15)
#define FCOE_KCQE_OPCODE_ENABLE_CONN (0x16)
#define FCOE_KCQE_OPCODE_DISABLE_CONN (0x17)
#define FCOE_KCQE_OPCODE_DESTROY_CONN (0x18)
#define FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION (0x20)
#define FCOE_KCQE_OPCODE_FCOE_ERROR (0x21)
/* KCQ (kernel completion queue) completion status */
#define FCOE_KCQE_COMPLETION_STATUS_SUCCESS (0x0)
#define FCOE_KCQE_COMPLETION_STATUS_ERROR (0x1)
#define FCOE_KCQE_COMPLETION_STATUS_INVALID_OPCODE (0x2)
#define FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE (0x3)
#define FCOE_KCQE_COMPLETION_STATUS_CTX_FREE_FAILURE (0x4)
#define FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR (0x5)
#define FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION (0x6)
#define FCOE_KCQE_COMPLETION_STATUS_PARITY_ERROR (0x81)
/* CQE type */
#define FCOE_PENDING_CQE_TYPE 0
#define FCOE_UNSOLIC_CQE_TYPE 1
/* Unsolicited CQE type */
#define FCOE_UNSOLICITED_FRAME_CQE_TYPE 0
#define FCOE_ERROR_DETECTION_CQE_TYPE 1
#define FCOE_WARNING_DETECTION_CQE_TYPE 2
/* E_D_TOV timer resolution in ms */
#define FCOE_E_D_TOV_TIMER_RESOLUTION_MS (20)
/* E_D_TOV timer resolution for SDM (4 micro) */
#define FCOE_E_D_TOV_SDM_TIMER_RESOLUTION \
(FCOE_E_D_TOV_TIMER_RESOLUTION_MS * 1000 / 4)
/* REC timer resolution in ms */
#define FCOE_REC_TIMER_RESOLUTION_MS (20)
/* REC timer resolution for SDM (4 micro) */
#define FCOE_REC_SDM_TIMER_RESOLUTION (FCOE_REC_TIMER_RESOLUTION_MS * 1000 / 4)
/* E_D_TOV timer default wraparound value (2 sec) in 20 ms resolution */
#define FCOE_E_D_TOV_DEFAULT_WRAPAROUND_VAL \
(2000 / FCOE_E_D_TOV_TIMER_RESOLUTION_MS)
/* REC_TOV timer default wraparound value (3 sec) in 20 ms resolution */
#define FCOE_REC_TOV_DEFAULT_WRAPAROUND_VAL \
(3000 / FCOE_REC_TIMER_RESOLUTION_MS)
#define FCOE_NUM_OF_TIMER_TASKS (8 * 1024)
#define FCOE_NUM_OF_CACHED_TASKS_TIMER (8)
/* Task context constants */
/******** Remove FCP_CMD write tce sleep ***********************/
/* In case timer services are required then shall be updated by Xstorm after
* start processing the task. In case no timer facilities are required then the
* driver would initialize the state to this value
*
#define FCOE_TASK_TX_STATE_NORMAL 0
* After driver has initialize the task in case timer services required *
#define FCOE_TASK_TX_STATE_INIT 1
******** Remove FCP_CMD write tce sleep ***********************/
/* After driver has initialize the task in case timer services required */
#define FCOE_TASK_TX_STATE_INIT 0
/* In case timer services are required then shall be updated by Xstorm after
* start processing the task. In case no timer facilities are required then the
* driver would initialize the state to this value
*/
#define FCOE_TASK_TX_STATE_NORMAL 1
/* Task is under abort procedure. Updated in order to stop processing of
* pending WQEs on this task
*/
#define FCOE_TASK_TX_STATE_ABORT 2
/* For E_D_T_TOV timer expiration in Xstorm (Class 2 only) */
#define FCOE_TASK_TX_STATE_ERROR 3
/* For REC_TOV timer expiration indication received from Xstorm */
#define FCOE_TASK_TX_STATE_WARNING 4
/* For completed unsolicited task */
#define FCOE_TASK_TX_STATE_UNSOLICITED_COMPLETED 5
/* For exchange cleanup request task */
#define FCOE_TASK_TX_STATE_EXCHANGE_CLEANUP 6
/* For sequence cleanup request task */
#define FCOE_TASK_TX_STATE_SEQUENCE_CLEANUP 7
/* For completion the ABTS task. */
#define FCOE_TASK_TX_STATE_ABTS_TX 8
#define FCOE_TASK_RX_STATE_NORMAL 0
#define FCOE_TASK_RX_STATE_COMPLETED 1
/* Obsolete: Intermediate completion (middle path with local completion) */
#define FCOE_TASK_RX_STATE_INTER_COMP 2
/* For REC_TOV timer expiration indication received from Xstorm */
#define FCOE_TASK_RX_STATE_WARNING 3
/* For E_D_T_TOV timer expiration in Ustorm */
#define FCOE_TASK_RX_STATE_ERROR 4
/* FW only: First visit at rx-path, part of the abts round trip */
#define FCOE_TASK_RX_STATE_ABTS_IN_PROCESS 5
/* FW only: Second visit at rx-path, after ABTS frame transmitted */
#define FCOE_TASK_RX_STATE_ABTS_TRANSMITTED 6
/* Special completion indication in case of task was aborted. */
#define FCOE_TASK_RX_STATE_ABTS_COMPLETED 7
/* FW only: First visit at rx-path, part of the cleanup round trip */
#define FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_IN_PROCESS 8
/* FW only: Special completion indication in case of task was cleaned. */
#define FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED 9
/* Not in used: Special completion indication (in task requested the exchange
* cleanup) in case cleaned task is in non-valid.
*/
#define FCOE_TASK_RX_STATE_ABORT_CLEANUP_COMPLETED 10
/* Special completion indication (in task requested the sequence cleanup) in
* case cleaned task was already returned to normal.
*/
#define FCOE_TASK_RX_STATE_IGNORED_SEQUENCE_CLEANUP 11
#define FCOE_TASK_TYPE_WRITE 0
#define FCOE_TASK_TYPE_READ 1
#define FCOE_TASK_TYPE_MIDPATH 2
#define FCOE_TASK_TYPE_UNSOLICITED 3
#define FCOE_TASK_TYPE_ABTS 4
#define FCOE_TASK_TYPE_EXCHANGE_CLEANUP 5
#define FCOE_TASK_TYPE_SEQUENCE_CLEANUP 6
#define FCOE_TASK_DEV_TYPE_DISK 0
#define FCOE_TASK_DEV_TYPE_TAPE 1
#define FCOE_TASK_CLASS_TYPE_3 0
#define FCOE_TASK_CLASS_TYPE_2 1
/* FCoE/FC packet fields */
#define FCOE_ETH_TYPE 0x8906
/* FCoE maximum elements in hash table */
#define FCOE_MAX_ELEMENTS_IN_HASH_TABLE_ROW 8
/* FCoE half of the elements in hash table */
#define FCOE_HALF_ELEMENTS_IN_HASH_TABLE_ROW \
(FCOE_MAX_ELEMENTS_IN_HASH_TABLE_ROW / 2)
/* FcoE number of cached T2 entries */
#define T_FCOE_NUMBER_OF_CACHED_T2_ENTRIES (4)
/* FCoE maximum elements in hash table */
#define FCOE_HASH_TBL_CHUNK_SIZE 16384
/* Everest FCoE connection type */
#define B577XX_FCOE_CONNECTION_TYPE 4
/* FCoE number of rows (in log). This number derives
* from the maximum connections supported which is 2048.
* TBA: Need a different constant for E2
*/
#define FCOE_MAX_NUM_SESSIONS_LOG 11
#define FC_ABTS_REPLY_MAX_PAYLOAD_LEN 12
/* Error codes for Error Reporting in slow path flows */
#define FCOE_SLOW_PATH_ERROR_CODE_TOO_MANY_FUNCS 0
#define FCOE_SLOW_PATH_ERROR_CODE_NO_LICENSE 1
/* Error codes for Error Reporting in fast path flows
* XFER error codes
*/
#define FCOE_ERROR_CODE_XFER_OOO_RO 0
#define FCOE_ERROR_CODE_XFER_RO_NOT_ALIGNED 1
#define FCOE_ERROR_CODE_XFER_NULL_BURST_LEN 2
#define FCOE_ERROR_CODE_XFER_RO_GREATER_THAN_DATA2TRNS 3
#define FCOE_ERROR_CODE_XFER_INVALID_PAYLOAD_SIZE 4
#define FCOE_ERROR_CODE_XFER_TASK_TYPE_NOT_WRITE 5
#define FCOE_ERROR_CODE_XFER_PEND_XFER_SET 6
#define FCOE_ERROR_CODE_XFER_OPENED_SEQ 7
#define FCOE_ERROR_CODE_XFER_FCTL 8
/* FCP RSP error codes */
#define FCOE_ERROR_CODE_FCP_RSP_BIDI_FLAGS_SET 9
#define FCOE_ERROR_CODE_FCP_RSP_UNDERFLOW 10
#define FCOE_ERROR_CODE_FCP_RSP_OVERFLOW 11
#define FCOE_ERROR_CODE_FCP_RSP_INVALID_LENGTH_FIELD 12
#define FCOE_ERROR_CODE_FCP_RSP_INVALID_SNS_FIELD 13
#define FCOE_ERROR_CODE_FCP_RSP_INVALID_PAYLOAD_SIZE 14
#define FCOE_ERROR_CODE_FCP_RSP_PEND_XFER_SET 15
#define FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ 16
#define FCOE_ERROR_CODE_FCP_RSP_FCTL 17
#define FCOE_ERROR_CODE_FCP_RSP_LAST_SEQ_RESET 18
#define FCOE_ERROR_CODE_FCP_RSP_CONF_REQ_NOT_SUPPORTED_YET 19
/* FCP DATA error codes */
#define FCOE_ERROR_CODE_DATA_OOO_RO 20
#define FCOE_ERROR_CODE_DATA_EXCEEDS_DEFINED_MAX_FRAME_SIZE 21
#define FCOE_ERROR_CODE_DATA_EXCEEDS_DATA2TRNS 22
#define FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET 23
#define FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET 24
#define FCOE_ERROR_CODE_DATA_EOFN_END_SEQ_SET 25
#define FCOE_ERROR_CODE_DATA_EOFT_END_SEQ_RESET 26
#define FCOE_ERROR_CODE_DATA_TASK_TYPE_NOT_READ 27
#define FCOE_ERROR_CODE_DATA_FCTL 28
/* Middle path error codes */
#define FCOE_ERROR_CODE_MIDPATH_INVALID_TYPE 29
#define FCOE_ERROR_CODE_MIDPATH_SOFI3_SEQ_ACTIVE_SET 30
#define FCOE_ERROR_CODE_MIDPATH_SOFN_SEQ_ACTIVE_RESET 31
#define FCOE_ERROR_CODE_MIDPATH_EOFN_END_SEQ_SET 32
#define FCOE_ERROR_CODE_MIDPATH_EOFT_END_SEQ_RESET 33
#define FCOE_ERROR_CODE_MIDPATH_REPLY_FCTL 34
#define FCOE_ERROR_CODE_MIDPATH_INVALID_REPLY 35
#define FCOE_ERROR_CODE_MIDPATH_ELS_REPLY_RCTL 36
/* ABTS error codes */
#define FCOE_ERROR_CODE_ABTS_REPLY_F_CTL 37
#define FCOE_ERROR_CODE_ABTS_REPLY_DDF_RCTL_FIELD 38
#define FCOE_ERROR_CODE_ABTS_REPLY_INVALID_BLS_RCTL 39
#define FCOE_ERROR_CODE_ABTS_REPLY_INVALID_RCTL 40
#define FCOE_ERROR_CODE_ABTS_REPLY_RCTL_GENERAL_MISMATCH 41
/* Common error codes */
#define FCOE_ERROR_CODE_COMMON_MIDDLE_FRAME_WITH_PAD 42
#define FCOE_ERROR_CODE_COMMON_SEQ_INIT_IN_TCE 43
#define FCOE_ERROR_CODE_COMMON_FC_HDR_RX_ID_MISMATCH 44
#define FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT 45
#define FCOE_ERROR_CODE_COMMON_DATA_FC_HDR_FCP_TYPE_MISMATCH 46
#define FCOE_ERROR_CODE_COMMON_DATA_NO_MORE_SGES 47
#define FCOE_ERROR_CODE_COMMON_OPTIONAL_FC_HDR 48
#define FCOE_ERROR_CODE_COMMON_READ_TCE_OX_ID_TOO_BIG 49
#define FCOE_ERROR_CODE_COMMON_DATA_WAS_NOT_TRANSMITTED 50
/* Unsolicited Rx error codes */
#define FCOE_ERROR_CODE_UNSOLICITED_TYPE_NOT_ELS 51
#define FCOE_ERROR_CODE_UNSOLICITED_TYPE_NOT_BLS 52
#define FCOE_ERROR_CODE_UNSOLICITED_FCTL_ELS 53
#define FCOE_ERROR_CODE_UNSOLICITED_FCTL_BLS 54
#define FCOE_ERROR_CODE_UNSOLICITED_R_CTL 55
#define FCOE_ERROR_CODE_RW_TASK_DDF_RCTL_INFO_FIELD 56
#define FCOE_ERROR_CODE_RW_TASK_INVALID_RCTL 57
#define FCOE_ERROR_CODE_RW_TASK_RCTL_GENERAL_MISMATCH 58
/* Timer error codes */
#define FCOE_ERROR_CODE_E_D_TOV_TIMER_EXPIRATION 60
#define FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION 61
#endif /* BNX2FC_CONSTANTS_H_ */
+70
View File
@@ -0,0 +1,70 @@
#ifndef __BNX2FC_DEBUG__
#define __BNX2FC_DEBUG__
/* Log level bit mask */
#define LOG_IO 0x01 /* scsi cmd error, cleanup */
#define LOG_TGT 0x02 /* Session setup, cleanup, etc' */
#define LOG_HBA 0x04 /* lport events, link, mtu, etc' */
#define LOG_ELS 0x08 /* ELS logs */
#define LOG_MISC 0x10 /* fcoe L2 frame related logs*/
#define LOG_ALL 0xff /* LOG all messages */
extern unsigned int bnx2fc_debug_level;
#define BNX2FC_CHK_LOGGING(LEVEL, CMD) \
do { \
if (unlikely(bnx2fc_debug_level & LEVEL)) \
do { \
CMD; \
} while (0); \
} while (0)
#define BNX2FC_ELS_DBG(fmt, arg...) \
BNX2FC_CHK_LOGGING(LOG_ELS, \
printk(KERN_INFO PFX fmt, ##arg))
#define BNX2FC_MISC_DBG(fmt, arg...) \
BNX2FC_CHK_LOGGING(LOG_MISC, \
printk(KERN_INFO PFX fmt, ##arg))
#define BNX2FC_IO_DBG(io_req, fmt, arg...) \
do { \
if (!io_req || !io_req->port || !io_req->port->lport || \
!io_req->port->lport->host) \
BNX2FC_CHK_LOGGING(LOG_IO, \
printk(KERN_INFO PFX "NULL " fmt, ##arg)); \
else \
BNX2FC_CHK_LOGGING(LOG_IO, \
shost_printk(KERN_INFO, \
(io_req)->port->lport->host, \
PFX "xid:0x%x " fmt, \
(io_req)->xid, ##arg)); \
} while (0)
#define BNX2FC_TGT_DBG(tgt, fmt, arg...) \
do { \
if (!tgt || !tgt->port || !tgt->port->lport || \
!tgt->port->lport->host || !tgt->rport) \
BNX2FC_CHK_LOGGING(LOG_TGT, \
printk(KERN_INFO PFX "NULL " fmt, ##arg)); \
else \
BNX2FC_CHK_LOGGING(LOG_TGT, \
shost_printk(KERN_INFO, \
(tgt)->port->lport->host, \
PFX "port:%x " fmt, \
(tgt)->rport->port_id, ##arg)); \
} while (0)
#define BNX2FC_HBA_DBG(lport, fmt, arg...) \
do { \
if (!lport || !lport->host) \
BNX2FC_CHK_LOGGING(LOG_HBA, \
printk(KERN_INFO PFX "NULL " fmt, ##arg)); \
else \
BNX2FC_CHK_LOGGING(LOG_HBA, \
shost_printk(KERN_INFO, lport->host, \
PFX fmt, ##arg)); \
} while (0)
#endif
+929
View File
@@ -0,0 +1,929 @@
/*
* bnx2fc_els.c: Broadcom NetXtreme II Linux FCoE offload driver.
* This file contains helper routines that handle ELS requests
* and responses.
*
* Copyright (c) 2008 - 2011 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: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
*/
#include "bnx2fc.h"
static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp,
void *arg);
static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
void *arg);
static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
void *data, u32 data_len,
void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg),
struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec);
static void bnx2fc_rrq_compl(struct bnx2fc_els_cb_arg *cb_arg)
{
struct bnx2fc_cmd *orig_io_req;
struct bnx2fc_cmd *rrq_req;
int rc = 0;
BUG_ON(!cb_arg);
rrq_req = cb_arg->io_req;
orig_io_req = cb_arg->aborted_io_req;
BUG_ON(!orig_io_req);
BNX2FC_ELS_DBG("rrq_compl: orig xid = 0x%x, rrq_xid = 0x%x\n",
orig_io_req->xid, rrq_req->xid);
kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rrq_req->req_flags)) {
/*
* els req is timed out. cleanup the IO with FW and
* drop the completion. Remove from active_cmd_queue.
*/
BNX2FC_ELS_DBG("rrq xid - 0x%x timed out, clean it up\n",
rrq_req->xid);
if (rrq_req->on_active_queue) {
list_del_init(&rrq_req->link);
rrq_req->on_active_queue = 0;
rc = bnx2fc_initiate_cleanup(rrq_req);
BUG_ON(rc);
}
}
kfree(cb_arg);
}
int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req)
{
struct fc_els_rrq rrq;
struct bnx2fc_rport *tgt = aborted_io_req->tgt;
struct fc_lport *lport = tgt->rdata->local_port;
struct bnx2fc_els_cb_arg *cb_arg = NULL;
u32 sid = tgt->sid;
u32 r_a_tov = lport->r_a_tov;
unsigned long start = jiffies;
int rc;
BNX2FC_ELS_DBG("Sending RRQ orig_xid = 0x%x\n",
aborted_io_req->xid);
memset(&rrq, 0, sizeof(rrq));
cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_NOIO);
if (!cb_arg) {
printk(KERN_ERR PFX "Unable to allocate cb_arg for RRQ\n");
rc = -ENOMEM;
goto rrq_err;
}
cb_arg->aborted_io_req = aborted_io_req;
rrq.rrq_cmd = ELS_RRQ;
hton24(rrq.rrq_s_id, sid);
rrq.rrq_ox_id = htons(aborted_io_req->xid);
rrq.rrq_rx_id = htons(aborted_io_req->task->rxwr_txrd.var_ctx.rx_id);
retry_rrq:
rc = bnx2fc_initiate_els(tgt, ELS_RRQ, &rrq, sizeof(rrq),
bnx2fc_rrq_compl, cb_arg,
r_a_tov);
if (rc == -ENOMEM) {
if (time_after(jiffies, start + (10 * HZ))) {
BNX2FC_ELS_DBG("rrq Failed\n");
rc = FAILED;
goto rrq_err;
}
msleep(20);
goto retry_rrq;
}
rrq_err:
if (rc) {
BNX2FC_ELS_DBG("RRQ failed - release orig io req 0x%x\n",
aborted_io_req->xid);
kfree(cb_arg);
spin_lock_bh(&tgt->tgt_lock);
kref_put(&aborted_io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
}
return rc;
}
static void bnx2fc_l2_els_compl(struct bnx2fc_els_cb_arg *cb_arg)
{
struct bnx2fc_cmd *els_req;
struct bnx2fc_rport *tgt;
struct bnx2fc_mp_req *mp_req;
struct fc_frame_header *fc_hdr;
unsigned char *buf;
void *resp_buf;
u32 resp_len, hdr_len;
u16 l2_oxid;
int frame_len;
int rc = 0;
l2_oxid = cb_arg->l2_oxid;
BNX2FC_ELS_DBG("ELS COMPL - l2_oxid = 0x%x\n", l2_oxid);
els_req = cb_arg->io_req;
if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &els_req->req_flags)) {
/*
* els req is timed out. cleanup the IO with FW and
* drop the completion. libfc will handle the els timeout
*/
if (els_req->on_active_queue) {
list_del_init(&els_req->link);
els_req->on_active_queue = 0;
rc = bnx2fc_initiate_cleanup(els_req);
BUG_ON(rc);
}
goto free_arg;
}
tgt = els_req->tgt;
mp_req = &(els_req->mp_req);
fc_hdr = &(mp_req->resp_fc_hdr);
resp_len = mp_req->resp_len;
resp_buf = mp_req->resp_buf;
buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
if (!buf) {
printk(KERN_ERR PFX "Unable to alloc mp buf\n");
goto free_arg;
}
hdr_len = sizeof(*fc_hdr);
if (hdr_len + resp_len > PAGE_SIZE) {
printk(KERN_ERR PFX "l2_els_compl: resp len is "
"beyond page size\n");
goto free_buf;
}
memcpy(buf, fc_hdr, hdr_len);
memcpy(buf + hdr_len, resp_buf, resp_len);
frame_len = hdr_len + resp_len;
bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, l2_oxid);
free_buf:
kfree(buf);
free_arg:
kfree(cb_arg);
}
int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp)
{
struct fc_els_adisc *adisc;
struct fc_frame_header *fh;
struct bnx2fc_els_cb_arg *cb_arg;
struct fc_lport *lport = tgt->rdata->local_port;
u32 r_a_tov = lport->r_a_tov;
int rc;
fh = fc_frame_header_get(fp);
cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
if (!cb_arg) {
printk(KERN_ERR PFX "Unable to allocate cb_arg for ADISC\n");
return -ENOMEM;
}
cb_arg->l2_oxid = ntohs(fh->fh_ox_id);
BNX2FC_ELS_DBG("send ADISC: l2_oxid = 0x%x\n", cb_arg->l2_oxid);
adisc = fc_frame_payload_get(fp, sizeof(*adisc));
/* adisc is initialized by libfc */
rc = bnx2fc_initiate_els(tgt, ELS_ADISC, adisc, sizeof(*adisc),
bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov);
if (rc)
kfree(cb_arg);
return rc;
}
int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp)
{
struct fc_els_logo *logo;
struct fc_frame_header *fh;
struct bnx2fc_els_cb_arg *cb_arg;
struct fc_lport *lport = tgt->rdata->local_port;
u32 r_a_tov = lport->r_a_tov;
int rc;
fh = fc_frame_header_get(fp);
cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
if (!cb_arg) {
printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n");
return -ENOMEM;
}
cb_arg->l2_oxid = ntohs(fh->fh_ox_id);
BNX2FC_ELS_DBG("Send LOGO: l2_oxid = 0x%x\n", cb_arg->l2_oxid);
logo = fc_frame_payload_get(fp, sizeof(*logo));
/* logo is initialized by libfc */
rc = bnx2fc_initiate_els(tgt, ELS_LOGO, logo, sizeof(*logo),
bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov);
if (rc)
kfree(cb_arg);
return rc;
}
int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp)
{
struct fc_els_rls *rls;
struct fc_frame_header *fh;
struct bnx2fc_els_cb_arg *cb_arg;
struct fc_lport *lport = tgt->rdata->local_port;
u32 r_a_tov = lport->r_a_tov;
int rc;
fh = fc_frame_header_get(fp);
cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
if (!cb_arg) {
printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n");
return -ENOMEM;
}
cb_arg->l2_oxid = ntohs(fh->fh_ox_id);
rls = fc_frame_payload_get(fp, sizeof(*rls));
/* rls is initialized by libfc */
rc = bnx2fc_initiate_els(tgt, ELS_RLS, rls, sizeof(*rls),
bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov);
if (rc)
kfree(cb_arg);
return rc;
}
void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg)
{
struct bnx2fc_mp_req *mp_req;
struct fc_frame_header *fc_hdr, *fh;
struct bnx2fc_cmd *srr_req;
struct bnx2fc_cmd *orig_io_req;
struct fc_frame *fp;
unsigned char *buf;
void *resp_buf;
u32 resp_len, hdr_len;
u8 opcode;
int rc = 0;
orig_io_req = cb_arg->aborted_io_req;
srr_req = cb_arg->io_req;
if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &srr_req->req_flags)) {
/* SRR timedout */
BNX2FC_IO_DBG(srr_req, "srr timed out, abort "
"orig_io - 0x%x\n",
orig_io_req->xid);
rc = bnx2fc_initiate_abts(srr_req);
if (rc != SUCCESS) {
BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
"failed. issue cleanup\n");
bnx2fc_initiate_cleanup(srr_req);
}
if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) ||
test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
BNX2FC_IO_DBG(srr_req, "srr_compl:xid 0x%x flags = %lx",
orig_io_req->xid, orig_io_req->req_flags);
goto srr_compl_done;
}
orig_io_req->srr_retry++;
if (orig_io_req->srr_retry <= SRR_RETRY_COUNT) {
struct bnx2fc_rport *tgt = orig_io_req->tgt;
spin_unlock_bh(&tgt->tgt_lock);
rc = bnx2fc_send_srr(orig_io_req,
orig_io_req->srr_offset,
orig_io_req->srr_rctl);
spin_lock_bh(&tgt->tgt_lock);
if (!rc)
goto srr_compl_done;
}
rc = bnx2fc_initiate_abts(orig_io_req);
if (rc != SUCCESS) {
BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
"failed xid = 0x%x. issue cleanup\n",
orig_io_req->xid);
bnx2fc_initiate_cleanup(orig_io_req);
}
goto srr_compl_done;
}
if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) ||
test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
BNX2FC_IO_DBG(srr_req, "srr_compl:xid - 0x%x flags = %lx",
orig_io_req->xid, orig_io_req->req_flags);
goto srr_compl_done;
}
mp_req = &(srr_req->mp_req);
fc_hdr = &(mp_req->resp_fc_hdr);
resp_len = mp_req->resp_len;
resp_buf = mp_req->resp_buf;
hdr_len = sizeof(*fc_hdr);
buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
if (!buf) {
printk(KERN_ERR PFX "srr buf: mem alloc failure\n");
goto srr_compl_done;
}
memcpy(buf, fc_hdr, hdr_len);
memcpy(buf + hdr_len, resp_buf, resp_len);
fp = fc_frame_alloc(NULL, resp_len);
if (!fp) {
printk(KERN_ERR PFX "fc_frame_alloc failure\n");
goto free_buf;
}
fh = (struct fc_frame_header *) fc_frame_header_get(fp);
/* Copy FC Frame header and payload into the frame */
memcpy(fh, buf, hdr_len + resp_len);
opcode = fc_frame_payload_op(fp);
switch (opcode) {
case ELS_LS_ACC:
BNX2FC_IO_DBG(srr_req, "SRR success\n");
break;
case ELS_LS_RJT:
BNX2FC_IO_DBG(srr_req, "SRR rejected\n");
rc = bnx2fc_initiate_abts(orig_io_req);
if (rc != SUCCESS) {
BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
"failed xid = 0x%x. issue cleanup\n",
orig_io_req->xid);
bnx2fc_initiate_cleanup(orig_io_req);
}
break;
default:
BNX2FC_IO_DBG(srr_req, "srr compl - invalid opcode = %d\n",
opcode);
break;
}
fc_frame_free(fp);
free_buf:
kfree(buf);
srr_compl_done:
kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
}
void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg)
{
struct bnx2fc_cmd *orig_io_req, *new_io_req;
struct bnx2fc_cmd *rec_req;
struct bnx2fc_mp_req *mp_req;
struct fc_frame_header *fc_hdr, *fh;
struct fc_els_ls_rjt *rjt;
struct fc_els_rec_acc *acc;
struct bnx2fc_rport *tgt;
struct fcoe_err_report_entry *err_entry;
struct scsi_cmnd *sc_cmd;
enum fc_rctl r_ctl;
unsigned char *buf;
void *resp_buf;
struct fc_frame *fp;
u8 opcode;
u32 offset;
u32 e_stat;
u32 resp_len, hdr_len;
int rc = 0;
bool send_seq_clnp = false;
bool abort_io = false;
BNX2FC_MISC_DBG("Entered rec_compl callback\n");
rec_req = cb_arg->io_req;
orig_io_req = cb_arg->aborted_io_req;
BNX2FC_IO_DBG(rec_req, "rec_compl: orig xid = 0x%x", orig_io_req->xid);
tgt = orig_io_req->tgt;
/* Handle REC timeout case */
if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rec_req->req_flags)) {
BNX2FC_IO_DBG(rec_req, "timed out, abort "
"orig_io - 0x%x\n",
orig_io_req->xid);
/* els req is timed out. send abts for els */
rc = bnx2fc_initiate_abts(rec_req);
if (rc != SUCCESS) {
BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
"failed. issue cleanup\n");
bnx2fc_initiate_cleanup(rec_req);
}
orig_io_req->rec_retry++;
/* REC timedout. send ABTS to the orig IO req */
if (orig_io_req->rec_retry <= REC_RETRY_COUNT) {
spin_unlock_bh(&tgt->tgt_lock);
rc = bnx2fc_send_rec(orig_io_req);
spin_lock_bh(&tgt->tgt_lock);
if (!rc)
goto rec_compl_done;
}
rc = bnx2fc_initiate_abts(orig_io_req);
if (rc != SUCCESS) {
BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
"failed xid = 0x%x. issue cleanup\n",
orig_io_req->xid);
bnx2fc_initiate_cleanup(orig_io_req);
}
goto rec_compl_done;
}
if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) {
BNX2FC_IO_DBG(rec_req, "completed"
"orig_io - 0x%x\n",
orig_io_req->xid);
goto rec_compl_done;
}
if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
BNX2FC_IO_DBG(rec_req, "abts in prog "
"orig_io - 0x%x\n",
orig_io_req->xid);
goto rec_compl_done;
}
mp_req = &(rec_req->mp_req);
fc_hdr = &(mp_req->resp_fc_hdr);
resp_len = mp_req->resp_len;
acc = resp_buf = mp_req->resp_buf;
hdr_len = sizeof(*fc_hdr);
buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
if (!buf) {
printk(KERN_ERR PFX "rec buf: mem alloc failure\n");
goto rec_compl_done;
}
memcpy(buf, fc_hdr, hdr_len);
memcpy(buf + hdr_len, resp_buf, resp_len);
fp = fc_frame_alloc(NULL, resp_len);
if (!fp) {
printk(KERN_ERR PFX "fc_frame_alloc failure\n");
goto free_buf;
}
fh = (struct fc_frame_header *) fc_frame_header_get(fp);
/* Copy FC Frame header and payload into the frame */
memcpy(fh, buf, hdr_len + resp_len);
opcode = fc_frame_payload_op(fp);
if (opcode == ELS_LS_RJT) {
BNX2FC_IO_DBG(rec_req, "opcode is RJT\n");
rjt = fc_frame_payload_get(fp, sizeof(*rjt));
if ((rjt->er_reason == ELS_RJT_LOGIC ||
rjt->er_reason == ELS_RJT_UNAB) &&
rjt->er_explan == ELS_EXPL_OXID_RXID) {
BNX2FC_IO_DBG(rec_req, "handle CMD LOST case\n");
new_io_req = bnx2fc_cmd_alloc(tgt);
if (!new_io_req)
goto abort_io;
new_io_req->sc_cmd = orig_io_req->sc_cmd;
/* cleanup orig_io_req that is with the FW */
set_bit(BNX2FC_FLAG_CMD_LOST,
&orig_io_req->req_flags);
bnx2fc_initiate_cleanup(orig_io_req);
/* Post a new IO req with the same sc_cmd */
BNX2FC_IO_DBG(rec_req, "Post IO request again\n");
spin_unlock_bh(&tgt->tgt_lock);
rc = bnx2fc_post_io_req(tgt, new_io_req);
spin_lock_bh(&tgt->tgt_lock);
if (!rc)
goto free_frame;
BNX2FC_IO_DBG(rec_req, "REC: io post err\n");
}
abort_io:
rc = bnx2fc_initiate_abts(orig_io_req);
if (rc != SUCCESS) {
BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
"failed. issue cleanup\n");
bnx2fc_initiate_cleanup(orig_io_req);
}
} else if (opcode == ELS_LS_ACC) {
/* REVISIT: Check if the exchange is already aborted */
offset = ntohl(acc->reca_fc4value);
e_stat = ntohl(acc->reca_e_stat);
if (e_stat & ESB_ST_SEQ_INIT) {
BNX2FC_IO_DBG(rec_req, "target has the seq init\n");
goto free_frame;
}
BNX2FC_IO_DBG(rec_req, "e_stat = 0x%x, offset = 0x%x\n",
e_stat, offset);
/* Seq initiative is with us */
err_entry = (struct fcoe_err_report_entry *)
&orig_io_req->err_entry;
sc_cmd = orig_io_req->sc_cmd;
if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) {
/* SCSI WRITE command */
if (offset == orig_io_req->data_xfer_len) {
BNX2FC_IO_DBG(rec_req, "WRITE - resp lost\n");
/* FCP_RSP lost */
r_ctl = FC_RCTL_DD_CMD_STATUS;
offset = 0;
} else {
/* start transmitting from offset */
BNX2FC_IO_DBG(rec_req, "XFER_RDY/DATA lost\n");
send_seq_clnp = true;
r_ctl = FC_RCTL_DD_DATA_DESC;
if (bnx2fc_initiate_seq_cleanup(orig_io_req,
offset, r_ctl))
abort_io = true;
/* XFER_RDY */
}
} else {
/* SCSI READ command */
if (err_entry->data.rx_buf_off ==
orig_io_req->data_xfer_len) {
/* FCP_RSP lost */
BNX2FC_IO_DBG(rec_req, "READ - resp lost\n");
r_ctl = FC_RCTL_DD_CMD_STATUS;
offset = 0;
} else {
/* request retransmission from this offset */
send_seq_clnp = true;
offset = err_entry->data.rx_buf_off;
BNX2FC_IO_DBG(rec_req, "RD DATA lost\n");
/* FCP_DATA lost */
r_ctl = FC_RCTL_DD_SOL_DATA;
if (bnx2fc_initiate_seq_cleanup(orig_io_req,
offset, r_ctl))
abort_io = true;
}
}
if (abort_io) {
rc = bnx2fc_initiate_abts(orig_io_req);
if (rc != SUCCESS) {
BNX2FC_IO_DBG(rec_req, "rec_compl:initiate_abts"
" failed. issue cleanup\n");
bnx2fc_initiate_cleanup(orig_io_req);
}
} else if (!send_seq_clnp) {
BNX2FC_IO_DBG(rec_req, "Send SRR - FCP_RSP\n");
spin_unlock_bh(&tgt->tgt_lock);
rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl);
spin_lock_bh(&tgt->tgt_lock);
if (rc) {
BNX2FC_IO_DBG(rec_req, "Unable to send SRR"
" IO will abort\n");
}
}
}
free_frame:
fc_frame_free(fp);
free_buf:
kfree(buf);
rec_compl_done:
kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
kfree(cb_arg);
}
int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req)
{
struct fc_els_rec rec;
struct bnx2fc_rport *tgt = orig_io_req->tgt;
struct fc_lport *lport = tgt->rdata->local_port;
struct bnx2fc_els_cb_arg *cb_arg = NULL;
u32 sid = tgt->sid;
u32 r_a_tov = lport->r_a_tov;
int rc;
BNX2FC_IO_DBG(orig_io_req, "Sending REC\n");
memset(&rec, 0, sizeof(rec));
cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
if (!cb_arg) {
printk(KERN_ERR PFX "Unable to allocate cb_arg for REC\n");
rc = -ENOMEM;
goto rec_err;
}
kref_get(&orig_io_req->refcount);
cb_arg->aborted_io_req = orig_io_req;
rec.rec_cmd = ELS_REC;
hton24(rec.rec_s_id, sid);
rec.rec_ox_id = htons(orig_io_req->xid);
rec.rec_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id);
rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec),
bnx2fc_rec_compl, cb_arg,
r_a_tov);
rec_err:
if (rc) {
BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n");
spin_lock_bh(&tgt->tgt_lock);
kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
kfree(cb_arg);
}
return rc;
}
int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl)
{
struct fcp_srr srr;
struct bnx2fc_rport *tgt = orig_io_req->tgt;
struct fc_lport *lport = tgt->rdata->local_port;
struct bnx2fc_els_cb_arg *cb_arg = NULL;
u32 r_a_tov = lport->r_a_tov;
int rc;
BNX2FC_IO_DBG(orig_io_req, "Sending SRR\n");
memset(&srr, 0, sizeof(srr));
cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
if (!cb_arg) {
printk(KERN_ERR PFX "Unable to allocate cb_arg for SRR\n");
rc = -ENOMEM;
goto srr_err;
}
kref_get(&orig_io_req->refcount);
cb_arg->aborted_io_req = orig_io_req;
srr.srr_op = ELS_SRR;
srr.srr_ox_id = htons(orig_io_req->xid);
srr.srr_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id);
srr.srr_rel_off = htonl(offset);
srr.srr_r_ctl = r_ctl;
orig_io_req->srr_offset = offset;
orig_io_req->srr_rctl = r_ctl;
rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr),
bnx2fc_srr_compl, cb_arg,
r_a_tov);
srr_err:
if (rc) {
BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n");
spin_lock_bh(&tgt->tgt_lock);
kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
kfree(cb_arg);
} else
set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags);
return rc;
}
static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
void *data, u32 data_len,
void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg),
struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec)
{
struct fcoe_port *port = tgt->port;
struct bnx2fc_interface *interface = port->priv;
struct fc_rport *rport = tgt->rport;
struct fc_lport *lport = port->lport;
struct bnx2fc_cmd *els_req;
struct bnx2fc_mp_req *mp_req;
struct fc_frame_header *fc_hdr;
struct fcoe_task_ctx_entry *task;
struct fcoe_task_ctx_entry *task_page;
int rc = 0;
int task_idx, index;
u32 did, sid;
u16 xid;
rc = fc_remote_port_chkready(rport);
if (rc) {
printk(KERN_ERR PFX "els 0x%x: rport not ready\n", op);
rc = -EINVAL;
goto els_err;
}
if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
printk(KERN_ERR PFX "els 0x%x: link is not ready\n", op);
rc = -EINVAL;
goto els_err;
}
if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) ||
(test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags))) {
printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op);
rc = -EINVAL;
goto els_err;
}
els_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ELS);
if (!els_req) {
rc = -ENOMEM;
goto els_err;
}
els_req->sc_cmd = NULL;
els_req->port = port;
els_req->tgt = tgt;
els_req->cb_func = cb_func;
cb_arg->io_req = els_req;
els_req->cb_arg = cb_arg;
mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req);
rc = bnx2fc_init_mp_req(els_req);
if (rc == FAILED) {
printk(KERN_ERR PFX "ELS MP request init failed\n");
spin_lock_bh(&tgt->tgt_lock);
kref_put(&els_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
rc = -ENOMEM;
goto els_err;
} else {
/* rc SUCCESS */
rc = 0;
}
/* Set the data_xfer_len to the size of ELS payload */
mp_req->req_len = data_len;
els_req->data_xfer_len = mp_req->req_len;
/* Fill ELS Payload */
if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) {
memcpy(mp_req->req_buf, data, data_len);
} else {
printk(KERN_ERR PFX "Invalid ELS op 0x%x\n", op);
els_req->cb_func = NULL;
els_req->cb_arg = NULL;
spin_lock_bh(&tgt->tgt_lock);
kref_put(&els_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
rc = -EINVAL;
}
if (rc)
goto els_err;
/* Fill FC header */
fc_hdr = &(mp_req->req_fc_hdr);
did = tgt->rport->port_id;
sid = tgt->sid;
if (op == ELS_SRR)
__fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS4_REQ, did, sid,
FC_TYPE_FCP, FC_FC_FIRST_SEQ |
FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
else
__fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid,
FC_TYPE_ELS, FC_FC_FIRST_SEQ |
FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
/* Obtain exchange id */
xid = els_req->xid;
task_idx = xid/BNX2FC_TASKS_PER_PAGE;
index = xid % BNX2FC_TASKS_PER_PAGE;
/* Initialize task context for this IO request */
task_page = (struct fcoe_task_ctx_entry *)
interface->hba->task_ctx[task_idx];
task = &(task_page[index]);
bnx2fc_init_mp_task(els_req, task);
spin_lock_bh(&tgt->tgt_lock);
if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) {
printk(KERN_ERR PFX "initiate_els.. session not ready\n");
els_req->cb_func = NULL;
els_req->cb_arg = NULL;
kref_put(&els_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
return -EINVAL;
}
if (timer_msec)
bnx2fc_cmd_timer_set(els_req, timer_msec);
bnx2fc_add_2_sq(tgt, xid);
els_req->on_active_queue = 1;
list_add_tail(&els_req->link, &tgt->els_queue);
/* Ring doorbell */
bnx2fc_ring_doorbell(tgt);
spin_unlock_bh(&tgt->tgt_lock);
els_err:
return rc;
}
void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
struct fcoe_task_ctx_entry *task, u8 num_rq)
{
struct bnx2fc_mp_req *mp_req;
struct fc_frame_header *fc_hdr;
u64 *hdr;
u64 *temp_hdr;
BNX2FC_ELS_DBG("Entered process_els_compl xid = 0x%x"
"cmd_type = %d\n", els_req->xid, els_req->cmd_type);
if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE,
&els_req->req_flags)) {
BNX2FC_ELS_DBG("Timer context finished processing this "
"els - 0x%x\n", els_req->xid);
/* This IO doesn't receive cleanup completion */
kref_put(&els_req->refcount, bnx2fc_cmd_release);
return;
}
/* Cancel the timeout_work, as we received the response */
if (cancel_delayed_work(&els_req->timeout_work))
kref_put(&els_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
if (els_req->on_active_queue) {
list_del_init(&els_req->link);
els_req->on_active_queue = 0;
}
mp_req = &(els_req->mp_req);
fc_hdr = &(mp_req->resp_fc_hdr);
hdr = (u64 *)fc_hdr;
temp_hdr = (u64 *)
&task->rxwr_only.union_ctx.comp_info.mp_rsp.fc_hdr;
hdr[0] = cpu_to_be64(temp_hdr[0]);
hdr[1] = cpu_to_be64(temp_hdr[1]);
hdr[2] = cpu_to_be64(temp_hdr[2]);
mp_req->resp_len =
task->rxwr_only.union_ctx.comp_info.mp_rsp.mp_payload_len;
/* Parse ELS response */
if ((els_req->cb_func) && (els_req->cb_arg)) {
els_req->cb_func(els_req->cb_arg);
els_req->cb_arg = NULL;
}
kref_put(&els_req->refcount, bnx2fc_cmd_release);
}
static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
void *arg)
{
struct fcoe_ctlr *fip = arg;
struct fc_exch *exch = fc_seq_exch(seq);
struct fc_lport *lport = exch->lp;
u8 *mac;
struct fc_frame_header *fh;
u8 op;
if (IS_ERR(fp))
goto done;
mac = fr_cb(fp)->granted_mac;
if (is_zero_ether_addr(mac)) {
fh = fc_frame_header_get(fp);
if (fh->fh_type != FC_TYPE_ELS) {
printk(KERN_ERR PFX "bnx2fc_flogi_resp:"
"fh_type != FC_TYPE_ELS\n");
fc_frame_free(fp);
return;
}
op = fc_frame_payload_op(fp);
if (lport->vport) {
if (op == ELS_LS_RJT) {
printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n");
fc_vport_terminate(lport->vport);
fc_frame_free(fp);
return;
}
}
if (fcoe_ctlr_recv_flogi(fip, lport, fp)) {
fc_frame_free(fp);
return;
}
}
fip->update_mac(lport, mac);
done:
fc_lport_flogi_resp(seq, fp, lport);
}
static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp,
void *arg)
{
struct fcoe_ctlr *fip = arg;
struct fc_exch *exch = fc_seq_exch(seq);
struct fc_lport *lport = exch->lp;
static u8 zero_mac[ETH_ALEN] = { 0 };
if (!IS_ERR(fp))
fip->update_mac(lport, zero_mac);
fc_lport_logo_resp(seq, fp, lport);
}
struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did,
struct fc_frame *fp, unsigned int op,
void (*resp)(struct fc_seq *,
struct fc_frame *,
void *),
void *arg, u32 timeout)
{
struct fcoe_port *port = lport_priv(lport);
struct bnx2fc_interface *interface = port->priv;
struct fcoe_ctlr *fip = &interface->ctlr;
struct fc_frame_header *fh = fc_frame_header_get(fp);
switch (op) {
case ELS_FLOGI:
case ELS_FDISC:
return fc_elsct_send(lport, did, fp, op, bnx2fc_flogi_resp,
fip, timeout);
case ELS_LOGO:
/* only hook onto fabric logouts, not port logouts */
if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
break;
return fc_elsct_send(lport, did, fp, op, bnx2fc_logo_resp,
fip, timeout);
}
return fc_elsct_send(lport, did, fp, op, resp, arg, timeout);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+870
View File
@@ -0,0 +1,870 @@
/* bnx2fc_tgt.c: Broadcom NetXtreme II Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
* Copyright (c) 2008 - 2011 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: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
*/
#include "bnx2fc.h"
static void bnx2fc_upld_timer(unsigned long data);
static void bnx2fc_ofld_timer(unsigned long data);
static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
struct fcoe_port *port,
struct fc_rport_priv *rdata);
static u32 bnx2fc_alloc_conn_id(struct bnx2fc_hba *hba,
struct bnx2fc_rport *tgt);
static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
struct bnx2fc_rport *tgt);
static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba,
struct bnx2fc_rport *tgt);
static void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id);
static void bnx2fc_upld_timer(unsigned long data)
{
struct bnx2fc_rport *tgt = (struct bnx2fc_rport *)data;
BNX2FC_TGT_DBG(tgt, "upld_timer - Upload compl not received!!\n");
/* fake upload completion */
clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags);
set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags);
wake_up_interruptible(&tgt->upld_wait);
}
static void bnx2fc_ofld_timer(unsigned long data)
{
struct bnx2fc_rport *tgt = (struct bnx2fc_rport *)data;
BNX2FC_TGT_DBG(tgt, "entered bnx2fc_ofld_timer\n");
/* NOTE: This function should never be called, as
* offload should never timeout
*/
/*
* If the timer has expired, this session is dead
* Clear offloaded flag and logout of this device.
* Since OFFLOADED flag is cleared, this case
* will be considered as offload error and the
* port will be logged off, and conn_id, session
* resources are freed up in bnx2fc_offload_session
*/
clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags);
set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
wake_up_interruptible(&tgt->ofld_wait);
}
static void bnx2fc_offload_session(struct fcoe_port *port,
struct bnx2fc_rport *tgt,
struct fc_rport_priv *rdata)
{
struct fc_lport *lport = rdata->local_port;
struct fc_rport *rport = rdata->rport;
struct bnx2fc_interface *interface = port->priv;
struct bnx2fc_hba *hba = interface->hba;
int rval;
int i = 0;
/* Initialize bnx2fc_rport */
/* NOTE: tgt is already bzero'd */
rval = bnx2fc_init_tgt(tgt, port, rdata);
if (rval) {
printk(KERN_ERR PFX "Failed to allocate conn id for "
"port_id (%6x)\n", rport->port_id);
goto tgt_init_err;
}
/* Allocate session resources */
rval = bnx2fc_alloc_session_resc(hba, tgt);
if (rval) {
printk(KERN_ERR PFX "Failed to allocate resources\n");
goto ofld_err;
}
/*
* Initialize FCoE session offload process.
* Upon completion of offload process add
* rport to list of rports
*/
retry_ofld:
clear_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
rval = bnx2fc_send_session_ofld_req(port, tgt);
if (rval) {
printk(KERN_ERR PFX "ofld_req failed\n");
goto ofld_err;
}
/*
* wait for the session is offloaded and enabled. 3 Secs
* should be ample time for this process to complete.
*/
setup_timer(&tgt->ofld_timer, bnx2fc_ofld_timer, (unsigned long)tgt);
mod_timer(&tgt->ofld_timer, jiffies + BNX2FC_FW_TIMEOUT);
wait_event_interruptible(tgt->ofld_wait,
(test_bit(
BNX2FC_FLAG_OFLD_REQ_CMPL,
&tgt->flags)));
if (signal_pending(current))
flush_signals(current);
del_timer_sync(&tgt->ofld_timer);
if (!(test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags))) {
if (test_and_clear_bit(BNX2FC_FLAG_CTX_ALLOC_FAILURE,
&tgt->flags)) {
BNX2FC_TGT_DBG(tgt, "ctx_alloc_failure, "
"retry ofld..%d\n", i++);
msleep_interruptible(1000);
if (i > 3) {
i = 0;
goto ofld_err;
}
goto retry_ofld;
}
goto ofld_err;
}
if (bnx2fc_map_doorbell(tgt)) {
printk(KERN_ERR PFX "map doorbell failed - no mem\n");
/* upload will take care of cleaning up sess resc */
lport->tt.rport_logoff(rdata);
}
return;
ofld_err:
/* couldn't offload the session. log off from this rport */
BNX2FC_TGT_DBG(tgt, "bnx2fc_offload_session - offload error\n");
/* Free session resources */
bnx2fc_free_session_resc(hba, tgt);
tgt_init_err:
if (tgt->fcoe_conn_id != -1)
bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id);
lport->tt.rport_logoff(rdata);
}
void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
{
struct bnx2fc_cmd *io_req;
struct list_head *list;
struct list_head *tmp;
int rc;
int i = 0;
BNX2FC_TGT_DBG(tgt, "Entered flush_active_ios - %d\n",
tgt->num_active_ios.counter);
spin_lock_bh(&tgt->tgt_lock);
tgt->flush_in_prog = 1;
list_for_each_safe(list, tmp, &tgt->active_cmd_queue) {
i++;
io_req = (struct bnx2fc_cmd *)list;
list_del_init(&io_req->link);
io_req->on_active_queue = 0;
BNX2FC_IO_DBG(io_req, "cmd_queue cleanup\n");
if (cancel_delayed_work(&io_req->timeout_work)) {
if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
&io_req->req_flags)) {
/* Handle eh_abort timeout */
BNX2FC_IO_DBG(io_req, "eh_abort for IO "
"cleaned up\n");
complete(&io_req->tm_done);
}
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
}
set_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags);
set_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags);
rc = bnx2fc_initiate_cleanup(io_req);
BUG_ON(rc);
}
list_for_each_safe(list, tmp, &tgt->els_queue) {
i++;
io_req = (struct bnx2fc_cmd *)list;
list_del_init(&io_req->link);
io_req->on_active_queue = 0;
BNX2FC_IO_DBG(io_req, "els_queue cleanup\n");
if (cancel_delayed_work(&io_req->timeout_work))
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
if ((io_req->cb_func) && (io_req->cb_arg)) {
io_req->cb_func(io_req->cb_arg);
io_req->cb_arg = NULL;
}
rc = bnx2fc_initiate_cleanup(io_req);
BUG_ON(rc);
}
list_for_each_safe(list, tmp, &tgt->io_retire_queue) {
i++;
io_req = (struct bnx2fc_cmd *)list;
list_del_init(&io_req->link);
BNX2FC_IO_DBG(io_req, "retire_queue flush\n");
if (cancel_delayed_work(&io_req->timeout_work))
kref_put(&io_req->refcount, bnx2fc_cmd_release);
clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags);
}
BNX2FC_TGT_DBG(tgt, "IOs flushed = %d\n", i);
i = 0;
spin_unlock_bh(&tgt->tgt_lock);
/* wait for active_ios to go to 0 */
while ((tgt->num_active_ios.counter != 0) && (i++ < BNX2FC_WAIT_CNT))
msleep(25);
if (tgt->num_active_ios.counter != 0)
printk(KERN_ERR PFX "CLEANUP on port 0x%x:"
" active_ios = %d\n",
tgt->rdata->ids.port_id, tgt->num_active_ios.counter);
spin_lock_bh(&tgt->tgt_lock);
tgt->flush_in_prog = 0;
spin_unlock_bh(&tgt->tgt_lock);
}
static void bnx2fc_upload_session(struct fcoe_port *port,
struct bnx2fc_rport *tgt)
{
struct bnx2fc_interface *interface = port->priv;
struct bnx2fc_hba *hba = interface->hba;
BNX2FC_TGT_DBG(tgt, "upload_session: active_ios = %d\n",
tgt->num_active_ios.counter);
/*
* Called with hba->hba_mutex held.
* This is a blocking call
*/
clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags);
bnx2fc_send_session_disable_req(port, tgt);
/*
* wait for upload to complete. 3 Secs
* should be sufficient time for this process to complete.
*/
setup_timer(&tgt->upld_timer, bnx2fc_upld_timer, (unsigned long)tgt);
mod_timer(&tgt->upld_timer, jiffies + BNX2FC_FW_TIMEOUT);
BNX2FC_TGT_DBG(tgt, "waiting for disable compl\n");
wait_event_interruptible(tgt->upld_wait,
(test_bit(
BNX2FC_FLAG_UPLD_REQ_COMPL,
&tgt->flags)));
if (signal_pending(current))
flush_signals(current);
del_timer_sync(&tgt->upld_timer);
/*
* traverse thru the active_q and tmf_q and cleanup
* IOs in these lists
*/
BNX2FC_TGT_DBG(tgt, "flush/upload - disable wait flags = 0x%lx\n",
tgt->flags);
bnx2fc_flush_active_ios(tgt);
/* Issue destroy KWQE */
if (test_bit(BNX2FC_FLAG_DISABLED, &tgt->flags)) {
BNX2FC_TGT_DBG(tgt, "send destroy req\n");
clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags);
bnx2fc_send_session_destroy_req(hba, tgt);
/* wait for destroy to complete */
setup_timer(&tgt->upld_timer,
bnx2fc_upld_timer, (unsigned long)tgt);
mod_timer(&tgt->upld_timer, jiffies + BNX2FC_FW_TIMEOUT);
wait_event_interruptible(tgt->upld_wait,
(test_bit(
BNX2FC_FLAG_UPLD_REQ_COMPL,
&tgt->flags)));
if (!(test_bit(BNX2FC_FLAG_DESTROYED, &tgt->flags)))
printk(KERN_ERR PFX "ERROR!! destroy timed out\n");
BNX2FC_TGT_DBG(tgt, "destroy wait complete flags = 0x%lx\n",
tgt->flags);
if (signal_pending(current))
flush_signals(current);
del_timer_sync(&tgt->upld_timer);
} else
printk(KERN_ERR PFX "ERROR!! DISABLE req timed out, destroy"
" not sent to FW\n");
/* Free session resources */
bnx2fc_free_session_resc(hba, tgt);
bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id);
}
static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
struct fcoe_port *port,
struct fc_rport_priv *rdata)
{
struct fc_rport *rport = rdata->rport;
struct bnx2fc_interface *interface = port->priv;
struct bnx2fc_hba *hba = interface->hba;
struct b577xx_doorbell_set_prod *sq_db = &tgt->sq_db;
struct b577xx_fcoe_rx_doorbell *rx_db = &tgt->rx_db;
tgt->rport = rport;
tgt->rdata = rdata;
tgt->port = port;
if (hba->num_ofld_sess >= BNX2FC_NUM_MAX_SESS) {
BNX2FC_TGT_DBG(tgt, "exceeded max sessions. logoff this tgt\n");
tgt->fcoe_conn_id = -1;
return -1;
}
tgt->fcoe_conn_id = bnx2fc_alloc_conn_id(hba, tgt);
if (tgt->fcoe_conn_id == -1)
return -1;
BNX2FC_TGT_DBG(tgt, "init_tgt - conn_id = 0x%x\n", tgt->fcoe_conn_id);
tgt->max_sqes = BNX2FC_SQ_WQES_MAX;
tgt->max_rqes = BNX2FC_RQ_WQES_MAX;
tgt->max_cqes = BNX2FC_CQ_WQES_MAX;
atomic_set(&tgt->free_sqes, BNX2FC_SQ_WQES_MAX);
/* Initialize the toggle bit */
tgt->sq_curr_toggle_bit = 1;
tgt->cq_curr_toggle_bit = 1;
tgt->sq_prod_idx = 0;
tgt->cq_cons_idx = 0;
tgt->rq_prod_idx = 0x8000;
tgt->rq_cons_idx = 0;
atomic_set(&tgt->num_active_ios, 0);
if (rdata->flags & FC_RP_FLAGS_RETRY) {
tgt->dev_type = TYPE_TAPE;
tgt->io_timeout = 0; /* use default ULP timeout */
} else {
tgt->dev_type = TYPE_DISK;
tgt->io_timeout = BNX2FC_IO_TIMEOUT;
}
/* initialize sq doorbell */
sq_db->header.header = B577XX_DOORBELL_HDR_DB_TYPE;
sq_db->header.header |= B577XX_FCOE_CONNECTION_TYPE <<
B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT;
/* initialize rx doorbell */
rx_db->hdr.header = ((0x1 << B577XX_DOORBELL_HDR_RX_SHIFT) |
(0x1 << B577XX_DOORBELL_HDR_DB_TYPE_SHIFT) |
(B577XX_FCOE_CONNECTION_TYPE <<
B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT));
rx_db->params = (0x2 << B577XX_FCOE_RX_DOORBELL_NEGATIVE_ARM_SHIFT) |
(0x3 << B577XX_FCOE_RX_DOORBELL_OPCODE_SHIFT);
spin_lock_init(&tgt->tgt_lock);
spin_lock_init(&tgt->cq_lock);
/* Initialize active_cmd_queue list */
INIT_LIST_HEAD(&tgt->active_cmd_queue);
/* Initialize IO retire queue */
INIT_LIST_HEAD(&tgt->io_retire_queue);
INIT_LIST_HEAD(&tgt->els_queue);
/* Initialize active_tm_queue list */
INIT_LIST_HEAD(&tgt->active_tm_queue);
init_waitqueue_head(&tgt->ofld_wait);
init_waitqueue_head(&tgt->upld_wait);
return 0;
}
/**
* This event_callback is called after successful completion of libfc
* initiated target login. bnx2fc can proceed with initiating the session
* establishment.
*/
void bnx2fc_rport_event_handler(struct fc_lport *lport,
struct fc_rport_priv *rdata,
enum fc_rport_event event)
{
struct fcoe_port *port = lport_priv(lport);
struct bnx2fc_interface *interface = port->priv;
struct bnx2fc_hba *hba = interface->hba;
struct fc_rport *rport = rdata->rport;
struct fc_rport_libfc_priv *rp;
struct bnx2fc_rport *tgt;
u32 port_id;
BNX2FC_HBA_DBG(lport, "rport_event_hdlr: event = %d, port_id = 0x%x\n",
event, rdata->ids.port_id);
switch (event) {
case RPORT_EV_READY:
if (!rport) {
printk(KERN_ERR PFX "rport is NULL: ERROR!\n");
break;
}
rp = rport->dd_data;
if (rport->port_id == FC_FID_DIR_SERV) {
/*
* bnx2fc_rport structure doesn't exist for
* directory server.
* We should not come here, as lport will
* take care of fabric login
*/
printk(KERN_ERR PFX "%x - rport_event_handler ERROR\n",
rdata->ids.port_id);
break;
}
if (rdata->spp_type != FC_TYPE_FCP) {
BNX2FC_HBA_DBG(lport, "not FCP type target."
" not offloading\n");
break;
}
if (!(rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET)) {
BNX2FC_HBA_DBG(lport, "not FCP_TARGET"
" not offloading\n");
break;
}
/*
* Offlaod process is protected with hba mutex.
* Use the same mutex_lock for upload process too
*/
mutex_lock(&hba->hba_mutex);
tgt = (struct bnx2fc_rport *)&rp[1];
/* This can happen when ADISC finds the same target */
if (test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags)) {
BNX2FC_TGT_DBG(tgt, "already offloaded\n");
mutex_unlock(&hba->hba_mutex);
return;
}
/*
* Offload the session. This is a blocking call, and will
* wait until the session is offloaded.
*/
bnx2fc_offload_session(port, tgt, rdata);
BNX2FC_TGT_DBG(tgt, "OFFLOAD num_ofld_sess = %d\n",
hba->num_ofld_sess);
if (test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags)) {
/*
* Session is offloaded and enabled. Map
* doorbell register for this target
*/
BNX2FC_TGT_DBG(tgt, "sess offloaded\n");
/* This counter is protected with hba mutex */
hba->num_ofld_sess++;
set_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags);
} else {
/*
* Offload or enable would have failed.
* In offload/enable completion path, the
* rport would have already been removed
*/
BNX2FC_TGT_DBG(tgt, "Port is being logged off as "
"offloaded flag not set\n");
}
mutex_unlock(&hba->hba_mutex);
break;
case RPORT_EV_LOGO:
case RPORT_EV_FAILED:
case RPORT_EV_STOP:
port_id = rdata->ids.port_id;
if (port_id == FC_FID_DIR_SERV)
break;
if (!rport) {
printk(KERN_INFO PFX "%x - rport not created Yet!!\n",
port_id);
break;
}
rp = rport->dd_data;
mutex_lock(&hba->hba_mutex);
/*
* Perform session upload. Note that rdata->peers is already
* removed from disc->rports list before we get this event.
*/
tgt = (struct bnx2fc_rport *)&rp[1];
if (!(test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags))) {
mutex_unlock(&hba->hba_mutex);
break;
}
clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags);
bnx2fc_upload_session(port, tgt);
hba->num_ofld_sess--;
BNX2FC_TGT_DBG(tgt, "UPLOAD num_ofld_sess = %d\n",
hba->num_ofld_sess);
/*
* Try to wake up the linkdown wait thread. If num_ofld_sess
* is 0, the waiting therad wakes up
*/
if ((hba->wait_for_link_down) &&
(hba->num_ofld_sess == 0)) {
wake_up_interruptible(&hba->shutdown_wait);
}
if (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags)) {
printk(KERN_ERR PFX "Relogin to the tgt\n");
mutex_lock(&lport->disc.disc_mutex);
lport->tt.rport_login(rdata);
mutex_unlock(&lport->disc.disc_mutex);
}
mutex_unlock(&hba->hba_mutex);
break;
case RPORT_EV_NONE:
break;
}
}
/**
* bnx2fc_tgt_lookup() - Lookup a bnx2fc_rport by port_id
*
* @port: fcoe_port struct to lookup the target port on
* @port_id: The remote port ID to look up
*/
struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
u32 port_id)
{
struct bnx2fc_interface *interface = port->priv;
struct bnx2fc_hba *hba = interface->hba;
struct bnx2fc_rport *tgt;
struct fc_rport_priv *rdata;
int i;
for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) {
tgt = hba->tgt_ofld_list[i];
if ((tgt) && (tgt->port == port)) {
rdata = tgt->rdata;
if (rdata->ids.port_id == port_id) {
if (rdata->rp_state != RPORT_ST_DELETE) {
BNX2FC_TGT_DBG(tgt, "rport "
"obtained\n");
return tgt;
} else {
BNX2FC_TGT_DBG(tgt, "rport 0x%x "
"is in DELETED state\n",
rdata->ids.port_id);
return NULL;
}
}
}
}
return NULL;
}
/**
* bnx2fc_alloc_conn_id - allocates FCOE Connection id
*
* @hba: pointer to adapter structure
* @tgt: pointer to bnx2fc_rport structure
*/
static u32 bnx2fc_alloc_conn_id(struct bnx2fc_hba *hba,
struct bnx2fc_rport *tgt)
{
u32 conn_id, next;
/* called with hba mutex held */
/*
* tgt_ofld_list access is synchronized using
* both hba mutex and hba lock. Atleast hba mutex or
* hba lock needs to be held for read access.
*/
spin_lock_bh(&hba->hba_lock);
next = hba->next_conn_id;
conn_id = hba->next_conn_id++;
if (hba->next_conn_id == BNX2FC_NUM_MAX_SESS)
hba->next_conn_id = 0;
while (hba->tgt_ofld_list[conn_id] != NULL) {
conn_id++;
if (conn_id == BNX2FC_NUM_MAX_SESS)
conn_id = 0;
if (conn_id == next) {
/* No free conn_ids are available */
spin_unlock_bh(&hba->hba_lock);
return -1;
}
}
hba->tgt_ofld_list[conn_id] = tgt;
tgt->fcoe_conn_id = conn_id;
spin_unlock_bh(&hba->hba_lock);
return conn_id;
}
static void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id)
{
/* called with hba mutex held */
spin_lock_bh(&hba->hba_lock);
hba->tgt_ofld_list[conn_id] = NULL;
spin_unlock_bh(&hba->hba_lock);
}
/**
*bnx2fc_alloc_session_resc - Allocate qp resources for the session
*
*/
static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
struct bnx2fc_rport *tgt)
{
dma_addr_t page;
int num_pages;
u32 *pbl;
/* Allocate and map SQ */
tgt->sq_mem_size = tgt->max_sqes * BNX2FC_SQ_WQE_SIZE;
tgt->sq_mem_size = (tgt->sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
&tgt->sq_dma, GFP_KERNEL);
if (!tgt->sq) {
printk(KERN_ERR PFX "unable to allocate SQ memory %d\n",
tgt->sq_mem_size);
goto mem_alloc_failure;
}
memset(tgt->sq, 0, tgt->sq_mem_size);
/* Allocate and map CQ */
tgt->cq_mem_size = tgt->max_cqes * BNX2FC_CQ_WQE_SIZE;
tgt->cq_mem_size = (tgt->cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
&tgt->cq_dma, GFP_KERNEL);
if (!tgt->cq) {
printk(KERN_ERR PFX "unable to allocate CQ memory %d\n",
tgt->cq_mem_size);
goto mem_alloc_failure;
}
memset(tgt->cq, 0, tgt->cq_mem_size);
/* Allocate and map RQ and RQ PBL */
tgt->rq_mem_size = tgt->max_rqes * BNX2FC_RQ_WQE_SIZE;
tgt->rq_mem_size = (tgt->rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
&tgt->rq_dma, GFP_KERNEL);
if (!tgt->rq) {
printk(KERN_ERR PFX "unable to allocate RQ memory %d\n",
tgt->rq_mem_size);
goto mem_alloc_failure;
}
memset(tgt->rq, 0, tgt->rq_mem_size);
tgt->rq_pbl_size = (tgt->rq_mem_size / PAGE_SIZE) * sizeof(void *);
tgt->rq_pbl_size = (tgt->rq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
&tgt->rq_pbl_dma, GFP_KERNEL);
if (!tgt->rq_pbl) {
printk(KERN_ERR PFX "unable to allocate RQ PBL %d\n",
tgt->rq_pbl_size);
goto mem_alloc_failure;
}
memset(tgt->rq_pbl, 0, tgt->rq_pbl_size);
num_pages = tgt->rq_mem_size / PAGE_SIZE;
page = tgt->rq_dma;
pbl = (u32 *)tgt->rq_pbl;
while (num_pages--) {
*pbl = (u32)page;
pbl++;
*pbl = (u32)((u64)page >> 32);
pbl++;
page += PAGE_SIZE;
}
/* Allocate and map XFERQ */
tgt->xferq_mem_size = tgt->max_sqes * BNX2FC_XFERQ_WQE_SIZE;
tgt->xferq_mem_size = (tgt->xferq_mem_size + (PAGE_SIZE - 1)) &
PAGE_MASK;
tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
&tgt->xferq_dma, GFP_KERNEL);
if (!tgt->xferq) {
printk(KERN_ERR PFX "unable to allocate XFERQ %d\n",
tgt->xferq_mem_size);
goto mem_alloc_failure;
}
memset(tgt->xferq, 0, tgt->xferq_mem_size);
/* Allocate and map CONFQ & CONFQ PBL */
tgt->confq_mem_size = tgt->max_sqes * BNX2FC_CONFQ_WQE_SIZE;
tgt->confq_mem_size = (tgt->confq_mem_size + (PAGE_SIZE - 1)) &
PAGE_MASK;
tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
&tgt->confq_dma, GFP_KERNEL);
if (!tgt->confq) {
printk(KERN_ERR PFX "unable to allocate CONFQ %d\n",
tgt->confq_mem_size);
goto mem_alloc_failure;
}
memset(tgt->confq, 0, tgt->confq_mem_size);
tgt->confq_pbl_size =
(tgt->confq_mem_size / PAGE_SIZE) * sizeof(void *);
tgt->confq_pbl_size =
(tgt->confq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev,
tgt->confq_pbl_size,
&tgt->confq_pbl_dma, GFP_KERNEL);
if (!tgt->confq_pbl) {
printk(KERN_ERR PFX "unable to allocate CONFQ PBL %d\n",
tgt->confq_pbl_size);
goto mem_alloc_failure;
}
memset(tgt->confq_pbl, 0, tgt->confq_pbl_size);
num_pages = tgt->confq_mem_size / PAGE_SIZE;
page = tgt->confq_dma;
pbl = (u32 *)tgt->confq_pbl;
while (num_pages--) {
*pbl = (u32)page;
pbl++;
*pbl = (u32)((u64)page >> 32);
pbl++;
page += PAGE_SIZE;
}
/* Allocate and map ConnDB */
tgt->conn_db_mem_size = sizeof(struct fcoe_conn_db);
tgt->conn_db = dma_alloc_coherent(&hba->pcidev->dev,
tgt->conn_db_mem_size,
&tgt->conn_db_dma, GFP_KERNEL);
if (!tgt->conn_db) {
printk(KERN_ERR PFX "unable to allocate conn_db %d\n",
tgt->conn_db_mem_size);
goto mem_alloc_failure;
}
memset(tgt->conn_db, 0, tgt->conn_db_mem_size);
/* Allocate and map LCQ */
tgt->lcq_mem_size = (tgt->max_sqes + 8) * BNX2FC_SQ_WQE_SIZE;
tgt->lcq_mem_size = (tgt->lcq_mem_size + (PAGE_SIZE - 1)) &
PAGE_MASK;
tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
&tgt->lcq_dma, GFP_KERNEL);
if (!tgt->lcq) {
printk(KERN_ERR PFX "unable to allocate lcq %d\n",
tgt->lcq_mem_size);
goto mem_alloc_failure;
}
memset(tgt->lcq, 0, tgt->lcq_mem_size);
tgt->conn_db->rq_prod = 0x8000;
return 0;
mem_alloc_failure:
return -ENOMEM;
}
/**
* bnx2i_free_session_resc - free qp resources for the session
*
* @hba: adapter structure pointer
* @tgt: bnx2fc_rport structure pointer
*
* Free QP resources - SQ/RQ/CQ/XFERQ memory and PBL
*/
static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba,
struct bnx2fc_rport *tgt)
{
void __iomem *ctx_base_ptr;
BNX2FC_TGT_DBG(tgt, "Freeing up session resources\n");
spin_lock_bh(&tgt->cq_lock);
ctx_base_ptr = tgt->ctx_base;
tgt->ctx_base = NULL;
/* Free LCQ */
if (tgt->lcq) {
dma_free_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
tgt->lcq, tgt->lcq_dma);
tgt->lcq = NULL;
}
/* Free connDB */
if (tgt->conn_db) {
dma_free_coherent(&hba->pcidev->dev, tgt->conn_db_mem_size,
tgt->conn_db, tgt->conn_db_dma);
tgt->conn_db = NULL;
}
/* Free confq and confq pbl */
if (tgt->confq_pbl) {
dma_free_coherent(&hba->pcidev->dev, tgt->confq_pbl_size,
tgt->confq_pbl, tgt->confq_pbl_dma);
tgt->confq_pbl = NULL;
}
if (tgt->confq) {
dma_free_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
tgt->confq, tgt->confq_dma);
tgt->confq = NULL;
}
/* Free XFERQ */
if (tgt->xferq) {
dma_free_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
tgt->xferq, tgt->xferq_dma);
tgt->xferq = NULL;
}
/* Free RQ PBL and RQ */
if (tgt->rq_pbl) {
dma_free_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
tgt->rq_pbl, tgt->rq_pbl_dma);
tgt->rq_pbl = NULL;
}
if (tgt->rq) {
dma_free_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
tgt->rq, tgt->rq_dma);
tgt->rq = NULL;
}
/* Free CQ */
if (tgt->cq) {
dma_free_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
tgt->cq, tgt->cq_dma);
tgt->cq = NULL;
}
/* Free SQ */
if (tgt->sq) {
dma_free_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
tgt->sq, tgt->sq_dma);
tgt->sq = NULL;
}
spin_unlock_bh(&tgt->cq_lock);
if (ctx_base_ptr)
iounmap(ctx_base_ptr);
}