cregit-Linux how code gets into the kernel

Release 4.11 drivers/scsi/libfc/fc_lport.c

/*
 * Copyright(c) 2007 Intel Corporation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Maintained at www.Open-FCoE.org
 */

/*
 * PORT LOCKING NOTES
 *
 * These comments only apply to the 'port code' which consists of the lport,
 * disc and rport blocks.
 *
 * MOTIVATION
 *
 * The lport, disc and rport blocks all have mutexes that are used to protect
 * those objects. The main motivation for these locks is to prevent from
 * having an lport reset just before we send a frame. In that scenario the
 * lport's FID would get set to zero and then we'd send a frame with an
 * invalid SID. We also need to ensure that states don't change unexpectedly
 * while processing another state.
 *
 * HIERARCHY
 *
 * The following hierarchy defines the locking rules. A greater lock
 * may be held before acquiring a lesser lock, but a lesser lock should never
 * be held while attempting to acquire a greater lock. Here is the hierarchy-
 *
 * lport > disc, lport > rport, disc > rport
 *
 * CALLBACKS
 *
 * The callbacks cause complications with this scheme. There is a callback
 * from the rport (to either lport or disc) and a callback from disc
 * (to the lport).
 *
 * As rports exit the rport state machine a callback is made to the owner of
 * the rport to notify success or failure. Since the callback is likely to
 * cause the lport or disc to grab its lock we cannot hold the rport lock
 * while making the callback. To ensure that the rport is not free'd while
 * processing the callback the rport callbacks are serialized through a
 * single-threaded workqueue. An rport would never be free'd while in a
 * callback handler because no other rport work in this queue can be executed
 * at the same time.
 *
 * When discovery succeeds or fails a callback is made to the lport as
 * notification. Currently, successful discovery causes the lport to take no
 * action. A failure will cause the lport to reset. There is likely a circular
 * locking problem with this implementation.
 */

/*
 * LPORT LOCKING
 *
 * The critical sections protected by the lport's mutex are quite broad and
 * may be improved upon in the future. The lport code and its locking doesn't
 * influence the I/O path, so excessive locking doesn't penalize I/O
 * performance.
 *
 * The strategy is to lock whenever processing a request or response. Note
 * that every _enter_* function corresponds to a state change. They generally
 * change the lports state and then send a request out on the wire. We lock
 * before calling any of these functions to protect that state change. This
 * means that the entry points into the lport block manage the locks while
 * the state machine can transition between states (i.e. _enter_* functions)
 * while always staying protected.
 *
 * When handling responses we also hold the lport mutex broadly. When the
 * lport receives the response frame it locks the mutex and then calls the
 * appropriate handler for the particuar response. Generally a response will
 * trigger a state change and so the lock must already be held.
 *
 * Retries also have to consider the locking. The retries occur from a work
 * context and the work function will lock the lport and then retry the state
 * (i.e. _enter_* function).
 */

#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/unaligned.h>

#include <scsi/fc/fc_gs.h>

#include <scsi/libfc.h>
#include <scsi/fc_encode.h>
#include <linux/scatterlist.h>

#include "fc_libfc.h"

/* Fabric IDs to use for point-to-point mode, chosen on whims. */

#define FC_LOCAL_PTP_FID_LO   0x010101

#define FC_LOCAL_PTP_FID_HI   0x010102


#define	DNS_DELAY	      3 
/* Discovery delay after RSCN (in seconds)*/

static void fc_lport_error(struct fc_lport *, struct fc_frame *);

static void fc_lport_enter_reset(struct fc_lport *);
static void fc_lport_enter_flogi(struct fc_lport *);
static void fc_lport_enter_dns(struct fc_lport *);
static void fc_lport_enter_ns(struct fc_lport *, enum fc_lport_state);
static void fc_lport_enter_scr(struct fc_lport *);
static void fc_lport_enter_ready(struct fc_lport *);
static void fc_lport_enter_logo(struct fc_lport *);
static void fc_lport_enter_fdmi(struct fc_lport *lport);
static void fc_lport_enter_ms(struct fc_lport *, enum fc_lport_state);


static const char *fc_lport_state_names[] = {
	[LPORT_ST_DISABLED] = "disabled",
	[LPORT_ST_FLOGI] =    "FLOGI",
	[LPORT_ST_DNS] =      "dNS",
	[LPORT_ST_RNN_ID] =   "RNN_ID",
	[LPORT_ST_RSNN_NN] =  "RSNN_NN",
	[LPORT_ST_RSPN_ID] =  "RSPN_ID",
	[LPORT_ST_RFT_ID] =   "RFT_ID",
	[LPORT_ST_RFF_ID] =   "RFF_ID",
	[LPORT_ST_FDMI] =     "FDMI",
	[LPORT_ST_RHBA] =     "RHBA",
	[LPORT_ST_RPA] =      "RPA",
	[LPORT_ST_DHBA] =     "DHBA",
	[LPORT_ST_DPRT] =     "DPRT",
	[LPORT_ST_SCR] =      "SCR",
	[LPORT_ST_READY] =    "Ready",
	[LPORT_ST_LOGO] =     "LOGO",
	[LPORT_ST_RESET] =    "reset",
};

/**
 * struct fc_bsg_info - FC Passthrough managemet structure
 * @job:      The passthrough job
 * @lport:    The local port to pass through a command
 * @rsp_code: The expected response code
 * @sg:       job->reply_payload.sg_list
 * @nents:    job->reply_payload.sg_cnt
 * @offset:   The offset into the response data
 */

struct fc_bsg_info {
	
struct bsg_job *job;
	
struct fc_lport *lport;
	
u16 rsp_code;
	
struct scatterlist *sg;
	
u32 nents;
	
size_t offset;
};

/**
 * fc_frame_drop() - Dummy frame handler
 * @lport: The local port the frame was received on
 * @fp:    The received frame
 */

static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) { fc_frame_free(fp); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love24100.00%1100.00%
Total24100.00%1100.00%

/** * fc_lport_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event * @rdata: private remote port data * @event: The event that occurred * * Locking Note: The rport lock should not be held when calling * this function. */
static void fc_lport_rport_callback(struct fc_lport *lport, struct fc_rport_priv *rdata, enum fc_rport_event event) { FC_LPORT_DBG(lport, "Received a %d event for port (%6.6x)\n", event, rdata->ids.port_id); mutex_lock(&lport->lp_mutex); switch (event) { case RPORT_EV_READY: if (lport->state == LPORT_ST_DNS) { lport->dns_rdata = rdata; fc_lport_enter_ns(lport, LPORT_ST_RNN_ID); } else if (lport->state == LPORT_ST_FDMI) { lport->ms_rdata = rdata; fc_lport_enter_ms(lport, LPORT_ST_DHBA); } else { FC_LPORT_DBG(lport, "Received an READY event " "on port (%6.6x) for the directory " "server, but the lport is not " "in the DNS or FDMI state, it's in the " "%d state", rdata->ids.port_id, lport->state); fc_rport_logoff(rdata); } break; case RPORT_EV_LOGO: case RPORT_EV_FAILED: case RPORT_EV_STOP: if (rdata->ids.port_id == FC_FID_DIR_SERV) lport->dns_rdata = NULL; else if (rdata->ids.port_id == FC_FID_MGMT_SERV) lport->ms_rdata = NULL; break; case RPORT_EV_NONE: break; } mutex_unlock(&lport->lp_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love10154.89%327.27%
Neerav Parikh5228.26%19.09%
Joe Eykholt2513.59%436.36%
Christopher Leech52.72%218.18%
Hannes Reinecke10.54%19.09%
Total184100.00%11100.00%

/** * fc_lport_state() - Return a string which represents the lport's state * @lport: The lport whose state is to converted to a string */
static const char *fc_lport_state(struct fc_lport *lport) { const char *cp; cp = fc_lport_state_names[lport->state]; if (!cp) cp = "unknown"; return cp; }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love39100.00%1100.00%
Total39100.00%1100.00%

/** * fc_lport_ptp_setup() - Create an rport for point-to-point mode * @lport: The lport to attach the ptp rport to * @remote_fid: The FID of the ptp rport * @remote_wwpn: The WWPN of the ptp rport * @remote_wwnn: The WWNN of the ptp rport * * Locking Note: The lport lock is expected to be held before calling * this routine. */
static void fc_lport_ptp_setup(struct fc_lport *lport, u32 remote_fid, u64 remote_wwpn, u64 remote_wwnn) { if (lport->ptp_rdata) { fc_rport_logoff(lport->ptp_rdata); kref_put(&lport->ptp_rdata->kref, fc_rport_destroy); } mutex_lock(&lport->disc.disc_mutex); lport->ptp_rdata = fc_rport_create(lport, remote_fid); kref_get(&lport->ptp_rdata->kref); lport->ptp_rdata->ids.port_name = remote_wwpn; lport->ptp_rdata->ids.node_name = remote_wwnn; mutex_unlock(&lport->disc.disc_mutex); fc_rport_login(lport->ptp_rdata); fc_lport_enter_ready(lport); }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love7159.17%327.27%
Joe Eykholt4033.33%327.27%
Hannes Reinecke97.50%545.45%
Total120100.00%11100.00%

/** * fc_get_host_port_state() - Return the port state of the given Scsi_Host * @shost: The SCSI host whose port state is to be determined */
void fc_get_host_port_state(struct Scsi_Host *shost) { struct fc_lport *lport = shost_priv(shost); mutex_lock(&lport->lp_mutex); if (!lport->link_up) fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; else switch (lport->state) { case LPORT_ST_READY: fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; break; default: fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; } mutex_unlock(&lport->lp_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love4253.85%250.00%
Christopher Leech3544.87%125.00%
Vasu Dev11.28%125.00%
Total78100.00%4100.00%

EXPORT_SYMBOL(fc_get_host_port_state); /** * fc_get_host_speed() - Return the speed of the given Scsi_Host * @shost: The SCSI host whose port speed is to be determined */
void fc_get_host_speed(struct Scsi_Host *shost) { struct fc_lport *lport = shost_priv(shost); fc_host_speed(shost) = lport->link_speed; }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love29100.00%1100.00%
Total29100.00%1100.00%

EXPORT_SYMBOL(fc_get_host_speed); /** * fc_get_host_stats() - Return the Scsi_Host's statistics * @shost: The SCSI host whose statistics are to be returned */
struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) { struct fc_host_statistics *fc_stats; struct fc_lport *lport = shost_priv(shost); unsigned int cpu; u64 fcp_in_bytes = 0; u64 fcp_out_bytes = 0; fc_stats = &lport->host_stats; memset(fc_stats, 0, sizeof(struct fc_host_statistics)); fc_stats->seconds_since_last_reset = (jiffies - lport->boot_time) / HZ; for_each_possible_cpu(cpu) { struct fc_stats *stats; stats = per_cpu_ptr(lport->stats, cpu); fc_stats->tx_frames += stats->TxFrames; fc_stats->tx_words += stats->TxWords; fc_stats->rx_frames += stats->RxFrames; fc_stats->rx_words += stats->RxWords; fc_stats->error_frames += stats->ErrorFrames; fc_stats->invalid_crc_count += stats->InvalidCRCCount; fc_stats->fcp_input_requests += stats->InputRequests; fc_stats->fcp_output_requests += stats->OutputRequests; fc_stats->fcp_control_requests += stats->ControlRequests; fcp_in_bytes += stats->InputBytes; fcp_out_bytes += stats->OutputBytes; fc_stats->fcp_packet_alloc_failures += stats->FcpPktAllocFails; fc_stats->fcp_packet_aborts += stats->FcpPktAborts; fc_stats->fcp_frame_alloc_failures += stats->FcpFrameAllocFails; fc_stats->link_failure_count += stats->LinkFailureCount; } fc_stats->fcp_input_megabytes = div_u64(fcp_in_bytes, 1000000); fc_stats->fcp_output_megabytes = div_u64(fcp_out_bytes, 1000000); fc_stats->lip_count = -1; fc_stats->nos_count = -1; fc_stats->loss_of_sync_count = -1; fc_stats->loss_of_signal_count = -1; fc_stats->prim_seq_protocol_err_count = -1; fc_stats->dumped_frames = -1; /* update exches stats */ fc_exch_update_stats(lport); return fc_stats; }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love19066.43%337.50%
Vasu Dev5519.23%225.00%
Joe Eykholt3411.89%112.50%
Arnd Bergmann51.75%112.50%
Johannes Thumshirn20.70%112.50%
Total286100.00%8100.00%

EXPORT_SYMBOL(fc_get_host_stats); /** * fc_lport_flogi_fill() - Fill in FLOGI command for request * @lport: The local port the FLOGI is for * @flogi: The FLOGI command * @op: The opcode */
static void fc_lport_flogi_fill(struct fc_lport *lport, struct fc_els_flogi *flogi, unsigned int op) { struct fc_els_csp *sp; struct fc_els_cssp *cp; memset(flogi, 0, sizeof(*flogi)); flogi->fl_cmd = (u8) op; put_unaligned_be64(lport->wwpn, &flogi->fl_wwpn); put_unaligned_be64(lport->wwnn, &flogi->fl_wwnn); sp = &flogi->fl_csp; sp->sp_hi_ver = 0x20; sp->sp_lo_ver = 0x20; sp->sp_bb_cred = htons(10); /* this gets set by gateway */ sp->sp_bb_data = htons((u16) lport->mfs); cp = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */ cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); if (op != ELS_FLOGI) { sp->sp_features = htons(FC_SP_FT_CIRO); sp->sp_tot_seq = htons(255); /* seq. we accept */ sp->sp_rel_off = htons(0x1f); sp->sp_e_d_tov = htonl(lport->e_d_tov); cp->cp_rdfs = htons((u16) lport->mfs); cp->cp_con_seq = htons(255); cp->cp_open_seq = 1; } }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love219100.00%1100.00%
Total219100.00%1100.00%

/** * fc_lport_add_fc4_type() - Add a supported FC-4 type to a local port * @lport: The local port to add a new FC-4 type to * @type: The new FC-4 type */
static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) { __be32 *mp; mp = &lport->fcts.ff_type_map[type / FC_NS_BPW]; *mp = htonl(ntohl(*mp) | 1UL << (type % FC_NS_BPW)); }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love53100.00%1100.00%
Total53100.00%1100.00%

/** * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. * @lport: Fibre Channel local port receiving the RLIR * @fp: The RLIR request frame * * Locking Note: The lport lock is expected to be held before calling * this function. */
static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp) { FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", fc_lport_state(lport)); fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL); fc_frame_free(fp); }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love3890.48%250.00%
Joe Eykholt37.14%125.00%
Hannes Reinecke12.38%125.00%
Total42100.00%4100.00%

/** * fc_lport_recv_echo_req() - Handle received ECHO request * @lport: The local port receiving the ECHO * @fp: ECHO request frame * * Locking Note: The lport lock is expected to be held before calling * this function. */
static void fc_lport_recv_echo_req(struct fc_lport *lport, struct fc_frame *in_fp) { struct fc_frame *fp; unsigned int len; void *pp; void *dp; FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n", fc_lport_state(lport)); len = fr_len(in_fp) - sizeof(struct fc_frame_header); pp = fc_frame_payload_get(in_fp, len); if (len < sizeof(__be32)) len = sizeof(__be32); fp = fc_frame_alloc(lport, len); if (fp) { dp = fc_frame_payload_get(fp, len); memcpy(dp, pp, len); *((__be32 *)dp) = htonl(ELS_LS_ACC << 24); fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); lport->tt.frame_send(lport, fp); } fc_frame_free(in_fp); }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love15194.97%240.00%
Joe Eykholt85.03%360.00%
Total159100.00%5100.00%

/** * fc_lport_recv_rnid_req() - Handle received Request Node ID data request * @lport: The local port receiving the RNID * @fp: The RNID request frame * * Locking Note: The lport lock is expected to be held before calling * this function. */
static void fc_lport_recv_rnid_req(struct fc_lport *lport, struct fc_frame *in_fp) { struct fc_frame *fp; struct fc_els_rnid *req; struct { struct fc_els_rnid_resp rnid; struct fc_els_rnid_cid cid; struct fc_els_rnid_gen gen; } *rp; struct fc_seq_els_data rjt_data; u8 fmt; size_t len; FC_LPORT_DBG(lport, "Received RNID request while in state %s\n", fc_lport_state(lport)); req = fc_frame_payload_get(in_fp, sizeof(*req)); if (!req) { rjt_data.reason = ELS_RJT_LOGIC; rjt_data.explan = ELS_EXPL_NONE; fc_seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data); } else { fmt = req->rnid_fmt; len = sizeof(*rp); if (fmt != ELS_RNIDF_GEN || ntohl(lport->rnid_gen.rnid_atype) == 0) { fmt = ELS_RNIDF_NONE; /* nothing to provide */ len -= sizeof(rp->gen); } fp = fc_frame_alloc(lport, len); if (fp) { rp = fc_frame_payload_get(fp, len); memset(rp, 0, len); rp->rnid.rnid_cmd = ELS_LS_ACC; rp->rnid.rnid_fmt = fmt; rp->rnid.rnid_cid_len = sizeof(rp->cid); rp->cid.rnid_wwpn = htonll(lport->wwpn); rp->cid.rnid_wwnn = htonll(lport->wwnn); if (fmt == ELS_RNIDF_GEN) { rp->rnid.rnid_sid_len = sizeof(rp->gen); memcpy(&rp->gen, &lport->rnid_gen, sizeof(rp->gen)); } fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); lport->tt.frame_send(lport, fp); } } fc_frame_free(in_fp); }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love30697.45%240.00%
Joe Eykholt72.23%240.00%
Hannes Reinecke10.32%120.00%
Total314100.00%5100.00%

/** * fc_lport_recv_logo_req() - Handle received fabric LOGO request * @lport: The local port receiving the LOGO * @fp: The LOGO request frame * * Locking Note: The lport lock is expected to be held before calling * this function. */
static void fc_lport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) { fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL); fc_lport_enter_reset(lport); fc_frame_free(fp); }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love3188.57%133.33%
Joe Eykholt38.57%133.33%
Hannes Reinecke12.86%133.33%
Total35100.00%3100.00%

/** * fc_fabric_login() - Start the lport state machine * @lport: The local port that should log into the fabric * * Locking Note: This function should not be called * with the lport lock held. */
int fc_fabric_login(struct fc_lport *lport) { int rc = -1; mutex_lock(&lport->lp_mutex); if (lport->state == LPORT_ST_DISABLED || lport->state == LPORT_ST_LOGO) { fc_lport_state_enter(lport, LPORT_ST_RESET); fc_lport_enter_reset(lport); rc = 0; } mutex_unlock(&lport->lp_mutex); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love5379.10%133.33%
Vasu Dev1319.40%133.33%
Joe Eykholt11.49%133.33%
Total67100.00%3100.00%

EXPORT_SYMBOL(fc_fabric_login); /** * __fc_linkup() - Handler for transport linkup events * @lport: The lport whose link is up * * Locking: must be called with the lp_mutex held */
void __fc_linkup(struct fc_lport *lport) { if (!lport->link_up) { lport->link_up = 1; if (lport->state == LPORT_ST_RESET) fc_lport_enter_flogi(lport); } }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love3181.58%133.33%
Vasu Dev513.16%133.33%
Christopher Leech25.26%133.33%
Total38100.00%3100.00%

/** * fc_linkup() - Handler for transport linkup events * @lport: The local port whose link is up */
void fc_linkup(struct fc_lport *lport) { printk(KERN_INFO "host%d: libfc: Link up on port (%6.6x)\n", lport->host->host_no, lport->port_id); mutex_lock(&lport->lp_mutex); __fc_linkup(lport); mutex_unlock(&lport->lp_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Leech3165.96%240.00%
Robert Love1021.28%240.00%
Joe Eykholt612.77%120.00%
Total47100.00%5100.00%

EXPORT_SYMBOL(fc_linkup); /** * __fc_linkdown() - Handler for transport linkdown events * @lport: The lport whose link is down * * Locking: must be called with the lp_mutex held */
void __fc_linkdown(struct fc_lport *lport) { if (lport->link_up) { lport->link_up = 0; fc_lport_enter_reset(lport); lport->tt.fcp_cleanup(lport); } }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love3284.21%133.33%
Vasu Dev410.53%133.33%
Christopher Leech25.26%133.33%
Total38100.00%3100.00%

/** * fc_linkdown() - Handler for transport linkdown events * @lport: The local port whose link is down */
void fc_linkdown(struct fc_lport *lport) { printk(KERN_INFO "host%d: libfc: Link down on port (%6.6x)\n", lport->host->host_no, lport->port_id); mutex_lock(&lport->lp_mutex); __fc_linkdown(lport); mutex_unlock(&lport->lp_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Leech3165.96%240.00%
Robert Love1021.28%240.00%
Joe Eykholt612.77%120.00%
Total47100.00%5100.00%

EXPORT_SYMBOL(fc_linkdown); /** * fc_fabric_logoff() - Logout of the fabric * @lport: The local port to logoff the fabric * * Return value: * 0 for success, -1 for failure */
int fc_fabric_logoff(struct fc_lport *lport) { lport->tt.disc_stop_final(lport); mutex_lock(&lport->lp_mutex); if (lport->dns_rdata) fc_rport_logoff(lport->dns_rdata); mutex_unlock(&lport->lp_mutex); fc_rport_flush_queue(); mutex_lock(&lport->lp_mutex); fc_lport_enter_logo(lport); mutex_unlock(&lport->lp_mutex); cancel_delayed_work_sync(&lport->retry_work); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love4554.22%233.33%
Abhijeet Joglekar2833.73%116.67%
Steve Ma89.64%116.67%
Hannes Reinecke22.41%233.33%
Total83100.00%6100.00%

EXPORT_SYMBOL(fc_fabric_logoff); /** * fc_lport_destroy() - Unregister a fc_lport * @lport: The local port to unregister * * Note: * exit routine for fc_lport instance * clean-up all the allocated memory * and free up other system resources. * */
int fc_lport_destroy(struct fc_lport *lport) { mutex_lock(&lport->lp_mutex); lport->state = LPORT_ST_DISABLED; lport->link_up = 0; lport->tt.frame_send = fc_frame_drop; mutex_unlock(&lport->lp_mutex); lport->tt.fcp_abort_io(lport); lport->tt.disc_stop_final(lport); lport->tt.exch_mgr_reset(lport, 0, 0); cancel_delayed_work_sync(&lport->retry_work); fc_fc4_del_lport(lport); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love4346.24%116.67%
Abhijeet Joglekar2729.03%116.67%
Joe Eykholt1516.13%350.00%
Vasu Dev88.60%116.67%
Total93100.00%6100.00%

EXPORT_SYMBOL(fc_lport_destroy); /** * fc_set_mfs() - Set the maximum frame size for a local port * @lport: The local port to set the MFS for * @mfs: The new MFS */
int fc_set_mfs(struct fc_lport *lport, u32 mfs) { unsigned int old_mfs; int rc = -EINVAL; mutex_lock(&lport->lp_mutex); old_mfs = lport->mfs; if (mfs >= FC_MIN_MAX_FRAME) { mfs &= ~3; if (mfs > FC_MAX_FRAME) mfs = FC_MAX_FRAME; mfs -= sizeof(struct fc_frame_header); lport->mfs = mfs; rc = 0; } if (!rc && mfs < old_mfs) fc_lport_enter_reset(lport); mutex_unlock(&lport->lp_mutex); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love103100.00%1100.00%
Total103100.00%1100.00%

EXPORT_SYMBOL(fc_set_mfs); /** * fc_lport_disc_callback() - Callback for discovery events * @lport: The local port receiving the event * @event: The discovery event */
static void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) { switch (event) { case DISC_EV_SUCCESS: FC_LPORT_DBG(lport, "Discovery succeeded\n"); break; case DISC_EV_FAILED: printk(KERN_ERR "host%d: libfc: " "Discovery failed for port (%6.6x)\n", lport->host->host_no, lport->port_id); mutex_lock(&lport->lp_mutex); fc_lport_enter_reset(lport); mutex_unlock(&lport->lp_mutex); break; case DISC_EV_NONE: WARN_ON(1); break; } }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love7489.16%350.00%
Joe Eykholt78.43%116.67%
Christopher Leech11.20%116.67%
Bart Van Assche11.20%116.67%
Total83100.00%6100.00%

/** * fc_rport_enter_ready() - Enter the ready state and start discovery * @lport: The local port that is ready * * Locking Note: The lport lock is expected to be held before calling * this routine. */
static void fc_lport_enter_ready(struct fc_lport *lport) { FC_LPORT_DBG(lport, "Entered READY from state %s\n", fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_READY); if (lport->vport) fc_vport_set_state(lport->vport, FC_VPORT_ACTIVE); fc_vports_linkchange(lport); if (!lport->ptp_rdata) lport->tt.disc_start(fc_lport_disc_callback, lport); }

Contributors

PersonTokensPropCommitsCommitProp
Robert Love4261.76%360.00%
Christopher Leech2029.41%120.00%
Joe Eykholt68.82%120.00%
Total68100.00%5100.00%

/** * fc_lport_set_port_id() - set the local port Port ID * @lport: The local port which will have its Port ID set. * @port_id: The new port ID. * @fp: The frame containing the incoming request, or NULL. * * Locking Note: The lport lock is expected to be held before calling * this function. */
static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id, struct fc_frame *fp) { if (port_id) printk(KERN_INFO "host%d: Assigned Port ID %6.6x\n", lport->host->host_no, port_id); lport->port_id = port_id; /* Update the fc_host */ fc_host_port_id(lport->host) = port_id; if (lport->tt.lport_set_port_id) lport->tt.lport_set_port_id(lport, port_id, fp); }

Contributors

PersonTokensPropCommitsCommitProp
Joe Eykholt6689.19%133.33%
Robert Love79.46%133.33%
Christopher Leech11.35%133.33%
Total74100.00%3100.00%

/** * fc_lport_set_port_id() - set the local port Port ID for point-to-multipoint * @lport: The local port which will have its Port ID set. * @port_id: The new port ID. * * Called by the lower-level driver when transport sets the local port_id. * This is used in VN_port to VN_port mode for FCoE, and causes FLOGI and * discovery to be skipped. */
void fc_lport_set_local_id(struct fc_lport *lport, u32 port_id) { mutex_lock(&lport->lp_mutex); fc_lport_set_port_id(lport, port_id, NULL); switch (lport->state) { case LPORT_ST_RESET: case LPORT_ST_FLOGI: if (port_id) fc_lport_enter_ready(lport); break; default: break; } mutex_unlock(&lport->lp_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
Joe Eykholt64100.00%1100.00%
Total64100.00%1100.00%

EXPORT_SYMBOL(fc_lport_set_local_id); /** * fc_lport_recv_flogi_req() - Receive a FLOGI request * @lport: The local port that received the request * @rx_fp: The FLOGI frame * * A received FLOGI request indicates a point-to-point connection. * Accept it with the common service parameters indicating our N port. * Set up to do a PLOGI if we have the higher-number WWPN. * * Locking Note: The lport lock is expected to be held before calling * this function. */
static void fc_lport_recv_flogi_req(struct fc_lport *lport, struct fc_frame *rx_fp) { struct fc_frame *fp; struct fc_frame_header *fh; struct fc_els_flogi *flp; struct fc_els_flogi *new_flp; u64 remote_wwpn; u32 remote_fid; u32 local_fid; FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", fc_lport_state(lport)); remote_fid = fc_frame_sid(rx_fp); flp = fc_frame_payload_get(rx_fp, sizeof(*flp)); if (!flp) goto out; remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); if (remote_wwpn == lport->wwpn) { printk(KERN_WARNING "host%d: libfc: Received FLOGI from port " "with same WWPN %16.16llx\n", lport->host->host_no, remote_wwpn); goto out; } FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn); /* * XXX what is the right thing to do for FIDs? * The originator might expect our S_ID to be 0xfffffe. * But if so, both of us could end up with the same FID. */ local_fid = FC_LOCAL_PTP_FID_LO; if (remote_wwpn < lport->wwpn) { local_fid = FC_LOCAL_PTP_FID_HI; if (!remote_fid || remote_fid == local_fid) remote_fid = FC_LOCAL_PTP_FID_LO; } else if (!remote_fid) { remote_fid = FC_LOCAL_PTP_FID_HI; } fc_lport_set_port_id(lport, local_fid, rx_fp); fp = fc_frame_alloc(lport, sizeof(*flp)); if (fp) { new_flp = fc_frame_payload_get(fp, sizeof(