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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 24 | 100.00% | 1 | 100.00% |
Total | 24 | 100.00% | 1 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 101 | 54.89% | 3 | 27.27% |
Neerav Parikh | 52 | 28.26% | 1 | 9.09% |
Joe Eykholt | 25 | 13.59% | 4 | 36.36% |
Christopher Leech | 5 | 2.72% | 2 | 18.18% |
Hannes Reinecke | 1 | 0.54% | 1 | 9.09% |
Total | 184 | 100.00% | 11 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 39 | 100.00% | 1 | 100.00% |
Total | 39 | 100.00% | 1 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 71 | 59.17% | 3 | 27.27% |
Joe Eykholt | 40 | 33.33% | 3 | 27.27% |
Hannes Reinecke | 9 | 7.50% | 5 | 45.45% |
Total | 120 | 100.00% | 11 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 42 | 53.85% | 2 | 50.00% |
Christopher Leech | 35 | 44.87% | 1 | 25.00% |
Vasu Dev | 1 | 1.28% | 1 | 25.00% |
Total | 78 | 100.00% | 4 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 29 | 100.00% | 1 | 100.00% |
Total | 29 | 100.00% | 1 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 190 | 66.43% | 3 | 37.50% |
Vasu Dev | 55 | 19.23% | 2 | 25.00% |
Joe Eykholt | 34 | 11.89% | 1 | 12.50% |
Arnd Bergmann | 5 | 1.75% | 1 | 12.50% |
Johannes Thumshirn | 2 | 0.70% | 1 | 12.50% |
Total | 286 | 100.00% | 8 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 219 | 100.00% | 1 | 100.00% |
Total | 219 | 100.00% | 1 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 53 | 100.00% | 1 | 100.00% |
Total | 53 | 100.00% | 1 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 38 | 90.48% | 2 | 50.00% |
Joe Eykholt | 3 | 7.14% | 1 | 25.00% |
Hannes Reinecke | 1 | 2.38% | 1 | 25.00% |
Total | 42 | 100.00% | 4 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 151 | 94.97% | 2 | 40.00% |
Joe Eykholt | 8 | 5.03% | 3 | 60.00% |
Total | 159 | 100.00% | 5 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 306 | 97.45% | 2 | 40.00% |
Joe Eykholt | 7 | 2.23% | 2 | 40.00% |
Hannes Reinecke | 1 | 0.32% | 1 | 20.00% |
Total | 314 | 100.00% | 5 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 31 | 88.57% | 1 | 33.33% |
Joe Eykholt | 3 | 8.57% | 1 | 33.33% |
Hannes Reinecke | 1 | 2.86% | 1 | 33.33% |
Total | 35 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 53 | 79.10% | 1 | 33.33% |
Vasu Dev | 13 | 19.40% | 1 | 33.33% |
Joe Eykholt | 1 | 1.49% | 1 | 33.33% |
Total | 67 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 31 | 81.58% | 1 | 33.33% |
Vasu Dev | 5 | 13.16% | 1 | 33.33% |
Christopher Leech | 2 | 5.26% | 1 | 33.33% |
Total | 38 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Christopher Leech | 31 | 65.96% | 2 | 40.00% |
Robert Love | 10 | 21.28% | 2 | 40.00% |
Joe Eykholt | 6 | 12.77% | 1 | 20.00% |
Total | 47 | 100.00% | 5 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 32 | 84.21% | 1 | 33.33% |
Vasu Dev | 4 | 10.53% | 1 | 33.33% |
Christopher Leech | 2 | 5.26% | 1 | 33.33% |
Total | 38 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Christopher Leech | 31 | 65.96% | 2 | 40.00% |
Robert Love | 10 | 21.28% | 2 | 40.00% |
Joe Eykholt | 6 | 12.77% | 1 | 20.00% |
Total | 47 | 100.00% | 5 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 45 | 54.22% | 2 | 33.33% |
Abhijeet Joglekar | 28 | 33.73% | 1 | 16.67% |
Steve Ma | 8 | 9.64% | 1 | 16.67% |
Hannes Reinecke | 2 | 2.41% | 2 | 33.33% |
Total | 83 | 100.00% | 6 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 43 | 46.24% | 1 | 16.67% |
Abhijeet Joglekar | 27 | 29.03% | 1 | 16.67% |
Joe Eykholt | 15 | 16.13% | 3 | 50.00% |
Vasu Dev | 8 | 8.60% | 1 | 16.67% |
Total | 93 | 100.00% | 6 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 103 | 100.00% | 1 | 100.00% |
Total | 103 | 100.00% | 1 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 74 | 89.16% | 3 | 50.00% |
Joe Eykholt | 7 | 8.43% | 1 | 16.67% |
Christopher Leech | 1 | 1.20% | 1 | 16.67% |
Bart Van Assche | 1 | 1.20% | 1 | 16.67% |
Total | 83 | 100.00% | 6 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 42 | 61.76% | 3 | 60.00% |
Christopher Leech | 20 | 29.41% | 1 | 20.00% |
Joe Eykholt | 6 | 8.82% | 1 | 20.00% |
Total | 68 | 100.00% | 5 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Joe Eykholt | 66 | 89.19% | 1 | 33.33% |
Robert Love | 7 | 9.46% | 1 | 33.33% |
Christopher Leech | 1 | 1.35% | 1 | 33.33% |
Total | 74 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Joe Eykholt | 64 | 100.00% | 1 | 100.00% |
Total | 64 | 100.00% | 1 | 100.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(