/* * 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.
*/
/* * 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.
*/ staticstruct 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;
/** * 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;
/* * 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.
*/ staticstruct 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;
/* 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;
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".
*/
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;
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);
}
/* 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.
*/ staticint
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);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.