mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
1003
drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
Normal file
1003
drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
Normal file
File diff suppressed because it is too large
Load diff
13
drivers/scsi/bnx2fc/Kconfig
Normal file
13
drivers/scsi/bnx2fc/Kconfig
Normal file
|
@ -0,0 +1,13 @@
|
|||
config SCSI_BNX2X_FCOE
|
||||
tristate "QLogic NetXtreme II FCoE support"
|
||||
depends on PCI
|
||||
depends on (IPV6 || IPV6=n)
|
||||
depends on LIBFC
|
||||
depends on LIBFCOE
|
||||
select NETDEVICES
|
||||
select ETHERNET
|
||||
select NET_VENDOR_BROADCOM
|
||||
select CNIC
|
||||
---help---
|
||||
This driver supports FCoE offload for the QLogic NetXtreme II
|
||||
devices.
|
4
drivers/scsi/bnx2fc/Makefile
Normal file
4
drivers/scsi/bnx2fc/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
obj-$(CONFIG_SCSI_BNX2X_FCOE) += bnx2fc.o
|
||||
|
||||
bnx2fc-y := bnx2fc_els.o bnx2fc_fcoe.o bnx2fc_hwi.o bnx2fc_io.o bnx2fc_tgt.o \
|
||||
bnx2fc_debug.o
|
594
drivers/scsi/bnx2fc/bnx2fc.h
Normal file
594
drivers/scsi/bnx2fc/bnx2fc.h
Normal file
|
@ -0,0 +1,594 @@
|
|||
/* bnx2fc.h: QLogic NetXtreme II Linux FCoE offload driver.
|
||||
*
|
||||
* Copyright (c) 2008 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2014, QLogic 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)
|
||||
*/
|
||||
|
||||
#ifndef _BNX2FC_H_
|
||||
#define _BNX2FC_H_
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#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 "../../net/ethernet/broadcom/cnic_if.h"
|
||||
#include "../../net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h"
|
||||
#include "bnx2fc_constants.h"
|
||||
|
||||
#define BNX2FC_NAME "bnx2fc"
|
||||
#define BNX2FC_VERSION "2.4.2"
|
||||
|
||||
#define PFX "bnx2fc: "
|
||||
|
||||
#define BCM_CHIP_LEN 16
|
||||
|
||||
#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_NPIV 256
|
||||
|
||||
#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 BNX2X_DB_SHIFT 3
|
||||
|
||||
#define BNX2FC_TASK_SIZE 128
|
||||
#define BNX2FC_TASKS_PER_PAGE (PAGE_SIZE/BNX2FC_TASK_SIZE)
|
||||
|
||||
#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 FCOE_MAX_NUM_XIDS 0x2000
|
||||
#define FCOE_MAX_XID_OFFSET (FCOE_MAX_NUM_XIDS - 1)
|
||||
#define FCOE_XIDS_PER_CPU_OFFSET ((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
|
||||
|
||||
#define BNX2FC_STATS(hba, stat, cnt) \
|
||||
do { \
|
||||
u32 val; \
|
||||
\
|
||||
val = fw_stats->stat.cnt; \
|
||||
if (hba->prev_stats.stat.cnt <= val) \
|
||||
val -= hba->prev_stats.stat.cnt; \
|
||||
else \
|
||||
val += (0xfffffff - hba->prev_stats.stat.cnt); \
|
||||
hba->bfw_stats.cnt += val; \
|
||||
} while (0)
|
||||
|
||||
/* 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_fw_stats {
|
||||
u64 fc_crc_cnt;
|
||||
u64 fcoe_tx_pkt_cnt;
|
||||
u64 fcoe_rx_pkt_cnt;
|
||||
u64 fcoe_tx_byte_cnt;
|
||||
u64 fcoe_rx_byte_cnt;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
/* xid resources */
|
||||
u16 max_xid;
|
||||
u32 max_tasks;
|
||||
u32 max_outstanding_cmds;
|
||||
u32 elstm_xids;
|
||||
|
||||
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 bnx2fc_fw_stats bfw_stats;
|
||||
struct fcoe_statistics_params prev_stats;
|
||||
struct fcoe_statistics_params *stats_buffer;
|
||||
dma_addr_t stats_buf_dma;
|
||||
struct completion stat_req_done;
|
||||
struct fcoe_capabilities fcoe_cap;
|
||||
|
||||
/*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;
|
||||
|
||||
char chip_num[BCM_CHIP_LEN];
|
||||
};
|
||||
|
||||
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;
|
||||
u8 vlan_enabled;
|
||||
int vlan_id;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
#define bnx2fc_from_ctlr(x) \
|
||||
((struct bnx2fc_interface *)((x) + 1))
|
||||
|
||||
#define bnx2fc_to_ctlr(x) \
|
||||
((struct fcoe_ctlr *)(((struct fcoe_ctlr *)(x)) - 1))
|
||||
|
||||
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
|
||||
#define BNX2FC_FLAG_DISABLE_FAILED 0x9
|
||||
#define BNX2FC_FLAG_ENABLED 0xa
|
||||
|
||||
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;
|
||||
unsigned long retry_delay_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_enable_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);
|
||||
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);
|
||||
|
||||
|
||||
#include "bnx2fc_debug.h"
|
||||
|
||||
#endif
|
287
drivers/scsi/bnx2fc/bnx2fc_constants.h
Normal file
287
drivers/scsi/bnx2fc/bnx2fc_constants.h
Normal file
|
@ -0,0 +1,287 @@
|
|||
/* bnx2fc_constants.h: QLogic 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 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2014, QLogic 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_ */
|
83
drivers/scsi/bnx2fc/bnx2fc_debug.c
Normal file
83
drivers/scsi/bnx2fc/bnx2fc_debug.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* bnx2fc_debug.c: QLogic 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 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2014, QLogic 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bnx2fc.h"
|
||||
|
||||
void BNX2FC_IO_DBG(const struct bnx2fc_cmd *io_req, const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
if (likely(!(bnx2fc_debug_level & LOG_IO)))
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
if (io_req && io_req->port && io_req->port->lport &&
|
||||
io_req->port->lport->host)
|
||||
shost_printk(KERN_INFO, io_req->port->lport->host,
|
||||
PFX "xid:0x%x %pV",
|
||||
io_req->xid, &vaf);
|
||||
else
|
||||
pr_info("NULL %pV", &vaf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void BNX2FC_TGT_DBG(const struct bnx2fc_rport *tgt, const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
if (likely(!(bnx2fc_debug_level & LOG_TGT)))
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
if (tgt && tgt->port && tgt->port->lport && tgt->port->lport->host &&
|
||||
tgt->rport)
|
||||
shost_printk(KERN_INFO, tgt->port->lport->host,
|
||||
PFX "port:%x %pV",
|
||||
tgt->rport->port_id, &vaf);
|
||||
else
|
||||
pr_info("NULL %pV", &vaf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void BNX2FC_HBA_DBG(const struct fc_lport *lport, const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
if (likely(!(bnx2fc_debug_level & LOG_HBA)))
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
if (lport && lport->host)
|
||||
shost_printk(KERN_INFO, lport->host, PFX "%pV", &vaf);
|
||||
else
|
||||
pr_info("NULL %pV", &vaf);
|
||||
|
||||
va_end(args);
|
||||
}
|
46
drivers/scsi/bnx2fc/bnx2fc_debug.h
Normal file
46
drivers/scsi/bnx2fc/bnx2fc_debug.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* bnx2fc_debug.h: QLogic 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 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2014, QLogic 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_ELS_DBG(fmt, ...) \
|
||||
do { \
|
||||
if (unlikely(bnx2fc_debug_level & LOG_ELS)) \
|
||||
pr_info(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define BNX2FC_MISC_DBG(fmt, ...) \
|
||||
do { \
|
||||
if (unlikely(bnx2fc_debug_level & LOG_MISC)) \
|
||||
pr_info(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
__printf(2, 3)
|
||||
void BNX2FC_IO_DBG(const struct bnx2fc_cmd *io_req, const char *fmt, ...);
|
||||
__printf(2, 3)
|
||||
void BNX2FC_TGT_DBG(const struct bnx2fc_rport *tgt, const char *fmt, ...);
|
||||
__printf(2, 3)
|
||||
void BNX2FC_HBA_DBG(const struct fc_lport *lport, const char *fmt, ...);
|
||||
|
||||
#endif
|
918
drivers/scsi/bnx2fc/bnx2fc_els.c
Normal file
918
drivers/scsi/bnx2fc/bnx2fc_els.c
Normal file
|
@ -0,0 +1,918 @@
|
|||
/*
|
||||
* bnx2fc_els.c: QLogic NetXtreme II Linux FCoE offload driver.
|
||||
* This file contains helper routines that handle ELS requests
|
||||
* and responses.
|
||||
*
|
||||
* Copyright (c) 2008 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2014, QLogic 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");
|
||||
rc = bnx2fc_post_io_req(tgt, new_io_req);
|
||||
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;
|
||||
u8 op;
|
||||
|
||||
if (IS_ERR(fp))
|
||||
goto done;
|
||||
|
||||
mac = fr_cb(fp)->granted_mac;
|
||||
if (is_zero_ether_addr(mac)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
fcoe_ctlr_recv_flogi(fip, lport, fp);
|
||||
}
|
||||
if (!is_zero_ether_addr(mac))
|
||||
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 = bnx2fc_to_ctlr(interface);
|
||||
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);
|
||||
}
|
2824
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
Normal file
2824
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
Normal file
File diff suppressed because it is too large
Load diff
2195
drivers/scsi/bnx2fc/bnx2fc_hwi.c
Normal file
2195
drivers/scsi/bnx2fc/bnx2fc_hwi.c
Normal file
File diff suppressed because it is too large
Load diff
2097
drivers/scsi/bnx2fc/bnx2fc_io.c
Normal file
2097
drivers/scsi/bnx2fc/bnx2fc_io.c
Normal file
File diff suppressed because it is too large
Load diff
910
drivers/scsi/bnx2fc/bnx2fc_tgt.c
Normal file
910
drivers/scsi/bnx2fc/bnx2fc_tgt.c
Normal file
|
@ -0,0 +1,910 @@
|
|||
/* bnx2fc_tgt.c: QLogic 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 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2014, QLogic 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);
|
||||
clear_bit(BNX2FC_FLAG_ENABLED, &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);
|
||||
clear_bit(BNX2FC_FLAG_ENABLED, &tgt->flags);
|
||||
set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
|
||||
wake_up_interruptible(&tgt->ofld_wait);
|
||||
}
|
||||
|
||||
static void bnx2fc_ofld_wait(struct bnx2fc_rport *tgt)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
bnx2fc_ofld_wait(tgt);
|
||||
|
||||
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");
|
||||
goto ofld_err;
|
||||
}
|
||||
clear_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
|
||||
rval = bnx2fc_send_session_enable_req(port, tgt);
|
||||
if (rval) {
|
||||
pr_err(PFX "enable session failed\n");
|
||||
goto ofld_err;
|
||||
}
|
||||
bnx2fc_ofld_wait(tgt);
|
||||
if (!(test_bit(BNX2FC_FLAG_ENABLED, &tgt->flags)))
|
||||
goto ofld_err;
|
||||
return;
|
||||
|
||||
ofld_err:
|
||||
/* couldn't offload the session. log off from this rport */
|
||||
BNX2FC_TGT_DBG(tgt, "bnx2fc_offload_session - offload error\n");
|
||||
clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags);
|
||||
/* 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 bnx2fc_cmd *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_entry_safe(io_req, tmp, &tgt->active_cmd_queue, link) {
|
||||
i++;
|
||||
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);
|
||||
|
||||
/* Do not issue cleanup when disable request failed */
|
||||
if (test_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags))
|
||||
bnx2fc_process_cleanup_compl(io_req, io_req->task, 0);
|
||||
else {
|
||||
rc = bnx2fc_initiate_cleanup(io_req);
|
||||
BUG_ON(rc);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(io_req, tmp, &tgt->active_tm_queue, link) {
|
||||
i++;
|
||||
list_del_init(&io_req->link);
|
||||
io_req->on_tmf_queue = 0;
|
||||
BNX2FC_IO_DBG(io_req, "tm_queue cleanup\n");
|
||||
if (io_req->wait_for_comp)
|
||||
complete(&io_req->tm_done);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(io_req, tmp, &tgt->els_queue, link) {
|
||||
i++;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Do not issue cleanup when disable request failed */
|
||||
if (test_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags))
|
||||
bnx2fc_process_cleanup_compl(io_req, io_req->task, 0);
|
||||
else {
|
||||
rc = bnx2fc_initiate_cleanup(io_req);
|
||||
BUG_ON(rc);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(io_req, tmp, &tgt->io_retire_queue, link) {
|
||||
i++;
|
||||
list_del_init(&io_req->link);
|
||||
|
||||
BNX2FC_IO_DBG(io_req, "retire_queue flush\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 "
|
||||
"in retire_q\n");
|
||||
if (io_req->wait_for_comp)
|
||||
complete(&io_req->tm_done);
|
||||
}
|
||||
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_upld_wait(struct bnx2fc_rport *tgt)
|
||||
{
|
||||
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 (signal_pending(current))
|
||||
flush_signals(current);
|
||||
del_timer_sync(&tgt->upld_timer);
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
BNX2FC_TGT_DBG(tgt, "waiting for disable compl\n");
|
||||
bnx2fc_upld_wait(tgt);
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
bnx2fc_upld_wait(tgt);
|
||||
|
||||
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);
|
||||
|
||||
} else if (test_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags)) {
|
||||
printk(KERN_ERR PFX "ERROR!! DISABLE req failed, destroy"
|
||||
" not sent to FW\n");
|
||||
} 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);
|
||||
tgt->retry_delay_timestamp = 0;
|
||||
|
||||
if (rdata->flags & FC_RP_FLAGS_RETRY &&
|
||||
rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET &&
|
||||
!(rdata->ids.roles & FC_RPORT_ROLE_FCP_INITIATOR)) {
|
||||
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_ENABLED, &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_ENABLED, &tgt->flags)) {
|
||||
/* Session is offloaded and enabled. */
|
||||
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_ENABLED, &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 + (CNIC_PAGE_SIZE - 1)) &
|
||||
CNIC_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 + (CNIC_PAGE_SIZE - 1)) &
|
||||
CNIC_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 + (CNIC_PAGE_SIZE - 1)) &
|
||||
CNIC_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 / CNIC_PAGE_SIZE) * sizeof(void *);
|
||||
tgt->rq_pbl_size = (tgt->rq_pbl_size + (CNIC_PAGE_SIZE - 1)) &
|
||||
CNIC_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 / CNIC_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 += CNIC_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 + (CNIC_PAGE_SIZE - 1)) &
|
||||
CNIC_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 + (CNIC_PAGE_SIZE - 1)) &
|
||||
CNIC_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 / CNIC_PAGE_SIZE) * sizeof(void *);
|
||||
tgt->confq_pbl_size =
|
||||
(tgt->confq_pbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_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 / CNIC_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 += CNIC_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 + (CNIC_PAGE_SIZE - 1)) &
|
||||
CNIC_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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue