Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is part of the Chelsio FCoE driver for Linux.
0003  *
0004  * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
0005  *
0006  * This software is available to you under a choice of one of two
0007  * licenses.  You may choose to be licensed under the terms of the GNU
0008  * General Public License (GPL) Version 2, available from the file
0009  * COPYING in the main directory of this source tree, or the
0010  * OpenIB.org BSD license below:
0011  *
0012  *     Redistribution and use in source and binary forms, with or
0013  *     without modification, are permitted provided that the following
0014  *     conditions are met:
0015  *
0016  *      - Redistributions of source code must retain the above
0017  *        copyright notice, this list of conditions and the following
0018  *        disclaimer.
0019  *
0020  *      - Redistributions in binary form must reproduce the above
0021  *        copyright notice, this list of conditions and the following
0022  *        disclaimer in the documentation and/or other materials
0023  *        provided with the distribution.
0024  *
0025  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0026  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0027  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0028  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0029  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0030  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0031  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0032  * SOFTWARE.
0033  */
0034 
0035 #include <linux/kernel.h>
0036 #include <linux/string.h>
0037 #include <linux/delay.h>
0038 #include <linux/module.h>
0039 #include <linux/init.h>
0040 #include <linux/pci.h>
0041 #include <linux/mm.h>
0042 #include <linux/jiffies.h>
0043 #include <scsi/fc/fc_fs.h>
0044 
0045 #include "csio_init.h"
0046 
0047 static void
0048 csio_vport_set_state(struct csio_lnode *ln);
0049 
0050 /*
0051  * csio_reg_rnode - Register a remote port with FC transport.
0052  * @rn: Rnode representing remote port.
0053  *
0054  * Call fc_remote_port_add() to register this remote port with FC transport.
0055  * If remote port is Initiator OR Target OR both, change the role appropriately.
0056  *
0057  */
0058 void
0059 csio_reg_rnode(struct csio_rnode *rn)
0060 {
0061     struct csio_lnode *ln       = csio_rnode_to_lnode(rn);
0062     struct Scsi_Host *shost     = csio_ln_to_shost(ln);
0063     struct fc_rport_identifiers ids;
0064     struct fc_rport  *rport;
0065     struct csio_service_parms *sp;
0066 
0067     ids.node_name   = wwn_to_u64(csio_rn_wwnn(rn));
0068     ids.port_name   = wwn_to_u64(csio_rn_wwpn(rn));
0069     ids.port_id = rn->nport_id;
0070     ids.roles   = FC_RPORT_ROLE_UNKNOWN;
0071 
0072     if (rn->role & CSIO_RNFR_INITIATOR || rn->role & CSIO_RNFR_TARGET) {
0073         rport = rn->rport;
0074         CSIO_ASSERT(rport != NULL);
0075         goto update_role;
0076     }
0077 
0078     rn->rport = fc_remote_port_add(shost, 0, &ids);
0079     if (!rn->rport) {
0080         csio_ln_err(ln, "Failed to register rport = 0x%x.\n",
0081                     rn->nport_id);
0082         return;
0083     }
0084 
0085     ln->num_reg_rnodes++;
0086     rport = rn->rport;
0087     spin_lock_irq(shost->host_lock);
0088     *((struct csio_rnode **)rport->dd_data) = rn;
0089     spin_unlock_irq(shost->host_lock);
0090 
0091     sp = &rn->rn_sparm;
0092     rport->maxframe_size = ntohs(sp->csp.sp_bb_data);
0093     if (ntohs(sp->clsp[2].cp_class) & FC_CPC_VALID)
0094         rport->supported_classes = FC_COS_CLASS3;
0095     else
0096         rport->supported_classes = FC_COS_UNSPECIFIED;
0097 update_role:
0098     if (rn->role & CSIO_RNFR_INITIATOR)
0099         ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
0100     if (rn->role & CSIO_RNFR_TARGET)
0101         ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
0102 
0103     if (ids.roles != FC_RPORT_ROLE_UNKNOWN)
0104         fc_remote_port_rolechg(rport, ids.roles);
0105 
0106     rn->scsi_id = rport->scsi_target_id;
0107 
0108     csio_ln_dbg(ln, "Remote port x%x role 0x%x registered\n",
0109         rn->nport_id, ids.roles);
0110 }
0111 
0112 /*
0113  * csio_unreg_rnode - Unregister a remote port with FC transport.
0114  * @rn: Rnode representing remote port.
0115  *
0116  * Call fc_remote_port_delete() to unregister this remote port with FC
0117  * transport.
0118  *
0119  */
0120 void
0121 csio_unreg_rnode(struct csio_rnode *rn)
0122 {
0123     struct csio_lnode *ln = csio_rnode_to_lnode(rn);
0124     struct fc_rport *rport = rn->rport;
0125 
0126     rn->role &= ~(CSIO_RNFR_INITIATOR | CSIO_RNFR_TARGET);
0127     fc_remote_port_delete(rport);
0128     ln->num_reg_rnodes--;
0129 
0130     csio_ln_dbg(ln, "Remote port x%x un-registered\n", rn->nport_id);
0131 }
0132 
0133 /*
0134  * csio_lnode_async_event - Async events from local port.
0135  * @ln: lnode representing local port.
0136  *
0137  * Async events from local node that FC transport/SCSI ML
0138  * should be made aware of (Eg: RSCN).
0139  */
0140 void
0141 csio_lnode_async_event(struct csio_lnode *ln, enum csio_ln_fc_evt fc_evt)
0142 {
0143     switch (fc_evt) {
0144     case CSIO_LN_FC_RSCN:
0145         /* Get payload of rscn from ln */
0146         /* For each RSCN entry */
0147             /*
0148              * fc_host_post_event(shost,
0149              *            fc_get_event_number(),
0150              *            FCH_EVT_RSCN,
0151              *            rscn_entry);
0152              */
0153         break;
0154     case CSIO_LN_FC_LINKUP:
0155         /* send fc_host_post_event */
0156         /* set vport state */
0157         if (csio_is_npiv_ln(ln))
0158             csio_vport_set_state(ln);
0159 
0160         break;
0161     case CSIO_LN_FC_LINKDOWN:
0162         /* send fc_host_post_event */
0163         /* set vport state */
0164         if (csio_is_npiv_ln(ln))
0165             csio_vport_set_state(ln);
0166 
0167         break;
0168     case CSIO_LN_FC_ATTRIB_UPDATE:
0169         csio_fchost_attr_init(ln);
0170         break;
0171     default:
0172         break;
0173     }
0174 }
0175 
0176 /*
0177  * csio_fchost_attr_init - Initialize FC transport attributes
0178  * @ln: Lnode.
0179  *
0180  */
0181 void
0182 csio_fchost_attr_init(struct csio_lnode *ln)
0183 {
0184     struct Scsi_Host  *shost = csio_ln_to_shost(ln);
0185 
0186     fc_host_node_name(shost) = wwn_to_u64(csio_ln_wwnn(ln));
0187     fc_host_port_name(shost) = wwn_to_u64(csio_ln_wwpn(ln));
0188 
0189     fc_host_supported_classes(shost) = FC_COS_CLASS3;
0190     fc_host_max_npiv_vports(shost) =
0191             (csio_lnode_to_hw(ln))->fres_info.max_vnps;
0192     fc_host_supported_speeds(shost) = FC_PORTSPEED_10GBIT |
0193         FC_PORTSPEED_1GBIT;
0194 
0195     fc_host_maxframe_size(shost) = ntohs(ln->ln_sparm.csp.sp_bb_data);
0196     memset(fc_host_supported_fc4s(shost), 0,
0197         sizeof(fc_host_supported_fc4s(shost)));
0198     fc_host_supported_fc4s(shost)[7] = 1;
0199 
0200     memset(fc_host_active_fc4s(shost), 0,
0201         sizeof(fc_host_active_fc4s(shost)));
0202     fc_host_active_fc4s(shost)[7] = 1;
0203 }
0204 
0205 /*
0206  * csio_get_host_port_id - sysfs entries for nport_id is
0207  * populated/cached from this function
0208  */
0209 static void
0210 csio_get_host_port_id(struct Scsi_Host *shost)
0211 {
0212     struct csio_lnode *ln   = shost_priv(shost);
0213     struct csio_hw *hw = csio_lnode_to_hw(ln);
0214 
0215     spin_lock_irq(&hw->lock);
0216     fc_host_port_id(shost) = ln->nport_id;
0217     spin_unlock_irq(&hw->lock);
0218 }
0219 
0220 /*
0221  * csio_get_port_type - Return FC local port type.
0222  * @shost: scsi host.
0223  *
0224  */
0225 static void
0226 csio_get_host_port_type(struct Scsi_Host *shost)
0227 {
0228     struct csio_lnode *ln = shost_priv(shost);
0229     struct csio_hw *hw = csio_lnode_to_hw(ln);
0230 
0231     spin_lock_irq(&hw->lock);
0232     if (csio_is_npiv_ln(ln))
0233         fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
0234     else
0235         fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
0236     spin_unlock_irq(&hw->lock);
0237 }
0238 
0239 /*
0240  * csio_get_port_state - Return FC local port state.
0241  * @shost: scsi host.
0242  *
0243  */
0244 static void
0245 csio_get_host_port_state(struct Scsi_Host *shost)
0246 {
0247     struct csio_lnode *ln = shost_priv(shost);
0248     struct csio_hw *hw = csio_lnode_to_hw(ln);
0249     char state[16];
0250 
0251     spin_lock_irq(&hw->lock);
0252 
0253     csio_lnode_state_to_str(ln, state);
0254     if (!strcmp(state, "READY"))
0255         fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
0256     else if (!strcmp(state, "OFFLINE"))
0257         fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
0258     else
0259         fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
0260 
0261     spin_unlock_irq(&hw->lock);
0262 }
0263 
0264 /*
0265  * csio_get_host_speed - Return link speed to FC transport.
0266  * @shost: scsi host.
0267  *
0268  */
0269 static void
0270 csio_get_host_speed(struct Scsi_Host *shost)
0271 {
0272     struct csio_lnode *ln = shost_priv(shost);
0273     struct csio_hw *hw = csio_lnode_to_hw(ln);
0274 
0275     spin_lock_irq(&hw->lock);
0276     switch (hw->pport[ln->portid].link_speed) {
0277     case FW_PORT_CAP32_SPEED_1G:
0278         fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
0279         break;
0280     case FW_PORT_CAP32_SPEED_10G:
0281         fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
0282         break;
0283     case FW_PORT_CAP32_SPEED_25G:
0284         fc_host_speed(shost) = FC_PORTSPEED_25GBIT;
0285         break;
0286     case FW_PORT_CAP32_SPEED_40G:
0287         fc_host_speed(shost) = FC_PORTSPEED_40GBIT;
0288         break;
0289     case FW_PORT_CAP32_SPEED_50G:
0290         fc_host_speed(shost) = FC_PORTSPEED_50GBIT;
0291         break;
0292     case FW_PORT_CAP32_SPEED_100G:
0293         fc_host_speed(shost) = FC_PORTSPEED_100GBIT;
0294         break;
0295     default:
0296         fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
0297         break;
0298     }
0299     spin_unlock_irq(&hw->lock);
0300 }
0301 
0302 /*
0303  * csio_get_host_fabric_name - Return fabric name
0304  * @shost: scsi host.
0305  *
0306  */
0307 static void
0308 csio_get_host_fabric_name(struct Scsi_Host *shost)
0309 {
0310     struct csio_lnode *ln = shost_priv(shost);
0311     struct csio_rnode *rn = NULL;
0312     struct csio_hw *hw = csio_lnode_to_hw(ln);
0313 
0314     spin_lock_irq(&hw->lock);
0315     rn = csio_rnode_lookup_portid(ln, FC_FID_FLOGI);
0316     if (rn)
0317         fc_host_fabric_name(shost) = wwn_to_u64(csio_rn_wwnn(rn));
0318     else
0319         fc_host_fabric_name(shost) = 0;
0320     spin_unlock_irq(&hw->lock);
0321 }
0322 
0323 /*
0324  * csio_get_host_speed - Return FC transport statistics.
0325  * @ln: Lnode.
0326  *
0327  */
0328 static struct fc_host_statistics *
0329 csio_get_stats(struct Scsi_Host *shost)
0330 {
0331     struct csio_lnode *ln = shost_priv(shost);
0332     struct csio_hw *hw = csio_lnode_to_hw(ln);
0333     struct fc_host_statistics *fhs = &ln->fch_stats;
0334     struct fw_fcoe_port_stats fcoe_port_stats;
0335     uint64_t seconds;
0336 
0337     memset(&fcoe_port_stats, 0, sizeof(struct fw_fcoe_port_stats));
0338     csio_get_phy_port_stats(hw, ln->portid, &fcoe_port_stats);
0339 
0340     fhs->tx_frames  += (be64_to_cpu(fcoe_port_stats.tx_bcast_frames) +
0341                 be64_to_cpu(fcoe_port_stats.tx_mcast_frames) +
0342                 be64_to_cpu(fcoe_port_stats.tx_ucast_frames) +
0343                 be64_to_cpu(fcoe_port_stats.tx_offload_frames));
0344     fhs->tx_words  += (be64_to_cpu(fcoe_port_stats.tx_bcast_bytes) +
0345                be64_to_cpu(fcoe_port_stats.tx_mcast_bytes) +
0346                be64_to_cpu(fcoe_port_stats.tx_ucast_bytes) +
0347                be64_to_cpu(fcoe_port_stats.tx_offload_bytes)) /
0348                             CSIO_WORD_TO_BYTE;
0349     fhs->rx_frames += (be64_to_cpu(fcoe_port_stats.rx_bcast_frames) +
0350                be64_to_cpu(fcoe_port_stats.rx_mcast_frames) +
0351                be64_to_cpu(fcoe_port_stats.rx_ucast_frames));
0352     fhs->rx_words += (be64_to_cpu(fcoe_port_stats.rx_bcast_bytes) +
0353               be64_to_cpu(fcoe_port_stats.rx_mcast_bytes) +
0354               be64_to_cpu(fcoe_port_stats.rx_ucast_bytes)) /
0355                             CSIO_WORD_TO_BYTE;
0356     fhs->error_frames += be64_to_cpu(fcoe_port_stats.rx_err_frames);
0357     fhs->fcp_input_requests +=  ln->stats.n_input_requests;
0358     fhs->fcp_output_requests +=  ln->stats.n_output_requests;
0359     fhs->fcp_control_requests +=  ln->stats.n_control_requests;
0360     fhs->fcp_input_megabytes +=  ln->stats.n_input_bytes >> 20;
0361     fhs->fcp_output_megabytes +=  ln->stats.n_output_bytes >> 20;
0362     fhs->link_failure_count = ln->stats.n_link_down;
0363     /* Reset stats for the device */
0364     seconds = jiffies_to_msecs(jiffies) - hw->stats.n_reset_start;
0365     do_div(seconds, 1000);
0366     fhs->seconds_since_last_reset = seconds;
0367 
0368     return fhs;
0369 }
0370 
0371 /*
0372  * csio_set_rport_loss_tmo - Set the rport dev loss timeout
0373  * @rport: fc rport.
0374  * @timeout: new value for dev loss tmo.
0375  *
0376  * If timeout is non zero set the dev_loss_tmo to timeout, else set
0377  * dev_loss_tmo to one.
0378  */
0379 static void
0380 csio_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
0381 {
0382     if (timeout)
0383         rport->dev_loss_tmo = timeout;
0384     else
0385         rport->dev_loss_tmo = 1;
0386 }
0387 
0388 static void
0389 csio_vport_set_state(struct csio_lnode *ln)
0390 {
0391     struct fc_vport *fc_vport = ln->fc_vport;
0392     struct csio_lnode  *pln = ln->pln;
0393     char state[16];
0394 
0395     /* Set fc vport state based on phyiscal lnode */
0396     csio_lnode_state_to_str(pln, state);
0397     if (strcmp(state, "READY")) {
0398         fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
0399         return;
0400     }
0401 
0402     if (!(pln->flags & CSIO_LNF_NPIVSUPP)) {
0403         fc_vport_set_state(fc_vport, FC_VPORT_NO_FABRIC_SUPP);
0404         return;
0405     }
0406 
0407     /* Set fc vport state based on virtual lnode */
0408     csio_lnode_state_to_str(ln, state);
0409     if (strcmp(state, "READY")) {
0410         fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
0411         return;
0412     }
0413     fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
0414 }
0415 
0416 static int
0417 csio_fcoe_alloc_vnp(struct csio_hw *hw, struct csio_lnode *ln)
0418 {
0419     struct csio_lnode *pln;
0420     struct csio_mb  *mbp;
0421     struct fw_fcoe_vnp_cmd *rsp;
0422     int ret = 0;
0423     int retry = 0;
0424 
0425     /* Issue VNP cmd to alloc vport */
0426     /* Allocate Mbox request */
0427     spin_lock_irq(&hw->lock);
0428     mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
0429     if (!mbp) {
0430         CSIO_INC_STATS(hw, n_err_nomem);
0431         ret = -ENOMEM;
0432         goto out;
0433     }
0434 
0435     pln = ln->pln;
0436     ln->fcf_flowid = pln->fcf_flowid;
0437     ln->portid = pln->portid;
0438 
0439     csio_fcoe_vnp_alloc_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
0440                     pln->fcf_flowid, pln->vnp_flowid, 0,
0441                     csio_ln_wwnn(ln), csio_ln_wwpn(ln), NULL);
0442 
0443     for (retry = 0; retry < 3; retry++) {
0444         /* FW is expected to complete vnp cmd in immediate mode
0445          * without much delay.
0446          * Otherwise, there will be increase in IO latency since HW
0447          * lock is held till completion of vnp mbox cmd.
0448          */
0449         ret = csio_mb_issue(hw, mbp);
0450         if (ret != -EBUSY)
0451             break;
0452 
0453         /* Retry if mbox returns busy */
0454         spin_unlock_irq(&hw->lock);
0455         msleep(2000);
0456         spin_lock_irq(&hw->lock);
0457     }
0458 
0459     if (ret) {
0460         csio_ln_err(ln, "Failed to issue mbox FCoE VNP command\n");
0461         goto out_free;
0462     }
0463 
0464     /* Process Mbox response of VNP command */
0465     rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
0466     if (FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
0467         csio_ln_err(ln, "FCOE VNP ALLOC cmd returned 0x%x!\n",
0468                 FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)));
0469         ret = -EINVAL;
0470         goto out_free;
0471     }
0472 
0473     ln->vnp_flowid = FW_FCOE_VNP_CMD_VNPI_GET(
0474                 ntohl(rsp->gen_wwn_to_vnpi));
0475     memcpy(csio_ln_wwnn(ln), rsp->vnport_wwnn, 8);
0476     memcpy(csio_ln_wwpn(ln), rsp->vnport_wwpn, 8);
0477 
0478     csio_ln_dbg(ln, "FCOE VNPI: 0x%x\n", ln->vnp_flowid);
0479     csio_ln_dbg(ln, "\tWWNN: %x%x%x%x%x%x%x%x\n",
0480             ln->ln_sparm.wwnn[0], ln->ln_sparm.wwnn[1],
0481             ln->ln_sparm.wwnn[2], ln->ln_sparm.wwnn[3],
0482             ln->ln_sparm.wwnn[4], ln->ln_sparm.wwnn[5],
0483             ln->ln_sparm.wwnn[6], ln->ln_sparm.wwnn[7]);
0484     csio_ln_dbg(ln, "\tWWPN: %x%x%x%x%x%x%x%x\n",
0485             ln->ln_sparm.wwpn[0], ln->ln_sparm.wwpn[1],
0486             ln->ln_sparm.wwpn[2], ln->ln_sparm.wwpn[3],
0487             ln->ln_sparm.wwpn[4], ln->ln_sparm.wwpn[5],
0488             ln->ln_sparm.wwpn[6], ln->ln_sparm.wwpn[7]);
0489 
0490 out_free:
0491     mempool_free(mbp, hw->mb_mempool);
0492 out:
0493     spin_unlock_irq(&hw->lock);
0494     return ret;
0495 }
0496 
0497 static int
0498 csio_fcoe_free_vnp(struct csio_hw *hw, struct csio_lnode *ln)
0499 {
0500     struct csio_mb  *mbp;
0501     struct fw_fcoe_vnp_cmd *rsp;
0502     int ret = 0;
0503     int retry = 0;
0504 
0505     /* Issue VNP cmd to free vport */
0506     /* Allocate Mbox request */
0507 
0508     spin_lock_irq(&hw->lock);
0509     mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
0510     if (!mbp) {
0511         CSIO_INC_STATS(hw, n_err_nomem);
0512         ret = -ENOMEM;
0513         goto out;
0514     }
0515 
0516     csio_fcoe_vnp_free_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
0517                    ln->fcf_flowid, ln->vnp_flowid,
0518                    NULL);
0519 
0520     for (retry = 0; retry < 3; retry++) {
0521         ret = csio_mb_issue(hw, mbp);
0522         if (ret != -EBUSY)
0523             break;
0524 
0525         /* Retry if mbox returns busy */
0526         spin_unlock_irq(&hw->lock);
0527         msleep(2000);
0528         spin_lock_irq(&hw->lock);
0529     }
0530 
0531     if (ret) {
0532         csio_ln_err(ln, "Failed to issue mbox FCoE VNP command\n");
0533         goto out_free;
0534     }
0535 
0536     /* Process Mbox response of VNP command */
0537     rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
0538     if (FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
0539         csio_ln_err(ln, "FCOE VNP FREE cmd returned 0x%x!\n",
0540                 FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)));
0541         ret = -EINVAL;
0542     }
0543 
0544 out_free:
0545     mempool_free(mbp, hw->mb_mempool);
0546 out:
0547     spin_unlock_irq(&hw->lock);
0548     return ret;
0549 }
0550 
0551 static int
0552 csio_vport_create(struct fc_vport *fc_vport, bool disable)
0553 {
0554     struct Scsi_Host *shost = fc_vport->shost;
0555     struct csio_lnode *pln = shost_priv(shost);
0556     struct csio_lnode *ln = NULL;
0557     struct csio_hw *hw = csio_lnode_to_hw(pln);
0558     uint8_t wwn[8];
0559     int ret = -1;
0560 
0561     ln = csio_shost_init(hw, &fc_vport->dev, false, pln);
0562     if (!ln)
0563         goto error;
0564 
0565     if (fc_vport->node_name != 0) {
0566         u64_to_wwn(fc_vport->node_name, wwn);
0567 
0568         if (!CSIO_VALID_WWN(wwn)) {
0569             csio_ln_err(ln,
0570                     "vport create failed. Invalid wwnn\n");
0571             goto error;
0572         }
0573         memcpy(csio_ln_wwnn(ln), wwn, 8);
0574     }
0575 
0576     if (fc_vport->port_name != 0) {
0577         u64_to_wwn(fc_vport->port_name, wwn);
0578 
0579         if (!CSIO_VALID_WWN(wwn)) {
0580             csio_ln_err(ln,
0581                     "vport create failed. Invalid wwpn\n");
0582             goto error;
0583         }
0584 
0585         if (csio_lnode_lookup_by_wwpn(hw, wwn)) {
0586             csio_ln_err(ln,
0587                 "vport create failed. wwpn already exists\n");
0588             goto error;
0589         }
0590         memcpy(csio_ln_wwpn(ln), wwn, 8);
0591     }
0592 
0593     fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING);
0594     ln->fc_vport = fc_vport;
0595 
0596     if (csio_fcoe_alloc_vnp(hw, ln))
0597         goto error;
0598 
0599     *(struct csio_lnode **)fc_vport->dd_data = ln;
0600     if (!fc_vport->node_name)
0601         fc_vport->node_name = wwn_to_u64(csio_ln_wwnn(ln));
0602     if (!fc_vport->port_name)
0603         fc_vport->port_name = wwn_to_u64(csio_ln_wwpn(ln));
0604     csio_fchost_attr_init(ln);
0605     return 0;
0606 error:
0607     if (ln)
0608         csio_shost_exit(ln);
0609 
0610     return ret;
0611 }
0612 
0613 static int
0614 csio_vport_delete(struct fc_vport *fc_vport)
0615 {
0616     struct csio_lnode *ln = *(struct csio_lnode **)fc_vport->dd_data;
0617     struct Scsi_Host *shost = csio_ln_to_shost(ln);
0618     struct csio_hw *hw = csio_lnode_to_hw(ln);
0619     int rmv;
0620 
0621     spin_lock_irq(&hw->lock);
0622     rmv = csio_is_hw_removing(hw);
0623     spin_unlock_irq(&hw->lock);
0624 
0625     if (rmv) {
0626         csio_shost_exit(ln);
0627         return 0;
0628     }
0629 
0630     /* Quiesce ios and send remove event to lnode */
0631     scsi_block_requests(shost);
0632     spin_lock_irq(&hw->lock);
0633     csio_scsim_cleanup_io_lnode(csio_hw_to_scsim(hw), ln);
0634     csio_lnode_close(ln);
0635     spin_unlock_irq(&hw->lock);
0636     scsi_unblock_requests(shost);
0637 
0638     /* Free vnp */
0639     if (fc_vport->vport_state !=  FC_VPORT_DISABLED)
0640         csio_fcoe_free_vnp(hw, ln);
0641 
0642     csio_shost_exit(ln);
0643     return 0;
0644 }
0645 
0646 static int
0647 csio_vport_disable(struct fc_vport *fc_vport, bool disable)
0648 {
0649     struct csio_lnode *ln = *(struct csio_lnode **)fc_vport->dd_data;
0650     struct Scsi_Host *shost = csio_ln_to_shost(ln);
0651     struct csio_hw *hw = csio_lnode_to_hw(ln);
0652 
0653     /* disable vport */
0654     if (disable) {
0655         /* Quiesce ios and send stop event to lnode */
0656         scsi_block_requests(shost);
0657         spin_lock_irq(&hw->lock);
0658         csio_scsim_cleanup_io_lnode(csio_hw_to_scsim(hw), ln);
0659         csio_lnode_stop(ln);
0660         spin_unlock_irq(&hw->lock);
0661         scsi_unblock_requests(shost);
0662 
0663         /* Free vnp */
0664         csio_fcoe_free_vnp(hw, ln);
0665         fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
0666         csio_ln_err(ln, "vport disabled\n");
0667         return 0;
0668     } else {
0669         /* enable vport */
0670         fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING);
0671         if (csio_fcoe_alloc_vnp(hw, ln)) {
0672             csio_ln_err(ln, "vport enabled failed.\n");
0673             return -1;
0674         }
0675         csio_ln_err(ln, "vport enabled\n");
0676         return 0;
0677     }
0678 }
0679 
0680 static void
0681 csio_dev_loss_tmo_callbk(struct fc_rport *rport)
0682 {
0683     struct csio_rnode *rn;
0684     struct csio_hw *hw;
0685     struct csio_lnode *ln;
0686 
0687     rn = *((struct csio_rnode **)rport->dd_data);
0688     ln = csio_rnode_to_lnode(rn);
0689     hw = csio_lnode_to_hw(ln);
0690 
0691     spin_lock_irq(&hw->lock);
0692 
0693     /* return if driver is being removed or same rnode comes back online */
0694     if (csio_is_hw_removing(hw) || csio_is_rnode_ready(rn))
0695         goto out;
0696 
0697     csio_ln_dbg(ln, "devloss timeout on rnode:%p portid:x%x flowid:x%x\n",
0698             rn, rn->nport_id, csio_rn_flowid(rn));
0699 
0700     CSIO_INC_STATS(ln, n_dev_loss_tmo);
0701 
0702     /*
0703      * enqueue devloss event to event worker thread to serialize all
0704      * rnode events.
0705      */
0706     if (csio_enqueue_evt(hw, CSIO_EVT_DEV_LOSS, &rn, sizeof(rn))) {
0707         CSIO_INC_STATS(hw, n_evt_drop);
0708         goto out;
0709     }
0710 
0711     if (!(hw->flags & CSIO_HWF_FWEVT_PENDING)) {
0712         hw->flags |= CSIO_HWF_FWEVT_PENDING;
0713         spin_unlock_irq(&hw->lock);
0714         schedule_work(&hw->evtq_work);
0715         return;
0716     }
0717 
0718 out:
0719     spin_unlock_irq(&hw->lock);
0720 }
0721 
0722 /* FC transport functions template - Physical port */
0723 struct fc_function_template csio_fc_transport_funcs = {
0724     .show_host_node_name = 1,
0725     .show_host_port_name = 1,
0726     .show_host_supported_classes = 1,
0727     .show_host_supported_fc4s = 1,
0728     .show_host_maxframe_size = 1,
0729 
0730     .get_host_port_id = csio_get_host_port_id,
0731     .show_host_port_id = 1,
0732 
0733     .get_host_port_type = csio_get_host_port_type,
0734     .show_host_port_type = 1,
0735 
0736     .get_host_port_state = csio_get_host_port_state,
0737     .show_host_port_state = 1,
0738 
0739     .show_host_active_fc4s = 1,
0740     .get_host_speed = csio_get_host_speed,
0741     .show_host_speed = 1,
0742     .get_host_fabric_name = csio_get_host_fabric_name,
0743     .show_host_fabric_name = 1,
0744 
0745     .get_fc_host_stats = csio_get_stats,
0746 
0747     .dd_fcrport_size = sizeof(struct csio_rnode *),
0748     .show_rport_maxframe_size = 1,
0749     .show_rport_supported_classes = 1,
0750 
0751     .set_rport_dev_loss_tmo = csio_set_rport_loss_tmo,
0752     .show_rport_dev_loss_tmo = 1,
0753 
0754     .show_starget_port_id = 1,
0755     .show_starget_node_name = 1,
0756     .show_starget_port_name = 1,
0757 
0758     .dev_loss_tmo_callbk = csio_dev_loss_tmo_callbk,
0759     .dd_fcvport_size = sizeof(struct csio_lnode *),
0760 
0761     .vport_create = csio_vport_create,
0762     .vport_disable = csio_vport_disable,
0763     .vport_delete = csio_vport_delete,
0764 };
0765 
0766 /* FC transport functions template - Virtual  port */
0767 struct fc_function_template csio_fc_transport_vport_funcs = {
0768     .show_host_node_name = 1,
0769     .show_host_port_name = 1,
0770     .show_host_supported_classes = 1,
0771     .show_host_supported_fc4s = 1,
0772     .show_host_maxframe_size = 1,
0773 
0774     .get_host_port_id = csio_get_host_port_id,
0775     .show_host_port_id = 1,
0776 
0777     .get_host_port_type = csio_get_host_port_type,
0778     .show_host_port_type = 1,
0779 
0780     .get_host_port_state = csio_get_host_port_state,
0781     .show_host_port_state = 1,
0782     .show_host_active_fc4s = 1,
0783 
0784     .get_host_speed = csio_get_host_speed,
0785     .show_host_speed = 1,
0786 
0787     .get_host_fabric_name = csio_get_host_fabric_name,
0788     .show_host_fabric_name = 1,
0789 
0790     .get_fc_host_stats = csio_get_stats,
0791 
0792     .dd_fcrport_size = sizeof(struct csio_rnode *),
0793     .show_rport_maxframe_size = 1,
0794     .show_rport_supported_classes = 1,
0795 
0796     .set_rport_dev_loss_tmo = csio_set_rport_loss_tmo,
0797     .show_rport_dev_loss_tmo = 1,
0798 
0799     .show_starget_port_id = 1,
0800     .show_starget_node_name = 1,
0801     .show_starget_port_name = 1,
0802 
0803     .dev_loss_tmo_callbk = csio_dev_loss_tmo_callbk,
0804 
0805 };