linux/drivers/scsi/libfc/fc_rport.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
 *
 * Maintained at www.Open-FCoE.org
 */

/*
 * RPORT GENERAL INFO
 *
 * This file contains all processing regarding fc_rports. It contains the
 * rport state machine and does all rport interaction with the transport class.
 * There should be no other places in libfc that interact directly with the
 * transport class in regards to adding and deleting rports.
 *
 * fc_rport's represent N_Port's within the fabric.
 */

/*
 * RPORT LOCKING
 *
 * The rport should never hold the rport mutex and then attempt to acquire
 * either the lport or disc mutexes. The rport's mutex is considered lesser
 * than both the lport's mutex and the disc mutex. Refer to fc_lport.c for
 * more comments on the hierarchy.
 *
 * The locking strategy is similar to the lport's strategy. The lock protects
 * the rport's states and is held and released by the entry points to the rport
 * block. All _enter_* functions correspond to rport states and expect the rport
 * mutex to be locked before calling them. This means that rports only handle
 * one request or response at a time, since they're not critical for the I/O
 * path this potential over-use of the mutex is acceptable.
 */

/*
 * RPORT REFERENCE COUNTING
 *
 * A rport reference should be taken when:
 * - an rport is allocated
 * - a workqueue item is scheduled
 * - an ELS request is send
 * The reference should be dropped when:
 * - the workqueue function has finished
 * - the ELS response is handled
 * - an rport is removed
 */

#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/export.h>
#include <linux/rculist.h>

#include <linux/unaligned.h>

#include <scsi/libfc.h>

#include "fc_encode.h"
#include "fc_libfc.h"

static struct workqueue_struct *rport_event_queue;

static void fc_rport_enter_flogi(struct fc_rport_priv *);
static void fc_rport_enter_plogi(struct fc_rport_priv *);
static void fc_rport_enter_prli(struct fc_rport_priv *);
static void fc_rport_enter_rtv(struct fc_rport_priv *);
static void fc_rport_enter_ready(struct fc_rport_priv *);
static void fc_rport_enter_logo(struct fc_rport_priv *);
static void fc_rport_enter_adisc(struct fc_rport_priv *);

static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_frame *);
static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_frame *);
static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_frame *);
static void fc_rport_recv_logo_req(struct fc_lport *, struct fc_frame *);
static void fc_rport_timeout(struct work_struct *);
static void fc_rport_error(struct fc_rport_priv *, int);
static void fc_rport_error_retry(struct fc_rport_priv *, int);
static void fc_rport_work(struct work_struct *);

static const char *fc_rport_state_names[] =;

/**
 * fc_rport_lookup() - Lookup a remote port by port_id
 * @lport:   The local port to lookup the remote port on
 * @port_id: The remote port ID to look up
 *
 * The reference count of the fc_rport_priv structure is
 * increased by one.
 */
struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
				      u32 port_id)
{}
EXPORT_SYMBOL();

/**
 * fc_rport_create() - Create a new remote port
 * @lport: The local port this remote port will be associated with
 * @port_id:   The identifiers for the new remote port
 *
 * The remote port will start in the INIT state.
 */
struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, u32 port_id)
{}
EXPORT_SYMBOL();

/**
 * fc_rport_destroy() - Free a remote port after last reference is released
 * @kref: The remote port's kref
 */
void fc_rport_destroy(struct kref *kref)
{}
EXPORT_SYMBOL();

/**
 * fc_rport_state() - Return a string identifying the remote port's state
 * @rdata: The remote port
 */
static const char *fc_rport_state(struct fc_rport_priv *rdata)
{}

/**
 * fc_set_rport_loss_tmo() - Set the remote port loss timeout
 * @rport:   The remote port that gets a new timeout value
 * @timeout: The new timeout value (in seconds)
 */
void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
{}
EXPORT_SYMBOL();

/**
 * fc_plogi_get_maxframe() - Get the maximum payload from the common service
 *			     parameters in a FLOGI frame
 * @flp:    The FLOGI or PLOGI payload
 * @maxval: The maximum frame size upper limit; this may be less than what
 *	    is in the service parameters
 */
static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
					  unsigned int maxval)
{}

/**
 * fc_rport_state_enter() - Change the state of a remote port
 * @rdata: The remote port whose state should change
 * @new:   The new state
 */
static void fc_rport_state_enter(struct fc_rport_priv *rdata,
				 enum fc_rport_state new)
{}

/**
 * fc_rport_work() - Handler for remote port events in the rport_event_queue
 * @work: Handle to the remote port being dequeued
 *
 * Reference counting: drops kref on return
 */
static void fc_rport_work(struct work_struct *work)
{}

/**
 * fc_rport_login() - Start the remote port login state machine
 * @rdata: The remote port to be logged in to
 *
 * Initiates the RP state machine. It is called from the LP module.
 * This function will issue the following commands to the N_Port
 * identified by the FC ID provided.
 *
 * - PLOGI
 * - PRLI
 * - RTV
 *
 * Locking Note: Called without the rport lock held. This
 * function will hold the rport lock, call an _enter_*
 * function and then unlock the rport.
 *
 * This indicates the intent to be logged into the remote port.
 * If it appears we are already logged in, ADISC is used to verify
 * the setup.
 */
int fc_rport_login(struct fc_rport_priv *rdata)
{}
EXPORT_SYMBOL();

/**
 * fc_rport_enter_delete() - Schedule a remote port to be deleted
 * @rdata: The remote port to be deleted
 * @event: The event to report as the reason for deletion
 *
 * Allow state change into DELETE only once.
 *
 * Call queue_work only if there's no event already pending.
 * Set the new event so that the old pending event will not occur.
 * Since we have the mutex, even if fc_rport_work() is already started,
 * it'll see the new event.
 *
 * Reference counting: does not modify kref
 */
static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
				  enum fc_rport_event event)
{}

/**
 * fc_rport_logoff() - Logoff and remove a remote port
 * @rdata: The remote port to be logged off of
 *
 * Locking Note: Called without the rport lock held. This
 * function will hold the rport lock, call an _enter_*
 * function and then unlock the rport.
 */
int fc_rport_logoff(struct fc_rport_priv *rdata)
{}
EXPORT_SYMBOL();

/**
 * fc_rport_enter_ready() - Transition to the RPORT_ST_READY state
 * @rdata: The remote port that is ready
 *
 * Reference counting: schedules workqueue, does not modify kref
 */
static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
{}

/**
 * fc_rport_timeout() - Handler for the retry_work timer
 * @work: Handle to the remote port that has timed out
 *
 * Locking Note: Called without the rport lock held. This
 * function will hold the rport lock, call an _enter_*
 * function and then unlock the rport.
 *
 * Reference counting: Drops kref on return.
 */
static void fc_rport_timeout(struct work_struct *work)
{}

/**
 * fc_rport_error() - Error handler, called once retries have been exhausted
 * @rdata: The remote port the error is happened on
 * @err:   The error code
 *
 * Reference counting: does not modify kref
 */
static void fc_rport_error(struct fc_rport_priv *rdata, int err)
{}

/**
 * fc_rport_error_retry() - Handler for remote port state retries
 * @rdata: The remote port whose state is to be retried
 * @err:   The error code
 *
 * If the error was an exchange timeout retry immediately,
 * otherwise wait for E_D_TOV.
 *
 * Reference counting: increments kref when scheduling retry_work
 */
static void fc_rport_error_retry(struct fc_rport_priv *rdata, int err)
{}

/**
 * fc_rport_login_complete() - Handle parameters and completion of p-mp login.
 * @rdata:  The remote port which we logged into or which logged into us.
 * @fp:     The FLOGI or PLOGI request or response frame
 *
 * Returns non-zero error if a problem is detected with the frame.
 * Does not free the frame.
 *
 * This is only used in point-to-multipoint mode for FIP currently.
 */
static int fc_rport_login_complete(struct fc_rport_priv *rdata,
				   struct fc_frame *fp)
{}

/**
 * fc_rport_flogi_resp() - Handle response to FLOGI request for p-mp mode
 * @sp:	    The sequence that the FLOGI was on
 * @fp:	    The FLOGI response frame
 * @rp_arg: The remote port that received the FLOGI response
 */
static void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
				void *rp_arg)
{}

/**
 * fc_rport_enter_flogi() - Send a FLOGI request to the remote port for p-mp
 * @rdata: The remote port to send a FLOGI to
 *
 * Reference counting: increments kref when sending ELS
 */
static void fc_rport_enter_flogi(struct fc_rport_priv *rdata)
{}

/**
 * fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode
 * @lport: The local port that received the PLOGI request
 * @rx_fp: The PLOGI request frame
 *
 * Reference counting: drops kref on return
 */
static void fc_rport_recv_flogi_req(struct fc_lport *lport,
				    struct fc_frame *rx_fp)
{}

/**
 * fc_rport_plogi_resp() - Handler for ELS PLOGI responses
 * @sp:	       The sequence the PLOGI is on
 * @fp:	       The PLOGI response frame
 * @rdata_arg: The remote port that sent the PLOGI response
 *
 * Locking Note: This function will be called without the rport lock
 * held, but it will lock, call an _enter_* function or fc_rport_error
 * and then unlock the rport.
 */
static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
				void *rdata_arg)
{}

static bool
fc_rport_compatible_roles(struct fc_lport *lport, struct fc_rport_priv *rdata)
{}

/**
 * fc_rport_enter_plogi() - Send Port Login (PLOGI) request
 * @rdata: The remote port to send a PLOGI to
 *
 * Reference counting: increments kref when sending ELS
 */
static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
{}

/**
 * fc_rport_prli_resp() - Process Login (PRLI) response handler
 * @sp:	       The sequence the PRLI response was on
 * @fp:	       The PRLI response frame
 * @rdata_arg: The remote port that sent the PRLI response
 *
 * Locking Note: This function will be called without the rport lock
 * held, but it will lock, call an _enter_* function or fc_rport_error
 * and then unlock the rport.
 */
static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
			       void *rdata_arg)
{}

/**
 * fc_rport_enter_prli() - Send Process Login (PRLI) request
 * @rdata: The remote port to send the PRLI request to
 *
 * Reference counting: increments kref when sending ELS
 */
static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
{}

/**
 * fc_rport_rtv_resp() - Handler for Request Timeout Value (RTV) responses
 * @sp:	       The sequence the RTV was on
 * @fp:	       The RTV response frame
 * @rdata_arg: The remote port that sent the RTV response
 *
 * Many targets don't seem to support this.
 *
 * Locking Note: This function will be called without the rport lock
 * held, but it will lock, call an _enter_* function or fc_rport_error
 * and then unlock the rport.
 */
static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
			      void *rdata_arg)
{}

/**
 * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request
 * @rdata: The remote port to send the RTV request to
 *
 * Reference counting: increments kref when sending ELS
 */
static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
{}

/**
 * fc_rport_recv_rtv_req() - Handler for Read Timeout Value (RTV) requests
 * @rdata: The remote port that sent the RTV request
 * @in_fp: The RTV request frame
 */
static void fc_rport_recv_rtv_req(struct fc_rport_priv *rdata,
				  struct fc_frame *in_fp)
{}

/**
 * fc_rport_logo_resp() - Handler for logout (LOGO) responses
 * @sp:	       The sequence the LOGO was on
 * @fp:	       The LOGO response frame
 * @rdata_arg: The remote port
 */
static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
			       void *rdata_arg)
{}

/**
 * fc_rport_enter_logo() - Send a logout (LOGO) request
 * @rdata: The remote port to send the LOGO request to
 *
 * Reference counting: increments kref when sending ELS
 */
static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
{}

/**
 * fc_rport_adisc_resp() - Handler for Address Discovery (ADISC) responses
 * @sp:	       The sequence the ADISC response was on
 * @fp:	       The ADISC response frame
 * @rdata_arg: The remote port that sent the ADISC response
 *
 * Locking Note: This function will be called without the rport lock
 * held, but it will lock, call an _enter_* function or fc_rport_error
 * and then unlock the rport.
 */
static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp,
				void *rdata_arg)
{}

/**
 * fc_rport_enter_adisc() - Send Address Discover (ADISC) request
 * @rdata: The remote port to send the ADISC request to
 *
 * Reference counting: increments kref when sending ELS
 */
static void fc_rport_enter_adisc(struct fc_rport_priv *rdata)
{}

/**
 * fc_rport_recv_adisc_req() - Handler for Address Discovery (ADISC) requests
 * @rdata: The remote port that sent the ADISC request
 * @in_fp: The ADISC request frame
 */
static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata,
				    struct fc_frame *in_fp)
{}

/**
 * fc_rport_recv_rls_req() - Handle received Read Link Status request
 * @rdata: The remote port that sent the RLS request
 * @rx_fp: The PRLI request frame
 */
static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata,
				  struct fc_frame *rx_fp)

{}

/**
 * fc_rport_recv_els_req() - Handler for validated ELS requests
 * @lport: The local port that received the ELS request
 * @fp:	   The ELS request frame
 *
 * Handle incoming ELS requests that require port login.
 * The ELS opcode has already been validated by the caller.
 *
 * Reference counting: does not modify kref
 */
static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp)
{}

/**
 * fc_rport_recv_req() - Handler for requests
 * @lport: The local port that received the request
 * @fp:	   The request frame
 *
 * Reference counting: does not modify kref
 */
void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
{}
EXPORT_SYMBOL();

/**
 * fc_rport_recv_plogi_req() - Handler for Port Login (PLOGI) requests
 * @lport: The local port that received the PLOGI request
 * @rx_fp: The PLOGI request frame
 *
 * Reference counting: increments kref on return
 */
static void fc_rport_recv_plogi_req(struct fc_lport *lport,
				    struct fc_frame *rx_fp)
{}

/**
 * fc_rport_recv_prli_req() - Handler for process login (PRLI) requests
 * @rdata: The remote port that sent the PRLI request
 * @rx_fp: The PRLI request frame
 */
static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
				   struct fc_frame *rx_fp)
{}

/**
 * fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests
 * @rdata: The remote port that sent the PRLO request
 * @rx_fp: The PRLO request frame
 */
static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
				   struct fc_frame *rx_fp)
{}

/**
 * fc_rport_recv_logo_req() - Handler for logout (LOGO) requests
 * @lport: The local port that received the LOGO request
 * @fp:	   The LOGO request frame
 *
 * Reference counting: drops kref on return
 */
static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
{}

/**
 * fc_rport_flush_queue() - Flush the rport_event_queue
 */
void fc_rport_flush_queue(void)
{}
EXPORT_SYMBOL();

/**
 * fc_rport_fcp_prli() - Handle incoming PRLI for the FCP initiator.
 * @rdata: remote port private
 * @spp_len: service parameter page length
 * @rspp: received service parameter page
 * @spp: response service parameter page
 *
 * Returns the value for the response code to be placed in spp_flags;
 * Returns 0 if not an initiator.
 */
static int fc_rport_fcp_prli(struct fc_rport_priv *rdata, u32 spp_len,
			     const struct fc_els_spp *rspp,
			     struct fc_els_spp *spp)
{}

/*
 * FC-4 provider ops for FCP initiator.
 */
struct fc4_prov fc_rport_fcp_init =;

/**
 * fc_rport_t0_prli() - Handle incoming PRLI parameters for type 0
 * @rdata: remote port private
 * @spp_len: service parameter page length
 * @rspp: received service parameter page
 * @spp: response service parameter page
 */
static int fc_rport_t0_prli(struct fc_rport_priv *rdata, u32 spp_len,
			    const struct fc_els_spp *rspp,
			    struct fc_els_spp *spp)
{}

/*
 * FC-4 provider ops for type 0 service parameters.
 *
 * This handles the special case of type 0 which is always successful
 * but doesn't do anything otherwise.
 */
struct fc4_prov fc_rport_t0_prov =;

/**
 * fc_setup_rport() - Initialize the rport_event_queue
 */
int fc_setup_rport(void)
{}

/**
 * fc_destroy_rport() - Destroy the rport_event_queue
 */
void fc_destroy_rport(void)
{}

/**
 * fc_rport_terminate_io() - Stop all outstanding I/O on a remote port
 * @rport: The remote port whose I/O should be terminated
 */
void fc_rport_terminate_io(struct fc_rport *rport)
{}
EXPORT_SYMBOL();