linux/drivers/scsi/libfc/fc_fcp.c

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

#include <linux/module.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/scatterlist.h>
#include <linux/err.h>
#include <linux/crc32.h>
#include <linux/slab.h>

#include <scsi/scsi_tcq.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>

#include <scsi/fc/fc_fc2.h>

#include <scsi/libfc.h>

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

static struct kmem_cache *scsi_pkt_cachep;

/* SRB state definitions */
#define FC_SRB_FREE
#define FC_SRB_CMD_SENT
#define FC_SRB_RCV_STATUS
#define FC_SRB_ABORT_PENDING
#define FC_SRB_ABORTED
#define FC_SRB_DISCONTIG
#define FC_SRB_COMPL
#define FC_SRB_FCP_PROCESSING_TMO

#define FC_SRB_READ
#define FC_SRB_WRITE

static struct libfc_cmd_priv *libfc_priv(struct scsi_cmnd *cmd)
{}

/**
 * struct fc_fcp_internal - FCP layer internal data
 * @scsi_pkt_pool: Memory pool to draw FCP packets from
 * @scsi_queue_lock: Protects the scsi_pkt_queue
 * @scsi_pkt_queue: Current FCP packets
 * @last_can_queue_ramp_down_time: ramp down time
 * @last_can_queue_ramp_up_time: ramp up time
 * @max_can_queue: max can_queue size
 */
struct fc_fcp_internal {};

#define fc_get_scsi_internal(x)

/*
 * function prototypes
 * FC scsi I/O related functions
 */
static void fc_fcp_recv_data(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_fcp_recv(struct fc_seq *, struct fc_frame *, void *);
static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_fcp_complete_locked(struct fc_fcp_pkt *);
static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);
static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_fcp_recovery(struct fc_fcp_pkt *, u8 code);
static void fc_fcp_timeout(struct timer_list *);
static void fc_fcp_rec(struct fc_fcp_pkt *);
static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *);
static void fc_fcp_rec_resp(struct fc_seq *, struct fc_frame *, void *);
static void fc_io_compl(struct fc_fcp_pkt *);

static void fc_fcp_srr(struct fc_fcp_pkt *, enum fc_rctl, u32);
static void fc_fcp_srr_resp(struct fc_seq *, struct fc_frame *, void *);
static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *);

/*
 * command status codes
 */
#define FC_COMPLETE
#define FC_CMD_ABORTED
#define FC_CMD_RESET
#define FC_CMD_PLOGO
#define FC_SNS_RCV
#define FC_TRANS_ERR
#define FC_DATA_OVRRUN
#define FC_DATA_UNDRUN
#define FC_ERROR
#define FC_HRD_ERROR
#define FC_CRC_ERROR
#define FC_TIMED_OUT
#define FC_TRANS_RESET

/*
 * Error recovery timeout values.
 */
#define FC_SCSI_TM_TOV
#define FC_HOST_RESET_TIMEOUT
#define FC_CAN_QUEUE_PERIOD

#define FC_MAX_ERROR_CNT
#define FC_MAX_RECOV_RETRY

#define FC_FCP_DFLT_QUEUE_DEPTH

/**
 * fc_fcp_pkt_alloc() - Allocate a fcp_pkt
 * @lport: The local port that the FCP packet is for
 * @gfp:   GFP flags for allocation
 *
 * Return value: fcp_pkt structure or null on allocation failure.
 * Context:	 Can be called from process context, no lock is required.
 */
static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp)
{}

/**
 * fc_fcp_pkt_release() - Release hold on a fcp_pkt
 * @fsp: The FCP packet to be released
 *
 * Context: Can be called from process or interrupt context,
 *	    no lock is required.
 */
static void fc_fcp_pkt_release(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_pkt_hold() - Hold a fcp_pkt
 * @fsp: The FCP packet to be held
 */
static void fc_fcp_pkt_hold(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_pkt_destroy() - Release hold on a fcp_pkt
 * @seq: The sequence that the FCP packet is on (required by destructor API)
 * @fsp: The FCP packet to be released
 *
 * This routine is called by a destructor callback in the fc_exch_seq_send()
 * routine of the libfc Transport Template. The 'struct fc_seq' is a required
 * argument even though it is not used by this routine.
 *
 * Context: No locking required.
 */
static void fc_fcp_pkt_destroy(struct fc_seq *seq, void *fsp)
{}

/**
 * fc_fcp_lock_pkt() - Lock a fcp_pkt and increase its reference count
 * @fsp: The FCP packet to be locked and incremented
 *
 * We should only return error if we return a command to SCSI-ml before
 * getting a response. This can happen in cases where we send a abort, but
 * do not wait for the response and the abort and command can be passing
 * each other on the wire/network-layer.
 *
 * Note: this function locks the packet and gets a reference to allow
 * callers to call the completion function while the lock is held and
 * not have to worry about the packets refcount.
 *
 * TODO: Maybe we should just have callers grab/release the lock and
 * have a function that they call to verify the fsp and grab a ref if
 * needed.
 */
static inline int fc_fcp_lock_pkt(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_unlock_pkt() - Release a fcp_pkt's lock and decrement its
 *			 reference count
 * @fsp: The FCP packet to be unlocked and decremented
 */
static inline void fc_fcp_unlock_pkt(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_timer_set() - Start a timer for a fcp_pkt
 * @fsp:   The FCP packet to start a timer for
 * @delay: The timeout period in jiffies
 */
static void fc_fcp_timer_set(struct fc_fcp_pkt *fsp, unsigned long delay)
{}

static void fc_fcp_abort_done(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_send_abort() - Send an abort for exchanges associated with a
 *			 fcp_pkt
 * @fsp: The FCP packet to abort exchanges on
 */
static int fc_fcp_send_abort(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_retry_cmd() - Retry a fcp_pkt
 * @fsp: The FCP packet to be retried
 * @status_code: The FCP status code to set
 *
 * Sets the status code to be FC_ERROR and then calls
 * fc_fcp_complete_locked() which in turn calls fc_io_compl().
 * fc_io_compl() will notify the SCSI-ml that the I/O is done.
 * The SCSI-ml will retry the command.
 */
static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp, int status_code)
{}

/**
 * fc_fcp_ddp_setup() - Calls a LLD's ddp_setup routine to set up DDP context
 * @fsp: The FCP packet that will manage the DDP frames
 * @xid: The XID that will be used for the DDP exchange
 */
void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid)
{}

/**
 * fc_fcp_ddp_done() - Calls a LLD's ddp_done routine to release any
 *		       DDP related resources for a fcp_pkt
 * @fsp: The FCP packet that DDP had been used on
 */
void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_can_queue_ramp_up() - increases can_queue
 * @lport: lport to ramp up can_queue
 */
static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport)
{}

/**
 * fc_fcp_can_queue_ramp_down() - reduces can_queue
 * @lport: lport to reduce can_queue
 *
 * If we are getting memory allocation failures, then we may
 * be trying to execute too many commands. We let the running
 * commands complete or timeout, then try again with a reduced
 * can_queue. Eventually we will hit the point where we run
 * on all reserved structs.
 */
static bool fc_fcp_can_queue_ramp_down(struct fc_lport *lport)
{}

/*
 * fc_fcp_frame_alloc() -  Allocates fc_frame structure and buffer.
 * @lport:	fc lport struct
 * @len:	payload length
 *
 * Allocates fc_frame structure and buffer but if fails to allocate
 * then reduce can_queue.
 */
static inline struct fc_frame *fc_fcp_frame_alloc(struct fc_lport *lport,
						  size_t len)
{}

/**
 * get_fsp_rec_tov() - Helper function to get REC_TOV
 * @fsp: the FCP packet
 *
 * Returns rec tov in jiffies as rpriv->e_d_tov + 1 second
 */
static inline unsigned int get_fsp_rec_tov(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_recv_data() - Handler for receiving SCSI-FCP data from a target
 * @fsp: The FCP packet the data is on
 * @fp:	 The data frame
 */
static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{}

/**
 * fc_fcp_send_data() - Send SCSI data to a target
 * @fsp:      The FCP packet the data is on
 * @seq:      The sequence the data is to be sent on
 * @offset:   The starting offset for this data request
 * @seq_blen: The burst length for this data request
 *
 * Called after receiving a Transfer Ready data descriptor.
 * If the LLD is capable of sequence offload then send down the
 * seq_blen amount of data in single frame, otherwise send
 * multiple frames of the maximum frame payload supported by
 * the target port.
 */
static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
			    size_t offset, size_t seq_blen)
{}

/**
 * fc_fcp_abts_resp() - Receive an ABTS response
 * @fsp: The FCP packet that is being aborted
 * @fp:	 The response frame
 */
static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{}

/**
 * fc_fcp_recv() - Receive an FCP frame
 * @seq: The sequence the frame is on
 * @fp:	 The received frame
 * @arg: The related FCP packet
 *
 * Context: Called from Soft IRQ context. Can not be called
 *	    holding the FCP packet list lock.
 */
static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{}

/**
 * fc_fcp_resp() - Handler for FCP responses
 * @fsp: The FCP packet the response is for
 * @fp:	 The response frame
 */
static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{}

/**
 * fc_fcp_complete_locked() - Complete processing of a fcp_pkt with the
 *			      fcp_pkt lock held
 * @fsp: The FCP packet to be completed
 *
 * This function may sleep if a timer is pending. The packet lock must be
 * held, and the host lock must not be held.
 */
static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_cleanup_cmd() - Cancel the active exchange on a fcp_pkt
 * @fsp:   The FCP packet whose exchanges should be canceled
 * @error: The reason for the cancellation
 */
static void fc_fcp_cleanup_cmd(struct fc_fcp_pkt *fsp, int error)
{}

/**
 * fc_fcp_cleanup_each_cmd() - Cancel all exchanges on a local port
 * @lport: The local port whose exchanges should be canceled
 * @id:	   The target's ID
 * @lun:   The LUN
 * @error: The reason for cancellation
 *
 * If lun or id is -1, they are ignored.
 */
static void fc_fcp_cleanup_each_cmd(struct fc_lport *lport, unsigned int id,
				    unsigned int lun, int error)
{}

/**
 * fc_fcp_abort_io() - Abort all FCP-SCSI exchanges on a local port
 * @lport: The local port whose exchanges are to be aborted
 */
static void fc_fcp_abort_io(struct fc_lport *lport)
{}

/**
 * fc_fcp_pkt_send() - Send a fcp_pkt
 * @lport: The local port to send the FCP packet on
 * @fsp:   The FCP packet to send
 *
 * Return:  Zero for success and -1 for failure
 * Locks:   Called without locks held
 */
static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_cmd_send() - Send a FCP command
 * @lport: The local port to send the command on
 * @fsp:   The FCP packet the command is on
 * @resp:  The handler for the response
 */
static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
			   void (*resp)(struct fc_seq *,
					struct fc_frame *fp,
					void *arg))
{}

/**
 * fc_fcp_error() - Handler for FCP layer errors
 * @fsp: The FCP packet the error is on
 * @fp:	 The frame that has errored
 */
static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{}

/**
 * fc_fcp_pkt_abort() - Abort a fcp_pkt
 * @fsp:   The FCP packet to abort on
 *
 * Called to send an abort and then wait for abort completion
 */
static int fc_fcp_pkt_abort(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_lun_reset_send() - Send LUN reset command
 * @t: Timer context used to fetch the FSP packet
 */
static void fc_lun_reset_send(struct timer_list *t)
{}

/**
 * fc_lun_reset() - Send a LUN RESET command to a device
 *		    and wait for the reply
 * @lport: The local port to sent the command on
 * @fsp:   The FCP packet that identifies the LUN to be reset
 * @id:	   The SCSI command ID
 * @lun:   The LUN ID to be reset
 */
static int fc_lun_reset(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
			unsigned int id, unsigned int lun)
{}

/**
 * fc_tm_done() - Task Management response handler
 * @seq: The sequence that the response is on
 * @fp:	 The response frame
 * @arg: The FCP packet the response is for
 */
static void fc_tm_done(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{}

/**
 * fc_fcp_cleanup() - Cleanup all FCP exchanges on a local port
 * @lport: The local port to be cleaned up
 */
static void fc_fcp_cleanup(struct fc_lport *lport)
{}

/**
 * fc_fcp_timeout() - Handler for fcp_pkt timeouts
 * @t: Timer context used to fetch the FSP packet
 *
 * If REC is supported then just issue it and return. The REC exchange will
 * complete or time out and recovery can continue at that point. Otherwise,
 * if the response has been received without all the data it has been
 * ER_TIMEOUT since the response was received. If the response has not been
 * received we see if data was received recently. If it has been then we
 * continue waiting, otherwise, we abort the command.
 */
static void fc_fcp_timeout(struct timer_list *t)
{}

/**
 * fc_fcp_rec() - Send a REC ELS request
 * @fsp: The FCP packet to send the REC request on
 */
static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_fcp_rec_resp() - Handler for REC ELS responses
 * @seq: The sequence the response is on
 * @fp:	 The response frame
 * @arg: The FCP packet the response is on
 *
 * If the response is a reject then the scsi layer will handle
 * the timeout. If the response is a LS_ACC then if the I/O was not completed
 * set the timeout and return. If the I/O was completed then complete the
 * exchange and tell the SCSI layer.
 */
static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{}

/**
 * fc_fcp_rec_error() - Handler for REC errors
 * @fsp: The FCP packet the error is on
 * @fp:	 The REC frame
 */
static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{}

/**
 * fc_fcp_recovery() - Handler for fcp_pkt recovery
 * @fsp: The FCP pkt that needs to be aborted
 * @code: The FCP status code to set
 */
static void fc_fcp_recovery(struct fc_fcp_pkt *fsp, u8 code)
{}

/**
 * fc_fcp_srr() - Send a SRR request (Sequence Retransmission Request)
 * @fsp:   The FCP packet the SRR is to be sent on
 * @r_ctl: The R_CTL field for the SRR request
 * @offset: The SRR relative offset
 * This is called after receiving status but insufficient data, or
 * when expecting status but the request has timed out.
 */
static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
{}

/**
 * fc_fcp_srr_resp() - Handler for SRR response
 * @seq: The sequence the SRR is on
 * @fp:	 The SRR frame
 * @arg: The FCP packet the SRR is on
 */
static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{}

/**
 * fc_fcp_srr_error() - Handler for SRR errors
 * @fsp: The FCP packet that the SRR error is on
 * @fp:	 The SRR frame
 */
static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{}

/**
 * fc_fcp_lport_queue_ready() - Determine if the lport and it's queue is ready
 * @lport: The local port to be checked
 */
static inline int fc_fcp_lport_queue_ready(struct fc_lport *lport)
{}

/**
 * fc_queuecommand() - The queuecommand function of the SCSI template
 * @shost: The Scsi_Host that the command was issued to
 * @sc_cmd:   The scsi_cmnd to be executed
 *
 * This is the i/o strategy routine, called by the SCSI layer.
 */
int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd)
{}
EXPORT_SYMBOL();

/**
 * fc_io_compl() - Handle responses for completed commands
 * @fsp: The FCP packet that is complete
 *
 * Translates fcp_pkt errors to a Linux SCSI errors.
 * The fcp packet lock must be held when calling.
 */
static void fc_io_compl(struct fc_fcp_pkt *fsp)
{}

/**
 * fc_eh_abort() - Abort a command
 * @sc_cmd: The SCSI command to abort
 *
 * From SCSI host template.
 * Send an ABTS to the target device and wait for the response.
 */
int fc_eh_abort(struct scsi_cmnd *sc_cmd)
{}
EXPORT_SYMBOL();

/**
 * fc_eh_device_reset() - Reset a single LUN
 * @sc_cmd: The SCSI command which identifies the device whose
 *	    LUN is to be reset
 *
 * Set from SCSI host template.
 */
int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
{}
EXPORT_SYMBOL();

/**
 * fc_eh_host_reset() - Reset a Scsi_Host.
 * @sc_cmd: The SCSI command that identifies the SCSI host to be reset
 */
int fc_eh_host_reset(struct scsi_cmnd *sc_cmd)
{}
EXPORT_SYMBOL();

/**
 * fc_slave_alloc() - Configure the queue depth of a Scsi_Host
 * @sdev: The SCSI device that identifies the SCSI host
 *
 * Configures queue depth based on host's cmd_per_len. If not set
 * then we use the libfc default.
 */
int fc_slave_alloc(struct scsi_device *sdev)
{}
EXPORT_SYMBOL();

/**
 * fc_fcp_destroy() - Tear down the FCP layer for a given local port
 * @lport: The local port that no longer needs the FCP layer
 */
void fc_fcp_destroy(struct fc_lport *lport)
{}
EXPORT_SYMBOL();

int fc_setup_fcp(void)
{}

void fc_destroy_fcp(void)
{}

/**
 * fc_fcp_init() - Initialize the FCP layer for a local port
 * @lport: The local port to initialize the exchange layer for
 */
int fc_fcp_init(struct fc_lport *lport)
{}
EXPORT_SYMBOL();