// 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(…);