/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of version 2 of the GNU General * * Public License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful. * * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * * TO BE LEGALLY INVALID. See the GNU General Public License for * * more details, a copy of which can be found in the file COPYING * * included with this package. * *******************************************************************/ #include <linux/pci.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/export.h> #include <linux/delay.h> #include <asm/unaligned.h> #include <linux/t10-pi.h> #include <linux/crc-t10dif.h> #include <linux/blk-cgroup.h> #include <net/checksum.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_transport_fc.h> #include "lpfc_version.h" #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc.h" #include "lpfc_scsi.h" #include "lpfc_logmsg.h" #include "lpfc_crtn.h" #include "lpfc_vport.h" #define LPFC_RESET_WAIT … #define LPFC_ABORT_WAIT … static char *dif_op_str[] = …; struct scsi_dif_tuple { … }; static struct lpfc_rport_data * lpfc_rport_data_from_scsi_device(struct scsi_device *sdev) { … } static void lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb); static void lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb); static int lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc); /** * lpfc_sli4_set_rsp_sgl_last - Set the last bit in the response sge. * @phba: Pointer to HBA object. * @lpfc_cmd: lpfc scsi command object pointer. * * This function is called from the lpfc_prep_task_mgmt_cmd function to * set the last bit in the response sge entry. **/ static void lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) { … } /** * lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread * @phba: The Hba for which this call is being executed. * * This routine is called when there is resource error in driver or firmware. * This routine posts WORKER_RAMP_DOWN_QUEUE event for @phba. This routine * posts at most 1 event each second. This routine wakes up worker thread of * @phba to process WORKER_RAM_DOWN_EVENT event. * * This routine should be called with no lock held. **/ void lpfc_rampdown_queue_depth(struct lpfc_hba *phba) { … } /** * lpfc_ramp_down_queue_handler - WORKER_RAMP_DOWN_QUEUE event handler * @phba: The Hba for which this call is being executed. * * This routine is called to process WORKER_RAMP_DOWN_QUEUE event for worker * thread.This routine reduces queue depth for all scsi device on each vport * associated with @phba. **/ void lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) { … } /** * lpfc_scsi_dev_block - set all scsi hosts to block state * @phba: Pointer to HBA context object. * * This function walks vport list and set each SCSI host to block state * by invoking fc_remote_port_delete() routine. This function is invoked * with EEH when device's PCI slot has been permanently disabled. **/ void lpfc_scsi_dev_block(struct lpfc_hba *phba) { … } /** * lpfc_new_scsi_buf_s3 - Scsi buffer allocator for HBA with SLI3 IF spec * @vport: The virtual port for which this call being executed. * @num_to_alloc: The requested number of buffers to allocate. * * This routine allocates a scsi buffer for device with SLI-3 interface spec, * the scsi buffer contains all the necessary information needed to initiate * a SCSI I/O. The non-DMAable buffer region contains information to build * the IOCB. The DMAable region contains memory for the FCP CMND, FCP RSP, * and the initial BPL. In addition to allocating memory, the FCP CMND and * FCP RSP BDEs are setup in the BPL and the BPL BDE is setup in the IOCB. * * Return codes: * int - number of scsi buffers that were allocated. * 0 = failure, less than num_to_alloc is a partial failure. **/ static int lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) { … } /** * lpfc_sli4_vport_delete_fcp_xri_aborted -Remove all ndlp references for vport * @vport: pointer to lpfc vport data structure. * * This routine is invoked by the vport cleanup for deletions and the cleanup * for an ndlp on removal. **/ void lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport) { … } /** * lpfc_sli4_io_xri_aborted - Fast-path process of fcp xri abort * @phba: pointer to lpfc hba data structure. * @axri: pointer to the fcp xri abort wcqe structure. * @idx: index into hdwq * * This routine is invoked by the worker thread to process a SLI4 fast-path * FCP or NVME aborted xri. **/ void lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri, int idx) { … } /** * lpfc_get_scsi_buf_s3 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA * @phba: The HBA for which this call is being executed. * @ndlp: pointer to a node-list data structure. * @cmnd: Pointer to scsi_cmnd data structure. * * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list * and returns to caller. * * Return codes: * NULL - Error * Pointer to lpfc_scsi_buf - Success **/ static struct lpfc_io_buf * lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct scsi_cmnd *cmnd) { … } /** * lpfc_get_scsi_buf_s4 - Get a scsi buffer from io_buf_list of the HBA * @phba: The HBA for which this call is being executed. * @ndlp: pointer to a node-list data structure. * @cmnd: Pointer to scsi_cmnd data structure. * * This routine removes a scsi buffer from head of @hdwq io_buf_list * and returns to caller. * * Return codes: * NULL - Error * Pointer to lpfc_scsi_buf - Success **/ static struct lpfc_io_buf * lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct scsi_cmnd *cmnd) { … } /** * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA * @phba: The HBA for which this call is being executed. * @ndlp: pointer to a node-list data structure. * @cmnd: Pointer to scsi_cmnd data structure. * * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list * and returns to caller. * * Return codes: * NULL - Error * Pointer to lpfc_scsi_buf - Success **/ static struct lpfc_io_buf* lpfc_get_scsi_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct scsi_cmnd *cmnd) { … } /** * lpfc_release_scsi_buf_s3 - Return a scsi buffer back to hba scsi buf list * @phba: The Hba for which this call is being executed. * @psb: The scsi buffer which is being released. * * This routine releases @psb scsi buffer by adding it to tail of @phba * lpfc_scsi_buf_list list. **/ static void lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb) { … } /** * lpfc_release_scsi_buf_s4: Return a scsi buffer back to hba scsi buf list. * @phba: The Hba for which this call is being executed. * @psb: The scsi buffer which is being released. * * This routine releases @psb scsi buffer by adding it to tail of @hdwq * io_buf_list list. For SLI4 XRI's are tied to the scsi buffer * and cannot be reused for at least RA_TOV amount of time if it was * aborted. **/ static void lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb) { … } /** * lpfc_release_scsi_buf: Return a scsi buffer back to hba scsi buf list. * @phba: The Hba for which this call is being executed. * @psb: The scsi buffer which is being released. * * This routine releases @psb scsi buffer by adding it to tail of @phba * lpfc_scsi_buf_list list. **/ static void lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_io_buf *psb) { … } /** * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB * @data: A pointer to the immediate command data portion of the IOCB. * @fcp_cmnd: The FCP Command that is provided by the SCSI layer. * * The routine copies the entire FCP command from @fcp_cmnd to @data while * byte swapping the data to big endian format for transmission on the wire. **/ static void lpfc_fcpcmd_to_iocb(u8 *data, struct fcp_cmnd *fcp_cmnd) { … } /** * lpfc_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be mapped. * * This routine does the pci dma mapping for scatter-gather list of scsi cmnd * field of @lpfc_cmd for device with SLI-3 interface spec. This routine scans * through sg elements and format the bde. This routine also initializes all * IOCB fields which are dependent on scsi command request buffer. * * Return codes: * 1 - Error * 0 - Success **/ static int lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) { … } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS /* Return BG_ERR_INIT if error injection is detected by Initiator */ #define BG_ERR_INIT … /* Return BG_ERR_TGT if error injection is detected by Target */ #define BG_ERR_TGT … /* Return BG_ERR_SWAP if swapping CSUM<-->CRC is required for error injection */ #define BG_ERR_SWAP … /* * Return BG_ERR_CHECK if disabling Guard/Ref/App checking is required for * error injection */ #define BG_ERR_CHECK … /** * lpfc_bg_err_inject - Determine if we should inject an error * @phba: The Hba for which this call is being executed. * @sc: The SCSI command to examine * @reftag: (out) BlockGuard reference tag for transmitted data * @apptag: (out) BlockGuard application tag for transmitted data * @new_guard: (in) Value to replace CRC with if needed * * Returns BG_ERR_* bit mask or 0 if request ignored **/ static int lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t *reftag, uint16_t *apptag, uint32_t new_guard) { … } #endif /** * lpfc_sc_to_bg_opcodes - Determine the BlockGuard opcodes to be used with * the specified SCSI command. * @phba: The Hba for which this call is being executed. * @sc: The SCSI command to examine * @txop: (out) BlockGuard operation for transmitted data * @rxop: (out) BlockGuard operation for received data * * Returns: zero on success; non-zero if tx and/or rx op cannot be determined * **/ static int lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint8_t *txop, uint8_t *rxop) { … } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS /** * lpfc_bg_err_opcodes - reDetermine the BlockGuard opcodes to be used with * the specified SCSI command in order to force a guard tag error. * @phba: The Hba for which this call is being executed. * @sc: The SCSI command to examine * @txop: (out) BlockGuard operation for transmitted data * @rxop: (out) BlockGuard operation for received data * * Returns: zero on success; non-zero if tx and/or rx op cannot be determined * **/ static int lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint8_t *txop, uint8_t *rxop) { … } #endif /** * lpfc_bg_setup_bpl - Setup BlockGuard BPL with no protection data * @phba: The Hba for which this call is being executed. * @sc: pointer to scsi command we're working on * @bpl: pointer to buffer list for protection groups * @datasegcnt: number of segments of data that have been dma mapped * * This function sets up BPL buffer list for protection groups of * type LPFC_PG_TYPE_NO_DIF * * This is usually used when the HBA is instructed to generate * DIFs and insert them into data stream (or strip DIF from * incoming data stream) * * The buffer list consists of just one protection group described * below: * +-------------------------+ * start of prot group --> | PDE_5 | * +-------------------------+ * | PDE_6 | * +-------------------------+ * | Data BDE | * +-------------------------+ * |more Data BDE's ... (opt)| * +-------------------------+ * * * Note: Data s/g buffers have been dma mapped * * Returns the number of BDEs added to the BPL. **/ static int lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, struct ulp_bde64 *bpl, int datasegcnt) { … } /** * lpfc_bg_setup_bpl_prot - Setup BlockGuard BPL with protection data * @phba: The Hba for which this call is being executed. * @sc: pointer to scsi command we're working on * @bpl: pointer to buffer list for protection groups * @datacnt: number of segments of data that have been dma mapped * @protcnt: number of segment of protection data that have been dma mapped * * This function sets up BPL buffer list for protection groups of * type LPFC_PG_TYPE_DIF * * This is usually used when DIFs are in their own buffers, * separate from the data. The HBA can then by instructed * to place the DIFs in the outgoing stream. For read operations, * The HBA could extract the DIFs and place it in DIF buffers. * * The buffer list for this type consists of one or more of the * protection groups described below: * +-------------------------+ * start of first prot group --> | PDE_5 | * +-------------------------+ * | PDE_6 | * +-------------------------+ * | PDE_7 (Prot BDE) | * +-------------------------+ * | Data BDE | * +-------------------------+ * |more Data BDE's ... (opt)| * +-------------------------+ * start of new prot group --> | PDE_5 | * +-------------------------+ * | ... | * +-------------------------+ * * Note: It is assumed that both data and protection s/g buffers have been * mapped for DMA * * Returns the number of BDEs added to the BPL. **/ static int lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, struct ulp_bde64 *bpl, int datacnt, int protcnt) { … } /** * lpfc_bg_setup_sgl - Setup BlockGuard SGL with no protection data * @phba: The Hba for which this call is being executed. * @sc: pointer to scsi command we're working on * @sgl: pointer to buffer list for protection groups * @datasegcnt: number of segments of data that have been dma mapped * @lpfc_cmd: lpfc scsi command object pointer. * * This function sets up SGL buffer list for protection groups of * type LPFC_PG_TYPE_NO_DIF * * This is usually used when the HBA is instructed to generate * DIFs and insert them into data stream (or strip DIF from * incoming data stream) * * The buffer list consists of just one protection group described * below: * +-------------------------+ * start of prot group --> | DI_SEED | * +-------------------------+ * | Data SGE | * +-------------------------+ * |more Data SGE's ... (opt)| * +-------------------------+ * * * Note: Data s/g buffers have been dma mapped * * Returns the number of SGEs added to the SGL. **/ static uint32_t lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, struct sli4_sge *sgl, int datasegcnt, struct lpfc_io_buf *lpfc_cmd) { … } /** * lpfc_bg_setup_sgl_prot - Setup BlockGuard SGL with protection data * @phba: The Hba for which this call is being executed. * @sc: pointer to scsi command we're working on * @sgl: pointer to buffer list for protection groups * @datacnt: number of segments of data that have been dma mapped * @protcnt: number of segment of protection data that have been dma mapped * @lpfc_cmd: lpfc scsi command object pointer. * * This function sets up SGL buffer list for protection groups of * type LPFC_PG_TYPE_DIF * * This is usually used when DIFs are in their own buffers, * separate from the data. The HBA can then by instructed * to place the DIFs in the outgoing stream. For read operations, * The HBA could extract the DIFs and place it in DIF buffers. * * The buffer list for this type consists of one or more of the * protection groups described below: * +-------------------------+ * start of first prot group --> | DISEED | * +-------------------------+ * | DIF (Prot SGE) | * +-------------------------+ * | Data SGE | * +-------------------------+ * |more Data SGE's ... (opt)| * +-------------------------+ * start of new prot group --> | DISEED | * +-------------------------+ * | ... | * +-------------------------+ * * Note: It is assumed that both data and protection s/g buffers have been * mapped for DMA * * Returns the number of SGEs added to the SGL. **/ static uint32_t lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, struct sli4_sge *sgl, int datacnt, int protcnt, struct lpfc_io_buf *lpfc_cmd) { … } /** * lpfc_prot_group_type - Get prtotection group type of SCSI command * @phba: The Hba for which this call is being executed. * @sc: pointer to scsi command we're working on * * Given a SCSI command that supports DIF, determine composition of protection * groups involved in setting up buffer lists * * Returns: Protection group type (with or without DIF) * **/ static int lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc) { … } /** * lpfc_bg_scsi_adjust_dl - Adjust SCSI data length for BlockGuard * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be adjusted. * * Adjust the data length to account for how much data * is actually on the wire. * * returns the adjusted data length **/ static int lpfc_bg_scsi_adjust_dl(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) { … } /** * lpfc_bg_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be prep'ed. * * This is the protection/DIF aware version of * lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the * two functions eventually, but for now, it's here. * RETURNS 0 - SUCCESS, * 1 - Failed DMA map, retry. * 2 - Invalid scsi cmd or prot-type. Do not rety. **/ static int lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) { … } /* * This function calcuates the T10 DIF guard tag * on the specified data using a CRC algorithmn * using crc_t10dif. */ static uint16_t lpfc_bg_crc(uint8_t *data, int count) { … } /* * This function calcuates the T10 DIF guard tag * on the specified data using a CSUM algorithmn * using ip_compute_csum. */ static uint16_t lpfc_bg_csum(uint8_t *data, int count) { … } /* * This function examines the protection data to try to determine * what type of T10-DIF error occurred. */ static void lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) { … } /* * This function checks for BlockGuard errors detected by * the HBA. In case of errors, the ASC/ASCQ fields in the * sense buffer will be set accordingly, paired with * ILLEGAL_REQUEST to signal to the kernel that the HBA * detected corruption. * * Returns: * 0 - No error found * 1 - BlockGuard error found * -1 - Internal error (bad profile, ...etc) */ static int lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd, struct lpfc_iocbq *pIocbOut) { … } /** * lpfc_scsi_prep_dma_buf_s4 - DMA mapping for scsi buffer to SLI4 IF spec * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be mapped. * * This routine does the pci dma mapping for scatter-gather list of scsi cmnd * field of @lpfc_cmd for device with SLI-4 interface spec. * * Return codes: * 2 - Error - Do not retry * 1 - Error - Retry * 0 - Success **/ static int lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) { … } /** * lpfc_bg_scsi_prep_dma_buf_s4 - DMA mapping for scsi buffer to SLI4 IF spec * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be mapped. * * This is the protection/DIF aware version of * lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the * two functions eventually, but for now, it's here * Return codes: * 2 - Error - Do not retry * 1 - Error - Retry * 0 - Success **/ static int lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) { … } /** * lpfc_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be mapped. * * This routine wraps the actual DMA mapping function pointer from the * lpfc_hba struct. * * Return codes: * 1 - Error * 0 - Success **/ static inline int lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) { … } /** * lpfc_bg_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer * using BlockGuard. * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be mapped. * * This routine wraps the actual DMA mapping function pointer from the * lpfc_hba struct. * * Return codes: * 1 - Error * 0 - Success **/ static inline int lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) { … } /** * lpfc_scsi_prep_cmnd_buf - Wrapper function for IOCB/WQE mapping of scsi * buffer * @vport: Pointer to vport object. * @lpfc_cmd: The scsi buffer which is going to be mapped. * @tmo: Timeout value for IO * * This routine initializes IOCB/WQE data structure from scsi command * * Return codes: * 1 - Error * 0 - Success **/ static inline int lpfc_scsi_prep_cmnd_buf(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, uint8_t tmo) { … } /** * lpfc_send_scsi_error_event - Posts an event when there is SCSI error * @phba: Pointer to hba context object. * @vport: Pointer to vport object. * @lpfc_cmd: Pointer to lpfc scsi command which reported the error. * @fcpi_parm: FCP Initiator parameter. * * This function posts an event when there is a SCSI command reporting * error from the scsi device. **/ static void lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, uint32_t fcpi_parm) { … } /** * lpfc_scsi_unprep_dma_buf - Un-map DMA mapping of SG-list for dev * @phba: The HBA for which this call is being executed. * @psb: The scsi buffer which is going to be un-mapped. * * This routine does DMA un-mapping of scatter gather list of scsi command * field of @lpfc_cmd for device with SLI-3 interface spec. **/ static void lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_io_buf *psb) { … } /** * lpfc_unblock_requests - allow further commands to be queued. * @phba: pointer to phba object * * For single vport, just call scsi_unblock_requests on physical port. * For multiple vports, send scsi_unblock_requests for all the vports. */ void lpfc_unblock_requests(struct lpfc_hba *phba) { … } /** * lpfc_block_requests - prevent further commands from being queued. * @phba: pointer to phba object * * For single vport, just call scsi_block_requests on physical port. * For multiple vports, send scsi_block_requests for all the vports. */ void lpfc_block_requests(struct lpfc_hba *phba) { … } /** * lpfc_update_cmf_cmpl - Adjust CMF counters for IO completion * @phba: The HBA for which this call is being executed. * @time: The latency of the IO that completed (in ns) * @size: The size of the IO that completed * @shost: SCSI host the IO completed on (NULL for a NVME IO) * * The routine adjusts the various Burst and Bandwidth counters used in * Congestion management and E2E. If time is set to LPFC_CGN_NOT_SENT, * that means the IO was never issued to the HBA, so this routine is * just being called to cleanup the counter from a previous * lpfc_update_cmf_cmd call. */ int lpfc_update_cmf_cmpl(struct lpfc_hba *phba, uint64_t time, uint32_t size, struct Scsi_Host *shost) { … } /** * lpfc_update_cmf_cmd - Adjust CMF counters for IO submission * @phba: The HBA for which this call is being executed. * @size: The size of the IO that will be issued * * The routine adjusts the various Burst and Bandwidth counters used in * Congestion management and E2E. */ int lpfc_update_cmf_cmd(struct lpfc_hba *phba, uint32_t size) { … } /** * lpfc_handle_fcp_err - FCP response handler * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: Pointer to lpfc_io_buf data structure. * @fcpi_parm: FCP Initiator parameter. * * This routine is called to process response IOCB with status field * IOSTAT_FCP_RSP_ERROR. This routine sets result field of scsi command * based upon SCSI and FCP error. **/ static void lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, uint32_t fcpi_parm) { … } /** * lpfc_fcp_io_cmd_wqe_cmpl - Complete a FCP IO * @phba: The hba for which this call is being executed. * @pwqeIn: The command WQE for the scsi cmnd. * @pwqeOut: Pointer to driver response WQE object. * * This routine assigns scsi command result by looking into response WQE * status field appropriately. This routine handles QUEUE FULL condition as * well by ramping down device queue depth. **/ static void lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, struct lpfc_iocbq *pwqeOut) { … } /** * lpfc_scsi_cmd_iocb_cmpl - Scsi cmnd IOCB completion routine * @phba: The Hba for which this call is being executed. * @pIocbIn: The command IOCBQ for the scsi cmnd. * @pIocbOut: The response IOCBQ for the scsi cmnd. * * This routine assigns scsi command result by looking into response IOCB * status field appropriately. This routine handles QUEUE FULL condition as * well by ramping down device queue depth. **/ static void lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct lpfc_iocbq *pIocbOut) { … } /** * lpfc_scsi_prep_cmnd_buf_s3 - SLI-3 IOCB init for the IO * @vport: Pointer to vport object. * @lpfc_cmd: The scsi buffer which is going to be prep'ed. * @tmo: timeout value for the IO * * Based on the data-direction of the command, initialize IOCB * in the I/O buffer. Fill in the IOCB fields which are independent * of the scsi buffer * * RETURNS 0 - SUCCESS, **/ static int lpfc_scsi_prep_cmnd_buf_s3(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, uint8_t tmo) { … } /** * lpfc_scsi_prep_cmnd_buf_s4 - SLI-4 WQE init for the IO * @vport: Pointer to vport object. * @lpfc_cmd: The scsi buffer which is going to be prep'ed. * @tmo: timeout value for the IO * * Based on the data-direction of the command copy WQE template * to I/O buffer WQE. Fill in the WQE fields which are independent * of the scsi buffer * * RETURNS 0 - SUCCESS, **/ static int lpfc_scsi_prep_cmnd_buf_s4(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, uint8_t tmo) { … } /** * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: The scsi command which needs to send. * @pnode: Pointer to lpfc_nodelist. * * This routine initializes fcp_cmnd and iocb data structure from scsi command * to transfer for device with SLI3 interface spec. **/ static int lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, struct lpfc_nodelist *pnode) { … } /** * lpfc_scsi_prep_task_mgmt_cmd_s3 - Convert SLI3 scsi TM cmd to FCP info unit * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: Pointer to lpfc_io_buf data structure. * @lun: Logical unit number. * @task_mgmt_cmd: SCSI task management command. * * This routine creates FCP information unit corresponding to @task_mgmt_cmd * for device with SLI-3 interface spec. * * Return codes: * 0 - Error * 1 - Success **/ static int lpfc_scsi_prep_task_mgmt_cmd_s3(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, u64 lun, u8 task_mgmt_cmd) { … } /** * lpfc_scsi_prep_task_mgmt_cmd_s4 - Convert SLI4 scsi TM cmd to FCP info unit * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: Pointer to lpfc_io_buf data structure. * @lun: Logical unit number. * @task_mgmt_cmd: SCSI task management command. * * This routine creates FCP information unit corresponding to @task_mgmt_cmd * for device with SLI-4 interface spec. * * Return codes: * 0 - Error * 1 - Success **/ static int lpfc_scsi_prep_task_mgmt_cmd_s4(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, u64 lun, u8 task_mgmt_cmd) { … } /** * lpfc_scsi_api_table_setup - Set up scsi api function jump table * @phba: The hba struct for which this call is being executed. * @dev_grp: The HBA PCI-Device group number. * * This routine sets up the SCSI interface API function jump table in @phba * struct. * Returns: 0 - success, -ENODEV - failure. **/ int lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) { … } /** * lpfc_tskmgmt_def_cmpl - IOCB completion routine for task management command * @phba: The Hba for which this call is being executed. * @cmdiocbq: Pointer to lpfc_iocbq data structure. * @rspiocbq: Pointer to lpfc_iocbq data structure. * * This routine is IOCB completion routine for device reset and target reset * routine. This routine release scsi buffer associated with lpfc_cmd. **/ static void lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq, struct lpfc_iocbq *rspiocbq) { … } /** * lpfc_check_pci_resettable - Walks list of devices on pci_dev's bus to check * if issuing a pci_bus_reset is possibly unsafe * @phba: lpfc_hba pointer. * * Description: * Walks the bus_list to ensure only PCI devices with Emulex * vendor id, device ids that support hot reset, and only one occurrence * of function 0. * * Returns: * -EBADSLT, detected invalid device * 0, successful */ int lpfc_check_pci_resettable(struct lpfc_hba *phba) { … } /** * lpfc_info - Info entry point of scsi_host_template data structure * @host: The scsi host for which this call is being executed. * * This routine provides module information about hba. * * Reutrn code: * Pointer to char - Success. **/ const char * lpfc_info(struct Scsi_Host *host) { … } /** * lpfc_poll_rearm_timer - Routine to modify fcp_poll timer of hba * @phba: The Hba for which this call is being executed. * * This routine modifies fcp_poll_timer field of @phba by cfg_poll_tmo. * The default value of cfg_poll_tmo is 10 milliseconds. **/ static __inline__ void lpfc_poll_rearm_timer(struct lpfc_hba * phba) { … } /** * lpfc_poll_start_timer - Routine to start fcp_poll_timer of HBA * @phba: The Hba for which this call is being executed. * * This routine starts the fcp_poll_timer of @phba. **/ void lpfc_poll_start_timer(struct lpfc_hba * phba) { … } /** * lpfc_poll_timeout - Restart polling timer * @t: Timer construct where lpfc_hba data structure pointer is obtained. * * This routine restarts fcp_poll timer, when FCP ring polling is enable * and FCP Ring interrupt is disable. **/ void lpfc_poll_timeout(struct timer_list *t) { … } /* * lpfc_is_command_vm_io - get the UUID from blk cgroup * @cmd: Pointer to scsi_cmnd data structure * Returns UUID if present, otherwise NULL */ static char *lpfc_is_command_vm_io(struct scsi_cmnd *cmd) { … } /** * lpfc_queuecommand - scsi_host_template queuecommand entry point * @shost: kernel scsi host pointer. * @cmnd: Pointer to scsi_cmnd data structure. * * Driver registers this routine to scsi midlayer to submit a @cmd to process. * This routine prepares an IOCB from scsi command and provides to firmware. * The @done callback is invoked after driver finished processing the command. * * Return value : * 0 - Success * SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily. **/ static int lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) { … } /* * lpfc_vmid_vport_cleanup - cleans up the resources associated with a vport * @vport: The virtual port for which this call is being executed. */ void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport) { … } /** * lpfc_abort_handler - scsi_host_template eh_abort_handler entry point * @cmnd: Pointer to scsi_cmnd data structure. * * This routine aborts @cmnd pending in base driver. * * Return code : * 0x2003 - Error * 0x2002 - Success **/ static int lpfc_abort_handler(struct scsi_cmnd *cmnd) { … } static char * lpfc_taskmgmt_name(uint8_t task_mgmt_cmd) { … } /** * lpfc_check_fcp_rsp - check the returned fcp_rsp to see if task failed * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: Pointer to lpfc_io_buf data structure. * * This routine checks the FCP RSP INFO to see if the tsk mgmt command succeded * * Return code : * 0x2003 - Error * 0x2002 - Success **/ static int lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) { … } /** * lpfc_send_taskmgmt - Generic SCSI Task Mgmt Handler * @vport: The virtual port for which this call is being executed. * @rport: Pointer to remote port * @tgt_id: Target ID of remote device. * @lun_id: Lun number for the TMF * @task_mgmt_cmd: type of TMF to send * * This routine builds and sends a TMF (SCSI Task Mgmt Function) to * a remote port. * * Return Code: * 0x2003 - Error * 0x2002 - Success. **/ static int lpfc_send_taskmgmt(struct lpfc_vport *vport, struct fc_rport *rport, unsigned int tgt_id, uint64_t lun_id, uint8_t task_mgmt_cmd) { … } /** * lpfc_chk_tgt_mapped - * @vport: The virtual port to check on * @rport: Pointer to fc_rport data structure. * * This routine delays until the scsi target (aka rport) for the * command exists (is present and logged in) or we declare it non-existent. * * Return code : * 0x2003 - Error * 0x2002 - Success **/ static int lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct fc_rport *rport) { … } /** * lpfc_reset_flush_io_context - * @vport: The virtual port (scsi_host) for the flush context * @tgt_id: If aborting by Target contect - specifies the target id * @lun_id: If aborting by Lun context - specifies the lun id * @context: specifies the context level to flush at. * * After a reset condition via TMF, we need to flush orphaned i/o * contexts from the adapter. This routine aborts any contexts * outstanding, then waits for their completions. The wait is * bounded by devloss_tmo though. * * Return code : * 0x2003 - Error * 0x2002 - Success **/ static int lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd context) { … } /** * lpfc_device_reset_handler - scsi_host_template eh_device_reset entry point * @cmnd: Pointer to scsi_cmnd data structure. * * This routine does a device reset by sending a LUN_RESET task management * command. * * Return code : * 0x2003 - Error * 0x2002 - Success **/ static int lpfc_device_reset_handler(struct scsi_cmnd *cmnd) { … } /** * lpfc_target_reset_handler - scsi_host_template eh_target_reset entry point * @cmnd: Pointer to scsi_cmnd data structure. * * This routine does a target reset by sending a TARGET_RESET task management * command. * * Return code : * 0x2003 - Error * 0x2002 - Success **/ static int lpfc_target_reset_handler(struct scsi_cmnd *cmnd) { … } /** * lpfc_host_reset_handler - scsi_host_template eh_host_reset_handler entry pt * @cmnd: Pointer to scsi_cmnd data structure. * * This routine does host reset to the adaptor port. It brings the HBA * offline, performs a board restart, and then brings the board back online. * The lpfc_offline calls lpfc_sli_hba_down which will abort and local * reject all outstanding SCSI commands to the host and error returned * back to SCSI mid-level. As this will be SCSI mid-level's last resort * of error handling, it will only return error if resetting of the adapter * is not successful; in all other cases, will return success. * * Return code : * 0x2003 - Error * 0x2002 - Success **/ static int lpfc_host_reset_handler(struct scsi_cmnd *cmnd) { … } /** * lpfc_slave_alloc - scsi_host_template slave_alloc entry point * @sdev: Pointer to scsi_device. * * This routine populates the cmds_per_lun count + 2 scsi_bufs into this host's * globally available list of scsi buffers. This routine also makes sure scsi * buffer is not allocated more than HBA limit conveyed to midlayer. This list * of scsi buffer exists for the lifetime of the driver. * * Return codes: * non-0 - Error * 0 - Success **/ static int lpfc_slave_alloc(struct scsi_device *sdev) { … } /** * lpfc_slave_configure - scsi_host_template slave_configure entry point * @sdev: Pointer to scsi_device. * * This routine configures following items * - Tag command queuing support for @sdev if supported. * - Enable SLI polling for fcp ring if ENABLE_FCP_RING_POLLING flag is set. * * Return codes: * 0 - Success **/ static int lpfc_slave_configure(struct scsi_device *sdev) { … } /** * lpfc_slave_destroy - slave_destroy entry point of SHT data structure * @sdev: Pointer to scsi_device. * * This routine sets @sdev hostatdata filed to null. **/ static void lpfc_slave_destroy(struct scsi_device *sdev) { … } /** * lpfc_create_device_data - creates and initializes device data structure for OAS * @phba: Pointer to host bus adapter structure. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information * @lun: Lun on target * @pri: Priority * @atomic_create: Flag to indicate if memory should be allocated using the * GFP_ATOMIC flag or not. * * This routine creates a device data structure which will contain identifying * information for the device (host wwpn, target wwpn, lun), state of OAS, * whether or not the corresponding lun is available by the system, * and pointer to the rport data. * * Return codes: * NULL - Error * Pointer to lpfc_device_data - Success **/ struct lpfc_device_data* lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, struct lpfc_name *target_wwpn, uint64_t lun, uint32_t pri, bool atomic_create) { … } /** * lpfc_delete_device_data - frees a device data structure for OAS * @phba: Pointer to host bus adapter structure. * @lun_info: Pointer to device data structure to free. * * This routine frees the previously allocated device data structure passed. * **/ void lpfc_delete_device_data(struct lpfc_hba *phba, struct lpfc_device_data *lun_info) { … } /** * __lpfc_get_device_data - returns the device data for the specified lun * @phba: Pointer to host bus adapter structure. * @list: Point to list to search. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information * @lun: Lun on target * * This routine searches the list passed for the specified lun's device data. * This function does not hold locks, it is the responsibility of the caller * to ensure the proper lock is held before calling the function. * * Return codes: * NULL - Error * Pointer to lpfc_device_data - Success **/ struct lpfc_device_data* __lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list, struct lpfc_name *vport_wwpn, struct lpfc_name *target_wwpn, uint64_t lun) { … } /** * lpfc_find_next_oas_lun - searches for the next oas lun * @phba: Pointer to host bus adapter structure. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information * @starting_lun: Pointer to the lun to start searching for * @found_vport_wwpn: Pointer to the found lun's vport wwpn information * @found_target_wwpn: Pointer to the found lun's target wwpn information * @found_lun: Pointer to the found lun. * @found_lun_status: Pointer to status of the found lun. * @found_lun_pri: Pointer to priority of the found lun. * * This routine searches the luns list for the specified lun * or the first lun for the vport/target. If the vport wwpn contains * a zero value then a specific vport is not specified. In this case * any vport which contains the lun will be considered a match. If the * target wwpn contains a zero value then a specific target is not specified. * In this case any target which contains the lun will be considered a * match. If the lun is found, the lun, vport wwpn, target wwpn and lun status * are returned. The function will also return the next lun if available. * If the next lun is not found, starting_lun parameter will be set to * NO_MORE_OAS_LUN. * * Return codes: * non-0 - Error * 0 - Success **/ bool lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, struct lpfc_name *target_wwpn, uint64_t *starting_lun, struct lpfc_name *found_vport_wwpn, struct lpfc_name *found_target_wwpn, uint64_t *found_lun, uint32_t *found_lun_status, uint32_t *found_lun_pri) { … } /** * lpfc_enable_oas_lun - enables a lun for OAS operations * @phba: Pointer to host bus adapter structure. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information * @lun: Lun * @pri: Priority * * This routine enables a lun for oas operations. The routines does so by * doing the following : * * 1) Checks to see if the device data for the lun has been created. * 2) If found, sets the OAS enabled flag if not set and returns. * 3) Otherwise, creates a device data structure. * 4) If successfully created, indicates the device data is for an OAS lun, * indicates the lun is not available and add to the list of luns. * * Return codes: * false - Error * true - Success **/ bool lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, struct lpfc_name *target_wwpn, uint64_t lun, uint8_t pri) { … } /** * lpfc_disable_oas_lun - disables a lun for OAS operations * @phba: Pointer to host bus adapter structure. * @vport_wwpn: Pointer to vport's wwpn information * @target_wwpn: Pointer to target's wwpn information * @lun: Lun * @pri: Priority * * This routine disables a lun for oas operations. The routines does so by * doing the following : * * 1) Checks to see if the device data for the lun is created. * 2) If present, clears the flag indicating this lun is for OAS. * 3) If the lun is not available by the system, the device data is * freed. * * Return codes: * false - Error * true - Success **/ bool lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, struct lpfc_name *target_wwpn, uint64_t lun, uint8_t pri) { … } static int lpfc_no_command(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) { … } static int lpfc_no_slave(struct scsi_device *sdev) { … } struct scsi_host_template lpfc_template_nvme = …; struct scsi_host_template lpfc_template = …; struct scsi_host_template lpfc_vport_template = …;