18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is part of the Chelsio FCoE driver for Linux. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/kernel.h> 368c2ecf20Sopenharmony_ci#include <linux/delay.h> 378c2ecf20Sopenharmony_ci#include <linux/slab.h> 388c2ecf20Sopenharmony_ci#include <linux/utsname.h> 398c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 408c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_fc.h> 418c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 428c2ecf20Sopenharmony_ci#include <scsi/fc/fc_els.h> 438c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fs.h> 448c2ecf20Sopenharmony_ci#include <scsi/fc/fc_gs.h> 458c2ecf20Sopenharmony_ci#include <scsi/fc/fc_ms.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include "csio_hw.h" 488c2ecf20Sopenharmony_ci#include "csio_mb.h" 498c2ecf20Sopenharmony_ci#include "csio_lnode.h" 508c2ecf20Sopenharmony_ci#include "csio_rnode.h" 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciint csio_fcoe_rnodes = 1024; 538c2ecf20Sopenharmony_ciint csio_fdmi_enable = 1; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define PORT_ID_PTR(_x) ((uint8_t *)(&_x) + 1) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* Lnode SM declarations */ 588c2ecf20Sopenharmony_cistatic void csio_lns_uninit(struct csio_lnode *, enum csio_ln_ev); 598c2ecf20Sopenharmony_cistatic void csio_lns_online(struct csio_lnode *, enum csio_ln_ev); 608c2ecf20Sopenharmony_cistatic void csio_lns_ready(struct csio_lnode *, enum csio_ln_ev); 618c2ecf20Sopenharmony_cistatic void csio_lns_offline(struct csio_lnode *, enum csio_ln_ev); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int csio_ln_mgmt_submit_req(struct csio_ioreq *, 648c2ecf20Sopenharmony_ci void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *), 658c2ecf20Sopenharmony_ci enum fcoe_cmn_type, struct csio_dma_buf *, uint32_t); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* LN event mapping */ 688c2ecf20Sopenharmony_cistatic enum csio_ln_ev fwevt_to_lnevt[] = { 698c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* None */ 708c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PLOGI_ACC_RCVD */ 718c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PLOGI_RJT_RCVD */ 728c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PLOGI_RCVD */ 738c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PLOGO_RCVD */ 748c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PRLI_ACC_RCVD */ 758c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PRLI_RJT_RCVD */ 768c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PRLI_RCVD */ 778c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PRLO_RCVD */ 788c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* NPORT_ID_CHGD */ 798c2ecf20Sopenharmony_ci CSIO_LNE_LOGO, /* FLOGO_RCVD */ 808c2ecf20Sopenharmony_ci CSIO_LNE_LOGO, /* CLR_VIRT_LNK_RCVD */ 818c2ecf20Sopenharmony_ci CSIO_LNE_FAB_INIT_DONE,/* FLOGI_ACC_RCVD */ 828c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* FLOGI_RJT_RCVD */ 838c2ecf20Sopenharmony_ci CSIO_LNE_FAB_INIT_DONE,/* FDISC_ACC_RCVD */ 848c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* FDISC_RJT_RCVD */ 858c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* FLOGI_TMO_MAX_RETRY */ 868c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* IMPL_LOGO_ADISC_ACC */ 878c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* IMPL_LOGO_ADISC_RJT */ 888c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* IMPL_LOGO_ADISC_CNFLT */ 898c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PRLI_TMO */ 908c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* ADISC_TMO */ 918c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* RSCN_DEV_LOST */ 928c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* SCR_ACC_RCVD */ 938c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* ADISC_RJT_RCVD */ 948c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* LOGO_SNT */ 958c2ecf20Sopenharmony_ci CSIO_LNE_NONE, /* PROTO_ERR_IMPL_LOGO */ 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define CSIO_FWE_TO_LNE(_evt) ((_evt > PROTO_ERR_IMPL_LOGO) ? \ 998c2ecf20Sopenharmony_ci CSIO_LNE_NONE : \ 1008c2ecf20Sopenharmony_ci fwevt_to_lnevt[_evt]) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define csio_ct_rsp(cp) (((struct fc_ct_hdr *)cp)->ct_cmd) 1038c2ecf20Sopenharmony_ci#define csio_ct_reason(cp) (((struct fc_ct_hdr *)cp)->ct_reason) 1048c2ecf20Sopenharmony_ci#define csio_ct_expl(cp) (((struct fc_ct_hdr *)cp)->ct_explan) 1058c2ecf20Sopenharmony_ci#define csio_ct_get_pld(cp) ((void *)(((uint8_t *)cp) + FC_CT_HDR_LEN)) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* 1088c2ecf20Sopenharmony_ci * csio_ln_match_by_portid - lookup lnode using given portid. 1098c2ecf20Sopenharmony_ci * @hw: HW module 1108c2ecf20Sopenharmony_ci * @portid: port-id. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * If found, returns lnode matching given portid otherwise returns NULL. 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_cistatic struct csio_lnode * 1158c2ecf20Sopenharmony_cicsio_ln_lookup_by_portid(struct csio_hw *hw, uint8_t portid) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct csio_lnode *ln; 1188c2ecf20Sopenharmony_ci struct list_head *tmp; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Match siblings lnode with portid */ 1218c2ecf20Sopenharmony_ci list_for_each(tmp, &hw->sln_head) { 1228c2ecf20Sopenharmony_ci ln = (struct csio_lnode *) tmp; 1238c2ecf20Sopenharmony_ci if (ln->portid == portid) 1248c2ecf20Sopenharmony_ci return ln; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return NULL; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * csio_ln_lookup_by_vnpi - Lookup lnode using given vnp id. 1328c2ecf20Sopenharmony_ci * @hw - HW module 1338c2ecf20Sopenharmony_ci * @vnpi - vnp index. 1348c2ecf20Sopenharmony_ci * Returns - If found, returns lnode matching given vnp id 1358c2ecf20Sopenharmony_ci * otherwise returns NULL. 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_cistatic struct csio_lnode * 1388c2ecf20Sopenharmony_cicsio_ln_lookup_by_vnpi(struct csio_hw *hw, uint32_t vnp_id) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct list_head *tmp1, *tmp2; 1418c2ecf20Sopenharmony_ci struct csio_lnode *sln = NULL, *cln = NULL; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (list_empty(&hw->sln_head)) { 1448c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_lnlkup_miss); 1458c2ecf20Sopenharmony_ci return NULL; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci /* Traverse sibling lnodes */ 1488c2ecf20Sopenharmony_ci list_for_each(tmp1, &hw->sln_head) { 1498c2ecf20Sopenharmony_ci sln = (struct csio_lnode *) tmp1; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Match sibling lnode */ 1528c2ecf20Sopenharmony_ci if (sln->vnp_flowid == vnp_id) 1538c2ecf20Sopenharmony_ci return sln; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (list_empty(&sln->cln_head)) 1568c2ecf20Sopenharmony_ci continue; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* Traverse children lnodes */ 1598c2ecf20Sopenharmony_ci list_for_each(tmp2, &sln->cln_head) { 1608c2ecf20Sopenharmony_ci cln = (struct csio_lnode *) tmp2; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (cln->vnp_flowid == vnp_id) 1638c2ecf20Sopenharmony_ci return cln; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_lnlkup_miss); 1678c2ecf20Sopenharmony_ci return NULL; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/** 1718c2ecf20Sopenharmony_ci * csio_lnode_lookup_by_wwpn - Lookup lnode using given wwpn. 1728c2ecf20Sopenharmony_ci * @hw: HW module. 1738c2ecf20Sopenharmony_ci * @wwpn: WWPN. 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * If found, returns lnode matching given wwpn, returns NULL otherwise. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_cistruct csio_lnode * 1788c2ecf20Sopenharmony_cicsio_lnode_lookup_by_wwpn(struct csio_hw *hw, uint8_t *wwpn) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct list_head *tmp1, *tmp2; 1818c2ecf20Sopenharmony_ci struct csio_lnode *sln = NULL, *cln = NULL; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (list_empty(&hw->sln_head)) { 1848c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_lnlkup_miss); 1858c2ecf20Sopenharmony_ci return NULL; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci /* Traverse sibling lnodes */ 1888c2ecf20Sopenharmony_ci list_for_each(tmp1, &hw->sln_head) { 1898c2ecf20Sopenharmony_ci sln = (struct csio_lnode *) tmp1; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* Match sibling lnode */ 1928c2ecf20Sopenharmony_ci if (!memcmp(csio_ln_wwpn(sln), wwpn, 8)) 1938c2ecf20Sopenharmony_ci return sln; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (list_empty(&sln->cln_head)) 1968c2ecf20Sopenharmony_ci continue; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* Traverse children lnodes */ 1998c2ecf20Sopenharmony_ci list_for_each(tmp2, &sln->cln_head) { 2008c2ecf20Sopenharmony_ci cln = (struct csio_lnode *) tmp2; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (!memcmp(csio_ln_wwpn(cln), wwpn, 8)) 2038c2ecf20Sopenharmony_ci return cln; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci return NULL; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* FDMI */ 2108c2ecf20Sopenharmony_cistatic void 2118c2ecf20Sopenharmony_cicsio_fill_ct_iu(void *buf, uint8_t type, uint8_t sub_type, uint16_t op) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct fc_ct_hdr *cmd = (struct fc_ct_hdr *)buf; 2148c2ecf20Sopenharmony_ci cmd->ct_rev = FC_CT_REV; 2158c2ecf20Sopenharmony_ci cmd->ct_fs_type = type; 2168c2ecf20Sopenharmony_ci cmd->ct_fs_subtype = sub_type; 2178c2ecf20Sopenharmony_ci cmd->ct_cmd = htons(op); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int 2218c2ecf20Sopenharmony_cicsio_hostname(uint8_t *buf, size_t buf_len) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci if (snprintf(buf, buf_len, "%s", init_utsname()->nodename) > 0) 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci return -1; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic int 2298c2ecf20Sopenharmony_cicsio_osname(uint8_t *buf, size_t buf_len) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci if (snprintf(buf, buf_len, "%s %s %s", 2328c2ecf20Sopenharmony_ci init_utsname()->sysname, 2338c2ecf20Sopenharmony_ci init_utsname()->release, 2348c2ecf20Sopenharmony_ci init_utsname()->version) > 0) 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return -1; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic inline void 2418c2ecf20Sopenharmony_cicsio_append_attrib(uint8_t **ptr, uint16_t type, void *val, size_t val_len) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci uint16_t len; 2448c2ecf20Sopenharmony_ci struct fc_fdmi_attr_entry *ae = (struct fc_fdmi_attr_entry *)*ptr; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (WARN_ON(val_len > U16_MAX)) 2478c2ecf20Sopenharmony_ci return; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci len = val_len; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ae->type = htons(type); 2528c2ecf20Sopenharmony_ci len += 4; /* includes attribute type and length */ 2538c2ecf20Sopenharmony_ci len = (len + 3) & ~3; /* should be multiple of 4 bytes */ 2548c2ecf20Sopenharmony_ci ae->len = htons(len); 2558c2ecf20Sopenharmony_ci memcpy(ae->value, val, val_len); 2568c2ecf20Sopenharmony_ci if (len > val_len) 2578c2ecf20Sopenharmony_ci memset(ae->value + val_len, 0, len - val_len); 2588c2ecf20Sopenharmony_ci *ptr += len; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* 2628c2ecf20Sopenharmony_ci * csio_ln_fdmi_done - FDMI registeration completion 2638c2ecf20Sopenharmony_ci * @hw: HW context 2648c2ecf20Sopenharmony_ci * @fdmi_req: fdmi request 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_cistatic void 2678c2ecf20Sopenharmony_cicsio_ln_fdmi_done(struct csio_hw *hw, struct csio_ioreq *fdmi_req) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci void *cmd; 2708c2ecf20Sopenharmony_ci struct csio_lnode *ln = fdmi_req->lnode; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (fdmi_req->wr_status != FW_SUCCESS) { 2738c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "WR error:%x in processing fdmi rpa cmd\n", 2748c2ecf20Sopenharmony_ci fdmi_req->wr_status); 2758c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci cmd = fdmi_req->dma_buf.vaddr; 2798c2ecf20Sopenharmony_ci if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) { 2808c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "fdmi rpa cmd rejected reason %x expl %x\n", 2818c2ecf20Sopenharmony_ci csio_ct_reason(cmd), csio_ct_expl(cmd)); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* 2868c2ecf20Sopenharmony_ci * csio_ln_fdmi_rhba_cbfn - RHBA completion 2878c2ecf20Sopenharmony_ci * @hw: HW context 2888c2ecf20Sopenharmony_ci * @fdmi_req: fdmi request 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_cistatic void 2918c2ecf20Sopenharmony_cicsio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci void *cmd; 2948c2ecf20Sopenharmony_ci uint8_t *pld; 2958c2ecf20Sopenharmony_ci uint32_t len = 0; 2968c2ecf20Sopenharmony_ci __be32 val; 2978c2ecf20Sopenharmony_ci __be16 mfs; 2988c2ecf20Sopenharmony_ci uint32_t numattrs = 0; 2998c2ecf20Sopenharmony_ci struct csio_lnode *ln = fdmi_req->lnode; 3008c2ecf20Sopenharmony_ci struct fs_fdmi_attrs *attrib_blk; 3018c2ecf20Sopenharmony_ci struct fc_fdmi_port_name *port_name; 3028c2ecf20Sopenharmony_ci uint8_t buf[64]; 3038c2ecf20Sopenharmony_ci uint8_t *fc4_type; 3048c2ecf20Sopenharmony_ci unsigned long flags; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (fdmi_req->wr_status != FW_SUCCESS) { 3078c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "WR error:%x in processing fdmi rhba cmd\n", 3088c2ecf20Sopenharmony_ci fdmi_req->wr_status); 3098c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci cmd = fdmi_req->dma_buf.vaddr; 3138c2ecf20Sopenharmony_ci if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) { 3148c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "fdmi rhba cmd rejected reason %x expl %x\n", 3158c2ecf20Sopenharmony_ci csio_ct_reason(cmd), csio_ct_expl(cmd)); 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (!csio_is_rnode_ready(fdmi_req->rnode)) { 3198c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 3208c2ecf20Sopenharmony_ci return; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* Prepare CT hdr for RPA cmd */ 3248c2ecf20Sopenharmony_ci memset(cmd, 0, FC_CT_HDR_LEN); 3258c2ecf20Sopenharmony_ci csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, FC_FDMI_RPA); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Prepare RPA payload */ 3288c2ecf20Sopenharmony_ci pld = (uint8_t *)csio_ct_get_pld(cmd); 3298c2ecf20Sopenharmony_ci port_name = (struct fc_fdmi_port_name *)pld; 3308c2ecf20Sopenharmony_ci memcpy(&port_name->portname, csio_ln_wwpn(ln), 8); 3318c2ecf20Sopenharmony_ci pld += sizeof(*port_name); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* Start appending Port attributes */ 3348c2ecf20Sopenharmony_ci attrib_blk = (struct fs_fdmi_attrs *)pld; 3358c2ecf20Sopenharmony_ci attrib_blk->numattrs = 0; 3368c2ecf20Sopenharmony_ci len += sizeof(attrib_blk->numattrs); 3378c2ecf20Sopenharmony_ci pld += sizeof(attrib_blk->numattrs); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci fc4_type = &buf[0]; 3408c2ecf20Sopenharmony_ci memset(fc4_type, 0, FC_FDMI_PORT_ATTR_FC4TYPES_LEN); 3418c2ecf20Sopenharmony_ci fc4_type[2] = 1; 3428c2ecf20Sopenharmony_ci fc4_type[7] = 1; 3438c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_FC4TYPES, 3448c2ecf20Sopenharmony_ci fc4_type, FC_FDMI_PORT_ATTR_FC4TYPES_LEN); 3458c2ecf20Sopenharmony_ci numattrs++; 3468c2ecf20Sopenharmony_ci val = htonl(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); 3478c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_SUPPORTEDSPEED, 3488c2ecf20Sopenharmony_ci &val, 3498c2ecf20Sopenharmony_ci FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN); 3508c2ecf20Sopenharmony_ci numattrs++; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_1G) 3538c2ecf20Sopenharmony_ci val = htonl(FC_PORTSPEED_1GBIT); 3548c2ecf20Sopenharmony_ci else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_10G) 3558c2ecf20Sopenharmony_ci val = htonl(FC_PORTSPEED_10GBIT); 3568c2ecf20Sopenharmony_ci else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_25G) 3578c2ecf20Sopenharmony_ci val = htonl(FC_PORTSPEED_25GBIT); 3588c2ecf20Sopenharmony_ci else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_40G) 3598c2ecf20Sopenharmony_ci val = htonl(FC_PORTSPEED_40GBIT); 3608c2ecf20Sopenharmony_ci else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_50G) 3618c2ecf20Sopenharmony_ci val = htonl(FC_PORTSPEED_50GBIT); 3628c2ecf20Sopenharmony_ci else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_100G) 3638c2ecf20Sopenharmony_ci val = htonl(FC_PORTSPEED_100GBIT); 3648c2ecf20Sopenharmony_ci else 3658c2ecf20Sopenharmony_ci val = htonl(CSIO_HBA_PORTSPEED_UNKNOWN); 3668c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED, 3678c2ecf20Sopenharmony_ci &val, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN); 3688c2ecf20Sopenharmony_ci numattrs++; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci mfs = ln->ln_sparm.csp.sp_bb_data; 3718c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_MAXFRAMESIZE, 3728c2ecf20Sopenharmony_ci &mfs, sizeof(mfs)); 3738c2ecf20Sopenharmony_ci numattrs++; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci strcpy(buf, "csiostor"); 3768c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_OSDEVICENAME, buf, 3778c2ecf20Sopenharmony_ci strlen(buf)); 3788c2ecf20Sopenharmony_ci numattrs++; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (!csio_hostname(buf, sizeof(buf))) { 3818c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_HOSTNAME, 3828c2ecf20Sopenharmony_ci buf, strlen(buf)); 3838c2ecf20Sopenharmony_ci numattrs++; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci attrib_blk->numattrs = htonl(numattrs); 3868c2ecf20Sopenharmony_ci len = (uint32_t)(pld - (uint8_t *)cmd); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Submit FDMI RPA request */ 3898c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 3908c2ecf20Sopenharmony_ci if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_done, 3918c2ecf20Sopenharmony_ci FCOE_CT, &fdmi_req->dma_buf, len)) { 3928c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 3938c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "Failed to issue fdmi rpa req\n"); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci/* 3998c2ecf20Sopenharmony_ci * csio_ln_fdmi_dprt_cbfn - DPRT completion 4008c2ecf20Sopenharmony_ci * @hw: HW context 4018c2ecf20Sopenharmony_ci * @fdmi_req: fdmi request 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_cistatic void 4048c2ecf20Sopenharmony_cicsio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci void *cmd; 4078c2ecf20Sopenharmony_ci uint8_t *pld; 4088c2ecf20Sopenharmony_ci uint32_t len = 0; 4098c2ecf20Sopenharmony_ci uint32_t numattrs = 0; 4108c2ecf20Sopenharmony_ci __be32 maxpayload = htonl(65536); 4118c2ecf20Sopenharmony_ci struct fc_fdmi_hba_identifier *hbaid; 4128c2ecf20Sopenharmony_ci struct csio_lnode *ln = fdmi_req->lnode; 4138c2ecf20Sopenharmony_ci struct fc_fdmi_rpl *reg_pl; 4148c2ecf20Sopenharmony_ci struct fs_fdmi_attrs *attrib_blk; 4158c2ecf20Sopenharmony_ci uint8_t buf[64]; 4168c2ecf20Sopenharmony_ci unsigned long flags; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (fdmi_req->wr_status != FW_SUCCESS) { 4198c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "WR error:%x in processing fdmi dprt cmd\n", 4208c2ecf20Sopenharmony_ci fdmi_req->wr_status); 4218c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (!csio_is_rnode_ready(fdmi_req->rnode)) { 4258c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci cmd = fdmi_req->dma_buf.vaddr; 4298c2ecf20Sopenharmony_ci if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) { 4308c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "fdmi dprt cmd rejected reason %x expl %x\n", 4318c2ecf20Sopenharmony_ci csio_ct_reason(cmd), csio_ct_expl(cmd)); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Prepare CT hdr for RHBA cmd */ 4358c2ecf20Sopenharmony_ci memset(cmd, 0, FC_CT_HDR_LEN); 4368c2ecf20Sopenharmony_ci csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, FC_FDMI_RHBA); 4378c2ecf20Sopenharmony_ci len = FC_CT_HDR_LEN; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* Prepare RHBA payload */ 4408c2ecf20Sopenharmony_ci pld = (uint8_t *)csio_ct_get_pld(cmd); 4418c2ecf20Sopenharmony_ci hbaid = (struct fc_fdmi_hba_identifier *)pld; 4428c2ecf20Sopenharmony_ci memcpy(&hbaid->id, csio_ln_wwpn(ln), 8); /* HBA identifer */ 4438c2ecf20Sopenharmony_ci pld += sizeof(*hbaid); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* Register one port per hba */ 4468c2ecf20Sopenharmony_ci reg_pl = (struct fc_fdmi_rpl *)pld; 4478c2ecf20Sopenharmony_ci reg_pl->numport = htonl(1); 4488c2ecf20Sopenharmony_ci memcpy(®_pl->port[0].portname, csio_ln_wwpn(ln), 8); 4498c2ecf20Sopenharmony_ci pld += sizeof(*reg_pl); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Start appending HBA attributes hba */ 4528c2ecf20Sopenharmony_ci attrib_blk = (struct fs_fdmi_attrs *)pld; 4538c2ecf20Sopenharmony_ci attrib_blk->numattrs = 0; 4548c2ecf20Sopenharmony_ci len += sizeof(attrib_blk->numattrs); 4558c2ecf20Sopenharmony_ci pld += sizeof(attrib_blk->numattrs); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_NODENAME, csio_ln_wwnn(ln), 4588c2ecf20Sopenharmony_ci FC_FDMI_HBA_ATTR_NODENAME_LEN); 4598c2ecf20Sopenharmony_ci numattrs++; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci memset(buf, 0, sizeof(buf)); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci strcpy(buf, "Chelsio Communications"); 4648c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MANUFACTURER, buf, 4658c2ecf20Sopenharmony_ci strlen(buf)); 4668c2ecf20Sopenharmony_ci numattrs++; 4678c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_SERIALNUMBER, 4688c2ecf20Sopenharmony_ci hw->vpd.sn, sizeof(hw->vpd.sn)); 4698c2ecf20Sopenharmony_ci numattrs++; 4708c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODEL, hw->vpd.id, 4718c2ecf20Sopenharmony_ci sizeof(hw->vpd.id)); 4728c2ecf20Sopenharmony_ci numattrs++; 4738c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MODELDESCRIPTION, 4748c2ecf20Sopenharmony_ci hw->model_desc, strlen(hw->model_desc)); 4758c2ecf20Sopenharmony_ci numattrs++; 4768c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_HARDWAREVERSION, 4778c2ecf20Sopenharmony_ci hw->hw_ver, sizeof(hw->hw_ver)); 4788c2ecf20Sopenharmony_ci numattrs++; 4798c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_FIRMWAREVERSION, 4808c2ecf20Sopenharmony_ci hw->fwrev_str, strlen(hw->fwrev_str)); 4818c2ecf20Sopenharmony_ci numattrs++; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (!csio_osname(buf, sizeof(buf))) { 4848c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_OSNAMEVERSION, 4858c2ecf20Sopenharmony_ci buf, strlen(buf)); 4868c2ecf20Sopenharmony_ci numattrs++; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci csio_append_attrib(&pld, FC_FDMI_HBA_ATTR_MAXCTPAYLOAD, 4908c2ecf20Sopenharmony_ci &maxpayload, FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN); 4918c2ecf20Sopenharmony_ci len = (uint32_t)(pld - (uint8_t *)cmd); 4928c2ecf20Sopenharmony_ci numattrs++; 4938c2ecf20Sopenharmony_ci attrib_blk->numattrs = htonl(numattrs); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* Submit FDMI RHBA request */ 4968c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 4978c2ecf20Sopenharmony_ci if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_rhba_cbfn, 4988c2ecf20Sopenharmony_ci FCOE_CT, &fdmi_req->dma_buf, len)) { 4998c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 5008c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "Failed to issue fdmi rhba req\n"); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci/* 5068c2ecf20Sopenharmony_ci * csio_ln_fdmi_dhba_cbfn - DHBA completion 5078c2ecf20Sopenharmony_ci * @hw: HW context 5088c2ecf20Sopenharmony_ci * @fdmi_req: fdmi request 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_cistatic void 5118c2ecf20Sopenharmony_cicsio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct csio_lnode *ln = fdmi_req->lnode; 5148c2ecf20Sopenharmony_ci void *cmd; 5158c2ecf20Sopenharmony_ci struct fc_fdmi_port_name *port_name; 5168c2ecf20Sopenharmony_ci uint32_t len; 5178c2ecf20Sopenharmony_ci unsigned long flags; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (fdmi_req->wr_status != FW_SUCCESS) { 5208c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "WR error:%x in processing fdmi dhba cmd\n", 5218c2ecf20Sopenharmony_ci fdmi_req->wr_status); 5228c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (!csio_is_rnode_ready(fdmi_req->rnode)) { 5268c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 5278c2ecf20Sopenharmony_ci return; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci cmd = fdmi_req->dma_buf.vaddr; 5308c2ecf20Sopenharmony_ci if (ntohs(csio_ct_rsp(cmd)) != FC_FS_ACC) { 5318c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "fdmi dhba cmd rejected reason %x expl %x\n", 5328c2ecf20Sopenharmony_ci csio_ct_reason(cmd), csio_ct_expl(cmd)); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* Send FDMI cmd to de-register any Port attributes if registered 5368c2ecf20Sopenharmony_ci * before 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* Prepare FDMI DPRT cmd */ 5408c2ecf20Sopenharmony_ci memset(cmd, 0, FC_CT_HDR_LEN); 5418c2ecf20Sopenharmony_ci csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, FC_FDMI_DPRT); 5428c2ecf20Sopenharmony_ci len = FC_CT_HDR_LEN; 5438c2ecf20Sopenharmony_ci port_name = (struct fc_fdmi_port_name *)csio_ct_get_pld(cmd); 5448c2ecf20Sopenharmony_ci memcpy(&port_name->portname, csio_ln_wwpn(ln), 8); 5458c2ecf20Sopenharmony_ci len += sizeof(*port_name); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* Submit FDMI request */ 5488c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 5498c2ecf20Sopenharmony_ci if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dprt_cbfn, 5508c2ecf20Sopenharmony_ci FCOE_CT, &fdmi_req->dma_buf, len)) { 5518c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 5528c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "Failed to issue fdmi dprt req\n"); 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/** 5588c2ecf20Sopenharmony_ci * csio_ln_fdmi_start - Start an FDMI request. 5598c2ecf20Sopenharmony_ci * @ln: lnode 5608c2ecf20Sopenharmony_ci * @context: session context 5618c2ecf20Sopenharmony_ci * 5628c2ecf20Sopenharmony_ci * Issued with lock held. 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_ciint 5658c2ecf20Sopenharmony_cicsio_ln_fdmi_start(struct csio_lnode *ln, void *context) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct csio_ioreq *fdmi_req; 5688c2ecf20Sopenharmony_ci struct csio_rnode *fdmi_rn = (struct csio_rnode *)context; 5698c2ecf20Sopenharmony_ci void *cmd; 5708c2ecf20Sopenharmony_ci struct fc_fdmi_hba_identifier *hbaid; 5718c2ecf20Sopenharmony_ci uint32_t len; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (!(ln->flags & CSIO_LNF_FDMI_ENABLE)) 5748c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (!csio_is_rnode_ready(fdmi_rn)) 5778c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* Send FDMI cmd to de-register any HBA attributes if registered 5808c2ecf20Sopenharmony_ci * before 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci fdmi_req = ln->mgmt_req; 5848c2ecf20Sopenharmony_ci fdmi_req->lnode = ln; 5858c2ecf20Sopenharmony_ci fdmi_req->rnode = fdmi_rn; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* Prepare FDMI DHBA cmd */ 5888c2ecf20Sopenharmony_ci cmd = fdmi_req->dma_buf.vaddr; 5898c2ecf20Sopenharmony_ci memset(cmd, 0, FC_CT_HDR_LEN); 5908c2ecf20Sopenharmony_ci csio_fill_ct_iu(cmd, FC_FST_MGMT, FC_FDMI_SUBTYPE, FC_FDMI_DHBA); 5918c2ecf20Sopenharmony_ci len = FC_CT_HDR_LEN; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci hbaid = (struct fc_fdmi_hba_identifier *)csio_ct_get_pld(cmd); 5948c2ecf20Sopenharmony_ci memcpy(&hbaid->id, csio_ln_wwpn(ln), 8); 5958c2ecf20Sopenharmony_ci len += sizeof(*hbaid); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* Submit FDMI request */ 5988c2ecf20Sopenharmony_ci if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dhba_cbfn, 5998c2ecf20Sopenharmony_ci FCOE_CT, &fdmi_req->dma_buf, len)) { 6008c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_fdmi_err); 6018c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "Failed to issue fdmi dhba req\n"); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci/* 6088c2ecf20Sopenharmony_ci * csio_ln_vnp_read_cbfn - vnp read completion handler. 6098c2ecf20Sopenharmony_ci * @hw: HW lnode 6108c2ecf20Sopenharmony_ci * @cbfn: Completion handler. 6118c2ecf20Sopenharmony_ci * 6128c2ecf20Sopenharmony_ci * Reads vnp response and updates ln parameters. 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_cistatic void 6158c2ecf20Sopenharmony_cicsio_ln_vnp_read_cbfn(struct csio_hw *hw, struct csio_mb *mbp) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct csio_lnode *ln = ((struct csio_lnode *)mbp->priv); 6188c2ecf20Sopenharmony_ci struct fw_fcoe_vnp_cmd *rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb); 6198c2ecf20Sopenharmony_ci struct fc_els_csp *csp; 6208c2ecf20Sopenharmony_ci struct fc_els_cssp *clsp; 6218c2ecf20Sopenharmony_ci enum fw_retval retval; 6228c2ecf20Sopenharmony_ci __be32 nport_id = 0; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci retval = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)); 6258c2ecf20Sopenharmony_ci if (retval != FW_SUCCESS) { 6268c2ecf20Sopenharmony_ci csio_err(hw, "FCOE VNP read cmd returned error:0x%x\n", retval); 6278c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 6288c2ecf20Sopenharmony_ci return; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci memcpy(ln->mac, rsp->vnport_mac, sizeof(ln->mac)); 6348c2ecf20Sopenharmony_ci memcpy(&nport_id, &rsp->vnport_mac[3], sizeof(uint8_t)*3); 6358c2ecf20Sopenharmony_ci ln->nport_id = ntohl(nport_id); 6368c2ecf20Sopenharmony_ci ln->nport_id = ln->nport_id >> 8; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* Update WWNs */ 6398c2ecf20Sopenharmony_ci /* 6408c2ecf20Sopenharmony_ci * This may look like a duplication of what csio_fcoe_enable_link() 6418c2ecf20Sopenharmony_ci * does, but is absolutely necessary if the vnpi changes between 6428c2ecf20Sopenharmony_ci * a FCOE LINK UP and FCOE LINK DOWN. 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_ci memcpy(csio_ln_wwnn(ln), rsp->vnport_wwnn, 8); 6458c2ecf20Sopenharmony_ci memcpy(csio_ln_wwpn(ln), rsp->vnport_wwpn, 8); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Copy common sparam */ 6488c2ecf20Sopenharmony_ci csp = (struct fc_els_csp *)rsp->cmn_srv_parms; 6498c2ecf20Sopenharmony_ci ln->ln_sparm.csp.sp_hi_ver = csp->sp_hi_ver; 6508c2ecf20Sopenharmony_ci ln->ln_sparm.csp.sp_lo_ver = csp->sp_lo_ver; 6518c2ecf20Sopenharmony_ci ln->ln_sparm.csp.sp_bb_cred = csp->sp_bb_cred; 6528c2ecf20Sopenharmony_ci ln->ln_sparm.csp.sp_features = csp->sp_features; 6538c2ecf20Sopenharmony_ci ln->ln_sparm.csp.sp_bb_data = csp->sp_bb_data; 6548c2ecf20Sopenharmony_ci ln->ln_sparm.csp.sp_r_a_tov = csp->sp_r_a_tov; 6558c2ecf20Sopenharmony_ci ln->ln_sparm.csp.sp_e_d_tov = csp->sp_e_d_tov; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* Copy word 0 & word 1 of class sparam */ 6588c2ecf20Sopenharmony_ci clsp = (struct fc_els_cssp *)rsp->clsp_word_0_1; 6598c2ecf20Sopenharmony_ci ln->ln_sparm.clsp[2].cp_class = clsp->cp_class; 6608c2ecf20Sopenharmony_ci ln->ln_sparm.clsp[2].cp_init = clsp->cp_init; 6618c2ecf20Sopenharmony_ci ln->ln_sparm.clsp[2].cp_recip = clsp->cp_recip; 6628c2ecf20Sopenharmony_ci ln->ln_sparm.clsp[2].cp_rdfs = clsp->cp_rdfs; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* Send an event to update local attribs */ 6698c2ecf20Sopenharmony_ci csio_lnode_async_event(ln, CSIO_LN_FC_ATTRIB_UPDATE); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/* 6738c2ecf20Sopenharmony_ci * csio_ln_vnp_read - Read vnp params. 6748c2ecf20Sopenharmony_ci * @ln: lnode 6758c2ecf20Sopenharmony_ci * @cbfn: Completion handler. 6768c2ecf20Sopenharmony_ci * 6778c2ecf20Sopenharmony_ci * Issued with lock held. 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_cistatic int 6808c2ecf20Sopenharmony_cicsio_ln_vnp_read(struct csio_lnode *ln, 6818c2ecf20Sopenharmony_ci void (*cbfn) (struct csio_hw *, struct csio_mb *)) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci struct csio_hw *hw = ln->hwp; 6848c2ecf20Sopenharmony_ci struct csio_mb *mbp; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* Allocate Mbox request */ 6878c2ecf20Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 6888c2ecf20Sopenharmony_ci if (!mbp) { 6898c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_err_nomem); 6908c2ecf20Sopenharmony_ci return -ENOMEM; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* Prepare VNP Command */ 6948c2ecf20Sopenharmony_ci csio_fcoe_vnp_read_init_mb(ln, mbp, 6958c2ecf20Sopenharmony_ci CSIO_MB_DEFAULT_TMO, 6968c2ecf20Sopenharmony_ci ln->fcf_flowid, 6978c2ecf20Sopenharmony_ci ln->vnp_flowid, 6988c2ecf20Sopenharmony_ci cbfn); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* Issue MBOX cmd */ 7018c2ecf20Sopenharmony_ci if (csio_mb_issue(hw, mbp)) { 7028c2ecf20Sopenharmony_ci csio_err(hw, "Failed to issue mbox FCoE VNP command\n"); 7038c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 7048c2ecf20Sopenharmony_ci return -EINVAL; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci return 0; 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci/* 7118c2ecf20Sopenharmony_ci * csio_fcoe_enable_link - Enable fcoe link. 7128c2ecf20Sopenharmony_ci * @ln: lnode 7138c2ecf20Sopenharmony_ci * @enable: enable/disable 7148c2ecf20Sopenharmony_ci * Issued with lock held. 7158c2ecf20Sopenharmony_ci * Issues mbox cmd to bring up FCOE link on port associated with given ln. 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_cistatic int 7188c2ecf20Sopenharmony_cicsio_fcoe_enable_link(struct csio_lnode *ln, bool enable) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct csio_hw *hw = ln->hwp; 7218c2ecf20Sopenharmony_ci struct csio_mb *mbp; 7228c2ecf20Sopenharmony_ci enum fw_retval retval; 7238c2ecf20Sopenharmony_ci uint8_t portid; 7248c2ecf20Sopenharmony_ci uint8_t sub_op; 7258c2ecf20Sopenharmony_ci struct fw_fcoe_link_cmd *lcmd; 7268c2ecf20Sopenharmony_ci int i; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 7298c2ecf20Sopenharmony_ci if (!mbp) { 7308c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_err_nomem); 7318c2ecf20Sopenharmony_ci return -ENOMEM; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci portid = ln->portid; 7358c2ecf20Sopenharmony_ci sub_op = enable ? FCOE_LINK_UP : FCOE_LINK_DOWN; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci csio_dbg(hw, "bringing FCOE LINK %s on Port:%d\n", 7388c2ecf20Sopenharmony_ci sub_op ? "UP" : "DOWN", portid); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci csio_write_fcoe_link_cond_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO, 7418c2ecf20Sopenharmony_ci portid, sub_op, 0, 0, 0, NULL); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (csio_mb_issue(hw, mbp)) { 7448c2ecf20Sopenharmony_ci csio_err(hw, "failed to issue FCOE LINK cmd on port[%d]\n", 7458c2ecf20Sopenharmony_ci portid); 7468c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 7478c2ecf20Sopenharmony_ci return -EINVAL; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci retval = csio_mb_fw_retval(mbp); 7518c2ecf20Sopenharmony_ci if (retval != FW_SUCCESS) { 7528c2ecf20Sopenharmony_ci csio_err(hw, 7538c2ecf20Sopenharmony_ci "FCOE LINK %s cmd on port[%d] failed with " 7548c2ecf20Sopenharmony_ci "ret:x%x\n", sub_op ? "UP" : "DOWN", portid, retval); 7558c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 7568c2ecf20Sopenharmony_ci return -EINVAL; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (!enable) 7608c2ecf20Sopenharmony_ci goto out; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci lcmd = (struct fw_fcoe_link_cmd *)mbp->mb; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci memcpy(csio_ln_wwnn(ln), lcmd->vnport_wwnn, 8); 7658c2ecf20Sopenharmony_ci memcpy(csio_ln_wwpn(ln), lcmd->vnport_wwpn, 8); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci for (i = 0; i < CSIO_MAX_PPORTS; i++) 7688c2ecf20Sopenharmony_ci if (hw->pport[i].portid == portid) 7698c2ecf20Sopenharmony_ci memcpy(hw->pport[i].mac, lcmd->phy_mac, 6); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ciout: 7728c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 7738c2ecf20Sopenharmony_ci return 0; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci/* 7778c2ecf20Sopenharmony_ci * csio_ln_read_fcf_cbfn - Read fcf parameters 7788c2ecf20Sopenharmony_ci * @ln: lnode 7798c2ecf20Sopenharmony_ci * 7808c2ecf20Sopenharmony_ci * read fcf response and Update ln fcf information. 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_cistatic void 7838c2ecf20Sopenharmony_cicsio_ln_read_fcf_cbfn(struct csio_hw *hw, struct csio_mb *mbp) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct csio_lnode *ln = (struct csio_lnode *)mbp->priv; 7868c2ecf20Sopenharmony_ci struct csio_fcf_info *fcf_info; 7878c2ecf20Sopenharmony_ci struct fw_fcoe_fcf_cmd *rsp = 7888c2ecf20Sopenharmony_ci (struct fw_fcoe_fcf_cmd *)(mbp->mb); 7898c2ecf20Sopenharmony_ci enum fw_retval retval; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16)); 7928c2ecf20Sopenharmony_ci if (retval != FW_SUCCESS) { 7938c2ecf20Sopenharmony_ci csio_ln_err(ln, "FCOE FCF cmd failed with ret x%x\n", 7948c2ecf20Sopenharmony_ci retval); 7958c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 7968c2ecf20Sopenharmony_ci return; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 8008c2ecf20Sopenharmony_ci fcf_info = ln->fcfinfo; 8018c2ecf20Sopenharmony_ci fcf_info->priority = FW_FCOE_FCF_CMD_PRIORITY_GET( 8028c2ecf20Sopenharmony_ci ntohs(rsp->priority_pkd)); 8038c2ecf20Sopenharmony_ci fcf_info->vf_id = ntohs(rsp->vf_id); 8048c2ecf20Sopenharmony_ci fcf_info->vlan_id = rsp->vlan_id; 8058c2ecf20Sopenharmony_ci fcf_info->max_fcoe_size = ntohs(rsp->max_fcoe_size); 8068c2ecf20Sopenharmony_ci fcf_info->fka_adv = be32_to_cpu(rsp->fka_adv); 8078c2ecf20Sopenharmony_ci fcf_info->fcfi = FW_FCOE_FCF_CMD_FCFI_GET(ntohl(rsp->op_to_fcfi)); 8088c2ecf20Sopenharmony_ci fcf_info->fpma = FW_FCOE_FCF_CMD_FPMA_GET(rsp->fpma_to_portid); 8098c2ecf20Sopenharmony_ci fcf_info->spma = FW_FCOE_FCF_CMD_SPMA_GET(rsp->fpma_to_portid); 8108c2ecf20Sopenharmony_ci fcf_info->login = FW_FCOE_FCF_CMD_LOGIN_GET(rsp->fpma_to_portid); 8118c2ecf20Sopenharmony_ci fcf_info->portid = FW_FCOE_FCF_CMD_PORTID_GET(rsp->fpma_to_portid); 8128c2ecf20Sopenharmony_ci memcpy(fcf_info->fc_map, rsp->fc_map, sizeof(fcf_info->fc_map)); 8138c2ecf20Sopenharmony_ci memcpy(fcf_info->mac, rsp->mac, sizeof(fcf_info->mac)); 8148c2ecf20Sopenharmony_ci memcpy(fcf_info->name_id, rsp->name_id, sizeof(fcf_info->name_id)); 8158c2ecf20Sopenharmony_ci memcpy(fcf_info->fabric, rsp->fabric, sizeof(fcf_info->fabric)); 8168c2ecf20Sopenharmony_ci memcpy(fcf_info->spma_mac, rsp->spma_mac, sizeof(fcf_info->spma_mac)); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci/* 8248c2ecf20Sopenharmony_ci * csio_ln_read_fcf_entry - Read fcf entry. 8258c2ecf20Sopenharmony_ci * @ln: lnode 8268c2ecf20Sopenharmony_ci * @cbfn: Completion handler. 8278c2ecf20Sopenharmony_ci * 8288c2ecf20Sopenharmony_ci * Issued with lock held. 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_cistatic int 8318c2ecf20Sopenharmony_cicsio_ln_read_fcf_entry(struct csio_lnode *ln, 8328c2ecf20Sopenharmony_ci void (*cbfn) (struct csio_hw *, struct csio_mb *)) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct csio_hw *hw = ln->hwp; 8358c2ecf20Sopenharmony_ci struct csio_mb *mbp; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 8388c2ecf20Sopenharmony_ci if (!mbp) { 8398c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_err_nomem); 8408c2ecf20Sopenharmony_ci return -ENOMEM; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* Get FCoE FCF information */ 8448c2ecf20Sopenharmony_ci csio_fcoe_read_fcf_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO, 8458c2ecf20Sopenharmony_ci ln->portid, ln->fcf_flowid, cbfn); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (csio_mb_issue(hw, mbp)) { 8488c2ecf20Sopenharmony_ci csio_err(hw, "failed to issue FCOE FCF cmd\n"); 8498c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 8508c2ecf20Sopenharmony_ci return -EINVAL; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci return 0; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci/* 8578c2ecf20Sopenharmony_ci * csio_handle_link_up - Logical Linkup event. 8588c2ecf20Sopenharmony_ci * @hw - HW module. 8598c2ecf20Sopenharmony_ci * @portid - Physical port number 8608c2ecf20Sopenharmony_ci * @fcfi - FCF index. 8618c2ecf20Sopenharmony_ci * @vnpi - VNP index. 8628c2ecf20Sopenharmony_ci * Returns - none. 8638c2ecf20Sopenharmony_ci * 8648c2ecf20Sopenharmony_ci * This event is received from FW, when virtual link is established between 8658c2ecf20Sopenharmony_ci * Physical port[ENode] and FCF. If its new vnpi, then local node object is 8668c2ecf20Sopenharmony_ci * created on this FCF and set to [ONLINE] state. 8678c2ecf20Sopenharmony_ci * Lnode waits for FW_RDEV_CMD event to be received indicating that 8688c2ecf20Sopenharmony_ci * Fabric login is completed and lnode moves to [READY] state. 8698c2ecf20Sopenharmony_ci * 8708c2ecf20Sopenharmony_ci * This called with hw lock held 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_cistatic void 8738c2ecf20Sopenharmony_cicsio_handle_link_up(struct csio_hw *hw, uint8_t portid, uint32_t fcfi, 8748c2ecf20Sopenharmony_ci uint32_t vnpi) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci struct csio_lnode *ln = NULL; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* Lookup lnode based on vnpi */ 8798c2ecf20Sopenharmony_ci ln = csio_ln_lookup_by_vnpi(hw, vnpi); 8808c2ecf20Sopenharmony_ci if (!ln) { 8818c2ecf20Sopenharmony_ci /* Pick lnode based on portid */ 8828c2ecf20Sopenharmony_ci ln = csio_ln_lookup_by_portid(hw, portid); 8838c2ecf20Sopenharmony_ci if (!ln) { 8848c2ecf20Sopenharmony_ci csio_err(hw, "failed to lookup fcoe lnode on port:%d\n", 8858c2ecf20Sopenharmony_ci portid); 8868c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 8878c2ecf20Sopenharmony_ci return; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci /* Check if lnode has valid vnp flowid */ 8918c2ecf20Sopenharmony_ci if (ln->vnp_flowid != CSIO_INVALID_IDX) { 8928c2ecf20Sopenharmony_ci /* New VN-Port */ 8938c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 8948c2ecf20Sopenharmony_ci csio_lnode_alloc(hw); 8958c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 8968c2ecf20Sopenharmony_ci if (!ln) { 8978c2ecf20Sopenharmony_ci csio_err(hw, 8988c2ecf20Sopenharmony_ci "failed to allocate fcoe lnode" 8998c2ecf20Sopenharmony_ci "for port:%d vnpi:x%x\n", 9008c2ecf20Sopenharmony_ci portid, vnpi); 9018c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 9028c2ecf20Sopenharmony_ci return; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci ln->portid = portid; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci ln->vnp_flowid = vnpi; 9078c2ecf20Sopenharmony_ci ln->dev_num &= ~0xFFFF; 9088c2ecf20Sopenharmony_ci ln->dev_num |= vnpi; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /*Initialize fcfi */ 9128c2ecf20Sopenharmony_ci ln->fcf_flowid = fcfi; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci csio_info(hw, "Port:%d - FCOE LINK UP\n", portid); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_link_up); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* Send LINKUP event to SM */ 9198c2ecf20Sopenharmony_ci csio_post_event(&ln->sm, CSIO_LNE_LINKUP); 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci/* 9238c2ecf20Sopenharmony_ci * csio_post_event_rns 9248c2ecf20Sopenharmony_ci * @ln - FCOE lnode 9258c2ecf20Sopenharmony_ci * @evt - Given rnode event 9268c2ecf20Sopenharmony_ci * Returns - none 9278c2ecf20Sopenharmony_ci * 9288c2ecf20Sopenharmony_ci * Posts given rnode event to all FCOE rnodes connected with given Lnode. 9298c2ecf20Sopenharmony_ci * This routine is invoked when lnode receives LINK_DOWN/DOWN_LINK/CLOSE 9308c2ecf20Sopenharmony_ci * event. 9318c2ecf20Sopenharmony_ci * 9328c2ecf20Sopenharmony_ci * This called with hw lock held 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_cistatic void 9358c2ecf20Sopenharmony_cicsio_post_event_rns(struct csio_lnode *ln, enum csio_rn_ev evt) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead; 9388c2ecf20Sopenharmony_ci struct list_head *tmp, *next; 9398c2ecf20Sopenharmony_ci struct csio_rnode *rn; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci list_for_each_safe(tmp, next, &rnhead->sm.sm_list) { 9428c2ecf20Sopenharmony_ci rn = (struct csio_rnode *) tmp; 9438c2ecf20Sopenharmony_ci csio_post_event(&rn->sm, evt); 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci/* 9488c2ecf20Sopenharmony_ci * csio_cleanup_rns 9498c2ecf20Sopenharmony_ci * @ln - FCOE lnode 9508c2ecf20Sopenharmony_ci * Returns - none 9518c2ecf20Sopenharmony_ci * 9528c2ecf20Sopenharmony_ci * Frees all FCOE rnodes connected with given Lnode. 9538c2ecf20Sopenharmony_ci * 9548c2ecf20Sopenharmony_ci * This called with hw lock held 9558c2ecf20Sopenharmony_ci */ 9568c2ecf20Sopenharmony_cistatic void 9578c2ecf20Sopenharmony_cicsio_cleanup_rns(struct csio_lnode *ln) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead; 9608c2ecf20Sopenharmony_ci struct list_head *tmp, *next_rn; 9618c2ecf20Sopenharmony_ci struct csio_rnode *rn; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci list_for_each_safe(tmp, next_rn, &rnhead->sm.sm_list) { 9648c2ecf20Sopenharmony_ci rn = (struct csio_rnode *) tmp; 9658c2ecf20Sopenharmony_ci csio_put_rnode(ln, rn); 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci/* 9718c2ecf20Sopenharmony_ci * csio_post_event_lns 9728c2ecf20Sopenharmony_ci * @ln - FCOE lnode 9738c2ecf20Sopenharmony_ci * @evt - Given lnode event 9748c2ecf20Sopenharmony_ci * Returns - none 9758c2ecf20Sopenharmony_ci * 9768c2ecf20Sopenharmony_ci * Posts given lnode event to all FCOE lnodes connected with given Lnode. 9778c2ecf20Sopenharmony_ci * This routine is invoked when lnode receives LINK_DOWN/DOWN_LINK/CLOSE 9788c2ecf20Sopenharmony_ci * event. 9798c2ecf20Sopenharmony_ci * 9808c2ecf20Sopenharmony_ci * This called with hw lock held 9818c2ecf20Sopenharmony_ci */ 9828c2ecf20Sopenharmony_cistatic void 9838c2ecf20Sopenharmony_cicsio_post_event_lns(struct csio_lnode *ln, enum csio_ln_ev evt) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci struct list_head *tmp; 9868c2ecf20Sopenharmony_ci struct csio_lnode *cln, *sln; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* If NPIV lnode, send evt only to that and return */ 9898c2ecf20Sopenharmony_ci if (csio_is_npiv_ln(ln)) { 9908c2ecf20Sopenharmony_ci csio_post_event(&ln->sm, evt); 9918c2ecf20Sopenharmony_ci return; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci sln = ln; 9958c2ecf20Sopenharmony_ci /* Traverse children lnodes list and send evt */ 9968c2ecf20Sopenharmony_ci list_for_each(tmp, &sln->cln_head) { 9978c2ecf20Sopenharmony_ci cln = (struct csio_lnode *) tmp; 9988c2ecf20Sopenharmony_ci csio_post_event(&cln->sm, evt); 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Send evt to parent lnode */ 10028c2ecf20Sopenharmony_ci csio_post_event(&ln->sm, evt); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci/* 10068c2ecf20Sopenharmony_ci * csio_ln_down - Lcoal nport is down 10078c2ecf20Sopenharmony_ci * @ln - FCOE Lnode 10088c2ecf20Sopenharmony_ci * Returns - none 10098c2ecf20Sopenharmony_ci * 10108c2ecf20Sopenharmony_ci * Sends LINK_DOWN events to Lnode and its associated NPIVs lnodes. 10118c2ecf20Sopenharmony_ci * 10128c2ecf20Sopenharmony_ci * This called with hw lock held 10138c2ecf20Sopenharmony_ci */ 10148c2ecf20Sopenharmony_cistatic void 10158c2ecf20Sopenharmony_cicsio_ln_down(struct csio_lnode *ln) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci csio_post_event_lns(ln, CSIO_LNE_LINK_DOWN); 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci/* 10218c2ecf20Sopenharmony_ci * csio_handle_link_down - Logical Linkdown event. 10228c2ecf20Sopenharmony_ci * @hw - HW module. 10238c2ecf20Sopenharmony_ci * @portid - Physical port number 10248c2ecf20Sopenharmony_ci * @fcfi - FCF index. 10258c2ecf20Sopenharmony_ci * @vnpi - VNP index. 10268c2ecf20Sopenharmony_ci * Returns - none 10278c2ecf20Sopenharmony_ci * 10288c2ecf20Sopenharmony_ci * This event is received from FW, when virtual link goes down between 10298c2ecf20Sopenharmony_ci * Physical port[ENode] and FCF. Lnode and its associated NPIVs lnode hosted on 10308c2ecf20Sopenharmony_ci * this vnpi[VN-Port] will be de-instantiated. 10318c2ecf20Sopenharmony_ci * 10328c2ecf20Sopenharmony_ci * This called with hw lock held 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_cistatic void 10358c2ecf20Sopenharmony_cicsio_handle_link_down(struct csio_hw *hw, uint8_t portid, uint32_t fcfi, 10368c2ecf20Sopenharmony_ci uint32_t vnpi) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct csio_fcf_info *fp; 10398c2ecf20Sopenharmony_ci struct csio_lnode *ln; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Lookup lnode based on vnpi */ 10428c2ecf20Sopenharmony_ci ln = csio_ln_lookup_by_vnpi(hw, vnpi); 10438c2ecf20Sopenharmony_ci if (ln) { 10448c2ecf20Sopenharmony_ci fp = ln->fcfinfo; 10458c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_link_down); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /*Warn if linkdown received if lnode is not in ready state */ 10488c2ecf20Sopenharmony_ci if (!csio_is_lnode_ready(ln)) { 10498c2ecf20Sopenharmony_ci csio_ln_warn(ln, 10508c2ecf20Sopenharmony_ci "warn: FCOE link is already in offline " 10518c2ecf20Sopenharmony_ci "Ignoring Fcoe linkdown event on portid %d\n", 10528c2ecf20Sopenharmony_ci portid); 10538c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_drop); 10548c2ecf20Sopenharmony_ci return; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci /* Verify portid */ 10588c2ecf20Sopenharmony_ci if (fp->portid != portid) { 10598c2ecf20Sopenharmony_ci csio_ln_warn(ln, 10608c2ecf20Sopenharmony_ci "warn: FCOE linkdown recv with " 10618c2ecf20Sopenharmony_ci "invalid port %d\n", portid); 10628c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_drop); 10638c2ecf20Sopenharmony_ci return; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* verify fcfi */ 10678c2ecf20Sopenharmony_ci if (ln->fcf_flowid != fcfi) { 10688c2ecf20Sopenharmony_ci csio_ln_warn(ln, 10698c2ecf20Sopenharmony_ci "warn: FCOE linkdown recv with " 10708c2ecf20Sopenharmony_ci "invalid fcfi x%x\n", fcfi); 10718c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_drop); 10728c2ecf20Sopenharmony_ci return; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci csio_info(hw, "Port:%d - FCOE LINK DOWN\n", portid); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* Send LINK_DOWN event to lnode s/m */ 10788c2ecf20Sopenharmony_ci csio_ln_down(ln); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci return; 10818c2ecf20Sopenharmony_ci } else { 10828c2ecf20Sopenharmony_ci csio_warn(hw, 10838c2ecf20Sopenharmony_ci "warn: FCOE linkdown recv with invalid vnpi x%x\n", 10848c2ecf20Sopenharmony_ci vnpi); 10858c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_evt_drop); 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci/* 10908c2ecf20Sopenharmony_ci * csio_is_lnode_ready - Checks FCOE lnode is in ready state. 10918c2ecf20Sopenharmony_ci * @ln: Lnode module 10928c2ecf20Sopenharmony_ci * 10938c2ecf20Sopenharmony_ci * Returns True if FCOE lnode is in ready state. 10948c2ecf20Sopenharmony_ci */ 10958c2ecf20Sopenharmony_ciint 10968c2ecf20Sopenharmony_cicsio_is_lnode_ready(struct csio_lnode *ln) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci return (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)); 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci/*****************************************************************************/ 11028c2ecf20Sopenharmony_ci/* START: Lnode SM */ 11038c2ecf20Sopenharmony_ci/*****************************************************************************/ 11048c2ecf20Sopenharmony_ci/* 11058c2ecf20Sopenharmony_ci * csio_lns_uninit - The request in uninit state. 11068c2ecf20Sopenharmony_ci * @ln - FCOE lnode. 11078c2ecf20Sopenharmony_ci * @evt - Event to be processed. 11088c2ecf20Sopenharmony_ci * 11098c2ecf20Sopenharmony_ci * Process the given lnode event which is currently in "uninit" state. 11108c2ecf20Sopenharmony_ci * Invoked with HW lock held. 11118c2ecf20Sopenharmony_ci * Return - none. 11128c2ecf20Sopenharmony_ci */ 11138c2ecf20Sopenharmony_cistatic void 11148c2ecf20Sopenharmony_cicsio_lns_uninit(struct csio_lnode *ln, enum csio_ln_ev evt) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 11178c2ecf20Sopenharmony_ci struct csio_lnode *rln = hw->rln; 11188c2ecf20Sopenharmony_ci int rv; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_sm[evt]); 11218c2ecf20Sopenharmony_ci switch (evt) { 11228c2ecf20Sopenharmony_ci case CSIO_LNE_LINKUP: 11238c2ecf20Sopenharmony_ci csio_set_state(&ln->sm, csio_lns_online); 11248c2ecf20Sopenharmony_ci /* Read FCF only for physical lnode */ 11258c2ecf20Sopenharmony_ci if (csio_is_phys_ln(ln)) { 11268c2ecf20Sopenharmony_ci rv = csio_ln_read_fcf_entry(ln, 11278c2ecf20Sopenharmony_ci csio_ln_read_fcf_cbfn); 11288c2ecf20Sopenharmony_ci if (rv != 0) { 11298c2ecf20Sopenharmony_ci /* TODO: Send HW RESET event */ 11308c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_err); 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* Add FCF record */ 11358c2ecf20Sopenharmony_ci list_add_tail(&ln->fcfinfo->list, &rln->fcf_lsthead); 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci rv = csio_ln_vnp_read(ln, csio_ln_vnp_read_cbfn); 11398c2ecf20Sopenharmony_ci if (rv != 0) { 11408c2ecf20Sopenharmony_ci /* TODO: Send HW RESET event */ 11418c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_err); 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci break; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci case CSIO_LNE_DOWN_LINK: 11468c2ecf20Sopenharmony_ci break; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci default: 11498c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 11508c2ecf20Sopenharmony_ci "unexp ln event %d recv from did:x%x in " 11518c2ecf20Sopenharmony_ci "ln state[uninit].\n", evt, ln->nport_id); 11528c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_unexp); 11538c2ecf20Sopenharmony_ci break; 11548c2ecf20Sopenharmony_ci } /* switch event */ 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci/* 11588c2ecf20Sopenharmony_ci * csio_lns_online - The request in online state. 11598c2ecf20Sopenharmony_ci * @ln - FCOE lnode. 11608c2ecf20Sopenharmony_ci * @evt - Event to be processed. 11618c2ecf20Sopenharmony_ci * 11628c2ecf20Sopenharmony_ci * Process the given lnode event which is currently in "online" state. 11638c2ecf20Sopenharmony_ci * Invoked with HW lock held. 11648c2ecf20Sopenharmony_ci * Return - none. 11658c2ecf20Sopenharmony_ci */ 11668c2ecf20Sopenharmony_cistatic void 11678c2ecf20Sopenharmony_cicsio_lns_online(struct csio_lnode *ln, enum csio_ln_ev evt) 11688c2ecf20Sopenharmony_ci{ 11698c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_sm[evt]); 11728c2ecf20Sopenharmony_ci switch (evt) { 11738c2ecf20Sopenharmony_ci case CSIO_LNE_LINKUP: 11748c2ecf20Sopenharmony_ci csio_ln_warn(ln, 11758c2ecf20Sopenharmony_ci "warn: FCOE link is up already " 11768c2ecf20Sopenharmony_ci "Ignoring linkup on port:%d\n", ln->portid); 11778c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_drop); 11788c2ecf20Sopenharmony_ci break; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci case CSIO_LNE_FAB_INIT_DONE: 11818c2ecf20Sopenharmony_ci csio_set_state(&ln->sm, csio_lns_ready); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 11848c2ecf20Sopenharmony_ci csio_lnode_async_event(ln, CSIO_LN_FC_LINKUP); 11858c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci break; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci case CSIO_LNE_LINK_DOWN: 11908c2ecf20Sopenharmony_ci case CSIO_LNE_DOWN_LINK: 11918c2ecf20Sopenharmony_ci csio_set_state(&ln->sm, csio_lns_uninit); 11928c2ecf20Sopenharmony_ci if (csio_is_phys_ln(ln)) { 11938c2ecf20Sopenharmony_ci /* Remove FCF entry */ 11948c2ecf20Sopenharmony_ci list_del_init(&ln->fcfinfo->list); 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci break; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci default: 11998c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 12008c2ecf20Sopenharmony_ci "unexp ln event %d recv from did:x%x in " 12018c2ecf20Sopenharmony_ci "ln state[uninit].\n", evt, ln->nport_id); 12028c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_unexp); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci break; 12058c2ecf20Sopenharmony_ci } /* switch event */ 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci/* 12098c2ecf20Sopenharmony_ci * csio_lns_ready - The request in ready state. 12108c2ecf20Sopenharmony_ci * @ln - FCOE lnode. 12118c2ecf20Sopenharmony_ci * @evt - Event to be processed. 12128c2ecf20Sopenharmony_ci * 12138c2ecf20Sopenharmony_ci * Process the given lnode event which is currently in "ready" state. 12148c2ecf20Sopenharmony_ci * Invoked with HW lock held. 12158c2ecf20Sopenharmony_ci * Return - none. 12168c2ecf20Sopenharmony_ci */ 12178c2ecf20Sopenharmony_cistatic void 12188c2ecf20Sopenharmony_cicsio_lns_ready(struct csio_lnode *ln, enum csio_ln_ev evt) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_sm[evt]); 12238c2ecf20Sopenharmony_ci switch (evt) { 12248c2ecf20Sopenharmony_ci case CSIO_LNE_FAB_INIT_DONE: 12258c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 12268c2ecf20Sopenharmony_ci "ignoring event %d recv from did x%x" 12278c2ecf20Sopenharmony_ci "in ln state[ready].\n", evt, ln->nport_id); 12288c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_drop); 12298c2ecf20Sopenharmony_ci break; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci case CSIO_LNE_LINK_DOWN: 12328c2ecf20Sopenharmony_ci csio_set_state(&ln->sm, csio_lns_offline); 12338c2ecf20Sopenharmony_ci csio_post_event_rns(ln, CSIO_RNFE_DOWN); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 12368c2ecf20Sopenharmony_ci csio_lnode_async_event(ln, CSIO_LN_FC_LINKDOWN); 12378c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (csio_is_phys_ln(ln)) { 12408c2ecf20Sopenharmony_ci /* Remove FCF entry */ 12418c2ecf20Sopenharmony_ci list_del_init(&ln->fcfinfo->list); 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci break; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci case CSIO_LNE_DOWN_LINK: 12468c2ecf20Sopenharmony_ci csio_set_state(&ln->sm, csio_lns_offline); 12478c2ecf20Sopenharmony_ci csio_post_event_rns(ln, CSIO_RNFE_DOWN); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* Host need to issue aborts in case if FW has not returned 12508c2ecf20Sopenharmony_ci * WRs with status "ABORTED" 12518c2ecf20Sopenharmony_ci */ 12528c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 12538c2ecf20Sopenharmony_ci csio_lnode_async_event(ln, CSIO_LN_FC_LINKDOWN); 12548c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (csio_is_phys_ln(ln)) { 12578c2ecf20Sopenharmony_ci /* Remove FCF entry */ 12588c2ecf20Sopenharmony_ci list_del_init(&ln->fcfinfo->list); 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci break; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci case CSIO_LNE_CLOSE: 12638c2ecf20Sopenharmony_ci csio_set_state(&ln->sm, csio_lns_uninit); 12648c2ecf20Sopenharmony_ci csio_post_event_rns(ln, CSIO_RNFE_CLOSE); 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci case CSIO_LNE_LOGO: 12688c2ecf20Sopenharmony_ci csio_set_state(&ln->sm, csio_lns_offline); 12698c2ecf20Sopenharmony_ci csio_post_event_rns(ln, CSIO_RNFE_DOWN); 12708c2ecf20Sopenharmony_ci break; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci default: 12738c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 12748c2ecf20Sopenharmony_ci "unexp ln event %d recv from did:x%x in " 12758c2ecf20Sopenharmony_ci "ln state[uninit].\n", evt, ln->nport_id); 12768c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_unexp); 12778c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 12788c2ecf20Sopenharmony_ci break; 12798c2ecf20Sopenharmony_ci } /* switch event */ 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci/* 12838c2ecf20Sopenharmony_ci * csio_lns_offline - The request in offline state. 12848c2ecf20Sopenharmony_ci * @ln - FCOE lnode. 12858c2ecf20Sopenharmony_ci * @evt - Event to be processed. 12868c2ecf20Sopenharmony_ci * 12878c2ecf20Sopenharmony_ci * Process the given lnode event which is currently in "offline" state. 12888c2ecf20Sopenharmony_ci * Invoked with HW lock held. 12898c2ecf20Sopenharmony_ci * Return - none. 12908c2ecf20Sopenharmony_ci */ 12918c2ecf20Sopenharmony_cistatic void 12928c2ecf20Sopenharmony_cicsio_lns_offline(struct csio_lnode *ln, enum csio_ln_ev evt) 12938c2ecf20Sopenharmony_ci{ 12948c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 12958c2ecf20Sopenharmony_ci struct csio_lnode *rln = hw->rln; 12968c2ecf20Sopenharmony_ci int rv; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_sm[evt]); 12998c2ecf20Sopenharmony_ci switch (evt) { 13008c2ecf20Sopenharmony_ci case CSIO_LNE_LINKUP: 13018c2ecf20Sopenharmony_ci csio_set_state(&ln->sm, csio_lns_online); 13028c2ecf20Sopenharmony_ci /* Read FCF only for physical lnode */ 13038c2ecf20Sopenharmony_ci if (csio_is_phys_ln(ln)) { 13048c2ecf20Sopenharmony_ci rv = csio_ln_read_fcf_entry(ln, 13058c2ecf20Sopenharmony_ci csio_ln_read_fcf_cbfn); 13068c2ecf20Sopenharmony_ci if (rv != 0) { 13078c2ecf20Sopenharmony_ci /* TODO: Send HW RESET event */ 13088c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_err); 13098c2ecf20Sopenharmony_ci break; 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* Add FCF record */ 13138c2ecf20Sopenharmony_ci list_add_tail(&ln->fcfinfo->list, &rln->fcf_lsthead); 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci rv = csio_ln_vnp_read(ln, csio_ln_vnp_read_cbfn); 13178c2ecf20Sopenharmony_ci if (rv != 0) { 13188c2ecf20Sopenharmony_ci /* TODO: Send HW RESET event */ 13198c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_err); 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci break; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci case CSIO_LNE_LINK_DOWN: 13248c2ecf20Sopenharmony_ci case CSIO_LNE_DOWN_LINK: 13258c2ecf20Sopenharmony_ci case CSIO_LNE_LOGO: 13268c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 13278c2ecf20Sopenharmony_ci "ignoring event %d recv from did x%x" 13288c2ecf20Sopenharmony_ci "in ln state[offline].\n", evt, ln->nport_id); 13298c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_drop); 13308c2ecf20Sopenharmony_ci break; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci case CSIO_LNE_CLOSE: 13338c2ecf20Sopenharmony_ci csio_set_state(&ln->sm, csio_lns_uninit); 13348c2ecf20Sopenharmony_ci csio_post_event_rns(ln, CSIO_RNFE_CLOSE); 13358c2ecf20Sopenharmony_ci break; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci default: 13388c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 13398c2ecf20Sopenharmony_ci "unexp ln event %d recv from did:x%x in " 13408c2ecf20Sopenharmony_ci "ln state[offline]\n", evt, ln->nport_id); 13418c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_unexp); 13428c2ecf20Sopenharmony_ci CSIO_DB_ASSERT(0); 13438c2ecf20Sopenharmony_ci break; 13448c2ecf20Sopenharmony_ci } /* switch event */ 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci/*****************************************************************************/ 13488c2ecf20Sopenharmony_ci/* END: Lnode SM */ 13498c2ecf20Sopenharmony_ci/*****************************************************************************/ 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic void 13528c2ecf20Sopenharmony_cicsio_free_fcfinfo(struct kref *kref) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci struct csio_fcf_info *fcfinfo = container_of(kref, 13558c2ecf20Sopenharmony_ci struct csio_fcf_info, kref); 13568c2ecf20Sopenharmony_ci kfree(fcfinfo); 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci/* Helper routines for attributes */ 13608c2ecf20Sopenharmony_ci/* 13618c2ecf20Sopenharmony_ci * csio_lnode_state_to_str - Get current state of FCOE lnode. 13628c2ecf20Sopenharmony_ci * @ln - lnode 13638c2ecf20Sopenharmony_ci * @str - state of lnode. 13648c2ecf20Sopenharmony_ci * 13658c2ecf20Sopenharmony_ci */ 13668c2ecf20Sopenharmony_civoid 13678c2ecf20Sopenharmony_cicsio_lnode_state_to_str(struct csio_lnode *ln, int8_t *str) 13688c2ecf20Sopenharmony_ci{ 13698c2ecf20Sopenharmony_ci if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_uninit)) { 13708c2ecf20Sopenharmony_ci strcpy(str, "UNINIT"); 13718c2ecf20Sopenharmony_ci return; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)) { 13748c2ecf20Sopenharmony_ci strcpy(str, "READY"); 13758c2ecf20Sopenharmony_ci return; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_offline)) { 13788c2ecf20Sopenharmony_ci strcpy(str, "OFFLINE"); 13798c2ecf20Sopenharmony_ci return; 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci strcpy(str, "UNKNOWN"); 13828c2ecf20Sopenharmony_ci} /* csio_lnode_state_to_str */ 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ciint 13868c2ecf20Sopenharmony_cicsio_get_phy_port_stats(struct csio_hw *hw, uint8_t portid, 13878c2ecf20Sopenharmony_ci struct fw_fcoe_port_stats *port_stats) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct csio_mb *mbp; 13908c2ecf20Sopenharmony_ci struct fw_fcoe_port_cmd_params portparams; 13918c2ecf20Sopenharmony_ci enum fw_retval retval; 13928c2ecf20Sopenharmony_ci int idx; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 13958c2ecf20Sopenharmony_ci if (!mbp) { 13968c2ecf20Sopenharmony_ci csio_err(hw, "FCoE FCF PARAMS command out of memory!\n"); 13978c2ecf20Sopenharmony_ci return -EINVAL; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci portparams.portid = portid; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci for (idx = 1; idx <= 3; idx++) { 14028c2ecf20Sopenharmony_ci portparams.idx = (idx-1)*6 + 1; 14038c2ecf20Sopenharmony_ci portparams.nstats = 6; 14048c2ecf20Sopenharmony_ci if (idx == 3) 14058c2ecf20Sopenharmony_ci portparams.nstats = 4; 14068c2ecf20Sopenharmony_ci csio_fcoe_read_portparams_init_mb(hw, mbp, CSIO_MB_DEFAULT_TMO, 14078c2ecf20Sopenharmony_ci &portparams, NULL); 14088c2ecf20Sopenharmony_ci if (csio_mb_issue(hw, mbp)) { 14098c2ecf20Sopenharmony_ci csio_err(hw, "Issue of FCoE port params failed!\n"); 14108c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 14118c2ecf20Sopenharmony_ci return -EINVAL; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci csio_mb_process_portparams_rsp(hw, mbp, &retval, 14148c2ecf20Sopenharmony_ci &portparams, port_stats); 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 14188c2ecf20Sopenharmony_ci return 0; 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci/* 14228c2ecf20Sopenharmony_ci * csio_ln_mgmt_wr_handler -Mgmt Work Request handler. 14238c2ecf20Sopenharmony_ci * @wr - WR. 14248c2ecf20Sopenharmony_ci * @len - WR len. 14258c2ecf20Sopenharmony_ci * This handler is invoked when an outstanding mgmt WR is completed. 14268c2ecf20Sopenharmony_ci * Its invoked in the context of FW event worker thread for every 14278c2ecf20Sopenharmony_ci * mgmt event received. 14288c2ecf20Sopenharmony_ci * Return - none. 14298c2ecf20Sopenharmony_ci */ 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_cistatic void 14328c2ecf20Sopenharmony_cicsio_ln_mgmt_wr_handler(struct csio_hw *hw, void *wr, uint32_t len) 14338c2ecf20Sopenharmony_ci{ 14348c2ecf20Sopenharmony_ci struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw); 14358c2ecf20Sopenharmony_ci struct csio_ioreq *io_req = NULL; 14368c2ecf20Sopenharmony_ci struct fw_fcoe_els_ct_wr *wr_cmd; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci wr_cmd = (struct fw_fcoe_els_ct_wr *) wr; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci if (len < sizeof(struct fw_fcoe_els_ct_wr)) { 14428c2ecf20Sopenharmony_ci csio_err(mgmtm->hw, 14438c2ecf20Sopenharmony_ci "Invalid ELS CT WR length recvd, len:%x\n", len); 14448c2ecf20Sopenharmony_ci mgmtm->stats.n_err++; 14458c2ecf20Sopenharmony_ci return; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci io_req = (struct csio_ioreq *) ((uintptr_t) wr_cmd->cookie); 14498c2ecf20Sopenharmony_ci io_req->wr_status = csio_wr_status(wr_cmd); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci /* lookup ioreq exists in our active Q */ 14528c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 14538c2ecf20Sopenharmony_ci if (csio_mgmt_req_lookup(mgmtm, io_req) != 0) { 14548c2ecf20Sopenharmony_ci csio_err(mgmtm->hw, 14558c2ecf20Sopenharmony_ci "Error- Invalid IO handle recv in WR. handle: %p\n", 14568c2ecf20Sopenharmony_ci io_req); 14578c2ecf20Sopenharmony_ci mgmtm->stats.n_err++; 14588c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 14598c2ecf20Sopenharmony_ci return; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci mgmtm = csio_hw_to_mgmtm(hw); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci /* Dequeue from active queue */ 14658c2ecf20Sopenharmony_ci list_del_init(&io_req->sm.sm_list); 14668c2ecf20Sopenharmony_ci mgmtm->stats.n_active--; 14678c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci /* io_req will be freed by completion handler */ 14708c2ecf20Sopenharmony_ci if (io_req->io_cbfn) 14718c2ecf20Sopenharmony_ci io_req->io_cbfn(hw, io_req); 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci/** 14758c2ecf20Sopenharmony_ci * csio_fcoe_fwevt_handler - Event handler for Firmware FCoE events. 14768c2ecf20Sopenharmony_ci * @hw: HW module 14778c2ecf20Sopenharmony_ci * @cpl_op: CPL opcode 14788c2ecf20Sopenharmony_ci * @cmd: FW cmd/WR. 14798c2ecf20Sopenharmony_ci * 14808c2ecf20Sopenharmony_ci * Process received FCoE cmd/WR event from FW. 14818c2ecf20Sopenharmony_ci */ 14828c2ecf20Sopenharmony_civoid 14838c2ecf20Sopenharmony_cicsio_fcoe_fwevt_handler(struct csio_hw *hw, __u8 cpl_op, __be64 *cmd) 14848c2ecf20Sopenharmony_ci{ 14858c2ecf20Sopenharmony_ci struct csio_lnode *ln; 14868c2ecf20Sopenharmony_ci struct csio_rnode *rn; 14878c2ecf20Sopenharmony_ci uint8_t portid, opcode = *(uint8_t *)cmd; 14888c2ecf20Sopenharmony_ci struct fw_fcoe_link_cmd *lcmd; 14898c2ecf20Sopenharmony_ci struct fw_wr_hdr *wr; 14908c2ecf20Sopenharmony_ci struct fw_rdev_wr *rdev_wr; 14918c2ecf20Sopenharmony_ci enum fw_fcoe_link_status lstatus; 14928c2ecf20Sopenharmony_ci uint32_t fcfi, rdev_flowid, vnpi; 14938c2ecf20Sopenharmony_ci enum csio_ln_ev evt; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci if (cpl_op == CPL_FW6_MSG && opcode == FW_FCOE_LINK_CMD) { 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci lcmd = (struct fw_fcoe_link_cmd *)cmd; 14988c2ecf20Sopenharmony_ci lstatus = lcmd->lstatus; 14998c2ecf20Sopenharmony_ci portid = FW_FCOE_LINK_CMD_PORTID_GET( 15008c2ecf20Sopenharmony_ci ntohl(lcmd->op_to_portid)); 15018c2ecf20Sopenharmony_ci fcfi = FW_FCOE_LINK_CMD_FCFI_GET(ntohl(lcmd->sub_opcode_fcfi)); 15028c2ecf20Sopenharmony_ci vnpi = FW_FCOE_LINK_CMD_VNPI_GET(ntohl(lcmd->vnpi_pkd)); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci if (lstatus == FCOE_LINKUP) { 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci /* HW lock here */ 15078c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 15088c2ecf20Sopenharmony_ci csio_handle_link_up(hw, portid, fcfi, vnpi); 15098c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 15108c2ecf20Sopenharmony_ci /* HW un lock here */ 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci } else if (lstatus == FCOE_LINKDOWN) { 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci /* HW lock here */ 15158c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 15168c2ecf20Sopenharmony_ci csio_handle_link_down(hw, portid, fcfi, vnpi); 15178c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 15188c2ecf20Sopenharmony_ci /* HW un lock here */ 15198c2ecf20Sopenharmony_ci } else { 15208c2ecf20Sopenharmony_ci csio_warn(hw, "Unexpected FCOE LINK status:0x%x\n", 15218c2ecf20Sopenharmony_ci lcmd->lstatus); 15228c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_cpl_unexp); 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci } else if (cpl_op == CPL_FW6_PLD) { 15258c2ecf20Sopenharmony_ci wr = (struct fw_wr_hdr *) (cmd + 4); 15268c2ecf20Sopenharmony_ci if (FW_WR_OP_G(be32_to_cpu(wr->hi)) 15278c2ecf20Sopenharmony_ci == FW_RDEV_WR) { 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci rdev_wr = (struct fw_rdev_wr *) (cmd + 4); 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci rdev_flowid = FW_RDEV_WR_FLOWID_GET( 15328c2ecf20Sopenharmony_ci ntohl(rdev_wr->alloc_to_len16)); 15338c2ecf20Sopenharmony_ci vnpi = FW_RDEV_WR_ASSOC_FLOWID_GET( 15348c2ecf20Sopenharmony_ci ntohl(rdev_wr->flags_to_assoc_flowid)); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci csio_dbg(hw, 15378c2ecf20Sopenharmony_ci "FW_RDEV_WR: flowid:x%x ev_cause:x%x " 15388c2ecf20Sopenharmony_ci "vnpi:0x%x\n", rdev_flowid, 15398c2ecf20Sopenharmony_ci rdev_wr->event_cause, vnpi); 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (rdev_wr->protocol != PROT_FCOE) { 15428c2ecf20Sopenharmony_ci csio_err(hw, 15438c2ecf20Sopenharmony_ci "FW_RDEV_WR: invalid proto:x%x " 15448c2ecf20Sopenharmony_ci "received with flowid:x%x\n", 15458c2ecf20Sopenharmony_ci rdev_wr->protocol, 15468c2ecf20Sopenharmony_ci rdev_flowid); 15478c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_evt_drop); 15488c2ecf20Sopenharmony_ci return; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci /* HW lock here */ 15528c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 15538c2ecf20Sopenharmony_ci ln = csio_ln_lookup_by_vnpi(hw, vnpi); 15548c2ecf20Sopenharmony_ci if (!ln) { 15558c2ecf20Sopenharmony_ci csio_err(hw, 15568c2ecf20Sopenharmony_ci "FW_DEV_WR: invalid vnpi:x%x received " 15578c2ecf20Sopenharmony_ci "with flowid:x%x\n", vnpi, rdev_flowid); 15588c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_evt_drop); 15598c2ecf20Sopenharmony_ci goto out_pld; 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci rn = csio_confirm_rnode(ln, rdev_flowid, 15638c2ecf20Sopenharmony_ci &rdev_wr->u.fcoe_rdev); 15648c2ecf20Sopenharmony_ci if (!rn) { 15658c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 15668c2ecf20Sopenharmony_ci "Failed to confirm rnode " 15678c2ecf20Sopenharmony_ci "for flowid:x%x\n", rdev_flowid); 15688c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_evt_drop); 15698c2ecf20Sopenharmony_ci goto out_pld; 15708c2ecf20Sopenharmony_ci } 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci /* save previous event for debugging */ 15738c2ecf20Sopenharmony_ci ln->prev_evt = ln->cur_evt; 15748c2ecf20Sopenharmony_ci ln->cur_evt = rdev_wr->event_cause; 15758c2ecf20Sopenharmony_ci CSIO_INC_STATS(ln, n_evt_fw[rdev_wr->event_cause]); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci /* Translate all the fabric events to lnode SM events */ 15788c2ecf20Sopenharmony_ci evt = CSIO_FWE_TO_LNE(rdev_wr->event_cause); 15798c2ecf20Sopenharmony_ci if (evt) { 15808c2ecf20Sopenharmony_ci csio_ln_dbg(ln, 15818c2ecf20Sopenharmony_ci "Posting event to lnode event:%d " 15828c2ecf20Sopenharmony_ci "cause:%d flowid:x%x\n", evt, 15838c2ecf20Sopenharmony_ci rdev_wr->event_cause, rdev_flowid); 15848c2ecf20Sopenharmony_ci csio_post_event(&ln->sm, evt); 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci /* Handover event to rn SM here. */ 15888c2ecf20Sopenharmony_ci csio_rnode_fwevt_handler(rn, rdev_wr->event_cause); 15898c2ecf20Sopenharmony_ciout_pld: 15908c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 15918c2ecf20Sopenharmony_ci return; 15928c2ecf20Sopenharmony_ci } else { 15938c2ecf20Sopenharmony_ci csio_warn(hw, "unexpected WR op(0x%x) recv\n", 15948c2ecf20Sopenharmony_ci FW_WR_OP_G(be32_to_cpu((wr->hi)))); 15958c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_cpl_unexp); 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci } else if (cpl_op == CPL_FW6_MSG) { 15988c2ecf20Sopenharmony_ci wr = (struct fw_wr_hdr *) (cmd); 15998c2ecf20Sopenharmony_ci if (FW_WR_OP_G(be32_to_cpu(wr->hi)) == FW_FCOE_ELS_CT_WR) { 16008c2ecf20Sopenharmony_ci csio_ln_mgmt_wr_handler(hw, wr, 16018c2ecf20Sopenharmony_ci sizeof(struct fw_fcoe_els_ct_wr)); 16028c2ecf20Sopenharmony_ci } else { 16038c2ecf20Sopenharmony_ci csio_warn(hw, "unexpected WR op(0x%x) recv\n", 16048c2ecf20Sopenharmony_ci FW_WR_OP_G(be32_to_cpu((wr->hi)))); 16058c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_cpl_unexp); 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci } else { 16088c2ecf20Sopenharmony_ci csio_warn(hw, "unexpected CPL op(0x%x) recv\n", opcode); 16098c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_cpl_unexp); 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci/** 16148c2ecf20Sopenharmony_ci * csio_lnode_start - Kickstart lnode discovery. 16158c2ecf20Sopenharmony_ci * @ln: lnode 16168c2ecf20Sopenharmony_ci * 16178c2ecf20Sopenharmony_ci * This routine kickstarts the discovery by issuing an FCOE_LINK (up) command. 16188c2ecf20Sopenharmony_ci */ 16198c2ecf20Sopenharmony_ciint 16208c2ecf20Sopenharmony_cicsio_lnode_start(struct csio_lnode *ln) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci int rv = 0; 16238c2ecf20Sopenharmony_ci if (csio_is_phys_ln(ln) && !(ln->flags & CSIO_LNF_LINK_ENABLE)) { 16248c2ecf20Sopenharmony_ci rv = csio_fcoe_enable_link(ln, 1); 16258c2ecf20Sopenharmony_ci ln->flags |= CSIO_LNF_LINK_ENABLE; 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci return rv; 16298c2ecf20Sopenharmony_ci} 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci/** 16328c2ecf20Sopenharmony_ci * csio_lnode_stop - Stop the lnode. 16338c2ecf20Sopenharmony_ci * @ln: lnode 16348c2ecf20Sopenharmony_ci * 16358c2ecf20Sopenharmony_ci * This routine is invoked by HW module to stop lnode and its associated NPIV 16368c2ecf20Sopenharmony_ci * lnodes. 16378c2ecf20Sopenharmony_ci */ 16388c2ecf20Sopenharmony_civoid 16398c2ecf20Sopenharmony_cicsio_lnode_stop(struct csio_lnode *ln) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci csio_post_event_lns(ln, CSIO_LNE_DOWN_LINK); 16428c2ecf20Sopenharmony_ci if (csio_is_phys_ln(ln) && (ln->flags & CSIO_LNF_LINK_ENABLE)) { 16438c2ecf20Sopenharmony_ci csio_fcoe_enable_link(ln, 0); 16448c2ecf20Sopenharmony_ci ln->flags &= ~CSIO_LNF_LINK_ENABLE; 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "stopping ln :%p\n", ln); 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci/** 16508c2ecf20Sopenharmony_ci * csio_lnode_close - Close an lnode. 16518c2ecf20Sopenharmony_ci * @ln: lnode 16528c2ecf20Sopenharmony_ci * 16538c2ecf20Sopenharmony_ci * This routine is invoked by HW module to close an lnode and its 16548c2ecf20Sopenharmony_ci * associated NPIV lnodes. Lnode and its associated NPIV lnodes are 16558c2ecf20Sopenharmony_ci * set to uninitialized state. 16568c2ecf20Sopenharmony_ci */ 16578c2ecf20Sopenharmony_civoid 16588c2ecf20Sopenharmony_cicsio_lnode_close(struct csio_lnode *ln) 16598c2ecf20Sopenharmony_ci{ 16608c2ecf20Sopenharmony_ci csio_post_event_lns(ln, CSIO_LNE_CLOSE); 16618c2ecf20Sopenharmony_ci if (csio_is_phys_ln(ln)) 16628c2ecf20Sopenharmony_ci ln->vnp_flowid = CSIO_INVALID_IDX; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci csio_ln_dbg(ln, "closed ln :%p\n", ln); 16658c2ecf20Sopenharmony_ci} 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci/* 16688c2ecf20Sopenharmony_ci * csio_ln_prep_ecwr - Prepare ELS/CT WR. 16698c2ecf20Sopenharmony_ci * @io_req - IO request. 16708c2ecf20Sopenharmony_ci * @wr_len - WR len 16718c2ecf20Sopenharmony_ci * @immd_len - WR immediate data 16728c2ecf20Sopenharmony_ci * @sub_op - Sub opcode 16738c2ecf20Sopenharmony_ci * @sid - source portid. 16748c2ecf20Sopenharmony_ci * @did - destination portid 16758c2ecf20Sopenharmony_ci * @flow_id - flowid 16768c2ecf20Sopenharmony_ci * @fw_wr - ELS/CT WR to be prepared. 16778c2ecf20Sopenharmony_ci * Returns: 0 - on success 16788c2ecf20Sopenharmony_ci */ 16798c2ecf20Sopenharmony_cistatic int 16808c2ecf20Sopenharmony_cicsio_ln_prep_ecwr(struct csio_ioreq *io_req, uint32_t wr_len, 16818c2ecf20Sopenharmony_ci uint32_t immd_len, uint8_t sub_op, uint32_t sid, 16828c2ecf20Sopenharmony_ci uint32_t did, uint32_t flow_id, uint8_t *fw_wr) 16838c2ecf20Sopenharmony_ci{ 16848c2ecf20Sopenharmony_ci struct fw_fcoe_els_ct_wr *wr; 16858c2ecf20Sopenharmony_ci __be32 port_id; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci wr = (struct fw_fcoe_els_ct_wr *)fw_wr; 16888c2ecf20Sopenharmony_ci wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_FCOE_ELS_CT_WR) | 16898c2ecf20Sopenharmony_ci FW_FCOE_ELS_CT_WR_IMMDLEN(immd_len)); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci wr_len = DIV_ROUND_UP(wr_len, 16); 16928c2ecf20Sopenharmony_ci wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(flow_id) | 16938c2ecf20Sopenharmony_ci FW_WR_LEN16_V(wr_len)); 16948c2ecf20Sopenharmony_ci wr->els_ct_type = sub_op; 16958c2ecf20Sopenharmony_ci wr->ctl_pri = 0; 16968c2ecf20Sopenharmony_ci wr->cp_en_class = 0; 16978c2ecf20Sopenharmony_ci wr->cookie = io_req->fw_handle; 16988c2ecf20Sopenharmony_ci wr->iqid = cpu_to_be16(csio_q_physiqid( 16998c2ecf20Sopenharmony_ci io_req->lnode->hwp, io_req->iq_idx)); 17008c2ecf20Sopenharmony_ci wr->fl_to_sp = FW_FCOE_ELS_CT_WR_SP(1); 17018c2ecf20Sopenharmony_ci wr->tmo_val = (uint8_t) io_req->tmo; 17028c2ecf20Sopenharmony_ci port_id = htonl(sid); 17038c2ecf20Sopenharmony_ci memcpy(wr->l_id, PORT_ID_PTR(port_id), 3); 17048c2ecf20Sopenharmony_ci port_id = htonl(did); 17058c2ecf20Sopenharmony_ci memcpy(wr->r_id, PORT_ID_PTR(port_id), 3); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci /* Prepare RSP SGL */ 17088c2ecf20Sopenharmony_ci wr->rsp_dmalen = cpu_to_be32(io_req->dma_buf.len); 17098c2ecf20Sopenharmony_ci wr->rsp_dmaaddr = cpu_to_be64(io_req->dma_buf.paddr); 17108c2ecf20Sopenharmony_ci return 0; 17118c2ecf20Sopenharmony_ci} 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci/* 17148c2ecf20Sopenharmony_ci * csio_ln_mgmt_submit_wr - Post elsct work request. 17158c2ecf20Sopenharmony_ci * @mgmtm - mgmtm 17168c2ecf20Sopenharmony_ci * @io_req - io request. 17178c2ecf20Sopenharmony_ci * @sub_op - ELS or CT request type 17188c2ecf20Sopenharmony_ci * @pld - Dma Payload buffer 17198c2ecf20Sopenharmony_ci * @pld_len - Payload len 17208c2ecf20Sopenharmony_ci * Prepares ELSCT Work request and sents it to FW. 17218c2ecf20Sopenharmony_ci * Returns: 0 - on success 17228c2ecf20Sopenharmony_ci */ 17238c2ecf20Sopenharmony_cistatic int 17248c2ecf20Sopenharmony_cicsio_ln_mgmt_submit_wr(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req, 17258c2ecf20Sopenharmony_ci uint8_t sub_op, struct csio_dma_buf *pld, 17268c2ecf20Sopenharmony_ci uint32_t pld_len) 17278c2ecf20Sopenharmony_ci{ 17288c2ecf20Sopenharmony_ci struct csio_wr_pair wrp; 17298c2ecf20Sopenharmony_ci struct csio_lnode *ln = io_req->lnode; 17308c2ecf20Sopenharmony_ci struct csio_rnode *rn = io_req->rnode; 17318c2ecf20Sopenharmony_ci struct csio_hw *hw = mgmtm->hw; 17328c2ecf20Sopenharmony_ci uint8_t fw_wr[64]; 17338c2ecf20Sopenharmony_ci struct ulptx_sgl dsgl; 17348c2ecf20Sopenharmony_ci uint32_t wr_size = 0; 17358c2ecf20Sopenharmony_ci uint8_t im_len = 0; 17368c2ecf20Sopenharmony_ci uint32_t wr_off = 0; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci int ret = 0; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci /* Calculate WR Size for this ELS REQ */ 17418c2ecf20Sopenharmony_ci wr_size = sizeof(struct fw_fcoe_els_ct_wr); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci /* Send as immediate data if pld < 256 */ 17448c2ecf20Sopenharmony_ci if (pld_len < 256) { 17458c2ecf20Sopenharmony_ci wr_size += ALIGN(pld_len, 8); 17468c2ecf20Sopenharmony_ci im_len = (uint8_t)pld_len; 17478c2ecf20Sopenharmony_ci } else 17488c2ecf20Sopenharmony_ci wr_size += sizeof(struct ulptx_sgl); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci /* Roundup WR size in units of 16 bytes */ 17518c2ecf20Sopenharmony_ci wr_size = ALIGN(wr_size, 16); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci /* Get WR to send ELS REQ */ 17548c2ecf20Sopenharmony_ci ret = csio_wr_get(hw, mgmtm->eq_idx, wr_size, &wrp); 17558c2ecf20Sopenharmony_ci if (ret != 0) { 17568c2ecf20Sopenharmony_ci csio_err(hw, "Failed to get WR for ec_req %p ret:%d\n", 17578c2ecf20Sopenharmony_ci io_req, ret); 17588c2ecf20Sopenharmony_ci return ret; 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* Prepare Generic WR used by all ELS/CT cmd */ 17628c2ecf20Sopenharmony_ci csio_ln_prep_ecwr(io_req, wr_size, im_len, sub_op, 17638c2ecf20Sopenharmony_ci ln->nport_id, rn->nport_id, 17648c2ecf20Sopenharmony_ci csio_rn_flowid(rn), 17658c2ecf20Sopenharmony_ci &fw_wr[0]); 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci /* Copy ELS/CT WR CMD */ 17688c2ecf20Sopenharmony_ci csio_wr_copy_to_wrp(&fw_wr[0], &wrp, wr_off, 17698c2ecf20Sopenharmony_ci sizeof(struct fw_fcoe_els_ct_wr)); 17708c2ecf20Sopenharmony_ci wr_off += sizeof(struct fw_fcoe_els_ct_wr); 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci /* Copy payload to Immediate section of WR */ 17738c2ecf20Sopenharmony_ci if (im_len) 17748c2ecf20Sopenharmony_ci csio_wr_copy_to_wrp(pld->vaddr, &wrp, wr_off, im_len); 17758c2ecf20Sopenharmony_ci else { 17768c2ecf20Sopenharmony_ci /* Program DSGL to dma payload */ 17778c2ecf20Sopenharmony_ci dsgl.cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | 17788c2ecf20Sopenharmony_ci ULPTX_MORE_F | ULPTX_NSGE_V(1)); 17798c2ecf20Sopenharmony_ci dsgl.len0 = cpu_to_be32(pld_len); 17808c2ecf20Sopenharmony_ci dsgl.addr0 = cpu_to_be64(pld->paddr); 17818c2ecf20Sopenharmony_ci csio_wr_copy_to_wrp(&dsgl, &wrp, ALIGN(wr_off, 8), 17828c2ecf20Sopenharmony_ci sizeof(struct ulptx_sgl)); 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci /* Issue work request to xmit ELS/CT req to FW */ 17868c2ecf20Sopenharmony_ci csio_wr_issue(mgmtm->hw, mgmtm->eq_idx, false); 17878c2ecf20Sopenharmony_ci return ret; 17888c2ecf20Sopenharmony_ci} 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci/* 17918c2ecf20Sopenharmony_ci * csio_ln_mgmt_submit_req - Submit FCOE Mgmt request. 17928c2ecf20Sopenharmony_ci * @io_req - IO Request 17938c2ecf20Sopenharmony_ci * @io_cbfn - Completion handler. 17948c2ecf20Sopenharmony_ci * @req_type - ELS or CT request type 17958c2ecf20Sopenharmony_ci * @pld - Dma Payload buffer 17968c2ecf20Sopenharmony_ci * @pld_len - Payload len 17978c2ecf20Sopenharmony_ci * 17988c2ecf20Sopenharmony_ci * 17998c2ecf20Sopenharmony_ci * This API used submit managment ELS/CT request. 18008c2ecf20Sopenharmony_ci * This called with hw lock held 18018c2ecf20Sopenharmony_ci * Returns: 0 - on success 18028c2ecf20Sopenharmony_ci * -ENOMEM - on error. 18038c2ecf20Sopenharmony_ci */ 18048c2ecf20Sopenharmony_cistatic int 18058c2ecf20Sopenharmony_cicsio_ln_mgmt_submit_req(struct csio_ioreq *io_req, 18068c2ecf20Sopenharmony_ci void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *), 18078c2ecf20Sopenharmony_ci enum fcoe_cmn_type req_type, struct csio_dma_buf *pld, 18088c2ecf20Sopenharmony_ci uint32_t pld_len) 18098c2ecf20Sopenharmony_ci{ 18108c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(io_req->lnode); 18118c2ecf20Sopenharmony_ci struct csio_mgmtm *mgmtm = csio_hw_to_mgmtm(hw); 18128c2ecf20Sopenharmony_ci int rv; 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci BUG_ON(pld_len > pld->len); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci io_req->io_cbfn = io_cbfn; /* Upper layer callback handler */ 18178c2ecf20Sopenharmony_ci io_req->fw_handle = (uintptr_t) (io_req); 18188c2ecf20Sopenharmony_ci io_req->eq_idx = mgmtm->eq_idx; 18198c2ecf20Sopenharmony_ci io_req->iq_idx = mgmtm->iq_idx; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci rv = csio_ln_mgmt_submit_wr(mgmtm, io_req, req_type, pld, pld_len); 18228c2ecf20Sopenharmony_ci if (rv == 0) { 18238c2ecf20Sopenharmony_ci list_add_tail(&io_req->sm.sm_list, &mgmtm->active_q); 18248c2ecf20Sopenharmony_ci mgmtm->stats.n_active++; 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci return rv; 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci/* 18308c2ecf20Sopenharmony_ci * csio_ln_fdmi_init - FDMI Init entry point. 18318c2ecf20Sopenharmony_ci * @ln: lnode 18328c2ecf20Sopenharmony_ci */ 18338c2ecf20Sopenharmony_cistatic int 18348c2ecf20Sopenharmony_cicsio_ln_fdmi_init(struct csio_lnode *ln) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 18378c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci /* Allocate MGMT request required for FDMI */ 18408c2ecf20Sopenharmony_ci ln->mgmt_req = kzalloc(sizeof(struct csio_ioreq), GFP_KERNEL); 18418c2ecf20Sopenharmony_ci if (!ln->mgmt_req) { 18428c2ecf20Sopenharmony_ci csio_ln_err(ln, "Failed to alloc ioreq for FDMI\n"); 18438c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_err_nomem); 18448c2ecf20Sopenharmony_ci return -ENOMEM; 18458c2ecf20Sopenharmony_ci } 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci /* Allocate Dma buffers for FDMI response Payload */ 18488c2ecf20Sopenharmony_ci dma_buf = &ln->mgmt_req->dma_buf; 18498c2ecf20Sopenharmony_ci dma_buf->len = 2048; 18508c2ecf20Sopenharmony_ci dma_buf->vaddr = dma_alloc_coherent(&hw->pdev->dev, dma_buf->len, 18518c2ecf20Sopenharmony_ci &dma_buf->paddr, GFP_KERNEL); 18528c2ecf20Sopenharmony_ci if (!dma_buf->vaddr) { 18538c2ecf20Sopenharmony_ci csio_err(hw, "Failed to alloc DMA buffer for FDMI!\n"); 18548c2ecf20Sopenharmony_ci kfree(ln->mgmt_req); 18558c2ecf20Sopenharmony_ci ln->mgmt_req = NULL; 18568c2ecf20Sopenharmony_ci return -ENOMEM; 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci ln->flags |= CSIO_LNF_FDMI_ENABLE; 18608c2ecf20Sopenharmony_ci return 0; 18618c2ecf20Sopenharmony_ci} 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci/* 18648c2ecf20Sopenharmony_ci * csio_ln_fdmi_exit - FDMI exit entry point. 18658c2ecf20Sopenharmony_ci * @ln: lnode 18668c2ecf20Sopenharmony_ci */ 18678c2ecf20Sopenharmony_cistatic int 18688c2ecf20Sopenharmony_cicsio_ln_fdmi_exit(struct csio_lnode *ln) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci struct csio_dma_buf *dma_buf; 18718c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci if (!ln->mgmt_req) 18748c2ecf20Sopenharmony_ci return 0; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci dma_buf = &ln->mgmt_req->dma_buf; 18778c2ecf20Sopenharmony_ci if (dma_buf->vaddr) 18788c2ecf20Sopenharmony_ci dma_free_coherent(&hw->pdev->dev, dma_buf->len, dma_buf->vaddr, 18798c2ecf20Sopenharmony_ci dma_buf->paddr); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci kfree(ln->mgmt_req); 18828c2ecf20Sopenharmony_ci return 0; 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ciint 18868c2ecf20Sopenharmony_cicsio_scan_done(struct csio_lnode *ln, unsigned long ticks, 18878c2ecf20Sopenharmony_ci unsigned long time, unsigned long max_scan_ticks, 18888c2ecf20Sopenharmony_ci unsigned long delta_scan_ticks) 18898c2ecf20Sopenharmony_ci{ 18908c2ecf20Sopenharmony_ci int rv = 0; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci if (time >= max_scan_ticks) 18938c2ecf20Sopenharmony_ci return 1; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci if (!ln->tgt_scan_tick) 18968c2ecf20Sopenharmony_ci ln->tgt_scan_tick = ticks; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (((ticks - ln->tgt_scan_tick) >= delta_scan_ticks)) { 18998c2ecf20Sopenharmony_ci if (!ln->last_scan_ntgts) 19008c2ecf20Sopenharmony_ci ln->last_scan_ntgts = ln->n_scsi_tgts; 19018c2ecf20Sopenharmony_ci else { 19028c2ecf20Sopenharmony_ci if (ln->last_scan_ntgts == ln->n_scsi_tgts) 19038c2ecf20Sopenharmony_ci return 1; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci ln->last_scan_ntgts = ln->n_scsi_tgts; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci ln->tgt_scan_tick = ticks; 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci return rv; 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci/* 19138c2ecf20Sopenharmony_ci * csio_notify_lnodes: 19148c2ecf20Sopenharmony_ci * @hw: HW module 19158c2ecf20Sopenharmony_ci * @note: Notification 19168c2ecf20Sopenharmony_ci * 19178c2ecf20Sopenharmony_ci * Called from the HW SM to fan out notifications to the 19188c2ecf20Sopenharmony_ci * Lnode SM. Since the HW SM is entered with lock held, 19198c2ecf20Sopenharmony_ci * there is no need to hold locks here. 19208c2ecf20Sopenharmony_ci * 19218c2ecf20Sopenharmony_ci */ 19228c2ecf20Sopenharmony_civoid 19238c2ecf20Sopenharmony_cicsio_notify_lnodes(struct csio_hw *hw, enum csio_ln_notify note) 19248c2ecf20Sopenharmony_ci{ 19258c2ecf20Sopenharmony_ci struct list_head *tmp; 19268c2ecf20Sopenharmony_ci struct csio_lnode *ln; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci csio_dbg(hw, "Notifying all nodes of event %d\n", note); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci /* Traverse children lnodes list and send evt */ 19318c2ecf20Sopenharmony_ci list_for_each(tmp, &hw->sln_head) { 19328c2ecf20Sopenharmony_ci ln = (struct csio_lnode *) tmp; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci switch (note) { 19358c2ecf20Sopenharmony_ci case CSIO_LN_NOTIFY_HWREADY: 19368c2ecf20Sopenharmony_ci csio_lnode_start(ln); 19378c2ecf20Sopenharmony_ci break; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci case CSIO_LN_NOTIFY_HWRESET: 19408c2ecf20Sopenharmony_ci case CSIO_LN_NOTIFY_HWREMOVE: 19418c2ecf20Sopenharmony_ci csio_lnode_close(ln); 19428c2ecf20Sopenharmony_ci break; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci case CSIO_LN_NOTIFY_HWSTOP: 19458c2ecf20Sopenharmony_ci csio_lnode_stop(ln); 19468c2ecf20Sopenharmony_ci break; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci default: 19498c2ecf20Sopenharmony_ci break; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci/* 19568c2ecf20Sopenharmony_ci * csio_disable_lnodes: 19578c2ecf20Sopenharmony_ci * @hw: HW module 19588c2ecf20Sopenharmony_ci * @portid:port id 19598c2ecf20Sopenharmony_ci * @disable: disable/enable flag. 19608c2ecf20Sopenharmony_ci * If disable=1, disables all lnode hosted on given physical port. 19618c2ecf20Sopenharmony_ci * otherwise enables all the lnodes on given phsysical port. 19628c2ecf20Sopenharmony_ci * This routine need to called with hw lock held. 19638c2ecf20Sopenharmony_ci */ 19648c2ecf20Sopenharmony_civoid 19658c2ecf20Sopenharmony_cicsio_disable_lnodes(struct csio_hw *hw, uint8_t portid, bool disable) 19668c2ecf20Sopenharmony_ci{ 19678c2ecf20Sopenharmony_ci struct list_head *tmp; 19688c2ecf20Sopenharmony_ci struct csio_lnode *ln; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci csio_dbg(hw, "Notifying event to all nodes of port:%d\n", portid); 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci /* Traverse sibling lnodes list and send evt */ 19738c2ecf20Sopenharmony_ci list_for_each(tmp, &hw->sln_head) { 19748c2ecf20Sopenharmony_ci ln = (struct csio_lnode *) tmp; 19758c2ecf20Sopenharmony_ci if (ln->portid != portid) 19768c2ecf20Sopenharmony_ci continue; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (disable) 19798c2ecf20Sopenharmony_ci csio_lnode_stop(ln); 19808c2ecf20Sopenharmony_ci else 19818c2ecf20Sopenharmony_ci csio_lnode_start(ln); 19828c2ecf20Sopenharmony_ci } 19838c2ecf20Sopenharmony_ci} 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci/* 19868c2ecf20Sopenharmony_ci * csio_ln_init - Initialize an lnode. 19878c2ecf20Sopenharmony_ci * @ln: lnode 19888c2ecf20Sopenharmony_ci * 19898c2ecf20Sopenharmony_ci */ 19908c2ecf20Sopenharmony_cistatic int 19918c2ecf20Sopenharmony_cicsio_ln_init(struct csio_lnode *ln) 19928c2ecf20Sopenharmony_ci{ 19938c2ecf20Sopenharmony_ci int rv = -EINVAL; 19948c2ecf20Sopenharmony_ci struct csio_lnode *pln; 19958c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci csio_init_state(&ln->sm, csio_lns_uninit); 19988c2ecf20Sopenharmony_ci ln->vnp_flowid = CSIO_INVALID_IDX; 19998c2ecf20Sopenharmony_ci ln->fcf_flowid = CSIO_INVALID_IDX; 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci if (csio_is_root_ln(ln)) { 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci /* This is the lnode used during initialization */ 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci ln->fcfinfo = kzalloc(sizeof(struct csio_fcf_info), GFP_KERNEL); 20068c2ecf20Sopenharmony_ci if (!ln->fcfinfo) { 20078c2ecf20Sopenharmony_ci csio_ln_err(ln, "Failed to alloc FCF record\n"); 20088c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_err_nomem); 20098c2ecf20Sopenharmony_ci goto err; 20108c2ecf20Sopenharmony_ci } 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ln->fcf_lsthead); 20138c2ecf20Sopenharmony_ci kref_init(&ln->fcfinfo->kref); 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci if (csio_fdmi_enable && csio_ln_fdmi_init(ln)) 20168c2ecf20Sopenharmony_ci goto err; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci } else { /* Either a non-root physical or a virtual lnode */ 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci /* 20218c2ecf20Sopenharmony_ci * THe rest is common for non-root physical and NPIV lnodes. 20228c2ecf20Sopenharmony_ci * Just get references to all other modules 20238c2ecf20Sopenharmony_ci */ 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci if (csio_is_npiv_ln(ln)) { 20268c2ecf20Sopenharmony_ci /* NPIV */ 20278c2ecf20Sopenharmony_ci pln = csio_parent_lnode(ln); 20288c2ecf20Sopenharmony_ci kref_get(&pln->fcfinfo->kref); 20298c2ecf20Sopenharmony_ci ln->fcfinfo = pln->fcfinfo; 20308c2ecf20Sopenharmony_ci } else { 20318c2ecf20Sopenharmony_ci /* Another non-root physical lnode (FCF) */ 20328c2ecf20Sopenharmony_ci ln->fcfinfo = kzalloc(sizeof(struct csio_fcf_info), 20338c2ecf20Sopenharmony_ci GFP_KERNEL); 20348c2ecf20Sopenharmony_ci if (!ln->fcfinfo) { 20358c2ecf20Sopenharmony_ci csio_ln_err(ln, "Failed to alloc FCF info\n"); 20368c2ecf20Sopenharmony_ci CSIO_INC_STATS(hw, n_err_nomem); 20378c2ecf20Sopenharmony_ci goto err; 20388c2ecf20Sopenharmony_ci } 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci kref_init(&ln->fcfinfo->kref); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci if (csio_fdmi_enable && csio_ln_fdmi_init(ln)) 20438c2ecf20Sopenharmony_ci goto err; 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci } /* if (!csio_is_root_ln(ln)) */ 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci return 0; 20498c2ecf20Sopenharmony_cierr: 20508c2ecf20Sopenharmony_ci return rv; 20518c2ecf20Sopenharmony_ci} 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_cistatic void 20548c2ecf20Sopenharmony_cicsio_ln_exit(struct csio_lnode *ln) 20558c2ecf20Sopenharmony_ci{ 20568c2ecf20Sopenharmony_ci struct csio_lnode *pln; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci csio_cleanup_rns(ln); 20598c2ecf20Sopenharmony_ci if (csio_is_npiv_ln(ln)) { 20608c2ecf20Sopenharmony_ci pln = csio_parent_lnode(ln); 20618c2ecf20Sopenharmony_ci kref_put(&pln->fcfinfo->kref, csio_free_fcfinfo); 20628c2ecf20Sopenharmony_ci } else { 20638c2ecf20Sopenharmony_ci kref_put(&ln->fcfinfo->kref, csio_free_fcfinfo); 20648c2ecf20Sopenharmony_ci if (csio_fdmi_enable) 20658c2ecf20Sopenharmony_ci csio_ln_fdmi_exit(ln); 20668c2ecf20Sopenharmony_ci } 20678c2ecf20Sopenharmony_ci ln->fcfinfo = NULL; 20688c2ecf20Sopenharmony_ci} 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci/* 20718c2ecf20Sopenharmony_ci * csio_lnode_init - Initialize the members of an lnode. 20728c2ecf20Sopenharmony_ci * @ln: lnode 20738c2ecf20Sopenharmony_ci */ 20748c2ecf20Sopenharmony_ciint 20758c2ecf20Sopenharmony_cicsio_lnode_init(struct csio_lnode *ln, struct csio_hw *hw, 20768c2ecf20Sopenharmony_ci struct csio_lnode *pln) 20778c2ecf20Sopenharmony_ci{ 20788c2ecf20Sopenharmony_ci int rv = -EINVAL; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci /* Link this lnode to hw */ 20818c2ecf20Sopenharmony_ci csio_lnode_to_hw(ln) = hw; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci /* Link child to parent if child lnode */ 20848c2ecf20Sopenharmony_ci if (pln) 20858c2ecf20Sopenharmony_ci ln->pln = pln; 20868c2ecf20Sopenharmony_ci else 20878c2ecf20Sopenharmony_ci ln->pln = NULL; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci /* Initialize scsi_tgt and timers to zero */ 20908c2ecf20Sopenharmony_ci ln->n_scsi_tgts = 0; 20918c2ecf20Sopenharmony_ci ln->last_scan_ntgts = 0; 20928c2ecf20Sopenharmony_ci ln->tgt_scan_tick = 0; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci /* Initialize rnode list */ 20958c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ln->rnhead); 20968c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ln->cln_head); 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci /* Initialize log level for debug */ 20998c2ecf20Sopenharmony_ci ln->params.log_level = hw->params.log_level; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci if (csio_ln_init(ln)) 21028c2ecf20Sopenharmony_ci goto err; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci /* Add lnode to list of sibling or children lnodes */ 21058c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 21068c2ecf20Sopenharmony_ci list_add_tail(&ln->sm.sm_list, pln ? &pln->cln_head : &hw->sln_head); 21078c2ecf20Sopenharmony_ci if (pln) 21088c2ecf20Sopenharmony_ci pln->num_vports++; 21098c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci hw->num_lns++; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci return 0; 21148c2ecf20Sopenharmony_cierr: 21158c2ecf20Sopenharmony_ci csio_lnode_to_hw(ln) = NULL; 21168c2ecf20Sopenharmony_ci return rv; 21178c2ecf20Sopenharmony_ci} 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci/** 21208c2ecf20Sopenharmony_ci * csio_lnode_exit - De-instantiate an lnode. 21218c2ecf20Sopenharmony_ci * @ln: lnode 21228c2ecf20Sopenharmony_ci * 21238c2ecf20Sopenharmony_ci */ 21248c2ecf20Sopenharmony_civoid 21258c2ecf20Sopenharmony_cicsio_lnode_exit(struct csio_lnode *ln) 21268c2ecf20Sopenharmony_ci{ 21278c2ecf20Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci csio_ln_exit(ln); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci /* Remove this lnode from hw->sln_head */ 21328c2ecf20Sopenharmony_ci spin_lock_irq(&hw->lock); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci list_del_init(&ln->sm.sm_list); 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci /* If it is children lnode, decrement the 21378c2ecf20Sopenharmony_ci * counter in its parent lnode 21388c2ecf20Sopenharmony_ci */ 21398c2ecf20Sopenharmony_ci if (ln->pln) 21408c2ecf20Sopenharmony_ci ln->pln->num_vports--; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci /* Update root lnode pointer */ 21438c2ecf20Sopenharmony_ci if (list_empty(&hw->sln_head)) 21448c2ecf20Sopenharmony_ci hw->rln = NULL; 21458c2ecf20Sopenharmony_ci else 21468c2ecf20Sopenharmony_ci hw->rln = (struct csio_lnode *)csio_list_next(&hw->sln_head); 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci spin_unlock_irq(&hw->lock); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci csio_lnode_to_hw(ln) = NULL; 21518c2ecf20Sopenharmony_ci hw->num_lns--; 21528c2ecf20Sopenharmony_ci} 2153