18c2ecf20Sopenharmony_ci/* bnx2fc_hwi.c: QLogic Linux FCoE offload driver. 28c2ecf20Sopenharmony_ci * This file contains the code that low level functions that interact 38c2ecf20Sopenharmony_ci * with 57712 FCoE firmware. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2008-2013 Broadcom Corporation 68c2ecf20Sopenharmony_ci * Copyright (c) 2014-2016 QLogic Corporation 78c2ecf20Sopenharmony_ci * Copyright (c) 2016-2017 Cavium Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 118c2ecf20Sopenharmony_ci * the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "bnx2fc.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciDECLARE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba, 218c2ecf20Sopenharmony_ci struct fcoe_kcqe *new_cqe_kcqe); 228c2ecf20Sopenharmony_cistatic void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, 238c2ecf20Sopenharmony_ci struct fcoe_kcqe *ofld_kcqe); 248c2ecf20Sopenharmony_cistatic void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, 258c2ecf20Sopenharmony_ci struct fcoe_kcqe *ofld_kcqe); 268c2ecf20Sopenharmony_cistatic void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code); 278c2ecf20Sopenharmony_cistatic void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba, 288c2ecf20Sopenharmony_ci struct fcoe_kcqe *destroy_kcqe); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciint bnx2fc_send_stat_req(struct bnx2fc_hba *hba) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct fcoe_kwqe_stat stat_req; 338c2ecf20Sopenharmony_ci struct kwqe *kwqe_arr[2]; 348c2ecf20Sopenharmony_ci int num_kwqes = 1; 358c2ecf20Sopenharmony_ci int rc = 0; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci memset(&stat_req, 0x00, sizeof(struct fcoe_kwqe_stat)); 388c2ecf20Sopenharmony_ci stat_req.hdr.op_code = FCOE_KWQE_OPCODE_STAT; 398c2ecf20Sopenharmony_ci stat_req.hdr.flags = 408c2ecf20Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci stat_req.stat_params_addr_lo = (u32) hba->stats_buf_dma; 438c2ecf20Sopenharmony_ci stat_req.stat_params_addr_hi = (u32) ((u64)hba->stats_buf_dma >> 32); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &stat_req; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 488c2ecf20Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return rc; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * bnx2fc_send_fw_fcoe_init_msg - initiates initial handshake with FCoE f/w 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * @hba: adapter structure pointer 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * Send down FCoE firmware init KWQEs which initiates the initial handshake 598c2ecf20Sopenharmony_ci * with the f/w. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ciint bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct fcoe_kwqe_init1 fcoe_init1; 658c2ecf20Sopenharmony_ci struct fcoe_kwqe_init2 fcoe_init2; 668c2ecf20Sopenharmony_ci struct fcoe_kwqe_init3 fcoe_init3; 678c2ecf20Sopenharmony_ci struct kwqe *kwqe_arr[3]; 688c2ecf20Sopenharmony_ci int num_kwqes = 3; 698c2ecf20Sopenharmony_ci int rc = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (!hba->cnic) { 728c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "hba->cnic NULL during fcoe fw init\n"); 738c2ecf20Sopenharmony_ci return -ENODEV; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* fill init1 KWQE */ 778c2ecf20Sopenharmony_ci memset(&fcoe_init1, 0x00, sizeof(struct fcoe_kwqe_init1)); 788c2ecf20Sopenharmony_ci fcoe_init1.hdr.op_code = FCOE_KWQE_OPCODE_INIT1; 798c2ecf20Sopenharmony_ci fcoe_init1.hdr.flags = (FCOE_KWQE_LAYER_CODE << 808c2ecf20Sopenharmony_ci FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci fcoe_init1.num_tasks = hba->max_tasks; 838c2ecf20Sopenharmony_ci fcoe_init1.sq_num_wqes = BNX2FC_SQ_WQES_MAX; 848c2ecf20Sopenharmony_ci fcoe_init1.rq_num_wqes = BNX2FC_RQ_WQES_MAX; 858c2ecf20Sopenharmony_ci fcoe_init1.rq_buffer_log_size = BNX2FC_RQ_BUF_LOG_SZ; 868c2ecf20Sopenharmony_ci fcoe_init1.cq_num_wqes = BNX2FC_CQ_WQES_MAX; 878c2ecf20Sopenharmony_ci fcoe_init1.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma; 888c2ecf20Sopenharmony_ci fcoe_init1.dummy_buffer_addr_hi = (u32) ((u64)hba->dummy_buf_dma >> 32); 898c2ecf20Sopenharmony_ci fcoe_init1.task_list_pbl_addr_lo = (u32) hba->task_ctx_bd_dma; 908c2ecf20Sopenharmony_ci fcoe_init1.task_list_pbl_addr_hi = 918c2ecf20Sopenharmony_ci (u32) ((u64) hba->task_ctx_bd_dma >> 32); 928c2ecf20Sopenharmony_ci fcoe_init1.mtu = BNX2FC_MINI_JUMBO_MTU; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci fcoe_init1.flags = (PAGE_SHIFT << 958c2ecf20Sopenharmony_ci FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci fcoe_init1.num_sessions_log = BNX2FC_NUM_MAX_SESS_LOG; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* fill init2 KWQE */ 1008c2ecf20Sopenharmony_ci memset(&fcoe_init2, 0x00, sizeof(struct fcoe_kwqe_init2)); 1018c2ecf20Sopenharmony_ci fcoe_init2.hdr.op_code = FCOE_KWQE_OPCODE_INIT2; 1028c2ecf20Sopenharmony_ci fcoe_init2.hdr.flags = (FCOE_KWQE_LAYER_CODE << 1038c2ecf20Sopenharmony_ci FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci fcoe_init2.hsi_major_version = FCOE_HSI_MAJOR_VERSION; 1068c2ecf20Sopenharmony_ci fcoe_init2.hsi_minor_version = FCOE_HSI_MINOR_VERSION; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci fcoe_init2.hash_tbl_pbl_addr_lo = (u32) hba->hash_tbl_pbl_dma; 1108c2ecf20Sopenharmony_ci fcoe_init2.hash_tbl_pbl_addr_hi = (u32) 1118c2ecf20Sopenharmony_ci ((u64) hba->hash_tbl_pbl_dma >> 32); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci fcoe_init2.t2_hash_tbl_addr_lo = (u32) hba->t2_hash_tbl_dma; 1148c2ecf20Sopenharmony_ci fcoe_init2.t2_hash_tbl_addr_hi = (u32) 1158c2ecf20Sopenharmony_ci ((u64) hba->t2_hash_tbl_dma >> 32); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci fcoe_init2.t2_ptr_hash_tbl_addr_lo = (u32) hba->t2_hash_tbl_ptr_dma; 1188c2ecf20Sopenharmony_ci fcoe_init2.t2_ptr_hash_tbl_addr_hi = (u32) 1198c2ecf20Sopenharmony_ci ((u64) hba->t2_hash_tbl_ptr_dma >> 32); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci fcoe_init2.free_list_count = BNX2FC_NUM_MAX_SESS; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* fill init3 KWQE */ 1248c2ecf20Sopenharmony_ci memset(&fcoe_init3, 0x00, sizeof(struct fcoe_kwqe_init3)); 1258c2ecf20Sopenharmony_ci fcoe_init3.hdr.op_code = FCOE_KWQE_OPCODE_INIT3; 1268c2ecf20Sopenharmony_ci fcoe_init3.hdr.flags = (FCOE_KWQE_LAYER_CODE << 1278c2ecf20Sopenharmony_ci FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 1288c2ecf20Sopenharmony_ci fcoe_init3.error_bit_map_lo = 0xffffffff; 1298c2ecf20Sopenharmony_ci fcoe_init3.error_bit_map_hi = 0xffffffff; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* 1328c2ecf20Sopenharmony_ci * enable both cached connection and cached tasks 1338c2ecf20Sopenharmony_ci * 0 = none, 1 = cached connection, 2 = cached tasks, 3 = both 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci fcoe_init3.perf_config = 3; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &fcoe_init1; 1388c2ecf20Sopenharmony_ci kwqe_arr[1] = (struct kwqe *) &fcoe_init2; 1398c2ecf20Sopenharmony_ci kwqe_arr[2] = (struct kwqe *) &fcoe_init3; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 1428c2ecf20Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return rc; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ciint bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct fcoe_kwqe_destroy fcoe_destroy; 1498c2ecf20Sopenharmony_ci struct kwqe *kwqe_arr[2]; 1508c2ecf20Sopenharmony_ci int num_kwqes = 1; 1518c2ecf20Sopenharmony_ci int rc = -1; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* fill destroy KWQE */ 1548c2ecf20Sopenharmony_ci memset(&fcoe_destroy, 0x00, sizeof(struct fcoe_kwqe_destroy)); 1558c2ecf20Sopenharmony_ci fcoe_destroy.hdr.op_code = FCOE_KWQE_OPCODE_DESTROY; 1568c2ecf20Sopenharmony_ci fcoe_destroy.hdr.flags = (FCOE_KWQE_LAYER_CODE << 1578c2ecf20Sopenharmony_ci FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 1588c2ecf20Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &fcoe_destroy; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 1618c2ecf20Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 1628c2ecf20Sopenharmony_ci return rc; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/** 1668c2ecf20Sopenharmony_ci * bnx2fc_send_session_ofld_req - initiates FCoE Session offload process 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * @port: port structure pointer 1698c2ecf20Sopenharmony_ci * @tgt: bnx2fc_rport structure pointer 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ciint bnx2fc_send_session_ofld_req(struct fcoe_port *port, 1728c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct fc_lport *lport = port->lport; 1758c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 1768c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 1778c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 1788c2ecf20Sopenharmony_ci struct kwqe *kwqe_arr[4]; 1798c2ecf20Sopenharmony_ci struct fcoe_kwqe_conn_offload1 ofld_req1; 1808c2ecf20Sopenharmony_ci struct fcoe_kwqe_conn_offload2 ofld_req2; 1818c2ecf20Sopenharmony_ci struct fcoe_kwqe_conn_offload3 ofld_req3; 1828c2ecf20Sopenharmony_ci struct fcoe_kwqe_conn_offload4 ofld_req4; 1838c2ecf20Sopenharmony_ci struct fc_rport_priv *rdata = tgt->rdata; 1848c2ecf20Sopenharmony_ci struct fc_rport *rport = tgt->rport; 1858c2ecf20Sopenharmony_ci int num_kwqes = 4; 1868c2ecf20Sopenharmony_ci u32 port_id; 1878c2ecf20Sopenharmony_ci int rc = 0; 1888c2ecf20Sopenharmony_ci u16 conn_id; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Initialize offload request 1 structure */ 1918c2ecf20Sopenharmony_ci memset(&ofld_req1, 0x00, sizeof(struct fcoe_kwqe_conn_offload1)); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci ofld_req1.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN1; 1948c2ecf20Sopenharmony_ci ofld_req1.hdr.flags = 1958c2ecf20Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci conn_id = (u16)tgt->fcoe_conn_id; 1998c2ecf20Sopenharmony_ci ofld_req1.fcoe_conn_id = conn_id; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci ofld_req1.sq_addr_lo = (u32) tgt->sq_dma; 2038c2ecf20Sopenharmony_ci ofld_req1.sq_addr_hi = (u32)((u64) tgt->sq_dma >> 32); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ofld_req1.rq_pbl_addr_lo = (u32) tgt->rq_pbl_dma; 2068c2ecf20Sopenharmony_ci ofld_req1.rq_pbl_addr_hi = (u32)((u64) tgt->rq_pbl_dma >> 32); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ofld_req1.rq_first_pbe_addr_lo = (u32) tgt->rq_dma; 2098c2ecf20Sopenharmony_ci ofld_req1.rq_first_pbe_addr_hi = 2108c2ecf20Sopenharmony_ci (u32)((u64) tgt->rq_dma >> 32); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ofld_req1.rq_prod = 0x8000; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* Initialize offload request 2 structure */ 2158c2ecf20Sopenharmony_ci memset(&ofld_req2, 0x00, sizeof(struct fcoe_kwqe_conn_offload2)); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci ofld_req2.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN2; 2188c2ecf20Sopenharmony_ci ofld_req2.hdr.flags = 2198c2ecf20Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ofld_req2.tx_max_fc_pay_len = rdata->maxframe_size; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ofld_req2.cq_addr_lo = (u32) tgt->cq_dma; 2248c2ecf20Sopenharmony_ci ofld_req2.cq_addr_hi = (u32)((u64)tgt->cq_dma >> 32); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ofld_req2.xferq_addr_lo = (u32) tgt->xferq_dma; 2278c2ecf20Sopenharmony_ci ofld_req2.xferq_addr_hi = (u32)((u64)tgt->xferq_dma >> 32); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ofld_req2.conn_db_addr_lo = (u32)tgt->conn_db_dma; 2308c2ecf20Sopenharmony_ci ofld_req2.conn_db_addr_hi = (u32)((u64)tgt->conn_db_dma >> 32); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Initialize offload request 3 structure */ 2338c2ecf20Sopenharmony_ci memset(&ofld_req3, 0x00, sizeof(struct fcoe_kwqe_conn_offload3)); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci ofld_req3.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN3; 2368c2ecf20Sopenharmony_ci ofld_req3.hdr.flags = 2378c2ecf20Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci ofld_req3.vlan_tag = interface->vlan_id << 2408c2ecf20Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT; 2418c2ecf20Sopenharmony_ci ofld_req3.vlan_tag |= 3 << FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci port_id = fc_host_port_id(lport->host); 2448c2ecf20Sopenharmony_ci if (port_id == 0) { 2458c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "ofld_req: port_id = 0, link down?\n"); 2468c2ecf20Sopenharmony_ci return -EINVAL; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* 2508c2ecf20Sopenharmony_ci * Store s_id of the initiator for further reference. This will 2518c2ecf20Sopenharmony_ci * be used during disable/destroy during linkdown processing as 2528c2ecf20Sopenharmony_ci * when the lport is reset, the port_id also is reset to 0 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci tgt->sid = port_id; 2558c2ecf20Sopenharmony_ci ofld_req3.s_id[0] = (port_id & 0x000000FF); 2568c2ecf20Sopenharmony_ci ofld_req3.s_id[1] = (port_id & 0x0000FF00) >> 8; 2578c2ecf20Sopenharmony_ci ofld_req3.s_id[2] = (port_id & 0x00FF0000) >> 16; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci port_id = rport->port_id; 2608c2ecf20Sopenharmony_ci ofld_req3.d_id[0] = (port_id & 0x000000FF); 2618c2ecf20Sopenharmony_ci ofld_req3.d_id[1] = (port_id & 0x0000FF00) >> 8; 2628c2ecf20Sopenharmony_ci ofld_req3.d_id[2] = (port_id & 0x00FF0000) >> 16; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci ofld_req3.tx_total_conc_seqs = rdata->max_seq; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ofld_req3.tx_max_conc_seqs_c3 = rdata->max_seq; 2678c2ecf20Sopenharmony_ci ofld_req3.rx_max_fc_pay_len = lport->mfs; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ofld_req3.rx_total_conc_seqs = BNX2FC_MAX_SEQS; 2708c2ecf20Sopenharmony_ci ofld_req3.rx_max_conc_seqs_c3 = BNX2FC_MAX_SEQS; 2718c2ecf20Sopenharmony_ci ofld_req3.rx_open_seqs_exch_c3 = 1; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci ofld_req3.confq_first_pbe_addr_lo = tgt->confq_dma; 2748c2ecf20Sopenharmony_ci ofld_req3.confq_first_pbe_addr_hi = (u32)((u64) tgt->confq_dma >> 32); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* set mul_n_port_ids supported flag to 0, until it is supported */ 2778c2ecf20Sopenharmony_ci ofld_req3.flags = 0; 2788c2ecf20Sopenharmony_ci /* 2798c2ecf20Sopenharmony_ci ofld_req3.flags |= (((lport->send_sp_features & FC_SP_FT_MNA) ? 1:0) << 2808c2ecf20Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT); 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_ci /* Info from PLOGI response */ 2838c2ecf20Sopenharmony_ci ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_EDTR) ? 1 : 0) << 2848c2ecf20Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_SEQC) ? 1 : 0) << 2878c2ecf20Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* 2908c2ecf20Sopenharmony_ci * Info from PRLI response, this info is used for sequence level error 2918c2ecf20Sopenharmony_ci * recovery support 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci if (tgt->dev_type == TYPE_TAPE) { 2948c2ecf20Sopenharmony_ci ofld_req3.flags |= 1 << 2958c2ecf20Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT; 2968c2ecf20Sopenharmony_ci ofld_req3.flags |= (((rdata->flags & FC_RP_FLAGS_REC_SUPPORTED) 2978c2ecf20Sopenharmony_ci ? 1 : 0) << 2988c2ecf20Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* vlan flag */ 3028c2ecf20Sopenharmony_ci ofld_req3.flags |= (interface->vlan_enabled << 3038c2ecf20Sopenharmony_ci FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* C2_VALID and ACK flags are not set as they are not supported */ 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Initialize offload request 4 structure */ 3098c2ecf20Sopenharmony_ci memset(&ofld_req4, 0x00, sizeof(struct fcoe_kwqe_conn_offload4)); 3108c2ecf20Sopenharmony_ci ofld_req4.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN4; 3118c2ecf20Sopenharmony_ci ofld_req4.hdr.flags = 3128c2ecf20Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci ofld_req4.e_d_tov_timer_val = lport->e_d_tov / 20; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ofld_req4.src_mac_addr_lo[0] = port->data_src_addr[5]; 3188c2ecf20Sopenharmony_ci /* local mac */ 3198c2ecf20Sopenharmony_ci ofld_req4.src_mac_addr_lo[1] = port->data_src_addr[4]; 3208c2ecf20Sopenharmony_ci ofld_req4.src_mac_addr_mid[0] = port->data_src_addr[3]; 3218c2ecf20Sopenharmony_ci ofld_req4.src_mac_addr_mid[1] = port->data_src_addr[2]; 3228c2ecf20Sopenharmony_ci ofld_req4.src_mac_addr_hi[0] = port->data_src_addr[1]; 3238c2ecf20Sopenharmony_ci ofld_req4.src_mac_addr_hi[1] = port->data_src_addr[0]; 3248c2ecf20Sopenharmony_ci ofld_req4.dst_mac_addr_lo[0] = ctlr->dest_addr[5]; 3258c2ecf20Sopenharmony_ci /* fcf mac */ 3268c2ecf20Sopenharmony_ci ofld_req4.dst_mac_addr_lo[1] = ctlr->dest_addr[4]; 3278c2ecf20Sopenharmony_ci ofld_req4.dst_mac_addr_mid[0] = ctlr->dest_addr[3]; 3288c2ecf20Sopenharmony_ci ofld_req4.dst_mac_addr_mid[1] = ctlr->dest_addr[2]; 3298c2ecf20Sopenharmony_ci ofld_req4.dst_mac_addr_hi[0] = ctlr->dest_addr[1]; 3308c2ecf20Sopenharmony_ci ofld_req4.dst_mac_addr_hi[1] = ctlr->dest_addr[0]; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci ofld_req4.lcq_addr_lo = (u32) tgt->lcq_dma; 3338c2ecf20Sopenharmony_ci ofld_req4.lcq_addr_hi = (u32)((u64) tgt->lcq_dma >> 32); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci ofld_req4.confq_pbl_base_addr_lo = (u32) tgt->confq_pbl_dma; 3368c2ecf20Sopenharmony_ci ofld_req4.confq_pbl_base_addr_hi = 3378c2ecf20Sopenharmony_ci (u32)((u64) tgt->confq_pbl_dma >> 32); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &ofld_req1; 3408c2ecf20Sopenharmony_ci kwqe_arr[1] = (struct kwqe *) &ofld_req2; 3418c2ecf20Sopenharmony_ci kwqe_arr[2] = (struct kwqe *) &ofld_req3; 3428c2ecf20Sopenharmony_ci kwqe_arr[3] = (struct kwqe *) &ofld_req4; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 3458c2ecf20Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return rc; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/** 3518c2ecf20Sopenharmony_ci * bnx2fc_send_session_enable_req - initiates FCoE Session enablement 3528c2ecf20Sopenharmony_ci * 3538c2ecf20Sopenharmony_ci * @port: port structure pointer 3548c2ecf20Sopenharmony_ci * @tgt: bnx2fc_rport structure pointer 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_ciint bnx2fc_send_session_enable_req(struct fcoe_port *port, 3578c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct kwqe *kwqe_arr[2]; 3608c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 3618c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 3628c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 3638c2ecf20Sopenharmony_ci struct fcoe_kwqe_conn_enable_disable enbl_req; 3648c2ecf20Sopenharmony_ci struct fc_lport *lport = port->lport; 3658c2ecf20Sopenharmony_ci struct fc_rport *rport = tgt->rport; 3668c2ecf20Sopenharmony_ci int num_kwqes = 1; 3678c2ecf20Sopenharmony_ci int rc = 0; 3688c2ecf20Sopenharmony_ci u32 port_id; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci memset(&enbl_req, 0x00, 3718c2ecf20Sopenharmony_ci sizeof(struct fcoe_kwqe_conn_enable_disable)); 3728c2ecf20Sopenharmony_ci enbl_req.hdr.op_code = FCOE_KWQE_OPCODE_ENABLE_CONN; 3738c2ecf20Sopenharmony_ci enbl_req.hdr.flags = 3748c2ecf20Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci enbl_req.src_mac_addr_lo[0] = port->data_src_addr[5]; 3778c2ecf20Sopenharmony_ci /* local mac */ 3788c2ecf20Sopenharmony_ci enbl_req.src_mac_addr_lo[1] = port->data_src_addr[4]; 3798c2ecf20Sopenharmony_ci enbl_req.src_mac_addr_mid[0] = port->data_src_addr[3]; 3808c2ecf20Sopenharmony_ci enbl_req.src_mac_addr_mid[1] = port->data_src_addr[2]; 3818c2ecf20Sopenharmony_ci enbl_req.src_mac_addr_hi[0] = port->data_src_addr[1]; 3828c2ecf20Sopenharmony_ci enbl_req.src_mac_addr_hi[1] = port->data_src_addr[0]; 3838c2ecf20Sopenharmony_ci memcpy(tgt->src_addr, port->data_src_addr, ETH_ALEN); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci enbl_req.dst_mac_addr_lo[0] = ctlr->dest_addr[5]; 3868c2ecf20Sopenharmony_ci enbl_req.dst_mac_addr_lo[1] = ctlr->dest_addr[4]; 3878c2ecf20Sopenharmony_ci enbl_req.dst_mac_addr_mid[0] = ctlr->dest_addr[3]; 3888c2ecf20Sopenharmony_ci enbl_req.dst_mac_addr_mid[1] = ctlr->dest_addr[2]; 3898c2ecf20Sopenharmony_ci enbl_req.dst_mac_addr_hi[0] = ctlr->dest_addr[1]; 3908c2ecf20Sopenharmony_ci enbl_req.dst_mac_addr_hi[1] = ctlr->dest_addr[0]; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci port_id = fc_host_port_id(lport->host); 3938c2ecf20Sopenharmony_ci if (port_id != tgt->sid) { 3948c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "WARN: enable_req port_id = 0x%x," 3958c2ecf20Sopenharmony_ci "sid = 0x%x\n", port_id, tgt->sid); 3968c2ecf20Sopenharmony_ci port_id = tgt->sid; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci enbl_req.s_id[0] = (port_id & 0x000000FF); 3998c2ecf20Sopenharmony_ci enbl_req.s_id[1] = (port_id & 0x0000FF00) >> 8; 4008c2ecf20Sopenharmony_ci enbl_req.s_id[2] = (port_id & 0x00FF0000) >> 16; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci port_id = rport->port_id; 4038c2ecf20Sopenharmony_ci enbl_req.d_id[0] = (port_id & 0x000000FF); 4048c2ecf20Sopenharmony_ci enbl_req.d_id[1] = (port_id & 0x0000FF00) >> 8; 4058c2ecf20Sopenharmony_ci enbl_req.d_id[2] = (port_id & 0x00FF0000) >> 16; 4068c2ecf20Sopenharmony_ci enbl_req.vlan_tag = interface->vlan_id << 4078c2ecf20Sopenharmony_ci FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT; 4088c2ecf20Sopenharmony_ci enbl_req.vlan_tag |= 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT; 4098c2ecf20Sopenharmony_ci enbl_req.vlan_flag = interface->vlan_enabled; 4108c2ecf20Sopenharmony_ci enbl_req.context_id = tgt->context_id; 4118c2ecf20Sopenharmony_ci enbl_req.conn_id = tgt->fcoe_conn_id; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &enbl_req; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 4168c2ecf20Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 4178c2ecf20Sopenharmony_ci return rc; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci/** 4218c2ecf20Sopenharmony_ci * bnx2fc_send_session_disable_req - initiates FCoE Session disable 4228c2ecf20Sopenharmony_ci * 4238c2ecf20Sopenharmony_ci * @port: port structure pointer 4248c2ecf20Sopenharmony_ci * @tgt: bnx2fc_rport structure pointer 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_ciint bnx2fc_send_session_disable_req(struct fcoe_port *port, 4278c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 4308c2ecf20Sopenharmony_ci struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); 4318c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 4328c2ecf20Sopenharmony_ci struct fcoe_kwqe_conn_enable_disable disable_req; 4338c2ecf20Sopenharmony_ci struct kwqe *kwqe_arr[2]; 4348c2ecf20Sopenharmony_ci struct fc_rport *rport = tgt->rport; 4358c2ecf20Sopenharmony_ci int num_kwqes = 1; 4368c2ecf20Sopenharmony_ci int rc = 0; 4378c2ecf20Sopenharmony_ci u32 port_id; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci memset(&disable_req, 0x00, 4408c2ecf20Sopenharmony_ci sizeof(struct fcoe_kwqe_conn_enable_disable)); 4418c2ecf20Sopenharmony_ci disable_req.hdr.op_code = FCOE_KWQE_OPCODE_DISABLE_CONN; 4428c2ecf20Sopenharmony_ci disable_req.hdr.flags = 4438c2ecf20Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci disable_req.src_mac_addr_lo[0] = tgt->src_addr[5]; 4468c2ecf20Sopenharmony_ci disable_req.src_mac_addr_lo[1] = tgt->src_addr[4]; 4478c2ecf20Sopenharmony_ci disable_req.src_mac_addr_mid[0] = tgt->src_addr[3]; 4488c2ecf20Sopenharmony_ci disable_req.src_mac_addr_mid[1] = tgt->src_addr[2]; 4498c2ecf20Sopenharmony_ci disable_req.src_mac_addr_hi[0] = tgt->src_addr[1]; 4508c2ecf20Sopenharmony_ci disable_req.src_mac_addr_hi[1] = tgt->src_addr[0]; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci disable_req.dst_mac_addr_lo[0] = ctlr->dest_addr[5]; 4538c2ecf20Sopenharmony_ci disable_req.dst_mac_addr_lo[1] = ctlr->dest_addr[4]; 4548c2ecf20Sopenharmony_ci disable_req.dst_mac_addr_mid[0] = ctlr->dest_addr[3]; 4558c2ecf20Sopenharmony_ci disable_req.dst_mac_addr_mid[1] = ctlr->dest_addr[2]; 4568c2ecf20Sopenharmony_ci disable_req.dst_mac_addr_hi[0] = ctlr->dest_addr[1]; 4578c2ecf20Sopenharmony_ci disable_req.dst_mac_addr_hi[1] = ctlr->dest_addr[0]; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci port_id = tgt->sid; 4608c2ecf20Sopenharmony_ci disable_req.s_id[0] = (port_id & 0x000000FF); 4618c2ecf20Sopenharmony_ci disable_req.s_id[1] = (port_id & 0x0000FF00) >> 8; 4628c2ecf20Sopenharmony_ci disable_req.s_id[2] = (port_id & 0x00FF0000) >> 16; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci port_id = rport->port_id; 4668c2ecf20Sopenharmony_ci disable_req.d_id[0] = (port_id & 0x000000FF); 4678c2ecf20Sopenharmony_ci disable_req.d_id[1] = (port_id & 0x0000FF00) >> 8; 4688c2ecf20Sopenharmony_ci disable_req.d_id[2] = (port_id & 0x00FF0000) >> 16; 4698c2ecf20Sopenharmony_ci disable_req.context_id = tgt->context_id; 4708c2ecf20Sopenharmony_ci disable_req.conn_id = tgt->fcoe_conn_id; 4718c2ecf20Sopenharmony_ci disable_req.vlan_tag = interface->vlan_id << 4728c2ecf20Sopenharmony_ci FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT; 4738c2ecf20Sopenharmony_ci disable_req.vlan_tag |= 4748c2ecf20Sopenharmony_ci 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT; 4758c2ecf20Sopenharmony_ci disable_req.vlan_flag = interface->vlan_enabled; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &disable_req; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 4808c2ecf20Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return rc; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci/** 4868c2ecf20Sopenharmony_ci * bnx2fc_send_session_destroy_req - initiates FCoE Session destroy 4878c2ecf20Sopenharmony_ci * 4888c2ecf20Sopenharmony_ci * @hba: adapter structure pointer 4898c2ecf20Sopenharmony_ci * @tgt: bnx2fc_rport structure pointer 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ciint bnx2fc_send_session_destroy_req(struct bnx2fc_hba *hba, 4928c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct fcoe_kwqe_conn_destroy destroy_req; 4958c2ecf20Sopenharmony_ci struct kwqe *kwqe_arr[2]; 4968c2ecf20Sopenharmony_ci int num_kwqes = 1; 4978c2ecf20Sopenharmony_ci int rc = 0; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci memset(&destroy_req, 0x00, sizeof(struct fcoe_kwqe_conn_destroy)); 5008c2ecf20Sopenharmony_ci destroy_req.hdr.op_code = FCOE_KWQE_OPCODE_DESTROY_CONN; 5018c2ecf20Sopenharmony_ci destroy_req.hdr.flags = 5028c2ecf20Sopenharmony_ci (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci destroy_req.context_id = tgt->context_id; 5058c2ecf20Sopenharmony_ci destroy_req.conn_id = tgt->fcoe_conn_id; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci kwqe_arr[0] = (struct kwqe *) &destroy_req; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (hba->cnic && hba->cnic->submit_kwqes) 5108c2ecf20Sopenharmony_ci rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return rc; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic bool is_valid_lport(struct bnx2fc_hba *hba, struct fc_lport *lport) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct bnx2fc_lport *blport; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 5208c2ecf20Sopenharmony_ci list_for_each_entry(blport, &hba->vports, list) { 5218c2ecf20Sopenharmony_ci if (blport->lport == lport) { 5228c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 5238c2ecf20Sopenharmony_ci return true; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 5278c2ecf20Sopenharmony_ci return false; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic void bnx2fc_unsol_els_work(struct work_struct *work) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct bnx2fc_unsol_els *unsol_els; 5358c2ecf20Sopenharmony_ci struct fc_lport *lport; 5368c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba; 5378c2ecf20Sopenharmony_ci struct fc_frame *fp; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci unsol_els = container_of(work, struct bnx2fc_unsol_els, unsol_els_work); 5408c2ecf20Sopenharmony_ci lport = unsol_els->lport; 5418c2ecf20Sopenharmony_ci fp = unsol_els->fp; 5428c2ecf20Sopenharmony_ci hba = unsol_els->hba; 5438c2ecf20Sopenharmony_ci if (is_valid_lport(hba, lport)) 5448c2ecf20Sopenharmony_ci fc_exch_recv(lport, fp); 5458c2ecf20Sopenharmony_ci kfree(unsol_els); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_civoid bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, 5498c2ecf20Sopenharmony_ci unsigned char *buf, 5508c2ecf20Sopenharmony_ci u32 frame_len, u16 l2_oxid) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct fcoe_port *port = tgt->port; 5538c2ecf20Sopenharmony_ci struct fc_lport *lport = port->lport; 5548c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 5558c2ecf20Sopenharmony_ci struct bnx2fc_unsol_els *unsol_els; 5568c2ecf20Sopenharmony_ci struct fc_frame_header *fh; 5578c2ecf20Sopenharmony_ci struct fc_frame *fp; 5588c2ecf20Sopenharmony_ci struct sk_buff *skb; 5598c2ecf20Sopenharmony_ci u32 payload_len; 5608c2ecf20Sopenharmony_ci u32 crc; 5618c2ecf20Sopenharmony_ci u8 op; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci unsol_els = kzalloc(sizeof(*unsol_els), GFP_ATOMIC); 5658c2ecf20Sopenharmony_ci if (!unsol_els) { 5668c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Unable to allocate unsol_work\n"); 5678c2ecf20Sopenharmony_ci return; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "l2_frame_compl l2_oxid = 0x%x, frame_len = %d\n", 5718c2ecf20Sopenharmony_ci l2_oxid, frame_len); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci payload_len = frame_len - sizeof(struct fc_frame_header); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci fp = fc_frame_alloc(lport, payload_len); 5768c2ecf20Sopenharmony_ci if (!fp) { 5778c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "fc_frame_alloc failure\n"); 5788c2ecf20Sopenharmony_ci kfree(unsol_els); 5798c2ecf20Sopenharmony_ci return; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci fh = (struct fc_frame_header *) fc_frame_header_get(fp); 5838c2ecf20Sopenharmony_ci /* Copy FC Frame header and payload into the frame */ 5848c2ecf20Sopenharmony_ci memcpy(fh, buf, frame_len); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (l2_oxid != FC_XID_UNKNOWN) 5878c2ecf20Sopenharmony_ci fh->fh_ox_id = htons(l2_oxid); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci skb = fp_skb(fp); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if ((fh->fh_r_ctl == FC_RCTL_ELS_REQ) || 5928c2ecf20Sopenharmony_ci (fh->fh_r_ctl == FC_RCTL_ELS_REP)) { 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (fh->fh_type == FC_TYPE_ELS) { 5958c2ecf20Sopenharmony_ci op = fc_frame_payload_op(fp); 5968c2ecf20Sopenharmony_ci if ((op == ELS_TEST) || (op == ELS_ESTC) || 5978c2ecf20Sopenharmony_ci (op == ELS_FAN) || (op == ELS_CSU)) { 5988c2ecf20Sopenharmony_ci /* 5998c2ecf20Sopenharmony_ci * No need to reply for these 6008c2ecf20Sopenharmony_ci * ELS requests 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "dropping ELS 0x%x\n", op); 6038c2ecf20Sopenharmony_ci kfree_skb(skb); 6048c2ecf20Sopenharmony_ci kfree(unsol_els); 6058c2ecf20Sopenharmony_ci return; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci crc = fcoe_fc_crc(fp); 6098c2ecf20Sopenharmony_ci fc_frame_init(fp); 6108c2ecf20Sopenharmony_ci fr_dev(fp) = lport; 6118c2ecf20Sopenharmony_ci fr_sof(fp) = FC_SOF_I3; 6128c2ecf20Sopenharmony_ci fr_eof(fp) = FC_EOF_T; 6138c2ecf20Sopenharmony_ci fr_crc(fp) = cpu_to_le32(~crc); 6148c2ecf20Sopenharmony_ci unsol_els->lport = lport; 6158c2ecf20Sopenharmony_ci unsol_els->hba = interface->hba; 6168c2ecf20Sopenharmony_ci unsol_els->fp = fp; 6178c2ecf20Sopenharmony_ci INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work); 6188c2ecf20Sopenharmony_ci queue_work(bnx2fc_wq, &unsol_els->unsol_els_work); 6198c2ecf20Sopenharmony_ci } else { 6208c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "fh_r_ctl = 0x%x\n", fh->fh_r_ctl); 6218c2ecf20Sopenharmony_ci kfree_skb(skb); 6228c2ecf20Sopenharmony_ci kfree(unsol_els); 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci u8 num_rq; 6298c2ecf20Sopenharmony_ci struct fcoe_err_report_entry *err_entry; 6308c2ecf20Sopenharmony_ci unsigned char *rq_data; 6318c2ecf20Sopenharmony_ci unsigned char *buf = NULL, *buf1; 6328c2ecf20Sopenharmony_ci int i; 6338c2ecf20Sopenharmony_ci u16 xid; 6348c2ecf20Sopenharmony_ci u32 frame_len, len; 6358c2ecf20Sopenharmony_ci struct bnx2fc_cmd *io_req = NULL; 6368c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = tgt->port->priv; 6378c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 6388c2ecf20Sopenharmony_ci int rc = 0; 6398c2ecf20Sopenharmony_ci u64 err_warn_bit_map; 6408c2ecf20Sopenharmony_ci u8 err_warn = 0xff; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Entered UNSOL COMPLETION wqe = 0x%x\n", wqe); 6448c2ecf20Sopenharmony_ci switch (wqe & FCOE_UNSOLICITED_CQE_SUBTYPE) { 6458c2ecf20Sopenharmony_ci case FCOE_UNSOLICITED_FRAME_CQE_TYPE: 6468c2ecf20Sopenharmony_ci frame_len = (wqe & FCOE_UNSOLICITED_CQE_PKT_LEN) >> 6478c2ecf20Sopenharmony_ci FCOE_UNSOLICITED_CQE_PKT_LEN_SHIFT; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci num_rq = (frame_len + BNX2FC_RQ_BUF_SZ - 1) / BNX2FC_RQ_BUF_SZ; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 6528c2ecf20Sopenharmony_ci rq_data = (unsigned char *)bnx2fc_get_next_rqe(tgt, num_rq); 6538c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (rq_data) { 6568c2ecf20Sopenharmony_ci buf = rq_data; 6578c2ecf20Sopenharmony_ci } else { 6588c2ecf20Sopenharmony_ci buf1 = buf = kmalloc((num_rq * BNX2FC_RQ_BUF_SZ), 6598c2ecf20Sopenharmony_ci GFP_ATOMIC); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (!buf1) { 6628c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Memory alloc failure\n"); 6638c2ecf20Sopenharmony_ci break; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci for (i = 0; i < num_rq; i++) { 6678c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 6688c2ecf20Sopenharmony_ci rq_data = (unsigned char *) 6698c2ecf20Sopenharmony_ci bnx2fc_get_next_rqe(tgt, 1); 6708c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 6718c2ecf20Sopenharmony_ci len = BNX2FC_RQ_BUF_SZ; 6728c2ecf20Sopenharmony_ci memcpy(buf1, rq_data, len); 6738c2ecf20Sopenharmony_ci buf1 += len; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, 6778c2ecf20Sopenharmony_ci FC_XID_UNKNOWN); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (buf != rq_data) 6808c2ecf20Sopenharmony_ci kfree(buf); 6818c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 6828c2ecf20Sopenharmony_ci bnx2fc_return_rqe(tgt, num_rq); 6838c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci case FCOE_ERROR_DETECTION_CQE_TYPE: 6878c2ecf20Sopenharmony_ci /* 6888c2ecf20Sopenharmony_ci * In case of error reporting CQE a single RQ entry 6898c2ecf20Sopenharmony_ci * is consumed. 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 6928c2ecf20Sopenharmony_ci num_rq = 1; 6938c2ecf20Sopenharmony_ci err_entry = (struct fcoe_err_report_entry *) 6948c2ecf20Sopenharmony_ci bnx2fc_get_next_rqe(tgt, 1); 6958c2ecf20Sopenharmony_ci xid = err_entry->fc_hdr.ox_id; 6968c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Unsol Error Frame OX_ID = 0x%x\n", xid); 6978c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x\n", 6988c2ecf20Sopenharmony_ci err_entry->data.err_warn_bitmap_hi, 6998c2ecf20Sopenharmony_ci err_entry->data.err_warn_bitmap_lo); 7008c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n", 7018c2ecf20Sopenharmony_ci err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (xid > hba->max_xid) { 7048c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", 7058c2ecf20Sopenharmony_ci xid); 7068c2ecf20Sopenharmony_ci goto ret_err_rqe; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; 7118c2ecf20Sopenharmony_ci if (!io_req) 7128c2ecf20Sopenharmony_ci goto ret_err_rqe; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (io_req->cmd_type != BNX2FC_SCSI_CMD) { 7158c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n"); 7168c2ecf20Sopenharmony_ci goto ret_err_rqe; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP, 7208c2ecf20Sopenharmony_ci &io_req->req_flags)) { 7218c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "unsol_err: cleanup in " 7228c2ecf20Sopenharmony_ci "progress.. ignore unsol err\n"); 7238c2ecf20Sopenharmony_ci goto ret_err_rqe; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci err_warn_bit_map = (u64) 7278c2ecf20Sopenharmony_ci ((u64)err_entry->data.err_warn_bitmap_hi << 32) | 7288c2ecf20Sopenharmony_ci (u64)err_entry->data.err_warn_bitmap_lo; 7298c2ecf20Sopenharmony_ci for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) { 7308c2ecf20Sopenharmony_ci if (err_warn_bit_map & (u64)((u64)1 << i)) { 7318c2ecf20Sopenharmony_ci err_warn = i; 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* 7378c2ecf20Sopenharmony_ci * If ABTS is already in progress, and FW error is 7388c2ecf20Sopenharmony_ci * received after that, do not cancel the timeout_work 7398c2ecf20Sopenharmony_ci * and let the error recovery continue by explicitly 7408c2ecf20Sopenharmony_ci * logging out the target, when the ABTS eventually 7418c2ecf20Sopenharmony_ci * times out. 7428c2ecf20Sopenharmony_ci */ 7438c2ecf20Sopenharmony_ci if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { 7448c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "err_warn: io_req (0x%x) already " 7458c2ecf20Sopenharmony_ci "in ABTS processing\n", xid); 7468c2ecf20Sopenharmony_ci goto ret_err_rqe; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "err = 0x%x\n", err_warn); 7498c2ecf20Sopenharmony_ci if (tgt->dev_type != TYPE_TAPE) 7508c2ecf20Sopenharmony_ci goto skip_rec; 7518c2ecf20Sopenharmony_ci switch (err_warn) { 7528c2ecf20Sopenharmony_ci case FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION: 7538c2ecf20Sopenharmony_ci case FCOE_ERROR_CODE_DATA_OOO_RO: 7548c2ecf20Sopenharmony_ci case FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT: 7558c2ecf20Sopenharmony_ci case FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET: 7568c2ecf20Sopenharmony_ci case FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ: 7578c2ecf20Sopenharmony_ci case FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET: 7588c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "REC TOV popped for xid - 0x%x\n", 7598c2ecf20Sopenharmony_ci xid); 7608c2ecf20Sopenharmony_ci memcpy(&io_req->err_entry, err_entry, 7618c2ecf20Sopenharmony_ci sizeof(struct fcoe_err_report_entry)); 7628c2ecf20Sopenharmony_ci if (!test_bit(BNX2FC_FLAG_SRR_SENT, 7638c2ecf20Sopenharmony_ci &io_req->req_flags)) { 7648c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 7658c2ecf20Sopenharmony_ci rc = bnx2fc_send_rec(io_req); 7668c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (rc) 7698c2ecf20Sopenharmony_ci goto skip_rec; 7708c2ecf20Sopenharmony_ci } else 7718c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "SRR in progress\n"); 7728c2ecf20Sopenharmony_ci goto ret_err_rqe; 7738c2ecf20Sopenharmony_ci break; 7748c2ecf20Sopenharmony_ci default: 7758c2ecf20Sopenharmony_ci break; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ciskip_rec: 7798c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags); 7808c2ecf20Sopenharmony_ci /* 7818c2ecf20Sopenharmony_ci * Cancel the timeout_work, as we received IO 7828c2ecf20Sopenharmony_ci * completion with FW error. 7838c2ecf20Sopenharmony_ci */ 7848c2ecf20Sopenharmony_ci if (cancel_delayed_work(&io_req->timeout_work)) 7858c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, bnx2fc_cmd_release); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci rc = bnx2fc_initiate_abts(io_req); 7888c2ecf20Sopenharmony_ci if (rc != SUCCESS) { 7898c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "err_warn: initiate_abts " 7908c2ecf20Sopenharmony_ci "failed xid = 0x%x. issue cleanup\n", 7918c2ecf20Sopenharmony_ci io_req->xid); 7928c2ecf20Sopenharmony_ci bnx2fc_initiate_cleanup(io_req); 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ciret_err_rqe: 7958c2ecf20Sopenharmony_ci bnx2fc_return_rqe(tgt, 1); 7968c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci case FCOE_WARNING_DETECTION_CQE_TYPE: 8008c2ecf20Sopenharmony_ci /* 8018c2ecf20Sopenharmony_ci *In case of warning reporting CQE a single RQ entry 8028c2ecf20Sopenharmony_ci * is consumes. 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 8058c2ecf20Sopenharmony_ci num_rq = 1; 8068c2ecf20Sopenharmony_ci err_entry = (struct fcoe_err_report_entry *) 8078c2ecf20Sopenharmony_ci bnx2fc_get_next_rqe(tgt, 1); 8088c2ecf20Sopenharmony_ci xid = cpu_to_be16(err_entry->fc_hdr.ox_id); 8098c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Unsol Warning Frame OX_ID = 0x%x\n", xid); 8108c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x", 8118c2ecf20Sopenharmony_ci err_entry->data.err_warn_bitmap_hi, 8128c2ecf20Sopenharmony_ci err_entry->data.err_warn_bitmap_lo); 8138c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x", 8148c2ecf20Sopenharmony_ci err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (xid > hba->max_xid) { 8178c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid); 8188c2ecf20Sopenharmony_ci goto ret_warn_rqe; 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci err_warn_bit_map = (u64) 8228c2ecf20Sopenharmony_ci ((u64)err_entry->data.err_warn_bitmap_hi << 32) | 8238c2ecf20Sopenharmony_ci (u64)err_entry->data.err_warn_bitmap_lo; 8248c2ecf20Sopenharmony_ci for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) { 8258c2ecf20Sopenharmony_ci if (err_warn_bit_map & ((u64)1 << i)) { 8268c2ecf20Sopenharmony_ci err_warn = i; 8278c2ecf20Sopenharmony_ci break; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "warn = 0x%x\n", err_warn); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; 8338c2ecf20Sopenharmony_ci if (!io_req) 8348c2ecf20Sopenharmony_ci goto ret_warn_rqe; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (io_req->cmd_type != BNX2FC_SCSI_CMD) { 8378c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n"); 8388c2ecf20Sopenharmony_ci goto ret_warn_rqe; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci memcpy(&io_req->err_entry, err_entry, 8428c2ecf20Sopenharmony_ci sizeof(struct fcoe_err_report_entry)); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (err_warn == FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION) 8458c2ecf20Sopenharmony_ci /* REC_TOV is not a warning code */ 8468c2ecf20Sopenharmony_ci BUG_ON(1); 8478c2ecf20Sopenharmony_ci else 8488c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Unsolicited warning\n"); 8498c2ecf20Sopenharmony_ciret_warn_rqe: 8508c2ecf20Sopenharmony_ci bnx2fc_return_rqe(tgt, 1); 8518c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 8528c2ecf20Sopenharmony_ci break; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci default: 8558c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Unsol Compl: Invalid CQE Subtype\n"); 8568c2ecf20Sopenharmony_ci break; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_civoid bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe, 8618c2ecf20Sopenharmony_ci unsigned char *rq_data, u8 num_rq, 8628c2ecf20Sopenharmony_ci struct fcoe_task_ctx_entry *task) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci struct fcoe_port *port = tgt->port; 8658c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 8668c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 8678c2ecf20Sopenharmony_ci struct bnx2fc_cmd *io_req; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci u16 xid; 8708c2ecf20Sopenharmony_ci u8 cmd_type; 8718c2ecf20Sopenharmony_ci u8 rx_state = 0; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID; 8768c2ecf20Sopenharmony_ci io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (io_req == NULL) { 8798c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ERROR? cq_compl - io_req is NULL\n"); 8808c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 8818c2ecf20Sopenharmony_ci return; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* Timestamp IO completion time */ 8858c2ecf20Sopenharmony_ci cmd_type = io_req->cmd_type; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci rx_state = ((task->rxwr_txrd.var_ctx.rx_flags & 8888c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE) >> 8898c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE_SHIFT); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci /* Process other IO completion types */ 8928c2ecf20Sopenharmony_ci switch (cmd_type) { 8938c2ecf20Sopenharmony_ci case BNX2FC_SCSI_CMD: 8948c2ecf20Sopenharmony_ci if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) { 8958c2ecf20Sopenharmony_ci bnx2fc_process_scsi_cmd_compl(io_req, task, num_rq, 8968c2ecf20Sopenharmony_ci rq_data); 8978c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 8988c2ecf20Sopenharmony_ci return; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (rx_state == FCOE_TASK_RX_STATE_ABTS_COMPLETED) 9028c2ecf20Sopenharmony_ci bnx2fc_process_abts_compl(io_req, task, num_rq); 9038c2ecf20Sopenharmony_ci else if (rx_state == 9048c2ecf20Sopenharmony_ci FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED) 9058c2ecf20Sopenharmony_ci bnx2fc_process_cleanup_compl(io_req, task, num_rq); 9068c2ecf20Sopenharmony_ci else 9078c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Invalid rx state - %d\n", 9088c2ecf20Sopenharmony_ci rx_state); 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci case BNX2FC_TASK_MGMT_CMD: 9128c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "Processing TM complete\n"); 9138c2ecf20Sopenharmony_ci bnx2fc_process_tm_compl(io_req, task, num_rq, rq_data); 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci case BNX2FC_ABTS: 9178c2ecf20Sopenharmony_ci /* 9188c2ecf20Sopenharmony_ci * ABTS request received by firmware. ABTS response 9198c2ecf20Sopenharmony_ci * will be delivered to the task belonging to the IO 9208c2ecf20Sopenharmony_ci * that was aborted 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "cq_compl- ABTS sent out by fw\n"); 9238c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, bnx2fc_cmd_release); 9248c2ecf20Sopenharmony_ci break; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci case BNX2FC_ELS: 9278c2ecf20Sopenharmony_ci if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) 9288c2ecf20Sopenharmony_ci bnx2fc_process_els_compl(io_req, task, num_rq); 9298c2ecf20Sopenharmony_ci else if (rx_state == FCOE_TASK_RX_STATE_ABTS_COMPLETED) 9308c2ecf20Sopenharmony_ci bnx2fc_process_abts_compl(io_req, task, num_rq); 9318c2ecf20Sopenharmony_ci else if (rx_state == 9328c2ecf20Sopenharmony_ci FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED) 9338c2ecf20Sopenharmony_ci bnx2fc_process_cleanup_compl(io_req, task, num_rq); 9348c2ecf20Sopenharmony_ci else 9358c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Invalid rx state = %d\n", 9368c2ecf20Sopenharmony_ci rx_state); 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci case BNX2FC_CLEANUP: 9408c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "cq_compl- cleanup resp rcvd\n"); 9418c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, bnx2fc_cmd_release); 9428c2ecf20Sopenharmony_ci break; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci case BNX2FC_SEQ_CLEANUP: 9458c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "cq_compl(0x%x) - seq cleanup resp\n", 9468c2ecf20Sopenharmony_ci io_req->xid); 9478c2ecf20Sopenharmony_ci bnx2fc_process_seq_cleanup_compl(io_req, task, rx_state); 9488c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, bnx2fc_cmd_release); 9498c2ecf20Sopenharmony_ci break; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci default: 9528c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Invalid cmd_type %d\n", cmd_type); 9538c2ecf20Sopenharmony_ci break; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_civoid bnx2fc_arm_cq(struct bnx2fc_rport *tgt) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci struct b577xx_fcoe_rx_doorbell *rx_db = &tgt->rx_db; 9618c2ecf20Sopenharmony_ci u32 msg; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci wmb(); 9648c2ecf20Sopenharmony_ci rx_db->doorbell_cq_cons = tgt->cq_cons_idx | (tgt->cq_curr_toggle_bit << 9658c2ecf20Sopenharmony_ci FCOE_CQE_TOGGLE_BIT_SHIFT); 9668c2ecf20Sopenharmony_ci msg = *((u32 *)rx_db); 9678c2ecf20Sopenharmony_ci writel(cpu_to_le32(msg), tgt->ctx_base); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe, 9728c2ecf20Sopenharmony_ci unsigned char *rq_data, u8 num_rq, 9738c2ecf20Sopenharmony_ci struct fcoe_task_ctx_entry *task) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci struct bnx2fc_work *work; 9768c2ecf20Sopenharmony_ci work = kzalloc(sizeof(struct bnx2fc_work), GFP_ATOMIC); 9778c2ecf20Sopenharmony_ci if (!work) 9788c2ecf20Sopenharmony_ci return NULL; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&work->list); 9818c2ecf20Sopenharmony_ci work->tgt = tgt; 9828c2ecf20Sopenharmony_ci work->wqe = wqe; 9838c2ecf20Sopenharmony_ci work->num_rq = num_rq; 9848c2ecf20Sopenharmony_ci work->task = task; 9858c2ecf20Sopenharmony_ci if (rq_data) 9868c2ecf20Sopenharmony_ci memcpy(work->rq_data, rq_data, BNX2FC_RQ_BUF_SZ); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci return work; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci/* Pending work request completion */ 9928c2ecf20Sopenharmony_cistatic bool bnx2fc_pending_work(struct bnx2fc_rport *tgt, unsigned int wqe) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci unsigned int cpu = wqe % num_possible_cpus(); 9958c2ecf20Sopenharmony_ci struct bnx2fc_percpu_s *fps; 9968c2ecf20Sopenharmony_ci struct bnx2fc_work *work; 9978c2ecf20Sopenharmony_ci struct fcoe_task_ctx_entry *task; 9988c2ecf20Sopenharmony_ci struct fcoe_task_ctx_entry *task_page; 9998c2ecf20Sopenharmony_ci struct fcoe_port *port = tgt->port; 10008c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 10018c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 10028c2ecf20Sopenharmony_ci unsigned char *rq_data = NULL; 10038c2ecf20Sopenharmony_ci unsigned char rq_data_buff[BNX2FC_RQ_BUF_SZ]; 10048c2ecf20Sopenharmony_ci int task_idx, index; 10058c2ecf20Sopenharmony_ci u16 xid; 10068c2ecf20Sopenharmony_ci u8 num_rq; 10078c2ecf20Sopenharmony_ci int i; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID; 10108c2ecf20Sopenharmony_ci if (xid >= hba->max_tasks) { 10118c2ecf20Sopenharmony_ci pr_err(PFX "ERROR:xid out of range\n"); 10128c2ecf20Sopenharmony_ci return false; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci task_idx = xid / BNX2FC_TASKS_PER_PAGE; 10168c2ecf20Sopenharmony_ci index = xid % BNX2FC_TASKS_PER_PAGE; 10178c2ecf20Sopenharmony_ci task_page = (struct fcoe_task_ctx_entry *)hba->task_ctx[task_idx]; 10188c2ecf20Sopenharmony_ci task = &task_page[index]; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci num_rq = ((task->rxwr_txrd.var_ctx.rx_flags & 10218c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE) >> 10228c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci memset(rq_data_buff, 0, BNX2FC_RQ_BUF_SZ); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (!num_rq) 10278c2ecf20Sopenharmony_ci goto num_rq_zero; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci rq_data = bnx2fc_get_next_rqe(tgt, 1); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (num_rq > 1) { 10328c2ecf20Sopenharmony_ci /* We do not need extra sense data */ 10338c2ecf20Sopenharmony_ci for (i = 1; i < num_rq; i++) 10348c2ecf20Sopenharmony_ci bnx2fc_get_next_rqe(tgt, 1); 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (rq_data) 10388c2ecf20Sopenharmony_ci memcpy(rq_data_buff, rq_data, BNX2FC_RQ_BUF_SZ); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci /* return RQ entries */ 10418c2ecf20Sopenharmony_ci for (i = 0; i < num_rq; i++) 10428c2ecf20Sopenharmony_ci bnx2fc_return_rqe(tgt, 1); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cinum_rq_zero: 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci fps = &per_cpu(bnx2fc_percpu, cpu); 10478c2ecf20Sopenharmony_ci spin_lock_bh(&fps->fp_work_lock); 10488c2ecf20Sopenharmony_ci if (fps->iothread) { 10498c2ecf20Sopenharmony_ci work = bnx2fc_alloc_work(tgt, wqe, rq_data_buff, 10508c2ecf20Sopenharmony_ci num_rq, task); 10518c2ecf20Sopenharmony_ci if (work) { 10528c2ecf20Sopenharmony_ci list_add_tail(&work->list, &fps->work_list); 10538c2ecf20Sopenharmony_ci wake_up_process(fps->iothread); 10548c2ecf20Sopenharmony_ci spin_unlock_bh(&fps->fp_work_lock); 10558c2ecf20Sopenharmony_ci return true; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci spin_unlock_bh(&fps->fp_work_lock); 10598c2ecf20Sopenharmony_ci bnx2fc_process_cq_compl(tgt, wqe, 10608c2ecf20Sopenharmony_ci rq_data_buff, num_rq, task); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci return true; 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ciint bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci struct fcoe_cqe *cq; 10688c2ecf20Sopenharmony_ci u32 cq_cons; 10698c2ecf20Sopenharmony_ci struct fcoe_cqe *cqe; 10708c2ecf20Sopenharmony_ci u32 num_free_sqes = 0; 10718c2ecf20Sopenharmony_ci u32 num_cqes = 0; 10728c2ecf20Sopenharmony_ci u16 wqe; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* 10758c2ecf20Sopenharmony_ci * cq_lock is a low contention lock used to protect 10768c2ecf20Sopenharmony_ci * the CQ data structure from being freed up during 10778c2ecf20Sopenharmony_ci * the upload operation 10788c2ecf20Sopenharmony_ci */ 10798c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->cq_lock); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (!tgt->cq) { 10828c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "process_new_cqes: cq is NULL\n"); 10838c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->cq_lock); 10848c2ecf20Sopenharmony_ci return 0; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci cq = tgt->cq; 10878c2ecf20Sopenharmony_ci cq_cons = tgt->cq_cons_idx; 10888c2ecf20Sopenharmony_ci cqe = &cq[cq_cons]; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci while (((wqe = cqe->wqe) & FCOE_CQE_TOGGLE_BIT) == 10918c2ecf20Sopenharmony_ci (tgt->cq_curr_toggle_bit << 10928c2ecf20Sopenharmony_ci FCOE_CQE_TOGGLE_BIT_SHIFT)) { 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* new entry on the cq */ 10958c2ecf20Sopenharmony_ci if (wqe & FCOE_CQE_CQE_TYPE) { 10968c2ecf20Sopenharmony_ci /* Unsolicited event notification */ 10978c2ecf20Sopenharmony_ci bnx2fc_process_unsol_compl(tgt, wqe); 10988c2ecf20Sopenharmony_ci } else { 10998c2ecf20Sopenharmony_ci if (bnx2fc_pending_work(tgt, wqe)) 11008c2ecf20Sopenharmony_ci num_free_sqes++; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci cqe++; 11038c2ecf20Sopenharmony_ci tgt->cq_cons_idx++; 11048c2ecf20Sopenharmony_ci num_cqes++; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) { 11078c2ecf20Sopenharmony_ci tgt->cq_cons_idx = 0; 11088c2ecf20Sopenharmony_ci cqe = cq; 11098c2ecf20Sopenharmony_ci tgt->cq_curr_toggle_bit = 11108c2ecf20Sopenharmony_ci 1 - tgt->cq_curr_toggle_bit; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci if (num_cqes) { 11148c2ecf20Sopenharmony_ci /* Arm CQ only if doorbell is mapped */ 11158c2ecf20Sopenharmony_ci if (tgt->ctx_base) 11168c2ecf20Sopenharmony_ci bnx2fc_arm_cq(tgt); 11178c2ecf20Sopenharmony_ci atomic_add(num_free_sqes, &tgt->free_sqes); 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->cq_lock); 11208c2ecf20Sopenharmony_ci return 0; 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci/** 11248c2ecf20Sopenharmony_ci * bnx2fc_fastpath_notification - process global event queue (KCQ) 11258c2ecf20Sopenharmony_ci * 11268c2ecf20Sopenharmony_ci * @hba: adapter structure pointer 11278c2ecf20Sopenharmony_ci * @new_cqe_kcqe: pointer to newly DMA'd KCQ entry 11288c2ecf20Sopenharmony_ci * 11298c2ecf20Sopenharmony_ci * Fast path event notification handler 11308c2ecf20Sopenharmony_ci */ 11318c2ecf20Sopenharmony_cistatic void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba, 11328c2ecf20Sopenharmony_ci struct fcoe_kcqe *new_cqe_kcqe) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci u32 conn_id = new_cqe_kcqe->fcoe_conn_id; 11358c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt = hba->tgt_ofld_list[conn_id]; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (!tgt) { 11388c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "conn_id 0x%x not valid\n", conn_id); 11398c2ecf20Sopenharmony_ci return; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci bnx2fc_process_new_cqes(tgt); 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci/** 11468c2ecf20Sopenharmony_ci * bnx2fc_process_ofld_cmpl - process FCoE session offload completion 11478c2ecf20Sopenharmony_ci * 11488c2ecf20Sopenharmony_ci * @hba: adapter structure pointer 11498c2ecf20Sopenharmony_ci * @ofld_kcqe: connection offload kcqe pointer 11508c2ecf20Sopenharmony_ci * 11518c2ecf20Sopenharmony_ci * handle session offload completion, enable the session if offload is 11528c2ecf20Sopenharmony_ci * successful. 11538c2ecf20Sopenharmony_ci */ 11548c2ecf20Sopenharmony_cistatic void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, 11558c2ecf20Sopenharmony_ci struct fcoe_kcqe *ofld_kcqe) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt; 11588c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 11598c2ecf20Sopenharmony_ci u32 conn_id; 11608c2ecf20Sopenharmony_ci u32 context_id; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci conn_id = ofld_kcqe->fcoe_conn_id; 11638c2ecf20Sopenharmony_ci context_id = ofld_kcqe->fcoe_conn_context_id; 11648c2ecf20Sopenharmony_ci tgt = hba->tgt_ofld_list[conn_id]; 11658c2ecf20Sopenharmony_ci if (!tgt) { 11668c2ecf20Sopenharmony_ci printk(KERN_ALERT PFX "ERROR:ofld_cmpl: No pending ofld req\n"); 11678c2ecf20Sopenharmony_ci return; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Entered ofld compl - context_id = 0x%x\n", 11708c2ecf20Sopenharmony_ci ofld_kcqe->fcoe_conn_context_id); 11718c2ecf20Sopenharmony_ci interface = tgt->port->priv; 11728c2ecf20Sopenharmony_ci if (hba != interface->hba) { 11738c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mis-match\n"); 11748c2ecf20Sopenharmony_ci goto ofld_cmpl_err; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci /* 11778c2ecf20Sopenharmony_ci * cnic has allocated a context_id for this session; use this 11788c2ecf20Sopenharmony_ci * while enabling the session. 11798c2ecf20Sopenharmony_ci */ 11808c2ecf20Sopenharmony_ci tgt->context_id = context_id; 11818c2ecf20Sopenharmony_ci if (ofld_kcqe->completion_status) { 11828c2ecf20Sopenharmony_ci if (ofld_kcqe->completion_status == 11838c2ecf20Sopenharmony_ci FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE) { 11848c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate FCoE context " 11858c2ecf20Sopenharmony_ci "resources\n"); 11868c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_CTX_ALLOC_FAILURE, &tgt->flags); 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci } else { 11898c2ecf20Sopenharmony_ci /* FW offload request successfully completed */ 11908c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ciofld_cmpl_err: 11938c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); 11948c2ecf20Sopenharmony_ci wake_up_interruptible(&tgt->ofld_wait); 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci/** 11988c2ecf20Sopenharmony_ci * bnx2fc_process_enable_conn_cmpl - process FCoE session enable completion 11998c2ecf20Sopenharmony_ci * 12008c2ecf20Sopenharmony_ci * @hba: adapter structure pointer 12018c2ecf20Sopenharmony_ci * @ofld_kcqe: connection offload kcqe pointer 12028c2ecf20Sopenharmony_ci * 12038c2ecf20Sopenharmony_ci * handle session enable completion, mark the rport as ready 12048c2ecf20Sopenharmony_ci */ 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_cistatic void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, 12078c2ecf20Sopenharmony_ci struct fcoe_kcqe *ofld_kcqe) 12088c2ecf20Sopenharmony_ci{ 12098c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt; 12108c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface; 12118c2ecf20Sopenharmony_ci u32 conn_id; 12128c2ecf20Sopenharmony_ci u32 context_id; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci context_id = ofld_kcqe->fcoe_conn_context_id; 12158c2ecf20Sopenharmony_ci conn_id = ofld_kcqe->fcoe_conn_id; 12168c2ecf20Sopenharmony_ci tgt = hba->tgt_ofld_list[conn_id]; 12178c2ecf20Sopenharmony_ci if (!tgt) { 12188c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ERROR:enbl_cmpl: No pending ofld req\n"); 12198c2ecf20Sopenharmony_ci return; 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Enable compl - context_id = 0x%x\n", 12238c2ecf20Sopenharmony_ci ofld_kcqe->fcoe_conn_context_id); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci /* 12268c2ecf20Sopenharmony_ci * context_id should be the same for this target during offload 12278c2ecf20Sopenharmony_ci * and enable 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci if (tgt->context_id != context_id) { 12308c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "context id mis-match\n"); 12318c2ecf20Sopenharmony_ci return; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci interface = tgt->port->priv; 12348c2ecf20Sopenharmony_ci if (hba != interface->hba) { 12358c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mis-match\n"); 12368c2ecf20Sopenharmony_ci goto enbl_cmpl_err; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci if (!ofld_kcqe->completion_status) 12398c2ecf20Sopenharmony_ci /* enable successful - rport ready for issuing IOs */ 12408c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_ENABLED, &tgt->flags); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_cienbl_cmpl_err: 12438c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); 12448c2ecf20Sopenharmony_ci wake_up_interruptible(&tgt->ofld_wait); 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic void bnx2fc_process_conn_disable_cmpl(struct bnx2fc_hba *hba, 12488c2ecf20Sopenharmony_ci struct fcoe_kcqe *disable_kcqe) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt; 12528c2ecf20Sopenharmony_ci u32 conn_id; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci conn_id = disable_kcqe->fcoe_conn_id; 12558c2ecf20Sopenharmony_ci tgt = hba->tgt_ofld_list[conn_id]; 12568c2ecf20Sopenharmony_ci if (!tgt) { 12578c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ERROR: disable_cmpl: No disable req\n"); 12588c2ecf20Sopenharmony_ci return; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, PFX "disable_cmpl: conn_id %d\n", conn_id); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci if (disable_kcqe->completion_status) { 12648c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Disable failed with cmpl status %d\n", 12658c2ecf20Sopenharmony_ci disable_kcqe->completion_status); 12668c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags); 12678c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); 12688c2ecf20Sopenharmony_ci wake_up_interruptible(&tgt->upld_wait); 12698c2ecf20Sopenharmony_ci } else { 12708c2ecf20Sopenharmony_ci /* disable successful */ 12718c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "disable successful\n"); 12728c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); 12738c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_ENABLED, &tgt->flags); 12748c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_DISABLED, &tgt->flags); 12758c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); 12768c2ecf20Sopenharmony_ci wake_up_interruptible(&tgt->upld_wait); 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba, 12818c2ecf20Sopenharmony_ci struct fcoe_kcqe *destroy_kcqe) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt; 12848c2ecf20Sopenharmony_ci u32 conn_id; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci conn_id = destroy_kcqe->fcoe_conn_id; 12878c2ecf20Sopenharmony_ci tgt = hba->tgt_ofld_list[conn_id]; 12888c2ecf20Sopenharmony_ci if (!tgt) { 12898c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "destroy_cmpl: No destroy req\n"); 12908c2ecf20Sopenharmony_ci return; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "destroy_cmpl: conn_id %d\n", conn_id); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if (destroy_kcqe->completion_status) { 12968c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Destroy conn failed, cmpl status %d\n", 12978c2ecf20Sopenharmony_ci destroy_kcqe->completion_status); 12988c2ecf20Sopenharmony_ci return; 12998c2ecf20Sopenharmony_ci } else { 13008c2ecf20Sopenharmony_ci /* destroy successful */ 13018c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "upload successful\n"); 13028c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_DISABLED, &tgt->flags); 13038c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_DESTROYED, &tgt->flags); 13048c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); 13058c2ecf20Sopenharmony_ci wake_up_interruptible(&tgt->upld_wait); 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci switch (err_code) { 13128c2ecf20Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_INVALID_OPCODE: 13138c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "init_failure due to invalid opcode\n"); 13148c2ecf20Sopenharmony_ci break; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE: 13178c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "init failed due to ctx alloc failure\n"); 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR: 13218c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "init_failure due to NIC error\n"); 13228c2ecf20Sopenharmony_ci break; 13238c2ecf20Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_ERROR: 13248c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "init failure due to compl status err\n"); 13258c2ecf20Sopenharmony_ci break; 13268c2ecf20Sopenharmony_ci case FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION: 13278c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "init failure due to HSI mismatch\n"); 13288c2ecf20Sopenharmony_ci break; 13298c2ecf20Sopenharmony_ci default: 13308c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Unknown Error code %d\n", err_code); 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci/** 13358c2ecf20Sopenharmony_ci * bnx2fc_indicae_kcqe - process KCQE 13368c2ecf20Sopenharmony_ci * 13378c2ecf20Sopenharmony_ci * @context: adapter structure pointer 13388c2ecf20Sopenharmony_ci * @kcq: kcqe pointer 13398c2ecf20Sopenharmony_ci * @num_cqe: Number of completion queue elements 13408c2ecf20Sopenharmony_ci * 13418c2ecf20Sopenharmony_ci * Generic KCQ event handler 13428c2ecf20Sopenharmony_ci */ 13438c2ecf20Sopenharmony_civoid bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[], 13448c2ecf20Sopenharmony_ci u32 num_cqe) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context; 13478c2ecf20Sopenharmony_ci int i = 0; 13488c2ecf20Sopenharmony_ci struct fcoe_kcqe *kcqe = NULL; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci while (i < num_cqe) { 13518c2ecf20Sopenharmony_ci kcqe = (struct fcoe_kcqe *) kcq[i++]; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci switch (kcqe->op_code) { 13548c2ecf20Sopenharmony_ci case FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION: 13558c2ecf20Sopenharmony_ci bnx2fc_fastpath_notification(hba, kcqe); 13568c2ecf20Sopenharmony_ci break; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci case FCOE_KCQE_OPCODE_OFFLOAD_CONN: 13598c2ecf20Sopenharmony_ci bnx2fc_process_ofld_cmpl(hba, kcqe); 13608c2ecf20Sopenharmony_ci break; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci case FCOE_KCQE_OPCODE_ENABLE_CONN: 13638c2ecf20Sopenharmony_ci bnx2fc_process_enable_conn_cmpl(hba, kcqe); 13648c2ecf20Sopenharmony_ci break; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci case FCOE_KCQE_OPCODE_INIT_FUNC: 13678c2ecf20Sopenharmony_ci if (kcqe->completion_status != 13688c2ecf20Sopenharmony_ci FCOE_KCQE_COMPLETION_STATUS_SUCCESS) { 13698c2ecf20Sopenharmony_ci bnx2fc_init_failure(hba, 13708c2ecf20Sopenharmony_ci kcqe->completion_status); 13718c2ecf20Sopenharmony_ci } else { 13728c2ecf20Sopenharmony_ci set_bit(ADAPTER_STATE_UP, &hba->adapter_state); 13738c2ecf20Sopenharmony_ci bnx2fc_get_link_state(hba); 13748c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "[%.2x]: FCOE_INIT passed\n", 13758c2ecf20Sopenharmony_ci (u8)hba->pcidev->bus->number); 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci break; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci case FCOE_KCQE_OPCODE_DESTROY_FUNC: 13808c2ecf20Sopenharmony_ci if (kcqe->completion_status != 13818c2ecf20Sopenharmony_ci FCOE_KCQE_COMPLETION_STATUS_SUCCESS) { 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "DESTROY failed\n"); 13848c2ecf20Sopenharmony_ci } else { 13858c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "DESTROY success\n"); 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); 13888c2ecf20Sopenharmony_ci wake_up_interruptible(&hba->destroy_wait); 13898c2ecf20Sopenharmony_ci break; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci case FCOE_KCQE_OPCODE_DISABLE_CONN: 13928c2ecf20Sopenharmony_ci bnx2fc_process_conn_disable_cmpl(hba, kcqe); 13938c2ecf20Sopenharmony_ci break; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci case FCOE_KCQE_OPCODE_DESTROY_CONN: 13968c2ecf20Sopenharmony_ci bnx2fc_process_conn_destroy_cmpl(hba, kcqe); 13978c2ecf20Sopenharmony_ci break; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci case FCOE_KCQE_OPCODE_STAT_FUNC: 14008c2ecf20Sopenharmony_ci if (kcqe->completion_status != 14018c2ecf20Sopenharmony_ci FCOE_KCQE_COMPLETION_STATUS_SUCCESS) 14028c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "STAT failed\n"); 14038c2ecf20Sopenharmony_ci complete(&hba->stat_req_done); 14048c2ecf20Sopenharmony_ci break; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci case FCOE_KCQE_OPCODE_FCOE_ERROR: 14078c2ecf20Sopenharmony_ci default: 14088c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unknown opcode 0x%x\n", 14098c2ecf20Sopenharmony_ci kcqe->op_code); 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_civoid bnx2fc_add_2_sq(struct bnx2fc_rport *tgt, u16 xid) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci struct fcoe_sqe *sqe; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci sqe = &tgt->sq[tgt->sq_prod_idx]; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* Fill SQ WQE */ 14218c2ecf20Sopenharmony_ci sqe->wqe = xid << FCOE_SQE_TASK_ID_SHIFT; 14228c2ecf20Sopenharmony_ci sqe->wqe |= tgt->sq_curr_toggle_bit << FCOE_SQE_TOGGLE_BIT_SHIFT; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci /* Advance SQ Prod Idx */ 14258c2ecf20Sopenharmony_ci if (++tgt->sq_prod_idx == BNX2FC_SQ_WQES_MAX) { 14268c2ecf20Sopenharmony_ci tgt->sq_prod_idx = 0; 14278c2ecf20Sopenharmony_ci tgt->sq_curr_toggle_bit = 1 - tgt->sq_curr_toggle_bit; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci} 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_civoid bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt) 14328c2ecf20Sopenharmony_ci{ 14338c2ecf20Sopenharmony_ci struct b577xx_doorbell_set_prod *sq_db = &tgt->sq_db; 14348c2ecf20Sopenharmony_ci u32 msg; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci wmb(); 14378c2ecf20Sopenharmony_ci sq_db->prod = tgt->sq_prod_idx | 14388c2ecf20Sopenharmony_ci (tgt->sq_curr_toggle_bit << 15); 14398c2ecf20Sopenharmony_ci msg = *((u32 *)sq_db); 14408c2ecf20Sopenharmony_ci writel(cpu_to_le32(msg), tgt->ctx_base); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ciint bnx2fc_map_doorbell(struct bnx2fc_rport *tgt) 14458c2ecf20Sopenharmony_ci{ 14468c2ecf20Sopenharmony_ci u32 context_id = tgt->context_id; 14478c2ecf20Sopenharmony_ci struct fcoe_port *port = tgt->port; 14488c2ecf20Sopenharmony_ci u32 reg_off; 14498c2ecf20Sopenharmony_ci resource_size_t reg_base; 14508c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 14518c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci reg_base = pci_resource_start(hba->pcidev, 14548c2ecf20Sopenharmony_ci BNX2X_DOORBELL_PCI_BAR); 14558c2ecf20Sopenharmony_ci reg_off = (1 << BNX2X_DB_SHIFT) * (context_id & 0x1FFFF); 14568c2ecf20Sopenharmony_ci tgt->ctx_base = ioremap(reg_base + reg_off, 4); 14578c2ecf20Sopenharmony_ci if (!tgt->ctx_base) 14588c2ecf20Sopenharmony_ci return -ENOMEM; 14598c2ecf20Sopenharmony_ci return 0; 14608c2ecf20Sopenharmony_ci} 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_cichar *bnx2fc_get_next_rqe(struct bnx2fc_rport *tgt, u8 num_items) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci char *buf = (char *)tgt->rq + (tgt->rq_cons_idx * BNX2FC_RQ_BUF_SZ); 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (tgt->rq_cons_idx + num_items > BNX2FC_RQ_WQES_MAX) 14678c2ecf20Sopenharmony_ci return NULL; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci tgt->rq_cons_idx += num_items; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if (tgt->rq_cons_idx >= BNX2FC_RQ_WQES_MAX) 14728c2ecf20Sopenharmony_ci tgt->rq_cons_idx -= BNX2FC_RQ_WQES_MAX; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci return buf; 14758c2ecf20Sopenharmony_ci} 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_civoid bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items) 14788c2ecf20Sopenharmony_ci{ 14798c2ecf20Sopenharmony_ci /* return the rq buffer */ 14808c2ecf20Sopenharmony_ci u32 next_prod_idx = tgt->rq_prod_idx + num_items; 14818c2ecf20Sopenharmony_ci if ((next_prod_idx & 0x7fff) == BNX2FC_RQ_WQES_MAX) { 14828c2ecf20Sopenharmony_ci /* Wrap around RQ */ 14838c2ecf20Sopenharmony_ci next_prod_idx += 0x8000 - BNX2FC_RQ_WQES_MAX; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci tgt->rq_prod_idx = next_prod_idx; 14868c2ecf20Sopenharmony_ci tgt->conn_db->rq_prod = tgt->rq_prod_idx; 14878c2ecf20Sopenharmony_ci} 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_civoid bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnp_req, 14908c2ecf20Sopenharmony_ci struct fcoe_task_ctx_entry *task, 14918c2ecf20Sopenharmony_ci struct bnx2fc_cmd *orig_io_req, 14928c2ecf20Sopenharmony_ci u32 offset) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci struct scsi_cmnd *sc_cmd = orig_io_req->sc_cmd; 14958c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt = seq_clnp_req->tgt; 14968c2ecf20Sopenharmony_ci struct fcoe_bd_ctx *bd = orig_io_req->bd_tbl->bd_tbl; 14978c2ecf20Sopenharmony_ci struct fcoe_ext_mul_sges_ctx *sgl; 14988c2ecf20Sopenharmony_ci u8 task_type = FCOE_TASK_TYPE_SEQUENCE_CLEANUP; 14998c2ecf20Sopenharmony_ci u8 orig_task_type; 15008c2ecf20Sopenharmony_ci u16 orig_xid = orig_io_req->xid; 15018c2ecf20Sopenharmony_ci u32 context_id = tgt->context_id; 15028c2ecf20Sopenharmony_ci u64 phys_addr = (u64)orig_io_req->bd_tbl->bd_tbl_dma; 15038c2ecf20Sopenharmony_ci u32 orig_offset = offset; 15048c2ecf20Sopenharmony_ci int bd_count; 15058c2ecf20Sopenharmony_ci int i; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) 15108c2ecf20Sopenharmony_ci orig_task_type = FCOE_TASK_TYPE_WRITE; 15118c2ecf20Sopenharmony_ci else 15128c2ecf20Sopenharmony_ci orig_task_type = FCOE_TASK_TYPE_READ; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci /* Tx flags */ 15158c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.tx_flags = 15168c2ecf20Sopenharmony_ci FCOE_TASK_TX_STATE_SEQUENCE_CLEANUP << 15178c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; 15188c2ecf20Sopenharmony_ci /* init flags */ 15198c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags = task_type << 15208c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; 15218c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << 15228c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; 15238c2ecf20Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 15248c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 15258c2ecf20Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 15268c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_seq_cnt = 0; 15318c2ecf20Sopenharmony_ci task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_data_offset = offset; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci bd_count = orig_io_req->bd_tbl->bd_valid; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci /* obtain the appropriate bd entry from relative offset */ 15368c2ecf20Sopenharmony_ci for (i = 0; i < bd_count; i++) { 15378c2ecf20Sopenharmony_ci if (offset < bd[i].buf_len) 15388c2ecf20Sopenharmony_ci break; 15398c2ecf20Sopenharmony_ci offset -= bd[i].buf_len; 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci phys_addr += (i * sizeof(struct fcoe_bd_ctx)); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (orig_task_type == FCOE_TASK_TYPE_WRITE) { 15448c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = 15458c2ecf20Sopenharmony_ci (u32)phys_addr; 15468c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = 15478c2ecf20Sopenharmony_ci (u32)((u64)phys_addr >> 32); 15488c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = 15498c2ecf20Sopenharmony_ci bd_count; 15508c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_off = 15518c2ecf20Sopenharmony_ci offset; /* adjusted offset */ 15528c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_idx = i; 15538c2ecf20Sopenharmony_ci } else { 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci /* Multiple SGEs were used for this IO */ 15568c2ecf20Sopenharmony_ci sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; 15578c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.lo = (u32)phys_addr; 15588c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.hi = (u32)((u64)phys_addr >> 32); 15598c2ecf20Sopenharmony_ci sgl->mul_sgl.sgl_size = bd_count; 15608c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_off = offset; /*adjusted offset */ 15618c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_idx = i; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci memset(&task->rxwr_only.rx_seq_ctx, 0, 15648c2ecf20Sopenharmony_ci sizeof(struct fcoe_rx_seq_ctx)); 15658c2ecf20Sopenharmony_ci task->rxwr_only.rx_seq_ctx.low_exp_ro = orig_offset; 15668c2ecf20Sopenharmony_ci task->rxwr_only.rx_seq_ctx.high_exp_ro = orig_offset; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_civoid bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req, 15708c2ecf20Sopenharmony_ci struct fcoe_task_ctx_entry *task, 15718c2ecf20Sopenharmony_ci u16 orig_xid) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci u8 task_type = FCOE_TASK_TYPE_EXCHANGE_CLEANUP; 15748c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt = io_req->tgt; 15758c2ecf20Sopenharmony_ci u32 context_id = tgt->context_id; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci /* Tx Write Rx Read */ 15808c2ecf20Sopenharmony_ci /* init flags */ 15818c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags = task_type << 15828c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; 15838c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << 15848c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; 15858c2ecf20Sopenharmony_ci if (tgt->dev_type == TYPE_TAPE) 15868c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 15878c2ecf20Sopenharmony_ci FCOE_TASK_DEV_TYPE_TAPE << 15888c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 15898c2ecf20Sopenharmony_ci else 15908c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 15918c2ecf20Sopenharmony_ci FCOE_TASK_DEV_TYPE_DISK << 15928c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 15938c2ecf20Sopenharmony_ci task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci /* Tx flags */ 15968c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.tx_flags = 15978c2ecf20Sopenharmony_ci FCOE_TASK_TX_STATE_EXCHANGE_CLEANUP << 15988c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci /* Rx Read Tx Write */ 16018c2ecf20Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 16028c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 16038c2ecf20Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_flags |= 1 << 16048c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT; 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_civoid bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req, 16088c2ecf20Sopenharmony_ci struct fcoe_task_ctx_entry *task) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci struct bnx2fc_mp_req *mp_req = &(io_req->mp_req); 16118c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt = io_req->tgt; 16128c2ecf20Sopenharmony_ci struct fc_frame_header *fc_hdr; 16138c2ecf20Sopenharmony_ci struct fcoe_ext_mul_sges_ctx *sgl; 16148c2ecf20Sopenharmony_ci u8 task_type = 0; 16158c2ecf20Sopenharmony_ci u64 *hdr; 16168c2ecf20Sopenharmony_ci u64 temp_hdr[3]; 16178c2ecf20Sopenharmony_ci u32 context_id; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci /* Obtain task_type */ 16218c2ecf20Sopenharmony_ci if ((io_req->cmd_type == BNX2FC_TASK_MGMT_CMD) || 16228c2ecf20Sopenharmony_ci (io_req->cmd_type == BNX2FC_ELS)) { 16238c2ecf20Sopenharmony_ci task_type = FCOE_TASK_TYPE_MIDPATH; 16248c2ecf20Sopenharmony_ci } else if (io_req->cmd_type == BNX2FC_ABTS) { 16258c2ecf20Sopenharmony_ci task_type = FCOE_TASK_TYPE_ABTS; 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* Setup the task from io_req for easy reference */ 16318c2ecf20Sopenharmony_ci io_req->task = task; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "Init MP task for cmd_type = %d task_type = %d\n", 16348c2ecf20Sopenharmony_ci io_req->cmd_type, task_type); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci /* Tx only */ 16378c2ecf20Sopenharmony_ci if ((task_type == FCOE_TASK_TYPE_MIDPATH) || 16388c2ecf20Sopenharmony_ci (task_type == FCOE_TASK_TYPE_UNSOLICITED)) { 16398c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = 16408c2ecf20Sopenharmony_ci (u32)mp_req->mp_req_bd_dma; 16418c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = 16428c2ecf20Sopenharmony_ci (u32)((u64)mp_req->mp_req_bd_dma >> 32); 16438c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = 1; 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci /* Tx Write Rx Read */ 16478c2ecf20Sopenharmony_ci /* init flags */ 16488c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags = task_type << 16498c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; 16508c2ecf20Sopenharmony_ci if (tgt->dev_type == TYPE_TAPE) 16518c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 16528c2ecf20Sopenharmony_ci FCOE_TASK_DEV_TYPE_TAPE << 16538c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 16548c2ecf20Sopenharmony_ci else 16558c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 16568c2ecf20Sopenharmony_ci FCOE_TASK_DEV_TYPE_DISK << 16578c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 16588c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << 16598c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci /* tx flags */ 16628c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.tx_flags = FCOE_TASK_TX_STATE_INIT << 16638c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci /* Rx Write Tx Read */ 16668c2ecf20Sopenharmony_ci task->rxwr_txrd.const_ctx.data_2_trns = io_req->data_xfer_len; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci /* rx flags */ 16698c2ecf20Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_flags |= 1 << 16708c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci context_id = tgt->context_id; 16738c2ecf20Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 16748c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci fc_hdr = &(mp_req->req_fc_hdr); 16778c2ecf20Sopenharmony_ci if (task_type == FCOE_TASK_TYPE_MIDPATH) { 16788c2ecf20Sopenharmony_ci fc_hdr->fh_ox_id = cpu_to_be16(io_req->xid); 16798c2ecf20Sopenharmony_ci fc_hdr->fh_rx_id = htons(0xffff); 16808c2ecf20Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_id = 0xffff; 16818c2ecf20Sopenharmony_ci } else if (task_type == FCOE_TASK_TYPE_UNSOLICITED) { 16828c2ecf20Sopenharmony_ci fc_hdr->fh_rx_id = cpu_to_be16(io_req->xid); 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci /* Fill FC Header into middle path buffer */ 16868c2ecf20Sopenharmony_ci hdr = (u64 *) &task->txwr_rxrd.union_ctx.tx_frame.fc_hdr; 16878c2ecf20Sopenharmony_ci memcpy(temp_hdr, fc_hdr, sizeof(temp_hdr)); 16888c2ecf20Sopenharmony_ci hdr[0] = cpu_to_be64(temp_hdr[0]); 16898c2ecf20Sopenharmony_ci hdr[1] = cpu_to_be64(temp_hdr[1]); 16908c2ecf20Sopenharmony_ci hdr[2] = cpu_to_be64(temp_hdr[2]); 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci /* Rx Only */ 16938c2ecf20Sopenharmony_ci if (task_type == FCOE_TASK_TYPE_MIDPATH) { 16948c2ecf20Sopenharmony_ci sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.lo = (u32)mp_req->mp_resp_bd_dma; 16978c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.hi = 16988c2ecf20Sopenharmony_ci (u32)((u64)mp_req->mp_resp_bd_dma >> 32); 16998c2ecf20Sopenharmony_ci sgl->mul_sgl.sgl_size = 1; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_civoid bnx2fc_init_task(struct bnx2fc_cmd *io_req, 17048c2ecf20Sopenharmony_ci struct fcoe_task_ctx_entry *task) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci u8 task_type; 17078c2ecf20Sopenharmony_ci struct scsi_cmnd *sc_cmd = io_req->sc_cmd; 17088c2ecf20Sopenharmony_ci struct io_bdt *bd_tbl = io_req->bd_tbl; 17098c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt = io_req->tgt; 17108c2ecf20Sopenharmony_ci struct fcoe_cached_sge_ctx *cached_sge; 17118c2ecf20Sopenharmony_ci struct fcoe_ext_mul_sges_ctx *sgl; 17128c2ecf20Sopenharmony_ci int dev_type = tgt->dev_type; 17138c2ecf20Sopenharmony_ci u64 *fcp_cmnd; 17148c2ecf20Sopenharmony_ci u64 tmp_fcp_cmnd[4]; 17158c2ecf20Sopenharmony_ci u32 context_id; 17168c2ecf20Sopenharmony_ci int cnt, i; 17178c2ecf20Sopenharmony_ci int bd_count; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci /* Setup the task from io_req for easy reference */ 17228c2ecf20Sopenharmony_ci io_req->task = task; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) 17258c2ecf20Sopenharmony_ci task_type = FCOE_TASK_TYPE_WRITE; 17268c2ecf20Sopenharmony_ci else 17278c2ecf20Sopenharmony_ci task_type = FCOE_TASK_TYPE_READ; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci /* Tx only */ 17308c2ecf20Sopenharmony_ci bd_count = bd_tbl->bd_valid; 17318c2ecf20Sopenharmony_ci cached_sge = &task->rxwr_only.union_ctx.read_info.sgl_ctx.cached_sge; 17328c2ecf20Sopenharmony_ci if (task_type == FCOE_TASK_TYPE_WRITE) { 17338c2ecf20Sopenharmony_ci if ((dev_type == TYPE_DISK) && (bd_count == 1)) { 17348c2ecf20Sopenharmony_ci struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.lo = 17378c2ecf20Sopenharmony_ci cached_sge->cur_buf_addr.lo = 17388c2ecf20Sopenharmony_ci fcoe_bd_tbl->buf_addr_lo; 17398c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.hi = 17408c2ecf20Sopenharmony_ci cached_sge->cur_buf_addr.hi = 17418c2ecf20Sopenharmony_ci fcoe_bd_tbl->buf_addr_hi; 17428c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.cached_sge.cur_buf_rem = 17438c2ecf20Sopenharmony_ci cached_sge->cur_buf_rem = 17448c2ecf20Sopenharmony_ci fcoe_bd_tbl->buf_len; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 1 << 17478c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; 17488c2ecf20Sopenharmony_ci } else { 17498c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = 17508c2ecf20Sopenharmony_ci (u32)bd_tbl->bd_tbl_dma; 17518c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = 17528c2ecf20Sopenharmony_ci (u32)((u64)bd_tbl->bd_tbl_dma >> 32); 17538c2ecf20Sopenharmony_ci task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = 17548c2ecf20Sopenharmony_ci bd_tbl->bd_valid; 17558c2ecf20Sopenharmony_ci } 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci /*Tx Write Rx Read */ 17598c2ecf20Sopenharmony_ci /* Init state to NORMAL */ 17608c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= task_type << 17618c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; 17628c2ecf20Sopenharmony_ci if (dev_type == TYPE_TAPE) { 17638c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 17648c2ecf20Sopenharmony_ci FCOE_TASK_DEV_TYPE_TAPE << 17658c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 17668c2ecf20Sopenharmony_ci io_req->rec_retry = 0; 17678c2ecf20Sopenharmony_ci io_req->rec_retry = 0; 17688c2ecf20Sopenharmony_ci } else 17698c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 17708c2ecf20Sopenharmony_ci FCOE_TASK_DEV_TYPE_DISK << 17718c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; 17728c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << 17738c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; 17748c2ecf20Sopenharmony_ci /* tx flags */ 17758c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.tx_flags = FCOE_TASK_TX_STATE_NORMAL << 17768c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci /* Set initial seq counter */ 17798c2ecf20Sopenharmony_ci task->txwr_rxrd.union_ctx.tx_seq.ctx.seq_cnt = 1; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci /* Fill FCP_CMND IU */ 17828c2ecf20Sopenharmony_ci fcp_cmnd = (u64 *) 17838c2ecf20Sopenharmony_ci task->txwr_rxrd.union_ctx.fcp_cmd.opaque; 17848c2ecf20Sopenharmony_ci bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)&tmp_fcp_cmnd); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci /* swap fcp_cmnd */ 17878c2ecf20Sopenharmony_ci cnt = sizeof(struct fcp_cmnd) / sizeof(u64); 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 17908c2ecf20Sopenharmony_ci *fcp_cmnd = cpu_to_be64(tmp_fcp_cmnd[i]); 17918c2ecf20Sopenharmony_ci fcp_cmnd++; 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci /* Rx Write Tx Read */ 17958c2ecf20Sopenharmony_ci task->rxwr_txrd.const_ctx.data_2_trns = io_req->data_xfer_len; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci context_id = tgt->context_id; 17988c2ecf20Sopenharmony_ci task->rxwr_txrd.const_ctx.init_flags = context_id << 17998c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci /* rx flags */ 18028c2ecf20Sopenharmony_ci /* Set state to "waiting for the first packet" */ 18038c2ecf20Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_flags |= 1 << 18048c2ecf20Sopenharmony_ci FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci task->rxwr_txrd.var_ctx.rx_id = 0xffff; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci /* Rx Only */ 18098c2ecf20Sopenharmony_ci if (task_type != FCOE_TASK_TYPE_READ) 18108c2ecf20Sopenharmony_ci return; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; 18138c2ecf20Sopenharmony_ci bd_count = bd_tbl->bd_valid; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (dev_type == TYPE_DISK) { 18168c2ecf20Sopenharmony_ci if (bd_count == 1) { 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci cached_sge->cur_buf_addr.lo = fcoe_bd_tbl->buf_addr_lo; 18218c2ecf20Sopenharmony_ci cached_sge->cur_buf_addr.hi = fcoe_bd_tbl->buf_addr_hi; 18228c2ecf20Sopenharmony_ci cached_sge->cur_buf_rem = fcoe_bd_tbl->buf_len; 18238c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 1 << 18248c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; 18258c2ecf20Sopenharmony_ci } else if (bd_count == 2) { 18268c2ecf20Sopenharmony_ci struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci cached_sge->cur_buf_addr.lo = fcoe_bd_tbl->buf_addr_lo; 18298c2ecf20Sopenharmony_ci cached_sge->cur_buf_addr.hi = fcoe_bd_tbl->buf_addr_hi; 18308c2ecf20Sopenharmony_ci cached_sge->cur_buf_rem = fcoe_bd_tbl->buf_len; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci fcoe_bd_tbl++; 18338c2ecf20Sopenharmony_ci cached_sge->second_buf_addr.lo = 18348c2ecf20Sopenharmony_ci fcoe_bd_tbl->buf_addr_lo; 18358c2ecf20Sopenharmony_ci cached_sge->second_buf_addr.hi = 18368c2ecf20Sopenharmony_ci fcoe_bd_tbl->buf_addr_hi; 18378c2ecf20Sopenharmony_ci cached_sge->second_buf_rem = fcoe_bd_tbl->buf_len; 18388c2ecf20Sopenharmony_ci task->txwr_rxrd.const_ctx.init_flags |= 1 << 18398c2ecf20Sopenharmony_ci FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; 18408c2ecf20Sopenharmony_ci } else { 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma; 18438c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.hi = 18448c2ecf20Sopenharmony_ci (u32)((u64)bd_tbl->bd_tbl_dma >> 32); 18458c2ecf20Sopenharmony_ci sgl->mul_sgl.sgl_size = bd_count; 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci } else { 18488c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma; 18498c2ecf20Sopenharmony_ci sgl->mul_sgl.cur_sge_addr.hi = 18508c2ecf20Sopenharmony_ci (u32)((u64)bd_tbl->bd_tbl_dma >> 32); 18518c2ecf20Sopenharmony_ci sgl->mul_sgl.sgl_size = bd_count; 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci} 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci/** 18568c2ecf20Sopenharmony_ci * bnx2fc_setup_task_ctx - allocate and map task context 18578c2ecf20Sopenharmony_ci * 18588c2ecf20Sopenharmony_ci * @hba: pointer to adapter structure 18598c2ecf20Sopenharmony_ci * 18608c2ecf20Sopenharmony_ci * allocate memory for task context, and associated BD table to be used 18618c2ecf20Sopenharmony_ci * by firmware 18628c2ecf20Sopenharmony_ci * 18638c2ecf20Sopenharmony_ci */ 18648c2ecf20Sopenharmony_ciint bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba) 18658c2ecf20Sopenharmony_ci{ 18668c2ecf20Sopenharmony_ci int rc = 0; 18678c2ecf20Sopenharmony_ci struct regpair *task_ctx_bdt; 18688c2ecf20Sopenharmony_ci dma_addr_t addr; 18698c2ecf20Sopenharmony_ci int task_ctx_arr_sz; 18708c2ecf20Sopenharmony_ci int i; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci /* 18738c2ecf20Sopenharmony_ci * Allocate task context bd table. A page size of bd table 18748c2ecf20Sopenharmony_ci * can map 256 buffers. Each buffer contains 32 task context 18758c2ecf20Sopenharmony_ci * entries. Hence the limit with one page is 8192 task context 18768c2ecf20Sopenharmony_ci * entries. 18778c2ecf20Sopenharmony_ci */ 18788c2ecf20Sopenharmony_ci hba->task_ctx_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, 18798c2ecf20Sopenharmony_ci PAGE_SIZE, 18808c2ecf20Sopenharmony_ci &hba->task_ctx_bd_dma, 18818c2ecf20Sopenharmony_ci GFP_KERNEL); 18828c2ecf20Sopenharmony_ci if (!hba->task_ctx_bd_tbl) { 18838c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate task context BDT\n"); 18848c2ecf20Sopenharmony_ci rc = -1; 18858c2ecf20Sopenharmony_ci goto out; 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci /* 18898c2ecf20Sopenharmony_ci * Allocate task_ctx which is an array of pointers pointing to 18908c2ecf20Sopenharmony_ci * a page containing 32 task contexts 18918c2ecf20Sopenharmony_ci */ 18928c2ecf20Sopenharmony_ci task_ctx_arr_sz = (hba->max_tasks / BNX2FC_TASKS_PER_PAGE); 18938c2ecf20Sopenharmony_ci hba->task_ctx = kzalloc((task_ctx_arr_sz * sizeof(void *)), 18948c2ecf20Sopenharmony_ci GFP_KERNEL); 18958c2ecf20Sopenharmony_ci if (!hba->task_ctx) { 18968c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate task context array\n"); 18978c2ecf20Sopenharmony_ci rc = -1; 18988c2ecf20Sopenharmony_ci goto out1; 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci /* 19028c2ecf20Sopenharmony_ci * Allocate task_ctx_dma which is an array of dma addresses 19038c2ecf20Sopenharmony_ci */ 19048c2ecf20Sopenharmony_ci hba->task_ctx_dma = kmalloc((task_ctx_arr_sz * 19058c2ecf20Sopenharmony_ci sizeof(dma_addr_t)), GFP_KERNEL); 19068c2ecf20Sopenharmony_ci if (!hba->task_ctx_dma) { 19078c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to alloc context mapping array\n"); 19088c2ecf20Sopenharmony_ci rc = -1; 19098c2ecf20Sopenharmony_ci goto out2; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci task_ctx_bdt = (struct regpair *)hba->task_ctx_bd_tbl; 19138c2ecf20Sopenharmony_ci for (i = 0; i < task_ctx_arr_sz; i++) { 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci hba->task_ctx[i] = dma_alloc_coherent(&hba->pcidev->dev, 19168c2ecf20Sopenharmony_ci PAGE_SIZE, 19178c2ecf20Sopenharmony_ci &hba->task_ctx_dma[i], 19188c2ecf20Sopenharmony_ci GFP_KERNEL); 19198c2ecf20Sopenharmony_ci if (!hba->task_ctx[i]) { 19208c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to alloc task context\n"); 19218c2ecf20Sopenharmony_ci rc = -1; 19228c2ecf20Sopenharmony_ci goto out3; 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci addr = (u64)hba->task_ctx_dma[i]; 19258c2ecf20Sopenharmony_ci task_ctx_bdt->hi = cpu_to_le32((u64)addr >> 32); 19268c2ecf20Sopenharmony_ci task_ctx_bdt->lo = cpu_to_le32((u32)addr); 19278c2ecf20Sopenharmony_ci task_ctx_bdt++; 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci return 0; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ciout3: 19328c2ecf20Sopenharmony_ci for (i = 0; i < task_ctx_arr_sz; i++) { 19338c2ecf20Sopenharmony_ci if (hba->task_ctx[i]) { 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 19368c2ecf20Sopenharmony_ci hba->task_ctx[i], hba->task_ctx_dma[i]); 19378c2ecf20Sopenharmony_ci hba->task_ctx[i] = NULL; 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci kfree(hba->task_ctx_dma); 19428c2ecf20Sopenharmony_ci hba->task_ctx_dma = NULL; 19438c2ecf20Sopenharmony_ciout2: 19448c2ecf20Sopenharmony_ci kfree(hba->task_ctx); 19458c2ecf20Sopenharmony_ci hba->task_ctx = NULL; 19468c2ecf20Sopenharmony_ciout1: 19478c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 19488c2ecf20Sopenharmony_ci hba->task_ctx_bd_tbl, hba->task_ctx_bd_dma); 19498c2ecf20Sopenharmony_ci hba->task_ctx_bd_tbl = NULL; 19508c2ecf20Sopenharmony_ciout: 19518c2ecf20Sopenharmony_ci return rc; 19528c2ecf20Sopenharmony_ci} 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_civoid bnx2fc_free_task_ctx(struct bnx2fc_hba *hba) 19558c2ecf20Sopenharmony_ci{ 19568c2ecf20Sopenharmony_ci int task_ctx_arr_sz; 19578c2ecf20Sopenharmony_ci int i; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci if (hba->task_ctx_bd_tbl) { 19608c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 19618c2ecf20Sopenharmony_ci hba->task_ctx_bd_tbl, 19628c2ecf20Sopenharmony_ci hba->task_ctx_bd_dma); 19638c2ecf20Sopenharmony_ci hba->task_ctx_bd_tbl = NULL; 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci task_ctx_arr_sz = (hba->max_tasks / BNX2FC_TASKS_PER_PAGE); 19678c2ecf20Sopenharmony_ci if (hba->task_ctx) { 19688c2ecf20Sopenharmony_ci for (i = 0; i < task_ctx_arr_sz; i++) { 19698c2ecf20Sopenharmony_ci if (hba->task_ctx[i]) { 19708c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 19718c2ecf20Sopenharmony_ci hba->task_ctx[i], 19728c2ecf20Sopenharmony_ci hba->task_ctx_dma[i]); 19738c2ecf20Sopenharmony_ci hba->task_ctx[i] = NULL; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci kfree(hba->task_ctx); 19778c2ecf20Sopenharmony_ci hba->task_ctx = NULL; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci kfree(hba->task_ctx_dma); 19818c2ecf20Sopenharmony_ci hba->task_ctx_dma = NULL; 19828c2ecf20Sopenharmony_ci} 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_cistatic void bnx2fc_free_hash_table(struct bnx2fc_hba *hba) 19858c2ecf20Sopenharmony_ci{ 19868c2ecf20Sopenharmony_ci int i; 19878c2ecf20Sopenharmony_ci int segment_count; 19888c2ecf20Sopenharmony_ci u32 *pbl; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci if (hba->hash_tbl_segments) { 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci pbl = hba->hash_tbl_pbl; 19938c2ecf20Sopenharmony_ci if (pbl) { 19948c2ecf20Sopenharmony_ci segment_count = hba->hash_tbl_segment_count; 19958c2ecf20Sopenharmony_ci for (i = 0; i < segment_count; ++i) { 19968c2ecf20Sopenharmony_ci dma_addr_t dma_address; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci dma_address = le32_to_cpu(*pbl); 19998c2ecf20Sopenharmony_ci ++pbl; 20008c2ecf20Sopenharmony_ci dma_address += ((u64)le32_to_cpu(*pbl)) << 32; 20018c2ecf20Sopenharmony_ci ++pbl; 20028c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, 20038c2ecf20Sopenharmony_ci BNX2FC_HASH_TBL_CHUNK_SIZE, 20048c2ecf20Sopenharmony_ci hba->hash_tbl_segments[i], 20058c2ecf20Sopenharmony_ci dma_address); 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci } 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci kfree(hba->hash_tbl_segments); 20108c2ecf20Sopenharmony_ci hba->hash_tbl_segments = NULL; 20118c2ecf20Sopenharmony_ci } 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci if (hba->hash_tbl_pbl) { 20148c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 20158c2ecf20Sopenharmony_ci hba->hash_tbl_pbl, 20168c2ecf20Sopenharmony_ci hba->hash_tbl_pbl_dma); 20178c2ecf20Sopenharmony_ci hba->hash_tbl_pbl = NULL; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_cistatic int bnx2fc_allocate_hash_table(struct bnx2fc_hba *hba) 20228c2ecf20Sopenharmony_ci{ 20238c2ecf20Sopenharmony_ci int i; 20248c2ecf20Sopenharmony_ci int hash_table_size; 20258c2ecf20Sopenharmony_ci int segment_count; 20268c2ecf20Sopenharmony_ci int segment_array_size; 20278c2ecf20Sopenharmony_ci int dma_segment_array_size; 20288c2ecf20Sopenharmony_ci dma_addr_t *dma_segment_array; 20298c2ecf20Sopenharmony_ci u32 *pbl; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci hash_table_size = BNX2FC_NUM_MAX_SESS * BNX2FC_MAX_ROWS_IN_HASH_TBL * 20328c2ecf20Sopenharmony_ci sizeof(struct fcoe_hash_table_entry); 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci segment_count = hash_table_size + BNX2FC_HASH_TBL_CHUNK_SIZE - 1; 20358c2ecf20Sopenharmony_ci segment_count /= BNX2FC_HASH_TBL_CHUNK_SIZE; 20368c2ecf20Sopenharmony_ci hba->hash_tbl_segment_count = segment_count; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci segment_array_size = segment_count * sizeof(*hba->hash_tbl_segments); 20398c2ecf20Sopenharmony_ci hba->hash_tbl_segments = kzalloc(segment_array_size, GFP_KERNEL); 20408c2ecf20Sopenharmony_ci if (!hba->hash_tbl_segments) { 20418c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "hash table pointers alloc failed\n"); 20428c2ecf20Sopenharmony_ci return -ENOMEM; 20438c2ecf20Sopenharmony_ci } 20448c2ecf20Sopenharmony_ci dma_segment_array_size = segment_count * sizeof(*dma_segment_array); 20458c2ecf20Sopenharmony_ci dma_segment_array = kzalloc(dma_segment_array_size, GFP_KERNEL); 20468c2ecf20Sopenharmony_ci if (!dma_segment_array) { 20478c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "hash table pointers (dma) alloc failed\n"); 20488c2ecf20Sopenharmony_ci goto cleanup_ht; 20498c2ecf20Sopenharmony_ci } 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci for (i = 0; i < segment_count; ++i) { 20528c2ecf20Sopenharmony_ci hba->hash_tbl_segments[i] = dma_alloc_coherent(&hba->pcidev->dev, 20538c2ecf20Sopenharmony_ci BNX2FC_HASH_TBL_CHUNK_SIZE, 20548c2ecf20Sopenharmony_ci &dma_segment_array[i], 20558c2ecf20Sopenharmony_ci GFP_KERNEL); 20568c2ecf20Sopenharmony_ci if (!hba->hash_tbl_segments[i]) { 20578c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "hash segment alloc failed\n"); 20588c2ecf20Sopenharmony_ci goto cleanup_dma; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci hba->hash_tbl_pbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, 20638c2ecf20Sopenharmony_ci &hba->hash_tbl_pbl_dma, 20648c2ecf20Sopenharmony_ci GFP_KERNEL); 20658c2ecf20Sopenharmony_ci if (!hba->hash_tbl_pbl) { 20668c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "hash table pbl alloc failed\n"); 20678c2ecf20Sopenharmony_ci goto cleanup_dma; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci pbl = hba->hash_tbl_pbl; 20718c2ecf20Sopenharmony_ci for (i = 0; i < segment_count; ++i) { 20728c2ecf20Sopenharmony_ci u64 paddr = dma_segment_array[i]; 20738c2ecf20Sopenharmony_ci *pbl = cpu_to_le32((u32) paddr); 20748c2ecf20Sopenharmony_ci ++pbl; 20758c2ecf20Sopenharmony_ci *pbl = cpu_to_le32((u32) (paddr >> 32)); 20768c2ecf20Sopenharmony_ci ++pbl; 20778c2ecf20Sopenharmony_ci } 20788c2ecf20Sopenharmony_ci pbl = hba->hash_tbl_pbl; 20798c2ecf20Sopenharmony_ci i = 0; 20808c2ecf20Sopenharmony_ci while (*pbl && *(pbl + 1)) { 20818c2ecf20Sopenharmony_ci ++pbl; 20828c2ecf20Sopenharmony_ci ++pbl; 20838c2ecf20Sopenharmony_ci ++i; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci kfree(dma_segment_array); 20868c2ecf20Sopenharmony_ci return 0; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_cicleanup_dma: 20898c2ecf20Sopenharmony_ci for (i = 0; i < segment_count; ++i) { 20908c2ecf20Sopenharmony_ci if (hba->hash_tbl_segments[i]) 20918c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, 20928c2ecf20Sopenharmony_ci BNX2FC_HASH_TBL_CHUNK_SIZE, 20938c2ecf20Sopenharmony_ci hba->hash_tbl_segments[i], 20948c2ecf20Sopenharmony_ci dma_segment_array[i]); 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci kfree(dma_segment_array); 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_cicleanup_ht: 21008c2ecf20Sopenharmony_ci kfree(hba->hash_tbl_segments); 21018c2ecf20Sopenharmony_ci hba->hash_tbl_segments = NULL; 21028c2ecf20Sopenharmony_ci return -ENOMEM; 21038c2ecf20Sopenharmony_ci} 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci/** 21068c2ecf20Sopenharmony_ci * bnx2fc_setup_fw_resc - Allocate and map hash table and dummy buffer 21078c2ecf20Sopenharmony_ci * 21088c2ecf20Sopenharmony_ci * @hba: Pointer to adapter structure 21098c2ecf20Sopenharmony_ci * 21108c2ecf20Sopenharmony_ci */ 21118c2ecf20Sopenharmony_ciint bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba) 21128c2ecf20Sopenharmony_ci{ 21138c2ecf20Sopenharmony_ci u64 addr; 21148c2ecf20Sopenharmony_ci u32 mem_size; 21158c2ecf20Sopenharmony_ci int i; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci if (bnx2fc_allocate_hash_table(hba)) 21188c2ecf20Sopenharmony_ci return -ENOMEM; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct regpair); 21218c2ecf20Sopenharmony_ci hba->t2_hash_tbl_ptr = dma_alloc_coherent(&hba->pcidev->dev, mem_size, 21228c2ecf20Sopenharmony_ci &hba->t2_hash_tbl_ptr_dma, 21238c2ecf20Sopenharmony_ci GFP_KERNEL); 21248c2ecf20Sopenharmony_ci if (!hba->t2_hash_tbl_ptr) { 21258c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate t2 hash table ptr\n"); 21268c2ecf20Sopenharmony_ci bnx2fc_free_fw_resc(hba); 21278c2ecf20Sopenharmony_ci return -ENOMEM; 21288c2ecf20Sopenharmony_ci } 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci mem_size = BNX2FC_NUM_MAX_SESS * 21318c2ecf20Sopenharmony_ci sizeof(struct fcoe_t2_hash_table_entry); 21328c2ecf20Sopenharmony_ci hba->t2_hash_tbl = dma_alloc_coherent(&hba->pcidev->dev, mem_size, 21338c2ecf20Sopenharmony_ci &hba->t2_hash_tbl_dma, 21348c2ecf20Sopenharmony_ci GFP_KERNEL); 21358c2ecf20Sopenharmony_ci if (!hba->t2_hash_tbl) { 21368c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate t2 hash table\n"); 21378c2ecf20Sopenharmony_ci bnx2fc_free_fw_resc(hba); 21388c2ecf20Sopenharmony_ci return -ENOMEM; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) { 21418c2ecf20Sopenharmony_ci addr = (unsigned long) hba->t2_hash_tbl_dma + 21428c2ecf20Sopenharmony_ci ((i+1) * sizeof(struct fcoe_t2_hash_table_entry)); 21438c2ecf20Sopenharmony_ci hba->t2_hash_tbl[i].next.lo = addr & 0xffffffff; 21448c2ecf20Sopenharmony_ci hba->t2_hash_tbl[i].next.hi = addr >> 32; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, 21488c2ecf20Sopenharmony_ci PAGE_SIZE, &hba->dummy_buf_dma, 21498c2ecf20Sopenharmony_ci GFP_KERNEL); 21508c2ecf20Sopenharmony_ci if (!hba->dummy_buffer) { 21518c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to alloc MP Dummy Buffer\n"); 21528c2ecf20Sopenharmony_ci bnx2fc_free_fw_resc(hba); 21538c2ecf20Sopenharmony_ci return -ENOMEM; 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci hba->stats_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, 21578c2ecf20Sopenharmony_ci &hba->stats_buf_dma, 21588c2ecf20Sopenharmony_ci GFP_KERNEL); 21598c2ecf20Sopenharmony_ci if (!hba->stats_buffer) { 21608c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to alloc Stats Buffer\n"); 21618c2ecf20Sopenharmony_ci bnx2fc_free_fw_resc(hba); 21628c2ecf20Sopenharmony_ci return -ENOMEM; 21638c2ecf20Sopenharmony_ci } 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci return 0; 21668c2ecf20Sopenharmony_ci} 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_civoid bnx2fc_free_fw_resc(struct bnx2fc_hba *hba) 21698c2ecf20Sopenharmony_ci{ 21708c2ecf20Sopenharmony_ci u32 mem_size; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci if (hba->stats_buffer) { 21738c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 21748c2ecf20Sopenharmony_ci hba->stats_buffer, hba->stats_buf_dma); 21758c2ecf20Sopenharmony_ci hba->stats_buffer = NULL; 21768c2ecf20Sopenharmony_ci } 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci if (hba->dummy_buffer) { 21798c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, 21808c2ecf20Sopenharmony_ci hba->dummy_buffer, hba->dummy_buf_dma); 21818c2ecf20Sopenharmony_ci hba->dummy_buffer = NULL; 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci if (hba->t2_hash_tbl_ptr) { 21858c2ecf20Sopenharmony_ci mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct regpair); 21868c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, mem_size, 21878c2ecf20Sopenharmony_ci hba->t2_hash_tbl_ptr, 21888c2ecf20Sopenharmony_ci hba->t2_hash_tbl_ptr_dma); 21898c2ecf20Sopenharmony_ci hba->t2_hash_tbl_ptr = NULL; 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci if (hba->t2_hash_tbl) { 21938c2ecf20Sopenharmony_ci mem_size = BNX2FC_NUM_MAX_SESS * 21948c2ecf20Sopenharmony_ci sizeof(struct fcoe_t2_hash_table_entry); 21958c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, mem_size, 21968c2ecf20Sopenharmony_ci hba->t2_hash_tbl, hba->t2_hash_tbl_dma); 21978c2ecf20Sopenharmony_ci hba->t2_hash_tbl = NULL; 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci bnx2fc_free_hash_table(hba); 22008c2ecf20Sopenharmony_ci} 2201