162306a36Sopenharmony_ci/* bnx2fc_hwi.c: QLogic Linux FCoE offload driver. 262306a36Sopenharmony_ci * This file contains the code that low level functions that interact 362306a36Sopenharmony_ci * with 57712 FCoE firmware. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2008-2013 Broadcom Corporation 662306a36Sopenharmony_ci * Copyright (c) 2014-2016 QLogic Corporation 762306a36Sopenharmony_ci * Copyright (c) 2016-2017 Cavium Inc. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 1062306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 1162306a36Sopenharmony_ci * the Free Software Foundation. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "bnx2fc.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciDECLARE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba, 2162306a36Sopenharmony_ci struct fcoe_kcqe *new_cqe_kcqe); 2262306a36Sopenharmony_cistatic void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, 2362306a36Sopenharmony_ci struct fcoe_kcqe *ofld_kcqe); 2462306a36Sopenharmony_cistatic void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, 2562306a36Sopenharmony_ci struct fcoe_kcqe *ofld_kcqe); 2662306a36Sopenharmony_cistatic void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code); 2762306a36Sopenharmony_cistatic void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba, 2862306a36Sopenharmony_ci struct fcoe_kcqe *destroy_kcqe); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciint bnx2fc_send_stat_req(struct bnx2fc_hba *hba) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct fcoe_kwqe_stat stat_req; 3362306a36Sopenharmony_ci struct kwqe *kwqe_arr[2]; 3462306a36Sopenharmony_ci int num_kwqes = 1; 3562306a36Sopenharmony_ci int rc = 0; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci memset(&stat_req, 0x00, sizeof(struct fcoe_kwqe_stat)); 3862306a36Sopenharmony_ci stat_req.hdr.op_code = FCOE_KWQE_OPCODE_STAT; 3962306a36Sopenharmony_ci stat_req.hdr.flags = 4062306a36Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci stat_req.stat_params_addr_lo = (u32) hba->stats_buf_dma; 4362306a36Sopenharmony_ci stat_req.stat_params_addr_hi = (u32) ((u64)hba->stats_buf_dma >> 32); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &stat_req; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 4862306a36Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return rc; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/** 5462306a36Sopenharmony_ci * bnx2fc_send_fw_fcoe_init_msg - initiates initial handshake with FCoE f/w 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * @hba: adapter structure pointer 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Send down FCoE firmware init KWQEs which initiates the initial handshake 5962306a36Sopenharmony_ci * with the f/w. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ciint bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct fcoe_kwqe_init1 fcoe_init1; 6562306a36Sopenharmony_ci struct fcoe_kwqe_init2 fcoe_init2; 6662306a36Sopenharmony_ci struct fcoe_kwqe_init3 fcoe_init3; 6762306a36Sopenharmony_ci struct kwqe *kwqe_arr[3]; 6862306a36Sopenharmony_ci int num_kwqes = 3; 6962306a36Sopenharmony_ci int rc = 0; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (!hba->cnic) { 7262306a36Sopenharmony_ci printk(KERN_ERR PFX "hba->cnic NULL during fcoe fw init\n"); 7362306a36Sopenharmony_ci return -ENODEV; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* fill init1 KWQE */ 7762306a36Sopenharmony_ci memset(&fcoe_init1, 0x00, sizeof(struct fcoe_kwqe_init1)); 7862306a36Sopenharmony_ci fcoe_init1.hdr.op_code = FCOE_KWQE_OPCODE_INIT1; 7962306a36Sopenharmony_ci fcoe_init1.hdr.flags = (FCOE_KWQE_LAYER_CODE << 8062306a36Sopenharmony_ci FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci fcoe_init1.num_tasks = hba->max_tasks; 8362306a36Sopenharmony_ci fcoe_init1.sq_num_wqes = BNX2FC_SQ_WQES_MAX; 8462306a36Sopenharmony_ci fcoe_init1.rq_num_wqes = BNX2FC_RQ_WQES_MAX; 8562306a36Sopenharmony_ci fcoe_init1.rq_buffer_log_size = BNX2FC_RQ_BUF_LOG_SZ; 8662306a36Sopenharmony_ci fcoe_init1.cq_num_wqes = BNX2FC_CQ_WQES_MAX; 8762306a36Sopenharmony_ci fcoe_init1.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma; 8862306a36Sopenharmony_ci fcoe_init1.dummy_buffer_addr_hi = (u32) ((u64)hba->dummy_buf_dma >> 32); 8962306a36Sopenharmony_ci fcoe_init1.task_list_pbl_addr_lo = (u32) hba->task_ctx_bd_dma; 9062306a36Sopenharmony_ci fcoe_init1.task_list_pbl_addr_hi = 9162306a36Sopenharmony_ci (u32) ((u64) hba->task_ctx_bd_dma >> 32); 9262306a36Sopenharmony_ci fcoe_init1.mtu = BNX2FC_MINI_JUMBO_MTU; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci fcoe_init1.flags = (PAGE_SHIFT << 9562306a36Sopenharmony_ci FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci fcoe_init1.num_sessions_log = BNX2FC_NUM_MAX_SESS_LOG; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* fill init2 KWQE */ 10062306a36Sopenharmony_ci memset(&fcoe_init2, 0x00, sizeof(struct fcoe_kwqe_init2)); 10162306a36Sopenharmony_ci fcoe_init2.hdr.op_code = FCOE_KWQE_OPCODE_INIT2; 10262306a36Sopenharmony_ci fcoe_init2.hdr.flags = (FCOE_KWQE_LAYER_CODE << 10362306a36Sopenharmony_ci FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci fcoe_init2.hsi_major_version = FCOE_HSI_MAJOR_VERSION; 10662306a36Sopenharmony_ci fcoe_init2.hsi_minor_version = FCOE_HSI_MINOR_VERSION; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci fcoe_init2.hash_tbl_pbl_addr_lo = (u32) hba->hash_tbl_pbl_dma; 11062306a36Sopenharmony_ci fcoe_init2.hash_tbl_pbl_addr_hi = (u32) 11162306a36Sopenharmony_ci ((u64) hba->hash_tbl_pbl_dma >> 32); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci fcoe_init2.t2_hash_tbl_addr_lo = (u32) hba->t2_hash_tbl_dma; 11462306a36Sopenharmony_ci fcoe_init2.t2_hash_tbl_addr_hi = (u32) 11562306a36Sopenharmony_ci ((u64) hba->t2_hash_tbl_dma >> 32); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci fcoe_init2.t2_ptr_hash_tbl_addr_lo = (u32) hba->t2_hash_tbl_ptr_dma; 11862306a36Sopenharmony_ci fcoe_init2.t2_ptr_hash_tbl_addr_hi = (u32) 11962306a36Sopenharmony_ci ((u64) hba->t2_hash_tbl_ptr_dma >> 32); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci fcoe_init2.free_list_count = BNX2FC_NUM_MAX_SESS; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* fill init3 KWQE */ 12462306a36Sopenharmony_ci memset(&fcoe_init3, 0x00, sizeof(struct fcoe_kwqe_init3)); 12562306a36Sopenharmony_ci fcoe_init3.hdr.op_code = FCOE_KWQE_OPCODE_INIT3; 12662306a36Sopenharmony_ci fcoe_init3.hdr.flags = (FCOE_KWQE_LAYER_CODE << 12762306a36Sopenharmony_ci FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 12862306a36Sopenharmony_ci fcoe_init3.error_bit_map_lo = 0xffffffff; 12962306a36Sopenharmony_ci fcoe_init3.error_bit_map_hi = 0xffffffff; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* 13262306a36Sopenharmony_ci * enable both cached connection and cached tasks 13362306a36Sopenharmony_ci * 0 = none, 1 = cached connection, 2 = cached tasks, 3 = both 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci fcoe_init3.perf_config = 3; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &fcoe_init1; 13862306a36Sopenharmony_ci kwqe_arr[1] = (struct kwqe *) &fcoe_init2; 13962306a36Sopenharmony_ci kwqe_arr[2] = (struct kwqe *) &fcoe_init3; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 14262306a36Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return rc; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ciint bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct fcoe_kwqe_destroy fcoe_destroy; 14962306a36Sopenharmony_ci struct kwqe *kwqe_arr[2]; 15062306a36Sopenharmony_ci int num_kwqes = 1; 15162306a36Sopenharmony_ci int rc = -1; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* fill destroy KWQE */ 15462306a36Sopenharmony_ci memset(&fcoe_destroy, 0x00, sizeof(struct fcoe_kwqe_destroy)); 15562306a36Sopenharmony_ci fcoe_destroy.hdr.op_code = FCOE_KWQE_OPCODE_DESTROY; 15662306a36Sopenharmony_ci fcoe_destroy.hdr.flags = (FCOE_KWQE_LAYER_CODE << 15762306a36Sopenharmony_ci FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 15862306a36Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &fcoe_destroy; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 16162306a36Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 16262306a36Sopenharmony_ci return rc; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/** 16662306a36Sopenharmony_ci * bnx2fc_send_session_ofld_req - initiates FCoE Session offload process 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * @port: port structure pointer 16962306a36Sopenharmony_ci * @tgt: bnx2fc_rport structure pointer 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ciint bnx2fc_send_session_ofld_req(struct fcoe_port *port, 17262306a36Sopenharmony_ci struct bnx2fc_rport *tgt) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct fc_lport *lport = port->lport; 17562306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 17662306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 17762306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 17862306a36Sopenharmony_ci struct kwqe *kwqe_arr[4]; 17962306a36Sopenharmony_ci struct fcoe_kwqe_conn_offload1 ofld_req1; 18062306a36Sopenharmony_ci struct fcoe_kwqe_conn_offload2 ofld_req2; 18162306a36Sopenharmony_ci struct fcoe_kwqe_conn_offload3 ofld_req3; 18262306a36Sopenharmony_ci struct fcoe_kwqe_conn_offload4 ofld_req4; 18362306a36Sopenharmony_ci struct fc_rport_priv *rdata = tgt->rdata; 18462306a36Sopenharmony_ci struct fc_rport *rport = tgt->rport; 18562306a36Sopenharmony_ci int num_kwqes = 4; 18662306a36Sopenharmony_ci u32 port_id; 18762306a36Sopenharmony_ci int rc = 0; 18862306a36Sopenharmony_ci u16 conn_id; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* Initialize offload request 1 structure */ 19162306a36Sopenharmony_ci memset(&ofld_req1, 0x00, sizeof(struct fcoe_kwqe_conn_offload1)); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci ofld_req1.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN1; 19462306a36Sopenharmony_ci ofld_req1.hdr.flags = 19562306a36Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci conn_id = (u16)tgt->fcoe_conn_id; 19962306a36Sopenharmony_ci ofld_req1.fcoe_conn_id = conn_id; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci ofld_req1.sq_addr_lo = (u32) tgt->sq_dma; 20362306a36Sopenharmony_ci ofld_req1.sq_addr_hi = (u32)((u64) tgt->sq_dma >> 32); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci ofld_req1.rq_pbl_addr_lo = (u32) tgt->rq_pbl_dma; 20662306a36Sopenharmony_ci ofld_req1.rq_pbl_addr_hi = (u32)((u64) tgt->rq_pbl_dma >> 32); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ofld_req1.rq_first_pbe_addr_lo = (u32) tgt->rq_dma; 20962306a36Sopenharmony_ci ofld_req1.rq_first_pbe_addr_hi = 21062306a36Sopenharmony_ci (u32)((u64) tgt->rq_dma >> 32); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ofld_req1.rq_prod = 0x8000; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* Initialize offload request 2 structure */ 21562306a36Sopenharmony_ci memset(&ofld_req2, 0x00, sizeof(struct fcoe_kwqe_conn_offload2)); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ofld_req2.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN2; 21862306a36Sopenharmony_ci ofld_req2.hdr.flags = 21962306a36Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ofld_req2.tx_max_fc_pay_len = rdata->maxframe_size; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ofld_req2.cq_addr_lo = (u32) tgt->cq_dma; 22462306a36Sopenharmony_ci ofld_req2.cq_addr_hi = (u32)((u64)tgt->cq_dma >> 32); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ofld_req2.xferq_addr_lo = (u32) tgt->xferq_dma; 22762306a36Sopenharmony_ci ofld_req2.xferq_addr_hi = (u32)((u64)tgt->xferq_dma >> 32); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ofld_req2.conn_db_addr_lo = (u32)tgt->conn_db_dma; 23062306a36Sopenharmony_ci ofld_req2.conn_db_addr_hi = (u32)((u64)tgt->conn_db_dma >> 32); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* Initialize offload request 3 structure */ 23362306a36Sopenharmony_ci memset(&ofld_req3, 0x00, sizeof(struct fcoe_kwqe_conn_offload3)); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci ofld_req3.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN3; 23662306a36Sopenharmony_ci ofld_req3.hdr.flags = 23762306a36Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci ofld_req3.vlan_tag = interface->vlan_id << 24062306a36Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT; 24162306a36Sopenharmony_ci ofld_req3.vlan_tag |= 3 << FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci port_id = fc_host_port_id(lport->host); 24462306a36Sopenharmony_ci if (port_id == 0) { 24562306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "ofld_req: port_id = 0, link down?\n"); 24662306a36Sopenharmony_ci return -EINVAL; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* 25062306a36Sopenharmony_ci * Store s_id of the initiator for further reference. This will 25162306a36Sopenharmony_ci * be used during disable/destroy during linkdown processing as 25262306a36Sopenharmony_ci * when the lport is reset, the port_id also is reset to 0 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci tgt->sid = port_id; 25562306a36Sopenharmony_ci ofld_req3.s_id[0] = (port_id & 0x000000FF); 25662306a36Sopenharmony_ci ofld_req3.s_id[1] = (port_id & 0x0000FF00) >> 8; 25762306a36Sopenharmony_ci ofld_req3.s_id[2] = (port_id & 0x00FF0000) >> 16; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci port_id = rport->port_id; 26062306a36Sopenharmony_ci ofld_req3.d_id[0] = (port_id & 0x000000FF); 26162306a36Sopenharmony_ci ofld_req3.d_id[1] = (port_id & 0x0000FF00) >> 8; 26262306a36Sopenharmony_ci ofld_req3.d_id[2] = (port_id & 0x00FF0000) >> 16; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci ofld_req3.tx_total_conc_seqs = rdata->max_seq; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci ofld_req3.tx_max_conc_seqs_c3 = rdata->max_seq; 26762306a36Sopenharmony_ci ofld_req3.rx_max_fc_pay_len = lport->mfs; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci ofld_req3.rx_total_conc_seqs = BNX2FC_MAX_SEQS; 27062306a36Sopenharmony_ci ofld_req3.rx_max_conc_seqs_c3 = BNX2FC_MAX_SEQS; 27162306a36Sopenharmony_ci ofld_req3.rx_open_seqs_exch_c3 = 1; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci ofld_req3.confq_first_pbe_addr_lo = tgt->confq_dma; 27462306a36Sopenharmony_ci ofld_req3.confq_first_pbe_addr_hi = (u32)((u64) tgt->confq_dma >> 32); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* set mul_n_port_ids supported flag to 0, until it is supported */ 27762306a36Sopenharmony_ci ofld_req3.flags = 0; 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci ofld_req3.flags |= (((lport->send_sp_features & FC_SP_FT_MNA) ? 1:0) << 28062306a36Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT); 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci /* Info from PLOGI response */ 28362306a36Sopenharmony_ci ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_EDTR) ? 1 : 0) << 28462306a36Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_SEQC) ? 1 : 0) << 28762306a36Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* 29062306a36Sopenharmony_ci * Info from PRLI response, this info is used for sequence level error 29162306a36Sopenharmony_ci * recovery support 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci if (tgt->dev_type == TYPE_TAPE) { 29462306a36Sopenharmony_ci ofld_req3.flags |= 1 << 29562306a36Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT; 29662306a36Sopenharmony_ci ofld_req3.flags |= (((rdata->flags & FC_RP_FLAGS_REC_SUPPORTED) 29762306a36Sopenharmony_ci ? 1 : 0) << 29862306a36Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* vlan flag */ 30262306a36Sopenharmony_ci ofld_req3.flags |= (interface->vlan_enabled << 30362306a36Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* C2_VALID and ACK flags are not set as they are not supported */ 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* Initialize offload request 4 structure */ 30962306a36Sopenharmony_ci memset(&ofld_req4, 0x00, sizeof(struct fcoe_kwqe_conn_offload4)); 31062306a36Sopenharmony_ci ofld_req4.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN4; 31162306a36Sopenharmony_ci ofld_req4.hdr.flags = 31262306a36Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci ofld_req4.e_d_tov_timer_val = lport->e_d_tov / 20; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci ofld_req4.src_mac_addr_lo[0] = port->data_src_addr[5]; 31862306a36Sopenharmony_ci /* local mac */ 31962306a36Sopenharmony_ci ofld_req4.src_mac_addr_lo[1] = port->data_src_addr[4]; 32062306a36Sopenharmony_ci ofld_req4.src_mac_addr_mid[0] = port->data_src_addr[3]; 32162306a36Sopenharmony_ci ofld_req4.src_mac_addr_mid[1] = port->data_src_addr[2]; 32262306a36Sopenharmony_ci ofld_req4.src_mac_addr_hi[0] = port->data_src_addr[1]; 32362306a36Sopenharmony_ci ofld_req4.src_mac_addr_hi[1] = port->data_src_addr[0]; 32462306a36Sopenharmony_ci ofld_req4.dst_mac_addr_lo[0] = ctlr->dest_addr[5]; 32562306a36Sopenharmony_ci /* fcf mac */ 32662306a36Sopenharmony_ci ofld_req4.dst_mac_addr_lo[1] = ctlr->dest_addr[4]; 32762306a36Sopenharmony_ci ofld_req4.dst_mac_addr_mid[0] = ctlr->dest_addr[3]; 32862306a36Sopenharmony_ci ofld_req4.dst_mac_addr_mid[1] = ctlr->dest_addr[2]; 32962306a36Sopenharmony_ci ofld_req4.dst_mac_addr_hi[0] = ctlr->dest_addr[1]; 33062306a36Sopenharmony_ci ofld_req4.dst_mac_addr_hi[1] = ctlr->dest_addr[0]; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci ofld_req4.lcq_addr_lo = (u32) tgt->lcq_dma; 33362306a36Sopenharmony_ci ofld_req4.lcq_addr_hi = (u32)((u64) tgt->lcq_dma >> 32); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci ofld_req4.confq_pbl_base_addr_lo = (u32) tgt->confq_pbl_dma; 33662306a36Sopenharmony_ci ofld_req4.confq_pbl_base_addr_hi = 33762306a36Sopenharmony_ci (u32)((u64) tgt->confq_pbl_dma >> 32); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &ofld_req1; 34062306a36Sopenharmony_ci kwqe_arr[1] = (struct kwqe *) &ofld_req2; 34162306a36Sopenharmony_ci kwqe_arr[2] = (struct kwqe *) &ofld_req3; 34262306a36Sopenharmony_ci kwqe_arr[3] = (struct kwqe *) &ofld_req4; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 34562306a36Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci return rc; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/** 35162306a36Sopenharmony_ci * bnx2fc_send_session_enable_req - initiates FCoE Session enablement 35262306a36Sopenharmony_ci * 35362306a36Sopenharmony_ci * @port: port structure pointer 35462306a36Sopenharmony_ci * @tgt: bnx2fc_rport structure pointer 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ciint bnx2fc_send_session_enable_req(struct fcoe_port *port, 35762306a36Sopenharmony_ci struct bnx2fc_rport *tgt) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct kwqe *kwqe_arr[2]; 36062306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 36162306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 36262306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 36362306a36Sopenharmony_ci struct fcoe_kwqe_conn_enable_disable enbl_req; 36462306a36Sopenharmony_ci struct fc_lport *lport = port->lport; 36562306a36Sopenharmony_ci struct fc_rport *rport = tgt->rport; 36662306a36Sopenharmony_ci int num_kwqes = 1; 36762306a36Sopenharmony_ci int rc = 0; 36862306a36Sopenharmony_ci u32 port_id; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci memset(&enbl_req, 0x00, 37162306a36Sopenharmony_ci sizeof(struct fcoe_kwqe_conn_enable_disable)); 37262306a36Sopenharmony_ci enbl_req.hdr.op_code = FCOE_KWQE_OPCODE_ENABLE_CONN; 37362306a36Sopenharmony_ci enbl_req.hdr.flags = 37462306a36Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci enbl_req.src_mac_addr_lo[0] = port->data_src_addr[5]; 37762306a36Sopenharmony_ci /* local mac */ 37862306a36Sopenharmony_ci enbl_req.src_mac_addr_lo[1] = port->data_src_addr[4]; 37962306a36Sopenharmony_ci enbl_req.src_mac_addr_mid[0] = port->data_src_addr[3]; 38062306a36Sopenharmony_ci enbl_req.src_mac_addr_mid[1] = port->data_src_addr[2]; 38162306a36Sopenharmony_ci enbl_req.src_mac_addr_hi[0] = port->data_src_addr[1]; 38262306a36Sopenharmony_ci enbl_req.src_mac_addr_hi[1] = port->data_src_addr[0]; 38362306a36Sopenharmony_ci memcpy(tgt->src_addr, port->data_src_addr, ETH_ALEN); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci enbl_req.dst_mac_addr_lo[0] = ctlr->dest_addr[5]; 38662306a36Sopenharmony_ci enbl_req.dst_mac_addr_lo[1] = ctlr->dest_addr[4]; 38762306a36Sopenharmony_ci enbl_req.dst_mac_addr_mid[0] = ctlr->dest_addr[3]; 38862306a36Sopenharmony_ci enbl_req.dst_mac_addr_mid[1] = ctlr->dest_addr[2]; 38962306a36Sopenharmony_ci enbl_req.dst_mac_addr_hi[0] = ctlr->dest_addr[1]; 39062306a36Sopenharmony_ci enbl_req.dst_mac_addr_hi[1] = ctlr->dest_addr[0]; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci port_id = fc_host_port_id(lport->host); 39362306a36Sopenharmony_ci if (port_id != tgt->sid) { 39462306a36Sopenharmony_ci printk(KERN_ERR PFX "WARN: enable_req port_id = 0x%x," 39562306a36Sopenharmony_ci "sid = 0x%x\n", port_id, tgt->sid); 39662306a36Sopenharmony_ci port_id = tgt->sid; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci enbl_req.s_id[0] = (port_id & 0x000000FF); 39962306a36Sopenharmony_ci enbl_req.s_id[1] = (port_id & 0x0000FF00) >> 8; 40062306a36Sopenharmony_ci enbl_req.s_id[2] = (port_id & 0x00FF0000) >> 16; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci port_id = rport->port_id; 40362306a36Sopenharmony_ci enbl_req.d_id[0] = (port_id & 0x000000FF); 40462306a36Sopenharmony_ci enbl_req.d_id[1] = (port_id & 0x0000FF00) >> 8; 40562306a36Sopenharmony_ci enbl_req.d_id[2] = (port_id & 0x00FF0000) >> 16; 40662306a36Sopenharmony_ci enbl_req.vlan_tag = interface->vlan_id << 40762306a36Sopenharmony_ci FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT; 40862306a36Sopenharmony_ci enbl_req.vlan_tag |= 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT; 40962306a36Sopenharmony_ci enbl_req.vlan_flag = interface->vlan_enabled; 41062306a36Sopenharmony_ci enbl_req.context_id = tgt->context_id; 41162306a36Sopenharmony_ci enbl_req.conn_id = tgt->fcoe_conn_id; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &enbl_req; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 41662306a36Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 41762306a36Sopenharmony_ci return rc; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/** 42162306a36Sopenharmony_ci * bnx2fc_send_session_disable_req - initiates FCoE Session disable 42262306a36Sopenharmony_ci * 42362306a36Sopenharmony_ci * @port: port structure pointer 42462306a36Sopenharmony_ci * @tgt: bnx2fc_rport structure pointer 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_ciint bnx2fc_send_session_disable_req(struct fcoe_port *port, 42762306a36Sopenharmony_ci struct bnx2fc_rport *tgt) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 43062306a36Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 43162306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 43262306a36Sopenharmony_ci struct fcoe_kwqe_conn_enable_disable disable_req; 43362306a36Sopenharmony_ci struct kwqe *kwqe_arr[2]; 43462306a36Sopenharmony_ci struct fc_rport *rport = tgt->rport; 43562306a36Sopenharmony_ci int num_kwqes = 1; 43662306a36Sopenharmony_ci int rc = 0; 43762306a36Sopenharmony_ci u32 port_id; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci memset(&disable_req, 0x00, 44062306a36Sopenharmony_ci sizeof(struct fcoe_kwqe_conn_enable_disable)); 44162306a36Sopenharmony_ci disable_req.hdr.op_code = FCOE_KWQE_OPCODE_DISABLE_CONN; 44262306a36Sopenharmony_ci disable_req.hdr.flags = 44362306a36Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci disable_req.src_mac_addr_lo[0] = tgt->src_addr[5]; 44662306a36Sopenharmony_ci disable_req.src_mac_addr_lo[1] = tgt->src_addr[4]; 44762306a36Sopenharmony_ci disable_req.src_mac_addr_mid[0] = tgt->src_addr[3]; 44862306a36Sopenharmony_ci disable_req.src_mac_addr_mid[1] = tgt->src_addr[2]; 44962306a36Sopenharmony_ci disable_req.src_mac_addr_hi[0] = tgt->src_addr[1]; 45062306a36Sopenharmony_ci disable_req.src_mac_addr_hi[1] = tgt->src_addr[0]; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci disable_req.dst_mac_addr_lo[0] = ctlr->dest_addr[5]; 45362306a36Sopenharmony_ci disable_req.dst_mac_addr_lo[1] = ctlr->dest_addr[4]; 45462306a36Sopenharmony_ci disable_req.dst_mac_addr_mid[0] = ctlr->dest_addr[3]; 45562306a36Sopenharmony_ci disable_req.dst_mac_addr_mid[1] = ctlr->dest_addr[2]; 45662306a36Sopenharmony_ci disable_req.dst_mac_addr_hi[0] = ctlr->dest_addr[1]; 45762306a36Sopenharmony_ci disable_req.dst_mac_addr_hi[1] = ctlr->dest_addr[0]; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci port_id = tgt->sid; 46062306a36Sopenharmony_ci disable_req.s_id[0] = (port_id & 0x000000FF); 46162306a36Sopenharmony_ci disable_req.s_id[1] = (port_id & 0x0000FF00) >> 8; 46262306a36Sopenharmony_ci disable_req.s_id[2] = (port_id & 0x00FF0000) >> 16; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci port_id = rport->port_id; 46662306a36Sopenharmony_ci disable_req.d_id[0] = (port_id & 0x000000FF); 46762306a36Sopenharmony_ci disable_req.d_id[1] = (port_id & 0x0000FF00) >> 8; 46862306a36Sopenharmony_ci disable_req.d_id[2] = (port_id & 0x00FF0000) >> 16; 46962306a36Sopenharmony_ci disable_req.context_id = tgt->context_id; 47062306a36Sopenharmony_ci disable_req.conn_id = tgt->fcoe_conn_id; 47162306a36Sopenharmony_ci disable_req.vlan_tag = interface->vlan_id << 47262306a36Sopenharmony_ci FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT; 47362306a36Sopenharmony_ci disable_req.vlan_tag |= 47462306a36Sopenharmony_ci 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT; 47562306a36Sopenharmony_ci disable_req.vlan_flag = interface->vlan_enabled; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &disable_req; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 48062306a36Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return rc; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci/** 48662306a36Sopenharmony_ci * bnx2fc_send_session_destroy_req - initiates FCoE Session destroy 48762306a36Sopenharmony_ci * 48862306a36Sopenharmony_ci * @hba: adapter structure pointer 48962306a36Sopenharmony_ci * @tgt: bnx2fc_rport structure pointer 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ciint bnx2fc_send_session_destroy_req(struct bnx2fc_hba *hba, 49262306a36Sopenharmony_ci struct bnx2fc_rport *tgt) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci struct fcoe_kwqe_conn_destroy destroy_req; 49562306a36Sopenharmony_ci struct kwqe *kwqe_arr[2]; 49662306a36Sopenharmony_ci int num_kwqes = 1; 49762306a36Sopenharmony_ci int rc = 0; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci memset(&destroy_req, 0x00, sizeof(struct fcoe_kwqe_conn_destroy)); 50062306a36Sopenharmony_ci destroy_req.hdr.op_code = FCOE_KWQE_OPCODE_DESTROY_CONN; 50162306a36Sopenharmony_ci destroy_req.hdr.flags = 50262306a36Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci destroy_req.context_id = tgt->context_id; 50562306a36Sopenharmony_ci destroy_req.conn_id = tgt->fcoe_conn_id; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &destroy_req; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 51062306a36Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return rc; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic bool is_valid_lport(struct bnx2fc_hba *hba, struct fc_lport *lport) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct bnx2fc_lport *blport; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 52062306a36Sopenharmony_ci list_for_each_entry(blport, &hba->vports, list) { 52162306a36Sopenharmony_ci if (blport->lport == lport) { 52262306a36Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 52362306a36Sopenharmony_ci return true; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 52762306a36Sopenharmony_ci return false; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic void bnx2fc_unsol_els_work(struct work_struct *work) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct bnx2fc_unsol_els *unsol_els; 53562306a36Sopenharmony_ci struct fc_lport *lport; 53662306a36Sopenharmony_ci struct bnx2fc_hba *hba; 53762306a36Sopenharmony_ci struct fc_frame *fp; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci unsol_els = container_of(work, struct bnx2fc_unsol_els, unsol_els_work); 54062306a36Sopenharmony_ci lport = unsol_els->lport; 54162306a36Sopenharmony_ci fp = unsol_els->fp; 54262306a36Sopenharmony_ci hba = unsol_els->hba; 54362306a36Sopenharmony_ci if (is_valid_lport(hba, lport)) 54462306a36Sopenharmony_ci fc_exch_recv(lport, fp); 54562306a36Sopenharmony_ci kfree(unsol_els); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_civoid bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, 54962306a36Sopenharmony_ci unsigned char *buf, 55062306a36Sopenharmony_ci u32 frame_len, u16 l2_oxid) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct fcoe_port *port = tgt->port; 55362306a36Sopenharmony_ci struct fc_lport *lport = port->lport; 55462306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 55562306a36Sopenharmony_ci struct bnx2fc_unsol_els *unsol_els; 55662306a36Sopenharmony_ci struct fc_frame_header *fh; 55762306a36Sopenharmony_ci struct fc_frame *fp; 55862306a36Sopenharmony_ci struct sk_buff *skb; 55962306a36Sopenharmony_ci u32 payload_len; 56062306a36Sopenharmony_ci u32 crc; 56162306a36Sopenharmony_ci u8 op; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci unsol_els = kzalloc(sizeof(*unsol_els), GFP_ATOMIC); 56562306a36Sopenharmony_ci if (!unsol_els) { 56662306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Unable to allocate unsol_work\n"); 56762306a36Sopenharmony_ci return; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "l2_frame_compl l2_oxid = 0x%x, frame_len = %d\n", 57162306a36Sopenharmony_ci l2_oxid, frame_len); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci payload_len = frame_len - sizeof(struct fc_frame_header); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci fp = fc_frame_alloc(lport, payload_len); 57662306a36Sopenharmony_ci if (!fp) { 57762306a36Sopenharmony_ci printk(KERN_ERR PFX "fc_frame_alloc failure\n"); 57862306a36Sopenharmony_ci kfree(unsol_els); 57962306a36Sopenharmony_ci return; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci fh = (struct fc_frame_header *) fc_frame_header_get(fp); 58362306a36Sopenharmony_ci /* Copy FC Frame header and payload into the frame */ 58462306a36Sopenharmony_ci memcpy(fh, buf, frame_len); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (l2_oxid != FC_XID_UNKNOWN) 58762306a36Sopenharmony_ci fh->fh_ox_id = htons(l2_oxid); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci skb = fp_skb(fp); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if ((fh->fh_r_ctl == FC_RCTL_ELS_REQ) || 59262306a36Sopenharmony_ci (fh->fh_r_ctl == FC_RCTL_ELS_REP)) { 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (fh->fh_type == FC_TYPE_ELS) { 59562306a36Sopenharmony_ci op = fc_frame_payload_op(fp); 59662306a36Sopenharmony_ci if ((op == ELS_TEST) || (op == ELS_ESTC) || 59762306a36Sopenharmony_ci (op == ELS_FAN) || (op == ELS_CSU)) { 59862306a36Sopenharmony_ci /* 59962306a36Sopenharmony_ci * No need to reply for these 60062306a36Sopenharmony_ci * ELS requests 60162306a36Sopenharmony_ci */ 60262306a36Sopenharmony_ci printk(KERN_ERR PFX "dropping ELS 0x%x\n", op); 60362306a36Sopenharmony_ci kfree_skb(skb); 60462306a36Sopenharmony_ci kfree(unsol_els); 60562306a36Sopenharmony_ci return; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci crc = fcoe_fc_crc(fp); 60962306a36Sopenharmony_ci fc_frame_init(fp); 61062306a36Sopenharmony_ci fr_dev(fp) = lport; 61162306a36Sopenharmony_ci fr_sof(fp) = FC_SOF_I3; 61262306a36Sopenharmony_ci fr_eof(fp) = FC_EOF_T; 61362306a36Sopenharmony_ci fr_crc(fp) = cpu_to_le32(~crc); 61462306a36Sopenharmony_ci unsol_els->lport = lport; 61562306a36Sopenharmony_ci unsol_els->hba = interface->hba; 61662306a36Sopenharmony_ci unsol_els->fp = fp; 61762306a36Sopenharmony_ci INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work); 61862306a36Sopenharmony_ci queue_work(bnx2fc_wq, &unsol_els->unsol_els_work); 61962306a36Sopenharmony_ci } else { 62062306a36Sopenharmony_ci BNX2FC_HBA_DBG(lport, "fh_r_ctl = 0x%x\n", fh->fh_r_ctl); 62162306a36Sopenharmony_ci kfree_skb(skb); 62262306a36Sopenharmony_ci kfree(unsol_els); 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci u8 num_rq; 62962306a36Sopenharmony_ci struct fcoe_err_report_entry *err_entry; 63062306a36Sopenharmony_ci unsigned char *rq_data; 63162306a36Sopenharmony_ci unsigned char *buf = NULL, *buf1; 63262306a36Sopenharmony_ci int i; 63362306a36Sopenharmony_ci u16 xid; 63462306a36Sopenharmony_ci u32 frame_len, len; 63562306a36Sopenharmony_ci struct bnx2fc_cmd *io_req = NULL; 63662306a36Sopenharmony_ci struct bnx2fc_interface *interface = tgt->port->priv; 63762306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 63862306a36Sopenharmony_ci int rc = 0; 63962306a36Sopenharmony_ci u64 err_warn_bit_map; 64062306a36Sopenharmony_ci u8 err_warn = 0xff; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Entered UNSOL COMPLETION wqe = 0x%x\n", wqe); 64462306a36Sopenharmony_ci switch (wqe & FCOE_UNSOLICITED_CQE_SUBTYPE) { 64562306a36Sopenharmony_ci case FCOE_UNSOLICITED_FRAME_CQE_TYPE: 64662306a36Sopenharmony_ci frame_len = (wqe & FCOE_UNSOLICITED_CQE_PKT_LEN) >> 64762306a36Sopenharmony_ci FCOE_UNSOLICITED_CQE_PKT_LEN_SHIFT; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci num_rq = (frame_len + BNX2FC_RQ_BUF_SZ - 1) / BNX2FC_RQ_BUF_SZ; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 65262306a36Sopenharmony_ci rq_data = (unsigned char *)bnx2fc_get_next_rqe(tgt, num_rq); 65362306a36Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (rq_data) { 65662306a36Sopenharmony_ci buf = rq_data; 65762306a36Sopenharmony_ci } else { 65862306a36Sopenharmony_ci buf1 = buf = kmalloc((num_rq * BNX2FC_RQ_BUF_SZ), 65962306a36Sopenharmony_ci GFP_ATOMIC); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (!buf1) { 66262306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Memory alloc failure\n"); 66362306a36Sopenharmony_ci break; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci for (i = 0; i < num_rq; i++) { 66762306a36Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 66862306a36Sopenharmony_ci rq_data = (unsigned char *) 66962306a36Sopenharmony_ci bnx2fc_get_next_rqe(tgt, 1); 67062306a36Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 67162306a36Sopenharmony_ci len = BNX2FC_RQ_BUF_SZ; 67262306a36Sopenharmony_ci memcpy(buf1, rq_data, len); 67362306a36Sopenharmony_ci buf1 += len; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, 67762306a36Sopenharmony_ci FC_XID_UNKNOWN); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (buf != rq_data) 68062306a36Sopenharmony_ci kfree(buf); 68162306a36Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 68262306a36Sopenharmony_ci bnx2fc_return_rqe(tgt, num_rq); 68362306a36Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 68462306a36Sopenharmony_ci break; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci case FCOE_ERROR_DETECTION_CQE_TYPE: 68762306a36Sopenharmony_ci /* 68862306a36Sopenharmony_ci * In case of error reporting CQE a single RQ entry 68962306a36Sopenharmony_ci * is consumed. 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 69262306a36Sopenharmony_ci num_rq = 1; 69362306a36Sopenharmony_ci err_entry = (struct fcoe_err_report_entry *) 69462306a36Sopenharmony_ci bnx2fc_get_next_rqe(tgt, 1); 69562306a36Sopenharmony_ci xid = err_entry->fc_hdr.ox_id; 69662306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Unsol Error Frame OX_ID = 0x%x\n", xid); 69762306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x\n", 69862306a36Sopenharmony_ci err_entry->data.err_warn_bitmap_hi, 69962306a36Sopenharmony_ci err_entry->data.err_warn_bitmap_lo); 70062306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n", 70162306a36Sopenharmony_ci err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (xid > hba->max_xid) { 70462306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", 70562306a36Sopenharmony_ci xid); 70662306a36Sopenharmony_ci goto ret_err_rqe; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; 71162306a36Sopenharmony_ci if (!io_req) 71262306a36Sopenharmony_ci goto ret_err_rqe; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (io_req->cmd_type != BNX2FC_SCSI_CMD) { 71562306a36Sopenharmony_ci printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n"); 71662306a36Sopenharmony_ci goto ret_err_rqe; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP, 72062306a36Sopenharmony_ci &io_req->req_flags)) { 72162306a36Sopenharmony_ci BNX2FC_IO_DBG(io_req, "unsol_err: cleanup in " 72262306a36Sopenharmony_ci "progress.. ignore unsol err\n"); 72362306a36Sopenharmony_ci goto ret_err_rqe; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci err_warn_bit_map = (u64) 72762306a36Sopenharmony_ci ((u64)err_entry->data.err_warn_bitmap_hi << 32) | 72862306a36Sopenharmony_ci (u64)err_entry->data.err_warn_bitmap_lo; 72962306a36Sopenharmony_ci for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) { 73062306a36Sopenharmony_ci if (err_warn_bit_map & (u64)((u64)1 << i)) { 73162306a36Sopenharmony_ci err_warn = i; 73262306a36Sopenharmony_ci break; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* 73762306a36Sopenharmony_ci * If ABTS is already in progress, and FW error is 73862306a36Sopenharmony_ci * received after that, do not cancel the timeout_work 73962306a36Sopenharmony_ci * and let the error recovery continue by explicitly 74062306a36Sopenharmony_ci * logging out the target, when the ABTS eventually 74162306a36Sopenharmony_ci * times out. 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_ci if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { 74462306a36Sopenharmony_ci printk(KERN_ERR PFX "err_warn: io_req (0x%x) already " 74562306a36Sopenharmony_ci "in ABTS processing\n", xid); 74662306a36Sopenharmony_ci goto ret_err_rqe; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "err = 0x%x\n", err_warn); 74962306a36Sopenharmony_ci if (tgt->dev_type != TYPE_TAPE) 75062306a36Sopenharmony_ci goto skip_rec; 75162306a36Sopenharmony_ci switch (err_warn) { 75262306a36Sopenharmony_ci case FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION: 75362306a36Sopenharmony_ci case FCOE_ERROR_CODE_DATA_OOO_RO: 75462306a36Sopenharmony_ci case FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT: 75562306a36Sopenharmony_ci case FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET: 75662306a36Sopenharmony_ci case FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ: 75762306a36Sopenharmony_ci case FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET: 75862306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "REC TOV popped for xid - 0x%x\n", 75962306a36Sopenharmony_ci xid); 76062306a36Sopenharmony_ci memcpy(&io_req->err_entry, err_entry, 76162306a36Sopenharmony_ci sizeof(struct fcoe_err_report_entry)); 76262306a36Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_SRR_SENT, 76362306a36Sopenharmony_ci &io_req->req_flags)) { 76462306a36Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 76562306a36Sopenharmony_ci rc = bnx2fc_send_rec(io_req); 76662306a36Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (rc) 76962306a36Sopenharmony_ci goto skip_rec; 77062306a36Sopenharmony_ci } else 77162306a36Sopenharmony_ci printk(KERN_ERR PFX "SRR in progress\n"); 77262306a36Sopenharmony_ci goto ret_err_rqe; 77362306a36Sopenharmony_ci default: 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ciskip_rec: 77862306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags); 77962306a36Sopenharmony_ci /* 78062306a36Sopenharmony_ci * Cancel the timeout_work, as we received IO 78162306a36Sopenharmony_ci * completion with FW error. 78262306a36Sopenharmony_ci */ 78362306a36Sopenharmony_ci if (cancel_delayed_work(&io_req->timeout_work)) 78462306a36Sopenharmony_ci kref_put(&io_req->refcount, bnx2fc_cmd_release); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci rc = bnx2fc_initiate_abts(io_req); 78762306a36Sopenharmony_ci if (rc != SUCCESS) { 78862306a36Sopenharmony_ci printk(KERN_ERR PFX "err_warn: initiate_abts " 78962306a36Sopenharmony_ci "failed xid = 0x%x. issue cleanup\n", 79062306a36Sopenharmony_ci io_req->xid); 79162306a36Sopenharmony_ci bnx2fc_initiate_cleanup(io_req); 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ciret_err_rqe: 79462306a36Sopenharmony_ci bnx2fc_return_rqe(tgt, 1); 79562306a36Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 79662306a36Sopenharmony_ci break; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci case FCOE_WARNING_DETECTION_CQE_TYPE: 79962306a36Sopenharmony_ci /* 80062306a36Sopenharmony_ci *In case of warning reporting CQE a single RQ entry 80162306a36Sopenharmony_ci * is consumes. 80262306a36Sopenharmony_ci */ 80362306a36Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 80462306a36Sopenharmony_ci num_rq = 1; 80562306a36Sopenharmony_ci err_entry = (struct fcoe_err_report_entry *) 80662306a36Sopenharmony_ci bnx2fc_get_next_rqe(tgt, 1); 80762306a36Sopenharmony_ci xid = cpu_to_be16(err_entry->fc_hdr.ox_id); 80862306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Unsol Warning Frame OX_ID = 0x%x\n", xid); 80962306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x", 81062306a36Sopenharmony_ci err_entry->data.err_warn_bitmap_hi, 81162306a36Sopenharmony_ci err_entry->data.err_warn_bitmap_lo); 81262306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x", 81362306a36Sopenharmony_ci err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (xid > hba->max_xid) { 81662306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid); 81762306a36Sopenharmony_ci goto ret_warn_rqe; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci err_warn_bit_map = (u64) 82162306a36Sopenharmony_ci ((u64)err_entry->data.err_warn_bitmap_hi << 32) | 82262306a36Sopenharmony_ci (u64)err_entry->data.err_warn_bitmap_lo; 82362306a36Sopenharmony_ci for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) { 82462306a36Sopenharmony_ci if (err_warn_bit_map & ((u64)1 << i)) { 82562306a36Sopenharmony_ci err_warn = i; 82662306a36Sopenharmony_ci break; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "warn = 0x%x\n", err_warn); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; 83262306a36Sopenharmony_ci if (!io_req) 83362306a36Sopenharmony_ci goto ret_warn_rqe; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (io_req->cmd_type != BNX2FC_SCSI_CMD) { 83662306a36Sopenharmony_ci printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n"); 83762306a36Sopenharmony_ci goto ret_warn_rqe; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci memcpy(&io_req->err_entry, err_entry, 84162306a36Sopenharmony_ci sizeof(struct fcoe_err_report_entry)); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (err_warn == FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION) 84462306a36Sopenharmony_ci /* REC_TOV is not a warning code */ 84562306a36Sopenharmony_ci BUG_ON(1); 84662306a36Sopenharmony_ci else 84762306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Unsolicited warning\n"); 84862306a36Sopenharmony_ciret_warn_rqe: 84962306a36Sopenharmony_ci bnx2fc_return_rqe(tgt, 1); 85062306a36Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci default: 85462306a36Sopenharmony_ci printk(KERN_ERR PFX "Unsol Compl: Invalid CQE Subtype\n"); 85562306a36Sopenharmony_ci break; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_civoid bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe, 86062306a36Sopenharmony_ci unsigned char *rq_data, u8 num_rq, 86162306a36Sopenharmony_ci struct fcoe_task_ctx_entry *task) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct fcoe_port *port = tgt->port; 86462306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 86562306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 86662306a36Sopenharmony_ci struct bnx2fc_cmd *io_req; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci u16 xid; 86962306a36Sopenharmony_ci u8 cmd_type; 87062306a36Sopenharmony_ci u8 rx_state = 0; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID; 87562306a36Sopenharmony_ci io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (io_req == NULL) { 87862306a36Sopenharmony_ci printk(KERN_ERR PFX "ERROR? cq_compl - io_req is NULL\n"); 87962306a36Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 88062306a36Sopenharmony_ci return; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* Timestamp IO completion time */ 88462306a36Sopenharmony_ci cmd_type = io_req->cmd_type; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci rx_state = ((task->rxwr_txrd.var_ctx.rx_flags & 88762306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE) >> 88862306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE_SHIFT); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* Process other IO completion types */ 89162306a36Sopenharmony_ci switch (cmd_type) { 89262306a36Sopenharmony_ci case BNX2FC_SCSI_CMD: 89362306a36Sopenharmony_ci if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) { 89462306a36Sopenharmony_ci bnx2fc_process_scsi_cmd_compl(io_req, task, num_rq, 89562306a36Sopenharmony_ci rq_data); 89662306a36Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 89762306a36Sopenharmony_ci return; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (rx_state == FCOE_TASK_RX_STATE_ABTS_COMPLETED) 90162306a36Sopenharmony_ci bnx2fc_process_abts_compl(io_req, task, num_rq); 90262306a36Sopenharmony_ci else if (rx_state == 90362306a36Sopenharmony_ci FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED) 90462306a36Sopenharmony_ci bnx2fc_process_cleanup_compl(io_req, task, num_rq); 90562306a36Sopenharmony_ci else 90662306a36Sopenharmony_ci printk(KERN_ERR PFX "Invalid rx state - %d\n", 90762306a36Sopenharmony_ci rx_state); 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci case BNX2FC_TASK_MGMT_CMD: 91162306a36Sopenharmony_ci BNX2FC_IO_DBG(io_req, "Processing TM complete\n"); 91262306a36Sopenharmony_ci bnx2fc_process_tm_compl(io_req, task, num_rq, rq_data); 91362306a36Sopenharmony_ci break; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci case BNX2FC_ABTS: 91662306a36Sopenharmony_ci /* 91762306a36Sopenharmony_ci * ABTS request received by firmware. ABTS response 91862306a36Sopenharmony_ci * will be delivered to the task belonging to the IO 91962306a36Sopenharmony_ci * that was aborted 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_ci BNX2FC_IO_DBG(io_req, "cq_compl- ABTS sent out by fw\n"); 92262306a36Sopenharmony_ci kref_put(&io_req->refcount, bnx2fc_cmd_release); 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci case BNX2FC_ELS: 92662306a36Sopenharmony_ci if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) 92762306a36Sopenharmony_ci bnx2fc_process_els_compl(io_req, task, num_rq); 92862306a36Sopenharmony_ci else if (rx_state == FCOE_TASK_RX_STATE_ABTS_COMPLETED) 92962306a36Sopenharmony_ci bnx2fc_process_abts_compl(io_req, task, num_rq); 93062306a36Sopenharmony_ci else if (rx_state == 93162306a36Sopenharmony_ci FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED) 93262306a36Sopenharmony_ci bnx2fc_process_cleanup_compl(io_req, task, num_rq); 93362306a36Sopenharmony_ci else 93462306a36Sopenharmony_ci printk(KERN_ERR PFX "Invalid rx state = %d\n", 93562306a36Sopenharmony_ci rx_state); 93662306a36Sopenharmony_ci break; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci case BNX2FC_CLEANUP: 93962306a36Sopenharmony_ci BNX2FC_IO_DBG(io_req, "cq_compl- cleanup resp rcvd\n"); 94062306a36Sopenharmony_ci kref_put(&io_req->refcount, bnx2fc_cmd_release); 94162306a36Sopenharmony_ci break; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci case BNX2FC_SEQ_CLEANUP: 94462306a36Sopenharmony_ci BNX2FC_IO_DBG(io_req, "cq_compl(0x%x) - seq cleanup resp\n", 94562306a36Sopenharmony_ci io_req->xid); 94662306a36Sopenharmony_ci bnx2fc_process_seq_cleanup_compl(io_req, task, rx_state); 94762306a36Sopenharmony_ci kref_put(&io_req->refcount, bnx2fc_cmd_release); 94862306a36Sopenharmony_ci break; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci default: 95162306a36Sopenharmony_ci printk(KERN_ERR PFX "Invalid cmd_type %d\n", cmd_type); 95262306a36Sopenharmony_ci break; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_civoid bnx2fc_arm_cq(struct bnx2fc_rport *tgt) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci struct b577xx_fcoe_rx_doorbell *rx_db = &tgt->rx_db; 96062306a36Sopenharmony_ci u32 msg; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci wmb(); 96362306a36Sopenharmony_ci rx_db->doorbell_cq_cons = tgt->cq_cons_idx | (tgt->cq_curr_toggle_bit << 96462306a36Sopenharmony_ci FCOE_CQE_TOGGLE_BIT_SHIFT); 96562306a36Sopenharmony_ci msg = *((u32 *)rx_db); 96662306a36Sopenharmony_ci writel(cpu_to_le32(msg), tgt->ctx_base); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cistatic struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe, 97162306a36Sopenharmony_ci unsigned char *rq_data, u8 num_rq, 97262306a36Sopenharmony_ci struct fcoe_task_ctx_entry *task) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci struct bnx2fc_work *work; 97562306a36Sopenharmony_ci work = kzalloc(sizeof(struct bnx2fc_work), GFP_ATOMIC); 97662306a36Sopenharmony_ci if (!work) 97762306a36Sopenharmony_ci return NULL; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci INIT_LIST_HEAD(&work->list); 98062306a36Sopenharmony_ci work->tgt = tgt; 98162306a36Sopenharmony_ci work->wqe = wqe; 98262306a36Sopenharmony_ci work->num_rq = num_rq; 98362306a36Sopenharmony_ci work->task = task; 98462306a36Sopenharmony_ci if (rq_data) 98562306a36Sopenharmony_ci memcpy(work->rq_data, rq_data, BNX2FC_RQ_BUF_SZ); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci return work; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/* Pending work request completion */ 99162306a36Sopenharmony_cistatic bool bnx2fc_pending_work(struct bnx2fc_rport *tgt, unsigned int wqe) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci unsigned int cpu = wqe % num_possible_cpus(); 99462306a36Sopenharmony_ci struct bnx2fc_percpu_s *fps; 99562306a36Sopenharmony_ci struct bnx2fc_work *work; 99662306a36Sopenharmony_ci struct fcoe_task_ctx_entry *task; 99762306a36Sopenharmony_ci struct fcoe_task_ctx_entry *task_page; 99862306a36Sopenharmony_ci struct fcoe_port *port = tgt->port; 99962306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 100062306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 100162306a36Sopenharmony_ci unsigned char *rq_data = NULL; 100262306a36Sopenharmony_ci unsigned char rq_data_buff[BNX2FC_RQ_BUF_SZ]; 100362306a36Sopenharmony_ci int task_idx, index; 100462306a36Sopenharmony_ci u16 xid; 100562306a36Sopenharmony_ci u8 num_rq; 100662306a36Sopenharmony_ci int i; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID; 100962306a36Sopenharmony_ci if (xid >= hba->max_tasks) { 101062306a36Sopenharmony_ci pr_err(PFX "ERROR:xid out of range\n"); 101162306a36Sopenharmony_ci return false; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci task_idx = xid / BNX2FC_TASKS_PER_PAGE; 101562306a36Sopenharmony_ci index = xid % BNX2FC_TASKS_PER_PAGE; 101662306a36Sopenharmony_ci task_page = (struct fcoe_task_ctx_entry *)hba->task_ctx[task_idx]; 101762306a36Sopenharmony_ci task = &task_page[index]; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci num_rq = ((task->rxwr_txrd.var_ctx.rx_flags & 102062306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE) >> 102162306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci memset(rq_data_buff, 0, BNX2FC_RQ_BUF_SZ); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (!num_rq) 102662306a36Sopenharmony_ci goto num_rq_zero; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci rq_data = bnx2fc_get_next_rqe(tgt, 1); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (num_rq > 1) { 103162306a36Sopenharmony_ci /* We do not need extra sense data */ 103262306a36Sopenharmony_ci for (i = 1; i < num_rq; i++) 103362306a36Sopenharmony_ci bnx2fc_get_next_rqe(tgt, 1); 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if (rq_data) 103762306a36Sopenharmony_ci memcpy(rq_data_buff, rq_data, BNX2FC_RQ_BUF_SZ); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* return RQ entries */ 104062306a36Sopenharmony_ci for (i = 0; i < num_rq; i++) 104162306a36Sopenharmony_ci bnx2fc_return_rqe(tgt, 1); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cinum_rq_zero: 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci fps = &per_cpu(bnx2fc_percpu, cpu); 104662306a36Sopenharmony_ci spin_lock_bh(&fps->fp_work_lock); 104762306a36Sopenharmony_ci if (fps->iothread) { 104862306a36Sopenharmony_ci work = bnx2fc_alloc_work(tgt, wqe, rq_data_buff, 104962306a36Sopenharmony_ci num_rq, task); 105062306a36Sopenharmony_ci if (work) { 105162306a36Sopenharmony_ci list_add_tail(&work->list, &fps->work_list); 105262306a36Sopenharmony_ci wake_up_process(fps->iothread); 105362306a36Sopenharmony_ci spin_unlock_bh(&fps->fp_work_lock); 105462306a36Sopenharmony_ci return true; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci spin_unlock_bh(&fps->fp_work_lock); 105862306a36Sopenharmony_ci bnx2fc_process_cq_compl(tgt, wqe, 105962306a36Sopenharmony_ci rq_data_buff, num_rq, task); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci return true; 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ciint bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci struct fcoe_cqe *cq; 106762306a36Sopenharmony_ci u32 cq_cons; 106862306a36Sopenharmony_ci struct fcoe_cqe *cqe; 106962306a36Sopenharmony_ci u32 num_free_sqes = 0; 107062306a36Sopenharmony_ci u32 num_cqes = 0; 107162306a36Sopenharmony_ci u16 wqe; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* 107462306a36Sopenharmony_ci * cq_lock is a low contention lock used to protect 107562306a36Sopenharmony_ci * the CQ data structure from being freed up during 107662306a36Sopenharmony_ci * the upload operation 107762306a36Sopenharmony_ci */ 107862306a36Sopenharmony_ci spin_lock_bh(&tgt->cq_lock); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (!tgt->cq) { 108162306a36Sopenharmony_ci printk(KERN_ERR PFX "process_new_cqes: cq is NULL\n"); 108262306a36Sopenharmony_ci spin_unlock_bh(&tgt->cq_lock); 108362306a36Sopenharmony_ci return 0; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci cq = tgt->cq; 108662306a36Sopenharmony_ci cq_cons = tgt->cq_cons_idx; 108762306a36Sopenharmony_ci cqe = &cq[cq_cons]; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci while (((wqe = cqe->wqe) & FCOE_CQE_TOGGLE_BIT) == 109062306a36Sopenharmony_ci (tgt->cq_curr_toggle_bit << 109162306a36Sopenharmony_ci FCOE_CQE_TOGGLE_BIT_SHIFT)) { 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci /* new entry on the cq */ 109462306a36Sopenharmony_ci if (wqe & FCOE_CQE_CQE_TYPE) { 109562306a36Sopenharmony_ci /* Unsolicited event notification */ 109662306a36Sopenharmony_ci bnx2fc_process_unsol_compl(tgt, wqe); 109762306a36Sopenharmony_ci } else { 109862306a36Sopenharmony_ci if (bnx2fc_pending_work(tgt, wqe)) 109962306a36Sopenharmony_ci num_free_sqes++; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci cqe++; 110262306a36Sopenharmony_ci tgt->cq_cons_idx++; 110362306a36Sopenharmony_ci num_cqes++; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) { 110662306a36Sopenharmony_ci tgt->cq_cons_idx = 0; 110762306a36Sopenharmony_ci cqe = cq; 110862306a36Sopenharmony_ci tgt->cq_curr_toggle_bit = 110962306a36Sopenharmony_ci 1 - tgt->cq_curr_toggle_bit; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci if (num_cqes) { 111362306a36Sopenharmony_ci /* Arm CQ only if doorbell is mapped */ 111462306a36Sopenharmony_ci if (tgt->ctx_base) 111562306a36Sopenharmony_ci bnx2fc_arm_cq(tgt); 111662306a36Sopenharmony_ci atomic_add(num_free_sqes, &tgt->free_sqes); 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci spin_unlock_bh(&tgt->cq_lock); 111962306a36Sopenharmony_ci return 0; 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci/** 112362306a36Sopenharmony_ci * bnx2fc_fastpath_notification - process global event queue (KCQ) 112462306a36Sopenharmony_ci * 112562306a36Sopenharmony_ci * @hba: adapter structure pointer 112662306a36Sopenharmony_ci * @new_cqe_kcqe: pointer to newly DMA'd KCQ entry 112762306a36Sopenharmony_ci * 112862306a36Sopenharmony_ci * Fast path event notification handler 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_cistatic void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba, 113162306a36Sopenharmony_ci struct fcoe_kcqe *new_cqe_kcqe) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci u32 conn_id = new_cqe_kcqe->fcoe_conn_id; 113462306a36Sopenharmony_ci struct bnx2fc_rport *tgt = hba->tgt_ofld_list[conn_id]; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if (!tgt) { 113762306a36Sopenharmony_ci printk(KERN_ERR PFX "conn_id 0x%x not valid\n", conn_id); 113862306a36Sopenharmony_ci return; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci bnx2fc_process_new_cqes(tgt); 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci/** 114562306a36Sopenharmony_ci * bnx2fc_process_ofld_cmpl - process FCoE session offload completion 114662306a36Sopenharmony_ci * 114762306a36Sopenharmony_ci * @hba: adapter structure pointer 114862306a36Sopenharmony_ci * @ofld_kcqe: connection offload kcqe pointer 114962306a36Sopenharmony_ci * 115062306a36Sopenharmony_ci * handle session offload completion, enable the session if offload is 115162306a36Sopenharmony_ci * successful. 115262306a36Sopenharmony_ci */ 115362306a36Sopenharmony_cistatic void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, 115462306a36Sopenharmony_ci struct fcoe_kcqe *ofld_kcqe) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci struct bnx2fc_rport *tgt; 115762306a36Sopenharmony_ci struct bnx2fc_interface *interface; 115862306a36Sopenharmony_ci u32 conn_id; 115962306a36Sopenharmony_ci u32 context_id; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci conn_id = ofld_kcqe->fcoe_conn_id; 116262306a36Sopenharmony_ci context_id = ofld_kcqe->fcoe_conn_context_id; 116362306a36Sopenharmony_ci tgt = hba->tgt_ofld_list[conn_id]; 116462306a36Sopenharmony_ci if (!tgt) { 116562306a36Sopenharmony_ci printk(KERN_ALERT PFX "ERROR:ofld_cmpl: No pending ofld req\n"); 116662306a36Sopenharmony_ci return; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Entered ofld compl - context_id = 0x%x\n", 116962306a36Sopenharmony_ci ofld_kcqe->fcoe_conn_context_id); 117062306a36Sopenharmony_ci interface = tgt->port->priv; 117162306a36Sopenharmony_ci if (hba != interface->hba) { 117262306a36Sopenharmony_ci printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mismatch\n"); 117362306a36Sopenharmony_ci goto ofld_cmpl_err; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci /* 117662306a36Sopenharmony_ci * cnic has allocated a context_id for this session; use this 117762306a36Sopenharmony_ci * while enabling the session. 117862306a36Sopenharmony_ci */ 117962306a36Sopenharmony_ci tgt->context_id = context_id; 118062306a36Sopenharmony_ci if (ofld_kcqe->completion_status) { 118162306a36Sopenharmony_ci if (ofld_kcqe->completion_status == 118262306a36Sopenharmony_ci FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE) { 118362306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate FCoE context " 118462306a36Sopenharmony_ci "resources\n"); 118562306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_CTX_ALLOC_FAILURE, &tgt->flags); 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci } else { 118862306a36Sopenharmony_ci /* FW offload request successfully completed */ 118962306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ciofld_cmpl_err: 119262306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); 119362306a36Sopenharmony_ci wake_up_interruptible(&tgt->ofld_wait); 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci/** 119762306a36Sopenharmony_ci * bnx2fc_process_enable_conn_cmpl - process FCoE session enable completion 119862306a36Sopenharmony_ci * 119962306a36Sopenharmony_ci * @hba: adapter structure pointer 120062306a36Sopenharmony_ci * @ofld_kcqe: connection offload kcqe pointer 120162306a36Sopenharmony_ci * 120262306a36Sopenharmony_ci * handle session enable completion, mark the rport as ready 120362306a36Sopenharmony_ci */ 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_cistatic void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, 120662306a36Sopenharmony_ci struct fcoe_kcqe *ofld_kcqe) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci struct bnx2fc_rport *tgt; 120962306a36Sopenharmony_ci struct bnx2fc_interface *interface; 121062306a36Sopenharmony_ci u32 conn_id; 121162306a36Sopenharmony_ci u32 context_id; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci context_id = ofld_kcqe->fcoe_conn_context_id; 121462306a36Sopenharmony_ci conn_id = ofld_kcqe->fcoe_conn_id; 121562306a36Sopenharmony_ci tgt = hba->tgt_ofld_list[conn_id]; 121662306a36Sopenharmony_ci if (!tgt) { 121762306a36Sopenharmony_ci printk(KERN_ERR PFX "ERROR:enbl_cmpl: No pending ofld req\n"); 121862306a36Sopenharmony_ci return; 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Enable compl - context_id = 0x%x\n", 122262306a36Sopenharmony_ci ofld_kcqe->fcoe_conn_context_id); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci /* 122562306a36Sopenharmony_ci * context_id should be the same for this target during offload 122662306a36Sopenharmony_ci * and enable 122762306a36Sopenharmony_ci */ 122862306a36Sopenharmony_ci if (tgt->context_id != context_id) { 122962306a36Sopenharmony_ci printk(KERN_ERR PFX "context id mismatch\n"); 123062306a36Sopenharmony_ci return; 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci interface = tgt->port->priv; 123362306a36Sopenharmony_ci if (hba != interface->hba) { 123462306a36Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mismatch\n"); 123562306a36Sopenharmony_ci goto enbl_cmpl_err; 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci if (!ofld_kcqe->completion_status) 123862306a36Sopenharmony_ci /* enable successful - rport ready for issuing IOs */ 123962306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_ENABLED, &tgt->flags); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_cienbl_cmpl_err: 124262306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); 124362306a36Sopenharmony_ci wake_up_interruptible(&tgt->ofld_wait); 124462306a36Sopenharmony_ci} 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_cistatic void bnx2fc_process_conn_disable_cmpl(struct bnx2fc_hba *hba, 124762306a36Sopenharmony_ci struct fcoe_kcqe *disable_kcqe) 124862306a36Sopenharmony_ci{ 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci struct bnx2fc_rport *tgt; 125162306a36Sopenharmony_ci u32 conn_id; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci conn_id = disable_kcqe->fcoe_conn_id; 125462306a36Sopenharmony_ci tgt = hba->tgt_ofld_list[conn_id]; 125562306a36Sopenharmony_ci if (!tgt) { 125662306a36Sopenharmony_ci printk(KERN_ERR PFX "ERROR: disable_cmpl: No disable req\n"); 125762306a36Sopenharmony_ci return; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, PFX "disable_cmpl: conn_id %d\n", conn_id); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (disable_kcqe->completion_status) { 126362306a36Sopenharmony_ci printk(KERN_ERR PFX "Disable failed with cmpl status %d\n", 126462306a36Sopenharmony_ci disable_kcqe->completion_status); 126562306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags); 126662306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); 126762306a36Sopenharmony_ci wake_up_interruptible(&tgt->upld_wait); 126862306a36Sopenharmony_ci } else { 126962306a36Sopenharmony_ci /* disable successful */ 127062306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "disable successful\n"); 127162306a36Sopenharmony_ci clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); 127262306a36Sopenharmony_ci clear_bit(BNX2FC_FLAG_ENABLED, &tgt->flags); 127362306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_DISABLED, &tgt->flags); 127462306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); 127562306a36Sopenharmony_ci wake_up_interruptible(&tgt->upld_wait); 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci} 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_cistatic void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba, 128062306a36Sopenharmony_ci struct fcoe_kcqe *destroy_kcqe) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci struct bnx2fc_rport *tgt; 128362306a36Sopenharmony_ci u32 conn_id; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci conn_id = destroy_kcqe->fcoe_conn_id; 128662306a36Sopenharmony_ci tgt = hba->tgt_ofld_list[conn_id]; 128762306a36Sopenharmony_ci if (!tgt) { 128862306a36Sopenharmony_ci printk(KERN_ERR PFX "destroy_cmpl: No destroy req\n"); 128962306a36Sopenharmony_ci return; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "destroy_cmpl: conn_id %d\n", conn_id); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (destroy_kcqe->completion_status) { 129562306a36Sopenharmony_ci printk(KERN_ERR PFX "Destroy conn failed, cmpl status %d\n", 129662306a36Sopenharmony_ci destroy_kcqe->completion_status); 129762306a36Sopenharmony_ci return; 129862306a36Sopenharmony_ci } else { 129962306a36Sopenharmony_ci /* destroy successful */ 130062306a36Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "upload successful\n"); 130162306a36Sopenharmony_ci clear_bit(BNX2FC_FLAG_DISABLED, &tgt->flags); 130262306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_DESTROYED, &tgt->flags); 130362306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); 130462306a36Sopenharmony_ci wake_up_interruptible(&tgt->upld_wait); 130562306a36Sopenharmony_ci } 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci switch (err_code) { 131162306a36Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_INVALID_OPCODE: 131262306a36Sopenharmony_ci printk(KERN_ERR PFX "init_failure due to invalid opcode\n"); 131362306a36Sopenharmony_ci break; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE: 131662306a36Sopenharmony_ci printk(KERN_ERR PFX "init failed due to ctx alloc failure\n"); 131762306a36Sopenharmony_ci break; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR: 132062306a36Sopenharmony_ci printk(KERN_ERR PFX "init_failure due to NIC error\n"); 132162306a36Sopenharmony_ci break; 132262306a36Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_ERROR: 132362306a36Sopenharmony_ci printk(KERN_ERR PFX "init failure due to compl status err\n"); 132462306a36Sopenharmony_ci break; 132562306a36Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION: 132662306a36Sopenharmony_ci printk(KERN_ERR PFX "init failure due to HSI mismatch\n"); 132762306a36Sopenharmony_ci break; 132862306a36Sopenharmony_ci default: 132962306a36Sopenharmony_ci printk(KERN_ERR PFX "Unknown Error code %d\n", err_code); 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci/** 133462306a36Sopenharmony_ci * bnx2fc_indicate_kcqe() - process KCQE 133562306a36Sopenharmony_ci * 133662306a36Sopenharmony_ci * @context: adapter structure pointer 133762306a36Sopenharmony_ci * @kcq: kcqe pointer 133862306a36Sopenharmony_ci * @num_cqe: Number of completion queue elements 133962306a36Sopenharmony_ci * 134062306a36Sopenharmony_ci * Generic KCQ event handler 134162306a36Sopenharmony_ci */ 134262306a36Sopenharmony_civoid bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[], 134362306a36Sopenharmony_ci u32 num_cqe) 134462306a36Sopenharmony_ci{ 134562306a36Sopenharmony_ci struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context; 134662306a36Sopenharmony_ci int i = 0; 134762306a36Sopenharmony_ci struct fcoe_kcqe *kcqe = NULL; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci while (i < num_cqe) { 135062306a36Sopenharmony_ci kcqe = (struct fcoe_kcqe *) kcq[i++]; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci switch (kcqe->op_code) { 135362306a36Sopenharmony_ci case FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION: 135462306a36Sopenharmony_ci bnx2fc_fastpath_notification(hba, kcqe); 135562306a36Sopenharmony_ci break; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci case FCOE_KCQE_OPCODE_OFFLOAD_CONN: 135862306a36Sopenharmony_ci bnx2fc_process_ofld_cmpl(hba, kcqe); 135962306a36Sopenharmony_ci break; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci case FCOE_KCQE_OPCODE_ENABLE_CONN: 136262306a36Sopenharmony_ci bnx2fc_process_enable_conn_cmpl(hba, kcqe); 136362306a36Sopenharmony_ci break; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci case FCOE_KCQE_OPCODE_INIT_FUNC: 136662306a36Sopenharmony_ci if (kcqe->completion_status != 136762306a36Sopenharmony_ci FCOE_KCQE_COMPLETION_STATUS_SUCCESS) { 136862306a36Sopenharmony_ci bnx2fc_init_failure(hba, 136962306a36Sopenharmony_ci kcqe->completion_status); 137062306a36Sopenharmony_ci } else { 137162306a36Sopenharmony_ci set_bit(ADAPTER_STATE_UP, &hba->adapter_state); 137262306a36Sopenharmony_ci bnx2fc_get_link_state(hba); 137362306a36Sopenharmony_ci printk(KERN_INFO PFX "[%.2x]: FCOE_INIT passed\n", 137462306a36Sopenharmony_ci (u8)hba->pcidev->bus->number); 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci break; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci case FCOE_KCQE_OPCODE_DESTROY_FUNC: 137962306a36Sopenharmony_ci if (kcqe->completion_status != 138062306a36Sopenharmony_ci FCOE_KCQE_COMPLETION_STATUS_SUCCESS) { 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci printk(KERN_ERR PFX "DESTROY failed\n"); 138362306a36Sopenharmony_ci } else { 138462306a36Sopenharmony_ci printk(KERN_ERR PFX "DESTROY success\n"); 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); 138762306a36Sopenharmony_ci wake_up_interruptible(&hba->destroy_wait); 138862306a36Sopenharmony_ci break; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci case FCOE_KCQE_OPCODE_DISABLE_CONN: 139162306a36Sopenharmony_ci bnx2fc_process_conn_disable_cmpl(hba, kcqe); 139262306a36Sopenharmony_ci break; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci case FCOE_KCQE_OPCODE_DESTROY_CONN: 139562306a36Sopenharmony_ci bnx2fc_process_conn_destroy_cmpl(hba, kcqe); 139662306a36Sopenharmony_ci break; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci case FCOE_KCQE_OPCODE_STAT_FUNC: 139962306a36Sopenharmony_ci if (kcqe->completion_status != 140062306a36Sopenharmony_ci FCOE_KCQE_COMPLETION_STATUS_SUCCESS) 140162306a36Sopenharmony_ci printk(KERN_ERR PFX "STAT failed\n"); 140262306a36Sopenharmony_ci complete(&hba->stat_req_done); 140362306a36Sopenharmony_ci break; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci case FCOE_KCQE_OPCODE_FCOE_ERROR: 140662306a36Sopenharmony_ci default: 140762306a36Sopenharmony_ci printk(KERN_ERR PFX "unknown opcode 0x%x\n", 140862306a36Sopenharmony_ci kcqe->op_code); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_civoid bnx2fc_add_2_sq(struct bnx2fc_rport *tgt, u16 xid) 141462306a36Sopenharmony_ci{ 141562306a36Sopenharmony_ci struct fcoe_sqe *sqe; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci sqe = &tgt->sq[tgt->sq_prod_idx]; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* Fill SQ WQE */ 142062306a36Sopenharmony_ci sqe->wqe = xid << FCOE_SQE_TASK_ID_SHIFT; 142162306a36Sopenharmony_ci sqe->wqe |= tgt->sq_curr_toggle_bit << FCOE_SQE_TOGGLE_BIT_SHIFT; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci /* Advance SQ Prod Idx */ 142462306a36Sopenharmony_ci if (++tgt->sq_prod_idx == BNX2FC_SQ_WQES_MAX) { 142562306a36Sopenharmony_ci tgt->sq_prod_idx = 0; 142662306a36Sopenharmony_ci tgt->sq_curr_toggle_bit = 1 - tgt->sq_curr_toggle_bit; 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_civoid bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt) 143162306a36Sopenharmony_ci{ 143262306a36Sopenharmony_ci struct b577xx_doorbell_set_prod *sq_db = &tgt->sq_db; 143362306a36Sopenharmony_ci u32 msg; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci wmb(); 143662306a36Sopenharmony_ci sq_db->prod = tgt->sq_prod_idx | 143762306a36Sopenharmony_ci (tgt->sq_curr_toggle_bit << 15); 143862306a36Sopenharmony_ci msg = *((u32 *)sq_db); 143962306a36Sopenharmony_ci writel(cpu_to_le32(msg), tgt->ctx_base); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci} 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ciint bnx2fc_map_doorbell(struct bnx2fc_rport *tgt) 144462306a36Sopenharmony_ci{ 144562306a36Sopenharmony_ci u32 context_id = tgt->context_id; 144662306a36Sopenharmony_ci struct fcoe_port *port = tgt->port; 144762306a36Sopenharmony_ci u32 reg_off; 144862306a36Sopenharmony_ci resource_size_t reg_base; 144962306a36Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 145062306a36Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci reg_base = pci_resource_start(hba->pcidev, 145362306a36Sopenharmony_ci BNX2X_DOORBELL_PCI_BAR); 145462306a36Sopenharmony_ci reg_off = (1 << BNX2X_DB_SHIFT) * (context_id & 0x1FFFF); 145562306a36Sopenharmony_ci tgt->ctx_base = ioremap(reg_base + reg_off, 4); 145662306a36Sopenharmony_ci if (!tgt->ctx_base) 145762306a36Sopenharmony_ci return -ENOMEM; 145862306a36Sopenharmony_ci return 0; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cichar *bnx2fc_get_next_rqe(struct bnx2fc_rport *tgt, u8 num_items) 146262306a36Sopenharmony_ci{ 146362306a36Sopenharmony_ci char *buf = (char *)tgt->rq + (tgt->rq_cons_idx * BNX2FC_RQ_BUF_SZ); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (tgt->rq_cons_idx + num_items > BNX2FC_RQ_WQES_MAX) 146662306a36Sopenharmony_ci return NULL; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci tgt->rq_cons_idx += num_items; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci if (tgt->rq_cons_idx >= BNX2FC_RQ_WQES_MAX) 147162306a36Sopenharmony_ci tgt->rq_cons_idx -= BNX2FC_RQ_WQES_MAX; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci return buf; 147462306a36Sopenharmony_ci} 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_civoid bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci /* return the rq buffer */ 147962306a36Sopenharmony_ci u32 next_prod_idx = tgt->rq_prod_idx + num_items; 148062306a36Sopenharmony_ci if ((next_prod_idx & 0x7fff) == BNX2FC_RQ_WQES_MAX) { 148162306a36Sopenharmony_ci /* Wrap around RQ */ 148262306a36Sopenharmony_ci next_prod_idx += 0x8000 - BNX2FC_RQ_WQES_MAX; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci tgt->rq_prod_idx = next_prod_idx; 148562306a36Sopenharmony_ci tgt->conn_db->rq_prod = tgt->rq_prod_idx; 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_civoid bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnp_req, 148962306a36Sopenharmony_ci struct fcoe_task_ctx_entry *task, 149062306a36Sopenharmony_ci struct bnx2fc_cmd *orig_io_req, 149162306a36Sopenharmony_ci u32 offset) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci struct scsi_cmnd *sc_cmd = orig_io_req->sc_cmd; 149462306a36Sopenharmony_ci struct bnx2fc_rport *tgt = seq_clnp_req->tgt; 149562306a36Sopenharmony_ci struct fcoe_bd_ctx *bd = orig_io_req->bd_tbl->bd_tbl; 149662306a36Sopenharmony_ci struct fcoe_ext_mul_sges_ctx *sgl; 149762306a36Sopenharmony_ci u8 task_type = FCOE_TASK_TYPE_SEQUENCE_CLEANUP; 149862306a36Sopenharmony_ci u8 orig_task_type; 149962306a36Sopenharmony_ci u16 orig_xid = orig_io_req->xid; 150062306a36Sopenharmony_ci u32 context_id = tgt->context_id; 150162306a36Sopenharmony_ci u64 phys_addr = (u64)orig_io_req->bd_tbl->bd_tbl_dma; 150262306a36Sopenharmony_ci u32 orig_offset = offset; 150362306a36Sopenharmony_ci int bd_count; 150462306a36Sopenharmony_ci int i; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) 150962306a36Sopenharmony_ci orig_task_type = FCOE_TASK_TYPE_WRITE; 151062306a36Sopenharmony_ci else 151162306a36Sopenharmony_ci orig_task_type = FCOE_TASK_TYPE_READ; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci /* Tx flags */ 151462306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.tx_flags = 151562306a36Sopenharmony_ci FCOE_TASK_TX_STATE_SEQUENCE_CLEANUP << 151662306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; 151762306a36Sopenharmony_ci /* init flags */ 151862306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags = task_type << 151962306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; 152062306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << 152162306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; 152262306a36Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 152362306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 152462306a36Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 152562306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_seq_cnt = 0; 153062306a36Sopenharmony_ci task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_data_offset = offset; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci bd_count = orig_io_req->bd_tbl->bd_valid; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* obtain the appropriate bd entry from relative offset */ 153562306a36Sopenharmony_ci for (i = 0; i < bd_count; i++) { 153662306a36Sopenharmony_ci if (offset < bd[i].buf_len) 153762306a36Sopenharmony_ci break; 153862306a36Sopenharmony_ci offset -= bd[i].buf_len; 153962306a36Sopenharmony_ci } 154062306a36Sopenharmony_ci phys_addr += (i * sizeof(struct fcoe_bd_ctx)); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci if (orig_task_type == FCOE_TASK_TYPE_WRITE) { 154362306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = 154462306a36Sopenharmony_ci (u32)phys_addr; 154562306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = 154662306a36Sopenharmony_ci (u32)((u64)phys_addr >> 32); 154762306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = 154862306a36Sopenharmony_ci bd_count; 154962306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_off = 155062306a36Sopenharmony_ci offset; /* adjusted offset */ 155162306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_idx = i; 155262306a36Sopenharmony_ci } else { 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci /* Multiple SGEs were used for this IO */ 155562306a36Sopenharmony_ci sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; 155662306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.lo = (u32)phys_addr; 155762306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.hi = (u32)((u64)phys_addr >> 32); 155862306a36Sopenharmony_ci sgl->mul_sgl.sgl_size = bd_count; 155962306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_off = offset; /*adjusted offset */ 156062306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_idx = i; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci memset(&task->rxwr_only.rx_seq_ctx, 0, 156362306a36Sopenharmony_ci sizeof(struct fcoe_rx_seq_ctx)); 156462306a36Sopenharmony_ci task->rxwr_only.rx_seq_ctx.low_exp_ro = orig_offset; 156562306a36Sopenharmony_ci task->rxwr_only.rx_seq_ctx.high_exp_ro = orig_offset; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_civoid bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req, 156962306a36Sopenharmony_ci struct fcoe_task_ctx_entry *task, 157062306a36Sopenharmony_ci u16 orig_xid) 157162306a36Sopenharmony_ci{ 157262306a36Sopenharmony_ci u8 task_type = FCOE_TASK_TYPE_EXCHANGE_CLEANUP; 157362306a36Sopenharmony_ci struct bnx2fc_rport *tgt = io_req->tgt; 157462306a36Sopenharmony_ci u32 context_id = tgt->context_id; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci /* Tx Write Rx Read */ 157962306a36Sopenharmony_ci /* init flags */ 158062306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags = task_type << 158162306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; 158262306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << 158362306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; 158462306a36Sopenharmony_ci if (tgt->dev_type == TYPE_TAPE) 158562306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 158662306a36Sopenharmony_ci FCOE_TASK_DEV_TYPE_TAPE << 158762306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 158862306a36Sopenharmony_ci else 158962306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 159062306a36Sopenharmony_ci FCOE_TASK_DEV_TYPE_DISK << 159162306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 159262306a36Sopenharmony_ci task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci /* Tx flags */ 159562306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.tx_flags = 159662306a36Sopenharmony_ci FCOE_TASK_TX_STATE_EXCHANGE_CLEANUP << 159762306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci /* Rx Read Tx Write */ 160062306a36Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 160162306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 160262306a36Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_flags |= 1 << 160362306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT; 160462306a36Sopenharmony_ci} 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_civoid bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req, 160762306a36Sopenharmony_ci struct fcoe_task_ctx_entry *task) 160862306a36Sopenharmony_ci{ 160962306a36Sopenharmony_ci struct bnx2fc_mp_req *mp_req = &(io_req->mp_req); 161062306a36Sopenharmony_ci struct bnx2fc_rport *tgt = io_req->tgt; 161162306a36Sopenharmony_ci struct fc_frame_header *fc_hdr; 161262306a36Sopenharmony_ci struct fcoe_ext_mul_sges_ctx *sgl; 161362306a36Sopenharmony_ci u8 task_type = 0; 161462306a36Sopenharmony_ci u64 *hdr; 161562306a36Sopenharmony_ci u64 temp_hdr[3]; 161662306a36Sopenharmony_ci u32 context_id; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci /* Obtain task_type */ 162062306a36Sopenharmony_ci if ((io_req->cmd_type == BNX2FC_TASK_MGMT_CMD) || 162162306a36Sopenharmony_ci (io_req->cmd_type == BNX2FC_ELS)) { 162262306a36Sopenharmony_ci task_type = FCOE_TASK_TYPE_MIDPATH; 162362306a36Sopenharmony_ci } else if (io_req->cmd_type == BNX2FC_ABTS) { 162462306a36Sopenharmony_ci task_type = FCOE_TASK_TYPE_ABTS; 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci /* Setup the task from io_req for easy reference */ 163062306a36Sopenharmony_ci io_req->task = task; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci BNX2FC_IO_DBG(io_req, "Init MP task for cmd_type = %d task_type = %d\n", 163362306a36Sopenharmony_ci io_req->cmd_type, task_type); 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci /* Tx only */ 163662306a36Sopenharmony_ci if ((task_type == FCOE_TASK_TYPE_MIDPATH) || 163762306a36Sopenharmony_ci (task_type == FCOE_TASK_TYPE_UNSOLICITED)) { 163862306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = 163962306a36Sopenharmony_ci (u32)mp_req->mp_req_bd_dma; 164062306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = 164162306a36Sopenharmony_ci (u32)((u64)mp_req->mp_req_bd_dma >> 32); 164262306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = 1; 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* Tx Write Rx Read */ 164662306a36Sopenharmony_ci /* init flags */ 164762306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags = task_type << 164862306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; 164962306a36Sopenharmony_ci if (tgt->dev_type == TYPE_TAPE) 165062306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 165162306a36Sopenharmony_ci FCOE_TASK_DEV_TYPE_TAPE << 165262306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 165362306a36Sopenharmony_ci else 165462306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 165562306a36Sopenharmony_ci FCOE_TASK_DEV_TYPE_DISK << 165662306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 165762306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << 165862306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci /* tx flags */ 166162306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.tx_flags = FCOE_TASK_TX_STATE_INIT << 166262306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci /* Rx Write Tx Read */ 166562306a36Sopenharmony_ci task->rxwr_txrd.const_ctx.data_2_trns = io_req->data_xfer_len; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci /* rx flags */ 166862306a36Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_flags |= 1 << 166962306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci context_id = tgt->context_id; 167262306a36Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 167362306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci fc_hdr = &(mp_req->req_fc_hdr); 167662306a36Sopenharmony_ci if (task_type == FCOE_TASK_TYPE_MIDPATH) { 167762306a36Sopenharmony_ci fc_hdr->fh_ox_id = cpu_to_be16(io_req->xid); 167862306a36Sopenharmony_ci fc_hdr->fh_rx_id = htons(0xffff); 167962306a36Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_id = 0xffff; 168062306a36Sopenharmony_ci } else if (task_type == FCOE_TASK_TYPE_UNSOLICITED) { 168162306a36Sopenharmony_ci fc_hdr->fh_rx_id = cpu_to_be16(io_req->xid); 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci /* Fill FC Header into middle path buffer */ 168562306a36Sopenharmony_ci hdr = (u64 *) &task->txwr_rxrd.union_ctx.tx_frame.fc_hdr; 168662306a36Sopenharmony_ci memcpy(temp_hdr, fc_hdr, sizeof(temp_hdr)); 168762306a36Sopenharmony_ci hdr[0] = cpu_to_be64(temp_hdr[0]); 168862306a36Sopenharmony_ci hdr[1] = cpu_to_be64(temp_hdr[1]); 168962306a36Sopenharmony_ci hdr[2] = cpu_to_be64(temp_hdr[2]); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci /* Rx Only */ 169262306a36Sopenharmony_ci if (task_type == FCOE_TASK_TYPE_MIDPATH) { 169362306a36Sopenharmony_ci sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.lo = (u32)mp_req->mp_resp_bd_dma; 169662306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.hi = 169762306a36Sopenharmony_ci (u32)((u64)mp_req->mp_resp_bd_dma >> 32); 169862306a36Sopenharmony_ci sgl->mul_sgl.sgl_size = 1; 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci} 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_civoid bnx2fc_init_task(struct bnx2fc_cmd *io_req, 170362306a36Sopenharmony_ci struct fcoe_task_ctx_entry *task) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci u8 task_type; 170662306a36Sopenharmony_ci struct scsi_cmnd *sc_cmd = io_req->sc_cmd; 170762306a36Sopenharmony_ci struct io_bdt *bd_tbl = io_req->bd_tbl; 170862306a36Sopenharmony_ci struct bnx2fc_rport *tgt = io_req->tgt; 170962306a36Sopenharmony_ci struct fcoe_cached_sge_ctx *cached_sge; 171062306a36Sopenharmony_ci struct fcoe_ext_mul_sges_ctx *sgl; 171162306a36Sopenharmony_ci int dev_type = tgt->dev_type; 171262306a36Sopenharmony_ci u64 *fcp_cmnd; 171362306a36Sopenharmony_ci u64 tmp_fcp_cmnd[4]; 171462306a36Sopenharmony_ci u32 context_id; 171562306a36Sopenharmony_ci int cnt, i; 171662306a36Sopenharmony_ci int bd_count; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci /* Setup the task from io_req for easy reference */ 172162306a36Sopenharmony_ci io_req->task = task; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) 172462306a36Sopenharmony_ci task_type = FCOE_TASK_TYPE_WRITE; 172562306a36Sopenharmony_ci else 172662306a36Sopenharmony_ci task_type = FCOE_TASK_TYPE_READ; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci /* Tx only */ 172962306a36Sopenharmony_ci bd_count = bd_tbl->bd_valid; 173062306a36Sopenharmony_ci cached_sge = &task->rxwr_only.union_ctx.read_info.sgl_ctx.cached_sge; 173162306a36Sopenharmony_ci if (task_type == FCOE_TASK_TYPE_WRITE) { 173262306a36Sopenharmony_ci if ((dev_type == TYPE_DISK) && (bd_count == 1)) { 173362306a36Sopenharmony_ci struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.lo = 173662306a36Sopenharmony_ci cached_sge->cur_buf_addr.lo = 173762306a36Sopenharmony_ci fcoe_bd_tbl->buf_addr_lo; 173862306a36Sopenharmony_ci task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.hi = 173962306a36Sopenharmony_ci cached_sge->cur_buf_addr.hi = 174062306a36Sopenharmony_ci fcoe_bd_tbl->buf_addr_hi; 174162306a36Sopenharmony_ci task->txwr_only.sgl_ctx.cached_sge.cur_buf_rem = 174262306a36Sopenharmony_ci cached_sge->cur_buf_rem = 174362306a36Sopenharmony_ci fcoe_bd_tbl->buf_len; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 1 << 174662306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; 174762306a36Sopenharmony_ci } else { 174862306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = 174962306a36Sopenharmony_ci (u32)bd_tbl->bd_tbl_dma; 175062306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = 175162306a36Sopenharmony_ci (u32)((u64)bd_tbl->bd_tbl_dma >> 32); 175262306a36Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = 175362306a36Sopenharmony_ci bd_tbl->bd_valid; 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci /*Tx Write Rx Read */ 175862306a36Sopenharmony_ci /* Init state to NORMAL */ 175962306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= task_type << 176062306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; 176162306a36Sopenharmony_ci if (dev_type == TYPE_TAPE) { 176262306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 176362306a36Sopenharmony_ci FCOE_TASK_DEV_TYPE_TAPE << 176462306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 176562306a36Sopenharmony_ci io_req->rec_retry = 0; 176662306a36Sopenharmony_ci io_req->rec_retry = 0; 176762306a36Sopenharmony_ci } else 176862306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 176962306a36Sopenharmony_ci FCOE_TASK_DEV_TYPE_DISK << 177062306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 177162306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << 177262306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; 177362306a36Sopenharmony_ci /* tx flags */ 177462306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.tx_flags = FCOE_TASK_TX_STATE_NORMAL << 177562306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci /* Set initial seq counter */ 177862306a36Sopenharmony_ci task->txwr_rxrd.union_ctx.tx_seq.ctx.seq_cnt = 1; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci /* Fill FCP_CMND IU */ 178162306a36Sopenharmony_ci fcp_cmnd = (u64 *) 178262306a36Sopenharmony_ci task->txwr_rxrd.union_ctx.fcp_cmd.opaque; 178362306a36Sopenharmony_ci bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)&tmp_fcp_cmnd); 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci /* swap fcp_cmnd */ 178662306a36Sopenharmony_ci cnt = sizeof(struct fcp_cmnd) / sizeof(u64); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 178962306a36Sopenharmony_ci *fcp_cmnd = cpu_to_be64(tmp_fcp_cmnd[i]); 179062306a36Sopenharmony_ci fcp_cmnd++; 179162306a36Sopenharmony_ci } 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci /* Rx Write Tx Read */ 179462306a36Sopenharmony_ci task->rxwr_txrd.const_ctx.data_2_trns = io_req->data_xfer_len; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci context_id = tgt->context_id; 179762306a36Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 179862306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci /* rx flags */ 180162306a36Sopenharmony_ci /* Set state to "waiting for the first packet" */ 180262306a36Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_flags |= 1 << 180362306a36Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_id = 0xffff; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci /* Rx Only */ 180862306a36Sopenharmony_ci if (task_type != FCOE_TASK_TYPE_READ) 180962306a36Sopenharmony_ci return; 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; 181262306a36Sopenharmony_ci bd_count = bd_tbl->bd_valid; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci if (dev_type == TYPE_DISK) { 181562306a36Sopenharmony_ci if (bd_count == 1) { 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci cached_sge->cur_buf_addr.lo = fcoe_bd_tbl->buf_addr_lo; 182062306a36Sopenharmony_ci cached_sge->cur_buf_addr.hi = fcoe_bd_tbl->buf_addr_hi; 182162306a36Sopenharmony_ci cached_sge->cur_buf_rem = fcoe_bd_tbl->buf_len; 182262306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 1 << 182362306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; 182462306a36Sopenharmony_ci } else if (bd_count == 2) { 182562306a36Sopenharmony_ci struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci cached_sge->cur_buf_addr.lo = fcoe_bd_tbl->buf_addr_lo; 182862306a36Sopenharmony_ci cached_sge->cur_buf_addr.hi = fcoe_bd_tbl->buf_addr_hi; 182962306a36Sopenharmony_ci cached_sge->cur_buf_rem = fcoe_bd_tbl->buf_len; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci fcoe_bd_tbl++; 183262306a36Sopenharmony_ci cached_sge->second_buf_addr.lo = 183362306a36Sopenharmony_ci fcoe_bd_tbl->buf_addr_lo; 183462306a36Sopenharmony_ci cached_sge->second_buf_addr.hi = 183562306a36Sopenharmony_ci fcoe_bd_tbl->buf_addr_hi; 183662306a36Sopenharmony_ci cached_sge->second_buf_rem = fcoe_bd_tbl->buf_len; 183762306a36Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 1 << 183862306a36Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; 183962306a36Sopenharmony_ci } else { 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma; 184262306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.hi = 184362306a36Sopenharmony_ci (u32)((u64)bd_tbl->bd_tbl_dma >> 32); 184462306a36Sopenharmony_ci sgl->mul_sgl.sgl_size = bd_count; 184562306a36Sopenharmony_ci } 184662306a36Sopenharmony_ci } else { 184762306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma; 184862306a36Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.hi = 184962306a36Sopenharmony_ci (u32)((u64)bd_tbl->bd_tbl_dma >> 32); 185062306a36Sopenharmony_ci sgl->mul_sgl.sgl_size = bd_count; 185162306a36Sopenharmony_ci } 185262306a36Sopenharmony_ci} 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci/** 185562306a36Sopenharmony_ci * bnx2fc_setup_task_ctx - allocate and map task context 185662306a36Sopenharmony_ci * 185762306a36Sopenharmony_ci * @hba: pointer to adapter structure 185862306a36Sopenharmony_ci * 185962306a36Sopenharmony_ci * allocate memory for task context, and associated BD table to be used 186062306a36Sopenharmony_ci * by firmware 186162306a36Sopenharmony_ci * 186262306a36Sopenharmony_ci */ 186362306a36Sopenharmony_ciint bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba) 186462306a36Sopenharmony_ci{ 186562306a36Sopenharmony_ci int rc = 0; 186662306a36Sopenharmony_ci struct regpair *task_ctx_bdt; 186762306a36Sopenharmony_ci dma_addr_t addr; 186862306a36Sopenharmony_ci int task_ctx_arr_sz; 186962306a36Sopenharmony_ci int i; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci /* 187262306a36Sopenharmony_ci * Allocate task context bd table. A page size of bd table 187362306a36Sopenharmony_ci * can map 256 buffers. Each buffer contains 32 task context 187462306a36Sopenharmony_ci * entries. Hence the limit with one page is 8192 task context 187562306a36Sopenharmony_ci * entries. 187662306a36Sopenharmony_ci */ 187762306a36Sopenharmony_ci hba->task_ctx_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, 187862306a36Sopenharmony_ci PAGE_SIZE, 187962306a36Sopenharmony_ci &hba->task_ctx_bd_dma, 188062306a36Sopenharmony_ci GFP_KERNEL); 188162306a36Sopenharmony_ci if (!hba->task_ctx_bd_tbl) { 188262306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate task context BDT\n"); 188362306a36Sopenharmony_ci rc = -1; 188462306a36Sopenharmony_ci goto out; 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* 188862306a36Sopenharmony_ci * Allocate task_ctx which is an array of pointers pointing to 188962306a36Sopenharmony_ci * a page containing 32 task contexts 189062306a36Sopenharmony_ci */ 189162306a36Sopenharmony_ci task_ctx_arr_sz = (hba->max_tasks / BNX2FC_TASKS_PER_PAGE); 189262306a36Sopenharmony_ci hba->task_ctx = kzalloc((task_ctx_arr_sz * sizeof(void *)), 189362306a36Sopenharmony_ci GFP_KERNEL); 189462306a36Sopenharmony_ci if (!hba->task_ctx) { 189562306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate task context array\n"); 189662306a36Sopenharmony_ci rc = -1; 189762306a36Sopenharmony_ci goto out1; 189862306a36Sopenharmony_ci } 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci /* 190162306a36Sopenharmony_ci * Allocate task_ctx_dma which is an array of dma addresses 190262306a36Sopenharmony_ci */ 190362306a36Sopenharmony_ci hba->task_ctx_dma = kmalloc((task_ctx_arr_sz * 190462306a36Sopenharmony_ci sizeof(dma_addr_t)), GFP_KERNEL); 190562306a36Sopenharmony_ci if (!hba->task_ctx_dma) { 190662306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to alloc context mapping array\n"); 190762306a36Sopenharmony_ci rc = -1; 190862306a36Sopenharmony_ci goto out2; 190962306a36Sopenharmony_ci } 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci task_ctx_bdt = (struct regpair *)hba->task_ctx_bd_tbl; 191262306a36Sopenharmony_ci for (i = 0; i < task_ctx_arr_sz; i++) { 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci hba->task_ctx[i] = dma_alloc_coherent(&hba->pcidev->dev, 191562306a36Sopenharmony_ci PAGE_SIZE, 191662306a36Sopenharmony_ci &hba->task_ctx_dma[i], 191762306a36Sopenharmony_ci GFP_KERNEL); 191862306a36Sopenharmony_ci if (!hba->task_ctx[i]) { 191962306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to alloc task context\n"); 192062306a36Sopenharmony_ci rc = -1; 192162306a36Sopenharmony_ci goto out3; 192262306a36Sopenharmony_ci } 192362306a36Sopenharmony_ci addr = (u64)hba->task_ctx_dma[i]; 192462306a36Sopenharmony_ci task_ctx_bdt->hi = cpu_to_le32((u64)addr >> 32); 192562306a36Sopenharmony_ci task_ctx_bdt->lo = cpu_to_le32((u32)addr); 192662306a36Sopenharmony_ci task_ctx_bdt++; 192762306a36Sopenharmony_ci } 192862306a36Sopenharmony_ci return 0; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ciout3: 193162306a36Sopenharmony_ci for (i = 0; i < task_ctx_arr_sz; i++) { 193262306a36Sopenharmony_ci if (hba->task_ctx[i]) { 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 193562306a36Sopenharmony_ci hba->task_ctx[i], hba->task_ctx_dma[i]); 193662306a36Sopenharmony_ci hba->task_ctx[i] = NULL; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci kfree(hba->task_ctx_dma); 194162306a36Sopenharmony_ci hba->task_ctx_dma = NULL; 194262306a36Sopenharmony_ciout2: 194362306a36Sopenharmony_ci kfree(hba->task_ctx); 194462306a36Sopenharmony_ci hba->task_ctx = NULL; 194562306a36Sopenharmony_ciout1: 194662306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 194762306a36Sopenharmony_ci hba->task_ctx_bd_tbl, hba->task_ctx_bd_dma); 194862306a36Sopenharmony_ci hba->task_ctx_bd_tbl = NULL; 194962306a36Sopenharmony_ciout: 195062306a36Sopenharmony_ci return rc; 195162306a36Sopenharmony_ci} 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_civoid bnx2fc_free_task_ctx(struct bnx2fc_hba *hba) 195462306a36Sopenharmony_ci{ 195562306a36Sopenharmony_ci int task_ctx_arr_sz; 195662306a36Sopenharmony_ci int i; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci if (hba->task_ctx_bd_tbl) { 195962306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 196062306a36Sopenharmony_ci hba->task_ctx_bd_tbl, 196162306a36Sopenharmony_ci hba->task_ctx_bd_dma); 196262306a36Sopenharmony_ci hba->task_ctx_bd_tbl = NULL; 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci task_ctx_arr_sz = (hba->max_tasks / BNX2FC_TASKS_PER_PAGE); 196662306a36Sopenharmony_ci if (hba->task_ctx) { 196762306a36Sopenharmony_ci for (i = 0; i < task_ctx_arr_sz; i++) { 196862306a36Sopenharmony_ci if (hba->task_ctx[i]) { 196962306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 197062306a36Sopenharmony_ci hba->task_ctx[i], 197162306a36Sopenharmony_ci hba->task_ctx_dma[i]); 197262306a36Sopenharmony_ci hba->task_ctx[i] = NULL; 197362306a36Sopenharmony_ci } 197462306a36Sopenharmony_ci } 197562306a36Sopenharmony_ci kfree(hba->task_ctx); 197662306a36Sopenharmony_ci hba->task_ctx = NULL; 197762306a36Sopenharmony_ci } 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci kfree(hba->task_ctx_dma); 198062306a36Sopenharmony_ci hba->task_ctx_dma = NULL; 198162306a36Sopenharmony_ci} 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_cistatic void bnx2fc_free_hash_table(struct bnx2fc_hba *hba) 198462306a36Sopenharmony_ci{ 198562306a36Sopenharmony_ci int i; 198662306a36Sopenharmony_ci int segment_count; 198762306a36Sopenharmony_ci u32 *pbl; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci if (hba->hash_tbl_segments) { 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci pbl = hba->hash_tbl_pbl; 199262306a36Sopenharmony_ci if (pbl) { 199362306a36Sopenharmony_ci segment_count = hba->hash_tbl_segment_count; 199462306a36Sopenharmony_ci for (i = 0; i < segment_count; ++i) { 199562306a36Sopenharmony_ci dma_addr_t dma_address; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci dma_address = le32_to_cpu(*pbl); 199862306a36Sopenharmony_ci ++pbl; 199962306a36Sopenharmony_ci dma_address += ((u64)le32_to_cpu(*pbl)) << 32; 200062306a36Sopenharmony_ci ++pbl; 200162306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, 200262306a36Sopenharmony_ci BNX2FC_HASH_TBL_CHUNK_SIZE, 200362306a36Sopenharmony_ci hba->hash_tbl_segments[i], 200462306a36Sopenharmony_ci dma_address); 200562306a36Sopenharmony_ci } 200662306a36Sopenharmony_ci } 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci kfree(hba->hash_tbl_segments); 200962306a36Sopenharmony_ci hba->hash_tbl_segments = NULL; 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci if (hba->hash_tbl_pbl) { 201362306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 201462306a36Sopenharmony_ci hba->hash_tbl_pbl, 201562306a36Sopenharmony_ci hba->hash_tbl_pbl_dma); 201662306a36Sopenharmony_ci hba->hash_tbl_pbl = NULL; 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci} 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_cistatic int bnx2fc_allocate_hash_table(struct bnx2fc_hba *hba) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci int i; 202362306a36Sopenharmony_ci int hash_table_size; 202462306a36Sopenharmony_ci int segment_count; 202562306a36Sopenharmony_ci int segment_array_size; 202662306a36Sopenharmony_ci int dma_segment_array_size; 202762306a36Sopenharmony_ci dma_addr_t *dma_segment_array; 202862306a36Sopenharmony_ci u32 *pbl; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci hash_table_size = BNX2FC_NUM_MAX_SESS * BNX2FC_MAX_ROWS_IN_HASH_TBL * 203162306a36Sopenharmony_ci sizeof(struct fcoe_hash_table_entry); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci segment_count = hash_table_size + BNX2FC_HASH_TBL_CHUNK_SIZE - 1; 203462306a36Sopenharmony_ci segment_count /= BNX2FC_HASH_TBL_CHUNK_SIZE; 203562306a36Sopenharmony_ci hba->hash_tbl_segment_count = segment_count; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci segment_array_size = segment_count * sizeof(*hba->hash_tbl_segments); 203862306a36Sopenharmony_ci hba->hash_tbl_segments = kzalloc(segment_array_size, GFP_KERNEL); 203962306a36Sopenharmony_ci if (!hba->hash_tbl_segments) { 204062306a36Sopenharmony_ci printk(KERN_ERR PFX "hash table pointers alloc failed\n"); 204162306a36Sopenharmony_ci return -ENOMEM; 204262306a36Sopenharmony_ci } 204362306a36Sopenharmony_ci dma_segment_array_size = segment_count * sizeof(*dma_segment_array); 204462306a36Sopenharmony_ci dma_segment_array = kzalloc(dma_segment_array_size, GFP_KERNEL); 204562306a36Sopenharmony_ci if (!dma_segment_array) { 204662306a36Sopenharmony_ci printk(KERN_ERR PFX "hash table pointers (dma) alloc failed\n"); 204762306a36Sopenharmony_ci goto cleanup_ht; 204862306a36Sopenharmony_ci } 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci for (i = 0; i < segment_count; ++i) { 205162306a36Sopenharmony_ci hba->hash_tbl_segments[i] = dma_alloc_coherent(&hba->pcidev->dev, 205262306a36Sopenharmony_ci BNX2FC_HASH_TBL_CHUNK_SIZE, 205362306a36Sopenharmony_ci &dma_segment_array[i], 205462306a36Sopenharmony_ci GFP_KERNEL); 205562306a36Sopenharmony_ci if (!hba->hash_tbl_segments[i]) { 205662306a36Sopenharmony_ci printk(KERN_ERR PFX "hash segment alloc failed\n"); 205762306a36Sopenharmony_ci goto cleanup_dma; 205862306a36Sopenharmony_ci } 205962306a36Sopenharmony_ci } 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci hba->hash_tbl_pbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, 206262306a36Sopenharmony_ci &hba->hash_tbl_pbl_dma, 206362306a36Sopenharmony_ci GFP_KERNEL); 206462306a36Sopenharmony_ci if (!hba->hash_tbl_pbl) { 206562306a36Sopenharmony_ci printk(KERN_ERR PFX "hash table pbl alloc failed\n"); 206662306a36Sopenharmony_ci goto cleanup_dma; 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci pbl = hba->hash_tbl_pbl; 207062306a36Sopenharmony_ci for (i = 0; i < segment_count; ++i) { 207162306a36Sopenharmony_ci u64 paddr = dma_segment_array[i]; 207262306a36Sopenharmony_ci *pbl = cpu_to_le32((u32) paddr); 207362306a36Sopenharmony_ci ++pbl; 207462306a36Sopenharmony_ci *pbl = cpu_to_le32((u32) (paddr >> 32)); 207562306a36Sopenharmony_ci ++pbl; 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci pbl = hba->hash_tbl_pbl; 207862306a36Sopenharmony_ci i = 0; 207962306a36Sopenharmony_ci while (*pbl && *(pbl + 1)) { 208062306a36Sopenharmony_ci ++pbl; 208162306a36Sopenharmony_ci ++pbl; 208262306a36Sopenharmony_ci ++i; 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci kfree(dma_segment_array); 208562306a36Sopenharmony_ci return 0; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_cicleanup_dma: 208862306a36Sopenharmony_ci for (i = 0; i < segment_count; ++i) { 208962306a36Sopenharmony_ci if (hba->hash_tbl_segments[i]) 209062306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, 209162306a36Sopenharmony_ci BNX2FC_HASH_TBL_CHUNK_SIZE, 209262306a36Sopenharmony_ci hba->hash_tbl_segments[i], 209362306a36Sopenharmony_ci dma_segment_array[i]); 209462306a36Sopenharmony_ci } 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci kfree(dma_segment_array); 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_cicleanup_ht: 209962306a36Sopenharmony_ci kfree(hba->hash_tbl_segments); 210062306a36Sopenharmony_ci hba->hash_tbl_segments = NULL; 210162306a36Sopenharmony_ci return -ENOMEM; 210262306a36Sopenharmony_ci} 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci/** 210562306a36Sopenharmony_ci * bnx2fc_setup_fw_resc - Allocate and map hash table and dummy buffer 210662306a36Sopenharmony_ci * 210762306a36Sopenharmony_ci * @hba: Pointer to adapter structure 210862306a36Sopenharmony_ci * 210962306a36Sopenharmony_ci */ 211062306a36Sopenharmony_ciint bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba) 211162306a36Sopenharmony_ci{ 211262306a36Sopenharmony_ci u64 addr; 211362306a36Sopenharmony_ci u32 mem_size; 211462306a36Sopenharmony_ci int i; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci if (bnx2fc_allocate_hash_table(hba)) 211762306a36Sopenharmony_ci return -ENOMEM; 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct regpair); 212062306a36Sopenharmony_ci hba->t2_hash_tbl_ptr = dma_alloc_coherent(&hba->pcidev->dev, mem_size, 212162306a36Sopenharmony_ci &hba->t2_hash_tbl_ptr_dma, 212262306a36Sopenharmony_ci GFP_KERNEL); 212362306a36Sopenharmony_ci if (!hba->t2_hash_tbl_ptr) { 212462306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate t2 hash table ptr\n"); 212562306a36Sopenharmony_ci bnx2fc_free_fw_resc(hba); 212662306a36Sopenharmony_ci return -ENOMEM; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci mem_size = BNX2FC_NUM_MAX_SESS * 213062306a36Sopenharmony_ci sizeof(struct fcoe_t2_hash_table_entry); 213162306a36Sopenharmony_ci hba->t2_hash_tbl = dma_alloc_coherent(&hba->pcidev->dev, mem_size, 213262306a36Sopenharmony_ci &hba->t2_hash_tbl_dma, 213362306a36Sopenharmony_ci GFP_KERNEL); 213462306a36Sopenharmony_ci if (!hba->t2_hash_tbl) { 213562306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate t2 hash table\n"); 213662306a36Sopenharmony_ci bnx2fc_free_fw_resc(hba); 213762306a36Sopenharmony_ci return -ENOMEM; 213862306a36Sopenharmony_ci } 213962306a36Sopenharmony_ci for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) { 214062306a36Sopenharmony_ci addr = (unsigned long) hba->t2_hash_tbl_dma + 214162306a36Sopenharmony_ci ((i+1) * sizeof(struct fcoe_t2_hash_table_entry)); 214262306a36Sopenharmony_ci hba->t2_hash_tbl[i].next.lo = addr & 0xffffffff; 214362306a36Sopenharmony_ci hba->t2_hash_tbl[i].next.hi = addr >> 32; 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, 214762306a36Sopenharmony_ci PAGE_SIZE, &hba->dummy_buf_dma, 214862306a36Sopenharmony_ci GFP_KERNEL); 214962306a36Sopenharmony_ci if (!hba->dummy_buffer) { 215062306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to alloc MP Dummy Buffer\n"); 215162306a36Sopenharmony_ci bnx2fc_free_fw_resc(hba); 215262306a36Sopenharmony_ci return -ENOMEM; 215362306a36Sopenharmony_ci } 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci hba->stats_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, 215662306a36Sopenharmony_ci &hba->stats_buf_dma, 215762306a36Sopenharmony_ci GFP_KERNEL); 215862306a36Sopenharmony_ci if (!hba->stats_buffer) { 215962306a36Sopenharmony_ci printk(KERN_ERR PFX "unable to alloc Stats Buffer\n"); 216062306a36Sopenharmony_ci bnx2fc_free_fw_resc(hba); 216162306a36Sopenharmony_ci return -ENOMEM; 216262306a36Sopenharmony_ci } 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci return 0; 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_civoid bnx2fc_free_fw_resc(struct bnx2fc_hba *hba) 216862306a36Sopenharmony_ci{ 216962306a36Sopenharmony_ci u32 mem_size; 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci if (hba->stats_buffer) { 217262306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 217362306a36Sopenharmony_ci hba->stats_buffer, hba->stats_buf_dma); 217462306a36Sopenharmony_ci hba->stats_buffer = NULL; 217562306a36Sopenharmony_ci } 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci if (hba->dummy_buffer) { 217862306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 217962306a36Sopenharmony_ci hba->dummy_buffer, hba->dummy_buf_dma); 218062306a36Sopenharmony_ci hba->dummy_buffer = NULL; 218162306a36Sopenharmony_ci } 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci if (hba->t2_hash_tbl_ptr) { 218462306a36Sopenharmony_ci mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct regpair); 218562306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, mem_size, 218662306a36Sopenharmony_ci hba->t2_hash_tbl_ptr, 218762306a36Sopenharmony_ci hba->t2_hash_tbl_ptr_dma); 218862306a36Sopenharmony_ci hba->t2_hash_tbl_ptr = NULL; 218962306a36Sopenharmony_ci } 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci if (hba->t2_hash_tbl) { 219262306a36Sopenharmony_ci mem_size = BNX2FC_NUM_MAX_SESS * 219362306a36Sopenharmony_ci sizeof(struct fcoe_t2_hash_table_entry); 219462306a36Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, mem_size, 219562306a36Sopenharmony_ci hba->t2_hash_tbl, hba->t2_hash_tbl_dma); 219662306a36Sopenharmony_ci hba->t2_hash_tbl = NULL; 219762306a36Sopenharmony_ci } 219862306a36Sopenharmony_ci bnx2fc_free_hash_table(hba); 219962306a36Sopenharmony_ci} 2200