linux/drivers/scsi/csiostor/csio_attr.c
<<
>>
Prefs
   1/*
   2 * This file is part of the Chelsio FCoE driver for Linux.
   3 *
   4 * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
   5 *
   6 * This software is available to you under a choice of one of two
   7 * licenses.  You may choose to be licensed under the terms of the GNU
   8 * General Public License (GPL) Version 2, available from the file
   9 * COPYING in the main directory of this source tree, or the
  10 * OpenIB.org BSD license below:
  11 *
  12 *     Redistribution and use in source and binary forms, with or
  13 *     without modification, are permitted provided that the following
  14 *     conditions are met:
  15 *
  16 *      - Redistributions of source code must retain the above
  17 *        copyright notice, this list of conditions and the following
  18 *        disclaimer.
  19 *
  20 *      - Redistributions in binary form must reproduce the above
  21 *        copyright notice, this list of conditions and the following
  22 *        disclaimer in the documentation and/or other materials
  23 *        provided with the distribution.
  24 *
  25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  32 * SOFTWARE.
  33 */
  34
  35#include <linux/kernel.h>
  36#include <linux/string.h>
  37#include <linux/delay.h>
  38#include <linux/module.h>
  39#include <linux/init.h>
  40#include <linux/pci.h>
  41#include <linux/mm.h>
  42#include <linux/jiffies.h>
  43#include <scsi/fc/fc_fs.h>
  44
  45#include "csio_init.h"
  46
  47static void
  48csio_vport_set_state(struct csio_lnode *ln);
  49
  50/*
  51 * csio_reg_rnode - Register a remote port with FC transport.
  52 * @rn: Rnode representing remote port.
  53 *
  54 * Call fc_remote_port_add() to register this remote port with FC transport.
  55 * If remote port is Initiator OR Target OR both, change the role appropriately.
  56 *
  57 */
  58void
  59csio_reg_rnode(struct csio_rnode *rn)
  60{
  61        struct csio_lnode *ln           = csio_rnode_to_lnode(rn);
  62        struct Scsi_Host *shost         = csio_ln_to_shost(ln);
  63        struct fc_rport_identifiers ids;
  64        struct fc_rport  *rport;
  65        struct csio_service_parms *sp;
  66
  67        ids.node_name   = wwn_to_u64(csio_rn_wwnn(rn));
  68        ids.port_name   = wwn_to_u64(csio_rn_wwpn(rn));
  69        ids.port_id     = rn->nport_id;
  70        ids.roles       = FC_RPORT_ROLE_UNKNOWN;
  71
  72        if (rn->role & CSIO_RNFR_INITIATOR || rn->role & CSIO_RNFR_TARGET) {
  73                rport = rn->rport;
  74                CSIO_ASSERT(rport != NULL);
  75                goto update_role;
  76        }
  77
  78        rn->rport = fc_remote_port_add(shost, 0, &ids);
  79        if (!rn->rport) {
  80                csio_ln_err(ln, "Failed to register rport = 0x%x.\n",
  81                                        rn->nport_id);
  82                return;
  83        }
  84
  85        ln->num_reg_rnodes++;
  86        rport = rn->rport;
  87        spin_lock_irq(shost->host_lock);
  88        *((struct csio_rnode **)rport->dd_data) = rn;
  89        spin_unlock_irq(shost->host_lock);
  90
  91        sp = &rn->rn_sparm;
  92        rport->maxframe_size = ntohs(sp->csp.sp_bb_data);
  93        if (ntohs(sp->clsp[2].cp_class) & FC_CPC_VALID)
  94                rport->supported_classes = FC_COS_CLASS3;
  95        else
  96                rport->supported_classes = FC_COS_UNSPECIFIED;
  97update_role:
  98        if (rn->role & CSIO_RNFR_INITIATOR)
  99                ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
 100        if (rn->role & CSIO_RNFR_TARGET)
 101                ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
 102
 103        if (ids.roles != FC_RPORT_ROLE_UNKNOWN)
 104                fc_remote_port_rolechg(rport, ids.roles);
 105
 106        rn->scsi_id = rport->scsi_target_id;
 107
 108        csio_ln_dbg(ln, "Remote port x%x role 0x%x registered\n",
 109                rn->nport_id, ids.roles);
 110}
 111
 112/*
 113 * csio_unreg_rnode - Unregister a remote port with FC transport.
 114 * @rn: Rnode representing remote port.
 115 *
 116 * Call fc_remote_port_delete() to unregister this remote port with FC
 117 * transport.
 118 *
 119 */
 120void
 121csio_unreg_rnode(struct csio_rnode *rn)
 122{
 123        struct csio_lnode *ln = csio_rnode_to_lnode(rn);
 124        struct fc_rport *rport = rn->rport;
 125
 126        rn->role &= ~(CSIO_RNFR_INITIATOR | CSIO_RNFR_TARGET);
 127        fc_remote_port_delete(rport);
 128        ln->num_reg_rnodes--;
 129
 130        csio_ln_dbg(ln, "Remote port x%x un-registered\n", rn->nport_id);
 131}
 132
 133/*
 134 * csio_lnode_async_event - Async events from local port.
 135 * @ln: lnode representing local port.
 136 *
 137 * Async events from local node that FC transport/SCSI ML
 138 * should be made aware of (Eg: RSCN).
 139 */
 140void
 141csio_lnode_async_event(struct csio_lnode *ln, enum csio_ln_fc_evt fc_evt)
 142{
 143        switch (fc_evt) {
 144        case CSIO_LN_FC_RSCN:
 145                /* Get payload of rscn from ln */
 146                /* For each RSCN entry */
 147                        /*
 148                         * fc_host_post_event(shost,
 149                         *                    fc_get_event_number(),
 150                         *                    FCH_EVT_RSCN,
 151                         *                    rscn_entry);
 152                         */
 153                break;
 154        case CSIO_LN_FC_LINKUP:
 155                /* send fc_host_post_event */
 156                /* set vport state */
 157                if (csio_is_npiv_ln(ln))
 158                        csio_vport_set_state(ln);
 159
 160                break;
 161        case CSIO_LN_FC_LINKDOWN:
 162                /* send fc_host_post_event */
 163                /* set vport state */
 164                if (csio_is_npiv_ln(ln))
 165                        csio_vport_set_state(ln);
 166
 167                break;
 168        case CSIO_LN_FC_ATTRIB_UPDATE:
 169                csio_fchost_attr_init(ln);
 170                break;
 171        default:
 172                break;
 173        }
 174}
 175
 176/*
 177 * csio_fchost_attr_init - Initialize FC transport attributes
 178 * @ln: Lnode.
 179 *
 180 */
 181void
 182csio_fchost_attr_init(struct csio_lnode *ln)
 183{
 184        struct Scsi_Host  *shost = csio_ln_to_shost(ln);
 185
 186        fc_host_node_name(shost) = wwn_to_u64(csio_ln_wwnn(ln));
 187        fc_host_port_name(shost) = wwn_to_u64(csio_ln_wwpn(ln));
 188
 189        fc_host_supported_classes(shost) = FC_COS_CLASS3;
 190        fc_host_max_npiv_vports(shost) =
 191                        (csio_lnode_to_hw(ln))->fres_info.max_vnps;
 192        fc_host_supported_speeds(shost) = FC_PORTSPEED_10GBIT |
 193                FC_PORTSPEED_1GBIT;
 194
 195        fc_host_maxframe_size(shost) = ntohs(ln->ln_sparm.csp.sp_bb_data);
 196        memset(fc_host_supported_fc4s(shost), 0,
 197                sizeof(fc_host_supported_fc4s(shost)));
 198        fc_host_supported_fc4s(shost)[7] = 1;
 199
 200        memset(fc_host_active_fc4s(shost), 0,
 201                sizeof(fc_host_active_fc4s(shost)));
 202        fc_host_active_fc4s(shost)[7] = 1;
 203}
 204
 205/*
 206 * csio_get_host_port_id - sysfs entries for nport_id is
 207 * populated/cached from this function
 208 */
 209static void
 210csio_get_host_port_id(struct Scsi_Host *shost)
 211{
 212        struct csio_lnode *ln   = shost_priv(shost);
 213        struct csio_hw *hw = csio_lnode_to_hw(ln);
 214
 215        spin_lock_irq(&hw->lock);
 216        fc_host_port_id(shost) = ln->nport_id;
 217        spin_unlock_irq(&hw->lock);
 218}
 219
 220/*
 221 * csio_get_port_type - Return FC local port type.
 222 * @shost: scsi host.
 223 *
 224 */
 225static void
 226csio_get_host_port_type(struct Scsi_Host *shost)
 227{
 228        struct csio_lnode *ln = shost_priv(shost);
 229        struct csio_hw *hw = csio_lnode_to_hw(ln);
 230
 231        spin_lock_irq(&hw->lock);
 232        if (csio_is_npiv_ln(ln))
 233                fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
 234        else
 235                fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
 236        spin_unlock_irq(&hw->lock);
 237}
 238
 239/*
 240 * csio_get_port_state - Return FC local port state.
 241 * @shost: scsi host.
 242 *
 243 */
 244static void
 245csio_get_host_port_state(struct Scsi_Host *shost)
 246{
 247        struct csio_lnode *ln = shost_priv(shost);
 248        struct csio_hw *hw = csio_lnode_to_hw(ln);
 249        char state[16];
 250
 251        spin_lock_irq(&hw->lock);
 252
 253        csio_lnode_state_to_str(ln, state);
 254        if (!strcmp(state, "READY"))
 255                fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
 256        else if (!strcmp(state, "OFFLINE"))
 257                fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
 258        else
 259                fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
 260
 261        spin_unlock_irq(&hw->lock);
 262}
 263
 264/*
 265 * csio_get_host_speed - Return link speed to FC transport.
 266 * @shost: scsi host.
 267 *
 268 */
 269static void
 270csio_get_host_speed(struct Scsi_Host *shost)
 271{
 272        struct csio_lnode *ln = shost_priv(shost);
 273        struct csio_hw *hw = csio_lnode_to_hw(ln);
 274
 275        spin_lock_irq(&hw->lock);
 276        switch (hw->pport[ln->portid].link_speed) {
 277        case FW_PORT_CAP_SPEED_1G:
 278                fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
 279                break;
 280        case FW_PORT_CAP_SPEED_10G:
 281                fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
 282                break;
 283        default:
 284                fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 285                break;
 286        }
 287        spin_unlock_irq(&hw->lock);
 288}
 289
 290/*
 291 * csio_get_host_fabric_name - Return fabric name
 292 * @shost: scsi host.
 293 *
 294 */
 295static void
 296csio_get_host_fabric_name(struct Scsi_Host *shost)
 297{
 298        struct csio_lnode *ln = shost_priv(shost);
 299        struct csio_rnode *rn = NULL;
 300        struct csio_hw *hw = csio_lnode_to_hw(ln);
 301
 302        spin_lock_irq(&hw->lock);
 303        rn = csio_rnode_lookup_portid(ln, FC_FID_FLOGI);
 304        if (rn)
 305                fc_host_fabric_name(shost) = wwn_to_u64(csio_rn_wwnn(rn));
 306        else
 307                fc_host_fabric_name(shost) = 0;
 308        spin_unlock_irq(&hw->lock);
 309}
 310
 311/*
 312 * csio_get_host_speed - Return FC transport statistics.
 313 * @ln: Lnode.
 314 *
 315 */
 316static struct fc_host_statistics *
 317csio_get_stats(struct Scsi_Host *shost)
 318{
 319        struct csio_lnode *ln = shost_priv(shost);
 320        struct csio_hw *hw = csio_lnode_to_hw(ln);
 321        struct fc_host_statistics *fhs = &ln->fch_stats;
 322        struct fw_fcoe_port_stats fcoe_port_stats;
 323        uint64_t seconds;
 324
 325        memset(&fcoe_port_stats, 0, sizeof(struct fw_fcoe_port_stats));
 326        csio_get_phy_port_stats(hw, ln->portid, &fcoe_port_stats);
 327
 328        fhs->tx_frames  += (be64_to_cpu(fcoe_port_stats.tx_bcast_frames) +
 329                            be64_to_cpu(fcoe_port_stats.tx_mcast_frames) +
 330                            be64_to_cpu(fcoe_port_stats.tx_ucast_frames) +
 331                            be64_to_cpu(fcoe_port_stats.tx_offload_frames));
 332        fhs->tx_words  += (be64_to_cpu(fcoe_port_stats.tx_bcast_bytes) +
 333                           be64_to_cpu(fcoe_port_stats.tx_mcast_bytes) +
 334                           be64_to_cpu(fcoe_port_stats.tx_ucast_bytes) +
 335                           be64_to_cpu(fcoe_port_stats.tx_offload_bytes)) /
 336                                                        CSIO_WORD_TO_BYTE;
 337        fhs->rx_frames += (be64_to_cpu(fcoe_port_stats.rx_bcast_frames) +
 338                           be64_to_cpu(fcoe_port_stats.rx_mcast_frames) +
 339                           be64_to_cpu(fcoe_port_stats.rx_ucast_frames));
 340        fhs->rx_words += (be64_to_cpu(fcoe_port_stats.rx_bcast_bytes) +
 341                          be64_to_cpu(fcoe_port_stats.rx_mcast_bytes) +
 342                          be64_to_cpu(fcoe_port_stats.rx_ucast_bytes)) /
 343                                                        CSIO_WORD_TO_BYTE;
 344        fhs->error_frames += be64_to_cpu(fcoe_port_stats.rx_err_frames);
 345        fhs->fcp_input_requests +=  ln->stats.n_input_requests;
 346        fhs->fcp_output_requests +=  ln->stats.n_output_requests;
 347        fhs->fcp_control_requests +=  ln->stats.n_control_requests;
 348        fhs->fcp_input_megabytes +=  ln->stats.n_input_bytes >> 20;
 349        fhs->fcp_output_megabytes +=  ln->stats.n_output_bytes >> 20;
 350        fhs->link_failure_count = ln->stats.n_link_down;
 351        /* Reset stats for the device */
 352        seconds = jiffies_to_msecs(jiffies) - hw->stats.n_reset_start;
 353        do_div(seconds, 1000);
 354        fhs->seconds_since_last_reset = seconds;
 355
 356        return fhs;
 357}
 358
 359/*
 360 * csio_set_rport_loss_tmo - Set the rport dev loss timeout
 361 * @rport: fc rport.
 362 * @timeout: new value for dev loss tmo.
 363 *
 364 * If timeout is non zero set the dev_loss_tmo to timeout, else set
 365 * dev_loss_tmo to one.
 366 */
 367static void
 368csio_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
 369{
 370        if (timeout)
 371                rport->dev_loss_tmo = timeout;
 372        else
 373                rport->dev_loss_tmo = 1;
 374}
 375
 376static void
 377csio_vport_set_state(struct csio_lnode *ln)
 378{
 379        struct fc_vport *fc_vport = ln->fc_vport;
 380        struct csio_lnode  *pln = ln->pln;
 381        char state[16];
 382
 383        /* Set fc vport state based on phyiscal lnode */
 384        csio_lnode_state_to_str(pln, state);
 385        if (strcmp(state, "READY")) {
 386                fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
 387                return;
 388        }
 389
 390        if (!(pln->flags & CSIO_LNF_NPIVSUPP)) {
 391                fc_vport_set_state(fc_vport, FC_VPORT_NO_FABRIC_SUPP);
 392                return;
 393        }
 394
 395        /* Set fc vport state based on virtual lnode */
 396        csio_lnode_state_to_str(ln, state);
 397        if (strcmp(state, "READY")) {
 398                fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
 399                return;
 400        }
 401        fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
 402}
 403
 404static int
 405csio_fcoe_alloc_vnp(struct csio_hw *hw, struct csio_lnode *ln)
 406{
 407        struct csio_lnode *pln;
 408        struct csio_mb  *mbp;
 409        struct fw_fcoe_vnp_cmd *rsp;
 410        int ret = 0;
 411        int retry = 0;
 412
 413        /* Issue VNP cmd to alloc vport */
 414        /* Allocate Mbox request */
 415        spin_lock_irq(&hw->lock);
 416        mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
 417        if (!mbp) {
 418                CSIO_INC_STATS(hw, n_err_nomem);
 419                ret = -ENOMEM;
 420                goto out;
 421        }
 422
 423        pln = ln->pln;
 424        ln->fcf_flowid = pln->fcf_flowid;
 425        ln->portid = pln->portid;
 426
 427        csio_fcoe_vnp_alloc_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
 428                                    pln->fcf_flowid, pln->vnp_flowid, 0,
 429                                    csio_ln_wwnn(ln), csio_ln_wwpn(ln), NULL);
 430
 431        for (retry = 0; retry < 3; retry++) {
 432                /* FW is expected to complete vnp cmd in immediate mode
 433                 * without much delay.
 434                 * Otherwise, there will be increase in IO latency since HW
 435                 * lock is held till completion of vnp mbox cmd.
 436                 */
 437                ret = csio_mb_issue(hw, mbp);
 438                if (ret != -EBUSY)
 439                        break;
 440
 441                /* Retry if mbox returns busy */
 442                spin_unlock_irq(&hw->lock);
 443                msleep(2000);
 444                spin_lock_irq(&hw->lock);
 445        }
 446
 447        if (ret) {
 448                csio_ln_err(ln, "Failed to issue mbox FCoE VNP command\n");
 449                goto out_free;
 450        }
 451
 452        /* Process Mbox response of VNP command */
 453        rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
 454        if (FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
 455                csio_ln_err(ln, "FCOE VNP ALLOC cmd returned 0x%x!\n",
 456                            FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)));
 457                ret = -EINVAL;
 458                goto out_free;
 459        }
 460
 461        ln->vnp_flowid = FW_FCOE_VNP_CMD_VNPI_GET(
 462                                ntohl(rsp->gen_wwn_to_vnpi));
 463        memcpy(csio_ln_wwnn(ln), rsp->vnport_wwnn, 8);
 464        memcpy(csio_ln_wwpn(ln), rsp->vnport_wwpn, 8);
 465
 466        csio_ln_dbg(ln, "FCOE VNPI: 0x%x\n", ln->vnp_flowid);
 467        csio_ln_dbg(ln, "\tWWNN: %x%x%x%x%x%x%x%x\n",
 468                    ln->ln_sparm.wwnn[0], ln->ln_sparm.wwnn[1],
 469                    ln->ln_sparm.wwnn[2], ln->ln_sparm.wwnn[3],
 470                    ln->ln_sparm.wwnn[4], ln->ln_sparm.wwnn[5],
 471                    ln->ln_sparm.wwnn[6], ln->ln_sparm.wwnn[7]);
 472        csio_ln_dbg(ln, "\tWWPN: %x%x%x%x%x%x%x%x\n",
 473                    ln->ln_sparm.wwpn[0], ln->ln_sparm.wwpn[1],
 474                    ln->ln_sparm.wwpn[2], ln->ln_sparm.wwpn[3],
 475                    ln->ln_sparm.wwpn[4], ln->ln_sparm.wwpn[5],
 476                    ln->ln_sparm.wwpn[6], ln->ln_sparm.wwpn[7]);
 477
 478out_free:
 479        mempool_free(mbp, hw->mb_mempool);
 480out:
 481        spin_unlock_irq(&hw->lock);
 482        return ret;
 483}
 484
 485static int
 486csio_fcoe_free_vnp(struct csio_hw *hw, struct csio_lnode *ln)
 487{
 488        struct csio_lnode *pln;
 489        struct csio_mb  *mbp;
 490        struct fw_fcoe_vnp_cmd *rsp;
 491        int ret = 0;
 492        int retry = 0;
 493
 494        /* Issue VNP cmd to free vport */
 495        /* Allocate Mbox request */
 496
 497        spin_lock_irq(&hw->lock);
 498        mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
 499        if (!mbp) {
 500                CSIO_INC_STATS(hw, n_err_nomem);
 501                ret = -ENOMEM;
 502                goto out;
 503        }
 504
 505        pln = ln->pln;
 506
 507        csio_fcoe_vnp_free_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
 508                                   ln->fcf_flowid, ln->vnp_flowid,
 509                                   NULL);
 510
 511        for (retry = 0; retry < 3; retry++) {
 512                ret = csio_mb_issue(hw, mbp);
 513                if (ret != -EBUSY)
 514                        break;
 515
 516                /* Retry if mbox returns busy */
 517                spin_unlock_irq(&hw->lock);
 518                msleep(2000);
 519                spin_lock_irq(&hw->lock);
 520        }
 521
 522        if (ret) {
 523                csio_ln_err(ln, "Failed to issue mbox FCoE VNP command\n");
 524                goto out_free;
 525        }
 526
 527        /* Process Mbox response of VNP command */
 528        rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
 529        if (FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
 530                csio_ln_err(ln, "FCOE VNP FREE cmd returned 0x%x!\n",
 531                            FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)));
 532                ret = -EINVAL;
 533        }
 534
 535out_free:
 536        mempool_free(mbp, hw->mb_mempool);
 537out:
 538        spin_unlock_irq(&hw->lock);
 539        return ret;
 540}
 541
 542static int
 543csio_vport_create(struct fc_vport *fc_vport, bool disable)
 544{
 545        struct Scsi_Host *shost = fc_vport->shost;
 546        struct csio_lnode *pln = shost_priv(shost);
 547        struct csio_lnode *ln = NULL;
 548        struct csio_hw *hw = csio_lnode_to_hw(pln);
 549        uint8_t wwn[8];
 550        int ret = -1;
 551
 552        ln = csio_shost_init(hw, &fc_vport->dev, false, pln);
 553        if (!ln)
 554                goto error;
 555
 556        if (fc_vport->node_name != 0) {
 557                u64_to_wwn(fc_vport->node_name, wwn);
 558
 559                if (!CSIO_VALID_WWN(wwn)) {
 560                        csio_ln_err(ln,
 561                                    "vport create failed. Invalid wwnn\n");
 562                        goto error;
 563                }
 564                memcpy(csio_ln_wwnn(ln), wwn, 8);
 565        }
 566
 567        if (fc_vport->port_name != 0) {
 568                u64_to_wwn(fc_vport->port_name, wwn);
 569
 570                if (!CSIO_VALID_WWN(wwn)) {
 571                        csio_ln_err(ln,
 572                                    "vport create failed. Invalid wwpn\n");
 573                        goto error;
 574                }
 575
 576                if (csio_lnode_lookup_by_wwpn(hw, wwn)) {
 577                        csio_ln_err(ln,
 578                            "vport create failed. wwpn already exists\n");
 579                        goto error;
 580                }
 581                memcpy(csio_ln_wwpn(ln), wwn, 8);
 582        }
 583
 584        fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING);
 585
 586        if (csio_fcoe_alloc_vnp(hw, ln))
 587                goto error;
 588
 589        *(struct csio_lnode **)fc_vport->dd_data = ln;
 590        ln->fc_vport = fc_vport;
 591        if (!fc_vport->node_name)
 592                fc_vport->node_name = wwn_to_u64(csio_ln_wwnn(ln));
 593        if (!fc_vport->port_name)
 594                fc_vport->port_name = wwn_to_u64(csio_ln_wwpn(ln));
 595        csio_fchost_attr_init(ln);
 596        return 0;
 597error:
 598        if (ln)
 599                csio_shost_exit(ln);
 600
 601        return ret;
 602}
 603
 604static int
 605csio_vport_delete(struct fc_vport *fc_vport)
 606{
 607        struct csio_lnode *ln = *(struct csio_lnode **)fc_vport->dd_data;
 608        struct Scsi_Host *shost = csio_ln_to_shost(ln);
 609        struct csio_hw *hw = csio_lnode_to_hw(ln);
 610        int rmv;
 611
 612        spin_lock_irq(&hw->lock);
 613        rmv = csio_is_hw_removing(hw);
 614        spin_unlock_irq(&hw->lock);
 615
 616        if (rmv) {
 617                csio_shost_exit(ln);
 618                return 0;
 619        }
 620
 621        /* Quiesce ios and send remove event to lnode */
 622        scsi_block_requests(shost);
 623        spin_lock_irq(&hw->lock);
 624        csio_scsim_cleanup_io_lnode(csio_hw_to_scsim(hw), ln);
 625        csio_lnode_close(ln);
 626        spin_unlock_irq(&hw->lock);
 627        scsi_unblock_requests(shost);
 628
 629        /* Free vnp */
 630        if (fc_vport->vport_state !=  FC_VPORT_DISABLED)
 631                csio_fcoe_free_vnp(hw, ln);
 632
 633        csio_shost_exit(ln);
 634        return 0;
 635}
 636
 637static int
 638csio_vport_disable(struct fc_vport *fc_vport, bool disable)
 639{
 640        struct csio_lnode *ln = *(struct csio_lnode **)fc_vport->dd_data;
 641        struct Scsi_Host *shost = csio_ln_to_shost(ln);
 642        struct csio_hw *hw = csio_lnode_to_hw(ln);
 643
 644        /* disable vport */
 645        if (disable) {
 646                /* Quiesce ios and send stop event to lnode */
 647                scsi_block_requests(shost);
 648                spin_lock_irq(&hw->lock);
 649                csio_scsim_cleanup_io_lnode(csio_hw_to_scsim(hw), ln);
 650                csio_lnode_stop(ln);
 651                spin_unlock_irq(&hw->lock);
 652                scsi_unblock_requests(shost);
 653
 654                /* Free vnp */
 655                csio_fcoe_free_vnp(hw, ln);
 656                fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
 657                csio_ln_err(ln, "vport disabled\n");
 658                return 0;
 659        } else {
 660                /* enable vport */
 661                fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING);
 662                if (csio_fcoe_alloc_vnp(hw, ln)) {
 663                        csio_ln_err(ln, "vport enabled failed.\n");
 664                        return -1;
 665                }
 666                csio_ln_err(ln, "vport enabled\n");
 667                return 0;
 668        }
 669}
 670
 671static void
 672csio_dev_loss_tmo_callbk(struct fc_rport *rport)
 673{
 674        struct csio_rnode *rn;
 675        struct csio_hw *hw;
 676        struct csio_lnode *ln;
 677
 678        rn = *((struct csio_rnode **)rport->dd_data);
 679        ln = csio_rnode_to_lnode(rn);
 680        hw = csio_lnode_to_hw(ln);
 681
 682        spin_lock_irq(&hw->lock);
 683
 684        /* return if driver is being removed or same rnode comes back online */
 685        if (csio_is_hw_removing(hw) || csio_is_rnode_ready(rn))
 686                goto out;
 687
 688        csio_ln_dbg(ln, "devloss timeout on rnode:%p portid:x%x flowid:x%x\n",
 689                    rn, rn->nport_id, csio_rn_flowid(rn));
 690
 691        CSIO_INC_STATS(ln, n_dev_loss_tmo);
 692
 693        /*
 694         * enqueue devloss event to event worker thread to serialize all
 695         * rnode events.
 696         */
 697        if (csio_enqueue_evt(hw, CSIO_EVT_DEV_LOSS, &rn, sizeof(rn))) {
 698                CSIO_INC_STATS(hw, n_evt_drop);
 699                goto out;
 700        }
 701
 702        if (!(hw->flags & CSIO_HWF_FWEVT_PENDING)) {
 703                hw->flags |= CSIO_HWF_FWEVT_PENDING;
 704                spin_unlock_irq(&hw->lock);
 705                schedule_work(&hw->evtq_work);
 706                return;
 707        }
 708
 709out:
 710        spin_unlock_irq(&hw->lock);
 711}
 712
 713/* FC transport functions template - Physical port */
 714struct fc_function_template csio_fc_transport_funcs = {
 715        .show_host_node_name = 1,
 716        .show_host_port_name = 1,
 717        .show_host_supported_classes = 1,
 718        .show_host_supported_fc4s = 1,
 719        .show_host_maxframe_size = 1,
 720
 721        .get_host_port_id = csio_get_host_port_id,
 722        .show_host_port_id = 1,
 723
 724        .get_host_port_type = csio_get_host_port_type,
 725        .show_host_port_type = 1,
 726
 727        .get_host_port_state = csio_get_host_port_state,
 728        .show_host_port_state = 1,
 729
 730        .show_host_active_fc4s = 1,
 731        .get_host_speed = csio_get_host_speed,
 732        .show_host_speed = 1,
 733        .get_host_fabric_name = csio_get_host_fabric_name,
 734        .show_host_fabric_name = 1,
 735
 736        .get_fc_host_stats = csio_get_stats,
 737
 738        .dd_fcrport_size = sizeof(struct csio_rnode *),
 739        .show_rport_maxframe_size = 1,
 740        .show_rport_supported_classes = 1,
 741
 742        .set_rport_dev_loss_tmo = csio_set_rport_loss_tmo,
 743        .show_rport_dev_loss_tmo = 1,
 744
 745        .show_starget_port_id = 1,
 746        .show_starget_node_name = 1,
 747        .show_starget_port_name = 1,
 748
 749        .dev_loss_tmo_callbk = csio_dev_loss_tmo_callbk,
 750        .dd_fcvport_size = sizeof(struct csio_lnode *),
 751
 752        .vport_create = csio_vport_create,
 753        .vport_disable = csio_vport_disable,
 754        .vport_delete = csio_vport_delete,
 755};
 756
 757/* FC transport functions template - Virtual  port */
 758struct fc_function_template csio_fc_transport_vport_funcs = {
 759        .show_host_node_name = 1,
 760        .show_host_port_name = 1,
 761        .show_host_supported_classes = 1,
 762        .show_host_supported_fc4s = 1,
 763        .show_host_maxframe_size = 1,
 764
 765        .get_host_port_id = csio_get_host_port_id,
 766        .show_host_port_id = 1,
 767
 768        .get_host_port_type = csio_get_host_port_type,
 769        .show_host_port_type = 1,
 770
 771        .get_host_port_state = csio_get_host_port_state,
 772        .show_host_port_state = 1,
 773        .show_host_active_fc4s = 1,
 774
 775        .get_host_speed = csio_get_host_speed,
 776        .show_host_speed = 1,
 777
 778        .get_host_fabric_name = csio_get_host_fabric_name,
 779        .show_host_fabric_name = 1,
 780
 781        .get_fc_host_stats = csio_get_stats,
 782
 783        .dd_fcrport_size = sizeof(struct csio_rnode *),
 784        .show_rport_maxframe_size = 1,
 785        .show_rport_supported_classes = 1,
 786
 787        .set_rport_dev_loss_tmo = csio_set_rport_loss_tmo,
 788        .show_rport_dev_loss_tmo = 1,
 789
 790        .show_starget_port_id = 1,
 791        .show_starget_node_name = 1,
 792        .show_starget_port_name = 1,
 793
 794        .dev_loss_tmo_callbk = csio_dev_loss_tmo_callbk,
 795
 796};
 797