mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 09:08:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
921
drivers/scsi/csiostor/csio_rnode.c
Normal file
921
drivers/scsi/csiostor/csio_rnode.c
Normal file
|
@ -0,0 +1,921 @@
|
|||
/*
|
||||
* This file is part of the Chelsio FCoE driver for Linux.
|
||||
*
|
||||
* Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the
|
||||
* OpenIB.org BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_transport_fc.h>
|
||||
#include <scsi/fc/fc_els.h>
|
||||
#include <scsi/fc/fc_fs.h>
|
||||
|
||||
#include "csio_hw.h"
|
||||
#include "csio_lnode.h"
|
||||
#include "csio_rnode.h"
|
||||
|
||||
static int csio_rnode_init(struct csio_rnode *, struct csio_lnode *);
|
||||
static void csio_rnode_exit(struct csio_rnode *);
|
||||
|
||||
/* Static machine forward declarations */
|
||||
static void csio_rns_uninit(struct csio_rnode *, enum csio_rn_ev);
|
||||
static void csio_rns_ready(struct csio_rnode *, enum csio_rn_ev);
|
||||
static void csio_rns_offline(struct csio_rnode *, enum csio_rn_ev);
|
||||
static void csio_rns_disappeared(struct csio_rnode *, enum csio_rn_ev);
|
||||
|
||||
/* RNF event mapping */
|
||||
static enum csio_rn_ev fwevt_to_rnevt[] = {
|
||||
CSIO_RNFE_NONE, /* None */
|
||||
CSIO_RNFE_LOGGED_IN, /* PLOGI_ACC_RCVD */
|
||||
CSIO_RNFE_NONE, /* PLOGI_RJT_RCVD */
|
||||
CSIO_RNFE_PLOGI_RECV, /* PLOGI_RCVD */
|
||||
CSIO_RNFE_LOGO_RECV, /* PLOGO_RCVD */
|
||||
CSIO_RNFE_PRLI_DONE, /* PRLI_ACC_RCVD */
|
||||
CSIO_RNFE_NONE, /* PRLI_RJT_RCVD */
|
||||
CSIO_RNFE_PRLI_RECV, /* PRLI_RCVD */
|
||||
CSIO_RNFE_PRLO_RECV, /* PRLO_RCVD */
|
||||
CSIO_RNFE_NONE, /* NPORT_ID_CHGD */
|
||||
CSIO_RNFE_LOGO_RECV, /* FLOGO_RCVD */
|
||||
CSIO_RNFE_NONE, /* CLR_VIRT_LNK_RCVD */
|
||||
CSIO_RNFE_LOGGED_IN, /* FLOGI_ACC_RCVD */
|
||||
CSIO_RNFE_NONE, /* FLOGI_RJT_RCVD */
|
||||
CSIO_RNFE_LOGGED_IN, /* FDISC_ACC_RCVD */
|
||||
CSIO_RNFE_NONE, /* FDISC_RJT_RCVD */
|
||||
CSIO_RNFE_NONE, /* FLOGI_TMO_MAX_RETRY */
|
||||
CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_ACC */
|
||||
CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_RJT */
|
||||
CSIO_RNFE_NONE, /* IMPL_LOGO_ADISC_CNFLT */
|
||||
CSIO_RNFE_NONE, /* PRLI_TMO */
|
||||
CSIO_RNFE_NONE, /* ADISC_TMO */
|
||||
CSIO_RNFE_NAME_MISSING, /* RSCN_DEV_LOST */
|
||||
CSIO_RNFE_NONE, /* SCR_ACC_RCVD */
|
||||
CSIO_RNFE_NONE, /* ADISC_RJT_RCVD */
|
||||
CSIO_RNFE_NONE, /* LOGO_SNT */
|
||||
CSIO_RNFE_LOGO_RECV, /* PROTO_ERR_IMPL_LOGO */
|
||||
};
|
||||
|
||||
#define CSIO_FWE_TO_RNFE(_evt) ((_evt > PROTO_ERR_IMPL_LOGO) ? \
|
||||
CSIO_RNFE_NONE : \
|
||||
fwevt_to_rnevt[_evt])
|
||||
int
|
||||
csio_is_rnode_ready(struct csio_rnode *rn)
|
||||
{
|
||||
return csio_match_state(rn, csio_rns_ready);
|
||||
}
|
||||
|
||||
static int
|
||||
csio_is_rnode_uninit(struct csio_rnode *rn)
|
||||
{
|
||||
return csio_match_state(rn, csio_rns_uninit);
|
||||
}
|
||||
|
||||
static int
|
||||
csio_is_rnode_wka(uint8_t rport_type)
|
||||
{
|
||||
if ((rport_type == FLOGI_VFPORT) ||
|
||||
(rport_type == FDISC_VFPORT) ||
|
||||
(rport_type == NS_VNPORT) ||
|
||||
(rport_type == FDMI_VNPORT))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_rn_lookup - Finds the rnode with the given flowid
|
||||
* @ln - lnode
|
||||
* @flowid - flowid.
|
||||
*
|
||||
* Does the rnode lookup on the given lnode and flowid.If no matching entry
|
||||
* found, NULL is returned.
|
||||
*/
|
||||
static struct csio_rnode *
|
||||
csio_rn_lookup(struct csio_lnode *ln, uint32_t flowid)
|
||||
{
|
||||
struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
|
||||
struct list_head *tmp;
|
||||
struct csio_rnode *rn;
|
||||
|
||||
list_for_each(tmp, &rnhead->sm.sm_list) {
|
||||
rn = (struct csio_rnode *) tmp;
|
||||
if (rn->flowid == flowid)
|
||||
return rn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_rn_lookup_wwpn - Finds the rnode with the given wwpn
|
||||
* @ln: lnode
|
||||
* @wwpn: wwpn
|
||||
*
|
||||
* Does the rnode lookup on the given lnode and wwpn. If no matching entry
|
||||
* found, NULL is returned.
|
||||
*/
|
||||
static struct csio_rnode *
|
||||
csio_rn_lookup_wwpn(struct csio_lnode *ln, uint8_t *wwpn)
|
||||
{
|
||||
struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
|
||||
struct list_head *tmp;
|
||||
struct csio_rnode *rn;
|
||||
|
||||
list_for_each(tmp, &rnhead->sm.sm_list) {
|
||||
rn = (struct csio_rnode *) tmp;
|
||||
if (!memcmp(csio_rn_wwpn(rn), wwpn, 8))
|
||||
return rn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* csio_rnode_lookup_portid - Finds the rnode with the given portid
|
||||
* @ln: lnode
|
||||
* @portid: port id
|
||||
*
|
||||
* Lookup the rnode list for a given portid. If no matching entry
|
||||
* found, NULL is returned.
|
||||
*/
|
||||
struct csio_rnode *
|
||||
csio_rnode_lookup_portid(struct csio_lnode *ln, uint32_t portid)
|
||||
{
|
||||
struct csio_rnode *rnhead = (struct csio_rnode *) &ln->rnhead;
|
||||
struct list_head *tmp;
|
||||
struct csio_rnode *rn;
|
||||
|
||||
list_for_each(tmp, &rnhead->sm.sm_list) {
|
||||
rn = (struct csio_rnode *) tmp;
|
||||
if (rn->nport_id == portid)
|
||||
return rn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
csio_rn_dup_flowid(struct csio_lnode *ln, uint32_t rdev_flowid,
|
||||
uint32_t *vnp_flowid)
|
||||
{
|
||||
struct csio_rnode *rnhead;
|
||||
struct list_head *tmp, *tmp1;
|
||||
struct csio_rnode *rn;
|
||||
struct csio_lnode *ln_tmp;
|
||||
struct csio_hw *hw = csio_lnode_to_hw(ln);
|
||||
|
||||
list_for_each(tmp1, &hw->sln_head) {
|
||||
ln_tmp = (struct csio_lnode *) tmp1;
|
||||
if (ln_tmp == ln)
|
||||
continue;
|
||||
|
||||
rnhead = (struct csio_rnode *)&ln_tmp->rnhead;
|
||||
list_for_each(tmp, &rnhead->sm.sm_list) {
|
||||
|
||||
rn = (struct csio_rnode *) tmp;
|
||||
if (csio_is_rnode_ready(rn)) {
|
||||
if (rn->flowid == rdev_flowid) {
|
||||
*vnp_flowid = csio_ln_flowid(ln_tmp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct csio_rnode *
|
||||
csio_alloc_rnode(struct csio_lnode *ln)
|
||||
{
|
||||
struct csio_hw *hw = csio_lnode_to_hw(ln);
|
||||
|
||||
struct csio_rnode *rn = mempool_alloc(hw->rnode_mempool, GFP_ATOMIC);
|
||||
if (!rn)
|
||||
goto err;
|
||||
|
||||
memset(rn, 0, sizeof(struct csio_rnode));
|
||||
if (csio_rnode_init(rn, ln))
|
||||
goto err_free;
|
||||
|
||||
CSIO_INC_STATS(ln, n_rnode_alloc);
|
||||
|
||||
return rn;
|
||||
|
||||
err_free:
|
||||
mempool_free(rn, hw->rnode_mempool);
|
||||
err:
|
||||
CSIO_INC_STATS(ln, n_rnode_nomem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
csio_free_rnode(struct csio_rnode *rn)
|
||||
{
|
||||
struct csio_hw *hw = csio_lnode_to_hw(csio_rnode_to_lnode(rn));
|
||||
|
||||
csio_rnode_exit(rn);
|
||||
CSIO_INC_STATS(rn->lnp, n_rnode_free);
|
||||
mempool_free(rn, hw->rnode_mempool);
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_get_rnode - Gets rnode with the given flowid
|
||||
* @ln - lnode
|
||||
* @flowid - flow id.
|
||||
*
|
||||
* Does the rnode lookup on the given lnode and flowid. If no matching
|
||||
* rnode found, then new rnode with given npid is allocated and returned.
|
||||
*/
|
||||
static struct csio_rnode *
|
||||
csio_get_rnode(struct csio_lnode *ln, uint32_t flowid)
|
||||
{
|
||||
struct csio_rnode *rn;
|
||||
|
||||
rn = csio_rn_lookup(ln, flowid);
|
||||
if (!rn) {
|
||||
rn = csio_alloc_rnode(ln);
|
||||
if (!rn)
|
||||
return NULL;
|
||||
|
||||
rn->flowid = flowid;
|
||||
}
|
||||
|
||||
return rn;
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_put_rnode - Frees the given rnode
|
||||
* @ln - lnode
|
||||
* @flowid - flow id.
|
||||
*
|
||||
* Does the rnode lookup on the given lnode and flowid. If no matching
|
||||
* rnode found, then new rnode with given npid is allocated and returned.
|
||||
*/
|
||||
void
|
||||
csio_put_rnode(struct csio_lnode *ln, struct csio_rnode *rn)
|
||||
{
|
||||
CSIO_DB_ASSERT(csio_is_rnode_uninit(rn) != 0);
|
||||
csio_free_rnode(rn);
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_confirm_rnode - confirms rnode based on wwpn.
|
||||
* @ln: lnode
|
||||
* @rdev_flowid: remote device flowid
|
||||
* @rdevp: remote device params
|
||||
* This routines searches other rnode in list having same wwpn of new rnode.
|
||||
* If there is a match, then matched rnode is returned and otherwise new rnode
|
||||
* is returned.
|
||||
* returns rnode.
|
||||
*/
|
||||
struct csio_rnode *
|
||||
csio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
|
||||
struct fcoe_rdev_entry *rdevp)
|
||||
{
|
||||
uint8_t rport_type;
|
||||
struct csio_rnode *rn, *match_rn;
|
||||
uint32_t vnp_flowid = 0;
|
||||
__be32 *port_id;
|
||||
|
||||
port_id = (__be32 *)&rdevp->r_id[0];
|
||||
rport_type =
|
||||
FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
|
||||
|
||||
/* Drop rdev event for cntrl port */
|
||||
if (rport_type == FAB_CTLR_VNPORT) {
|
||||
csio_ln_dbg(ln,
|
||||
"Unhandled rport_type:%d recv in rdev evt "
|
||||
"ssni:x%x\n", rport_type, rdev_flowid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Lookup on flowid */
|
||||
rn = csio_rn_lookup(ln, rdev_flowid);
|
||||
if (!rn) {
|
||||
|
||||
/* Drop events with duplicate flowid */
|
||||
if (csio_rn_dup_flowid(ln, rdev_flowid, &vnp_flowid)) {
|
||||
csio_ln_warn(ln,
|
||||
"ssni:%x already active on vnpi:%x",
|
||||
rdev_flowid, vnp_flowid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Lookup on wwpn for NPORTs */
|
||||
rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
|
||||
if (!rn)
|
||||
goto alloc_rnode;
|
||||
|
||||
} else {
|
||||
/* Lookup well-known ports with nport id */
|
||||
if (csio_is_rnode_wka(rport_type)) {
|
||||
match_rn = csio_rnode_lookup_portid(ln,
|
||||
((ntohl(*port_id) >> 8) & CSIO_DID_MASK));
|
||||
if (match_rn == NULL) {
|
||||
csio_rn_flowid(rn) = CSIO_INVALID_IDX;
|
||||
goto alloc_rnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now compare the wwpn to confirm that
|
||||
* same port relogged in. If so update the matched rn.
|
||||
* Else, go ahead and alloc a new rnode.
|
||||
*/
|
||||
if (!memcmp(csio_rn_wwpn(match_rn), rdevp->wwpn, 8)) {
|
||||
if (rn == match_rn)
|
||||
goto found_rnode;
|
||||
csio_ln_dbg(ln,
|
||||
"nport_id:x%x and wwpn:%llx"
|
||||
" match for ssni:x%x\n",
|
||||
rn->nport_id,
|
||||
wwn_to_u64(rdevp->wwpn),
|
||||
rdev_flowid);
|
||||
if (csio_is_rnode_ready(rn)) {
|
||||
csio_ln_warn(ln,
|
||||
"rnode is already"
|
||||
"active ssni:x%x\n",
|
||||
rdev_flowid);
|
||||
CSIO_ASSERT(0);
|
||||
}
|
||||
csio_rn_flowid(rn) = CSIO_INVALID_IDX;
|
||||
rn = match_rn;
|
||||
|
||||
/* Update rn */
|
||||
goto found_rnode;
|
||||
}
|
||||
csio_rn_flowid(rn) = CSIO_INVALID_IDX;
|
||||
goto alloc_rnode;
|
||||
}
|
||||
|
||||
/* wwpn match */
|
||||
if (!memcmp(csio_rn_wwpn(rn), rdevp->wwpn, 8))
|
||||
goto found_rnode;
|
||||
|
||||
/* Search for rnode that have same wwpn */
|
||||
match_rn = csio_rn_lookup_wwpn(ln, rdevp->wwpn);
|
||||
if (match_rn != NULL) {
|
||||
csio_ln_dbg(ln,
|
||||
"ssni:x%x changed for rport name(wwpn):%llx "
|
||||
"did:x%x\n", rdev_flowid,
|
||||
wwn_to_u64(rdevp->wwpn),
|
||||
match_rn->nport_id);
|
||||
csio_rn_flowid(rn) = CSIO_INVALID_IDX;
|
||||
rn = match_rn;
|
||||
} else {
|
||||
csio_ln_dbg(ln,
|
||||
"rnode wwpn mismatch found ssni:x%x "
|
||||
"name(wwpn):%llx\n",
|
||||
rdev_flowid,
|
||||
wwn_to_u64(csio_rn_wwpn(rn)));
|
||||
if (csio_is_rnode_ready(rn)) {
|
||||
csio_ln_warn(ln,
|
||||
"rnode is already active "
|
||||
"wwpn:%llx ssni:x%x\n",
|
||||
wwn_to_u64(csio_rn_wwpn(rn)),
|
||||
rdev_flowid);
|
||||
CSIO_ASSERT(0);
|
||||
}
|
||||
csio_rn_flowid(rn) = CSIO_INVALID_IDX;
|
||||
goto alloc_rnode;
|
||||
}
|
||||
}
|
||||
|
||||
found_rnode:
|
||||
csio_ln_dbg(ln, "found rnode:%p ssni:x%x name(wwpn):%llx\n",
|
||||
rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
|
||||
|
||||
/* Update flowid */
|
||||
csio_rn_flowid(rn) = rdev_flowid;
|
||||
|
||||
/* update rdev entry */
|
||||
rn->rdev_entry = rdevp;
|
||||
CSIO_INC_STATS(ln, n_rnode_match);
|
||||
return rn;
|
||||
|
||||
alloc_rnode:
|
||||
rn = csio_get_rnode(ln, rdev_flowid);
|
||||
if (!rn)
|
||||
return NULL;
|
||||
|
||||
csio_ln_dbg(ln, "alloc rnode:%p ssni:x%x name(wwpn):%llx\n",
|
||||
rn, rdev_flowid, wwn_to_u64(rdevp->wwpn));
|
||||
|
||||
/* update rdev entry */
|
||||
rn->rdev_entry = rdevp;
|
||||
return rn;
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_rn_verify_rparams - verify rparams.
|
||||
* @ln: lnode
|
||||
* @rn: rnode
|
||||
* @rdevp: remote device params
|
||||
* returns success if rparams are verified.
|
||||
*/
|
||||
static int
|
||||
csio_rn_verify_rparams(struct csio_lnode *ln, struct csio_rnode *rn,
|
||||
struct fcoe_rdev_entry *rdevp)
|
||||
{
|
||||
uint8_t null[8];
|
||||
uint8_t rport_type;
|
||||
uint8_t fc_class;
|
||||
__be32 *did;
|
||||
|
||||
did = (__be32 *) &rdevp->r_id[0];
|
||||
rport_type =
|
||||
FW_RDEV_WR_RPORT_TYPE_GET(rdevp->rd_xfer_rdy_to_rport_type);
|
||||
switch (rport_type) {
|
||||
case FLOGI_VFPORT:
|
||||
rn->role = CSIO_RNFR_FABRIC;
|
||||
if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_FLOGI) {
|
||||
csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
|
||||
csio_rn_flowid(rn));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* NPIV support */
|
||||
if (FW_RDEV_WR_NPIV_GET(rdevp->vft_to_qos))
|
||||
ln->flags |= CSIO_LNF_NPIVSUPP;
|
||||
|
||||
break;
|
||||
|
||||
case NS_VNPORT:
|
||||
rn->role = CSIO_RNFR_NS;
|
||||
if (((ntohl(*did) >> 8) & CSIO_DID_MASK) != FC_FID_DIR_SERV) {
|
||||
csio_ln_err(ln, "ssni:x%x invalid fabric portid\n",
|
||||
csio_rn_flowid(rn));
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case REG_FC4_VNPORT:
|
||||
case REG_VNPORT:
|
||||
rn->role = CSIO_RNFR_NPORT;
|
||||
if (rdevp->event_cause == PRLI_ACC_RCVD ||
|
||||
rdevp->event_cause == PRLI_RCVD) {
|
||||
if (FW_RDEV_WR_TASK_RETRY_ID_GET(
|
||||
rdevp->enh_disc_to_tgt))
|
||||
rn->fcp_flags |= FCP_SPPF_OVLY_ALLOW;
|
||||
|
||||
if (FW_RDEV_WR_RETRY_GET(rdevp->enh_disc_to_tgt))
|
||||
rn->fcp_flags |= FCP_SPPF_RETRY;
|
||||
|
||||
if (FW_RDEV_WR_CONF_CMPL_GET(rdevp->enh_disc_to_tgt))
|
||||
rn->fcp_flags |= FCP_SPPF_CONF_COMPL;
|
||||
|
||||
if (FW_RDEV_WR_TGT_GET(rdevp->enh_disc_to_tgt))
|
||||
rn->role |= CSIO_RNFR_TARGET;
|
||||
|
||||
if (FW_RDEV_WR_INI_GET(rdevp->enh_disc_to_tgt))
|
||||
rn->role |= CSIO_RNFR_INITIATOR;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case FDMI_VNPORT:
|
||||
case FAB_CTLR_VNPORT:
|
||||
rn->role = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
csio_ln_err(ln, "ssni:x%x invalid rport type recv x%x\n",
|
||||
csio_rn_flowid(rn), rport_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* validate wwpn/wwnn for Name server/remote port */
|
||||
if (rport_type == REG_VNPORT || rport_type == NS_VNPORT) {
|
||||
memset(null, 0, 8);
|
||||
if (!memcmp(rdevp->wwnn, null, 8)) {
|
||||
csio_ln_err(ln,
|
||||
"ssni:x%x invalid wwnn received from"
|
||||
" rport did:x%x\n",
|
||||
csio_rn_flowid(rn),
|
||||
(ntohl(*did) & CSIO_DID_MASK));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!memcmp(rdevp->wwpn, null, 8)) {
|
||||
csio_ln_err(ln,
|
||||
"ssni:x%x invalid wwpn received from"
|
||||
" rport did:x%x\n",
|
||||
csio_rn_flowid(rn),
|
||||
(ntohl(*did) & CSIO_DID_MASK));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Copy wwnn, wwpn and nport id */
|
||||
rn->nport_id = (ntohl(*did) >> 8) & CSIO_DID_MASK;
|
||||
memcpy(csio_rn_wwnn(rn), rdevp->wwnn, 8);
|
||||
memcpy(csio_rn_wwpn(rn), rdevp->wwpn, 8);
|
||||
rn->rn_sparm.csp.sp_bb_data = rdevp->rcv_fr_sz;
|
||||
fc_class = FW_RDEV_WR_CLASS_GET(rdevp->vft_to_qos);
|
||||
rn->rn_sparm.clsp[fc_class - 1].cp_class = htons(FC_CPC_VALID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
__csio_reg_rnode(struct csio_rnode *rn)
|
||||
{
|
||||
struct csio_lnode *ln = csio_rnode_to_lnode(rn);
|
||||
struct csio_hw *hw = csio_lnode_to_hw(ln);
|
||||
|
||||
spin_unlock_irq(&hw->lock);
|
||||
csio_reg_rnode(rn);
|
||||
spin_lock_irq(&hw->lock);
|
||||
|
||||
if (rn->role & CSIO_RNFR_TARGET)
|
||||
ln->n_scsi_tgts++;
|
||||
|
||||
if (rn->nport_id == FC_FID_MGMT_SERV)
|
||||
csio_ln_fdmi_start(ln, (void *) rn);
|
||||
}
|
||||
|
||||
static void
|
||||
__csio_unreg_rnode(struct csio_rnode *rn)
|
||||
{
|
||||
struct csio_lnode *ln = csio_rnode_to_lnode(rn);
|
||||
struct csio_hw *hw = csio_lnode_to_hw(ln);
|
||||
LIST_HEAD(tmp_q);
|
||||
int cmpl = 0;
|
||||
|
||||
if (!list_empty(&rn->host_cmpl_q)) {
|
||||
csio_dbg(hw, "Returning completion queue I/Os\n");
|
||||
list_splice_tail_init(&rn->host_cmpl_q, &tmp_q);
|
||||
cmpl = 1;
|
||||
}
|
||||
|
||||
if (rn->role & CSIO_RNFR_TARGET) {
|
||||
ln->n_scsi_tgts--;
|
||||
ln->last_scan_ntgts--;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&hw->lock);
|
||||
csio_unreg_rnode(rn);
|
||||
spin_lock_irq(&hw->lock);
|
||||
|
||||
/* Cleanup I/Os that were waiting for rnode to unregister */
|
||||
if (cmpl)
|
||||
csio_scsi_cleanup_io_q(csio_hw_to_scsim(hw), &tmp_q);
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* START: Rnode SM */
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* csio_rns_uninit -
|
||||
* @rn - rnode
|
||||
* @evt - SM event.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
csio_rns_uninit(struct csio_rnode *rn, enum csio_rn_ev evt)
|
||||
{
|
||||
struct csio_lnode *ln = csio_rnode_to_lnode(rn);
|
||||
int ret = 0;
|
||||
|
||||
CSIO_INC_STATS(rn, n_evt_sm[evt]);
|
||||
|
||||
switch (evt) {
|
||||
case CSIO_RNFE_LOGGED_IN:
|
||||
case CSIO_RNFE_PLOGI_RECV:
|
||||
ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
|
||||
if (!ret) {
|
||||
csio_set_state(&rn->sm, csio_rns_ready);
|
||||
__csio_reg_rnode(rn);
|
||||
} else {
|
||||
CSIO_INC_STATS(rn, n_err_inval);
|
||||
}
|
||||
break;
|
||||
case CSIO_RNFE_LOGO_RECV:
|
||||
csio_ln_dbg(ln,
|
||||
"ssni:x%x Ignoring event %d recv "
|
||||
"in rn state[uninit]\n", csio_rn_flowid(rn), evt);
|
||||
CSIO_INC_STATS(rn, n_evt_drop);
|
||||
break;
|
||||
default:
|
||||
csio_ln_dbg(ln,
|
||||
"ssni:x%x unexp event %d recv "
|
||||
"in rn state[uninit]\n", csio_rn_flowid(rn), evt);
|
||||
CSIO_INC_STATS(rn, n_evt_unexp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_rns_ready -
|
||||
* @rn - rnode
|
||||
* @evt - SM event.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
csio_rns_ready(struct csio_rnode *rn, enum csio_rn_ev evt)
|
||||
{
|
||||
struct csio_lnode *ln = csio_rnode_to_lnode(rn);
|
||||
int ret = 0;
|
||||
|
||||
CSIO_INC_STATS(rn, n_evt_sm[evt]);
|
||||
|
||||
switch (evt) {
|
||||
case CSIO_RNFE_LOGGED_IN:
|
||||
case CSIO_RNFE_PLOGI_RECV:
|
||||
csio_ln_dbg(ln,
|
||||
"ssni:x%x Ignoring event %d recv from did:x%x "
|
||||
"in rn state[ready]\n", csio_rn_flowid(rn), evt,
|
||||
rn->nport_id);
|
||||
CSIO_INC_STATS(rn, n_evt_drop);
|
||||
break;
|
||||
|
||||
case CSIO_RNFE_PRLI_DONE:
|
||||
case CSIO_RNFE_PRLI_RECV:
|
||||
ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
|
||||
if (!ret)
|
||||
__csio_reg_rnode(rn);
|
||||
else
|
||||
CSIO_INC_STATS(rn, n_err_inval);
|
||||
|
||||
break;
|
||||
case CSIO_RNFE_DOWN:
|
||||
csio_set_state(&rn->sm, csio_rns_offline);
|
||||
__csio_unreg_rnode(rn);
|
||||
|
||||
/* FW expected to internally aborted outstanding SCSI WRs
|
||||
* and return all SCSI WRs to host with status "ABORTED".
|
||||
*/
|
||||
break;
|
||||
|
||||
case CSIO_RNFE_LOGO_RECV:
|
||||
csio_set_state(&rn->sm, csio_rns_offline);
|
||||
|
||||
__csio_unreg_rnode(rn);
|
||||
|
||||
/* FW expected to internally aborted outstanding SCSI WRs
|
||||
* and return all SCSI WRs to host with status "ABORTED".
|
||||
*/
|
||||
break;
|
||||
|
||||
case CSIO_RNFE_CLOSE:
|
||||
/*
|
||||
* Each rnode receives CLOSE event when driver is removed or
|
||||
* device is reset
|
||||
* Note: All outstanding IOs on remote port need to returned
|
||||
* to uppper layer with appropriate error before sending
|
||||
* CLOSE event
|
||||
*/
|
||||
csio_set_state(&rn->sm, csio_rns_uninit);
|
||||
__csio_unreg_rnode(rn);
|
||||
break;
|
||||
|
||||
case CSIO_RNFE_NAME_MISSING:
|
||||
csio_set_state(&rn->sm, csio_rns_disappeared);
|
||||
__csio_unreg_rnode(rn);
|
||||
|
||||
/*
|
||||
* FW expected to internally aborted outstanding SCSI WRs
|
||||
* and return all SCSI WRs to host with status "ABORTED".
|
||||
*/
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
csio_ln_dbg(ln,
|
||||
"ssni:x%x unexp event %d recv from did:x%x "
|
||||
"in rn state[uninit]\n", csio_rn_flowid(rn), evt,
|
||||
rn->nport_id);
|
||||
CSIO_INC_STATS(rn, n_evt_unexp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_rns_offline -
|
||||
* @rn - rnode
|
||||
* @evt - SM event.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
csio_rns_offline(struct csio_rnode *rn, enum csio_rn_ev evt)
|
||||
{
|
||||
struct csio_lnode *ln = csio_rnode_to_lnode(rn);
|
||||
int ret = 0;
|
||||
|
||||
CSIO_INC_STATS(rn, n_evt_sm[evt]);
|
||||
|
||||
switch (evt) {
|
||||
case CSIO_RNFE_LOGGED_IN:
|
||||
case CSIO_RNFE_PLOGI_RECV:
|
||||
ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
|
||||
if (!ret) {
|
||||
csio_set_state(&rn->sm, csio_rns_ready);
|
||||
__csio_reg_rnode(rn);
|
||||
} else {
|
||||
CSIO_INC_STATS(rn, n_err_inval);
|
||||
csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case CSIO_RNFE_DOWN:
|
||||
csio_ln_dbg(ln,
|
||||
"ssni:x%x Ignoring event %d recv from did:x%x "
|
||||
"in rn state[offline]\n", csio_rn_flowid(rn), evt,
|
||||
rn->nport_id);
|
||||
CSIO_INC_STATS(rn, n_evt_drop);
|
||||
break;
|
||||
|
||||
case CSIO_RNFE_CLOSE:
|
||||
/* Each rnode receives CLOSE event when driver is removed or
|
||||
* device is reset
|
||||
* Note: All outstanding IOs on remote port need to returned
|
||||
* to uppper layer with appropriate error before sending
|
||||
* CLOSE event
|
||||
*/
|
||||
csio_set_state(&rn->sm, csio_rns_uninit);
|
||||
break;
|
||||
|
||||
case CSIO_RNFE_NAME_MISSING:
|
||||
csio_set_state(&rn->sm, csio_rns_disappeared);
|
||||
break;
|
||||
|
||||
default:
|
||||
csio_ln_dbg(ln,
|
||||
"ssni:x%x unexp event %d recv from did:x%x "
|
||||
"in rn state[offline]\n", csio_rn_flowid(rn), evt,
|
||||
rn->nport_id);
|
||||
CSIO_INC_STATS(rn, n_evt_unexp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_rns_disappeared -
|
||||
* @rn - rnode
|
||||
* @evt - SM event.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
csio_rns_disappeared(struct csio_rnode *rn, enum csio_rn_ev evt)
|
||||
{
|
||||
struct csio_lnode *ln = csio_rnode_to_lnode(rn);
|
||||
int ret = 0;
|
||||
|
||||
CSIO_INC_STATS(rn, n_evt_sm[evt]);
|
||||
|
||||
switch (evt) {
|
||||
case CSIO_RNFE_LOGGED_IN:
|
||||
case CSIO_RNFE_PLOGI_RECV:
|
||||
ret = csio_rn_verify_rparams(ln, rn, rn->rdev_entry);
|
||||
if (!ret) {
|
||||
csio_set_state(&rn->sm, csio_rns_ready);
|
||||
__csio_reg_rnode(rn);
|
||||
} else {
|
||||
CSIO_INC_STATS(rn, n_err_inval);
|
||||
csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case CSIO_RNFE_CLOSE:
|
||||
/* Each rnode receives CLOSE event when driver is removed or
|
||||
* device is reset.
|
||||
* Note: All outstanding IOs on remote port need to returned
|
||||
* to uppper layer with appropriate error before sending
|
||||
* CLOSE event
|
||||
*/
|
||||
csio_set_state(&rn->sm, csio_rns_uninit);
|
||||
break;
|
||||
|
||||
case CSIO_RNFE_DOWN:
|
||||
case CSIO_RNFE_NAME_MISSING:
|
||||
csio_ln_dbg(ln,
|
||||
"ssni:x%x Ignoring event %d recv from did x%x"
|
||||
"in rn state[disappeared]\n", csio_rn_flowid(rn),
|
||||
evt, rn->nport_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
csio_ln_dbg(ln,
|
||||
"ssni:x%x unexp event %d recv from did x%x"
|
||||
"in rn state[disappeared]\n", csio_rn_flowid(rn),
|
||||
evt, rn->nport_id);
|
||||
CSIO_INC_STATS(rn, n_evt_unexp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* END: Rnode SM */
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* csio_rnode_devloss_handler - Device loss event handler
|
||||
* @rn: rnode
|
||||
*
|
||||
* Post event to close rnode SM and free rnode.
|
||||
*/
|
||||
void
|
||||
csio_rnode_devloss_handler(struct csio_rnode *rn)
|
||||
{
|
||||
struct csio_lnode *ln = csio_rnode_to_lnode(rn);
|
||||
|
||||
/* ignore if same rnode came back as online */
|
||||
if (csio_is_rnode_ready(rn))
|
||||
return;
|
||||
|
||||
csio_post_event(&rn->sm, CSIO_RNFE_CLOSE);
|
||||
|
||||
/* Free rn if in uninit state */
|
||||
if (csio_is_rnode_uninit(rn))
|
||||
csio_put_rnode(ln, rn);
|
||||
}
|
||||
|
||||
/**
|
||||
* csio_rnode_fwevt_handler - Event handler for firmware rnode events.
|
||||
* @rn: rnode
|
||||
*
|
||||
*/
|
||||
void
|
||||
csio_rnode_fwevt_handler(struct csio_rnode *rn, uint8_t fwevt)
|
||||
{
|
||||
struct csio_lnode *ln = csio_rnode_to_lnode(rn);
|
||||
enum csio_rn_ev evt;
|
||||
|
||||
evt = CSIO_FWE_TO_RNFE(fwevt);
|
||||
if (!evt) {
|
||||
csio_ln_err(ln, "ssni:x%x Unhandled FW Rdev event: %d\n",
|
||||
csio_rn_flowid(rn), fwevt);
|
||||
CSIO_INC_STATS(rn, n_evt_unexp);
|
||||
return;
|
||||
}
|
||||
CSIO_INC_STATS(rn, n_evt_fw[fwevt]);
|
||||
|
||||
/* Track previous & current events for debugging */
|
||||
rn->prev_evt = rn->cur_evt;
|
||||
rn->cur_evt = fwevt;
|
||||
|
||||
/* Post event to rnode SM */
|
||||
csio_post_event(&rn->sm, evt);
|
||||
|
||||
/* Free rn if in uninit state */
|
||||
if (csio_is_rnode_uninit(rn))
|
||||
csio_put_rnode(ln, rn);
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_rnode_init - Initialize rnode.
|
||||
* @rn: RNode
|
||||
* @ln: Associated lnode
|
||||
*
|
||||
* Caller is responsible for holding the lock. The lock is required
|
||||
* to be held for inserting the rnode in ln->rnhead list.
|
||||
*/
|
||||
static int
|
||||
csio_rnode_init(struct csio_rnode *rn, struct csio_lnode *ln)
|
||||
{
|
||||
csio_rnode_to_lnode(rn) = ln;
|
||||
csio_init_state(&rn->sm, csio_rns_uninit);
|
||||
INIT_LIST_HEAD(&rn->host_cmpl_q);
|
||||
csio_rn_flowid(rn) = CSIO_INVALID_IDX;
|
||||
|
||||
/* Add rnode to list of lnodes->rnhead */
|
||||
list_add_tail(&rn->sm.sm_list, &ln->rnhead);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
csio_rnode_exit(struct csio_rnode *rn)
|
||||
{
|
||||
list_del_init(&rn->sm.sm_list);
|
||||
CSIO_DB_ASSERT(list_empty(&rn->host_cmpl_q));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue