162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is part of the Chelsio FCoE driver for Linux. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/kernel.h> 3662306a36Sopenharmony_ci#include <linux/string.h> 3762306a36Sopenharmony_ci#include <linux/delay.h> 3862306a36Sopenharmony_ci#include <linux/module.h> 3962306a36Sopenharmony_ci#include <linux/init.h> 4062306a36Sopenharmony_ci#include <linux/pci.h> 4162306a36Sopenharmony_ci#include <linux/mm.h> 4262306a36Sopenharmony_ci#include <linux/jiffies.h> 4362306a36Sopenharmony_ci#include <scsi/fc/fc_fs.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "csio_init.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic void 4862306a36Sopenharmony_cicsio_vport_set_state(struct csio_lnode *ln); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * csio_reg_rnode - Register a remote port with FC transport. 5262306a36Sopenharmony_ci * @rn: Rnode representing remote port. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * Call fc_remote_port_add() to register this remote port with FC transport. 5562306a36Sopenharmony_ci * If remote port is Initiator OR Target OR both, change the role appropriately. 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_civoid 5962306a36Sopenharmony_cicsio_reg_rnode(struct csio_rnode *rn) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 6262306a36Sopenharmony_ci struct Scsi_Host *shost = csio_ln_to_shost(ln); 6362306a36Sopenharmony_ci struct fc_rport_identifiers ids; 6462306a36Sopenharmony_ci struct fc_rport *rport; 6562306a36Sopenharmony_ci struct csio_service_parms *sp; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ids.node_name = wwn_to_u64(csio_rn_wwnn(rn)); 6862306a36Sopenharmony_ci ids.port_name = wwn_to_u64(csio_rn_wwpn(rn)); 6962306a36Sopenharmony_ci ids.port_id = rn->nport_id; 7062306a36Sopenharmony_ci ids.roles = FC_RPORT_ROLE_UNKNOWN; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (rn->role & CSIO_RNFR_INITIATOR || rn->role & CSIO_RNFR_TARGET) { 7362306a36Sopenharmony_ci rport = rn->rport; 7462306a36Sopenharmony_ci CSIO_ASSERT(rport != NULL); 7562306a36Sopenharmony_ci goto update_role; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci rn->rport = fc_remote_port_add(shost, 0, &ids); 7962306a36Sopenharmony_ci if (!rn->rport) { 8062306a36Sopenharmony_ci csio_ln_err(ln, "Failed to register rport = 0x%x.\n", 8162306a36Sopenharmony_ci rn->nport_id); 8262306a36Sopenharmony_ci return; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci ln->num_reg_rnodes++; 8662306a36Sopenharmony_ci rport = rn->rport; 8762306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 8862306a36Sopenharmony_ci *((struct csio_rnode **)rport->dd_data) = rn; 8962306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci sp = &rn->rn_sparm; 9262306a36Sopenharmony_ci rport->maxframe_size = ntohs(sp->csp.sp_bb_data); 9362306a36Sopenharmony_ci if (ntohs(sp->clsp[2].cp_class) & FC_CPC_VALID) 9462306a36Sopenharmony_ci rport->supported_classes = FC_COS_CLASS3; 9562306a36Sopenharmony_ci else 9662306a36Sopenharmony_ci rport->supported_classes = FC_COS_UNSPECIFIED; 9762306a36Sopenharmony_ciupdate_role: 9862306a36Sopenharmony_ci if (rn->role & CSIO_RNFR_INITIATOR) 9962306a36Sopenharmony_ci ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; 10062306a36Sopenharmony_ci if (rn->role & CSIO_RNFR_TARGET) 10162306a36Sopenharmony_ci ids.roles |= FC_RPORT_ROLE_FCP_TARGET; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (ids.roles != FC_RPORT_ROLE_UNKNOWN) 10462306a36Sopenharmony_ci fc_remote_port_rolechg(rport, ids.roles); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci rn->scsi_id = rport->scsi_target_id; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci csio_ln_dbg(ln, "Remote port x%x role 0x%x registered\n", 10962306a36Sopenharmony_ci rn->nport_id, ids.roles); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* 11362306a36Sopenharmony_ci * csio_unreg_rnode - Unregister a remote port with FC transport. 11462306a36Sopenharmony_ci * @rn: Rnode representing remote port. 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * Call fc_remote_port_delete() to unregister this remote port with FC 11762306a36Sopenharmony_ci * transport. 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_civoid 12162306a36Sopenharmony_cicsio_unreg_rnode(struct csio_rnode *rn) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct csio_lnode *ln = csio_rnode_to_lnode(rn); 12462306a36Sopenharmony_ci struct fc_rport *rport = rn->rport; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci rn->role &= ~(CSIO_RNFR_INITIATOR | CSIO_RNFR_TARGET); 12762306a36Sopenharmony_ci fc_remote_port_delete(rport); 12862306a36Sopenharmony_ci ln->num_reg_rnodes--; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci csio_ln_dbg(ln, "Remote port x%x un-registered\n", rn->nport_id); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * csio_lnode_async_event - Async events from local port. 13562306a36Sopenharmony_ci * @ln: lnode representing local port. 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * Async events from local node that FC transport/SCSI ML 13862306a36Sopenharmony_ci * should be made aware of (Eg: RSCN). 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_civoid 14162306a36Sopenharmony_cicsio_lnode_async_event(struct csio_lnode *ln, enum csio_ln_fc_evt fc_evt) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci switch (fc_evt) { 14462306a36Sopenharmony_ci case CSIO_LN_FC_RSCN: 14562306a36Sopenharmony_ci /* Get payload of rscn from ln */ 14662306a36Sopenharmony_ci /* For each RSCN entry */ 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * fc_host_post_event(shost, 14962306a36Sopenharmony_ci * fc_get_event_number(), 15062306a36Sopenharmony_ci * FCH_EVT_RSCN, 15162306a36Sopenharmony_ci * rscn_entry); 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci case CSIO_LN_FC_LINKUP: 15562306a36Sopenharmony_ci /* send fc_host_post_event */ 15662306a36Sopenharmony_ci /* set vport state */ 15762306a36Sopenharmony_ci if (csio_is_npiv_ln(ln)) 15862306a36Sopenharmony_ci csio_vport_set_state(ln); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci case CSIO_LN_FC_LINKDOWN: 16262306a36Sopenharmony_ci /* send fc_host_post_event */ 16362306a36Sopenharmony_ci /* set vport state */ 16462306a36Sopenharmony_ci if (csio_is_npiv_ln(ln)) 16562306a36Sopenharmony_ci csio_vport_set_state(ln); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci case CSIO_LN_FC_ATTRIB_UPDATE: 16962306a36Sopenharmony_ci csio_fchost_attr_init(ln); 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci default: 17262306a36Sopenharmony_ci break; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* 17762306a36Sopenharmony_ci * csio_fchost_attr_init - Initialize FC transport attributes 17862306a36Sopenharmony_ci * @ln: Lnode. 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_civoid 18262306a36Sopenharmony_cicsio_fchost_attr_init(struct csio_lnode *ln) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct Scsi_Host *shost = csio_ln_to_shost(ln); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci fc_host_node_name(shost) = wwn_to_u64(csio_ln_wwnn(ln)); 18762306a36Sopenharmony_ci fc_host_port_name(shost) = wwn_to_u64(csio_ln_wwpn(ln)); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci fc_host_supported_classes(shost) = FC_COS_CLASS3; 19062306a36Sopenharmony_ci fc_host_max_npiv_vports(shost) = 19162306a36Sopenharmony_ci (csio_lnode_to_hw(ln))->fres_info.max_vnps; 19262306a36Sopenharmony_ci fc_host_supported_speeds(shost) = FC_PORTSPEED_10GBIT | 19362306a36Sopenharmony_ci FC_PORTSPEED_1GBIT; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci fc_host_maxframe_size(shost) = ntohs(ln->ln_sparm.csp.sp_bb_data); 19662306a36Sopenharmony_ci memset(fc_host_supported_fc4s(shost), 0, 19762306a36Sopenharmony_ci sizeof(fc_host_supported_fc4s(shost))); 19862306a36Sopenharmony_ci fc_host_supported_fc4s(shost)[7] = 1; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci memset(fc_host_active_fc4s(shost), 0, 20162306a36Sopenharmony_ci sizeof(fc_host_active_fc4s(shost))); 20262306a36Sopenharmony_ci fc_host_active_fc4s(shost)[7] = 1; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* 20662306a36Sopenharmony_ci * csio_get_host_port_id - sysfs entries for nport_id is 20762306a36Sopenharmony_ci * populated/cached from this function 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistatic void 21062306a36Sopenharmony_cicsio_get_host_port_id(struct Scsi_Host *shost) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct csio_lnode *ln = shost_priv(shost); 21362306a36Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 21662306a36Sopenharmony_ci fc_host_port_id(shost) = ln->nport_id; 21762306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* 22162306a36Sopenharmony_ci * csio_get_port_type - Return FC local port type. 22262306a36Sopenharmony_ci * @shost: scsi host. 22362306a36Sopenharmony_ci * 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_cistatic void 22662306a36Sopenharmony_cicsio_get_host_port_type(struct Scsi_Host *shost) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct csio_lnode *ln = shost_priv(shost); 22962306a36Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 23262306a36Sopenharmony_ci if (csio_is_npiv_ln(ln)) 23362306a36Sopenharmony_ci fc_host_port_type(shost) = FC_PORTTYPE_NPIV; 23462306a36Sopenharmony_ci else 23562306a36Sopenharmony_ci fc_host_port_type(shost) = FC_PORTTYPE_NPORT; 23662306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* 24062306a36Sopenharmony_ci * csio_get_port_state - Return FC local port state. 24162306a36Sopenharmony_ci * @shost: scsi host. 24262306a36Sopenharmony_ci * 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_cistatic void 24562306a36Sopenharmony_cicsio_get_host_port_state(struct Scsi_Host *shost) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct csio_lnode *ln = shost_priv(shost); 24862306a36Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 24962306a36Sopenharmony_ci char state[16]; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci csio_lnode_state_to_str(ln, state); 25462306a36Sopenharmony_ci if (!strcmp(state, "READY")) 25562306a36Sopenharmony_ci fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; 25662306a36Sopenharmony_ci else if (!strcmp(state, "OFFLINE")) 25762306a36Sopenharmony_ci fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* 26562306a36Sopenharmony_ci * csio_get_host_speed - Return link speed to FC transport. 26662306a36Sopenharmony_ci * @shost: scsi host. 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_cistatic void 27062306a36Sopenharmony_cicsio_get_host_speed(struct Scsi_Host *shost) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct csio_lnode *ln = shost_priv(shost); 27362306a36Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 27662306a36Sopenharmony_ci switch (hw->pport[ln->portid].link_speed) { 27762306a36Sopenharmony_ci case FW_PORT_CAP32_SPEED_1G: 27862306a36Sopenharmony_ci fc_host_speed(shost) = FC_PORTSPEED_1GBIT; 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci case FW_PORT_CAP32_SPEED_10G: 28162306a36Sopenharmony_ci fc_host_speed(shost) = FC_PORTSPEED_10GBIT; 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci case FW_PORT_CAP32_SPEED_25G: 28462306a36Sopenharmony_ci fc_host_speed(shost) = FC_PORTSPEED_25GBIT; 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci case FW_PORT_CAP32_SPEED_40G: 28762306a36Sopenharmony_ci fc_host_speed(shost) = FC_PORTSPEED_40GBIT; 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci case FW_PORT_CAP32_SPEED_50G: 29062306a36Sopenharmony_ci fc_host_speed(shost) = FC_PORTSPEED_50GBIT; 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci case FW_PORT_CAP32_SPEED_100G: 29362306a36Sopenharmony_ci fc_host_speed(shost) = FC_PORTSPEED_100GBIT; 29462306a36Sopenharmony_ci break; 29562306a36Sopenharmony_ci default: 29662306a36Sopenharmony_ci fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* 30362306a36Sopenharmony_ci * csio_get_host_fabric_name - Return fabric name 30462306a36Sopenharmony_ci * @shost: scsi host. 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_cistatic void 30862306a36Sopenharmony_cicsio_get_host_fabric_name(struct Scsi_Host *shost) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct csio_lnode *ln = shost_priv(shost); 31162306a36Sopenharmony_ci struct csio_rnode *rn = NULL; 31262306a36Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 31562306a36Sopenharmony_ci rn = csio_rnode_lookup_portid(ln, FC_FID_FLOGI); 31662306a36Sopenharmony_ci if (rn) 31762306a36Sopenharmony_ci fc_host_fabric_name(shost) = wwn_to_u64(csio_rn_wwnn(rn)); 31862306a36Sopenharmony_ci else 31962306a36Sopenharmony_ci fc_host_fabric_name(shost) = 0; 32062306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/* 32462306a36Sopenharmony_ci * csio_get_host_speed - Return FC transport statistics. 32562306a36Sopenharmony_ci * @ln: Lnode. 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_cistatic struct fc_host_statistics * 32962306a36Sopenharmony_cicsio_get_stats(struct Scsi_Host *shost) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct csio_lnode *ln = shost_priv(shost); 33262306a36Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 33362306a36Sopenharmony_ci struct fc_host_statistics *fhs = &ln->fch_stats; 33462306a36Sopenharmony_ci struct fw_fcoe_port_stats fcoe_port_stats; 33562306a36Sopenharmony_ci uint64_t seconds; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci memset(&fcoe_port_stats, 0, sizeof(struct fw_fcoe_port_stats)); 33862306a36Sopenharmony_ci csio_get_phy_port_stats(hw, ln->portid, &fcoe_port_stats); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci fhs->tx_frames += (be64_to_cpu(fcoe_port_stats.tx_bcast_frames) + 34162306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.tx_mcast_frames) + 34262306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.tx_ucast_frames) + 34362306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.tx_offload_frames)); 34462306a36Sopenharmony_ci fhs->tx_words += (be64_to_cpu(fcoe_port_stats.tx_bcast_bytes) + 34562306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.tx_mcast_bytes) + 34662306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.tx_ucast_bytes) + 34762306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.tx_offload_bytes)) / 34862306a36Sopenharmony_ci CSIO_WORD_TO_BYTE; 34962306a36Sopenharmony_ci fhs->rx_frames += (be64_to_cpu(fcoe_port_stats.rx_bcast_frames) + 35062306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.rx_mcast_frames) + 35162306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.rx_ucast_frames)); 35262306a36Sopenharmony_ci fhs->rx_words += (be64_to_cpu(fcoe_port_stats.rx_bcast_bytes) + 35362306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.rx_mcast_bytes) + 35462306a36Sopenharmony_ci be64_to_cpu(fcoe_port_stats.rx_ucast_bytes)) / 35562306a36Sopenharmony_ci CSIO_WORD_TO_BYTE; 35662306a36Sopenharmony_ci fhs->error_frames += be64_to_cpu(fcoe_port_stats.rx_err_frames); 35762306a36Sopenharmony_ci fhs->fcp_input_requests += ln->stats.n_input_requests; 35862306a36Sopenharmony_ci fhs->fcp_output_requests += ln->stats.n_output_requests; 35962306a36Sopenharmony_ci fhs->fcp_control_requests += ln->stats.n_control_requests; 36062306a36Sopenharmony_ci fhs->fcp_input_megabytes += ln->stats.n_input_bytes >> 20; 36162306a36Sopenharmony_ci fhs->fcp_output_megabytes += ln->stats.n_output_bytes >> 20; 36262306a36Sopenharmony_ci fhs->link_failure_count = ln->stats.n_link_down; 36362306a36Sopenharmony_ci /* Reset stats for the device */ 36462306a36Sopenharmony_ci seconds = jiffies_to_msecs(jiffies) - hw->stats.n_reset_start; 36562306a36Sopenharmony_ci do_div(seconds, 1000); 36662306a36Sopenharmony_ci fhs->seconds_since_last_reset = seconds; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return fhs; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/* 37262306a36Sopenharmony_ci * csio_set_rport_loss_tmo - Set the rport dev loss timeout 37362306a36Sopenharmony_ci * @rport: fc rport. 37462306a36Sopenharmony_ci * @timeout: new value for dev loss tmo. 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * If timeout is non zero set the dev_loss_tmo to timeout, else set 37762306a36Sopenharmony_ci * dev_loss_tmo to one. 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_cistatic void 38062306a36Sopenharmony_cicsio_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci if (timeout) 38362306a36Sopenharmony_ci rport->dev_loss_tmo = timeout; 38462306a36Sopenharmony_ci else 38562306a36Sopenharmony_ci rport->dev_loss_tmo = 1; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic void 38962306a36Sopenharmony_cicsio_vport_set_state(struct csio_lnode *ln) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct fc_vport *fc_vport = ln->fc_vport; 39262306a36Sopenharmony_ci struct csio_lnode *pln = ln->pln; 39362306a36Sopenharmony_ci char state[16]; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* Set fc vport state based on phyiscal lnode */ 39662306a36Sopenharmony_ci csio_lnode_state_to_str(pln, state); 39762306a36Sopenharmony_ci if (strcmp(state, "READY")) { 39862306a36Sopenharmony_ci fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN); 39962306a36Sopenharmony_ci return; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (!(pln->flags & CSIO_LNF_NPIVSUPP)) { 40362306a36Sopenharmony_ci fc_vport_set_state(fc_vport, FC_VPORT_NO_FABRIC_SUPP); 40462306a36Sopenharmony_ci return; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Set fc vport state based on virtual lnode */ 40862306a36Sopenharmony_ci csio_lnode_state_to_str(ln, state); 40962306a36Sopenharmony_ci if (strcmp(state, "READY")) { 41062306a36Sopenharmony_ci fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN); 41162306a36Sopenharmony_ci return; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int 41762306a36Sopenharmony_cicsio_fcoe_alloc_vnp(struct csio_hw *hw, struct csio_lnode *ln) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct csio_lnode *pln; 42062306a36Sopenharmony_ci struct csio_mb *mbp; 42162306a36Sopenharmony_ci struct fw_fcoe_vnp_cmd *rsp; 42262306a36Sopenharmony_ci int ret = 0; 42362306a36Sopenharmony_ci int retry = 0; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Issue VNP cmd to alloc vport */ 42662306a36Sopenharmony_ci /* Allocate Mbox request */ 42762306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 42862306a36Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 42962306a36Sopenharmony_ci if (!mbp) { 43062306a36Sopenharmony_ci CSIO_INC_STATS(hw, n_err_nomem); 43162306a36Sopenharmony_ci ret = -ENOMEM; 43262306a36Sopenharmony_ci goto out; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci pln = ln->pln; 43662306a36Sopenharmony_ci ln->fcf_flowid = pln->fcf_flowid; 43762306a36Sopenharmony_ci ln->portid = pln->portid; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci csio_fcoe_vnp_alloc_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO, 44062306a36Sopenharmony_ci pln->fcf_flowid, pln->vnp_flowid, 0, 44162306a36Sopenharmony_ci csio_ln_wwnn(ln), csio_ln_wwpn(ln), NULL); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci for (retry = 0; retry < 3; retry++) { 44462306a36Sopenharmony_ci /* FW is expected to complete vnp cmd in immediate mode 44562306a36Sopenharmony_ci * without much delay. 44662306a36Sopenharmony_ci * Otherwise, there will be increase in IO latency since HW 44762306a36Sopenharmony_ci * lock is held till completion of vnp mbox cmd. 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci ret = csio_mb_issue(hw, mbp); 45062306a36Sopenharmony_ci if (ret != -EBUSY) 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Retry if mbox returns busy */ 45462306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 45562306a36Sopenharmony_ci msleep(2000); 45662306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (ret) { 46062306a36Sopenharmony_ci csio_ln_err(ln, "Failed to issue mbox FCoE VNP command\n"); 46162306a36Sopenharmony_ci goto out_free; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* Process Mbox response of VNP command */ 46562306a36Sopenharmony_ci rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb); 46662306a36Sopenharmony_ci if (FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) { 46762306a36Sopenharmony_ci csio_ln_err(ln, "FCOE VNP ALLOC cmd returned 0x%x!\n", 46862306a36Sopenharmony_ci FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16))); 46962306a36Sopenharmony_ci ret = -EINVAL; 47062306a36Sopenharmony_ci goto out_free; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci ln->vnp_flowid = FW_FCOE_VNP_CMD_VNPI_GET( 47462306a36Sopenharmony_ci ntohl(rsp->gen_wwn_to_vnpi)); 47562306a36Sopenharmony_ci memcpy(csio_ln_wwnn(ln), rsp->vnport_wwnn, 8); 47662306a36Sopenharmony_ci memcpy(csio_ln_wwpn(ln), rsp->vnport_wwpn, 8); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci csio_ln_dbg(ln, "FCOE VNPI: 0x%x\n", ln->vnp_flowid); 47962306a36Sopenharmony_ci csio_ln_dbg(ln, "\tWWNN: %x%x%x%x%x%x%x%x\n", 48062306a36Sopenharmony_ci ln->ln_sparm.wwnn[0], ln->ln_sparm.wwnn[1], 48162306a36Sopenharmony_ci ln->ln_sparm.wwnn[2], ln->ln_sparm.wwnn[3], 48262306a36Sopenharmony_ci ln->ln_sparm.wwnn[4], ln->ln_sparm.wwnn[5], 48362306a36Sopenharmony_ci ln->ln_sparm.wwnn[6], ln->ln_sparm.wwnn[7]); 48462306a36Sopenharmony_ci csio_ln_dbg(ln, "\tWWPN: %x%x%x%x%x%x%x%x\n", 48562306a36Sopenharmony_ci ln->ln_sparm.wwpn[0], ln->ln_sparm.wwpn[1], 48662306a36Sopenharmony_ci ln->ln_sparm.wwpn[2], ln->ln_sparm.wwpn[3], 48762306a36Sopenharmony_ci ln->ln_sparm.wwpn[4], ln->ln_sparm.wwpn[5], 48862306a36Sopenharmony_ci ln->ln_sparm.wwpn[6], ln->ln_sparm.wwpn[7]); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ciout_free: 49162306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 49262306a36Sopenharmony_ciout: 49362306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 49462306a36Sopenharmony_ci return ret; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int 49862306a36Sopenharmony_cicsio_fcoe_free_vnp(struct csio_hw *hw, struct csio_lnode *ln) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct csio_mb *mbp; 50162306a36Sopenharmony_ci struct fw_fcoe_vnp_cmd *rsp; 50262306a36Sopenharmony_ci int ret = 0; 50362306a36Sopenharmony_ci int retry = 0; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* Issue VNP cmd to free vport */ 50662306a36Sopenharmony_ci /* Allocate Mbox request */ 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 50962306a36Sopenharmony_ci mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 51062306a36Sopenharmony_ci if (!mbp) { 51162306a36Sopenharmony_ci CSIO_INC_STATS(hw, n_err_nomem); 51262306a36Sopenharmony_ci ret = -ENOMEM; 51362306a36Sopenharmony_ci goto out; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci csio_fcoe_vnp_free_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO, 51762306a36Sopenharmony_ci ln->fcf_flowid, ln->vnp_flowid, 51862306a36Sopenharmony_ci NULL); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci for (retry = 0; retry < 3; retry++) { 52162306a36Sopenharmony_ci ret = csio_mb_issue(hw, mbp); 52262306a36Sopenharmony_ci if (ret != -EBUSY) 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* Retry if mbox returns busy */ 52662306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 52762306a36Sopenharmony_ci msleep(2000); 52862306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (ret) { 53262306a36Sopenharmony_ci csio_ln_err(ln, "Failed to issue mbox FCoE VNP command\n"); 53362306a36Sopenharmony_ci goto out_free; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Process Mbox response of VNP command */ 53762306a36Sopenharmony_ci rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb); 53862306a36Sopenharmony_ci if (FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) { 53962306a36Sopenharmony_ci csio_ln_err(ln, "FCOE VNP FREE cmd returned 0x%x!\n", 54062306a36Sopenharmony_ci FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16))); 54162306a36Sopenharmony_ci ret = -EINVAL; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ciout_free: 54562306a36Sopenharmony_ci mempool_free(mbp, hw->mb_mempool); 54662306a36Sopenharmony_ciout: 54762306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 54862306a36Sopenharmony_ci return ret; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic int 55262306a36Sopenharmony_cicsio_vport_create(struct fc_vport *fc_vport, bool disable) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct Scsi_Host *shost = fc_vport->shost; 55562306a36Sopenharmony_ci struct csio_lnode *pln = shost_priv(shost); 55662306a36Sopenharmony_ci struct csio_lnode *ln = NULL; 55762306a36Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(pln); 55862306a36Sopenharmony_ci uint8_t wwn[8]; 55962306a36Sopenharmony_ci int ret = -1; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci ln = csio_shost_init(hw, &fc_vport->dev, false, pln); 56262306a36Sopenharmony_ci if (!ln) 56362306a36Sopenharmony_ci goto error; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (fc_vport->node_name != 0) { 56662306a36Sopenharmony_ci u64_to_wwn(fc_vport->node_name, wwn); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (!CSIO_VALID_WWN(wwn)) { 56962306a36Sopenharmony_ci csio_ln_err(ln, 57062306a36Sopenharmony_ci "vport create failed. Invalid wwnn\n"); 57162306a36Sopenharmony_ci goto error; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci memcpy(csio_ln_wwnn(ln), wwn, 8); 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (fc_vport->port_name != 0) { 57762306a36Sopenharmony_ci u64_to_wwn(fc_vport->port_name, wwn); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (!CSIO_VALID_WWN(wwn)) { 58062306a36Sopenharmony_ci csio_ln_err(ln, 58162306a36Sopenharmony_ci "vport create failed. Invalid wwpn\n"); 58262306a36Sopenharmony_ci goto error; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (csio_lnode_lookup_by_wwpn(hw, wwn)) { 58662306a36Sopenharmony_ci csio_ln_err(ln, 58762306a36Sopenharmony_ci "vport create failed. wwpn already exists\n"); 58862306a36Sopenharmony_ci goto error; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci memcpy(csio_ln_wwpn(ln), wwn, 8); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING); 59462306a36Sopenharmony_ci ln->fc_vport = fc_vport; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (csio_fcoe_alloc_vnp(hw, ln)) 59762306a36Sopenharmony_ci goto error; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci *(struct csio_lnode **)fc_vport->dd_data = ln; 60062306a36Sopenharmony_ci if (!fc_vport->node_name) 60162306a36Sopenharmony_ci fc_vport->node_name = wwn_to_u64(csio_ln_wwnn(ln)); 60262306a36Sopenharmony_ci if (!fc_vport->port_name) 60362306a36Sopenharmony_ci fc_vport->port_name = wwn_to_u64(csio_ln_wwpn(ln)); 60462306a36Sopenharmony_ci csio_fchost_attr_init(ln); 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_cierror: 60762306a36Sopenharmony_ci if (ln) 60862306a36Sopenharmony_ci csio_shost_exit(ln); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return ret; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic int 61462306a36Sopenharmony_cicsio_vport_delete(struct fc_vport *fc_vport) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci struct csio_lnode *ln = *(struct csio_lnode **)fc_vport->dd_data; 61762306a36Sopenharmony_ci struct Scsi_Host *shost = csio_ln_to_shost(ln); 61862306a36Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 61962306a36Sopenharmony_ci int rmv; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 62262306a36Sopenharmony_ci rmv = csio_is_hw_removing(hw); 62362306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (rmv) { 62662306a36Sopenharmony_ci csio_shost_exit(ln); 62762306a36Sopenharmony_ci return 0; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* Quiesce ios and send remove event to lnode */ 63162306a36Sopenharmony_ci scsi_block_requests(shost); 63262306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 63362306a36Sopenharmony_ci csio_scsim_cleanup_io_lnode(csio_hw_to_scsim(hw), ln); 63462306a36Sopenharmony_ci csio_lnode_close(ln); 63562306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 63662306a36Sopenharmony_ci scsi_unblock_requests(shost); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Free vnp */ 63962306a36Sopenharmony_ci if (fc_vport->vport_state != FC_VPORT_DISABLED) 64062306a36Sopenharmony_ci csio_fcoe_free_vnp(hw, ln); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci csio_shost_exit(ln); 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int 64762306a36Sopenharmony_cicsio_vport_disable(struct fc_vport *fc_vport, bool disable) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct csio_lnode *ln = *(struct csio_lnode **)fc_vport->dd_data; 65062306a36Sopenharmony_ci struct Scsi_Host *shost = csio_ln_to_shost(ln); 65162306a36Sopenharmony_ci struct csio_hw *hw = csio_lnode_to_hw(ln); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* disable vport */ 65462306a36Sopenharmony_ci if (disable) { 65562306a36Sopenharmony_ci /* Quiesce ios and send stop event to lnode */ 65662306a36Sopenharmony_ci scsi_block_requests(shost); 65762306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 65862306a36Sopenharmony_ci csio_scsim_cleanup_io_lnode(csio_hw_to_scsim(hw), ln); 65962306a36Sopenharmony_ci csio_lnode_stop(ln); 66062306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 66162306a36Sopenharmony_ci scsi_unblock_requests(shost); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* Free vnp */ 66462306a36Sopenharmony_ci csio_fcoe_free_vnp(hw, ln); 66562306a36Sopenharmony_ci fc_vport_set_state(fc_vport, FC_VPORT_DISABLED); 66662306a36Sopenharmony_ci csio_ln_err(ln, "vport disabled\n"); 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci } else { 66962306a36Sopenharmony_ci /* enable vport */ 67062306a36Sopenharmony_ci fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING); 67162306a36Sopenharmony_ci if (csio_fcoe_alloc_vnp(hw, ln)) { 67262306a36Sopenharmony_ci csio_ln_err(ln, "vport enabled failed.\n"); 67362306a36Sopenharmony_ci return -1; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci csio_ln_err(ln, "vport enabled\n"); 67662306a36Sopenharmony_ci return 0; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic void 68162306a36Sopenharmony_cicsio_dev_loss_tmo_callbk(struct fc_rport *rport) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci struct csio_rnode *rn; 68462306a36Sopenharmony_ci struct csio_hw *hw; 68562306a36Sopenharmony_ci struct csio_lnode *ln; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci rn = *((struct csio_rnode **)rport->dd_data); 68862306a36Sopenharmony_ci ln = csio_rnode_to_lnode(rn); 68962306a36Sopenharmony_ci hw = csio_lnode_to_hw(ln); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci spin_lock_irq(&hw->lock); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* return if driver is being removed or same rnode comes back online */ 69462306a36Sopenharmony_ci if (csio_is_hw_removing(hw) || csio_is_rnode_ready(rn)) 69562306a36Sopenharmony_ci goto out; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci csio_ln_dbg(ln, "devloss timeout on rnode:%p portid:x%x flowid:x%x\n", 69862306a36Sopenharmony_ci rn, rn->nport_id, csio_rn_flowid(rn)); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci CSIO_INC_STATS(ln, n_dev_loss_tmo); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* 70362306a36Sopenharmony_ci * enqueue devloss event to event worker thread to serialize all 70462306a36Sopenharmony_ci * rnode events. 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ci if (csio_enqueue_evt(hw, CSIO_EVT_DEV_LOSS, &rn, sizeof(rn))) { 70762306a36Sopenharmony_ci CSIO_INC_STATS(hw, n_evt_drop); 70862306a36Sopenharmony_ci goto out; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (!(hw->flags & CSIO_HWF_FWEVT_PENDING)) { 71262306a36Sopenharmony_ci hw->flags |= CSIO_HWF_FWEVT_PENDING; 71362306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 71462306a36Sopenharmony_ci schedule_work(&hw->evtq_work); 71562306a36Sopenharmony_ci return; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ciout: 71962306a36Sopenharmony_ci spin_unlock_irq(&hw->lock); 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci/* FC transport functions template - Physical port */ 72362306a36Sopenharmony_cistruct fc_function_template csio_fc_transport_funcs = { 72462306a36Sopenharmony_ci .show_host_node_name = 1, 72562306a36Sopenharmony_ci .show_host_port_name = 1, 72662306a36Sopenharmony_ci .show_host_supported_classes = 1, 72762306a36Sopenharmony_ci .show_host_supported_fc4s = 1, 72862306a36Sopenharmony_ci .show_host_maxframe_size = 1, 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci .get_host_port_id = csio_get_host_port_id, 73162306a36Sopenharmony_ci .show_host_port_id = 1, 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci .get_host_port_type = csio_get_host_port_type, 73462306a36Sopenharmony_ci .show_host_port_type = 1, 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci .get_host_port_state = csio_get_host_port_state, 73762306a36Sopenharmony_ci .show_host_port_state = 1, 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci .show_host_active_fc4s = 1, 74062306a36Sopenharmony_ci .get_host_speed = csio_get_host_speed, 74162306a36Sopenharmony_ci .show_host_speed = 1, 74262306a36Sopenharmony_ci .get_host_fabric_name = csio_get_host_fabric_name, 74362306a36Sopenharmony_ci .show_host_fabric_name = 1, 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci .get_fc_host_stats = csio_get_stats, 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci .dd_fcrport_size = sizeof(struct csio_rnode *), 74862306a36Sopenharmony_ci .show_rport_maxframe_size = 1, 74962306a36Sopenharmony_ci .show_rport_supported_classes = 1, 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci .set_rport_dev_loss_tmo = csio_set_rport_loss_tmo, 75262306a36Sopenharmony_ci .show_rport_dev_loss_tmo = 1, 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci .show_starget_port_id = 1, 75562306a36Sopenharmony_ci .show_starget_node_name = 1, 75662306a36Sopenharmony_ci .show_starget_port_name = 1, 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci .dev_loss_tmo_callbk = csio_dev_loss_tmo_callbk, 75962306a36Sopenharmony_ci .dd_fcvport_size = sizeof(struct csio_lnode *), 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci .vport_create = csio_vport_create, 76262306a36Sopenharmony_ci .vport_disable = csio_vport_disable, 76362306a36Sopenharmony_ci .vport_delete = csio_vport_delete, 76462306a36Sopenharmony_ci}; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci/* FC transport functions template - Virtual port */ 76762306a36Sopenharmony_cistruct fc_function_template csio_fc_transport_vport_funcs = { 76862306a36Sopenharmony_ci .show_host_node_name = 1, 76962306a36Sopenharmony_ci .show_host_port_name = 1, 77062306a36Sopenharmony_ci .show_host_supported_classes = 1, 77162306a36Sopenharmony_ci .show_host_supported_fc4s = 1, 77262306a36Sopenharmony_ci .show_host_maxframe_size = 1, 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci .get_host_port_id = csio_get_host_port_id, 77562306a36Sopenharmony_ci .show_host_port_id = 1, 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci .get_host_port_type = csio_get_host_port_type, 77862306a36Sopenharmony_ci .show_host_port_type = 1, 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci .get_host_port_state = csio_get_host_port_state, 78162306a36Sopenharmony_ci .show_host_port_state = 1, 78262306a36Sopenharmony_ci .show_host_active_fc4s = 1, 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci .get_host_speed = csio_get_host_speed, 78562306a36Sopenharmony_ci .show_host_speed = 1, 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci .get_host_fabric_name = csio_get_host_fabric_name, 78862306a36Sopenharmony_ci .show_host_fabric_name = 1, 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci .get_fc_host_stats = csio_get_stats, 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci .dd_fcrport_size = sizeof(struct csio_rnode *), 79362306a36Sopenharmony_ci .show_rport_maxframe_size = 1, 79462306a36Sopenharmony_ci .show_rport_supported_classes = 1, 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci .set_rport_dev_loss_tmo = csio_set_rport_loss_tmo, 79762306a36Sopenharmony_ci .show_rport_dev_loss_tmo = 1, 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci .show_starget_port_id = 1, 80062306a36Sopenharmony_ci .show_starget_node_name = 1, 80162306a36Sopenharmony_ci .show_starget_port_name = 1, 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci .dev_loss_tmo_callbk = csio_dev_loss_tmo_callbk, 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci}; 806