/******************************************************************* * 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/delay.h> #include <linux/unaligned.h> #include <linux/crc-t10dif.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 <scsi/fc/fc_fs.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_nvme.h" #include "lpfc_logmsg.h" #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_debugfs.h" static struct lpfc_iocbq *lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *, struct lpfc_async_xchg_ctx *, dma_addr_t rspbuf, uint16_t rspsize); static struct lpfc_iocbq *lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *, struct lpfc_async_xchg_ctx *); static int lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *, struct lpfc_async_xchg_ctx *, uint32_t, uint16_t); static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *, struct lpfc_async_xchg_ctx *, uint32_t, uint16_t); static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *, struct lpfc_queue *, struct lpfc_async_xchg_ctx *); static void lpfc_nvmet_fcp_rqst_defer_work(struct work_struct *); static void lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf); static union lpfc_wqe128 lpfc_tsend_cmd_template; static union lpfc_wqe128 lpfc_treceive_cmd_template; static union lpfc_wqe128 lpfc_trsp_cmd_template; /* Setup WQE templates for NVME IOs */ void lpfc_nvmet_cmd_template(void) { … } #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) static struct lpfc_async_xchg_ctx * lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri) { … } static struct lpfc_async_xchg_ctx * lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid) { … } #endif static void lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *ctxp) { … } /** * __lpfc_nvme_xmt_ls_rsp_cmp - Generic completion handler for the * transmission of an NVME LS response. * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. * @rspwqe: Pointer to driver response WQE object. * * The function is called from SLI ring event handler with no * lock held. The function frees memory resources used for the command * used to send the NVME LS RSP. **/ void __lpfc_nvme_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_iocbq *rspwqe) { … } /** * lpfc_nvmet_xmt_ls_rsp_cmp - Completion handler for LS Response * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. * @rspwqe: Pointer to driver response WQE object. * * The function is called from SLI ring event handler with no * lock held. This function is the completion handler for NVME LS commands * The function updates any states and statistics, then calls the * generic completion handler to free resources. **/ static void lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_iocbq *rspwqe) { … } /** * lpfc_nvmet_ctxbuf_post - Repost a NVMET RQ DMA buffer and clean up context * @phba: HBA buffer is associated with * @ctx_buf: ctx buffer context * * Description: Frees the given DMA buffer in the appropriate way given by * reposting it to its associated RQ so it can be reused. * * Notes: Takes phba->hbalock. Can be called with or without other locks held. * * Returns: None **/ void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) { … } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS static void lpfc_nvmet_ktime(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *ctxp) { … } #endif /** * lpfc_nvmet_xmt_fcp_op_cmp - Completion handler for FCP Response * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. * @rspwqe: Pointer to driver response WQE object. * * The function is called from SLI ring event handler with no * lock held. This function is the completion handler for NVME FCP commands * The function frees memory resources used for the NVME commands. **/ static void lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_iocbq *rspwqe) { … } /** * __lpfc_nvme_xmt_ls_rsp - Generic service routine to issue transmit * an NVME LS rsp for a prior NVME LS request that was received. * @axchg: pointer to exchange context for the NVME LS request the response * is for. * @ls_rsp: pointer to the transport LS RSP that is to be sent * @xmt_ls_rsp_cmp: completion routine to call upon RSP transmit done * * This routine is used to format and send a WQE to transmit a NVME LS * Response. The response is for a prior NVME LS request that was * received and posted to the transport. * * Returns: * 0 : if response successfully transmit * non-zero : if response failed to transmit, of the form -Exxx. **/ int __lpfc_nvme_xmt_ls_rsp(struct lpfc_async_xchg_ctx *axchg, struct nvmefc_ls_rsp *ls_rsp, void (*xmt_ls_rsp_cmp)(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_iocbq *rspwqe)) { … } /** * lpfc_nvmet_xmt_ls_rsp - Transmit NVME LS response * @tgtport: pointer to target port that NVME LS is to be transmit from. * @ls_rsp: pointer to the transport LS RSP that is to be sent * * Driver registers this routine to transmit responses for received NVME * LS requests. * * This routine is used to format and send a WQE to transmit a NVME LS * Response. The ls_rsp is used to reverse-map the LS to the original * NVME LS request sequence, which provides addressing information for * the remote port the LS to be sent to, as well as the exchange id * that is the LS is bound to. * * Returns: * 0 : if response successfully transmit * non-zero : if response failed to transmit, of the form -Exxx. **/ static int lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, struct nvmefc_ls_rsp *ls_rsp) { … } static int lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, struct nvmefc_tgt_fcp_req *rsp) { … } static void lpfc_nvmet_targetport_delete(struct nvmet_fc_target_port *targetport) { … } static void lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, struct nvmefc_tgt_fcp_req *req) { … } static void lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport, struct nvmefc_tgt_fcp_req *rsp) { … } static void lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, struct nvmefc_tgt_fcp_req *rsp) { … } /** * lpfc_nvmet_ls_req_cmp - completion handler for a nvme ls request * @phba: Pointer to HBA context object * @cmdwqe: Pointer to driver command WQE object. * @rspwqe: Pointer to driver response WQE object. * * This function is the completion handler for NVME LS requests. * The function updates any states and statistics, then calls the * generic completion handler to finish completion of the request. **/ static void lpfc_nvmet_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_iocbq *rspwqe) { … } /** * lpfc_nvmet_ls_req - Issue an Link Service request * @targetport: pointer to target instance registered with nvmet transport. * @hosthandle: hosthandle set by the driver in a prior ls_rqst_rcv. * Driver sets this value to the ndlp pointer. * @pnvme_lsreq: the transport nvme_ls_req structure for the LS * * Driver registers this routine to handle any link service request * from the nvme_fc transport to a remote nvme-aware port. * * Return value : * 0 - Success * non-zero: various error codes, in form of -Exxx **/ static int lpfc_nvmet_ls_req(struct nvmet_fc_target_port *targetport, void *hosthandle, struct nvmefc_ls_req *pnvme_lsreq) { … } /** * lpfc_nvmet_ls_abort - Abort a prior NVME LS request * @targetport: Transport targetport, that LS was issued from. * @hosthandle: hosthandle set by the driver in a prior ls_rqst_rcv. * Driver sets this value to the ndlp pointer. * @pnvme_lsreq: the transport nvme_ls_req structure for LS to be aborted * * Driver registers this routine to abort an NVME LS request that is * in progress (from the transports perspective). **/ static void lpfc_nvmet_ls_abort(struct nvmet_fc_target_port *targetport, void *hosthandle, struct nvmefc_ls_req *pnvme_lsreq) { … } static int lpfc_nvmet_host_traddr(void *hosthandle, u64 *wwnn, u64 *wwpn) { … } static void lpfc_nvmet_host_release(void *hosthandle) { … } static void lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport) { … } static struct nvmet_fc_target_template lpfc_tgttemplate = …; static void __lpfc_nvmet_clean_io_for_cpu(struct lpfc_hba *phba, struct lpfc_nvmet_ctx_info *infop) { … } static void lpfc_nvmet_cleanup_io_context(struct lpfc_hba *phba) { … } static int lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) { … } int lpfc_nvmet_create_targetport(struct lpfc_hba *phba) { … } int lpfc_nvmet_update_targetport(struct lpfc_hba *phba) { … } /** * lpfc_sli4_nvmet_xri_aborted - Fast-path process of nvmet xri abort * @phba: pointer to lpfc hba data structure. * @axri: pointer to the nvmet xri abort wcqe structure. * * This routine is invoked by the worker thread to process a SLI4 fast-path * NVMET aborted xri. **/ void lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri) { … } int lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, struct fc_frame_header *fc_hdr) { … } static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq, struct lpfc_async_xchg_ctx *ctxp) { … } void lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, struct lpfc_queue *wq) { … } void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) { … } /** * lpfc_nvmet_handle_lsreq - Process an NVME LS request * @phba: pointer to lpfc hba data structure. * @axchg: pointer to exchange context for the NVME LS request * * This routine is used for processing an asychronously received NVME LS * request. Any remaining validation is done and the LS is then forwarded * to the nvmet-fc transport via nvmet_fc_rcv_ls_req(). * * The calling sequence should be: nvmet_fc_rcv_ls_req() -> (processing) * -> lpfc_nvmet_xmt_ls_rsp/cmp -> req->done. * lpfc_nvme_xmt_ls_rsp_cmp should free the allocated axchg. * * Returns 0 if LS was handled and delivered to the transport * Returns 1 if LS failed to be handled and should be dropped */ int lpfc_nvmet_handle_lsreq(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *axchg) { … } static void lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) { … } static void lpfc_nvmet_fcp_rqst_defer_work(struct work_struct *work) { … } static struct lpfc_nvmet_ctxbuf * lpfc_nvmet_replenish_context(struct lpfc_hba *phba, struct lpfc_nvmet_ctx_info *current_infop) { … } /** * lpfc_nvmet_unsol_fcp_buffer - Process an unsolicited event data buffer * @phba: pointer to lpfc hba data structure. * @idx: relative index of MRQ vector * @nvmebuf: pointer to lpfc nvme command HBQ data structure. * @isr_timestamp: in jiffies. * @cqflag: cq processing information regarding workload. * * This routine is used for processing the WQE associated with a unsolicited * event. It first determines whether there is an existing ndlp that matches * the DID from the unsolicited WQE. If not, it will create a new one with * the DID from the unsolicited WQE. The ELS command from the unsolicited * WQE is then used to invoke the proper routine and to set up proper state * of the discovery state machine. **/ static void lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, uint32_t idx, struct rqb_dmabuf *nvmebuf, uint64_t isr_timestamp, uint8_t cqflag) { … } /** * lpfc_nvmet_unsol_fcp_event - Process an unsolicited event from an nvme nport * @phba: pointer to lpfc hba data structure. * @idx: relative index of MRQ vector * @nvmebuf: pointer to received nvme data structure. * @isr_timestamp: in jiffies. * @cqflag: cq processing information regarding workload. * * This routine is used to process an unsolicited event received from a SLI * (Service Level Interface) ring. The actual processing of the data buffer * associated with the unsolicited event is done by invoking the routine * lpfc_nvmet_unsol_fcp_buffer() after properly set up the buffer from the * SLI RQ on which the unsolicited event was received. **/ void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx, struct rqb_dmabuf *nvmebuf, uint64_t isr_timestamp, uint8_t cqflag) { … } /** * lpfc_nvmet_prep_ls_wqe - Allocate and prepare a lpfc wqe data structure * @phba: pointer to a host N_Port data structure. * @ctxp: Context info for NVME LS Request * @rspbuf: DMA buffer of NVME command. * @rspsize: size of the NVME command. * * This routine is used for allocating a lpfc-WQE data structure from * the driver lpfc-WQE free-list and prepare the WQE with the parameters * passed into the routine for discovery state machine to issue an Extended * Link Service (NVME) commands. It is a generic lpfc-WQE allocation * and preparation routine that is used by all the discovery state machine * routines and the NVME command-specific fields will be later set up by * the individual discovery machine routines after calling this routine * allocating and preparing a generic WQE data structure. It fills in the * Buffer Descriptor Entries (BDEs), allocates buffers for both command * payload and response payload (if expected). The reference count on the * ndlp is incremented by 1 and the reference to the ndlp is put into * context1 of the WQE data structure for this WQE to hold the ndlp * reference for the command's callback function to access later. * * Return code * Pointer to the newly allocated/prepared nvme wqe data structure * NULL - when nvme wqe data structure allocation/preparation failed **/ static struct lpfc_iocbq * lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *ctxp, dma_addr_t rspbuf, uint16_t rspsize) { … } static struct lpfc_iocbq * lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *ctxp) { … } /** * lpfc_nvmet_sol_fcp_abort_cmp - Completion handler for ABTS * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. * @rspwqe: Pointer to driver response WQE object. * * The function is called from SLI ring event handler with no * lock held. This function is the completion handler for NVME ABTS for FCP cmds * The function frees memory resources used for the NVME commands. **/ static void lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_iocbq *rspwqe) { … } /** * lpfc_nvmet_unsol_fcp_abort_cmp - Completion handler for ABTS * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. * @rspwqe: Pointer to driver response WQE object. * * The function is called from SLI ring event handler with no * lock held. This function is the completion handler for NVME ABTS for FCP cmds * The function frees memory resources used for the NVME commands. **/ static void lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_iocbq *rspwqe) { … } /** * lpfc_nvmet_xmt_ls_abort_cmp - Completion handler for ABTS * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. * @rspwqe: Pointer to driver response WQE object. * * The function is called from SLI ring event handler with no * lock held. This function is the completion handler for NVME ABTS for LS cmds * The function frees memory resources used for the NVME commands. **/ static void lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_iocbq *rspwqe) { … } static int lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, uint16_t xri) { … } static int lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, uint16_t xri) { … } static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, uint16_t xri) { … } /** * lpfc_nvme_unsol_ls_issue_abort - issue ABTS on an exchange received * via async frame receive where the frame is not handled. * @phba: pointer to adapter structure * @ctxp: pointer to the asynchronously received received sequence * @sid: address of the remote port to send the ABTS to * @xri: oxid value to for the ABTS (other side's exchange id). **/ int lpfc_nvme_unsol_ls_issue_abort(struct lpfc_hba *phba, struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, uint16_t xri) { … } /** * lpfc_nvmet_invalidate_host * * @phba: pointer to the driver instance bound to an adapter port. * @ndlp: pointer to an lpfc_nodelist type * * This routine upcalls the nvmet transport to invalidate an NVME * host to which this target instance had active connections. */ void lpfc_nvmet_invalidate_host(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { … }