18c2ecf20Sopenharmony_ci/* bnx2fc_tgt.c: QLogic Linux FCoE offload driver. 28c2ecf20Sopenharmony_ci * Handles operations such as session offload/upload etc, and manages 38c2ecf20Sopenharmony_ci * session resources such as connection id and qp resources. 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_cistatic void bnx2fc_upld_timer(struct timer_list *t); 188c2ecf20Sopenharmony_cistatic void bnx2fc_ofld_timer(struct timer_list *t); 198c2ecf20Sopenharmony_cistatic int bnx2fc_init_tgt(struct bnx2fc_rport *tgt, 208c2ecf20Sopenharmony_ci struct fcoe_port *port, 218c2ecf20Sopenharmony_ci struct fc_rport_priv *rdata); 228c2ecf20Sopenharmony_cistatic u32 bnx2fc_alloc_conn_id(struct bnx2fc_hba *hba, 238c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt); 248c2ecf20Sopenharmony_cistatic int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, 258c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt); 268c2ecf20Sopenharmony_cistatic void bnx2fc_free_session_resc(struct bnx2fc_hba *hba, 278c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt); 288c2ecf20Sopenharmony_cistatic void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic void bnx2fc_upld_timer(struct timer_list *t) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt = from_timer(tgt, t, upld_timer); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "upld_timer - Upload compl not received!!\n"); 368c2ecf20Sopenharmony_ci /* fake upload completion */ 378c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); 388c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_ENABLED, &tgt->flags); 398c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); 408c2ecf20Sopenharmony_ci wake_up_interruptible(&tgt->upld_wait); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void bnx2fc_ofld_timer(struct timer_list *t) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt = from_timer(tgt, t, ofld_timer); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "entered bnx2fc_ofld_timer\n"); 498c2ecf20Sopenharmony_ci /* NOTE: This function should never be called, as 508c2ecf20Sopenharmony_ci * offload should never timeout 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci /* 538c2ecf20Sopenharmony_ci * If the timer has expired, this session is dead 548c2ecf20Sopenharmony_ci * Clear offloaded flag and logout of this device. 558c2ecf20Sopenharmony_ci * Since OFFLOADED flag is cleared, this case 568c2ecf20Sopenharmony_ci * will be considered as offload error and the 578c2ecf20Sopenharmony_ci * port will be logged off, and conn_id, session 588c2ecf20Sopenharmony_ci * resources are freed up in bnx2fc_offload_session 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); 618c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_ENABLED, &tgt->flags); 628c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); 638c2ecf20Sopenharmony_ci wake_up_interruptible(&tgt->ofld_wait); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic void bnx2fc_ofld_wait(struct bnx2fc_rport *tgt) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci timer_setup(&tgt->ofld_timer, bnx2fc_ofld_timer, 0); 698c2ecf20Sopenharmony_ci mod_timer(&tgt->ofld_timer, jiffies + BNX2FC_FW_TIMEOUT); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci wait_event_interruptible(tgt->ofld_wait, 728c2ecf20Sopenharmony_ci (test_bit( 738c2ecf20Sopenharmony_ci BNX2FC_FLAG_OFLD_REQ_CMPL, 748c2ecf20Sopenharmony_ci &tgt->flags))); 758c2ecf20Sopenharmony_ci if (signal_pending(current)) 768c2ecf20Sopenharmony_ci flush_signals(current); 778c2ecf20Sopenharmony_ci del_timer_sync(&tgt->ofld_timer); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void bnx2fc_offload_session(struct fcoe_port *port, 818c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt, 828c2ecf20Sopenharmony_ci struct fc_rport_priv *rdata) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct fc_rport *rport = rdata->rport; 858c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 868c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 878c2ecf20Sopenharmony_ci int rval; 888c2ecf20Sopenharmony_ci int i = 0; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* Initialize bnx2fc_rport */ 918c2ecf20Sopenharmony_ci /* NOTE: tgt is already bzero'd */ 928c2ecf20Sopenharmony_ci rval = bnx2fc_init_tgt(tgt, port, rdata); 938c2ecf20Sopenharmony_ci if (rval) { 948c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Failed to allocate conn id for " 958c2ecf20Sopenharmony_ci "port_id (%6x)\n", rport->port_id); 968c2ecf20Sopenharmony_ci goto tgt_init_err; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* Allocate session resources */ 1008c2ecf20Sopenharmony_ci rval = bnx2fc_alloc_session_resc(hba, tgt); 1018c2ecf20Sopenharmony_ci if (rval) { 1028c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Failed to allocate resources\n"); 1038c2ecf20Sopenharmony_ci goto ofld_err; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * Initialize FCoE session offload process. 1088c2ecf20Sopenharmony_ci * Upon completion of offload process add 1098c2ecf20Sopenharmony_ci * rport to list of rports 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ciretry_ofld: 1128c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); 1138c2ecf20Sopenharmony_ci rval = bnx2fc_send_session_ofld_req(port, tgt); 1148c2ecf20Sopenharmony_ci if (rval) { 1158c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ofld_req failed\n"); 1168c2ecf20Sopenharmony_ci goto ofld_err; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * wait for the session is offloaded and enabled. 3 Secs 1218c2ecf20Sopenharmony_ci * should be ample time for this process to complete. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci bnx2fc_ofld_wait(tgt); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (!(test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags))) { 1268c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNX2FC_FLAG_CTX_ALLOC_FAILURE, 1278c2ecf20Sopenharmony_ci &tgt->flags)) { 1288c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "ctx_alloc_failure, " 1298c2ecf20Sopenharmony_ci "retry ofld..%d\n", i++); 1308c2ecf20Sopenharmony_ci msleep_interruptible(1000); 1318c2ecf20Sopenharmony_ci if (i > 3) { 1328c2ecf20Sopenharmony_ci i = 0; 1338c2ecf20Sopenharmony_ci goto ofld_err; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci goto retry_ofld; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci goto ofld_err; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci if (bnx2fc_map_doorbell(tgt)) { 1408c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "map doorbell failed - no mem\n"); 1418c2ecf20Sopenharmony_ci goto ofld_err; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); 1448c2ecf20Sopenharmony_ci rval = bnx2fc_send_session_enable_req(port, tgt); 1458c2ecf20Sopenharmony_ci if (rval) { 1468c2ecf20Sopenharmony_ci pr_err(PFX "enable session failed\n"); 1478c2ecf20Sopenharmony_ci goto ofld_err; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci bnx2fc_ofld_wait(tgt); 1508c2ecf20Sopenharmony_ci if (!(test_bit(BNX2FC_FLAG_ENABLED, &tgt->flags))) 1518c2ecf20Sopenharmony_ci goto ofld_err; 1528c2ecf20Sopenharmony_ci return; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ciofld_err: 1558c2ecf20Sopenharmony_ci /* couldn't offload the session. log off from this rport */ 1568c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "bnx2fc_offload_session - offload error\n"); 1578c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); 1588c2ecf20Sopenharmony_ci /* Free session resources */ 1598c2ecf20Sopenharmony_ci bnx2fc_free_session_resc(hba, tgt); 1608c2ecf20Sopenharmony_citgt_init_err: 1618c2ecf20Sopenharmony_ci if (tgt->fcoe_conn_id != -1) 1628c2ecf20Sopenharmony_ci bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id); 1638c2ecf20Sopenharmony_ci fc_rport_logoff(rdata); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_civoid bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct bnx2fc_cmd *io_req; 1698c2ecf20Sopenharmony_ci struct bnx2fc_cmd *tmp; 1708c2ecf20Sopenharmony_ci int rc; 1718c2ecf20Sopenharmony_ci int i = 0; 1728c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Entered flush_active_ios - %d\n", 1738c2ecf20Sopenharmony_ci tgt->num_active_ios.counter); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 1768c2ecf20Sopenharmony_ci tgt->flush_in_prog = 1; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci list_for_each_entry_safe(io_req, tmp, &tgt->active_cmd_queue, link) { 1798c2ecf20Sopenharmony_ci i++; 1808c2ecf20Sopenharmony_ci list_del_init(&io_req->link); 1818c2ecf20Sopenharmony_ci io_req->on_active_queue = 0; 1828c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "cmd_queue cleanup\n"); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (cancel_delayed_work(&io_req->timeout_work)) { 1858c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, 1868c2ecf20Sopenharmony_ci &io_req->req_flags)) { 1878c2ecf20Sopenharmony_ci /* Handle eh_abort timeout */ 1888c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "eh_abort for IO " 1898c2ecf20Sopenharmony_ci "cleaned up\n"); 1908c2ecf20Sopenharmony_ci complete(&io_req->abts_done); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, 1938c2ecf20Sopenharmony_ci bnx2fc_cmd_release); /* drop timer hold */ 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags); 1978c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Do not issue cleanup when disable request failed */ 2008c2ecf20Sopenharmony_ci if (test_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags)) 2018c2ecf20Sopenharmony_ci bnx2fc_process_cleanup_compl(io_req, io_req->task, 0); 2028c2ecf20Sopenharmony_ci else { 2038c2ecf20Sopenharmony_ci rc = bnx2fc_initiate_cleanup(io_req); 2048c2ecf20Sopenharmony_ci BUG_ON(rc); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci list_for_each_entry_safe(io_req, tmp, &tgt->active_tm_queue, link) { 2098c2ecf20Sopenharmony_ci i++; 2108c2ecf20Sopenharmony_ci list_del_init(&io_req->link); 2118c2ecf20Sopenharmony_ci io_req->on_tmf_queue = 0; 2128c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "tm_queue cleanup\n"); 2138c2ecf20Sopenharmony_ci if (io_req->wait_for_abts_comp) 2148c2ecf20Sopenharmony_ci complete(&io_req->abts_done); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci list_for_each_entry_safe(io_req, tmp, &tgt->els_queue, link) { 2188c2ecf20Sopenharmony_ci i++; 2198c2ecf20Sopenharmony_ci list_del_init(&io_req->link); 2208c2ecf20Sopenharmony_ci io_req->on_active_queue = 0; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "els_queue cleanup\n"); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (cancel_delayed_work(&io_req->timeout_work)) 2258c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, 2268c2ecf20Sopenharmony_ci bnx2fc_cmd_release); /* drop timer hold */ 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if ((io_req->cb_func) && (io_req->cb_arg)) { 2298c2ecf20Sopenharmony_ci io_req->cb_func(io_req->cb_arg); 2308c2ecf20Sopenharmony_ci io_req->cb_arg = NULL; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* Do not issue cleanup when disable request failed */ 2348c2ecf20Sopenharmony_ci if (test_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags)) 2358c2ecf20Sopenharmony_ci bnx2fc_process_cleanup_compl(io_req, io_req->task, 0); 2368c2ecf20Sopenharmony_ci else { 2378c2ecf20Sopenharmony_ci rc = bnx2fc_initiate_cleanup(io_req); 2388c2ecf20Sopenharmony_ci BUG_ON(rc); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci list_for_each_entry_safe(io_req, tmp, &tgt->io_retire_queue, link) { 2438c2ecf20Sopenharmony_ci i++; 2448c2ecf20Sopenharmony_ci list_del_init(&io_req->link); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "retire_queue flush\n"); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (cancel_delayed_work(&io_req->timeout_work)) { 2498c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, 2508c2ecf20Sopenharmony_ci &io_req->req_flags)) { 2518c2ecf20Sopenharmony_ci /* Handle eh_abort timeout */ 2528c2ecf20Sopenharmony_ci BNX2FC_IO_DBG(io_req, "eh_abort for IO " 2538c2ecf20Sopenharmony_ci "in retire_q\n"); 2548c2ecf20Sopenharmony_ci if (io_req->wait_for_abts_comp) 2558c2ecf20Sopenharmony_ci complete(&io_req->abts_done); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci kref_put(&io_req->refcount, bnx2fc_cmd_release); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags); 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "IOs flushed = %d\n", i); 2648c2ecf20Sopenharmony_ci i = 0; 2658c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 2668c2ecf20Sopenharmony_ci /* wait for active_ios to go to 0 */ 2678c2ecf20Sopenharmony_ci while ((tgt->num_active_ios.counter != 0) && (i++ < BNX2FC_WAIT_CNT)) 2688c2ecf20Sopenharmony_ci msleep(25); 2698c2ecf20Sopenharmony_ci if (tgt->num_active_ios.counter != 0) 2708c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "CLEANUP on port 0x%x:" 2718c2ecf20Sopenharmony_ci " active_ios = %d\n", 2728c2ecf20Sopenharmony_ci tgt->rdata->ids.port_id, tgt->num_active_ios.counter); 2738c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->tgt_lock); 2748c2ecf20Sopenharmony_ci tgt->flush_in_prog = 0; 2758c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->tgt_lock); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void bnx2fc_upld_wait(struct bnx2fc_rport *tgt) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci timer_setup(&tgt->upld_timer, bnx2fc_upld_timer, 0); 2818c2ecf20Sopenharmony_ci mod_timer(&tgt->upld_timer, jiffies + BNX2FC_FW_TIMEOUT); 2828c2ecf20Sopenharmony_ci wait_event_interruptible(tgt->upld_wait, 2838c2ecf20Sopenharmony_ci (test_bit( 2848c2ecf20Sopenharmony_ci BNX2FC_FLAG_UPLD_REQ_COMPL, 2858c2ecf20Sopenharmony_ci &tgt->flags))); 2868c2ecf20Sopenharmony_ci if (signal_pending(current)) 2878c2ecf20Sopenharmony_ci flush_signals(current); 2888c2ecf20Sopenharmony_ci del_timer_sync(&tgt->upld_timer); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void bnx2fc_upload_session(struct fcoe_port *port, 2928c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 2958c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "upload_session: active_ios = %d\n", 2988c2ecf20Sopenharmony_ci tgt->num_active_ios.counter); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * Called with hba->hba_mutex held. 3028c2ecf20Sopenharmony_ci * This is a blocking call 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); 3058c2ecf20Sopenharmony_ci bnx2fc_send_session_disable_req(port, tgt); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* 3088c2ecf20Sopenharmony_ci * wait for upload to complete. 3 Secs 3098c2ecf20Sopenharmony_ci * should be sufficient time for this process to complete. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "waiting for disable compl\n"); 3128c2ecf20Sopenharmony_ci bnx2fc_upld_wait(tgt); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* 3158c2ecf20Sopenharmony_ci * traverse thru the active_q and tmf_q and cleanup 3168c2ecf20Sopenharmony_ci * IOs in these lists 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "flush/upload - disable wait flags = 0x%lx\n", 3198c2ecf20Sopenharmony_ci tgt->flags); 3208c2ecf20Sopenharmony_ci bnx2fc_flush_active_ios(tgt); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* Issue destroy KWQE */ 3238c2ecf20Sopenharmony_ci if (test_bit(BNX2FC_FLAG_DISABLED, &tgt->flags)) { 3248c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "send destroy req\n"); 3258c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); 3268c2ecf20Sopenharmony_ci bnx2fc_send_session_destroy_req(hba, tgt); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* wait for destroy to complete */ 3298c2ecf20Sopenharmony_ci bnx2fc_upld_wait(tgt); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (!(test_bit(BNX2FC_FLAG_DESTROYED, &tgt->flags))) 3328c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ERROR!! destroy timed out\n"); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "destroy wait complete flags = 0x%lx\n", 3358c2ecf20Sopenharmony_ci tgt->flags); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci } else if (test_bit(BNX2FC_FLAG_DISABLE_FAILED, &tgt->flags)) { 3388c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ERROR!! DISABLE req failed, destroy" 3398c2ecf20Sopenharmony_ci " not sent to FW\n"); 3408c2ecf20Sopenharmony_ci } else { 3418c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "ERROR!! DISABLE req timed out, destroy" 3428c2ecf20Sopenharmony_ci " not sent to FW\n"); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* Free session resources */ 3468c2ecf20Sopenharmony_ci bnx2fc_free_session_resc(hba, tgt); 3478c2ecf20Sopenharmony_ci bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic int bnx2fc_init_tgt(struct bnx2fc_rport *tgt, 3518c2ecf20Sopenharmony_ci struct fcoe_port *port, 3528c2ecf20Sopenharmony_ci struct fc_rport_priv *rdata) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci struct fc_rport *rport = rdata->rport; 3568c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 3578c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 3588c2ecf20Sopenharmony_ci struct b577xx_doorbell_set_prod *sq_db = &tgt->sq_db; 3598c2ecf20Sopenharmony_ci struct b577xx_fcoe_rx_doorbell *rx_db = &tgt->rx_db; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci tgt->rport = rport; 3628c2ecf20Sopenharmony_ci tgt->rdata = rdata; 3638c2ecf20Sopenharmony_ci tgt->port = port; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (hba->num_ofld_sess >= BNX2FC_NUM_MAX_SESS) { 3668c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "exceeded max sessions. logoff this tgt\n"); 3678c2ecf20Sopenharmony_ci tgt->fcoe_conn_id = -1; 3688c2ecf20Sopenharmony_ci return -1; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci tgt->fcoe_conn_id = bnx2fc_alloc_conn_id(hba, tgt); 3728c2ecf20Sopenharmony_ci if (tgt->fcoe_conn_id == -1) 3738c2ecf20Sopenharmony_ci return -1; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "init_tgt - conn_id = 0x%x\n", tgt->fcoe_conn_id); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci tgt->max_sqes = BNX2FC_SQ_WQES_MAX; 3788c2ecf20Sopenharmony_ci tgt->max_rqes = BNX2FC_RQ_WQES_MAX; 3798c2ecf20Sopenharmony_ci tgt->max_cqes = BNX2FC_CQ_WQES_MAX; 3808c2ecf20Sopenharmony_ci atomic_set(&tgt->free_sqes, BNX2FC_SQ_WQES_MAX); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* Initialize the toggle bit */ 3838c2ecf20Sopenharmony_ci tgt->sq_curr_toggle_bit = 1; 3848c2ecf20Sopenharmony_ci tgt->cq_curr_toggle_bit = 1; 3858c2ecf20Sopenharmony_ci tgt->sq_prod_idx = 0; 3868c2ecf20Sopenharmony_ci tgt->cq_cons_idx = 0; 3878c2ecf20Sopenharmony_ci tgt->rq_prod_idx = 0x8000; 3888c2ecf20Sopenharmony_ci tgt->rq_cons_idx = 0; 3898c2ecf20Sopenharmony_ci atomic_set(&tgt->num_active_ios, 0); 3908c2ecf20Sopenharmony_ci tgt->retry_delay_timestamp = 0; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (rdata->flags & FC_RP_FLAGS_RETRY && 3938c2ecf20Sopenharmony_ci rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET && 3948c2ecf20Sopenharmony_ci !(rdata->ids.roles & FC_RPORT_ROLE_FCP_INITIATOR)) { 3958c2ecf20Sopenharmony_ci tgt->dev_type = TYPE_TAPE; 3968c2ecf20Sopenharmony_ci tgt->io_timeout = 0; /* use default ULP timeout */ 3978c2ecf20Sopenharmony_ci } else { 3988c2ecf20Sopenharmony_ci tgt->dev_type = TYPE_DISK; 3998c2ecf20Sopenharmony_ci tgt->io_timeout = BNX2FC_IO_TIMEOUT; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* initialize sq doorbell */ 4038c2ecf20Sopenharmony_ci sq_db->header.header = B577XX_DOORBELL_HDR_DB_TYPE; 4048c2ecf20Sopenharmony_ci sq_db->header.header |= B577XX_FCOE_CONNECTION_TYPE << 4058c2ecf20Sopenharmony_ci B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT; 4068c2ecf20Sopenharmony_ci /* initialize rx doorbell */ 4078c2ecf20Sopenharmony_ci rx_db->hdr.header = ((0x1 << B577XX_DOORBELL_HDR_RX_SHIFT) | 4088c2ecf20Sopenharmony_ci (0x1 << B577XX_DOORBELL_HDR_DB_TYPE_SHIFT) | 4098c2ecf20Sopenharmony_ci (B577XX_FCOE_CONNECTION_TYPE << 4108c2ecf20Sopenharmony_ci B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT)); 4118c2ecf20Sopenharmony_ci rx_db->params = (0x2 << B577XX_FCOE_RX_DOORBELL_NEGATIVE_ARM_SHIFT) | 4128c2ecf20Sopenharmony_ci (0x3 << B577XX_FCOE_RX_DOORBELL_OPCODE_SHIFT); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci spin_lock_init(&tgt->tgt_lock); 4158c2ecf20Sopenharmony_ci spin_lock_init(&tgt->cq_lock); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Initialize active_cmd_queue list */ 4188c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tgt->active_cmd_queue); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* Initialize IO retire queue */ 4218c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tgt->io_retire_queue); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tgt->els_queue); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* Initialize active_tm_queue list */ 4268c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tgt->active_tm_queue); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci init_waitqueue_head(&tgt->ofld_wait); 4298c2ecf20Sopenharmony_ci init_waitqueue_head(&tgt->upld_wait); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return 0; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci/* 4358c2ecf20Sopenharmony_ci * This event_callback is called after successful completion of libfc 4368c2ecf20Sopenharmony_ci * initiated target login. bnx2fc can proceed with initiating the session 4378c2ecf20Sopenharmony_ci * establishment. 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_civoid bnx2fc_rport_event_handler(struct fc_lport *lport, 4408c2ecf20Sopenharmony_ci struct fc_rport_priv *rdata, 4418c2ecf20Sopenharmony_ci enum fc_rport_event event) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct fcoe_port *port = lport_priv(lport); 4448c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 4458c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 4468c2ecf20Sopenharmony_ci struct fc_rport *rport = rdata->rport; 4478c2ecf20Sopenharmony_ci struct fc_rport_libfc_priv *rp; 4488c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt; 4498c2ecf20Sopenharmony_ci u32 port_id; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "rport_event_hdlr: event = %d, port_id = 0x%x\n", 4528c2ecf20Sopenharmony_ci event, rdata->ids.port_id); 4538c2ecf20Sopenharmony_ci switch (event) { 4548c2ecf20Sopenharmony_ci case RPORT_EV_READY: 4558c2ecf20Sopenharmony_ci if (!rport) { 4568c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "rport is NULL: ERROR!\n"); 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci rp = rport->dd_data; 4618c2ecf20Sopenharmony_ci if (rport->port_id == FC_FID_DIR_SERV) { 4628c2ecf20Sopenharmony_ci /* 4638c2ecf20Sopenharmony_ci * bnx2fc_rport structure doesn't exist for 4648c2ecf20Sopenharmony_ci * directory server. 4658c2ecf20Sopenharmony_ci * We should not come here, as lport will 4668c2ecf20Sopenharmony_ci * take care of fabric login 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "%x - rport_event_handler ERROR\n", 4698c2ecf20Sopenharmony_ci rdata->ids.port_id); 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (rdata->spp_type != FC_TYPE_FCP) { 4748c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "not FCP type target." 4758c2ecf20Sopenharmony_ci " not offloading\n"); 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci if (!(rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET)) { 4798c2ecf20Sopenharmony_ci BNX2FC_HBA_DBG(lport, "not FCP_TARGET" 4808c2ecf20Sopenharmony_ci " not offloading\n"); 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* 4858c2ecf20Sopenharmony_ci * Offlaod process is protected with hba mutex. 4868c2ecf20Sopenharmony_ci * Use the same mutex_lock for upload process too 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_ci mutex_lock(&hba->hba_mutex); 4898c2ecf20Sopenharmony_ci tgt = (struct bnx2fc_rport *)&rp[1]; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* This can happen when ADISC finds the same target */ 4928c2ecf20Sopenharmony_ci if (test_bit(BNX2FC_FLAG_ENABLED, &tgt->flags)) { 4938c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "already offloaded\n"); 4948c2ecf20Sopenharmony_ci mutex_unlock(&hba->hba_mutex); 4958c2ecf20Sopenharmony_ci return; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* 4998c2ecf20Sopenharmony_ci * Offload the session. This is a blocking call, and will 5008c2ecf20Sopenharmony_ci * wait until the session is offloaded. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci bnx2fc_offload_session(port, tgt, rdata); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "OFFLOAD num_ofld_sess = %d\n", 5058c2ecf20Sopenharmony_ci hba->num_ofld_sess); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (test_bit(BNX2FC_FLAG_ENABLED, &tgt->flags)) { 5088c2ecf20Sopenharmony_ci /* Session is offloaded and enabled. */ 5098c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "sess offloaded\n"); 5108c2ecf20Sopenharmony_ci /* This counter is protected with hba mutex */ 5118c2ecf20Sopenharmony_ci hba->num_ofld_sess++; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci set_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags); 5148c2ecf20Sopenharmony_ci } else { 5158c2ecf20Sopenharmony_ci /* 5168c2ecf20Sopenharmony_ci * Offload or enable would have failed. 5178c2ecf20Sopenharmony_ci * In offload/enable completion path, the 5188c2ecf20Sopenharmony_ci * rport would have already been removed 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Port is being logged off as " 5218c2ecf20Sopenharmony_ci "offloaded flag not set\n"); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci mutex_unlock(&hba->hba_mutex); 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci case RPORT_EV_LOGO: 5268c2ecf20Sopenharmony_ci case RPORT_EV_FAILED: 5278c2ecf20Sopenharmony_ci case RPORT_EV_STOP: 5288c2ecf20Sopenharmony_ci port_id = rdata->ids.port_id; 5298c2ecf20Sopenharmony_ci if (port_id == FC_FID_DIR_SERV) 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (!rport) { 5338c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "%x - rport not created Yet!!\n", 5348c2ecf20Sopenharmony_ci port_id); 5358c2ecf20Sopenharmony_ci break; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci rp = rport->dd_data; 5388c2ecf20Sopenharmony_ci mutex_lock(&hba->hba_mutex); 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * Perform session upload. Note that rdata->peers is already 5418c2ecf20Sopenharmony_ci * removed from disc->rports list before we get this event. 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ci tgt = (struct bnx2fc_rport *)&rp[1]; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!(test_bit(BNX2FC_FLAG_ENABLED, &tgt->flags))) { 5468c2ecf20Sopenharmony_ci mutex_unlock(&hba->hba_mutex); 5478c2ecf20Sopenharmony_ci break; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci bnx2fc_upload_session(port, tgt); 5528c2ecf20Sopenharmony_ci hba->num_ofld_sess--; 5538c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "UPLOAD num_ofld_sess = %d\n", 5548c2ecf20Sopenharmony_ci hba->num_ofld_sess); 5558c2ecf20Sopenharmony_ci /* 5568c2ecf20Sopenharmony_ci * Try to wake up the linkdown wait thread. If num_ofld_sess 5578c2ecf20Sopenharmony_ci * is 0, the waiting therad wakes up 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci if ((hba->wait_for_link_down) && 5608c2ecf20Sopenharmony_ci (hba->num_ofld_sess == 0)) { 5618c2ecf20Sopenharmony_ci wake_up_interruptible(&hba->shutdown_wait); 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci mutex_unlock(&hba->hba_mutex); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci case RPORT_EV_NONE: 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci/** 5738c2ecf20Sopenharmony_ci * bnx2fc_tgt_lookup() - Lookup a bnx2fc_rport by port_id 5748c2ecf20Sopenharmony_ci * 5758c2ecf20Sopenharmony_ci * @port: fcoe_port struct to lookup the target port on 5768c2ecf20Sopenharmony_ci * @port_id: The remote port ID to look up 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_cistruct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port, 5798c2ecf20Sopenharmony_ci u32 port_id) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct bnx2fc_interface *interface = port->priv; 5828c2ecf20Sopenharmony_ci struct bnx2fc_hba *hba = interface->hba; 5838c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt; 5848c2ecf20Sopenharmony_ci struct fc_rport_priv *rdata; 5858c2ecf20Sopenharmony_ci int i; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) { 5888c2ecf20Sopenharmony_ci tgt = hba->tgt_ofld_list[i]; 5898c2ecf20Sopenharmony_ci if ((tgt) && (tgt->port == port)) { 5908c2ecf20Sopenharmony_ci rdata = tgt->rdata; 5918c2ecf20Sopenharmony_ci if (rdata->ids.port_id == port_id) { 5928c2ecf20Sopenharmony_ci if (rdata->rp_state != RPORT_ST_DELETE) { 5938c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "rport " 5948c2ecf20Sopenharmony_ci "obtained\n"); 5958c2ecf20Sopenharmony_ci return tgt; 5968c2ecf20Sopenharmony_ci } else { 5978c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "rport 0x%x " 5988c2ecf20Sopenharmony_ci "is in DELETED state\n", 5998c2ecf20Sopenharmony_ci rdata->ids.port_id); 6008c2ecf20Sopenharmony_ci return NULL; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci return NULL; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci/** 6108c2ecf20Sopenharmony_ci * bnx2fc_alloc_conn_id - allocates FCOE Connection id 6118c2ecf20Sopenharmony_ci * 6128c2ecf20Sopenharmony_ci * @hba: pointer to adapter structure 6138c2ecf20Sopenharmony_ci * @tgt: pointer to bnx2fc_rport structure 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_cistatic u32 bnx2fc_alloc_conn_id(struct bnx2fc_hba *hba, 6168c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci u32 conn_id, next; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* called with hba mutex held */ 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* 6238c2ecf20Sopenharmony_ci * tgt_ofld_list access is synchronized using 6248c2ecf20Sopenharmony_ci * both hba mutex and hba lock. Atleast hba mutex or 6258c2ecf20Sopenharmony_ci * hba lock needs to be held for read access. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 6298c2ecf20Sopenharmony_ci next = hba->next_conn_id; 6308c2ecf20Sopenharmony_ci conn_id = hba->next_conn_id++; 6318c2ecf20Sopenharmony_ci if (hba->next_conn_id == BNX2FC_NUM_MAX_SESS) 6328c2ecf20Sopenharmony_ci hba->next_conn_id = 0; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci while (hba->tgt_ofld_list[conn_id] != NULL) { 6358c2ecf20Sopenharmony_ci conn_id++; 6368c2ecf20Sopenharmony_ci if (conn_id == BNX2FC_NUM_MAX_SESS) 6378c2ecf20Sopenharmony_ci conn_id = 0; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (conn_id == next) { 6408c2ecf20Sopenharmony_ci /* No free conn_ids are available */ 6418c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 6428c2ecf20Sopenharmony_ci return -1; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci hba->tgt_ofld_list[conn_id] = tgt; 6468c2ecf20Sopenharmony_ci tgt->fcoe_conn_id = conn_id; 6478c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 6488c2ecf20Sopenharmony_ci return conn_id; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci /* called with hba mutex held */ 6548c2ecf20Sopenharmony_ci spin_lock_bh(&hba->hba_lock); 6558c2ecf20Sopenharmony_ci hba->tgt_ofld_list[conn_id] = NULL; 6568c2ecf20Sopenharmony_ci spin_unlock_bh(&hba->hba_lock); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci/* 6608c2ecf20Sopenharmony_ci * bnx2fc_alloc_session_resc - Allocate qp resources for the session 6618c2ecf20Sopenharmony_ci */ 6628c2ecf20Sopenharmony_cistatic int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, 6638c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci dma_addr_t page; 6668c2ecf20Sopenharmony_ci int num_pages; 6678c2ecf20Sopenharmony_ci u32 *pbl; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* Allocate and map SQ */ 6708c2ecf20Sopenharmony_ci tgt->sq_mem_size = tgt->max_sqes * BNX2FC_SQ_WQE_SIZE; 6718c2ecf20Sopenharmony_ci tgt->sq_mem_size = (tgt->sq_mem_size + (CNIC_PAGE_SIZE - 1)) & 6728c2ecf20Sopenharmony_ci CNIC_PAGE_MASK; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size, 6758c2ecf20Sopenharmony_ci &tgt->sq_dma, GFP_KERNEL); 6768c2ecf20Sopenharmony_ci if (!tgt->sq) { 6778c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate SQ memory %d\n", 6788c2ecf20Sopenharmony_ci tgt->sq_mem_size); 6798c2ecf20Sopenharmony_ci goto mem_alloc_failure; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci /* Allocate and map CQ */ 6838c2ecf20Sopenharmony_ci tgt->cq_mem_size = tgt->max_cqes * BNX2FC_CQ_WQE_SIZE; 6848c2ecf20Sopenharmony_ci tgt->cq_mem_size = (tgt->cq_mem_size + (CNIC_PAGE_SIZE - 1)) & 6858c2ecf20Sopenharmony_ci CNIC_PAGE_MASK; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size, 6888c2ecf20Sopenharmony_ci &tgt->cq_dma, GFP_KERNEL); 6898c2ecf20Sopenharmony_ci if (!tgt->cq) { 6908c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate CQ memory %d\n", 6918c2ecf20Sopenharmony_ci tgt->cq_mem_size); 6928c2ecf20Sopenharmony_ci goto mem_alloc_failure; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* Allocate and map RQ and RQ PBL */ 6968c2ecf20Sopenharmony_ci tgt->rq_mem_size = tgt->max_rqes * BNX2FC_RQ_WQE_SIZE; 6978c2ecf20Sopenharmony_ci tgt->rq_mem_size = (tgt->rq_mem_size + (CNIC_PAGE_SIZE - 1)) & 6988c2ecf20Sopenharmony_ci CNIC_PAGE_MASK; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size, 7018c2ecf20Sopenharmony_ci &tgt->rq_dma, GFP_KERNEL); 7028c2ecf20Sopenharmony_ci if (!tgt->rq) { 7038c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate RQ memory %d\n", 7048c2ecf20Sopenharmony_ci tgt->rq_mem_size); 7058c2ecf20Sopenharmony_ci goto mem_alloc_failure; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci tgt->rq_pbl_size = (tgt->rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *); 7098c2ecf20Sopenharmony_ci tgt->rq_pbl_size = (tgt->rq_pbl_size + (CNIC_PAGE_SIZE - 1)) & 7108c2ecf20Sopenharmony_ci CNIC_PAGE_MASK; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size, 7138c2ecf20Sopenharmony_ci &tgt->rq_pbl_dma, GFP_KERNEL); 7148c2ecf20Sopenharmony_ci if (!tgt->rq_pbl) { 7158c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate RQ PBL %d\n", 7168c2ecf20Sopenharmony_ci tgt->rq_pbl_size); 7178c2ecf20Sopenharmony_ci goto mem_alloc_failure; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci num_pages = tgt->rq_mem_size / CNIC_PAGE_SIZE; 7218c2ecf20Sopenharmony_ci page = tgt->rq_dma; 7228c2ecf20Sopenharmony_ci pbl = (u32 *)tgt->rq_pbl; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci while (num_pages--) { 7258c2ecf20Sopenharmony_ci *pbl = (u32)page; 7268c2ecf20Sopenharmony_ci pbl++; 7278c2ecf20Sopenharmony_ci *pbl = (u32)((u64)page >> 32); 7288c2ecf20Sopenharmony_ci pbl++; 7298c2ecf20Sopenharmony_ci page += CNIC_PAGE_SIZE; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* Allocate and map XFERQ */ 7338c2ecf20Sopenharmony_ci tgt->xferq_mem_size = tgt->max_sqes * BNX2FC_XFERQ_WQE_SIZE; 7348c2ecf20Sopenharmony_ci tgt->xferq_mem_size = (tgt->xferq_mem_size + (CNIC_PAGE_SIZE - 1)) & 7358c2ecf20Sopenharmony_ci CNIC_PAGE_MASK; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, 7388c2ecf20Sopenharmony_ci tgt->xferq_mem_size, &tgt->xferq_dma, 7398c2ecf20Sopenharmony_ci GFP_KERNEL); 7408c2ecf20Sopenharmony_ci if (!tgt->xferq) { 7418c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate XFERQ %d\n", 7428c2ecf20Sopenharmony_ci tgt->xferq_mem_size); 7438c2ecf20Sopenharmony_ci goto mem_alloc_failure; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* Allocate and map CONFQ & CONFQ PBL */ 7478c2ecf20Sopenharmony_ci tgt->confq_mem_size = tgt->max_sqes * BNX2FC_CONFQ_WQE_SIZE; 7488c2ecf20Sopenharmony_ci tgt->confq_mem_size = (tgt->confq_mem_size + (CNIC_PAGE_SIZE - 1)) & 7498c2ecf20Sopenharmony_ci CNIC_PAGE_MASK; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, 7528c2ecf20Sopenharmony_ci tgt->confq_mem_size, &tgt->confq_dma, 7538c2ecf20Sopenharmony_ci GFP_KERNEL); 7548c2ecf20Sopenharmony_ci if (!tgt->confq) { 7558c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate CONFQ %d\n", 7568c2ecf20Sopenharmony_ci tgt->confq_mem_size); 7578c2ecf20Sopenharmony_ci goto mem_alloc_failure; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci tgt->confq_pbl_size = 7618c2ecf20Sopenharmony_ci (tgt->confq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *); 7628c2ecf20Sopenharmony_ci tgt->confq_pbl_size = 7638c2ecf20Sopenharmony_ci (tgt->confq_pbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev, 7668c2ecf20Sopenharmony_ci tgt->confq_pbl_size, 7678c2ecf20Sopenharmony_ci &tgt->confq_pbl_dma, GFP_KERNEL); 7688c2ecf20Sopenharmony_ci if (!tgt->confq_pbl) { 7698c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate CONFQ PBL %d\n", 7708c2ecf20Sopenharmony_ci tgt->confq_pbl_size); 7718c2ecf20Sopenharmony_ci goto mem_alloc_failure; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci num_pages = tgt->confq_mem_size / CNIC_PAGE_SIZE; 7758c2ecf20Sopenharmony_ci page = tgt->confq_dma; 7768c2ecf20Sopenharmony_ci pbl = (u32 *)tgt->confq_pbl; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci while (num_pages--) { 7798c2ecf20Sopenharmony_ci *pbl = (u32)page; 7808c2ecf20Sopenharmony_ci pbl++; 7818c2ecf20Sopenharmony_ci *pbl = (u32)((u64)page >> 32); 7828c2ecf20Sopenharmony_ci pbl++; 7838c2ecf20Sopenharmony_ci page += CNIC_PAGE_SIZE; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* Allocate and map ConnDB */ 7878c2ecf20Sopenharmony_ci tgt->conn_db_mem_size = sizeof(struct fcoe_conn_db); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci tgt->conn_db = dma_alloc_coherent(&hba->pcidev->dev, 7908c2ecf20Sopenharmony_ci tgt->conn_db_mem_size, 7918c2ecf20Sopenharmony_ci &tgt->conn_db_dma, GFP_KERNEL); 7928c2ecf20Sopenharmony_ci if (!tgt->conn_db) { 7938c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate conn_db %d\n", 7948c2ecf20Sopenharmony_ci tgt->conn_db_mem_size); 7958c2ecf20Sopenharmony_ci goto mem_alloc_failure; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* Allocate and map LCQ */ 8008c2ecf20Sopenharmony_ci tgt->lcq_mem_size = (tgt->max_sqes + 8) * BNX2FC_SQ_WQE_SIZE; 8018c2ecf20Sopenharmony_ci tgt->lcq_mem_size = (tgt->lcq_mem_size + (CNIC_PAGE_SIZE - 1)) & 8028c2ecf20Sopenharmony_ci CNIC_PAGE_MASK; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size, 8058c2ecf20Sopenharmony_ci &tgt->lcq_dma, GFP_KERNEL); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (!tgt->lcq) { 8088c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "unable to allocate lcq %d\n", 8098c2ecf20Sopenharmony_ci tgt->lcq_mem_size); 8108c2ecf20Sopenharmony_ci goto mem_alloc_failure; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci tgt->conn_db->rq_prod = 0x8000; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci return 0; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cimem_alloc_failure: 8188c2ecf20Sopenharmony_ci return -ENOMEM; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci/** 8228c2ecf20Sopenharmony_ci * bnx2i_free_session_resc - free qp resources for the session 8238c2ecf20Sopenharmony_ci * 8248c2ecf20Sopenharmony_ci * @hba: adapter structure pointer 8258c2ecf20Sopenharmony_ci * @tgt: bnx2fc_rport structure pointer 8268c2ecf20Sopenharmony_ci * 8278c2ecf20Sopenharmony_ci * Free QP resources - SQ/RQ/CQ/XFERQ memory and PBL 8288c2ecf20Sopenharmony_ci */ 8298c2ecf20Sopenharmony_cistatic void bnx2fc_free_session_resc(struct bnx2fc_hba *hba, 8308c2ecf20Sopenharmony_ci struct bnx2fc_rport *tgt) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci void __iomem *ctx_base_ptr; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci BNX2FC_TGT_DBG(tgt, "Freeing up session resources\n"); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci spin_lock_bh(&tgt->cq_lock); 8378c2ecf20Sopenharmony_ci ctx_base_ptr = tgt->ctx_base; 8388c2ecf20Sopenharmony_ci tgt->ctx_base = NULL; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci /* Free LCQ */ 8418c2ecf20Sopenharmony_ci if (tgt->lcq) { 8428c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, tgt->lcq_mem_size, 8438c2ecf20Sopenharmony_ci tgt->lcq, tgt->lcq_dma); 8448c2ecf20Sopenharmony_ci tgt->lcq = NULL; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci /* Free connDB */ 8478c2ecf20Sopenharmony_ci if (tgt->conn_db) { 8488c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, tgt->conn_db_mem_size, 8498c2ecf20Sopenharmony_ci tgt->conn_db, tgt->conn_db_dma); 8508c2ecf20Sopenharmony_ci tgt->conn_db = NULL; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci /* Free confq and confq pbl */ 8538c2ecf20Sopenharmony_ci if (tgt->confq_pbl) { 8548c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, tgt->confq_pbl_size, 8558c2ecf20Sopenharmony_ci tgt->confq_pbl, tgt->confq_pbl_dma); 8568c2ecf20Sopenharmony_ci tgt->confq_pbl = NULL; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci if (tgt->confq) { 8598c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, tgt->confq_mem_size, 8608c2ecf20Sopenharmony_ci tgt->confq, tgt->confq_dma); 8618c2ecf20Sopenharmony_ci tgt->confq = NULL; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci /* Free XFERQ */ 8648c2ecf20Sopenharmony_ci if (tgt->xferq) { 8658c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, tgt->xferq_mem_size, 8668c2ecf20Sopenharmony_ci tgt->xferq, tgt->xferq_dma); 8678c2ecf20Sopenharmony_ci tgt->xferq = NULL; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci /* Free RQ PBL and RQ */ 8708c2ecf20Sopenharmony_ci if (tgt->rq_pbl) { 8718c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, tgt->rq_pbl_size, 8728c2ecf20Sopenharmony_ci tgt->rq_pbl, tgt->rq_pbl_dma); 8738c2ecf20Sopenharmony_ci tgt->rq_pbl = NULL; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci if (tgt->rq) { 8768c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, tgt->rq_mem_size, 8778c2ecf20Sopenharmony_ci tgt->rq, tgt->rq_dma); 8788c2ecf20Sopenharmony_ci tgt->rq = NULL; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci /* Free CQ */ 8818c2ecf20Sopenharmony_ci if (tgt->cq) { 8828c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, tgt->cq_mem_size, 8838c2ecf20Sopenharmony_ci tgt->cq, tgt->cq_dma); 8848c2ecf20Sopenharmony_ci tgt->cq = NULL; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci /* Free SQ */ 8878c2ecf20Sopenharmony_ci if (tgt->sq) { 8888c2ecf20Sopenharmony_ci dma_free_coherent(&hba->pcidev->dev, tgt->sq_mem_size, 8898c2ecf20Sopenharmony_ci tgt->sq, tgt->sq_dma); 8908c2ecf20Sopenharmony_ci tgt->sq = NULL; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci spin_unlock_bh(&tgt->cq_lock); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (ctx_base_ptr) 8958c2ecf20Sopenharmony_ci iounmap(ctx_base_ptr); 8968c2ecf20Sopenharmony_ci} 897