diff options
Diffstat (limited to 'drivers/scsi/lpfc')
33 files changed, 20650 insertions, 12130 deletions
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index 092a971d066b..bbd1faf41e80 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile @@ -33,4 +33,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o \ lpfc_hbadisc.o lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o \ lpfc_scsi.o lpfc_attr.o lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o \ - lpfc_nvme.o lpfc_nvmet.o + lpfc_nvme.o lpfc_nvmet.o lpfc_vmid.o diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 04d73e2be373..9ad233b40a9e 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -22,6 +22,7 @@ *******************************************************************/ #include <scsi/scsi_host.h> +#include <linux/hashtable.h> #include <linux/ktime.h> #include <linux/workqueue.h> @@ -47,9 +48,6 @@ struct lpfc_sli2_slim; the NameServer before giving up. */ #define LPFC_CMD_PER_LUN 3 /* max outstanding cmds per lun */ #define LPFC_DEFAULT_SG_SEG_CNT 64 /* sg element count per scsi cmnd */ -#define LPFC_DEFAULT_MENLO_SG_SEG_CNT 128 /* sg element count per scsi - cmnd for menlo needs nearly twice as for firmware - downloads using bsg */ #define LPFC_DEFAULT_XPSGL_SIZE 256 #define LPFC_MAX_SG_TABLESIZE 0xffff @@ -70,8 +68,6 @@ struct lpfc_sli2_slim; #define LPFC_MIN_TGT_QDEPTH 10 #define LPFC_MAX_TGT_QDEPTH 0xFFFF -#define LPFC_MAX_BUCKET_COUNT 20 /* Maximum no. of buckets for stat data - collection. */ /* * Following time intervals are used of adjusting SCSI device * queue depths when there are driver resource error or Firmware @@ -114,6 +110,12 @@ struct lpfc_sli2_slim; #define LPFC_MBX_NO_WAIT 0 #define LPFC_MBX_WAIT 1 +#define LPFC_CFG_PARAM_MAGIC_NUM 0xFEAA0005 +#define LPFC_PORT_CFG_NAME "/cfg/port.cfg" + +#define lpfc_rangecheck(val, min, max) \ + ((uint)(val) >= (uint)(min) && (val) <= (max)) + enum lpfc_polling_flags { ENABLE_FCP_RING_POLLING = 0x1, DISABLE_FCP_RING_INT = 0x2 @@ -143,7 +145,7 @@ struct lpfc_dmabuf { struct lpfc_nvmet_ctxbuf { struct list_head list; - struct lpfc_nvmet_rcv_ctx *context; + struct lpfc_async_xchg_ctx *context; struct lpfc_iocbq *iocbq; struct lpfc_sglq *sglq; struct work_struct defer_work; @@ -207,8 +209,7 @@ typedef struct lpfc_vpd { } rev; struct { #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd3 :19; /* Reserved */ - uint32_t cdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd3 :20; /* Reserved */ uint32_t rsvd2 : 3; /* Reserved */ uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t cmv : 1; /* Configure Max VPIs */ @@ -230,8 +231,7 @@ typedef struct lpfc_vpd { uint32_t cmv : 1; /* Configure Max VPIs */ uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t rsvd2 : 3; /* Reserved */ - uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd3 :19; /* Reserved */ + uint32_t rsvd3 :20; /* Reserved */ #endif } sli3Feat; } lpfc_vpd_t; @@ -262,13 +262,13 @@ struct lpfc_stats { uint32_t elsRcvPRLI; uint32_t elsRcvLIRR; uint32_t elsRcvRLS; - uint32_t elsRcvRPS; uint32_t elsRcvRPL; uint32_t elsRcvRRQ; uint32_t elsRcvRTV; uint32_t elsRcvECHO; uint32_t elsRcvLCB; uint32_t elsRcvRDP; + uint32_t elsRcvRDF; uint32_t elsXmitFLOGI; uint32_t elsXmitFDISC; uint32_t elsXmitPLOGI; @@ -306,6 +306,64 @@ struct lpfc_stats { struct lpfc_hba; +#define LPFC_VMID_TIMER 300 /* timer interval in seconds */ + +#define LPFC_MAX_VMID_SIZE 256 +#define LPFC_COMPRESS_VMID_SIZE 16 + +union lpfc_vmid_io_tag { + u32 app_id; /* App Id vmid */ + u8 cs_ctl_vmid; /* Priority tag vmid */ +}; + +#define JIFFIES_PER_HR (HZ * 60 * 60) + +struct lpfc_vmid { + u8 flag; +#define LPFC_VMID_SLOT_FREE 0x0 +#define LPFC_VMID_SLOT_USED 0x1 +#define LPFC_VMID_REQ_REGISTER 0x2 +#define LPFC_VMID_REGISTERED 0x4 +#define LPFC_VMID_DE_REGISTER 0x8 + char host_vmid[LPFC_MAX_VMID_SIZE]; + union lpfc_vmid_io_tag un; + struct hlist_node hnode; + u64 io_rd_cnt; + u64 io_wr_cnt; + u8 vmid_len; + u8 delete_inactive; /* Delete if inactive flag 0 = no, 1 = yes */ + u32 hash_index; + u64 __percpu *last_io_time; +}; + +#define lpfc_vmid_is_type_priority_tag(vport)\ + (vport->vmid_priority_tagging ? 1 : 0) + +#define LPFC_VMID_HASH_SIZE 256 +#define LPFC_VMID_HASH_MASK 255 +#define LPFC_VMID_HASH_SHIFT 6 + +struct lpfc_vmid_context { + struct lpfc_vmid *vmp; + struct lpfc_nodelist *nlp; + bool instantiated; +}; + +struct lpfc_vmid_priority_range { + u8 low; + u8 high; + u8 qos; +}; + +struct lpfc_vmid_priority_info { + u32 num_descriptors; + struct lpfc_vmid_priority_range *vmid_range; +}; + +#define QFPA_EVEN_ONLY 0x01 +#define QFPA_ODD_ONLY 0x02 +#define QFPA_EVEN_ODD 0x03 + enum discovery_state { LPFC_VPORT_UNKNOWN = 0, /* vport state is unknown */ LPFC_VPORT_FAILED = 1, /* vport has failed */ @@ -345,6 +403,159 @@ struct lpfc_trunk_link { link1, link2, link3; + u32 phy_lnk_speed; +}; + +/* Format of congestion module parameters */ +struct lpfc_cgn_param { + uint32_t cgn_param_magic; + uint8_t cgn_param_version; /* version 1 */ + uint8_t cgn_param_mode; /* 0=off 1=managed 2=monitor only */ +#define LPFC_CFG_OFF 0 +#define LPFC_CFG_MANAGED 1 +#define LPFC_CFG_MONITOR 2 + uint8_t cgn_rsvd1; + uint8_t cgn_rsvd2; + uint8_t cgn_param_level0; + uint8_t cgn_param_level1; + uint8_t cgn_param_level2; + uint8_t byte11; + uint8_t byte12; + uint8_t byte13; + uint8_t byte14; + uint8_t byte15; +}; + +/* Max number of days of congestion data */ +#define LPFC_MAX_CGN_DAYS 10 + +/* Format of congestion buffer info + * This structure defines memory thats allocated and registered with + * the HBA firmware. When adding or removing fields from this structure + * the alignment must match the HBA firmware. + */ + +struct lpfc_cgn_info { + /* Header */ + __le16 cgn_info_size; /* is sizeof(struct lpfc_cgn_info) */ + uint8_t cgn_info_version; /* represents format of structure */ +#define LPFC_CGN_INFO_V1 1 +#define LPFC_CGN_INFO_V2 2 +#define LPFC_CGN_INFO_V3 3 + uint8_t cgn_info_mode; /* 0=off 1=managed 2=monitor only */ + uint8_t cgn_info_detect; + uint8_t cgn_info_action; + uint8_t cgn_info_level0; + uint8_t cgn_info_level1; + uint8_t cgn_info_level2; + + /* Start Time */ + uint8_t cgn_info_month; + uint8_t cgn_info_day; + uint8_t cgn_info_year; + uint8_t cgn_info_hour; + uint8_t cgn_info_minute; + uint8_t cgn_info_second; + + /* minute / hours / daily indices */ + uint8_t cgn_index_minute; + uint8_t cgn_index_hour; + uint8_t cgn_index_day; + + __le16 cgn_warn_freq; + __le16 cgn_alarm_freq; + __le16 cgn_lunq; + uint8_t cgn_pad1[8]; + + /* Driver Information */ + __le16 cgn_drvr_min[60]; + __le32 cgn_drvr_hr[24]; + __le32 cgn_drvr_day[LPFC_MAX_CGN_DAYS]; + + /* Congestion Warnings */ + __le16 cgn_warn_min[60]; + __le32 cgn_warn_hr[24]; + __le32 cgn_warn_day[LPFC_MAX_CGN_DAYS]; + + /* Latency Information */ + __le32 cgn_latency_min[60]; + __le32 cgn_latency_hr[24]; + __le32 cgn_latency_day[LPFC_MAX_CGN_DAYS]; + + /* Bandwidth Information */ + __le16 cgn_bw_min[60]; + __le16 cgn_bw_hr[24]; + __le16 cgn_bw_day[LPFC_MAX_CGN_DAYS]; + + /* Congestion Alarms */ + __le16 cgn_alarm_min[60]; + __le32 cgn_alarm_hr[24]; + __le32 cgn_alarm_day[LPFC_MAX_CGN_DAYS]; + + struct_group(cgn_stat, + uint8_t cgn_stat_npm; /* Notifications per minute */ + + /* Start Time */ + uint8_t cgn_stat_month; + uint8_t cgn_stat_day; + uint8_t cgn_stat_year; + uint8_t cgn_stat_hour; + uint8_t cgn_stat_minute; + uint8_t cgn_pad2[2]; + + __le32 cgn_notification; + __le32 cgn_peer_notification; + __le32 link_integ_notification; + __le32 delivery_notification; + + uint8_t cgn_stat_cgn_month; /* Last congestion notification FPIN */ + uint8_t cgn_stat_cgn_day; + uint8_t cgn_stat_cgn_year; + uint8_t cgn_stat_cgn_hour; + uint8_t cgn_stat_cgn_min; + uint8_t cgn_stat_cgn_sec; + + uint8_t cgn_stat_peer_month; /* Last peer congestion FPIN */ + uint8_t cgn_stat_peer_day; + uint8_t cgn_stat_peer_year; + uint8_t cgn_stat_peer_hour; + uint8_t cgn_stat_peer_min; + uint8_t cgn_stat_peer_sec; + + uint8_t cgn_stat_lnk_month; /* Last link integrity FPIN */ + uint8_t cgn_stat_lnk_day; + uint8_t cgn_stat_lnk_year; + uint8_t cgn_stat_lnk_hour; + uint8_t cgn_stat_lnk_min; + uint8_t cgn_stat_lnk_sec; + + uint8_t cgn_stat_del_month; /* Last delivery notification FPIN */ + uint8_t cgn_stat_del_day; + uint8_t cgn_stat_del_year; + uint8_t cgn_stat_del_hour; + uint8_t cgn_stat_del_min; + uint8_t cgn_stat_del_sec; + ); + + __le32 cgn_info_crc; +#define LPFC_CGN_CRC32_MAGIC_NUMBER 0x1EDC6F41 +#define LPFC_CGN_CRC32_SEED 0xFFFFFFFF +}; + +#define LPFC_CGN_INFO_SZ (sizeof(struct lpfc_cgn_info) - \ + sizeof(uint32_t)) + +struct lpfc_cgn_stat { + atomic64_t total_bytes; + atomic64_t rcv_bytes; + atomic64_t rx_latency; +#define LPFC_CGN_NOT_SENT 0xFFFFFFFFFFFFFFFFLL + atomic_t rx_io_cnt; +}; + +struct lpfc_cgn_acqe_stat { + atomic64_t alarm; + atomic64_t warn; }; struct lpfc_vport { @@ -377,6 +588,7 @@ struct lpfc_vport { #define FC_VPORT_LOGO_RCVD 0x200 /* LOGO received on vport */ #define FC_RSCN_DISCOVERY 0x400 /* Auth all devices after RSCN */ #define FC_LOGO_RCVD_DID_CHNG 0x800 /* FDISC on phys port detect DID chng*/ +#define FC_PT2PT_NO_NVME 0x1000 /* Don't send NVME PRLI */ #define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */ #define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */ #define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */ @@ -395,6 +607,7 @@ struct lpfc_vport { #define FC_CT_RSNN_NN 0x4 /* RSNN_NN accepted by switch */ #define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */ #define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */ +#define FC_CT_RPRT_DEFER 0x20 /* Defer issuing FDMI RPRT */ struct list_head fc_nodes; @@ -445,16 +658,19 @@ struct lpfc_vport { #define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */ #define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */ #define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */ +#define WORKER_CHECK_INACTIVE_VMID 0x4000 /* hba: check inactive vmids */ +#define WORKER_CHECK_VMID_ISSUE_QFPA 0x8000 /* vport: Check if qfpa needs + * to be issued */ struct timer_list els_tmofunc; struct timer_list delayed_disc_tmo; - int unreg_vpi_cmpl; - uint8_t load_flag; #define FC_LOADING 0x1 /* HBA in process of loading drvr */ #define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */ #define FC_ALLOW_FDMI 0x4 /* port is ready for FDMI requests */ +#define FC_ALLOW_VMID 0x8 /* Allow VMID I/Os */ +#define FC_DEREGISTER_ALL_APP_ID 0x10 /* Deregister all VMIDs */ /* Vport Config Parameters */ uint32_t cfg_scan_down; uint32_t cfg_lun_queue_depth; @@ -473,28 +689,53 @@ struct lpfc_vport { uint32_t cfg_tgt_queue_depth; uint32_t cfg_first_burst_size; uint32_t dev_loss_tmo_changed; + /* VMID parameters */ + u8 lpfc_vmid_host_uuid[LPFC_COMPRESS_VMID_SIZE]; + u32 max_vmid; /* maximum VMIDs allowed per port */ + u32 cur_vmid_cnt; /* Current VMID count */ +#define LPFC_MIN_VMID 4 +#define LPFC_MAX_VMID 255 + u32 vmid_inactivity_timeout; /* Time after which the VMID */ + /* deregisters from switch */ + u32 vmid_priority_tagging; +#define LPFC_VMID_PRIO_TAG_DISABLE 0 /* Disable */ +#define LPFC_VMID_PRIO_TAG_SUP_TARGETS 1 /* Allow supported targets only */ +#define LPFC_VMID_PRIO_TAG_ALL_TARGETS 2 /* Allow all targets */ + unsigned long *vmid_priority_range; +#define LPFC_VMID_MAX_PRIORITY_RANGE 256 +#define LPFC_VMID_PRIORITY_BITMAP_SIZE 32 + u8 vmid_flag; +#define LPFC_VMID_IN_USE 0x1 +#define LPFC_VMID_ISSUE_QFPA 0x2 +#define LPFC_VMID_QFPA_CMPL 0x4 +#define LPFC_VMID_QOS_ENABLED 0x8 +#define LPFC_VMID_TIMER_ENBLD 0x10 +#define LPFC_VMID_TYPE_PRIO 0x20 + struct fc_qfpa_res *qfpa_res; struct fc_vport *fc_vport; + struct lpfc_vmid *vmid; + DECLARE_HASHTABLE(hash_table, 8); + rwlock_t vmid_lock; + struct lpfc_vmid_priority_info vmid_priority; + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS struct dentry *debug_disc_trc; struct dentry *debug_nodelist; struct dentry *debug_nvmestat; struct dentry *debug_scsistat; - struct dentry *debug_nvmektime; - struct dentry *debug_cpucheck; + struct dentry *debug_ioktime; + struct dentry *debug_hdwqstat; struct dentry *vport_debugfs_root; struct lpfc_debugfs_trc *disc_trc; atomic_t disc_trc_cnt; #endif - uint8_t stat_data_enabled; - uint8_t stat_data_blocked; struct list_head rcv_buffer_list; unsigned long rcv_buffer_time_stamp; uint32_t vport_flag; -#define STATIC_VPORT 1 -#define FAWWPN_SET 2 -#define FAWWPN_PARAM_CHG 4 +#define STATIC_VPORT 0x1 +#define FAWWPN_PARAM_CHG 0x2 uint16_t fdmi_num_disc; uint32_t fdmi_hba_mask; @@ -630,6 +871,32 @@ struct lpfc_ras_fwlog { enum ras_state state; /* RAS logging running state */ }; +#define DBG_LOG_STR_SZ 256 +#define DBG_LOG_SZ 256 + +struct dbg_log_ent { + char log[DBG_LOG_STR_SZ]; + u64 t_ns; +}; + +enum lpfc_irq_chann_mode { + /* Assign IRQs to all possible cpus that have hardware queues */ + NORMAL_MODE, + + /* Assign IRQs only to cpus on the same numa node as HBA */ + NUMA_MODE, + + /* Assign IRQs only on non-hyperthreaded CPUs. This is the + * same as normal_mode, but assign IRQS only on physical CPUs. + */ + NHT_MODE, +}; + +enum lpfc_hba_bit_flags { + FABRIC_COMANDS_BLOCKED, + HBA_PCI_ERR, +}; + struct lpfc_hba { /* SCSI interface function jump table entries */ struct lpfc_io_buf * (*lpfc_get_scsi_buf) @@ -646,16 +913,25 @@ struct lpfc_hba { void (*lpfc_scsi_prep_cmnd) (struct lpfc_vport *, struct lpfc_io_buf *, struct lpfc_nodelist *); + int (*lpfc_scsi_prep_cmnd_buf) + (struct lpfc_vport *vport, + struct lpfc_io_buf *lpfc_cmd, + uint8_t tmo); + int (*lpfc_scsi_prep_task_mgmt_cmd) + (struct lpfc_vport *vport, + struct lpfc_io_buf *lpfc_cmd, + u64 lun, u8 task_mgmt_cmd); /* IOCB interface function jump table entries */ int (*__lpfc_sli_issue_iocb) (struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, uint32_t); + int (*__lpfc_sli_issue_fcp_io) + (struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag); void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *, struct lpfc_iocbq *); int (*lpfc_hba_down_post)(struct lpfc_hba *phba); - IOCB_t * (*lpfc_get_iocb_from_iocbq) - (struct lpfc_iocbq *); void (*lpfc_scsi_cmd_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); @@ -688,7 +964,24 @@ struct lpfc_hba { int (*lpfc_bg_scsi_prep_dma_buf) (struct lpfc_hba *, struct lpfc_io_buf *); - /* Add new entries here */ + + /* Prep SLI WQE/IOCB jump table entries */ + void (*__lpfc_sli_prep_els_req_rsp)(struct lpfc_iocbq *cmdiocbq, + struct lpfc_vport *vport, + struct lpfc_dmabuf *bmp, + u16 cmd_size, u32 did, u32 elscmd, + u8 tmo, u8 expect_rsp); + void (*__lpfc_sli_prep_gen_req)(struct lpfc_iocbq *cmdiocbq, + struct lpfc_dmabuf *bmp, u16 rpi, + u32 num_entry, u8 tmo); + void (*__lpfc_sli_prep_xmit_seq64)(struct lpfc_iocbq *cmdiocbq, + struct lpfc_dmabuf *bmp, u16 rpi, + u16 ox_id, u32 num_entry, u8 rctl, + u8 last_seq, u8 cr_cx_cmd); + void (*__lpfc_sli_prep_abort_xri)(struct lpfc_iocbq *cmdiocbq, + u16 ulp_context, u16 iotag, + u8 ulp_class, u16 cqid, bool ia, + bool wqec); /* expedite pool */ struct lpfc_epd_pool epd_pool; @@ -699,6 +992,9 @@ struct lpfc_hba { struct workqueue_struct *wq; struct delayed_work eq_delay_work; +#define LPFC_IDLE_STAT_DELAY 1000 + struct delayed_work idle_stat_delay_work; + struct lpfc_sli sli; uint8_t pci_dev_grp; /* lpfc PCI dev group: 0x0, 0x1, 0x2,... */ uint32_t sli_rev; /* SLI2, SLI3, or SLI4 */ @@ -723,7 +1019,9 @@ struct lpfc_hba { #define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ #define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */ #define LS_MDS_LINK_DOWN 0x8 /* MDS Diagnostics Link Down */ -#define LS_MDS_LOOPBACK 0x10 /* MDS Diagnostics Link Up (Loopback) */ +#define LS_MDS_LOOPBACK 0x10 /* MDS Diagnostics Link Up (Loopback) */ +#define LS_CT_VEN_RPA 0x20 /* Vendor RPA sent to switch */ +#define LS_EXTERNAL_LOOPBACK 0x40 /* External loopback plug inserted */ uint32_t hba_flag; /* hba generic flags */ #define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */ @@ -732,7 +1030,7 @@ struct lpfc_hba { #define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/ #define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */ #define HBA_PERSISTENT_TOPO 0x20 /* Persistent topology support in hba */ -#define ELS_XRI_ABORT_EVENT 0x40 +#define ELS_XRI_ABORT_EVENT 0x40 /* ELS_XRI abort event was queued */ #define ASYNC_EVENT 0x80 #define LINK_DISABLED 0x100 /* Link disabled by user */ #define FCF_TS_INPROG 0x200 /* FCF table scan in progress */ @@ -742,14 +1040,23 @@ struct lpfc_hba { #define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */ #define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ #define HBA_IOQ_FLUSH 0x8000 /* FCP/NVME I/O queues being flushed */ -#define HBA_FW_DUMP_OP 0x10000 /* Skips fn reset before FW dump */ #define HBA_RECOVERABLE_UE 0x20000 /* Firmware supports recoverable UE */ #define HBA_FORCED_LINK_SPEED 0x40000 /* * Firmware supports Forced Link Speed * capability */ #define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */ - +#define HBA_SHORT_CMF 0x200000 /* shorter CMF timer routine */ +#define HBA_CGN_DAY_WRAP 0x400000 /* HBA Congestion info day wraps */ +#define HBA_DEFER_FLOGI 0x800000 /* Defer FLOGI till read_sparm cmpl */ +#define HBA_SETUP 0x1000000 /* Signifies HBA setup is completed */ +#define HBA_NEEDS_CFG_PORT 0x2000000 /* SLI3 - needs a CONFIG_PORT mbox */ +#define HBA_HBEAT_INP 0x4000000 /* mbox HBEAT is in progress */ +#define HBA_HBEAT_TMO 0x8000000 /* HBEAT initiated after timeout */ +#define HBA_FLOGI_OUTSTANDING 0x10000000 /* FLOGI is outstanding */ +#define HBA_RHBA_CMPL 0x20000000 /* RHBA FDMI command is successful */ + + struct completion *fw_dump_cmpl; /* cmpl event tracker for fw_dump */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; @@ -797,7 +1104,6 @@ struct lpfc_hba { uint8_t wwpn[8]; uint32_t RandomData[7]; uint8_t fcp_embed_io; - uint8_t nvme_support; /* Firmware supports NVME */ uint8_t nvmet_support; /* driver supports NVMET */ #define LPFC_NVMET_MAX_PORTS 32 uint8_t mds_diags_support; @@ -837,7 +1143,6 @@ struct lpfc_hba { uint32_t cfg_fcp_mq_threshold; uint32_t cfg_hdw_queue; uint32_t cfg_irq_chann; - uint32_t cfg_irq_numa; uint32_t cfg_suppress_rsp; uint32_t cfg_nvme_oas; uint32_t cfg_nvme_embed_cmd; @@ -851,8 +1156,6 @@ struct lpfc_hba { uint32_t cfg_nvme_seg_cnt; uint32_t cfg_scsi_seg_cnt; uint32_t cfg_sg_dma_buf_size; - uint64_t cfg_soft_wwnn; - uint64_t cfg_soft_wwpn; uint32_t cfg_hba_queue_depth; uint32_t cfg_enable_hba_reset; uint32_t cfg_enable_hba_heartbeat; @@ -877,17 +1180,27 @@ struct lpfc_hba { uint32_t cfg_hostmem_hgp; uint32_t cfg_log_verbose; uint32_t cfg_enable_fc4_type; +#define LPFC_ENABLE_FCP 1 +#define LPFC_ENABLE_NVME 2 +#define LPFC_ENABLE_BOTH 3 +#if (IS_ENABLED(CONFIG_NVME_FC)) +#define LPFC_MAX_ENBL_FC4_TYPE LPFC_ENABLE_BOTH +#define LPFC_DEF_ENBL_FC4_TYPE LPFC_ENABLE_BOTH +#else +#define LPFC_MAX_ENBL_FC4_TYPE LPFC_ENABLE_FCP +#define LPFC_DEF_ENBL_FC4_TYPE LPFC_ENABLE_FCP +#endif uint32_t cfg_aer_support; uint32_t cfg_sriov_nr_virtfn; uint32_t cfg_request_firmware_upgrade; uint32_t cfg_suppress_link_up; uint32_t cfg_rrq_xri_bitmap_sz; + u32 cfg_fcp_wait_abts_rsp; uint32_t cfg_delay_discovery; uint32_t cfg_sli_mode; #define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */ #define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */ #define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */ - uint32_t cfg_enable_dss; uint32_t cfg_fdmi_on; #define LPFC_FDMI_NO_SUPPORT 0 /* FDMI not supported */ #define LPFC_FDMI_SUPPORT 1 /* FDMI supported? */ @@ -898,13 +1211,18 @@ struct lpfc_hba { uint32_t cfg_ras_fwlog_func; uint32_t cfg_enable_bbcr; /* Enable BB Credit Recovery */ uint32_t cfg_enable_dpp; /* Enable Direct Packet Push */ -#define LPFC_ENABLE_FCP 1 -#define LPFC_ENABLE_NVME 2 -#define LPFC_ENABLE_BOTH 3 uint32_t cfg_enable_pbde; + uint32_t cfg_enable_mi; struct nvmet_fc_target_port *targetport; lpfc_vpd_t vpd; /* vital product data */ + u32 cfg_max_vmid; /* maximum VMIDs allowed per port */ + u32 cfg_vmid_app_header; +#define LPFC_VMID_APP_HEADER_DISABLE 0 +#define LPFC_VMID_APP_HEADER_ENABLE 1 + u32 cfg_vmid_priority_tagging; + u32 cfg_vmid_inactivity_timeout; /* Time after which the VMID */ + /* deregisters from switch */ struct pci_dev *pcidev; struct list_head work_list; uint32_t work_ha; /* Host Attention Bits for WT */ @@ -969,7 +1287,6 @@ struct lpfc_hba { #define VPD_PORT 0x8 /* valid vpd port data */ #define VPD_MASK 0xf /* mask for any vpd data */ - uint8_t soft_wwn_enable; struct timer_list fcp_poll_timer; struct timer_list eratt_poll; @@ -989,6 +1306,7 @@ struct lpfc_hba { uint32_t total_iocbq_bufs; struct list_head active_rrq_list; spinlock_t hbalock; + struct work_struct unblock_request_work; /* SCSI layer unblock IOs */ /* dma_mem_pools */ struct dma_pool *lpfc_sg_dma_buf_pool; @@ -1006,6 +1324,7 @@ struct lpfc_hba { mempool_t *active_rrq_pool; struct fc_host_statistics link_stats; + enum lpfc_irq_chann_mode irq_chann_mode; enum intr_type_t intr_type; uint32_t intr_mode; #define LPFC_INTR_ERROR 0xFFFFFFFF @@ -1033,7 +1352,6 @@ struct lpfc_hba { atomic_t fabric_iocb_count; struct timer_list fabric_block_timer; unsigned long bit_flags; -#define FABRIC_COMANDS_BLOCKED 0 atomic_t num_rsrc_err; atomic_t num_cmd_success; unsigned long last_rsrc_error_time; @@ -1061,6 +1379,8 @@ struct lpfc_hba { #ifdef LPFC_HDWQ_LOCK_STAT struct dentry *debug_lockstat; #endif + struct dentry *debug_cgn_buffer; + struct dentry *debug_rx_monitor; struct dentry *debug_ras_log; atomic_t nvmeio_trc_cnt; uint32_t nvmeio_trc_size; @@ -1105,26 +1425,14 @@ struct lpfc_hba { unsigned long last_completion_time; unsigned long skipped_hb; struct timer_list hb_tmofunc; - uint8_t hb_outstanding; struct timer_list rrq_tmr; enum hba_temp_state over_temp_state; - /* ndlp reference management */ - spinlock_t ndlp_lock; /* * Following bit will be set for all buffer tags which are not * associated with any HBQ. */ #define QUE_BUFTAG_BIT (1<<31) uint32_t buffer_tag_count; - int wait_4_mlo_maint_flg; - wait_queue_head_t wait_4_mlo_m_q; - /* data structure used for latency data collection */ -#define LPFC_NO_BUCKET 0 -#define LPFC_LINEAR_BUCKET 1 -#define LPFC_POWER2_BUCKET 2 - uint8_t bucket_type; - uint32_t bucket_base; - uint32_t bucket_step; /* Maximum number of events that can be outstanding at any time*/ #define LPFC_MAX_EVT_COUNT 512 @@ -1147,17 +1455,14 @@ struct lpfc_hba { struct list_head ct_ev_waiters; struct unsol_rcv_ct_ctx ct_ctx[LPFC_CT_CTX_MAX]; uint32_t ctx_idx; + struct timer_list inactive_vmid_poll; /* RAS Support */ struct lpfc_ras_fwlog ras_fwlog; - uint8_t menlo_flag; /* menlo generic flags */ -#define HBA_MENLO_SUPPORT 0x1 /* HBA supports menlo commands */ uint32_t iocb_cnt; uint32_t iocb_max; atomic_t sdev_cnt; - uint8_t fips_spec_rev; - uint8_t fips_level; spinlock_t devicelock; /* lock for luns list */ mempool_t *device_data_mem_pool; struct list_head luns; @@ -1175,12 +1480,11 @@ struct lpfc_hba { uint16_t sfp_warning; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - uint16_t cpucheck_on; + uint16_t hdwqstat_on; #define LPFC_CHECK_OFF 0 #define LPFC_CHECK_NVME_IO 1 -#define LPFC_CHECK_NVMET_RCV 2 -#define LPFC_CHECK_NVMET_IO 4 -#define LPFC_CHECK_SCSI_IO 8 +#define LPFC_CHECK_NVMET_IO 2 +#define LPFC_CHECK_SCSI_IO 4 uint16_t ktime_on; uint64_t ktime_data_samples; uint64_t ktime_status_samples; @@ -1216,6 +1520,73 @@ struct lpfc_hba { uint64_t ktime_seg10_min; uint64_t ktime_seg10_max; #endif + /* CMF objects */ + struct lpfc_cgn_stat __percpu *cmf_stat; + uint32_t cmf_interval_rate; /* timer interval limit in ms */ + uint32_t cmf_timer_cnt; +#define LPFC_CMF_INTERVAL 90 + uint64_t cmf_link_byte_count; + uint64_t cmf_max_line_rate; + uint64_t cmf_max_bytes_per_interval; + uint64_t cmf_last_sync_bw; +#define LPFC_CMF_BLK_SIZE 512 + struct hrtimer cmf_timer; + atomic_t cmf_bw_wait; + atomic_t cmf_busy; + atomic_t cmf_stop_io; /* To block request and stop IO's */ + uint32_t cmf_active_mode; + uint32_t cmf_info_per_interval; +#define LPFC_MAX_CMF_INFO 32 + struct timespec64 cmf_latency; /* Interval congestion timestamp */ + uint32_t cmf_last_ts; /* Interval congestion time (ms) */ + uint32_t cmf_active_info; + + /* Signal / FPIN handling for Congestion Mgmt */ + u8 cgn_reg_fpin; /* Negotiated value from RDF */ + u8 cgn_init_reg_fpin; /* Initial value from READ_CONFIG */ +#define LPFC_CGN_FPIN_NONE 0x0 +#define LPFC_CGN_FPIN_WARN 0x1 +#define LPFC_CGN_FPIN_ALARM 0x2 +#define LPFC_CGN_FPIN_BOTH (LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM) + + u8 cgn_reg_signal; /* Negotiated value from EDC */ + u8 cgn_init_reg_signal; /* Initial value from READ_CONFIG */ + /* cgn_reg_signal and cgn_init_reg_signal use + * enum fc_edc_cg_signal_cap_types + */ + u16 cgn_fpin_frequency; /* In units of msecs */ +#define LPFC_FPIN_INIT_FREQ 0xffff + u32 cgn_sig_freq; + u32 cgn_acqe_cnt; + + /* RX monitor handling for CMF */ + struct lpfc_rx_info_monitor *rx_monitor; + atomic_t rx_max_read_cnt; /* Maximum read bytes */ + uint64_t rx_block_cnt; + + /* Congestion parameters from flash */ + struct lpfc_cgn_param cgn_p; + + /* Statistics counter for ACQE cgn alarms and warnings */ + struct lpfc_cgn_acqe_stat cgn_acqe_stat; + + /* Congestion buffer information */ + struct lpfc_dmabuf *cgn_i; /* Congestion Info buffer */ + atomic_t cgn_fabric_warn_cnt; /* Total warning cgn events for info */ + atomic_t cgn_fabric_alarm_cnt; /* Total alarm cgn events for info */ + atomic_t cgn_sync_warn_cnt; /* Total warning events for SYNC wqe */ + atomic_t cgn_sync_alarm_cnt; /* Total alarm events for SYNC wqe */ + atomic_t cgn_driver_evt_cnt; /* Total driver cgn events for fmw */ + atomic_t cgn_latency_evt_cnt; + struct timespec64 cgn_daily_ts; + atomic64_t cgn_latency_evt; /* Avg latency per minute */ + unsigned long cgn_evt_timestamp; +#define LPFC_CGN_TIMER_TO_MIN 60000 /* ms in a minute */ + uint32_t cgn_evt_minute; +#define LPFC_SEC_MIN 60 +#define LPFC_MIN_HOUR 60 +#define LPFC_HOUR_DAY 24 +#define LPFC_MIN_DAY (LPFC_MIN_HOUR * LPFC_HOUR_DAY) struct hlist_node cpuhp; /* used for cpuhp per hba callback */ struct timer_list cpuhp_poll_timer; @@ -1225,6 +1596,40 @@ struct lpfc_hba { #define LPFC_POLL_SLOWPATH 1 /* called from slowpath */ char os_host_name[MAXHOSTNAMELEN]; + + /* LD Signaling */ + u32 degrade_activate_threshold; + u32 degrade_deactivate_threshold; + u32 fec_degrade_interval; + + atomic_t dbg_log_idx; + atomic_t dbg_log_cnt; + atomic_t dbg_log_dmping; + struct dbg_log_ent dbg_log[DBG_LOG_SZ]; +}; + +#define LPFC_MAX_RXMONITOR_ENTRY 800 +#define LPFC_MAX_RXMONITOR_DUMP 32 +struct rx_info_entry { + uint64_t cmf_bytes; /* Total no of read bytes for CMF_SYNC_WQE */ + uint64_t total_bytes; /* Total no of read bytes requested */ + uint64_t rcv_bytes; /* Total no of read bytes completed */ + uint64_t avg_io_size; + uint64_t avg_io_latency;/* Average io latency in microseconds */ + uint64_t max_read_cnt; /* Maximum read bytes */ + uint64_t max_bytes_per_interval; + uint32_t cmf_busy; + uint32_t cmf_info; /* CMF_SYNC_WQE info */ + uint32_t io_cnt; + uint32_t timer_utilization; + uint32_t timer_interval; +}; + +struct lpfc_rx_info_monitor { + struct rx_info_entry *ring; /* info organized in a circular buffer */ + u32 head_idx, tail_idx; /* index to head/tail of ring */ + spinlock_t lock; /* spinlock for ring */ + u32 entries; /* storing number entries/size of ring */ }; static inline struct Scsi_Host * @@ -1315,19 +1720,19 @@ lpfc_phba_elsring(struct lpfc_hba *phba) } /** - * lpfc_next_online_numa_cpu - Finds next online CPU on NUMA node - * @numa_mask: Pointer to phba's numa_mask member. + * lpfc_next_online_cpu - Finds next online CPU on cpumask + * @mask: Pointer to phba's cpumask member. * @start: starting cpu index * * Note: If no valid cpu found, then nr_cpu_ids is returned. * **/ static inline unsigned int -lpfc_next_online_numa_cpu(const struct cpumask *numa_mask, unsigned int start) +lpfc_next_online_cpu(const struct cpumask *mask, unsigned int start) { unsigned int cpu_it; - for_each_cpu_wrap(cpu_it, numa_mask, start) { + for_each_cpu_wrap(cpu_it, mask, start) { if (cpu_online(cpu_it)) break; } @@ -1353,3 +1758,128 @@ lpfc_sli4_mod_hba_eq_delay(struct lpfc_hba *phba, struct lpfc_queue *eq, writel(reg_data.word0, phba->sli4_hba.u.if_type2.EQDregaddr); eq->q_mode = delay; } + + +/* + * Macro that declares tables and a routine to perform enum type to + * ascii string lookup. + * + * Defines a <key,value> table for an enum. Uses xxx_INIT defines for + * the enum to populate the table. Macro defines a routine (named + * by caller) that will search all elements of the table for the key + * and return the name string if found or "Unrecognized" if not found. + */ +#define DECLARE_ENUM2STR_LOOKUP(routine, enum_name, enum_init) \ +static struct { \ + enum enum_name value; \ + char *name; \ +} fc_##enum_name##_e2str_names[] = enum_init; \ +static const char *routine(enum enum_name table_key) \ +{ \ + int i; \ + char *name = "Unrecognized"; \ + \ + for (i = 0; i < ARRAY_SIZE(fc_##enum_name##_e2str_names); i++) {\ + if (fc_##enum_name##_e2str_names[i].value == table_key) {\ + name = fc_##enum_name##_e2str_names[i].name; \ + break; \ + } \ + } \ + return name; \ +} + +/** + * lpfc_is_vmid_enabled - returns if VMID is enabled for either switch types + * @phba: Pointer to HBA context object. + * + * Relationship between the enable, target support and if vmid tag is required + * for the particular combination + * --------------------------------------------------- + * Switch Enable Flag Target Support VMID Needed + * --------------------------------------------------- + * App Id 0 NA N + * App Id 1 0 N + * App Id 1 1 Y + * Pr Tag 0 NA N + * Pr Tag 1 0 N + * Pr Tag 1 1 Y + * Pr Tag 2 * Y + --------------------------------------------------- + * + **/ +static inline int lpfc_is_vmid_enabled(struct lpfc_hba *phba) +{ + return phba->cfg_vmid_app_header || phba->cfg_vmid_priority_tagging; +} + +static inline +u8 get_job_ulpstatus(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + if (phba->sli_rev == LPFC_SLI_REV4) + return bf_get(lpfc_wcqe_c_status, &iocbq->wcqe_cmpl); + else + return iocbq->iocb.ulpStatus; +} + +static inline +u32 get_job_word4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + if (phba->sli_rev == LPFC_SLI_REV4) + return iocbq->wcqe_cmpl.parameter; + else + return iocbq->iocb.un.ulpWord[4]; +} + +static inline +u8 get_job_cmnd(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + if (phba->sli_rev == LPFC_SLI_REV4) + return bf_get(wqe_cmnd, &iocbq->wqe.generic.wqe_com); + else + return iocbq->iocb.ulpCommand; +} + +static inline +u16 get_job_ulpcontext(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + if (phba->sli_rev == LPFC_SLI_REV4) + return bf_get(wqe_ctxt_tag, &iocbq->wqe.generic.wqe_com); + else + return iocbq->iocb.ulpContext; +} + +static inline +u16 get_job_rcvoxid(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + if (phba->sli_rev == LPFC_SLI_REV4) + return bf_get(wqe_rcvoxid, &iocbq->wqe.generic.wqe_com); + else + return iocbq->iocb.unsli3.rcvsli3.ox_id; +} + +static inline +u32 get_job_data_placed(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + if (phba->sli_rev == LPFC_SLI_REV4) + return iocbq->wcqe_cmpl.total_data_placed; + else + return iocbq->iocb.un.genreq64.bdl.bdeSize; +} + +static inline +u32 get_job_abtsiotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + if (phba->sli_rev == LPFC_SLI_REV4) + return iocbq->wqe.abort_cmd.wqe_com.abort_tag; + else + return iocbq->iocb.un.acxri.abortIoTag; +} + +static inline +u32 get_job_els_rsp64_did(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) +{ + if (phba->sli_rev == LPFC_SLI_REV4) + return bf_get(wqe_els_did, &iocbq->wqe.els_req.wqe_dest); + else + return iocbq->iocb.un.elsreq64.remoteID; +} diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 46f56f30f77e..ef1481326fd7 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -37,8 +37,6 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> -#include <linux/nvme-fc-driver.h> - #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" @@ -48,7 +46,6 @@ #include "lpfc.h" #include "lpfc_scsi.h" #include "lpfc_nvme.h" -#include "lpfc_nvmet.h" #include "lpfc_logmsg.h" #include "lpfc_version.h" #include "lpfc_compat.h" @@ -60,10 +57,8 @@ #define LPFC_MIN_DEVLOSS_TMO 1 #define LPFC_MAX_DEVLOSS_TMO 255 -#define LPFC_DEF_MRQ_POST 512 -#define LPFC_MIN_MRQ_POST 512 -#define LPFC_MAX_MRQ_POST 2048 - +#define LPFC_MAX_INFO_TMP_LEN 100 +#define LPFC_INFO_MORE_STR "\nCould be more info...\n" /* * Write key size should be multiple of 4. If write key is changed * make sure that library write key is also changed. @@ -119,6 +114,183 @@ lpfc_jedec_to_ascii(int incr, char hdw[]) return; } +static ssize_t +lpfc_cmf_info_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_cgn_info *cp = NULL; + struct lpfc_cgn_stat *cgs; + int len = 0; + int cpu; + u64 rcv, total; + char tmp[LPFC_MAX_INFO_TMP_LEN] = {0}; + + if (phba->cgn_i) + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + + scnprintf(tmp, sizeof(tmp), + "Congestion Mgmt Info: E2Eattr %d Ver %d " + "CMF %d cnt %d\n", + phba->sli4_hba.pc_sli4_params.mi_ver, + cp ? cp->cgn_info_version : 0, + phba->sli4_hba.pc_sli4_params.cmf, phba->cmf_timer_cnt); + + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + if (!phba->sli4_hba.pc_sli4_params.cmf) + goto buffer_done; + + switch (phba->cgn_init_reg_signal) { + case EDC_CG_SIG_WARN_ONLY: + scnprintf(tmp, sizeof(tmp), + "Register: Init: Signal:WARN "); + break; + case EDC_CG_SIG_WARN_ALARM: + scnprintf(tmp, sizeof(tmp), + "Register: Init: Signal:WARN|ALARM "); + break; + default: + scnprintf(tmp, sizeof(tmp), + "Register: Init: Signal:NONE "); + break; + } + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + switch (phba->cgn_init_reg_fpin) { + case LPFC_CGN_FPIN_WARN: + scnprintf(tmp, sizeof(tmp), + "FPIN:WARN\n"); + break; + case LPFC_CGN_FPIN_ALARM: + scnprintf(tmp, sizeof(tmp), + "FPIN:ALARM\n"); + break; + case LPFC_CGN_FPIN_BOTH: + scnprintf(tmp, sizeof(tmp), + "FPIN:WARN|ALARM\n"); + break; + default: + scnprintf(tmp, sizeof(tmp), + "FPIN:NONE\n"); + break; + } + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + switch (phba->cgn_reg_signal) { + case EDC_CG_SIG_WARN_ONLY: + scnprintf(tmp, sizeof(tmp), + " Current: Signal:WARN "); + break; + case EDC_CG_SIG_WARN_ALARM: + scnprintf(tmp, sizeof(tmp), + " Current: Signal:WARN|ALARM "); + break; + default: + scnprintf(tmp, sizeof(tmp), + " Current: Signal:NONE "); + break; + } + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + switch (phba->cgn_reg_fpin) { + case LPFC_CGN_FPIN_WARN: + scnprintf(tmp, sizeof(tmp), + "FPIN:WARN ACQEcnt:%d\n", phba->cgn_acqe_cnt); + break; + case LPFC_CGN_FPIN_ALARM: + scnprintf(tmp, sizeof(tmp), + "FPIN:ALARM ACQEcnt:%d\n", phba->cgn_acqe_cnt); + break; + case LPFC_CGN_FPIN_BOTH: + scnprintf(tmp, sizeof(tmp), + "FPIN:WARN|ALARM ACQEcnt:%d\n", phba->cgn_acqe_cnt); + break; + default: + scnprintf(tmp, sizeof(tmp), + "FPIN:NONE ACQEcnt:%d\n", phba->cgn_acqe_cnt); + break; + } + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + if (phba->cmf_active_mode != phba->cgn_p.cgn_param_mode) { + switch (phba->cmf_active_mode) { + case LPFC_CFG_OFF: + scnprintf(tmp, sizeof(tmp), "Active: Mode:Off\n"); + break; + case LPFC_CFG_MANAGED: + scnprintf(tmp, sizeof(tmp), "Active: Mode:Managed\n"); + break; + case LPFC_CFG_MONITOR: + scnprintf(tmp, sizeof(tmp), "Active: Mode:Monitor\n"); + break; + default: + scnprintf(tmp, sizeof(tmp), "Active: Mode:Unknown\n"); + } + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + } + + switch (phba->cgn_p.cgn_param_mode) { + case LPFC_CFG_OFF: + scnprintf(tmp, sizeof(tmp), "Config: Mode:Off "); + break; + case LPFC_CFG_MANAGED: + scnprintf(tmp, sizeof(tmp), "Config: Mode:Managed "); + break; + case LPFC_CFG_MONITOR: + scnprintf(tmp, sizeof(tmp), "Config: Mode:Monitor "); + break; + default: + scnprintf(tmp, sizeof(tmp), "Config: Mode:Unknown "); + } + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + total = 0; + rcv = 0; + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + total += atomic64_read(&cgs->total_bytes); + rcv += atomic64_read(&cgs->rcv_bytes); + } + + scnprintf(tmp, sizeof(tmp), + "IObusy:%d Info:%d Bytes: Rcv:x%llx Total:x%llx\n", + atomic_read(&phba->cmf_busy), + phba->cmf_active_info, rcv, total); + if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) + goto buffer_done; + + scnprintf(tmp, sizeof(tmp), + "Port_speed:%d Link_byte_cnt:%ld " + "Max_byte_per_interval:%ld\n", + lpfc_sli_port_speed_get(phba), + (unsigned long)phba->cmf_link_byte_count, + (unsigned long)phba->cmf_max_bytes_per_interval); + strlcat(buf, tmp, PAGE_SIZE); + +buffer_done: + len = strnlen(buf, PAGE_SIZE); + + if (unlikely(len >= (PAGE_SIZE - 1))) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6312 Catching potential buffer " + "overflow > PAGE_SIZE = %lu bytes\n", + PAGE_SIZE); + strscpy(buf + PAGE_SIZE - 1 - sizeof(LPFC_INFO_MORE_STR), + LPFC_INFO_MORE_STR, sizeof(LPFC_INFO_MORE_STR) + 1); + } + return len; +} + /** * lpfc_drvr_version_show - Return the Emulex driver string with version number * @dev: class unused variable. @@ -175,7 +347,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, char *statep; int i; int len = 0; - char tmp[LPFC_MAX_NVME_INFO_TMP_LEN] = {0}; + char tmp[LPFC_MAX_INFO_TMP_LEN] = {0}; if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) { len = scnprintf(buf, PAGE_SIZE, "NVME Disabled\n"); @@ -375,11 +547,11 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { nrport = NULL; - spin_lock(&vport->phba->hbalock); + spin_lock(&ndlp->lock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) nrport = rport->remoteport; - spin_unlock(&vport->phba->hbalock); + spin_unlock(&ndlp->lock); if (!nrport) continue; @@ -494,8 +666,8 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, atomic_read(&lport->xmt_fcp_noxri), atomic_read(&lport->xmt_fcp_bad_ndlp), atomic_read(&lport->xmt_fcp_qdepth), - atomic_read(&lport->xmt_fcp_err), - atomic_read(&lport->xmt_fcp_wqerr)); + atomic_read(&lport->xmt_fcp_wqerr), + atomic_read(&lport->xmt_fcp_err)); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) goto buffer_done; @@ -519,11 +691,9 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, "6314 Catching potential buffer " "overflow > PAGE_SIZE = %lu bytes\n", PAGE_SIZE); - strlcpy(buf + PAGE_SIZE - 1 - - strnlen(LPFC_NVME_INFO_MORE_STR, PAGE_SIZE - 1), - LPFC_NVME_INFO_MORE_STR, - strnlen(LPFC_NVME_INFO_MORE_STR, PAGE_SIZE - 1) - + 1); + strscpy(buf + PAGE_SIZE - 1 - sizeof(LPFC_INFO_MORE_STR), + LPFC_INFO_MORE_STR, + sizeof(LPFC_INFO_MORE_STR) + 1); } return len; @@ -752,25 +922,6 @@ lpfc_programtype_show(struct device *dev, struct device_attribute *attr, } /** - * lpfc_mlomgmt_show - Return the Menlo Maintenance sli flag - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the Menlo Maintenance sli flag. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_mlomgmt_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return scnprintf(buf, PAGE_SIZE, "%d\n", - (phba->sli.sli_flag & LPFC_MENLO_MAINT)); -} - -/** * lpfc_vportnum_show - Return the port number in ascii of the hba * @dev: class converted to a Scsi_host structure. * @attr: device attribute, not used. @@ -871,7 +1022,7 @@ lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr, } /** - * lpfc_state_show - Return the link state of the port + * lpfc_link_state_show - Return the link state of the port * @dev: class converted to a Scsi_host structure. * @attr: device attribute, not used. * @buf: on return contains text describing the state of the link. @@ -939,10 +1090,7 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, "Unknown\n"); break; } - if (phba->sli.sli_flag & LPFC_MENLO_MAINT) - len += scnprintf(buf + len, PAGE_SIZE-len, - " Menlo Maint Mode\n"); - else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { if (vport->fc_flag & FC_PUBLIC_LOOP) len += scnprintf(buf + len, PAGE_SIZE-len, " Public Loop\n"); @@ -950,12 +1098,22 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, len += scnprintf(buf + len, PAGE_SIZE-len, " Private Loop\n"); } else { - if (vport->fc_flag & FC_FABRIC) - len += scnprintf(buf + len, PAGE_SIZE-len, - " Fabric\n"); - else + if (vport->fc_flag & FC_FABRIC) { + if (phba->sli_rev == LPFC_SLI_REV4 && + vport->port_type == LPFC_PHYSICAL_PORT && + phba->sli4_hba.fawwpn_flag & + LPFC_FAWWPN_FABRIC) + len += scnprintf(buf + len, + PAGE_SIZE - len, + " Fabric FA-PWWN\n"); + else + len += scnprintf(buf + len, + PAGE_SIZE - len, + " Fabric\n"); + } else { len += scnprintf(buf + len, PAGE_SIZE-len, " Point-2-Point\n"); + } } } @@ -1145,6 +1303,9 @@ lpfc_issue_lip(struct Scsi_Host *shost) pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; pmboxq->u.mb.mbxOwner = OWN_HOST; + if ((vport->fc_flag & FC_PT2PT) && (vport->fc_flag & FC_PT2PT_NO_NVME)) + vport->fc_flag &= ~FC_PT2PT_NO_NVME; + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2); if ((mbxstatus == MBX_SUCCESS) && @@ -1183,8 +1344,7 @@ lpfc_emptyq_wait(struct lpfc_hba *phba, struct list_head *q, spinlock_t *lock) msleep(20); if (cnt++ > 250) { /* 5 secs */ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0466 %s %s\n", - "Outstanding IO when ", + "0466 Outstanding IO when " "bringing Adapter offline\n"); return 0; } @@ -1508,6 +1668,7 @@ lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) /** * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc * @phba: lpfc_hba pointer. + * @opcode: The sli4 config command opcode. * * Description: * Request SLI4 interface type-2 device to perform a physical register set @@ -1539,25 +1700,25 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) before_fc_flag = phba->pport->fc_flag; sriov_nr_virtfn = phba->cfg_sriov_nr_virtfn; - /* Disable SR-IOV virtual functions if enabled */ - if (phba->cfg_sriov_nr_virtfn) { - pci_disable_sriov(pdev); - phba->cfg_sriov_nr_virtfn = 0; - } + if (opcode == LPFC_FW_DUMP) { + init_completion(&online_compl); + phba->fw_dump_cmpl = &online_compl; + } else { + /* Disable SR-IOV virtual functions if enabled */ + if (phba->cfg_sriov_nr_virtfn) { + pci_disable_sriov(pdev); + phba->cfg_sriov_nr_virtfn = 0; + } - if (opcode == LPFC_FW_DUMP) - phba->hba_flag |= HBA_FW_DUMP_OP; + status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); + if (status != 0) + return status; - if (status != 0) { - phba->hba_flag &= ~HBA_FW_DUMP_OP; - return status; + /* wait for the device to be quiesced before firmware reset */ + msleep(100); } - /* wait for the device to be quiesced before firmware reset */ - msleep(100); - reg_val = readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET); @@ -1586,24 +1747,42 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3153 Fail to perform the requested " "access: x%x\n", reg_val); + if (phba->fw_dump_cmpl) + phba->fw_dump_cmpl = NULL; return rc; } /* keep the original port state */ - if (before_fc_flag & FC_OFFLINE_MODE) - goto out; - - init_completion(&online_compl); - job_posted = lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); - if (!job_posted) + if (before_fc_flag & FC_OFFLINE_MODE) { + if (phba->fw_dump_cmpl) + phba->fw_dump_cmpl = NULL; goto out; + } - wait_for_completion(&online_compl); + /* Firmware dump will trigger an HA_ERATT event, and + * lpfc_handle_eratt_s4 routine already handles bringing the port back + * online. + */ + if (opcode == LPFC_FW_DUMP) { + wait_for_completion(phba->fw_dump_cmpl); + } else { + init_completion(&online_compl); + job_posted = lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_ONLINE); + if (!job_posted) + goto out; + wait_for_completion(&online_compl); + } out: /* in any case, restore the virtual functions enabled as before */ if (sriov_nr_virtfn) { + /* If fw_dump was performed, first disable to clean up */ + if (opcode == LPFC_FW_DUMP) { + pci_disable_sriov(pdev); + phba->cfg_sriov_nr_virtfn = 0; + } + sriov_err = lpfc_sli_probe_sriov_nr_virtfn(phba, sriov_nr_virtfn); if (!sriov_err) @@ -1693,8 +1872,7 @@ lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out) lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "0071 Set trunk mode failed with status: %d", rc); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); + mempool_free(mbox, phba->mbox_mem_pool); return 0; } @@ -1794,6 +1972,8 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, else if (strncmp(buf, "pci_bus_reset", sizeof("pci_bus_reset") - 1) == 0) status = lpfc_reset_pci_bus(phba); + else if (strncmp(buf, "heartbeat", sizeof("heartbeat") - 1) == 0) + lpfc_issue_hb_tmo(phba); else if (strncmp(buf, "trunk", sizeof("trunk") - 1) == 0) status = lpfc_set_trunking(phba, (char *)buf + sizeof("trunk")); else @@ -2231,66 +2411,6 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr, } /** - * lpfc_fips_level_show - Return the current FIPS level for the HBA - * @dev: class unused variable. - * @attr: device attribute, not used. - * @buf: on return contains the module description text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_fips_level_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level); -} - -/** - * lpfc_fips_rev_show - Return the FIPS Spec revision for the HBA - * @dev: class unused variable. - * @attr: device attribute, not used. - * @buf: on return contains the module description text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_fips_rev_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev); -} - -/** - * lpfc_dss_show - Return the current state of dss and the configured state - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the formatted text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_dss_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return scnprintf(buf, PAGE_SIZE, "%s - %sOperational\n", - (phba->cfg_enable_dss) ? "Enabled" : "Disabled", - (phba->sli3_options & LPFC_SLI3_DSS_ENABLED) ? - "" : "Not "); -} - -/** * lpfc_sriov_hw_max_virtfn_show - Return maximum number of virtual functions * @dev: class converted to a Scsi_host structure. * @attr: device attribute, not used. @@ -2316,11 +2436,6 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn); } -static inline bool lpfc_rangecheck(uint val, uint min, uint max) -{ - return val >= min && val <= max; -} - /** * lpfc_enable_bbcr_set: Sets an attribute value. * @phba: pointer the the adapter structure. @@ -2340,18 +2455,18 @@ lpfc_enable_bbcr_set(struct lpfc_hba *phba, uint val) { if (lpfc_rangecheck(val, 0, 1) && phba->sli_rev == LPFC_SLI_REV4) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3068 %s_enable_bbcr changed from %d to %d\n", - LPFC_DRIVER_NAME, phba->cfg_enable_bbcr, val); + "3068 lpfc_enable_bbcr changed from %d to " + "%d\n", phba->cfg_enable_bbcr, val); phba->cfg_enable_bbcr = val; return 0; } lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0451 %s_enable_bbcr cannot set to %d, range is 0, 1\n", - LPFC_DRIVER_NAME, val); + "0451 lpfc_enable_bbcr cannot set to %d, range is 0, " + "1\n", val); return -EINVAL; } -/** +/* * lpfc_param_show - Return a cfg attribute value in decimal * * Description: @@ -2377,7 +2492,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ phba->cfg_##attr);\ } -/** +/* * lpfc_param_hex_show - Return a cfg attribute value in hex * * Description: @@ -2405,7 +2520,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ phba->cfg_##attr);\ } -/** +/* * lpfc_param_init - Initializes a cfg attribute * * Description: @@ -2439,7 +2554,7 @@ lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \ return -EINVAL;\ } -/** +/* * lpfc_param_set - Set a cfg attribute value * * Description: @@ -2476,7 +2591,7 @@ lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \ return -EINVAL;\ } -/** +/* * lpfc_param_store - Set a vport attribute value * * Description: @@ -2516,7 +2631,7 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \ return -EINVAL;\ } -/** +/* * lpfc_vport_param_show - Return decimal formatted cfg attribute value * * Description: @@ -2540,7 +2655,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ return scnprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\ } -/** +/* * lpfc_vport_param_hex_show - Return hex formatted attribute value * * Description: @@ -2565,7 +2680,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ return scnprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\ } -/** +/* * lpfc_vport_param_init - Initialize a vport cfg attribute * * Description: @@ -2598,7 +2713,7 @@ lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \ return -EINVAL;\ } -/** +/* * lpfc_vport_param_set - Set a vport cfg attribute * * Description: @@ -2634,7 +2749,7 @@ lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \ return -EINVAL;\ } -/** +/* * lpfc_vport_param_store - Set a vport attribute * * Description: @@ -2690,7 +2805,6 @@ static DEVICE_ATTR(option_rom_version, S_IRUGO, lpfc_option_rom_version_show, NULL); static DEVICE_ATTR(num_discovered_ports, S_IRUGO, lpfc_num_discovered_ports_show, NULL); -static DEVICE_ATTR(menlo_mgmt_mode, S_IRUGO, lpfc_mlomgmt_show, NULL); static DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL); static DEVICE_ATTR_RO(lpfc_drvr_version); static DEVICE_ATTR_RO(lpfc_enable_fip); @@ -2705,15 +2819,12 @@ static DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL); static DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL); static DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL); static DEVICE_ATTR_RO(lpfc_temp_sensor); -static DEVICE_ATTR_RO(lpfc_fips_level); -static DEVICE_ATTR_RO(lpfc_fips_rev); -static DEVICE_ATTR_RO(lpfc_dss); static DEVICE_ATTR_RO(lpfc_sriov_hw_max_virtfn); static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); static DEVICE_ATTR(lpfc_xlane_supported, S_IRUGO, lpfc_oas_supported_show, NULL); +static DEVICE_ATTR(cmf_info, 0444, lpfc_cmf_info_show, NULL); -static char *lpfc_soft_wwn_key = "C99G71SL8032A"; #define WWN_SZ 8 /** * lpfc_wwn_set - Convert string to the 8 byte WWN value. @@ -2757,228 +2868,7 @@ lpfc_wwn_set(const char *buf, size_t cnt, char wwn[]) } return 0; } -/** - * lpfc_soft_wwn_enable_store - Allows setting of the wwn if the key is valid - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing the string lpfc_soft_wwn_key. - * @count: must be size of lpfc_soft_wwn_key. - * - * Returns: - * -EINVAL if the buffer does not contain lpfc_soft_wwn_key - * length of buf indicates success - **/ -static ssize_t -lpfc_soft_wwn_enable_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - unsigned int cnt = count; - uint8_t vvvl = vport->fc_sparam.cmn.valid_vendor_ver_level; - u32 *fawwpn_key = (uint32_t *)&vport->fc_sparam.un.vendorVersion[0]; - - /* - * We're doing a simple sanity check for soft_wwpn setting. - * We require that the user write a specific key to enable - * the soft_wwpn attribute to be settable. Once the attribute - * is written, the enable key resets. If further updates are - * desired, the key must be written again to re-enable the - * attribute. - * - * The "key" is not secret - it is a hardcoded string shown - * here. The intent is to protect against the random user or - * application that is just writing attributes. - */ - if (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0051 "LPFC_DRIVER_NAME" soft wwpn can not" - " be enabled: fawwpn is enabled\n"); - return -EINVAL; - } - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if ((cnt != strlen(lpfc_soft_wwn_key)) || - (strncmp(buf, lpfc_soft_wwn_key, strlen(lpfc_soft_wwn_key)) != 0)) - return -EINVAL; - - phba->soft_wwn_enable = 1; - - dev_printk(KERN_WARNING, &phba->pcidev->dev, - "lpfc%d: soft_wwpn assignment has been enabled.\n", - phba->brd_no); - dev_printk(KERN_WARNING, &phba->pcidev->dev, - " The soft_wwpn feature is not supported by Broadcom."); - - return count; -} -static DEVICE_ATTR_WO(lpfc_soft_wwn_enable); - -/** - * lpfc_soft_wwpn_show - Return the cfg soft ww port name of the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the wwpn in hexadecimal. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_soft_wwpn_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return scnprintf(buf, PAGE_SIZE, "0x%llx\n", - (unsigned long long)phba->cfg_soft_wwpn); -} - -/** - * lpfc_soft_wwpn_store - Set the ww port name of the adapter - * @dev class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: contains the wwpn in hexadecimal. - * @count: number of wwpn bytes in buf - * - * Returns: - * -EACCES hba reset not enabled, adapter over temp - * -EINVAL soft wwn not enabled, count is invalid, invalid wwpn byte invalid - * -EIO error taking adapter offline or online - * value of count on success - **/ -static ssize_t -lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct completion online_compl; - int stat1 = 0, stat2 = 0; - unsigned int cnt = count; - u8 wwpn[WWN_SZ]; - int rc; - - if (!phba->cfg_enable_hba_reset) - return -EACCES; - spin_lock_irq(&phba->hbalock); - if (phba->over_temp_state == HBA_OVER_TEMP) { - spin_unlock_irq(&phba->hbalock); - return -EACCES; - } - spin_unlock_irq(&phba->hbalock); - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if (!phba->soft_wwn_enable) - return -EINVAL; - /* lock setting wwpn, wwnn down */ - phba->soft_wwn_enable = 0; - - rc = lpfc_wwn_set(buf, cnt, wwpn); - if (rc) { - /* not able to set wwpn, unlock it */ - phba->soft_wwn_enable = 1; - return rc; - } - - phba->cfg_soft_wwpn = wwn_to_u64(wwpn); - fc_host_port_name(shost) = phba->cfg_soft_wwpn; - if (phba->cfg_soft_wwnn) - fc_host_node_name(shost) = phba->cfg_soft_wwnn; - - dev_printk(KERN_NOTICE, &phba->pcidev->dev, - "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no); - - stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - if (stat1) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0463 lpfc_soft_wwpn attribute set failed to " - "reinit adapter - %d\n", stat1); - init_completion(&online_compl); - rc = lpfc_workq_post_event(phba, &stat2, &online_compl, - LPFC_EVT_ONLINE); - if (rc == 0) - return -ENOMEM; - - wait_for_completion(&online_compl); - if (stat2) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0464 lpfc_soft_wwpn attribute set failed to " - "reinit adapter - %d\n", stat2); - return (stat1 || stat2) ? -EIO : count; -} -static DEVICE_ATTR_RW(lpfc_soft_wwpn); - -/** - * lpfc_soft_wwnn_show - Return the cfg soft ww node name for the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the wwnn in hexadecimal. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_soft_wwnn_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - return scnprintf(buf, PAGE_SIZE, "0x%llx\n", - (unsigned long long)phba->cfg_soft_wwnn); -} - -/** - * lpfc_soft_wwnn_store - sets the ww node name of the adapter - * @cdev: class device that is converted into a Scsi_host. - * @buf: contains the ww node name in hexadecimal. - * @count: number of wwnn bytes in buf. - * - * Returns: - * -EINVAL soft wwn not enabled, count is invalid, invalid wwnn byte invalid - * value of count on success - **/ -static ssize_t -lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - unsigned int cnt = count; - u8 wwnn[WWN_SZ]; - int rc; - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if (!phba->soft_wwn_enable) - return -EINVAL; - - rc = lpfc_wwn_set(buf, cnt, wwnn); - if (rc) { - /* Allow wwnn to be set many times, as long as the enable - * is set. However, once the wwpn is set, everything locks. - */ - return rc; - } - - phba->cfg_soft_wwnn = wwn_to_u64(wwnn); - - dev_printk(KERN_NOTICE, &phba->pcidev->dev, - "lpfc%d: soft_wwnn set. Value will take effect upon " - "setting of the soft_wwpn\n", phba->brd_no); - - return count; -} -static DEVICE_ATTR_RW(lpfc_soft_wwnn); /** * lpfc_oas_tgt_show - Return wwpn of target whose luns maybe enabled for @@ -3273,9 +3163,11 @@ static DEVICE_ATTR(lpfc_xlane_lun_status, S_IRUGO, * lpfc_oas_lun_state_set - enable or disable a lun for Optimized Access Storage * (OAS) operations. * @phba: lpfc_hba pointer. - * @ndlp: pointer to fcp target node. + * @vpt_wwpn: wwpn of the vport associated with the returned lun + * @tgt_wwpn: wwpn of the target associated with the returned lun * @lun: the fc lun for setting oas state. * @oas_state: the oas state to be set to the lun. + * @pri: priority * * Returns: * SUCCESS : 0 @@ -3313,6 +3205,7 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[], * @vpt_wwpn: wwpn of the vport associated with the returned lun * @tgt_wwpn: wwpn of the target associated with the returned lun * @lun_status: status of the lun returned lun + * @lun_pri: priority of the lun returned lun * * Returns the first or next lun enabled for OAS operations for the vport/target * specified. If a lun is found, its vport wwpn, target wwpn and status is @@ -3351,6 +3244,7 @@ lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[], * @tgt_wwpn: target wwpn by reference. * @lun: the fc lun for setting oas state. * @oas_state: the oas state to be set to the oas_lun. + * @pri: priority * * This routine enables (OAS_LUN_ENABLE) or disables (OAS_LUN_DISABLE) * a lun for OAS operations. @@ -3425,6 +3319,7 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr, * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. * @buf: buffer for passing information. + * @count: size of the formatting string * * This function sets the OAS state for lun. Before this function is called, * the vport wwpn, target wwpn, and oas state need to be set. @@ -3504,11 +3399,8 @@ unsigned long lpfc_no_hba_reset[MAX_HBAS_NO_RESET] = { module_param_array(lpfc_no_hba_reset, ulong, &lpfc_no_hba_reset_cnt, 0444); MODULE_PARM_DESC(lpfc_no_hba_reset, "WWPN of HBAs that should not be reset"); -LPFC_ATTR(sli_mode, 0, 0, 3, - "SLI mode selector:" - " 0 - auto (SLI-3 if supported)," - " 2 - select SLI-2 even on SLI-3 capable HBAs," - " 3 - select SLI-3"); +LPFC_ATTR(sli_mode, 3, 3, 3, + "SLI mode selector: 3 - select SLI-3"); LPFC_ATTR_R(enable_npiv, 1, 0, 1, "Enable NPIV functionality"); @@ -3517,6 +3409,15 @@ LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2, "FCF Fast failover=1 Priority failover=2"); /* + * lpfc_fcp_wait_abts_rsp: Modifies criteria for reporting completion of + * aborted IO. + * The range is [0,1]. Default value is 0 + * 0, IO completes after ABTS issued (default). + * 1, IO completes after receipt of ABTS response or timeout. + */ +LPFC_ATTR_R(fcp_wait_abts_rsp, 0, 0, 1, "Wait for FCP ABTS completion"); + +/* # lpfc_enable_rrq: Track XRI/OXID reuse after IO failures # 0x0 = disabled, XRI/OXID use not tracked. # 0x1 = XRI/OXID reuse is timed with ratov, RRQ sent. @@ -3697,16 +3598,14 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) shost = lpfc_shost_from_vport(vport); spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->rport) ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; #if (IS_ENABLED(CONFIG_NVME_FC)) - spin_lock(&vport->phba->hbalock); + spin_lock(&ndlp->lock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) remoteport = rport->remoteport; - spin_unlock(&vport->phba->hbalock); + spin_unlock(&ndlp->lock); if (rport && remoteport) nvme_fc_set_remoteport_devloss(remoteport, vport->cfg_devloss_tmo); @@ -3846,8 +3745,8 @@ LPFC_ATTR_R(nvmet_mrq_post, * 3 - register both FCP and NVME * Supported values are [1,3]. Default value is 3 */ -LPFC_ATTR_R(enable_fc4_type, LPFC_ENABLE_BOTH, - LPFC_ENABLE_FCP, LPFC_ENABLE_BOTH, +LPFC_ATTR_R(enable_fc4_type, LPFC_DEF_ENBL_FC4_TYPE, + LPFC_ENABLE_FCP, LPFC_MAX_ENBL_FC4_TYPE, "Enable FC4 Protocol support - FCP / NVME"); /* @@ -3868,12 +3767,9 @@ LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1, /* # lun_queue_depth: This parameter is used to limit the number of outstanding -# commands per FCP LUN. Value range is [1,512]. Default value is 30. -# If this parameter value is greater than 1/8th the maximum number of exchanges -# supported by the HBA port, then the lun queue depth will be reduced to -# 1/8th the maximum number of exchanges. +# commands per FCP LUN. */ -LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512, +LPFC_VPORT_ATTR_R(lun_queue_depth, 64, 1, 512, "Max number of FCP commands we can queue to a specific LUN"); /* @@ -3888,8 +3784,8 @@ lpfc_vport_param_init(tgt_queue_depth, LPFC_MAX_TGT_QDEPTH, LPFC_MIN_TGT_QDEPTH, LPFC_MAX_TGT_QDEPTH); /** - * lpfc_tgt_queue_depth_store: Sets an attribute value. - * @phba: pointer the the adapter structure. + * lpfc_tgt_queue_depth_set: Sets an attribute value. + * @vport: lpfc vport structure pointer. * @val: integer attribute value. * * Description: Sets the parameter to the new value. @@ -4073,9 +3969,11 @@ LPFC_ATTR(topology, 0, 0, 6, "Select Fibre Channel topology"); /** - * lpfc_topology_set - Set the adapters topology field - * @phba: lpfc_hba pointer. - * @val: topology value. + * lpfc_topology_store - Set the adapters topology field + * @dev: class device that is converted into a scsi_host. + * @attr:device attribute, not used. + * @buf: buffer for passing information. + * @count: size of the data buffer. * * Description: * If val is in a valid range then set the adapter's topology field and @@ -4100,6 +3998,7 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, const char *val_buf = buf; int err; uint32_t prev_val; + u8 sli_family, if_type; if (!strncmp(buf, "nolip ", strlen("nolip "))) { nolip = 1; @@ -4123,13 +4022,16 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, /* * The 'topology' is not a configurable parameter if : * - persistent topology enabled - * - G7/G6 with no private loop support + * - ASIC_GEN_NUM >= 0xC, with no private loop support */ - + sli_family = bf_get(lpfc_sli_intf_sli_family, + &phba->sli4_hba.sli_intf); + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); if ((phba->hba_flag & HBA_PERSISTENT_TOPO || - (!phba->sli4_hba.pc_sli4_params.pls && - (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC || - phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC))) && + (!phba->sli4_hba.pc_sli4_params.pls && + (sli_family == LPFC_SLI_INTF_FAMILY_G6 || + if_type == LPFC_SLI_INTF_IF_TYPE_6))) && val == 4) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "3114 Loop mode not supported\n"); @@ -4191,340 +4093,17 @@ lpfc_static_vport_show(struct device *dev, struct device_attribute *attr, */ static DEVICE_ATTR_RO(lpfc_static_vport); -/** - * lpfc_stat_data_ctrl_store - write call back for lpfc_stat_data_ctrl sysfs file - * @dev: Pointer to class device. - * @buf: Data buffer. - * @count: Size of the data buffer. - * - * This function get called when a user write to the lpfc_stat_data_ctrl - * sysfs file. This function parse the command written to the sysfs file - * and take appropriate action. These commands are used for controlling - * driver statistical data collection. - * Following are the command this function handles. - * - * setbucket <bucket_type> <base> <step> - * = Set the latency buckets. - * destroybucket = destroy all the buckets. - * start = start data collection - * stop = stop data collection - * reset = reset the collected data - **/ -static ssize_t -lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; -#define LPFC_MAX_DATA_CTRL_LEN 1024 - static char bucket_data[LPFC_MAX_DATA_CTRL_LEN]; - unsigned long i; - char *str_ptr, *token; - struct lpfc_vport **vports; - struct Scsi_Host *v_shost; - char *bucket_type_str, *base_str, *step_str; - unsigned long base, step, bucket_type; - - if (!strncmp(buf, "setbucket", strlen("setbucket"))) { - if (strlen(buf) > (LPFC_MAX_DATA_CTRL_LEN - 1)) - return -EINVAL; - - strncpy(bucket_data, buf, LPFC_MAX_DATA_CTRL_LEN); - str_ptr = &bucket_data[0]; - /* Ignore this token - this is command token */ - token = strsep(&str_ptr, "\t "); - if (!token) - return -EINVAL; - - bucket_type_str = strsep(&str_ptr, "\t "); - if (!bucket_type_str) - return -EINVAL; - - if (!strncmp(bucket_type_str, "linear", strlen("linear"))) - bucket_type = LPFC_LINEAR_BUCKET; - else if (!strncmp(bucket_type_str, "power2", strlen("power2"))) - bucket_type = LPFC_POWER2_BUCKET; - else - return -EINVAL; - - base_str = strsep(&str_ptr, "\t "); - if (!base_str) - return -EINVAL; - base = simple_strtoul(base_str, NULL, 0); - - step_str = strsep(&str_ptr, "\t "); - if (!step_str) - return -EINVAL; - step = simple_strtoul(step_str, NULL, 0); - if (!step) - return -EINVAL; - - /* Block the data collection for every vport */ - vports = lpfc_create_vport_work_array(phba); - if (vports == NULL) - return -ENOMEM; - - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - v_shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(v_shost->host_lock); - /* Block and reset data collection */ - vports[i]->stat_data_blocked = 1; - if (vports[i]->stat_data_enabled) - lpfc_vport_reset_stat_data(vports[i]); - spin_unlock_irq(v_shost->host_lock); - } - - /* Set the bucket attributes */ - phba->bucket_type = bucket_type; - phba->bucket_base = base; - phba->bucket_step = step; - - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - v_shost = lpfc_shost_from_vport(vports[i]); - - /* Unblock data collection */ - spin_lock_irq(v_shost->host_lock); - vports[i]->stat_data_blocked = 0; - spin_unlock_irq(v_shost->host_lock); - } - lpfc_destroy_vport_work_array(phba, vports); - return strlen(buf); - } - - if (!strncmp(buf, "destroybucket", strlen("destroybucket"))) { - vports = lpfc_create_vport_work_array(phba); - if (vports == NULL) - return -ENOMEM; - - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - v_shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - vports[i]->stat_data_blocked = 1; - lpfc_free_bucket(vport); - vport->stat_data_enabled = 0; - vports[i]->stat_data_blocked = 0; - spin_unlock_irq(shost->host_lock); - } - lpfc_destroy_vport_work_array(phba, vports); - phba->bucket_type = LPFC_NO_BUCKET; - phba->bucket_base = 0; - phba->bucket_step = 0; - return strlen(buf); - } - - if (!strncmp(buf, "start", strlen("start"))) { - /* If no buckets configured return error */ - if (phba->bucket_type == LPFC_NO_BUCKET) - return -EINVAL; - spin_lock_irq(shost->host_lock); - if (vport->stat_data_enabled) { - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - lpfc_alloc_bucket(vport); - vport->stat_data_enabled = 1; - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - - if (!strncmp(buf, "stop", strlen("stop"))) { - spin_lock_irq(shost->host_lock); - if (vport->stat_data_enabled == 0) { - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - lpfc_free_bucket(vport); - vport->stat_data_enabled = 0; - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - - if (!strncmp(buf, "reset", strlen("reset"))) { - if ((phba->bucket_type == LPFC_NO_BUCKET) - || !vport->stat_data_enabled) - return strlen(buf); - spin_lock_irq(shost->host_lock); - vport->stat_data_blocked = 1; - lpfc_vport_reset_stat_data(vport); - vport->stat_data_blocked = 0; - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - return -EINVAL; -} - - -/** - * lpfc_stat_data_ctrl_show - Read function for lpfc_stat_data_ctrl sysfs file - * @dev: Pointer to class device object. - * @buf: Data buffer. - * - * This function is the read call back function for - * lpfc_stat_data_ctrl sysfs file. This function report the - * current statistical data collection state. - **/ -static ssize_t -lpfc_stat_data_ctrl_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int index = 0; - int i; - char *bucket_type; - unsigned long bucket_value; - - switch (phba->bucket_type) { - case LPFC_LINEAR_BUCKET: - bucket_type = "linear"; - break; - case LPFC_POWER2_BUCKET: - bucket_type = "power2"; - break; - default: - bucket_type = "No Bucket"; - break; - } - - sprintf(&buf[index], "Statistical Data enabled :%d, " - "blocked :%d, Bucket type :%s, Bucket base :%d," - " Bucket step :%d\nLatency Ranges :", - vport->stat_data_enabled, vport->stat_data_blocked, - bucket_type, phba->bucket_base, phba->bucket_step); - index = strlen(buf); - if (phba->bucket_type != LPFC_NO_BUCKET) { - for (i = 0; i < LPFC_MAX_BUCKET_COUNT; i++) { - if (phba->bucket_type == LPFC_LINEAR_BUCKET) - bucket_value = phba->bucket_base + - phba->bucket_step * i; - else - bucket_value = phba->bucket_base + - (1 << i) * phba->bucket_step; - - if (index + 10 > PAGE_SIZE) - break; - sprintf(&buf[index], "%08ld ", bucket_value); - index = strlen(buf); - } - } - sprintf(&buf[index], "\n"); - return strlen(buf); -} - -/* - * Sysfs attribute to control the statistical data collection. - */ -static DEVICE_ATTR_RW(lpfc_stat_data_ctrl); - -/* - * lpfc_drvr_stat_data: sysfs attr to get driver statistical data. - */ - -/* - * Each Bucket takes 11 characters and 1 new line + 17 bytes WWN - * for each target. - */ -#define STAT_DATA_SIZE_PER_TARGET(NUM_BUCKETS) ((NUM_BUCKETS) * 11 + 18) -#define MAX_STAT_DATA_SIZE_PER_TARGET \ - STAT_DATA_SIZE_PER_TARGET(LPFC_MAX_BUCKET_COUNT) - - -/** - * sysfs_drvr_stat_data_read - Read function for lpfc_drvr_stat_data attribute - * @filp: sysfs file - * @kobj: Pointer to the kernel object - * @bin_attr: Attribute object - * @buff: Buffer pointer - * @off: File offset - * @count: Buffer size - * - * This function is the read call back function for lpfc_drvr_stat_data - * sysfs file. This function export the statistical data to user - * applications. - **/ -static ssize_t -sysfs_drvr_stat_data_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, - kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int i = 0, index = 0; - unsigned long nport_index; - struct lpfc_nodelist *ndlp = NULL; - nport_index = (unsigned long)off / - MAX_STAT_DATA_SIZE_PER_TARGET; - - if (!vport->stat_data_enabled || vport->stat_data_blocked - || (phba->bucket_type == LPFC_NO_BUCKET)) - return 0; - - spin_lock_irq(shost->host_lock); - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp) || !ndlp->lat_data) - continue; - - if (nport_index > 0) { - nport_index--; - continue; - } - - if ((index + MAX_STAT_DATA_SIZE_PER_TARGET) - > count) - break; - - if (!ndlp->lat_data) - continue; - - /* Print the WWN */ - sprintf(&buf[index], "%02x%02x%02x%02x%02x%02x%02x%02x:", - ndlp->nlp_portname.u.wwn[0], - ndlp->nlp_portname.u.wwn[1], - ndlp->nlp_portname.u.wwn[2], - ndlp->nlp_portname.u.wwn[3], - ndlp->nlp_portname.u.wwn[4], - ndlp->nlp_portname.u.wwn[5], - ndlp->nlp_portname.u.wwn[6], - ndlp->nlp_portname.u.wwn[7]); - - index = strlen(buf); - - for (i = 0; i < LPFC_MAX_BUCKET_COUNT; i++) { - sprintf(&buf[index], "%010u,", - ndlp->lat_data[i].cmd_count); - index = strlen(buf); - } - sprintf(&buf[index], "\n"); - index = strlen(buf); - } - spin_unlock_irq(shost->host_lock); - return index; -} - -static struct bin_attribute sysfs_drvr_stat_data_attr = { - .attr = { - .name = "lpfc_drvr_stat_data", - .mode = S_IRUSR, - }, - .size = LPFC_MAX_TARGET * MAX_STAT_DATA_SIZE_PER_TARGET, - .read = sysfs_drvr_stat_data_read, - .write = NULL, -}; - /* # lpfc_link_speed: Link speed selection for initializing the Fibre Channel # connection. # Value range is [0,16]. Default value is 0. */ /** - * lpfc_link_speed_set - Set the adapters link speed - * @phba: lpfc_hba pointer. - * @val: link speed value. + * lpfc_link_speed_store - Set the adapters link speed + * @dev: Pointer to class device. + * @attr: Unused. + * @buf: Data buffer. + * @count: Size of the data buffer. * * Description: * If val is in a valid range then set the adapter's link speed field and @@ -4783,7 +4362,7 @@ static DEVICE_ATTR_RW(lpfc_aer_support); * Description: * If the @buf contains 1 and the device currently has the AER support * enabled, then invokes the kernel AER helper routine - * pci_cleanup_aer_uncorrect_error_status to clean up the uncorrectable + * pci_aer_clear_nonfatal_status() to clean up the uncorrectable * error status register. * * Notes: @@ -4809,7 +4388,7 @@ lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr, return -EINVAL; if (phba->hba_flag & HBA_AER_ENABLED) - rc = pci_cleanup_aer_uncorrect_error_status(phba->pcidev); + rc = pci_aer_clear_nonfatal_status(phba->pcidev); if (rc == 0) return strlen(buf); @@ -4921,7 +4500,7 @@ lpfc_param_show(sriov_nr_virtfn) static DEVICE_ATTR_RW(lpfc_sriov_nr_virtfn); /** - * lpfc_request_firmware_store - Request for Linux generic firmware upgrade + * lpfc_request_firmware_upgrade_store - Request for Linux generic firmware upgrade * * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. @@ -4943,7 +4522,7 @@ lpfc_request_firmware_upgrade_store(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; struct lpfc_hba *phba = vport->phba; - int val = 0, rc = -EINVAL; + int val = 0, rc; /* Sanity check on user data */ if (!isdigit(buf[0])) @@ -5275,8 +4854,8 @@ lpfc_cq_max_proc_limit_init(struct lpfc_hba *phba, int val) } lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0371 "LPFC_DRIVER_NAME"_cq_max_proc_limit: " - "%d out of range, using default\n", + "0371 lpfc_cq_max_proc_limit: %d out of range, using " + "default\n", phba->cfg_cq_max_proc_limit); return 0; @@ -5285,7 +4864,7 @@ lpfc_cq_max_proc_limit_init(struct lpfc_hba *phba, int val) static DEVICE_ATTR_RW(lpfc_cq_max_proc_limit); /** - * lpfc_state_show - Display current driver CPU affinity + * lpfc_fcp_cpu_map_show - Display current driver CPU affinity * @dev: class converted to a Scsi_host structure. * @attr: device attribute, not used. * @buf: on return contains text describing the state of the link. @@ -5407,8 +4986,7 @@ static ssize_t lpfc_fcp_cpu_map_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int status = -EINVAL; - return status; + return -EINVAL; } /* @@ -5471,9 +5049,9 @@ LPFC_VPORT_ATTR_R(fcp_class, 3, 2, 3, /* # lpfc_use_adisc: Use ADISC for FCP rediscovery instead of PLOGI. Value range -# is [0,1]. Default value is 0. +# is [0,1]. Default value is 1. */ -LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1, +LPFC_VPORT_ATTR_RW(use_adisc, 1, 0, 1, "Use ADISC on rediscovery to authenticate FCP devices"); /* @@ -5533,8 +5111,6 @@ lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val) spin_lock_irq(shost->host_lock); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; @@ -5770,17 +5346,69 @@ LPFC_ATTR_R(hdw_queue, LPFC_HBA_HDWQ_MIN, LPFC_HBA_HDWQ_MAX, "Set the number of I/O Hardware Queues"); -static inline void -lpfc_assign_default_irq_numa(struct lpfc_hba *phba) +#if IS_ENABLED(CONFIG_X86) +/** + * lpfc_cpumask_irq_mode_init - initalizes cpumask of phba based on + * irq_chann_mode + * @phba: Pointer to HBA context object. + **/ +static void +lpfc_cpumask_irq_mode_init(struct lpfc_hba *phba) +{ + unsigned int cpu, first_cpu, numa_node = NUMA_NO_NODE; + const struct cpumask *sibling_mask; + struct cpumask *aff_mask = &phba->sli4_hba.irq_aff_mask; + + cpumask_clear(aff_mask); + + if (phba->irq_chann_mode == NUMA_MODE) { + /* Check if we're a NUMA architecture */ + numa_node = dev_to_node(&phba->pcidev->dev); + if (numa_node == NUMA_NO_NODE) { + phba->irq_chann_mode = NORMAL_MODE; + return; + } + } + + for_each_possible_cpu(cpu) { + switch (phba->irq_chann_mode) { + case NUMA_MODE: + if (cpu_to_node(cpu) == numa_node) + cpumask_set_cpu(cpu, aff_mask); + break; + case NHT_MODE: + sibling_mask = topology_sibling_cpumask(cpu); + first_cpu = cpumask_first(sibling_mask); + if (first_cpu < nr_cpu_ids) + cpumask_set_cpu(first_cpu, aff_mask); + break; + default: + break; + } + } +} +#endif + +static void +lpfc_assign_default_irq_chann(struct lpfc_hba *phba) { #if IS_ENABLED(CONFIG_X86) - /* If AMD architecture, then default is LPFC_IRQ_CHANN_NUMA */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - phba->cfg_irq_numa = 1; - else - phba->cfg_irq_numa = 0; + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + /* If AMD architecture, then default is NUMA_MODE */ + phba->irq_chann_mode = NUMA_MODE; + break; + case X86_VENDOR_INTEL: + /* If Intel architecture, then default is no hyperthread mode */ + phba->irq_chann_mode = NHT_MODE; + break; + default: + phba->irq_chann_mode = NORMAL_MODE; + break; + } + lpfc_cpumask_irq_mode_init(phba); #else - phba->cfg_irq_numa = 0; + phba->irq_chann_mode = NORMAL_MODE; #endif } @@ -5792,6 +5420,7 @@ lpfc_assign_default_irq_numa(struct lpfc_hba *phba) * * 0 = Configure number of IRQ Channels to: * if AMD architecture, number of CPUs on HBA's NUMA node + * if Intel architecture, number of physical CPUs. * otherwise, number of active CPUs. * [1,256] = Manually specify how many IRQ Channels to use. * @@ -5817,35 +5446,46 @@ MODULE_PARM_DESC(lpfc_irq_chann, "Set number of interrupt vectors to allocate"); static int lpfc_irq_chann_init(struct lpfc_hba *phba, uint32_t val) { - const struct cpumask *numa_mask; + const struct cpumask *aff_mask; if (phba->cfg_use_msi != 2) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "8532 use_msi = %u ignoring cfg_irq_numa\n", phba->cfg_use_msi); - phba->cfg_irq_numa = 0; - phba->cfg_irq_chann = LPFC_IRQ_CHANN_MIN; + phba->irq_chann_mode = NORMAL_MODE; + phba->cfg_irq_chann = LPFC_IRQ_CHANN_DEF; return 0; } /* Check if default setting was passed */ - if (val == LPFC_IRQ_CHANN_DEF) - lpfc_assign_default_irq_numa(phba); + if (val == LPFC_IRQ_CHANN_DEF && + phba->cfg_hdw_queue == LPFC_HBA_HDWQ_DEF && + phba->sli_rev == LPFC_SLI_REV4) + lpfc_assign_default_irq_chann(phba); - if (phba->cfg_irq_numa) { - numa_mask = &phba->sli4_hba.numa_mask; + if (phba->irq_chann_mode != NORMAL_MODE) { + aff_mask = &phba->sli4_hba.irq_aff_mask; - if (cpumask_empty(numa_mask)) { + if (cpumask_empty(aff_mask)) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "8533 Could not identify NUMA node, " - "ignoring cfg_irq_numa\n"); - phba->cfg_irq_numa = 0; - phba->cfg_irq_chann = LPFC_IRQ_CHANN_MIN; + "8533 Could not identify CPUS for " + "mode %d, ignoring\n", + phba->irq_chann_mode); + phba->irq_chann_mode = NORMAL_MODE; + phba->cfg_irq_chann = LPFC_IRQ_CHANN_DEF; } else { - phba->cfg_irq_chann = cpumask_weight(numa_mask); + phba->cfg_irq_chann = cpumask_weight(aff_mask); + + /* If no hyperthread mode, then set hdwq count to + * aff_mask weight as well + */ + if (phba->irq_chann_mode == NHT_MODE) + phba->cfg_hdw_queue = phba->cfg_irq_chann; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "8543 lpfc_irq_chann set to %u " - "(numa)\n", phba->cfg_irq_chann); + "(mode: %d)\n", phba->cfg_irq_chann, + phba->irq_chann_mode); } } else { if (val > LPFC_IRQ_CHANN_MAX) { @@ -5856,10 +5496,15 @@ lpfc_irq_chann_init(struct lpfc_hba *phba, uint32_t val) val, LPFC_IRQ_CHANN_MIN, LPFC_IRQ_CHANN_MAX); - phba->cfg_irq_chann = LPFC_IRQ_CHANN_MIN; + phba->cfg_irq_chann = LPFC_IRQ_CHANN_DEF; return -EINVAL; } - phba->cfg_irq_chann = val; + if (phba->sli_rev == LPFC_SLI_REV4) { + phba->cfg_irq_chann = val; + } else { + phba->cfg_irq_chann = 2; + phba->cfg_hdw_queue = 1; + } } return 0; @@ -5927,7 +5572,7 @@ LPFC_ATTR_RW(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature."); LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support"); /* -# lpfc_prot_mask: i +# lpfc_prot_mask: # - Bit mask of host protection capabilities used to register with the # SCSI mid-layer # - Only meaningful if BG is turned on (lpfc_enable_bg=1). @@ -5952,7 +5597,7 @@ LPFC_ATTR(prot_mask, "T10-DIF host protection capabilities mask"); /* -# lpfc_prot_guard: i +# lpfc_prot_guard: # - Bit mask of protection guard types to register with the SCSI mid-layer # - Guard types are currently either 1) T10-DIF CRC 2) IP checksum # - Allows you to ultimately specify which profiles to use @@ -6014,7 +5659,8 @@ lpfc_sg_seg_cnt_show(struct device *dev, struct device_attribute *attr, len = scnprintf(buf, PAGE_SIZE, "SGL sz: %d total SGEs: %d\n", phba->cfg_sg_dma_buf_size, phba->cfg_total_seg_cnt); - len += scnprintf(buf + len, PAGE_SIZE, "Cfg: %d SCSI: %d NVME: %d\n", + len += scnprintf(buf + len, PAGE_SIZE - len, + "Cfg: %d SCSI: %d NVME: %d\n", phba->cfg_sg_seg_cnt, phba->cfg_scsi_seg_cnt, phba->cfg_nvme_seg_cnt); return len; @@ -6044,8 +5690,8 @@ lpfc_sg_seg_cnt_init(struct lpfc_hba *phba, int val) return 0; } lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0409 "LPFC_DRIVER_NAME"_sg_seg_cnt attribute cannot " - "be set to %d, allowed range is [%d, %d]\n", + "0409 lpfc_sg_seg_cnt attribute cannot be set to %d, " + "allowed range is [%d, %d]\n", val, LPFC_MIN_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT); phba->cfg_sg_seg_cnt = LPFC_DEFAULT_SG_SEG_CNT; return -EINVAL; @@ -6138,6 +5784,19 @@ LPFC_ATTR_RW(ras_fwlog_func, 0, 0, 7, "Firmware Logging Enabled on Function"); */ LPFC_BBCR_ATTR_RW(enable_bbcr, 1, 0, 1, "Enable BBC Recovery"); +/* Signaling module parameters */ +int lpfc_fabric_cgn_frequency = 100; /* 100 ms default */ +module_param(lpfc_fabric_cgn_frequency, int, 0444); +MODULE_PARM_DESC(lpfc_fabric_cgn_frequency, "Congestion signaling fabric freq"); + +int lpfc_acqe_cgn_frequency = 10; /* 10 sec default */ +module_param(lpfc_acqe_cgn_frequency, int, 0444); +MODULE_PARM_DESC(lpfc_acqe_cgn_frequency, "Congestion signaling ACQE freq"); + +int lpfc_use_cgn_signal = 1; /* 0 - only use FPINs, 1 - Use signals if avail */ +module_param(lpfc_use_cgn_signal, int, 0444); +MODULE_PARM_DESC(lpfc_use_cgn_signal, "Use Congestion signaling if available"); + /* * lpfc_enable_dpp: Enable DPP on G7 * 0 = DPP on G7 disabled @@ -6146,157 +5805,219 @@ LPFC_BBCR_ATTR_RW(enable_bbcr, 1, 0, 1, "Enable BBC Recovery"); */ LPFC_ATTR_RW(enable_dpp, 1, 0, 1, "Enable Direct Packet Push"); -struct device_attribute *lpfc_hba_attrs[] = { - &dev_attr_nvme_info, - &dev_attr_scsi_stat, - &dev_attr_bg_info, - &dev_attr_bg_guard_err, - &dev_attr_bg_apptag_err, - &dev_attr_bg_reftag_err, - &dev_attr_info, - &dev_attr_serialnum, - &dev_attr_modeldesc, - &dev_attr_modelname, - &dev_attr_programtype, - &dev_attr_portnum, - &dev_attr_fwrev, - &dev_attr_hdw, - &dev_attr_option_rom_version, - &dev_attr_link_state, - &dev_attr_num_discovered_ports, - &dev_attr_menlo_mgmt_mode, - &dev_attr_lpfc_drvr_version, - &dev_attr_lpfc_enable_fip, - &dev_attr_lpfc_temp_sensor, - &dev_attr_lpfc_log_verbose, - &dev_attr_lpfc_lun_queue_depth, - &dev_attr_lpfc_tgt_queue_depth, - &dev_attr_lpfc_hba_queue_depth, - &dev_attr_lpfc_peer_port_login, - &dev_attr_lpfc_nodev_tmo, - &dev_attr_lpfc_devloss_tmo, - &dev_attr_lpfc_enable_fc4_type, - &dev_attr_lpfc_fcp_class, - &dev_attr_lpfc_use_adisc, - &dev_attr_lpfc_first_burst_size, - &dev_attr_lpfc_ack0, - &dev_attr_lpfc_xri_rebalancing, - &dev_attr_lpfc_topology, - &dev_attr_lpfc_scan_down, - &dev_attr_lpfc_link_speed, - &dev_attr_lpfc_fcp_io_sched, - &dev_attr_lpfc_ns_query, - &dev_attr_lpfc_fcp2_no_tgt_reset, - &dev_attr_lpfc_cr_delay, - &dev_attr_lpfc_cr_count, - &dev_attr_lpfc_multi_ring_support, - &dev_attr_lpfc_multi_ring_rctl, - &dev_attr_lpfc_multi_ring_type, - &dev_attr_lpfc_fdmi_on, - &dev_attr_lpfc_enable_SmartSAN, - &dev_attr_lpfc_max_luns, - &dev_attr_lpfc_enable_npiv, - &dev_attr_lpfc_fcf_failover_policy, - &dev_attr_lpfc_enable_rrq, - &dev_attr_nport_evt_cnt, - &dev_attr_board_mode, - &dev_attr_max_vpi, - &dev_attr_used_vpi, - &dev_attr_max_rpi, - &dev_attr_used_rpi, - &dev_attr_max_xri, - &dev_attr_used_xri, - &dev_attr_npiv_info, - &dev_attr_issue_reset, - &dev_attr_lpfc_poll, - &dev_attr_lpfc_poll_tmo, - &dev_attr_lpfc_task_mgmt_tmo, - &dev_attr_lpfc_use_msi, - &dev_attr_lpfc_nvme_oas, - &dev_attr_lpfc_nvme_embed_cmd, - &dev_attr_lpfc_fcp_imax, - &dev_attr_lpfc_force_rscn, - &dev_attr_lpfc_cq_poll_threshold, - &dev_attr_lpfc_cq_max_proc_limit, - &dev_attr_lpfc_fcp_cpu_map, - &dev_attr_lpfc_fcp_mq_threshold, - &dev_attr_lpfc_hdw_queue, - &dev_attr_lpfc_irq_chann, - &dev_attr_lpfc_suppress_rsp, - &dev_attr_lpfc_nvmet_mrq, - &dev_attr_lpfc_nvmet_mrq_post, - &dev_attr_lpfc_nvme_enable_fb, - &dev_attr_lpfc_nvmet_fb_size, - &dev_attr_lpfc_enable_bg, - &dev_attr_lpfc_soft_wwnn, - &dev_attr_lpfc_soft_wwpn, - &dev_attr_lpfc_soft_wwn_enable, - &dev_attr_lpfc_enable_hba_reset, - &dev_attr_lpfc_enable_hba_heartbeat, - &dev_attr_lpfc_EnableXLane, - &dev_attr_lpfc_XLanePriority, - &dev_attr_lpfc_xlane_lun, - &dev_attr_lpfc_xlane_tgt, - &dev_attr_lpfc_xlane_vpt, - &dev_attr_lpfc_xlane_lun_state, - &dev_attr_lpfc_xlane_lun_status, - &dev_attr_lpfc_xlane_priority, - &dev_attr_lpfc_sg_seg_cnt, - &dev_attr_lpfc_max_scsicmpl_time, - &dev_attr_lpfc_stat_data_ctrl, - &dev_attr_lpfc_aer_support, - &dev_attr_lpfc_aer_state_cleanup, - &dev_attr_lpfc_sriov_nr_virtfn, - &dev_attr_lpfc_req_fw_upgrade, - &dev_attr_lpfc_suppress_link_up, - &dev_attr_iocb_hw, - &dev_attr_pls, - &dev_attr_pt, - &dev_attr_txq_hw, - &dev_attr_txcmplq_hw, - &dev_attr_lpfc_fips_level, - &dev_attr_lpfc_fips_rev, - &dev_attr_lpfc_dss, - &dev_attr_lpfc_sriov_hw_max_virtfn, - &dev_attr_protocol, - &dev_attr_lpfc_xlane_supported, - &dev_attr_lpfc_enable_mds_diags, - &dev_attr_lpfc_ras_fwlog_buffsize, - &dev_attr_lpfc_ras_fwlog_level, - &dev_attr_lpfc_ras_fwlog_func, - &dev_attr_lpfc_enable_bbcr, - &dev_attr_lpfc_enable_dpp, +/* + * lpfc_enable_mi: Enable FDMI MIB + * 0 = disabled + * 1 = enabled (default) + * Value range is [0,1]. + */ +LPFC_ATTR_R(enable_mi, 1, 0, 1, "Enable MI"); + +/* + * lpfc_max_vmid: Maximum number of VMs to be tagged. This is valid only if + * either vmid_app_header or vmid_priority_tagging is enabled. + * 4 - 255 = vmid support enabled for 4-255 VMs + * Value range is [4,255]. + */ +LPFC_ATTR_RW(max_vmid, LPFC_MIN_VMID, LPFC_MIN_VMID, LPFC_MAX_VMID, + "Maximum number of VMs supported"); + +/* + * lpfc_vmid_inactivity_timeout: Inactivity timeout duration in hours + * 0 = Timeout is disabled + * Value range is [0,24]. + */ +LPFC_ATTR_RW(vmid_inactivity_timeout, 4, 0, 24, + "Inactivity timeout in hours"); + +/* + * lpfc_vmid_app_header: Enable App Header VMID support + * 0 = Support is disabled (default) + * 1 = Support is enabled + * Value range is [0,1]. + */ +LPFC_ATTR_RW(vmid_app_header, LPFC_VMID_APP_HEADER_DISABLE, + LPFC_VMID_APP_HEADER_DISABLE, LPFC_VMID_APP_HEADER_ENABLE, + "Enable App Header VMID support"); + +/* + * lpfc_vmid_priority_tagging: Enable Priority Tagging VMID support + * 0 = Support is disabled (default) + * 1 = Allow supported targets only + * 2 = Allow all targets + * Value range is [0,2]. + */ +LPFC_ATTR_RW(vmid_priority_tagging, LPFC_VMID_PRIO_TAG_DISABLE, + LPFC_VMID_PRIO_TAG_DISABLE, + LPFC_VMID_PRIO_TAG_ALL_TARGETS, + "Enable Priority Tagging VMID support"); + +static struct attribute *lpfc_hba_attrs[] = { + &dev_attr_nvme_info.attr, + &dev_attr_scsi_stat.attr, + &dev_attr_bg_info.attr, + &dev_attr_bg_guard_err.attr, + &dev_attr_bg_apptag_err.attr, + &dev_attr_bg_reftag_err.attr, + &dev_attr_info.attr, + &dev_attr_serialnum.attr, + &dev_attr_modeldesc.attr, + &dev_attr_modelname.attr, + &dev_attr_programtype.attr, + &dev_attr_portnum.attr, + &dev_attr_fwrev.attr, + &dev_attr_hdw.attr, + &dev_attr_option_rom_version.attr, + &dev_attr_link_state.attr, + &dev_attr_num_discovered_ports.attr, + &dev_attr_lpfc_drvr_version.attr, + &dev_attr_lpfc_enable_fip.attr, + &dev_attr_lpfc_temp_sensor.attr, + &dev_attr_lpfc_log_verbose.attr, + &dev_attr_lpfc_lun_queue_depth.attr, + &dev_attr_lpfc_tgt_queue_depth.attr, + &dev_attr_lpfc_hba_queue_depth.attr, + &dev_attr_lpfc_peer_port_login.attr, + &dev_attr_lpfc_nodev_tmo.attr, + &dev_attr_lpfc_devloss_tmo.attr, + &dev_attr_lpfc_enable_fc4_type.attr, + &dev_attr_lpfc_fcp_class.attr, + &dev_attr_lpfc_use_adisc.attr, + &dev_attr_lpfc_first_burst_size.attr, + &dev_attr_lpfc_ack0.attr, + &dev_attr_lpfc_xri_rebalancing.attr, + &dev_attr_lpfc_topology.attr, + &dev_attr_lpfc_scan_down.attr, + &dev_attr_lpfc_link_speed.attr, + &dev_attr_lpfc_fcp_io_sched.attr, + &dev_attr_lpfc_ns_query.attr, + &dev_attr_lpfc_fcp2_no_tgt_reset.attr, + &dev_attr_lpfc_cr_delay.attr, + &dev_attr_lpfc_cr_count.attr, + &dev_attr_lpfc_multi_ring_support.attr, + &dev_attr_lpfc_multi_ring_rctl.attr, + &dev_attr_lpfc_multi_ring_type.attr, + &dev_attr_lpfc_fdmi_on.attr, + &dev_attr_lpfc_enable_SmartSAN.attr, + &dev_attr_lpfc_max_luns.attr, + &dev_attr_lpfc_enable_npiv.attr, + &dev_attr_lpfc_fcf_failover_policy.attr, + &dev_attr_lpfc_enable_rrq.attr, + &dev_attr_lpfc_fcp_wait_abts_rsp.attr, + &dev_attr_nport_evt_cnt.attr, + &dev_attr_board_mode.attr, + &dev_attr_max_vpi.attr, + &dev_attr_used_vpi.attr, + &dev_attr_max_rpi.attr, + &dev_attr_used_rpi.attr, + &dev_attr_max_xri.attr, + &dev_attr_used_xri.attr, + &dev_attr_npiv_info.attr, + &dev_attr_issue_reset.attr, + &dev_attr_lpfc_poll.attr, + &dev_attr_lpfc_poll_tmo.attr, + &dev_attr_lpfc_task_mgmt_tmo.attr, + &dev_attr_lpfc_use_msi.attr, + &dev_attr_lpfc_nvme_oas.attr, + &dev_attr_lpfc_nvme_embed_cmd.attr, + &dev_attr_lpfc_fcp_imax.attr, + &dev_attr_lpfc_force_rscn.attr, + &dev_attr_lpfc_cq_poll_threshold.attr, + &dev_attr_lpfc_cq_max_proc_limit.attr, + &dev_attr_lpfc_fcp_cpu_map.attr, + &dev_attr_lpfc_fcp_mq_threshold.attr, + &dev_attr_lpfc_hdw_queue.attr, + &dev_attr_lpfc_irq_chann.attr, + &dev_attr_lpfc_suppress_rsp.attr, + &dev_attr_lpfc_nvmet_mrq.attr, + &dev_attr_lpfc_nvmet_mrq_post.attr, + &dev_attr_lpfc_nvme_enable_fb.attr, + &dev_attr_lpfc_nvmet_fb_size.attr, + &dev_attr_lpfc_enable_bg.attr, + &dev_attr_lpfc_enable_hba_reset.attr, + &dev_attr_lpfc_enable_hba_heartbeat.attr, + &dev_attr_lpfc_EnableXLane.attr, + &dev_attr_lpfc_XLanePriority.attr, + &dev_attr_lpfc_xlane_lun.attr, + &dev_attr_lpfc_xlane_tgt.attr, + &dev_attr_lpfc_xlane_vpt.attr, + &dev_attr_lpfc_xlane_lun_state.attr, + &dev_attr_lpfc_xlane_lun_status.attr, + &dev_attr_lpfc_xlane_priority.attr, + &dev_attr_lpfc_sg_seg_cnt.attr, + &dev_attr_lpfc_max_scsicmpl_time.attr, + &dev_attr_lpfc_aer_support.attr, + &dev_attr_lpfc_aer_state_cleanup.attr, + &dev_attr_lpfc_sriov_nr_virtfn.attr, + &dev_attr_lpfc_req_fw_upgrade.attr, + &dev_attr_lpfc_suppress_link_up.attr, + &dev_attr_iocb_hw.attr, + &dev_attr_pls.attr, + &dev_attr_pt.attr, + &dev_attr_txq_hw.attr, + &dev_attr_txcmplq_hw.attr, + &dev_attr_lpfc_sriov_hw_max_virtfn.attr, + &dev_attr_protocol.attr, + &dev_attr_lpfc_xlane_supported.attr, + &dev_attr_lpfc_enable_mds_diags.attr, + &dev_attr_lpfc_ras_fwlog_buffsize.attr, + &dev_attr_lpfc_ras_fwlog_level.attr, + &dev_attr_lpfc_ras_fwlog_func.attr, + &dev_attr_lpfc_enable_bbcr.attr, + &dev_attr_lpfc_enable_dpp.attr, + &dev_attr_lpfc_enable_mi.attr, + &dev_attr_cmf_info.attr, + &dev_attr_lpfc_max_vmid.attr, + &dev_attr_lpfc_vmid_inactivity_timeout.attr, + &dev_attr_lpfc_vmid_app_header.attr, + &dev_attr_lpfc_vmid_priority_tagging.attr, NULL, }; -struct device_attribute *lpfc_vport_attrs[] = { - &dev_attr_info, - &dev_attr_link_state, - &dev_attr_num_discovered_ports, - &dev_attr_lpfc_drvr_version, - &dev_attr_lpfc_log_verbose, - &dev_attr_lpfc_lun_queue_depth, - &dev_attr_lpfc_tgt_queue_depth, - &dev_attr_lpfc_nodev_tmo, - &dev_attr_lpfc_devloss_tmo, - &dev_attr_lpfc_hba_queue_depth, - &dev_attr_lpfc_peer_port_login, - &dev_attr_lpfc_restrict_login, - &dev_attr_lpfc_fcp_class, - &dev_attr_lpfc_use_adisc, - &dev_attr_lpfc_first_burst_size, - &dev_attr_lpfc_max_luns, - &dev_attr_nport_evt_cnt, - &dev_attr_npiv_info, - &dev_attr_lpfc_enable_da_id, - &dev_attr_lpfc_max_scsicmpl_time, - &dev_attr_lpfc_stat_data_ctrl, - &dev_attr_lpfc_static_vport, - &dev_attr_lpfc_fips_level, - &dev_attr_lpfc_fips_rev, +static const struct attribute_group lpfc_hba_attr_group = { + .attrs = lpfc_hba_attrs +}; + +const struct attribute_group *lpfc_hba_groups[] = { + &lpfc_hba_attr_group, + NULL +}; + +static struct attribute *lpfc_vport_attrs[] = { + &dev_attr_info.attr, + &dev_attr_link_state.attr, + &dev_attr_num_discovered_ports.attr, + &dev_attr_lpfc_drvr_version.attr, + &dev_attr_lpfc_log_verbose.attr, + &dev_attr_lpfc_lun_queue_depth.attr, + &dev_attr_lpfc_tgt_queue_depth.attr, + &dev_attr_lpfc_nodev_tmo.attr, + &dev_attr_lpfc_devloss_tmo.attr, + &dev_attr_lpfc_hba_queue_depth.attr, + &dev_attr_lpfc_peer_port_login.attr, + &dev_attr_lpfc_restrict_login.attr, + &dev_attr_lpfc_fcp_class.attr, + &dev_attr_lpfc_use_adisc.attr, + &dev_attr_lpfc_first_burst_size.attr, + &dev_attr_lpfc_max_luns.attr, + &dev_attr_nport_evt_cnt.attr, + &dev_attr_npiv_info.attr, + &dev_attr_lpfc_enable_da_id.attr, + &dev_attr_lpfc_max_scsicmpl_time.attr, + &dev_attr_lpfc_static_vport.attr, + &dev_attr_cmf_info.attr, NULL, }; +static const struct attribute_group lpfc_vport_attr_group = { + .attrs = lpfc_vport_attrs +}; + +const struct attribute_group *lpfc_vport_groups[] = { + &lpfc_vport_attr_group, + NULL +}; + /** * sysfs_ctlreg_write - Write method for writing to ctlreg * @filp: open sysfs file @@ -6495,17 +6216,14 @@ lpfc_alloc_sysfs_attr(struct lpfc_vport *vport) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); int error; - error = sysfs_create_bin_file(&shost->shost_dev.kobj, - &sysfs_drvr_stat_data_attr); - /* Virtual ports do not need ctrl_reg and mbox */ - if (error || vport->port_type == LPFC_NPIV_PORT) - goto out; + if (vport->port_type == LPFC_NPIV_PORT) + return 0; error = sysfs_create_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); if (error) - goto out_remove_stat_attr; + goto out; error = sysfs_create_bin_file(&shost->shost_dev.kobj, &sysfs_mbox_attr); @@ -6515,9 +6233,6 @@ lpfc_alloc_sysfs_attr(struct lpfc_vport *vport) return 0; out_remove_ctlreg_attr: sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); -out_remove_stat_attr: - sysfs_remove_bin_file(&shost->shost_dev.kobj, - &sysfs_drvr_stat_data_attr); out: return error; } @@ -6530,8 +6245,7 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *vport) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - sysfs_remove_bin_file(&shost->shost_dev.kobj, - &sysfs_drvr_stat_data_attr); + /* Virtual ports do not need ctrl_reg and mbox */ if (vport->port_type == LPFC_NPIV_PORT) return; @@ -6685,15 +6399,24 @@ lpfc_get_host_speed(struct Scsi_Host *shost) case LPFC_LINK_SPEED_128GHZ: fc_host_speed(shost) = FC_PORTSPEED_128GBIT; break; + case LPFC_LINK_SPEED_256GHZ: + fc_host_speed(shost) = FC_PORTSPEED_256GBIT; + break; default: fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; } } else if (lpfc_is_link_up(phba) && (phba->hba_flag & HBA_FCOE_MODE)) { switch (phba->fc_linkspeed) { + case LPFC_ASYNC_LINK_SPEED_1GBPS: + fc_host_speed(shost) = FC_PORTSPEED_1GBIT; + break; case LPFC_ASYNC_LINK_SPEED_10GBPS: fc_host_speed(shost) = FC_PORTSPEED_10GBIT; break; + case LPFC_ASYNC_LINK_SPEED_20GBPS: + fc_host_speed(shost) = FC_PORTSPEED_20GBIT; + break; case LPFC_ASYNC_LINK_SPEED_25GBPS: fc_host_speed(shost) = FC_PORTSPEED_25GBIT; break; @@ -6787,31 +6510,52 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->ctx_buf = NULL; pmboxq->vport = vport; - if (vport->fc_flag & FC_OFFLINE_MODE) + if (vport->fc_flag & FC_OFFLINE_MODE) { rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) + if (rc != MBX_SUCCESS) { mempool_free(pmboxq, phba->mbox_mem_pool); - return NULL; + return NULL; + } + } else { + rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) + mempool_free(pmboxq, phba->mbox_mem_pool); + return NULL; + } } memset(hs, 0, sizeof (struct fc_host_statistics)); hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt; + hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt; + /* - * The MBX_READ_STATUS returns tx_k_bytes which has to - * converted to words + * The MBX_READ_STATUS returns tx_k_bytes which has to be + * converted to words. + * + * Check if extended byte flag is set, to know when to collect upper + * bits of 64 bit wide statistics counter. */ - hs->tx_words = (uint64_t) - ((uint64_t)pmb->un.varRdStatus.xmitByteCnt - * (uint64_t)256); - hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt; - hs->rx_words = (uint64_t) - ((uint64_t)pmb->un.varRdStatus.rcvByteCnt - * (uint64_t)256); + if (pmb->un.varRdStatus.xkb & RD_ST_XKB) { + hs->tx_words = (u64) + ((((u64)(pmb->un.varRdStatus.xmit_xkb & + RD_ST_XMIT_XKB_MASK) << 32) | + (u64)pmb->un.varRdStatus.xmitByteCnt) * + (u64)256); + hs->rx_words = (u64) + ((((u64)(pmb->un.varRdStatus.rcv_xkb & + RD_ST_RCV_XKB_MASK) << 32) | + (u64)pmb->un.varRdStatus.rcvByteCnt) * + (u64)256); + } else { + hs->tx_words = (uint64_t) + ((uint64_t)pmb->un.varRdStatus.xmitByteCnt + * (uint64_t)256); + hs->rx_words = (uint64_t) + ((uint64_t)pmb->un.varRdStatus.rcvByteCnt + * (uint64_t)256); + } memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); pmb->mbxCommand = MBX_READ_LNK_STAT; @@ -6819,15 +6563,19 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->ctx_buf = NULL; pmboxq->vport = vport; - if (vport->fc_flag & FC_OFFLINE_MODE) + if (vport->fc_flag & FC_OFFLINE_MODE) { rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) + if (rc != MBX_SUCCESS) { mempool_free(pmboxq, phba->mbox_mem_pool); - return NULL; + return NULL; + } + } else { + rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) + mempool_free(pmboxq, phba->mbox_mem_pool); + return NULL; + } } hs->link_failure_count = pmb->un.varRdLnk.linkFailureCnt; @@ -6838,6 +6586,9 @@ lpfc_get_stats(struct Scsi_Host *shost) hs->invalid_crc_count = pmb->un.varRdLnk.crcCnt; hs->error_frames = pmb->un.varRdLnk.crcCnt; + hs->cn_sig_warn = atomic64_read(&phba->cgn_acqe_stat.warn); + hs->cn_sig_alarm = atomic64_read(&phba->cgn_acqe_stat.alarm); + hs->link_failure_count -= lso->link_failure_count; hs->loss_of_sync_count -= lso->loss_of_sync_count; hs->loss_of_signal_count -= lso->loss_of_signal_count; @@ -6900,15 +6651,19 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) + if (rc != MBX_SUCCESS) { mempool_free(pmboxq, phba->mbox_mem_pool); - return; + return; + } + } else { + rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) + mempool_free(pmboxq, phba->mbox_mem_pool); + return; + } } memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); @@ -6918,15 +6673,19 @@ lpfc_reset_stats(struct Scsi_Host *shost) pmboxq->vport = vport; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) + (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - else + if (rc != MBX_SUCCESS) { + mempool_free(pmboxq, phba->mbox_mem_pool); + return; + } + } else { rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free( pmboxq, phba->mbox_mem_pool); - return; + if (rc != MBX_SUCCESS) { + if (rc != MBX_TIMEOUT) + mempool_free(pmboxq, phba->mbox_mem_pool); + return; + } } lso->link_failure_count = pmb->un.varRdLnk.linkFailureCnt; @@ -6941,6 +6700,12 @@ lpfc_reset_stats(struct Scsi_Host *shost) else lso->link_events = (phba->fc_eventTag >> 1); + atomic64_set(&phba->cgn_acqe_stat.warn, 0); + atomic64_set(&phba->cgn_acqe_stat.alarm, 0); + + memset(&shost_to_fc_host(shost)->fpin_stats, 0, + sizeof(shost_to_fc_host(shost)->fpin_stats)); + psli->stats_start = ktime_get_seconds(); mempool_free(pmboxq, phba->mbox_mem_pool); @@ -6971,8 +6736,7 @@ lpfc_get_node_by_target(struct scsi_target *starget) spin_lock_irq(shost->host_lock); /* Search for this, mapped, target ID */ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_MAPPED_NODE && + if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && starget->id == ndlp->nlp_sid) { spin_unlock_irq(shost->host_lock); return ndlp; @@ -7047,7 +6811,7 @@ lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) else rport->dev_loss_tmo = 1; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { dev_info(&rport->dev, "Cannot find remote node to " "set rport dev loss tmo, port_id x%x\n", rport->port_id); @@ -7063,7 +6827,7 @@ lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) #endif } -/** +/* * lpfc_rport_show_function - Return rport target information * * Description: @@ -7112,6 +6876,7 @@ lpfc_set_vport_symbolic_name(struct fc_vport *fc_vport) /** * lpfc_hba_log_verbose_init - Set hba's log verbose level * @phba: Pointer to lpfc_hba struct. + * @verbose: Verbose level to set. * * This function is called by the lpfc_get_cfgparam() routine to set the * module lpfc_log_verbose into the @phba cfg_log_verbose for use with @@ -7271,7 +7036,6 @@ lpfc_get_hba_function_mode(struct lpfc_hba *phba) case PCI_DEVICE_ID_LANCER_FCOE: case PCI_DEVICE_ID_LANCER_FCOE_VF: case PCI_DEVICE_ID_ZEPHYR_DCSP: - case PCI_DEVICE_ID_HORNET: case PCI_DEVICE_ID_TIGERSHARK: case PCI_DEVICE_ID_TOMCAT: phba->hba_flag |= HBA_FCOE_MODE; @@ -7307,6 +7071,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_enable_npiv_init(phba, lpfc_enable_npiv); lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy); lpfc_enable_rrq_init(phba, lpfc_enable_rrq); + lpfc_fcp_wait_abts_rsp_init(phba, lpfc_fcp_wait_abts_rsp); lpfc_fdmi_on_init(phba, lpfc_fdmi_on); lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN); lpfc_use_msi_init(phba, lpfc_use_msi); @@ -7321,6 +7086,11 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); lpfc_EnableXLane_init(phba, lpfc_EnableXLane); + /* VMID Inits */ + lpfc_max_vmid_init(phba, lpfc_max_vmid); + lpfc_vmid_inactivity_timeout_init(phba, lpfc_vmid_inactivity_timeout); + lpfc_vmid_app_header_init(phba, lpfc_vmid_app_header); + lpfc_vmid_priority_tagging_init(phba, lpfc_vmid_priority_tagging); if (phba->sli_rev != LPFC_SLI_REV4) phba->cfg_EnableXLane = 0; lpfc_XLanePriority_init(phba, lpfc_XLanePriority); @@ -7366,6 +7136,13 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_irq_chann_init(phba, lpfc_irq_chann); lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr); lpfc_enable_dpp_init(phba, lpfc_enable_dpp); + lpfc_enable_mi_init(phba, lpfc_enable_mi); + + phba->cgn_p.cgn_param_mode = LPFC_CFG_OFF; + phba->cmf_active_mode = LPFC_CFG_OFF; + if (lpfc_fabric_cgn_frequency > EDC_CG_SIGFREQ_CNT_MAX || + lpfc_fabric_cgn_frequency < EDC_CG_SIGFREQ_CNT_MIN) + lpfc_fabric_cgn_frequency = 100; /* 100 ms default */ if (phba->sli_rev != LPFC_SLI_REV4) { /* NVME only supported on SLI4 */ @@ -7389,11 +7166,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) phba->cfg_hdw_queue = phba->sli4_hba.num_present_cpu; if (phba->cfg_irq_chann == 0) phba->cfg_irq_chann = phba->sli4_hba.num_present_cpu; - if (phba->cfg_irq_chann > phba->cfg_hdw_queue) + if (phba->cfg_irq_chann > phba->cfg_hdw_queue && + phba->sli_rev == LPFC_SLI_REV4) phba->cfg_irq_chann = phba->cfg_hdw_queue; - phba->cfg_soft_wwnn = 0L; - phba->cfg_soft_wwpn = 0L; lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); lpfc_aer_support_init(phba, lpfc_aer_support); @@ -7402,7 +7178,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); lpfc_delay_discovery_init(phba, lpfc_delay_discovery); lpfc_sli_mode_init(phba, lpfc_sli_mode); - phba->cfg_enable_dss = 1; lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags); lpfc_ras_fwlog_buffsize_init(phba, lpfc_ras_fwlog_buffsize); lpfc_ras_fwlog_level_init(phba, lpfc_ras_fwlog_level); @@ -7419,12 +7194,26 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba) { - if (phba->cfg_hdw_queue > phba->sli4_hba.num_present_cpu) + int logit = 0; + + if (phba->cfg_hdw_queue > phba->sli4_hba.num_present_cpu) { phba->cfg_hdw_queue = phba->sli4_hba.num_present_cpu; - if (phba->cfg_irq_chann > phba->sli4_hba.num_present_cpu) + logit = 1; + } + if (phba->cfg_irq_chann > phba->sli4_hba.num_present_cpu) { phba->cfg_irq_chann = phba->sli4_hba.num_present_cpu; - if (phba->cfg_irq_chann > phba->cfg_hdw_queue) + logit = 1; + } + if (phba->cfg_irq_chann > phba->cfg_hdw_queue) { phba->cfg_irq_chann = phba->cfg_hdw_queue; + logit = 1; + } + if (logit) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2006 Reducing Queues - CPU limitation: " + "IRQ %d HDWQ %d\n", + phba->cfg_irq_chann, + phba->cfg_hdw_queue); if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME && phba->nvmet_support) { diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 0ea03ae93d91..852b025e2fec 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -88,17 +88,9 @@ struct lpfc_bsg_mbox { uint32_t outExtWLen; /* from app */ }; -#define MENLO_DID 0x0000FC0E - -struct lpfc_bsg_menlo { - struct lpfc_iocbq *cmdiocbq; - struct lpfc_dmabuf *rmp; -}; - #define TYPE_EVT 1 #define TYPE_IOCB 2 #define TYPE_MBOX 3 -#define TYPE_MENLO 4 struct bsg_job_data { uint32_t type; struct bsg_job *set_job; /* job waiting for this iocb to finish */ @@ -106,7 +98,6 @@ struct bsg_job_data { struct lpfc_bsg_event *evt; struct lpfc_bsg_iocb iocb; struct lpfc_bsg_mbox mbox; - struct lpfc_bsg_menlo menlo; } context_un; }; @@ -303,15 +294,14 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, struct bsg_job_data *dd_data; struct bsg_job *job; struct fc_bsg_reply *bsg_reply; - IOCB_t *rsp; struct lpfc_dmabuf *bmp, *cmp, *rmp; struct lpfc_nodelist *ndlp; struct lpfc_bsg_iocb *iocb; unsigned long flags; - unsigned int rsp_size; int rc = 0; + u32 ulp_status, ulp_word4, total_data_placed; - dd_data = cmdiocbq->context1; + dd_data = cmdiocbq->context_un.dd_data; /* Determine if job has been aborted */ spin_lock_irqsave(&phba->ct_ev_lock, flags); @@ -325,22 +315,24 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, /* Close the timeout handler abort window */ spin_lock_irqsave(&phba->hbalock, flags); - cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING; + cmdiocbq->cmd_flag &= ~LPFC_IO_CMD_OUTSTANDING; spin_unlock_irqrestore(&phba->hbalock, flags); iocb = &dd_data->context_un.iocb; - ndlp = iocb->ndlp; + ndlp = iocb->cmdiocbq->ndlp; rmp = iocb->rmp; - cmp = cmdiocbq->context2; - bmp = cmdiocbq->context3; - rsp = &rspiocbq->iocb; + cmp = cmdiocbq->cmd_dmabuf; + bmp = cmdiocbq->bpl_dmabuf; + ulp_status = get_job_ulpstatus(phba, rspiocbq); + ulp_word4 = get_job_word4(phba, rspiocbq); + total_data_placed = get_job_data_placed(phba, rspiocbq); /* Copy the completed data or set the error status */ if (job) { - if (rsp->ulpStatus) { - if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { + if (ulp_status) { + if (ulp_status == IOSTAT_LOCAL_REJECT) { + switch (ulp_word4 & IOERR_PARAM_MASK) { case IOERR_SEQUENCE_TIMEOUT: rc = -ETIMEDOUT; break; @@ -355,10 +347,9 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, rc = -EACCES; } } else { - rsp_size = rsp->un.genreq64.bdl.bdeSize; bsg_reply->reply_payload_rcv_len = lpfc_bsg_copy_data(rmp, &job->reply_payload, - rsp_size, 0); + total_data_placed, 0); } } @@ -366,8 +357,8 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, lpfc_free_bsg_buffers(phba, rmp); lpfc_mbuf_free(phba, bmp->virt, bmp->phys); kfree(bmp); - lpfc_sli_release_iocbq(phba, cmdiocbq); lpfc_nlp_put(ndlp); + lpfc_sli_release_iocbq(phba, cmdiocbq); kfree(dd_data); /* Complete the job if the job is still active */ @@ -388,26 +379,28 @@ static int lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) { struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); - struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata = fc_bsg_to_rport(job)->dd_data; + struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp = rdata->pnode; struct fc_bsg_reply *bsg_reply = job->reply; struct ulp_bde64 *bpl = NULL; - uint32_t timeout; struct lpfc_iocbq *cmdiocbq = NULL; - IOCB_t *cmd; struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; - int request_nseg; - int reply_nseg; + int request_nseg, reply_nseg; + u32 num_entry; struct bsg_job_data *dd_data; unsigned long flags; uint32_t creg_val; int rc = 0; int iocb_stat; + u16 ulp_context; /* in case no data is transferred */ bsg_reply->reply_payload_rcv_len = 0; + if (ndlp->nlp_flag & NLP_ELS_SND_MASK) + return -ENODEV; + /* allocate our bsg tracking structure */ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); if (!dd_data) { @@ -417,24 +410,12 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) goto no_dd_data; } - if (!lpfc_nlp_get(ndlp)) { - rc = -ENODEV; - goto no_ndlp; - } - - if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { - rc = -ENODEV; - goto free_ndlp; - } - cmdiocbq = lpfc_sli_get_iocbq(phba); if (!cmdiocbq) { rc = -ENOMEM; - goto free_ndlp; + goto free_dd; } - cmd = &cmdiocbq->iocb; - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (!bmp) { rc = -ENOMEM; @@ -468,39 +449,28 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) goto free_cmp; } - cmd->un.genreq64.bdl.ulpIoTag32 = 0; - cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); - cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); - cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - cmd->un.genreq64.bdl.bdeSize = - (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); - cmd->ulpCommand = CMD_GEN_REQUEST64_CR; - cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); - cmd->un.genreq64.w5.hcsw.Dfctl = 0; - cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; - cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; - cmd->ulpBdeCount = 1; - cmd->ulpLe = 1; - cmd->ulpClass = CLASS3; - cmd->ulpContext = ndlp->nlp_rpi; + num_entry = request_nseg + reply_nseg; + if (phba->sli_rev == LPFC_SLI_REV4) - cmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - cmd->ulpOwner = OWN_CHIP; + ulp_context = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; + else + ulp_context = ndlp->nlp_rpi; + + lpfc_sli_prep_gen_req(phba, cmdiocbq, bmp, ulp_context, num_entry, + phba->fc_ratov * 2); + + cmdiocbq->num_bdes = num_entry; cmdiocbq->vport = phba->pport; - cmdiocbq->context3 = bmp; - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - timeout = phba->fc_ratov * 2; - cmd->ulpTimeout = timeout; - - cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; - cmdiocbq->context1 = dd_data; - cmdiocbq->context2 = cmp; - cmdiocbq->context3 = bmp; - cmdiocbq->context_un.ndlp = ndlp; + cmdiocbq->cmd_dmabuf = cmp; + cmdiocbq->bpl_dmabuf = bmp; + cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC; + + cmdiocbq->cmd_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; + cmdiocbq->context_un.dd_data = dd_data; + dd_data->type = TYPE_IOCB; dd_data->set_job = job; dd_data->context_un.iocb.cmdiocbq = cmdiocbq; - dd_data->context_un.iocb.ndlp = ndlp; dd_data->context_un.iocb.rmp = rmp; job->dd_data = dd_data; @@ -514,14 +484,19 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) readl(phba->HCregaddr); /* flush */ } - iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); + cmdiocbq->ndlp = lpfc_nlp_get(ndlp); + if (!cmdiocbq->ndlp) { + rc = -ENODEV; + goto free_rmp; + } + iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); if (iocb_stat == IOCB_SUCCESS) { spin_lock_irqsave(&phba->hbalock, flags); /* make sure the I/O had not been completed yet */ - if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) { + if (cmdiocbq->cmd_flag & LPFC_IO_LIBDFC) { /* open up abort window to timeout handler */ - cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING; + cmdiocbq->cmd_flag |= LPFC_IO_CMD_OUTSTANDING; } spin_unlock_irqrestore(&phba->hbalock, flags); return 0; /* done for now */ @@ -532,7 +507,7 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) } /* iocb failed so cleanup */ - job->dd_data = NULL; + lpfc_nlp_put(ndlp); free_rmp: lpfc_free_bsg_buffers(phba, rmp); @@ -544,9 +519,7 @@ free_bmp: kfree(bmp); free_cmdiocbq: lpfc_sli_release_iocbq(phba, cmdiocbq); -free_ndlp: - lpfc_nlp_put(ndlp); -no_ndlp: +free_dd: kfree(dd_data); no_dd_data: /* make error code available to userspace */ @@ -580,7 +553,6 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, struct bsg_job_data *dd_data; struct bsg_job *job; struct fc_bsg_reply *bsg_reply; - IOCB_t *rsp; struct lpfc_nodelist *ndlp; struct lpfc_dmabuf *pcmd = NULL, *prsp = NULL; struct fc_bsg_ctels_reply *els_reply; @@ -588,10 +560,11 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, unsigned long flags; unsigned int rsp_size; int rc = 0; + u32 ulp_status, ulp_word4, total_data_placed; - dd_data = cmdiocbq->context1; + dd_data = cmdiocbq->context_un.dd_data; ndlp = dd_data->context_un.iocb.ndlp; - cmdiocbq->context1 = ndlp; + cmdiocbq->ndlp = ndlp; /* Determine if job has been aborted */ spin_lock_irqsave(&phba->ct_ev_lock, flags); @@ -605,11 +578,13 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, /* Close the timeout handler abort window */ spin_lock_irqsave(&phba->hbalock, flags); - cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING; + cmdiocbq->cmd_flag &= ~LPFC_IO_CMD_OUTSTANDING; spin_unlock_irqrestore(&phba->hbalock, flags); - rsp = &rspiocbq->iocb; - pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2; + ulp_status = get_job_ulpstatus(phba, rspiocbq); + ulp_word4 = get_job_word4(phba, rspiocbq); + total_data_placed = get_job_data_placed(phba, rspiocbq); + pcmd = cmdiocbq->cmd_dmabuf; prsp = (struct lpfc_dmabuf *)pcmd->list.next; /* Copy the completed job data or determine the job status if job is @@ -617,31 +592,36 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, */ if (job) { - if (rsp->ulpStatus == IOSTAT_SUCCESS) { - rsp_size = rsp->un.elsreq64.bdl.bdeSize; + if (ulp_status == IOSTAT_SUCCESS) { + rsp_size = total_data_placed; bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(job->reply_payload.sg_list, job->reply_payload.sg_cnt, prsp->virt, rsp_size); - } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { + } else if (ulp_status == IOSTAT_LS_RJT) { bsg_reply->reply_payload_rcv_len = sizeof(struct fc_bsg_ctels_reply); /* LS_RJT data returned in word 4 */ - rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; + rjt_data = (uint8_t *)&ulp_word4; els_reply = &bsg_reply->reply_data.ctels_reply; els_reply->status = FC_CTELS_STATUS_REJECT; els_reply->rjt_data.action = rjt_data[3]; els_reply->rjt_data.reason_code = rjt_data[2]; els_reply->rjt_data.reason_explanation = rjt_data[1]; els_reply->rjt_data.vendor_unique = rjt_data[0]; + } else if (ulp_status == IOSTAT_LOCAL_REJECT && + (ulp_word4 & IOERR_PARAM_MASK) == + IOERR_SEQUENCE_TIMEOUT) { + rc = -ETIMEDOUT; } else { rc = -EIO; } } - lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, cmdiocbq); + + lpfc_nlp_put(ndlp); kfree(dd_data); /* Complete the job if the job is still active */ @@ -710,7 +690,6 @@ lpfc_bsg_rport_els(struct bsg_job *job) * we won't be dma into memory that is no longer allocated to for the * request. */ - cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID, elscmd); if (!cmdiocbq) { @@ -718,23 +697,23 @@ lpfc_bsg_rport_els(struct bsg_job *job) goto release_ndlp; } - rpi = ndlp->nlp_rpi; - /* Transfer the request payload to allocated command dma buffer */ - sg_copy_to_buffer(job->request_payload.sg_list, job->request_payload.sg_cnt, - ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt, + cmdiocbq->cmd_dmabuf->virt, cmdsize); + rpi = ndlp->nlp_rpi; + if (phba->sli_rev == LPFC_SLI_REV4) - cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi]; + bf_set(wqe_ctxt_tag, &cmdiocbq->wqe.generic.wqe_com, + phba->sli4_hba.rpi_ids[rpi]); else cmdiocbq->iocb.ulpContext = rpi; - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - cmdiocbq->context1 = dd_data; - cmdiocbq->context_un.ndlp = ndlp; - cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; + cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC; + cmdiocbq->context_un.dd_data = dd_data; + cmdiocbq->ndlp = ndlp; + cmdiocbq->cmd_cmpl = lpfc_bsg_rport_els_cmp; dd_data->type = TYPE_IOCB; dd_data->set_job = job; dd_data->context_un.iocb.cmdiocbq = cmdiocbq; @@ -753,13 +732,12 @@ lpfc_bsg_rport_els(struct bsg_job *job) } rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); - if (rc == IOCB_SUCCESS) { spin_lock_irqsave(&phba->hbalock, flags); /* make sure the I/O had not been completed/released */ - if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) { + if (cmdiocbq->cmd_flag & LPFC_IO_LIBDFC) { /* open up abort window to timeout handler */ - cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING; + cmdiocbq->cmd_flag |= LPFC_IO_CMD_OUTSTANDING; } spin_unlock_irqrestore(&phba->hbalock, flags); return 0; /* done for now */ @@ -769,11 +747,9 @@ lpfc_bsg_rport_els(struct bsg_job *job) rc = -EIO; } - /* iocb failed so cleanup */ - job->dd_data = NULL; + /* I/O issue failed. Cleanup resources. */ linkdown_err: - cmdiocbq->context1 = ndlp; lpfc_els_free_iocb(phba, cmdiocbq); release_ndlp: @@ -902,11 +878,8 @@ diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) return 0; } -/** +/* * lpfc_bsg_ct_unsol_event - process an unsolicited CT command - * @phba: - * @pring: - * @piocbq: * * This function is called when an unsolicited CT command is received. It * forwards the event to any processes registered to receive CT events. @@ -921,46 +894,28 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_bsg_event *evt; struct event_data *evt_dat = NULL; struct lpfc_iocbq *iocbq; + IOCB_t *iocb = NULL; size_t offset = 0; struct list_head head; struct ulp_bde64 *bde; dma_addr_t dma_addr; int i; - struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; - struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; - struct lpfc_hbq_entry *hbqe; + struct lpfc_dmabuf *bdeBuf1 = piocbq->cmd_dmabuf; + struct lpfc_dmabuf *bdeBuf2 = piocbq->bpl_dmabuf; struct lpfc_sli_ct_request *ct_req; struct bsg_job *job = NULL; struct fc_bsg_reply *bsg_reply; struct bsg_job_data *dd_data = NULL; unsigned long flags; int size = 0; + u32 bde_count = 0; INIT_LIST_HEAD(&head); list_add_tail(&head, &piocbq->list); - if (piocbq->iocb.ulpBdeCount == 0 || - piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) - goto error_ct_unsol_exit; - - if (phba->link_state == LPFC_HBA_ERROR || - (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) - goto error_ct_unsol_exit; - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) - dmabuf = bdeBuf1; - else { - dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, - piocbq->iocb.un.cont64[0].addrLow); - dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); - } - if (dmabuf == NULL) - goto error_ct_unsol_exit; - ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; + ct_req = (struct lpfc_sli_ct_request *)bdeBuf1->virt; evt_req_id = ct_req->FsType; cmd = ct_req->CommandResponse.bits.CmdRsp; - if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); spin_lock_irqsave(&phba->ct_ev_lock, flags); list_for_each_entry(evt, &phba->ct_ev_waiters, node) { @@ -983,12 +938,17 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { /* take accumulated byte count from the last iocbq */ iocbq = list_entry(head.prev, typeof(*iocbq), list); - evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; + if (phba->sli_rev == LPFC_SLI_REV4) + evt_dat->len = iocbq->wcqe_cmpl.total_data_placed; + else + evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; } else { list_for_each_entry(iocbq, &head, list) { - for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) + iocb = &iocbq->iocb; + for (i = 0; i < iocb->ulpBdeCount; + i++) evt_dat->len += - iocbq->iocb.un.cont64[i].tus.f.bdeSize; + iocb->un.cont64[i].tus.f.bdeSize; } } @@ -1008,22 +968,21 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, list_for_each_entry(iocbq, &head, list) { size = 0; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - bdeBuf1 = iocbq->context2; - bdeBuf2 = iocbq->context3; + bdeBuf1 = iocbq->cmd_dmabuf; + bdeBuf2 = iocbq->bpl_dmabuf; } - for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { + if (phba->sli_rev == LPFC_SLI_REV4) + bde_count = iocbq->wcqe_cmpl.word3; + else + bde_count = iocbq->iocb.ulpBdeCount; + for (i = 0; i < bde_count; i++) { if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { if (i == 0) { - hbqe = (struct lpfc_hbq_entry *) - &iocbq->iocb.un.ulpWord[0]; - size = hbqe->bde.tus.f.bdeSize; + size = iocbq->wqe.gen_req.bde.tus.f.bdeSize; dmabuf = bdeBuf1; } else if (i == 1) { - hbqe = (struct lpfc_hbq_entry *) - &iocbq->iocb.unsli3. - sli3Words[4]; - size = hbqe->bde.tus.f.bdeSize; + size = iocbq->unsol_rcv_len; dmabuf = bdeBuf2; } if ((offset + size) > evt_dat->len) @@ -1077,17 +1036,17 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_in_buf_free(phba, dmabuf); } else { - lpfc_post_buffer(phba, - pring, - 1); + lpfc_sli3_post_buffer(phba, + pring, + 1); } break; default: if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_post_buffer(phba, - pring, - 1); + lpfc_sli3_post_buffer(phba, + pring, + 1); break; } } @@ -1110,14 +1069,15 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->ct_ctx[ evt_dat->immed_dat].SID); phba->ct_ctx[evt_dat->immed_dat].rxid = - piocbq->iocb.ulpContext; + get_job_ulpcontext(phba, piocbq); phba->ct_ctx[evt_dat->immed_dat].oxid = - piocbq->iocb.unsli3.rcvsli3.ox_id; + get_job_rcvoxid(phba, piocbq); phba->ct_ctx[evt_dat->immed_dat].SID = - piocbq->iocb.un.rcvels.remoteID; + bf_get(wqe_els_did, + &piocbq->wqe.xmit_els_rsp.wqe_dest); phba->ct_ctx[evt_dat->immed_dat].valid = UNSOL_VALID; } else - evt_dat->immed_dat = piocbq->iocb.ulpContext; + evt_dat->immed_dat = get_job_ulpcontext(phba, piocbq); evt_dat->type = FC_REG_CT_EVENT; list_add(&evt_dat->node, &evt->events_to_see); @@ -1400,13 +1360,13 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, struct bsg_job_data *dd_data; struct bsg_job *job; struct fc_bsg_reply *bsg_reply; - IOCB_t *rsp; struct lpfc_dmabuf *bmp, *cmp; struct lpfc_nodelist *ndlp; unsigned long flags; int rc = 0; + u32 ulp_status, ulp_word4; - dd_data = cmdiocbq->context1; + dd_data = cmdiocbq->context_un.dd_data; /* Determine if job has been aborted */ spin_lock_irqsave(&phba->ct_ev_lock, flags); @@ -1419,21 +1379,23 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, /* Close the timeout handler abort window */ spin_lock_irqsave(&phba->hbalock, flags); - cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING; + cmdiocbq->cmd_flag &= ~LPFC_IO_CMD_OUTSTANDING; spin_unlock_irqrestore(&phba->hbalock, flags); ndlp = dd_data->context_un.iocb.ndlp; - cmp = cmdiocbq->context2; - bmp = cmdiocbq->context3; - rsp = &rspiocbq->iocb; + cmp = cmdiocbq->cmd_dmabuf; + bmp = cmdiocbq->bpl_dmabuf; + + ulp_status = get_job_ulpstatus(phba, rspiocbq); + ulp_word4 = get_job_word4(phba, rspiocbq); /* Copy the completed job data or set the error status */ if (job) { bsg_reply = job->reply; - if (rsp->ulpStatus) { - if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { + if (ulp_status) { + if (ulp_status == IOSTAT_LOCAL_REJECT) { + switch (ulp_word4 & IOERR_PARAM_MASK) { case IOERR_SEQUENCE_TIMEOUT: rc = -ETIMEDOUT; break; @@ -1474,7 +1436,8 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, * @phba: Pointer to HBA context object. * @job: Pointer to the job object. * @tag: tag index value into the ports context exchange array. - * @bmp: Pointer to a dma buffer descriptor. + * @cmp: Pointer to a cmp dma buffer descriptor. + * @bmp: Pointer to a bmp dma buffer descriptor. * @num_entry: Number of enties in the bde. **/ static int @@ -1482,13 +1445,22 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, struct lpfc_dmabuf *cmp, struct lpfc_dmabuf *bmp, int num_entry) { - IOCB_t *icmd; struct lpfc_iocbq *ctiocb = NULL; int rc = 0; struct lpfc_nodelist *ndlp = NULL; struct bsg_job_data *dd_data; unsigned long flags; uint32_t creg_val; + u16 ulp_context, iotag; + + ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); + if (!ndlp) { + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, + "2721 ndlp null for oxid %x SID %x\n", + phba->ct_ctx[tag].rxid, + phba->ct_ctx[tag].SID); + return IOCB_ERROR; + } /* allocate our bsg tracking structure */ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); @@ -1506,81 +1478,53 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, goto no_ctiocb; } - icmd = &ctiocb->iocb; - icmd->un.xseq64.bdl.ulpIoTag32 = 0; - icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); - icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); - icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); - icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); - icmd->un.xseq64.w5.hcsw.Dfctl = 0; - icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; - icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; - - /* Fill in rest of iocb */ - icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; - icmd->ulpBdeCount = 1; - icmd->ulpLe = 1; - icmd->ulpClass = CLASS3; if (phba->sli_rev == LPFC_SLI_REV4) { /* Do not issue unsol response if oxid not marked as valid */ if (phba->ct_ctx[tag].valid != UNSOL_VALID) { rc = IOCB_ERROR; goto issue_ct_rsp_exit; } - icmd->ulpContext = phba->ct_ctx[tag].rxid; - icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid; - ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); - if (!ndlp) { - lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, - "2721 ndlp null for oxid %x SID %x\n", - icmd->ulpContext, - phba->ct_ctx[tag].SID); - rc = IOCB_ERROR; - goto issue_ct_rsp_exit; - } - /* Check if the ndlp is active */ - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - rc = IOCB_ERROR; - goto issue_ct_rsp_exit; - } - - /* get a refernece count so the ndlp doesn't go away while - * we respond - */ - if (!lpfc_nlp_get(ndlp)) { - rc = IOCB_ERROR; - goto issue_ct_rsp_exit; - } - - icmd->un.ulpWord[3] = - phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; + lpfc_sli_prep_xmit_seq64(phba, ctiocb, bmp, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi], + phba->ct_ctx[tag].oxid, num_entry, + FC_RCTL_DD_SOL_CTL, 1, + CMD_XMIT_SEQUENCE64_WQE); /* The exchange is done, mark the entry as invalid */ phba->ct_ctx[tag].valid = UNSOL_INVALID; - } else - icmd->ulpContext = (ushort) tag; + iotag = get_wqe_reqtag(ctiocb); + } else { + lpfc_sli_prep_xmit_seq64(phba, ctiocb, bmp, 0, tag, num_entry, + FC_RCTL_DD_SOL_CTL, 1, + CMD_XMIT_SEQUENCE64_CX); + ctiocb->num_bdes = num_entry; + iotag = ctiocb->iocb.ulpIoTag; + } - icmd->ulpTimeout = phba->fc_ratov * 2; + ulp_context = get_job_ulpcontext(phba, ctiocb); /* Xmit CT response on exchange <xid> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n", - icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state); + "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n", + ulp_context, iotag, tag, phba->link_state); - ctiocb->iocb_flag |= LPFC_IO_LIBDFC; + ctiocb->cmd_flag |= LPFC_IO_LIBDFC; ctiocb->vport = phba->pport; - ctiocb->context1 = dd_data; - ctiocb->context2 = cmp; - ctiocb->context3 = bmp; - ctiocb->context_un.ndlp = ndlp; - ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; + ctiocb->context_un.dd_data = dd_data; + ctiocb->cmd_dmabuf = cmp; + ctiocb->bpl_dmabuf = bmp; + ctiocb->ndlp = ndlp; + ctiocb->cmd_cmpl = lpfc_issue_ct_rsp_cmp; dd_data->type = TYPE_IOCB; dd_data->set_job = job; dd_data->context_un.iocb.cmdiocbq = ctiocb; - dd_data->context_un.iocb.ndlp = ndlp; + dd_data->context_un.iocb.ndlp = lpfc_nlp_get(ndlp); + if (!dd_data->context_un.iocb.ndlp) { + rc = -IOCB_ERROR; + goto issue_ct_rsp_exit; + } dd_data->context_un.iocb.rmp = NULL; job->dd_data = dd_data; @@ -1595,13 +1539,12 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, } rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); - if (rc == IOCB_SUCCESS) { spin_lock_irqsave(&phba->hbalock, flags); /* make sure the I/O had not been completed/released */ - if (ctiocb->iocb_flag & LPFC_IO_LIBDFC) { + if (ctiocb->cmd_flag & LPFC_IO_LIBDFC) { /* open up abort window to timeout handler */ - ctiocb->iocb_flag |= LPFC_IO_CMD_OUTSTANDING; + ctiocb->cmd_flag |= LPFC_IO_CMD_OUTSTANDING; } spin_unlock_irqrestore(&phba->hbalock, flags); return 0; /* done for now */ @@ -1609,6 +1552,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, /* iocb failed so cleanup */ job->dd_data = NULL; + lpfc_nlp_put(ndlp); issue_ct_rsp_exit: lpfc_sli_release_iocbq(phba, ctiocb); @@ -2033,8 +1977,6 @@ lpfc_sli4_bsg_set_loopback_mode(struct lpfc_hba *phba, int mode, static int lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) { - int rc; - if (phba->pport->fc_flag & FC_VFI_REGISTERED) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "3136 Port still had vfi registered: " @@ -2044,8 +1986,7 @@ lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) phba->vpi_ids[phba->pport->vpi]); return -EINVAL; } - rc = lpfc_issue_reg_vfi(phba->pport); - return rc; + return lpfc_issue_reg_vfi(phba->pport); } /** @@ -2404,33 +2345,27 @@ lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) union lpfc_sli4_cfg_shdr *shdr; uint32_t shdr_status, shdr_add_status; struct diag_status *diag_status_reply; - int mbxstatus, rc = 0; + int mbxstatus, rc = -ENODEV, rc1 = 0; shost = fc_bsg_to_shost(job); - if (!shost) { - rc = -ENODEV; + if (!shost) goto job_error; - } + vport = shost_priv(shost); - if (!vport) { - rc = -ENODEV; + if (!vport) goto job_error; - } + phba = vport->phba; - if (!phba) { - rc = -ENODEV; + if (!phba) goto job_error; - } - if (phba->sli_rev < LPFC_SLI_REV4) { - rc = -ENODEV; + + if (phba->sli_rev < LPFC_SLI_REV4) goto job_error; - } + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) < - LPFC_SLI_INTF_IF_TYPE_2) { - rc = -ENODEV; + LPFC_SLI_INTF_IF_TYPE_2) goto job_error; - } if (job->request_len < sizeof(struct fc_bsg_request) + sizeof(struct sli4_link_diag)) { @@ -2457,16 +2392,20 @@ lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) goto job_error; pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) + if (!pmboxq) { + rc = -ENOMEM; goto link_diag_test_exit; + } req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - sizeof(struct lpfc_sli4_cfg_mhdr)); alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, req_len, LPFC_SLI4_MBX_EMBED); - if (alloc_len != req_len) + if (alloc_len != req_len) { + rc = -ENOMEM; goto link_diag_test_exit; + } run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test; bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req, @@ -2498,13 +2437,12 @@ lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) diag_status_reply = (struct diag_status *) bsg_reply->reply_data.vendor_reply.vendor_rsp; - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct diag_status)) { + if (job->reply_len < sizeof(*bsg_reply) + sizeof(*diag_status_reply)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "3012 Received Run link diag test reply " "below minimum size (%d): reply_len:%d\n", - (int)(sizeof(struct fc_bsg_request) + - sizeof(struct diag_status)), + (int)(sizeof(*bsg_reply) + + sizeof(*diag_status_reply)), job->reply_len); rc = -EINVAL; goto job_error; @@ -2515,7 +2453,7 @@ lpfc_sli4_bsg_link_diag_test(struct bsg_job *job) diag_status_reply->shdr_add_status = shdr_add_status; link_diag_test_exit: - rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); + rc1 = lpfc_sli4_bsg_set_link_diag_state(phba, 0); if (pmboxq) mempool_free(pmboxq, phba->mbox_mem_pool); @@ -2524,6 +2462,8 @@ link_diag_test_exit: job_error: /* make error code available to userspace */ + if (rc1 && !rc) + rc = rc1; bsg_reply->result = rc; /* complete the job back to userspace if no error */ if (rc == 0) @@ -2642,7 +2582,7 @@ static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) * * This function obtains the transmit and receive ids required to send * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp - * flags are used to the unsolicted response handler is able to process + * flags are used to the unsolicited response handler is able to process * the ct command sent on the same port. **/ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, @@ -2650,7 +2590,6 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, { struct lpfc_bsg_event *evt; struct lpfc_iocbq *cmdiocbq, *rspiocbq; - IOCB_t *cmd, *rsp; struct lpfc_dmabuf *dmabuf; struct ulp_bde64 *bpl = NULL; struct lpfc_sli_ct_request *ctreq = NULL; @@ -2658,6 +2597,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, int time_left; int iocb_stat = IOCB_SUCCESS; unsigned long flags; + u32 status; *txxri = 0; *rxxri = 0; @@ -2701,9 +2641,6 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, goto err_get_xri_exit; } - cmd = &cmdiocbq->iocb; - rsp = &rspiocbq->iocb; - memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; @@ -2713,36 +2650,24 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; ctreq->CommandResponse.bits.Size = 0; - - cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); - cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); - cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); - - cmd->un.xseq64.w5.hcsw.Fctl = LA; - cmd->un.xseq64.w5.hcsw.Dfctl = 0; - cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; - cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; - - cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; - cmd->ulpBdeCount = 1; - cmd->ulpLe = 1; - cmd->ulpClass = CLASS3; - cmd->ulpContext = rpi; - - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; + cmdiocbq->bpl_dmabuf = dmabuf; + cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC; cmdiocbq->vport = phba->pport; - cmdiocbq->iocb_cmpl = NULL; + cmdiocbq->cmd_cmpl = NULL; + + lpfc_sli_prep_xmit_seq64(phba, cmdiocbq, dmabuf, rpi, 0, 1, + FC_RCTL_DD_SOL_CTL, 0, CMD_XMIT_SEQUENCE64_CR); iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, - rspiocbq, - (phba->fc_ratov * 2) - + LPFC_DRVR_TIMEOUT); - if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOSTAT_SUCCESS)) { + rspiocbq, (phba->fc_ratov * 2) + + LPFC_DRVR_TIMEOUT); + + status = get_job_ulpstatus(phba, rspiocbq); + if (iocb_stat != IOCB_SUCCESS || status != IOCB_SUCCESS) { ret_val = -EIO; goto err_get_xri_exit; } - *txxri = rsp->ulpContext; + *txxri = get_job_ulpcontext(phba, rspiocbq); evt->waiting = 1; evt->wait_time_stamp = jiffies; @@ -2943,16 +2868,16 @@ out: } /** - * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd + * lpfcdiag_sli3_loop_post_rxbufs - post the receive buffers for an unsol CT cmd * @phba: Pointer to HBA context object * @rxxri: Receive exchange id * @len: Number of data bytes * * This function allocates and posts a data buffer of sufficient size to receive - * an unsolicted CT command. + * an unsolicited CT command. **/ -static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, - size_t len) +static int lpfcdiag_sli3_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, + size_t len) { struct lpfc_sli_ring *pring; struct lpfc_iocbq *cmdiocbq; @@ -2989,7 +2914,6 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, /* Queue buffers for the receive exchange */ num_bde = (uint32_t)rxbuffer->flag; dmp = &rxbuffer->dma; - cmd = &cmdiocbq->iocb; i = 0; @@ -3057,7 +2981,6 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, ret_val = -EIO; goto err_post_rxbufs_exit; } - cmd = &cmdiocbq->iocb; i = 0; } @@ -3109,7 +3032,7 @@ lpfc_bsg_diag_loopback_run(struct bsg_job *job) size_t segment_len = 0, segment_offset = 0, current_offset = 0; uint16_t rpi = 0; struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL; - IOCB_t *cmd, *rsp = NULL; + union lpfc_wqe128 *cmdwqe, *rspwqe; struct lpfc_sli_ct_request *ctreq; struct lpfc_dmabuf *txbmp; struct ulp_bde64 *txbpl = NULL; @@ -3202,7 +3125,7 @@ lpfc_bsg_diag_loopback_run(struct bsg_job *job) goto loopback_test_exit; } - rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); + rc = lpfcdiag_sli3_loop_post_rxbufs(phba, rxxri, full_size); if (rc) { lpfcdiag_loop_self_unreg(phba, rpi); goto loopback_test_exit; @@ -3245,9 +3168,12 @@ lpfc_bsg_diag_loopback_run(struct bsg_job *job) goto err_loopback_test_exit; } - cmd = &cmdiocbq->iocb; - if (phba->sli_rev < LPFC_SLI_REV4) - rsp = &rspiocbq->iocb; + cmdwqe = &cmdiocbq->wqe; + memset(cmdwqe, 0, sizeof(union lpfc_wqe)); + if (phba->sli_rev < LPFC_SLI_REV4) { + rspwqe = &rspiocbq->wqe; + memset(rspwqe, 0, sizeof(union lpfc_wqe)); + } INIT_LIST_HEAD(&head); list_add_tail(&head, &txbuffer->dma.list); @@ -3279,41 +3205,32 @@ lpfc_bsg_diag_loopback_run(struct bsg_job *job) /* Build the XMIT_SEQUENCE iocb */ num_bde = (uint32_t)txbuffer->flag; - cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); - cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); - cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); - - cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); - cmd->un.xseq64.w5.hcsw.Dfctl = 0; - cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; - cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; - - cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; - cmd->ulpBdeCount = 1; - cmd->ulpLe = 1; - cmd->ulpClass = CLASS3; + cmdiocbq->num_bdes = num_bde; + cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC; + cmdiocbq->cmd_flag |= LPFC_IO_LOOPBACK; + cmdiocbq->vport = phba->pport; + cmdiocbq->cmd_cmpl = NULL; + cmdiocbq->bpl_dmabuf = txbmp; if (phba->sli_rev < LPFC_SLI_REV4) { - cmd->ulpContext = txxri; + lpfc_sli_prep_xmit_seq64(phba, cmdiocbq, txbmp, 0, txxri, + num_bde, FC_RCTL_DD_UNSOL_CTL, 1, + CMD_XMIT_SEQUENCE64_CX); + } else { - cmd->un.xseq64.bdl.ulpIoTag32 = 0; - cmd->un.ulpWord[3] = phba->sli4_hba.rpi_ids[rpi]; - cmdiocbq->context3 = txbmp; + lpfc_sli_prep_xmit_seq64(phba, cmdiocbq, txbmp, + phba->sli4_hba.rpi_ids[rpi], 0xffff, + full_size, FC_RCTL_DD_UNSOL_CTL, 1, + CMD_XMIT_SEQUENCE64_WQE); cmdiocbq->sli4_xritag = NO_XRI; - cmd->unsli3.rcvsli3.ox_id = 0xffff; } - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - cmdiocbq->iocb_flag |= LPFC_IO_LOOPBACK; - cmdiocbq->vport = phba->pport; - cmdiocbq->iocb_cmpl = NULL; + iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); - - if ((iocb_stat != IOCB_SUCCESS) || - ((phba->sli_rev < LPFC_SLI_REV4) && - (rsp->ulpStatus != IOSTAT_SUCCESS))) { + if (iocb_stat != IOCB_SUCCESS || + (phba->sli_rev < LPFC_SLI_REV4 && + (get_job_ulpstatus(phba, rspiocbq) != IOSTAT_SUCCESS))) { lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, "3126 Failed loopback test issue iocb: " "iocb_stat:x%x\n", iocb_stat); @@ -3420,8 +3337,7 @@ lpfc_bsg_get_dfc_rev(struct bsg_job *job) event_reply = (struct get_mgmt_rev_reply *) bsg_reply->reply_data.vendor_reply.vendor_rsp; - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) { + if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2741 Received GET_DFC_REV reply below " "minimum size\n"); @@ -3447,7 +3363,7 @@ job_error: * This is completion handler function for mailbox commands issued from * lpfc_bsg_issue_mbox function. This function is called by the * mailbox event handler function with no lock held. This function - * will wake up thread waiting on the wait queue pointed by context1 + * will wake up thread waiting on the wait queue pointed by dd_data * of the mailbox. **/ static void @@ -3539,6 +3455,7 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, mb->mbxCommand); return -EPERM; } + break; case MBX_WRITE_NV: case MBX_WRITE_VPARMS: case MBX_LOAD_SM: @@ -3573,15 +3490,6 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, "1226 mbox: set_variable 0x%x, 0x%x\n", mb->un.varWords[0], mb->un.varWords[1]); - if ((mb->un.varWords[0] == SETVAR_MLOMNT) - && (mb->un.varWords[1] == 1)) { - phba->wait_4_mlo_maint_flg = 1; - } else if (mb->un.varWords[0] == SETVAR_MLORST) { - spin_lock_irq(&phba->hbalock); - phba->link_flag &= ~LS_LOOPBACK_MODE; - spin_unlock_irq(&phba->hbalock); - phba->fc_topology = LPFC_TOPOLOGY_PT_PT; - } break; case MBX_READ_SPARM64: case MBX_REG_LOGIN: @@ -3599,7 +3507,7 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, } /** - * lpfc_bsg_mbox_ext_cleanup - clean up context of multi-buffer mbox session + * lpfc_bsg_mbox_ext_session_reset - clean up context of multi-buffer mbox session * @phba: Pointer to HBA context object. * * This is routine clean up and reset BSG handling of multi-buffer mbox @@ -3888,14 +3796,14 @@ lpfc_bsg_sli_cfg_dma_desc_setup(struct lpfc_hba *phba, enum nemb_type nemb_tp, } /** - * lpfc_bsg_sli_cfg_mse_read_cmd_ext - sli_config non-embedded mailbox cmd read + * lpfc_bsg_sli_cfg_read_cmd_ext - sli_config non-embedded mailbox cmd read * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. + * @job: Pointer to the job object. * @nemb_tp: Enumerate of non-embedded mailbox command type. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine performs SLI_CONFIG (0x9B) read mailbox command operation with - * non-embedded external bufffers. + * non-embedded external buffers. **/ static int lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, @@ -4079,11 +3987,12 @@ job_error: /** * lpfc_bsg_sli_cfg_write_cmd_ext - sli_config non-embedded mailbox cmd write * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. + * @nemb_tp: Enumerate of non-embedded mailbox command type. + * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine performs SLI_CONFIG (0x9B) write mailbox command operation with - * non-embedded external bufffers. + * non-embedded external buffers. **/ static int lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, @@ -4227,7 +4136,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job, goto job_error; } - /* wait for additoinal external buffers */ + /* wait for additional external buffers */ bsg_reply->result = 0; bsg_job_done(job, bsg_reply->result, @@ -4245,12 +4154,12 @@ job_error: /** * lpfc_bsg_handle_sli_cfg_mbox - handle sli-cfg mailbox cmd with ext buffer * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. + * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine handles SLI_CONFIG (0x9B) mailbox command with non-embedded - * external bufffers, including both 0x9B with non-embedded MSEs and 0x9B - * with embedded sussystem 0x1 and opcodes with external HBDs. + * external buffers, including both 0x9B with non-embedded MSEs and 0x9B + * with embedded subsystem 0x1 and opcodes with external HBDs. **/ static int lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct bsg_job *job, @@ -4306,6 +4215,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct bsg_job *job, case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: case COMN_OPCODE_GET_CNTL_ATTRIBUTES: case COMN_OPCODE_GET_PROFILE_CONFIG: + case COMN_OPCODE_SET_FEATURES: lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "3106 Handled SLI_CONFIG " "subsys_comn, opcode:x%x\n", @@ -4377,7 +4287,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct bsg_job *job, } /** - * lpfc_bsg_mbox_ext_abort_req - request to abort mbox command with ext buffers + * lpfc_bsg_mbox_ext_abort - request to abort mbox command with ext buffers * @phba: Pointer to HBA context object. * * This routine is for requesting to abort a pass-through mailbox command with @@ -4396,7 +4306,7 @@ lpfc_bsg_mbox_ext_abort(struct lpfc_hba *phba) /** * lpfc_bsg_read_ebuf_get - get the next mailbox read external buffer * @phba: Pointer to HBA context object. - * @dmabuf: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. * * This routine extracts the next mailbox read external buffer back to * user space through BSG. @@ -4466,6 +4376,7 @@ lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct bsg_job *job) /** * lpfc_bsg_write_ebuf_set - set the next mailbox write external buffer * @phba: Pointer to HBA context object. + * @job: Pointer to the job object. * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine sets up the next mailbox read external buffer obtained @@ -4573,7 +4484,7 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct bsg_job *job, goto job_error; } - /* wait for additoinal external buffers */ + /* wait for additional external buffers */ bsg_reply->result = 0; bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); @@ -4591,8 +4502,8 @@ job_error: /** * lpfc_bsg_handle_sli_cfg_ebuf - handle ext buffer with sli-cfg mailbox cmd * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. + * @dmabuf: Pointer to a DMA buffer descriptor. * * This routine handles the external buffer with SLI_CONFIG (0x9B) mailbox * command with multiple non-embedded external buffers. @@ -4636,10 +4547,10 @@ lpfc_bsg_handle_sli_cfg_ebuf(struct lpfc_hba *phba, struct bsg_job *job, /** * lpfc_bsg_handle_sli_cfg_ext - handle sli-cfg mailbox with external buffer * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. + * @job: Pointer to the job object. + * @dmabuf: Pointer to a DMA buffer descriptor. * - * This routine checkes and handles non-embedded multi-buffer SLI_CONFIG + * This routine checks and handles non-embedded multi-buffer SLI_CONFIG * (0x9B) mailbox commands and external buffers. **/ static int @@ -4710,14 +4621,14 @@ sli_cfg_ext_error: /** * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app * @phba: Pointer to HBA context object. - * @mb: Pointer to a mailbox object. + * @job: Pointer to the job object. * @vport: Pointer to a vport object. * * Allocate a tracking object, mailbox command memory, get a mailbox * from the mailbox pool, copy the caller mailbox command. * * If offline and the sli is active we need to poll for the command (port is - * being reset) and com-plete the job, otherwise issue the mailbox command and + * being reset) and complete the job, otherwise issue the mailbox command and * let our completion handler finish the command. **/ static int @@ -5060,283 +4971,6 @@ lpfc_bsg_mbox_cmd(struct bsg_job *job) return rc; } -/** - * lpfc_bsg_menlo_cmd_cmp - lpfc_menlo_cmd completion handler - * @phba: Pointer to HBA context object. - * @cmdiocbq: Pointer to command iocb. - * @rspiocbq: Pointer to response iocb. - * - * This function is the completion handler for iocbs issued using - * lpfc_menlo_cmd function. This function is called by the - * ring event handler function without any lock held. This function - * can be called from both worker thread context and interrupt - * context. This function also can be called from another thread which - * cleans up the SLI layer objects. - * This function copies the contents of the response iocb to the - * response iocb memory object provided by the caller of - * lpfc_sli_issue_iocb_wait and then wakes up the thread which - * sleeps for the iocb completion. - **/ -static void -lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba, - struct lpfc_iocbq *cmdiocbq, - struct lpfc_iocbq *rspiocbq) -{ - struct bsg_job_data *dd_data; - struct bsg_job *job; - struct fc_bsg_reply *bsg_reply; - IOCB_t *rsp; - struct lpfc_dmabuf *bmp, *cmp, *rmp; - struct lpfc_bsg_menlo *menlo; - unsigned long flags; - struct menlo_response *menlo_resp; - unsigned int rsp_size; - int rc = 0; - - dd_data = cmdiocbq->context1; - cmp = cmdiocbq->context2; - bmp = cmdiocbq->context3; - menlo = &dd_data->context_un.menlo; - rmp = menlo->rmp; - rsp = &rspiocbq->iocb; - - /* Determine if job has been aborted */ - spin_lock_irqsave(&phba->ct_ev_lock, flags); - job = dd_data->set_job; - if (job) { - bsg_reply = job->reply; - /* Prevent timeout handling from trying to abort job */ - job->dd_data = NULL; - } - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - - /* Copy the job data or set the failing status for the job */ - - if (job) { - /* always return the xri, this would be used in the case - * of a menlo download to allow the data to be sent as a - * continuation of the exchange. - */ - - menlo_resp = (struct menlo_response *) - bsg_reply->reply_data.vendor_reply.vendor_rsp; - menlo_resp->xri = rsp->ulpContext; - if (rsp->ulpStatus) { - if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) { - case IOERR_SEQUENCE_TIMEOUT: - rc = -ETIMEDOUT; - break; - case IOERR_INVALID_RPI: - rc = -EFAULT; - break; - default: - rc = -EACCES; - break; - } - } else { - rc = -EACCES; - } - } else { - rsp_size = rsp->un.genreq64.bdl.bdeSize; - bsg_reply->reply_payload_rcv_len = - lpfc_bsg_copy_data(rmp, &job->reply_payload, - rsp_size, 0); - } - - } - - lpfc_sli_release_iocbq(phba, cmdiocbq); - lpfc_free_bsg_buffers(phba, cmp); - lpfc_free_bsg_buffers(phba, rmp); - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); - kfree(bmp); - kfree(dd_data); - - /* Complete the job if active */ - - if (job) { - bsg_reply->result = rc; - bsg_job_done(job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); - } - - return; -} - -/** - * lpfc_menlo_cmd - send an ioctl for menlo hardware - * @job: fc_bsg_job to handle - * - * This function issues a gen request 64 CR ioctl for all menlo cmd requests, - * all the command completions will return the xri for the command. - * For menlo data requests a gen request 64 CX is used to continue the exchange - * supplied in the menlo request header xri field. - **/ -static int -lpfc_menlo_cmd(struct bsg_job *job) -{ - struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); - struct fc_bsg_request *bsg_request = job->request; - struct fc_bsg_reply *bsg_reply = job->reply; - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocbq; - IOCB_t *cmd; - int rc = 0; - struct menlo_command *menlo_cmd; - struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; - int request_nseg; - int reply_nseg; - struct bsg_job_data *dd_data; - struct ulp_bde64 *bpl = NULL; - - /* in case no data is returned return just the return code */ - bsg_reply->reply_payload_rcv_len = 0; - - if (job->request_len < - sizeof(struct fc_bsg_request) + - sizeof(struct menlo_command)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2784 Received MENLO_CMD request below " - "minimum size\n"); - rc = -ERANGE; - goto no_dd_data; - } - - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct menlo_response)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2785 Received MENLO_CMD reply below " - "minimum size\n"); - rc = -ERANGE; - goto no_dd_data; - } - - if (!(phba->menlo_flag & HBA_MENLO_SUPPORT)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2786 Adapter does not support menlo " - "commands\n"); - rc = -EPERM; - goto no_dd_data; - } - - menlo_cmd = (struct menlo_command *) - bsg_request->rqst_data.h_vendor.vendor_cmd; - - /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2787 Failed allocation of dd_data\n"); - rc = -ENOMEM; - goto no_dd_data; - } - - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) { - rc = -ENOMEM; - goto free_dd; - } - - bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); - if (!bmp->virt) { - rc = -ENOMEM; - goto free_bmp; - } - - INIT_LIST_HEAD(&bmp->list); - - bpl = (struct ulp_bde64 *)bmp->virt; - request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64); - cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len, - 1, bpl, &request_nseg); - if (!cmp) { - rc = -ENOMEM; - goto free_bmp; - } - lpfc_bsg_copy_data(cmp, &job->request_payload, - job->request_payload.payload_len, 1); - - bpl += request_nseg; - reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg; - rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0, - bpl, &reply_nseg); - if (!rmp) { - rc = -ENOMEM; - goto free_cmp; - } - - cmdiocbq = lpfc_sli_get_iocbq(phba); - if (!cmdiocbq) { - rc = -ENOMEM; - goto free_rmp; - } - - cmd = &cmdiocbq->iocb; - cmd->un.genreq64.bdl.ulpIoTag32 = 0; - cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); - cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); - cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - cmd->un.genreq64.bdl.bdeSize = - (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); - cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); - cmd->un.genreq64.w5.hcsw.Dfctl = 0; - cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CMD; - cmd->un.genreq64.w5.hcsw.Type = MENLO_TRANSPORT_TYPE; /* 0xfe */ - cmd->ulpBdeCount = 1; - cmd->ulpClass = CLASS3; - cmd->ulpOwner = OWN_CHIP; - cmd->ulpLe = 1; /* Limited Edition */ - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - cmdiocbq->vport = phba->pport; - /* We want the firmware to timeout before we do */ - cmd->ulpTimeout = MENLO_TIMEOUT - 5; - cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp; - cmdiocbq->context1 = dd_data; - cmdiocbq->context2 = cmp; - cmdiocbq->context3 = bmp; - if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) { - cmd->ulpCommand = CMD_GEN_REQUEST64_CR; - cmd->ulpPU = MENLO_PU; /* 3 */ - cmd->un.ulpWord[4] = MENLO_DID; /* 0x0000FC0E */ - cmd->ulpContext = MENLO_CONTEXT; /* 0 */ - } else { - cmd->ulpCommand = CMD_GEN_REQUEST64_CX; - cmd->ulpPU = 1; - cmd->un.ulpWord[4] = 0; - cmd->ulpContext = menlo_cmd->xri; - } - - dd_data->type = TYPE_MENLO; - dd_data->set_job = job; - dd_data->context_un.menlo.cmdiocbq = cmdiocbq; - dd_data->context_un.menlo.rmp = rmp; - job->dd_data = dd_data; - - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, - MENLO_TIMEOUT - 5); - if (rc == IOCB_SUCCESS) - return 0; /* done for now */ - - lpfc_sli_release_iocbq(phba, cmdiocbq); - -free_rmp: - lpfc_free_bsg_buffers(phba, rmp); -free_cmp: - lpfc_free_bsg_buffers(phba, cmp); -free_bmp: - if (bmp->virt) - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); - kfree(bmp); -free_dd: - kfree(dd_data); -no_dd_data: - /* make error code available to userspace */ - bsg_reply->result = rc; - job->dd_data = NULL; - return rc; -} - static int lpfc_forced_link_speed(struct bsg_job *job) { @@ -5360,9 +4994,7 @@ lpfc_forced_link_speed(struct bsg_job *job) forced_reply = (struct forced_link_speed_support_reply *) bsg_reply->reply_data.vendor_reply.vendor_rsp; - if (job->reply_len < - sizeof(struct fc_bsg_request) + - sizeof(struct forced_link_speed_support_reply)) { + if (job->reply_len < sizeof(*bsg_reply) + sizeof(*forced_reply)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "0049 Received FORCED_LINK_SPEED reply below " "minimum size\n"); @@ -5394,9 +5026,9 @@ lpfc_check_fwlog_support(struct lpfc_hba *phba) ras_fwlog = &phba->ras_fwlog; - if (ras_fwlog->ras_hwsupport == false) + if (!ras_fwlog->ras_hwsupport) return -EACCES; - else if (ras_fwlog->ras_enabled == false) + else if (!ras_fwlog->ras_enabled) return -EPERM; else return 0; @@ -5716,8 +5348,7 @@ lpfc_get_trunk_info(struct bsg_job *job) event_reply = (struct lpfc_trunk_info *) bsg_reply->reply_data.vendor_reply.vendor_rsp; - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct lpfc_trunk_info)) { + if (job->reply_len < sizeof(*bsg_reply) + sizeof(*event_reply)) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2728 Received GET TRUNK _INFO reply below " "minimum size\n"); @@ -5768,6 +5399,92 @@ job_error: } +static int +lpfc_get_cgnbuf_info(struct bsg_job *job) +{ + struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job)); + struct lpfc_hba *phba = vport->phba; + struct fc_bsg_request *bsg_request = job->request; + struct fc_bsg_reply *bsg_reply = job->reply; + struct get_cgnbuf_info_req *cgnbuf_req; + struct lpfc_cgn_info *cp; + uint8_t *cgn_buff; + int size, cinfosz; + int rc = 0; + + if (job->request_len < sizeof(struct fc_bsg_request) + + sizeof(struct get_cgnbuf_info_req)) { + rc = -ENOMEM; + goto job_exit; + } + + if (!phba->sli4_hba.pc_sli4_params.cmf) { + rc = -ENOENT; + goto job_exit; + } + + if (!phba->cgn_i || !phba->cgn_i->virt) { + rc = -ENOENT; + goto job_exit; + } + + cp = phba->cgn_i->virt; + if (cp->cgn_info_version < LPFC_CGN_INFO_V3) { + rc = -EPERM; + goto job_exit; + } + + cgnbuf_req = (struct get_cgnbuf_info_req *) + bsg_request->rqst_data.h_vendor.vendor_cmd; + + /* For reset or size == 0 */ + bsg_reply->reply_payload_rcv_len = 0; + + if (cgnbuf_req->reset == LPFC_BSG_CGN_RESET_STAT) { + lpfc_init_congestion_stat(phba); + goto job_exit; + } + + /* We don't want to include the CRC at the end */ + cinfosz = sizeof(struct lpfc_cgn_info) - sizeof(uint32_t); + + size = cgnbuf_req->read_size; + if (!size) + goto job_exit; + + if (size < cinfosz) { + /* Just copy back what we can */ + cinfosz = size; + rc = -E2BIG; + } + + /* Allocate memory to read congestion info */ + cgn_buff = vmalloc(cinfosz); + if (!cgn_buff) { + rc = -ENOMEM; + goto job_exit; + } + + memcpy(cgn_buff, cp, cinfosz); + + bsg_reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + cgn_buff, cinfosz); + + vfree(cgn_buff); + +job_exit: + bsg_reply->result = rc; + if (!rc) + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + else + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "2724 GET CGNBUF error: %d\n", rc); + return rc; +} + /** * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job * @job: fc_bsg_job to handle @@ -5808,10 +5525,6 @@ lpfc_bsg_hst_vendor(struct bsg_job *job) case LPFC_BSG_VENDOR_MBOX: rc = lpfc_bsg_mbox_cmd(job); break; - case LPFC_BSG_VENDOR_MENLO_CMD: - case LPFC_BSG_VENDOR_MENLO_DATA: - rc = lpfc_menlo_cmd(job); - break; case LPFC_BSG_VENDOR_FORCED_LINK_SPEED: rc = lpfc_forced_link_speed(job); break; @@ -5830,6 +5543,9 @@ lpfc_bsg_hst_vendor(struct bsg_job *job) case LPFC_BSG_VENDOR_GET_TRUNK_INFO: rc = lpfc_get_trunk_info(job); break; + case LPFC_BSG_VENDOR_GET_CGNBUF_INFO: + rc = lpfc_get_cgnbuf_info(job); + break; default: rc = -EINVAL; bsg_reply->reply_payload_rcv_len = 0; @@ -5929,7 +5645,7 @@ lpfc_bsg_timeout(struct bsg_job *job) spin_lock_irqsave(&phba->hbalock, flags); /* make sure the I/O abort window is still open */ - if (!(cmdiocb->iocb_flag & LPFC_IO_CMD_OUTSTANDING)) { + if (!(cmdiocb->cmd_flag & LPFC_IO_CMD_OUTSTANDING)) { spin_unlock_irqrestore(&phba->hbalock, flags); return -EAGAIN; } @@ -5941,7 +5657,7 @@ lpfc_bsg_timeout(struct bsg_job *job) } } if (list_empty(&completions)) - lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); + lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb, NULL); spin_unlock_irqrestore(&phba->hbalock, flags); if (!list_empty(&completions)) { lpfc_sli_cancel_iocbs(phba, &completions, @@ -5961,31 +5677,6 @@ lpfc_bsg_timeout(struct bsg_job *job) phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; spin_unlock_irqrestore(&phba->ct_ev_lock, flags); break; - case TYPE_MENLO: - /* Check to see if IOCB was issued to the port or not. If not, - * remove it from the txq queue and call cancel iocbs. - * Otherwise, call abort iotag. - */ - cmdiocb = dd_data->context_un.menlo.cmdiocbq; - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - - spin_lock_irqsave(&phba->hbalock, flags); - list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq, - list) { - if (check_iocb == cmdiocb) { - list_move_tail(&check_iocb->list, &completions); - break; - } - } - if (list_empty(&completions)) - lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); - spin_unlock_irqrestore(&phba->hbalock, flags); - if (!list_empty(&completions)) { - lpfc_sli_cancel_iocbs(phba, &completions, - IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); - } - break; default: spin_unlock_irqrestore(&phba->ct_ev_lock, flags); break; diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index d1708133fd54..3c04ca2d7455 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2010-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -33,8 +33,6 @@ #define LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK 5 #define LPFC_BSG_VENDOR_GET_MGMT_REV 6 #define LPFC_BSG_VENDOR_MBOX 7 -#define LPFC_BSG_VENDOR_MENLO_CMD 8 -#define LPFC_BSG_VENDOR_MENLO_DATA 9 #define LPFC_BSG_VENDOR_DIAG_MODE_END 10 #define LPFC_BSG_VENDOR_LINK_DIAG_TEST 11 #define LPFC_BSG_VENDOR_FORCED_LINK_SPEED 14 @@ -43,6 +41,7 @@ #define LPFC_BSG_VENDOR_RAS_GET_CONFIG 18 #define LPFC_BSG_VENDOR_RAS_SET_CONFIG 19 #define LPFC_BSG_VENDOR_GET_TRUNK_INFO 20 +#define LPFC_BSG_VENDOR_GET_CGNBUF_INFO 21 struct set_ct_event { uint32_t command; @@ -130,16 +129,6 @@ struct dfc_mbox_req { uint32_t extSeqNum; }; -/* Used for menlo command or menlo data. The xri is only used for menlo data */ -struct menlo_command { - uint32_t cmd; - uint32_t xri; -}; - -struct menlo_response { - uint32_t xri; /* return the xri of the iocb exchange */ -}; - /* * macros and data structures for handling sli-config mailbox command * pass-through support, this header file is shared between user and @@ -225,6 +214,10 @@ struct lpfc_sli_config_hdr { uint32_t reserved5; }; +#define LPFC_CSF_BOOT_DEV 0x1D +#define LPFC_CSF_QUERY 0 +#define LPFC_CSF_SAVE 1 + struct lpfc_sli_config_emb0_subsys { struct lpfc_sli_config_hdr sli_config_hdr; #define LPFC_MBX_SLI_CONFIG_MAX_MSE 19 @@ -243,6 +236,15 @@ struct lpfc_sli_config_emb0_subsys { #define FCOE_OPCODE_ADD_FCF 0x09 #define FCOE_OPCODE_SET_DPORT_MODE 0x27 #define FCOE_OPCODE_GET_DPORT_RESULTS 0x28 + uint32_t timeout; /* comn_set_feature timeout */ + uint32_t request_length; /* comn_set_feature request len */ + uint32_t version; /* comn_set_feature version */ + uint32_t csf_feature; /* comn_set_feature feature */ + uint32_t word69; /* comn_set_feature parameter len */ + uint32_t word70; /* comn_set_feature parameter val0 */ +#define lpfc_emb0_subcmnd_csf_p0_SHIFT 0 +#define lpfc_emb0_subcmnd_csf_p0_MASK 0x3 +#define lpfc_emb0_subcmnd_csf_p0_WORD word70 }; struct lpfc_sli_config_emb1_subsys { @@ -261,6 +263,7 @@ struct lpfc_sli_config_emb1_subsys { #define COMN_OPCODE_WRITE_OBJECT 0xAC #define COMN_OPCODE_READ_OBJECT_LIST 0xAD #define COMN_OPCODE_DELETE_OBJECT 0xAE +#define COMN_OPCODE_SET_FEATURES 0xBF #define COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES 0x79 #define COMN_OPCODE_GET_CNTL_ATTRIBUTES 0x20 uint32_t timeout; @@ -372,6 +375,13 @@ struct get_trunk_info_req { uint32_t command; }; +struct get_cgnbuf_info_req { + uint32_t command; + uint32_t read_size; + uint32_t reset; +#define LPFC_BSG_CGN_RESET_STAT 1 +}; + /* driver only */ #define SLI_CONFIG_NOT_HANDLED 0 #define SLI_CONFIG_HANDLED 1 diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 25d3dd39bc05..d2d207791056 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -24,7 +24,6 @@ typedef int (*node_filter)(struct lpfc_nodelist *, void *); struct fc_rport; struct fc_frame_header; -struct lpfc_nvmet_rcv_ctx; void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_sli_read_link_ste(struct lpfc_hba *); void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t); @@ -33,7 +32,9 @@ int lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); int lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *, struct lpfcMboxq *); void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); - +int lpfc_mbox_rsrc_prep(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox); +void lpfc_mbox_rsrc_cleanup(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, + enum lpfc_mbox_ctx locked); void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_read_topology(struct lpfc_hba *, LPFC_MBOXQ_t *, struct lpfc_dmabuf *); void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); @@ -56,12 +57,11 @@ void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *, void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *); -void lpfc_supported_pages(struct lpfcMboxq *); -void lpfc_pc_sli4_params(struct lpfcMboxq *); -int lpfc_pc_sli4_params_get(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_sli4_mbox_rsrc_extent(struct lpfc_hba *, struct lpfcMboxq *, uint16_t, uint16_t, bool); int lpfc_get_sli4_parameters(struct lpfc_hba *, LPFC_MBOXQ_t *); +int lpfc_reg_congestion_buf(struct lpfc_hba *phba); +int lpfc_unreg_congestion_buf(struct lpfc_hba *phba); struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); void lpfc_cleanup_rcv_buffers(struct lpfc_vport *); void lpfc_rcv_seq_check_edtov(struct lpfc_vport *); @@ -78,20 +78,44 @@ int lpfc_init_iocb_list(struct lpfc_hba *phba, int cnt); void lpfc_free_iocb_list(struct lpfc_hba *phba); int lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, struct lpfc_queue *drq, int count, int idx); +int lpfc_read_lds_params(struct lpfc_hba *phba); +uint32_t lpfc_calc_cmf_latency(struct lpfc_hba *phba); +void lpfc_cmf_signal_init(struct lpfc_hba *phba); +void lpfc_cmf_start(struct lpfc_hba *phba); +void lpfc_cmf_stop(struct lpfc_hba *phba); +void lpfc_init_congestion_stat(struct lpfc_hba *phba); +void lpfc_init_congestion_buf(struct lpfc_hba *phba); +int lpfc_sli4_cgn_params_read(struct lpfc_hba *phba); +uint32_t lpfc_cgn_calc_crc32(void *bufp, uint32_t sz, uint32_t seed); +int lpfc_config_cgn_signal(struct lpfc_hba *phba); +int lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total); +void lpfc_cgn_dump_rxmonitor(struct lpfc_hba *phba); +void lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag); +void lpfc_unblock_requests(struct lpfc_hba *phba); +void lpfc_block_requests(struct lpfc_hba *phba); +int lpfc_rx_monitor_create_ring(struct lpfc_rx_info_monitor *rx_monitor, + u32 entries); +void lpfc_rx_monitor_destroy_ring(struct lpfc_rx_info_monitor *rx_monitor); +void lpfc_rx_monitor_record(struct lpfc_rx_info_monitor *rx_monitor, + struct rx_info_entry *entry); +u32 lpfc_rx_monitor_report(struct lpfc_hba *phba, + struct lpfc_rx_info_monitor *rx_monitor, char *buf, + u32 buf_len, u32 max_read_entries); void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb); void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_unregister_vfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); -struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *, - struct lpfc_nodelist *, int); void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int); +void lpfc_nlp_reg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp); +void lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp); void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_set_disctmo(struct lpfc_vport *); int lpfc_can_disctmo(struct lpfc_vport *); @@ -106,12 +130,17 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_nodelist *lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did); struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *); int lpfc_nlp_put(struct lpfc_nodelist *); +void lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp); +void lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb); int lpfc_nlp_not_used(struct lpfc_nodelist *ndlp); struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t); void lpfc_disc_list_loopmap(struct lpfc_vport *); void lpfc_disc_start(struct lpfc_vport *); void lpfc_cleanup_discovery_resources(struct lpfc_vport *); void lpfc_cleanup(struct lpfc_vport *); +void lpfc_prep_embed_io(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd); void lpfc_disc_timeout(struct timer_list *); int lpfc_unregister_fcf_prep(struct lpfc_hba *); @@ -140,9 +169,12 @@ int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); -int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); +int lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry); int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry); int lpfc_issue_fabric_reglogin(struct lpfc_vport *); +int lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry); +int lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry); +void lpfc_els_rcv_fpin(struct lpfc_vport *vport, void *p, u32 fpin_length); int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, @@ -170,6 +202,7 @@ void lpfc_els_timeout_handler(struct lpfc_vport *); struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t, uint8_t, struct lpfc_nodelist *, uint32_t, uint32_t); +void lpfc_sli_prep_wqe(struct lpfc_hba *phba, struct lpfc_iocbq *job); void lpfc_hb_timeout_handler(struct lpfc_hba *); void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, @@ -187,10 +220,11 @@ void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *); int lpfc_config_port_prep(struct lpfc_hba *); void lpfc_update_vport_wwn(struct lpfc_vport *vport); int lpfc_config_port_post(struct lpfc_hba *); +int lpfc_sli4_refresh_params(struct lpfc_hba *phba); int lpfc_hba_down_prep(struct lpfc_hba *); int lpfc_hba_down_post(struct lpfc_hba *); void lpfc_hba_init(struct lpfc_hba *, uint32_t *); -int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int); +int lpfc_sli3_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt); void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); int lpfc_online(struct lpfc_hba *); void lpfc_unblock_mgmt_io(struct lpfc_hba *); @@ -215,6 +249,9 @@ irqreturn_t lpfc_sli_fp_intr_handler(int, void *); irqreturn_t lpfc_sli4_intr_handler(int, void *); irqreturn_t lpfc_sli4_hba_intr_handler(int, void *); +int lpfc_read_object(struct lpfc_hba *phba, char *s, uint32_t *datap, + uint32_t len); + void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba); int lpfc_sli4_poll_eq(struct lpfc_queue *q, uint8_t path); void lpfc_sli4_poll_hbtimer(struct timer_list *t); @@ -257,7 +294,6 @@ void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, int lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, struct fc_frame_header *fc_hdr); void lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, struct lpfc_queue *wq); -void lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba); void lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba); void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *, uint16_t); @@ -322,8 +358,28 @@ void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, uint32_t); +int lpfc_sli_issue_fcp_io(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag); int lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, struct lpfc_iocbq *pwqe); +int lpfc_sli4_issue_abort_iotag(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocb, void *cmpl); +void lpfc_sli_prep_els_req_rsp(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_vport *vport, + struct lpfc_dmabuf *bmp, u16 cmd_size, u32 did, + u32 elscmd, u8 tmo, u8 expect_rsp); +void lpfc_sli_prep_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq, + struct lpfc_dmabuf *bmp, u16 rpi, u32 num_entry, + u8 tmo); +void lpfc_sli_prep_xmit_seq64(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_dmabuf *bmp, u16 rpi, u16 ox_id, + u32 num_entry, u8 rctl, u8 last_seq, + u8 cr_cx_cmd); +void lpfc_sli_prep_abort_xri(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq, + u16 ulp_context, u16 iotag, u8 ulp_class, u16 cqid, + bool ia, bool wqec); struct lpfc_sglq *__lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xri); struct lpfc_sglq *__lpfc_sli_get_nvmet_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq); @@ -348,16 +404,18 @@ int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t); void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *); int lpfc_sli_hbq_size(void); int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *); + struct lpfc_iocbq *, void *); int lpfc_sli_sum_iocb(struct lpfc_vport *, uint16_t, uint64_t, lpfc_ctx_cmd); -int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t, - uint64_t, lpfc_ctx_cmd); +int lpfc_sli_abort_iocb(struct lpfc_vport *vport, u16 tgt_id, u64 lun_id, + lpfc_ctx_cmd abort_cmd); int lpfc_sli_abort_taskmgmt(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t, uint64_t, lpfc_ctx_cmd); void lpfc_mbox_timeout(struct timer_list *t); void lpfc_mbox_timeout_handler(struct lpfc_hba *); +int lpfc_issue_hb_mbox(struct lpfc_hba *phba); +void lpfc_issue_hb_tmo(struct lpfc_hba *phba); struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, @@ -383,10 +441,11 @@ void lpfc_nvmet_buf_free(struct lpfc_hba *phba, void *virtp, dma_addr_t dma); void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *); void lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp); +void lpfc_setup_fdmi_mask(struct lpfc_vport *vport); int lpfc_link_reset(struct lpfc_vport *vport); /* Function prototypes. */ -int lpfc_check_pci_resettable(const struct lpfc_hba *phba); +int lpfc_check_pci_resettable(struct lpfc_hba *phba); const char* lpfc_info(struct Scsi_Host *); int lpfc_scan_finished(struct Scsi_Host *, unsigned long); @@ -400,10 +459,9 @@ void lpfc_get_cfgparam(struct lpfc_hba *); void lpfc_get_vport_cfgparam(struct lpfc_vport *); int lpfc_alloc_sysfs_attr(struct lpfc_vport *); void lpfc_free_sysfs_attr(struct lpfc_vport *); -extern struct device_attribute *lpfc_hba_attrs[]; -extern struct device_attribute *lpfc_vport_attrs[]; +extern const struct attribute_group *lpfc_hba_groups[]; +extern const struct attribute_group *lpfc_vport_groups[]; extern struct scsi_host_template lpfc_template; -extern struct scsi_host_template lpfc_template_no_hr; extern struct scsi_host_template lpfc_template_nvme; extern struct scsi_host_template lpfc_vport_template; extern struct fc_function_template lpfc_transport_functions; @@ -456,6 +514,9 @@ void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *); void lpfc_create_static_vport(struct lpfc_hba *); void lpfc_stop_hba_timers(struct lpfc_hba *); void lpfc_stop_port(struct lpfc_hba *); +int lpfc_update_cmf_cmd(struct lpfc_hba *phba, uint32_t sz); +int lpfc_update_cmf_cmpl(struct lpfc_hba *phba, uint64_t val, uint32_t sz, + struct Scsi_Host *shost); void __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *); void lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *); void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t); @@ -565,15 +626,19 @@ void lpfc_nvme_update_localport(struct lpfc_vport *vport); int lpfc_nvmet_create_targetport(struct lpfc_hba *phba); int lpfc_nvmet_update_targetport(struct lpfc_hba *phba); void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba); -void lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb); +int lpfc_nvme_handle_lsreq(struct lpfc_hba *phba, + struct lpfc_async_xchg_ctx *axchg); +int lpfc_nvmet_handle_lsreq(struct lpfc_hba *phba, + struct lpfc_async_xchg_ctx *axchg); void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx, struct rqb_dmabuf *nvmebuf, uint64_t isr_ts, uint8_t cqflag); void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba); +void lpfc_nvmet_invalidate_host(struct lpfc_hba *phba, + struct lpfc_nodelist *ndlp); void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_wcqe_complete *abts_cmpl); + struct lpfc_iocbq *rspiocb); void lpfc_create_multixri_pools(struct lpfc_hba *phba); void lpfc_create_destroy_pools(struct lpfc_hba *phba); void lpfc_move_xri_pvt_to_pbl(struct lpfc_hba *phba, u32 hwqid); @@ -589,11 +654,36 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, int); void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd, struct lpfc_sli4_hdw_queue *qp); -void lpfc_nvme_cmd_template(void); +void lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd); +void lpfc_wqe_cmd_template(void); void lpfc_nvmet_cmd_template(void); -void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn); -void lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt); +void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, + uint32_t stat, uint32_t param); extern int lpfc_enable_nvmet_cnt; extern unsigned long long lpfc_enable_nvmet[]; extern int lpfc_no_hba_reset_cnt; extern unsigned long lpfc_no_hba_reset[]; +extern int lpfc_acqe_cgn_frequency; +extern int lpfc_fabric_cgn_frequency; +extern int lpfc_use_cgn_signal; + +extern union lpfc_wqe128 lpfc_iread_cmd_template; +extern union lpfc_wqe128 lpfc_iwrite_cmd_template; +extern union lpfc_wqe128 lpfc_icmnd_cmd_template; + +/* vmid interface */ +int lpfc_vmid_uvem(struct lpfc_vport *vport, struct lpfc_vmid *vmid, bool ins); +uint32_t lpfc_vmid_get_cs_ctl(struct lpfc_vport *vport); +int lpfc_vmid_cmd(struct lpfc_vport *vport, + int cmdcode, struct lpfc_vmid *vmid); +int lpfc_vmid_hash_fn(const char *vmid, int len); +struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport, + uint32_t hash, uint8_t *buf); +int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, + enum dma_data_direction iodir, + union lpfc_vmid_io_tag *tag); +void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport); +int lpfc_issue_els_qfpa(struct lpfc_vport *vport); + +void lpfc_sli_rpi_release(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 58b35a1442c1..e941a99aa965 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -44,7 +44,6 @@ #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_version.h" @@ -76,6 +75,9 @@ static char *lpfc_release_version = LPFC_DRIVER_VERSION; +static void +lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb); static void lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, @@ -85,12 +87,12 @@ lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "0146 Ignoring unsolicited CT No HBQ " "status = x%x\n", - piocbq->iocb.ulpStatus); + get_job_ulpstatus(phba, piocbq)); } lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "0145 Ignoring unsolicted CT HBQ Size:%d " + "0145 Ignoring unsolicited CT HBQ Size:%d " "status = x%x\n", - size, piocbq->iocb.ulpStatus); + size, get_job_ulpstatus(phba, piocbq)); } static void @@ -100,79 +102,348 @@ lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size); } +/** + * lpfc_ct_unsol_cmpl : Completion callback function for unsol ct commands + * @phba : pointer to lpfc hba data structure. + * @cmdiocb : pointer to lpfc command iocb data structure. + * @rspiocb : pointer to lpfc response iocb data structure. + * + * This routine is the callback function for issuing unsol ct reject command. + * The memory allocated in the reject command path is freed up here. + **/ +static void +lpfc_ct_unsol_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_nodelist *ndlp; + struct lpfc_dmabuf *mp, *bmp; + + ndlp = cmdiocb->ndlp; + if (ndlp) + lpfc_nlp_put(ndlp); + + mp = cmdiocb->rsp_dmabuf; + bmp = cmdiocb->bpl_dmabuf; + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + cmdiocb->rsp_dmabuf = NULL; + } + + if (bmp) { + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + kfree(bmp); + cmdiocb->bpl_dmabuf = NULL; + } + + lpfc_sli_release_iocbq(phba, cmdiocb); +} + +/** + * lpfc_ct_reject_event - Issue reject for unhandled CT MIB commands + * @ndlp: pointer to a node-list data structure. + * @ct_req: pointer to the CT request data structure. + * @ulp_context: context of received UNSOL CT command + * @ox_id: ox_id of the UNSOL CT command + * + * This routine is invoked by the lpfc_ct_handle_mibreq routine for sending + * a reject response. Reject response is sent for the unhandled commands. + **/ +static void +lpfc_ct_reject_event(struct lpfc_nodelist *ndlp, + struct lpfc_sli_ct_request *ct_req, + u16 ulp_context, u16 ox_id) +{ + struct lpfc_vport *vport = ndlp->vport; + struct lpfc_hba *phba = vport->phba; + struct lpfc_sli_ct_request *ct_rsp; + struct lpfc_iocbq *cmdiocbq = NULL; + struct lpfc_dmabuf *bmp = NULL; + struct lpfc_dmabuf *mp = NULL; + struct ulp_bde64 *bpl; + u8 rc = 0; + u32 tmo; + + /* fill in BDEs for command */ + mp = kmalloc(sizeof(*mp), GFP_KERNEL); + if (!mp) { + rc = 1; + goto ct_exit; + } + + mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp->phys); + if (!mp->virt) { + rc = 2; + goto ct_free_mp; + } + + /* Allocate buffer for Buffer ptr list */ + bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); + if (!bmp) { + rc = 3; + goto ct_free_mpvirt; + } + + bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &bmp->phys); + if (!bmp->virt) { + rc = 4; + goto ct_free_bmp; + } + + INIT_LIST_HEAD(&mp->list); + INIT_LIST_HEAD(&bmp->list); + + bpl = (struct ulp_bde64 *)bmp->virt; + memset(bpl, 0, sizeof(struct ulp_bde64)); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); + bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); + bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bpl->tus.f.bdeSize = (LPFC_CT_PREAMBLE - 4); + bpl->tus.w = le32_to_cpu(bpl->tus.w); + + ct_rsp = (struct lpfc_sli_ct_request *)mp->virt; + memset(ct_rsp, 0, sizeof(struct lpfc_sli_ct_request)); + + ct_rsp->RevisionId.bits.Revision = SLI_CT_REVISION; + ct_rsp->RevisionId.bits.InId = 0; + ct_rsp->FsType = ct_req->FsType; + ct_rsp->FsSubType = ct_req->FsSubType; + ct_rsp->CommandResponse.bits.Size = 0; + ct_rsp->CommandResponse.bits.CmdRsp = + cpu_to_be16(SLI_CT_RESPONSE_FS_RJT); + ct_rsp->ReasonCode = SLI_CT_REQ_NOT_SUPPORTED; + ct_rsp->Explanation = SLI_CT_NO_ADDITIONAL_EXPL; + + cmdiocbq = lpfc_sli_get_iocbq(phba); + if (!cmdiocbq) { + rc = 5; + goto ct_free_bmpvirt; + } + + if (phba->sli_rev == LPFC_SLI_REV4) { + lpfc_sli_prep_xmit_seq64(phba, cmdiocbq, bmp, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi], + ox_id, 1, FC_RCTL_DD_SOL_CTL, 1, + CMD_XMIT_SEQUENCE64_WQE); + } else { + lpfc_sli_prep_xmit_seq64(phba, cmdiocbq, bmp, 0, ulp_context, 1, + FC_RCTL_DD_SOL_CTL, 1, + CMD_XMIT_SEQUENCE64_CX); + } + + /* Save for completion so we can release these resources */ + cmdiocbq->rsp_dmabuf = mp; + cmdiocbq->bpl_dmabuf = bmp; + cmdiocbq->cmd_cmpl = lpfc_ct_unsol_cmpl; + tmo = (3 * phba->fc_ratov); + + cmdiocbq->retry = 0; + cmdiocbq->vport = vport; + cmdiocbq->drvrTimeout = tmo + LPFC_DRVR_TIMEOUT; + + cmdiocbq->ndlp = lpfc_nlp_get(ndlp); + if (!cmdiocbq->ndlp) + goto ct_no_ndlp; + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); + if (rc) { + lpfc_nlp_put(ndlp); + goto ct_no_ndlp; + } + return; + +ct_no_ndlp: + rc = 6; + lpfc_sli_release_iocbq(phba, cmdiocbq); +ct_free_bmpvirt: + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); +ct_free_bmp: + kfree(bmp); +ct_free_mpvirt: + lpfc_mbuf_free(phba, mp->virt, mp->phys); +ct_free_mp: + kfree(mp); +ct_exit: + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "6440 Unsol CT: Rsp err %d Data: x%x\n", + rc, vport->fc_flag); +} + +/** + * lpfc_ct_handle_mibreq - Process an unsolicited CT MIB request data buffer + * @phba: pointer to lpfc hba data structure. + * @ctiocbq: pointer to lpfc CT command iocb data structure. + * + * This routine is used for processing the IOCB associated with a unsolicited + * CT MIB request. It first determines whether there is an existing ndlp that + * matches the DID from the unsolicited IOCB. If not, it will return. + **/ +static void +lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq) +{ + struct lpfc_sli_ct_request *ct_req; + struct lpfc_nodelist *ndlp = NULL; + struct lpfc_vport *vport = ctiocbq->vport; + u32 ulp_status = get_job_ulpstatus(phba, ctiocbq); + u32 ulp_word4 = get_job_word4(phba, ctiocbq); + u32 did; + u32 mi_cmd; + + did = bf_get(els_rsp64_sid, &ctiocbq->wqe.xmit_els_rsp); + if (ulp_status) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6438 Unsol CT: status:x%x/x%x did : x%x\n", + ulp_status, ulp_word4, did); + return; + } + + /* Ignore traffic received during vport shutdown */ + if (vport->fc_flag & FC_UNLOADING) + return; + + ndlp = lpfc_findnode_did(vport, did); + if (!ndlp) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6439 Unsol CT: NDLP Not Found for DID : x%x", + did); + return; + } + + ct_req = (struct lpfc_sli_ct_request *)ctiocbq->cmd_dmabuf->virt; + + mi_cmd = ct_req->CommandResponse.bits.CmdRsp; + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "6442 : MI Cmd : x%x Not Supported\n", mi_cmd); + lpfc_ct_reject_event(ndlp, ct_req, + bf_get(wqe_ctxt_tag, + &ctiocbq->wqe.xmit_els_rsp.wqe_com), + bf_get(wqe_rcvoxid, + &ctiocbq->wqe.xmit_els_rsp.wqe_com)); +} + +/** + * lpfc_ct_unsol_event - Process an unsolicited event from a ct sli ring + * @phba: pointer to lpfc hba data structure. + * @pring: pointer to a SLI ring. + * @ctiocbq: pointer to lpfc ct iocb data structure. + * + * 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 appropriate routine + * after properly set up the iocb buffer from the SLI ring on which the + * unsolicited event was received. + **/ void lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *piocbq) + struct lpfc_iocbq *ctiocbq) { struct lpfc_dmabuf *mp = NULL; - IOCB_t *icmd = &piocbq->iocb; + IOCB_t *icmd = &ctiocbq->iocb; int i; struct lpfc_iocbq *iocbq; - dma_addr_t paddr; + struct lpfc_iocbq *iocb; + dma_addr_t dma_addr; uint32_t size; struct list_head head; - struct lpfc_dmabuf *bdeBuf; - - if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) - return; + struct lpfc_sli_ct_request *ct_req; + struct lpfc_dmabuf *bdeBuf1 = ctiocbq->cmd_dmabuf; + struct lpfc_dmabuf *bdeBuf2 = ctiocbq->bpl_dmabuf; + u32 status, parameter, bde_count = 0; + struct lpfc_wcqe_complete *wcqe_cmpl = NULL; + + ctiocbq->cmd_dmabuf = NULL; + ctiocbq->rsp_dmabuf = NULL; + ctiocbq->bpl_dmabuf = NULL; + + wcqe_cmpl = &ctiocbq->wcqe_cmpl; + status = get_job_ulpstatus(phba, ctiocbq); + parameter = get_job_word4(phba, ctiocbq); + if (phba->sli_rev == LPFC_SLI_REV4) + bde_count = wcqe_cmpl->word3; + else + bde_count = icmd->ulpBdeCount; - if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { + if (unlikely(status == IOSTAT_NEED_BUFFER)) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); - } else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((icmd->un.ulpWord[4] & IOERR_PARAM_MASK) == + } else if ((status == IOSTAT_LOCAL_REJECT) && + ((parameter & IOERR_PARAM_MASK) == IOERR_RCV_BUFFER_WAITING)) { /* Not enough posted buffers; Try posting more buffers */ phba->fc_stat.NoRcvBuf++; if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_post_buffer(phba, pring, 2); + lpfc_sli3_post_buffer(phba, pring, 2); return; } - /* If there are no BDEs associated with this IOCB, - * there is nothing to do. + /* If there are no BDEs associated + * with this IOCB, there is nothing to do. */ - if (icmd->ulpBdeCount == 0) + if (bde_count == 0) return; + ctiocbq->cmd_dmabuf = bdeBuf1; + if (bde_count == 2) + ctiocbq->bpl_dmabuf = bdeBuf2; + + ct_req = (struct lpfc_sli_ct_request *)ctiocbq->cmd_dmabuf->virt; + + if (ct_req->FsType == SLI_CT_MANAGEMENT_SERVICE && + ct_req->FsSubType == SLI_CT_MIB_Subtypes) { + lpfc_ct_handle_mibreq(phba, ctiocbq); + } else { + if (!lpfc_bsg_ct_unsol_event(phba, pring, ctiocbq)) + return; + } + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); - list_for_each_entry(iocbq, &head, list) { - icmd = &iocbq->iocb; - if (icmd->ulpBdeCount == 0) + list_add_tail(&head, &ctiocbq->list); + list_for_each_entry(iocb, &head, list) { + if (phba->sli_rev == LPFC_SLI_REV4) + bde_count = iocb->wcqe_cmpl.word3; + else + bde_count = iocb->iocb.ulpBdeCount; + + if (!bde_count) continue; - bdeBuf = iocbq->context2; - iocbq->context2 = NULL; - size = icmd->un.cont64[0].tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size); - lpfc_in_buf_free(phba, bdeBuf); - if (icmd->ulpBdeCount == 2) { - bdeBuf = iocbq->context3; - iocbq->context3 = NULL; - size = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, + bdeBuf1 = iocb->cmd_dmabuf; + iocb->cmd_dmabuf = NULL; + if (phba->sli_rev == LPFC_SLI_REV4) + size = iocb->wqe.gen_req.bde.tus.f.bdeSize; + else + size = iocb->iocb.un.cont64[0].tus.f.bdeSize; + lpfc_ct_unsol_buffer(phba, ctiocbq, bdeBuf1, size); + lpfc_in_buf_free(phba, bdeBuf1); + if (bde_count == 2) { + bdeBuf2 = iocb->bpl_dmabuf; + iocb->bpl_dmabuf = NULL; + if (phba->sli_rev == LPFC_SLI_REV4) + size = iocb->unsol_rcv_len; + else + size = iocb->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize; + lpfc_ct_unsol_buffer(phba, ctiocbq, bdeBuf2, size); - lpfc_in_buf_free(phba, bdeBuf); + lpfc_in_buf_free(phba, bdeBuf2); } } list_del(&head); } else { INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); + list_add_tail(&head, &ctiocbq->list); list_for_each_entry(iocbq, &head, list) { icmd = &iocbq->iocb; if (icmd->ulpBdeCount == 0) lpfc_ct_unsol_buffer(phba, iocbq, NULL, 0); for (i = 0; i < icmd->ulpBdeCount; i++) { - paddr = getPaddr(icmd->un.cont64[i].addrHigh, - icmd->un.cont64[i].addrLow); + dma_addr = getPaddr(icmd->un.cont64[i].addrHigh, + icmd->un.cont64[i].addrLow); mp = lpfc_sli_ringpostbuf_get(phba, pring, - paddr); + dma_addr); size = icmd->un.cont64[i].tus.f.bdeSize; lpfc_ct_unsol_buffer(phba, iocbq, mp, size); lpfc_in_buf_free(phba, mp); } - lpfc_post_buffer(phba, pring, i); + lpfc_sli3_post_buffer(phba, pring, i); } list_del(&head); } @@ -276,32 +547,31 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb) { struct lpfc_dmabuf *buf_ptr; - if (ctiocb->context_un.ndlp) { - lpfc_nlp_put(ctiocb->context_un.ndlp); - ctiocb->context_un.ndlp = NULL; - } - if (ctiocb->context1) { - buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1; + /* IOCBQ job structure gets cleaned during release. Just release + * the dma buffers here. + */ + if (ctiocb->cmd_dmabuf) { + buf_ptr = ctiocb->cmd_dmabuf; lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); kfree(buf_ptr); - ctiocb->context1 = NULL; + ctiocb->cmd_dmabuf = NULL; } - if (ctiocb->context2) { - lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2); - ctiocb->context2 = NULL; + if (ctiocb->rsp_dmabuf) { + lpfc_free_ct_rsp(phba, ctiocb->rsp_dmabuf); + ctiocb->rsp_dmabuf = NULL; } - if (ctiocb->context3) { - buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3; + if (ctiocb->bpl_dmabuf) { + buf_ptr = ctiocb->bpl_dmabuf; lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); kfree(buf_ptr); - ctiocb->context3 = NULL; + ctiocb->bpl_dmabuf = NULL; } lpfc_sli_release_iocbq(phba, ctiocb); return 0; } -/** +/* * lpfc_gen_req - Build and issue a GEN_REQUEST command to the SLI Layer * @vport: pointer to a host virtual N_Port data structure. * @bmp: Pointer to BPL for SLI command @@ -315,15 +585,15 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb) static int lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp, - void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *), - struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry, + void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, + struct lpfc_iocbq *), + struct lpfc_nodelist *ndlp, uint32_t event_tag, uint32_t num_entry, uint32_t tmo, uint8_t retry) { struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; struct lpfc_iocbq *geniocb; int rc; + u16 ulp_context; /* Allocate buffer for command iocb */ geniocb = lpfc_sli_get_iocbq(phba); @@ -331,71 +601,56 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, if (geniocb == NULL) return 1; - icmd = &geniocb->iocb; - icmd->un.genreq64.bdl.ulpIoTag32 = 0; - icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); - icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); - icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); + /* Update the num_entry bde count */ + geniocb->num_bdes = num_entry; - if (usr_flg) - geniocb->context3 = NULL; - else - geniocb->context3 = (uint8_t *) bmp; + geniocb->bpl_dmabuf = bmp; /* Save for completion so we can release these resources */ - geniocb->context1 = (uint8_t *) inp; - geniocb->context2 = (uint8_t *) outp; - geniocb->context_un.ndlp = lpfc_nlp_get(ndlp); + geniocb->cmd_dmabuf = inp; + geniocb->rsp_dmabuf = outp; - /* Fill in payload, bp points to frame payload */ - icmd->ulpCommand = CMD_GEN_REQUEST64_CR; - - /* Fill in rest of iocb */ - icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); - icmd->un.genreq64.w5.hcsw.Dfctl = 0; - icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; - icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; + geniocb->event_tag = event_tag; if (!tmo) { /* FC spec states we need 3 * ratov for CT requests */ tmo = (3 * phba->fc_ratov); } - icmd->ulpTimeout = tmo; - icmd->ulpBdeCount = 1; - icmd->ulpLe = 1; - icmd->ulpClass = CLASS3; - icmd->ulpContext = ndlp->nlp_rpi; + if (phba->sli_rev == LPFC_SLI_REV4) - icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; + ulp_context = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; + else + ulp_context = ndlp->nlp_rpi; - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { - /* For GEN_REQUEST64_CR, use the RPI */ - icmd->ulpCt_h = 0; - icmd->ulpCt_l = 0; - } + lpfc_sli_prep_gen_req(phba, geniocb, bmp, ulp_context, num_entry, tmo); /* Issue GEN REQ IOCB for NPORT <did> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0119 Issue GEN REQ IOCB to NPORT x%x " "Data: x%x x%x\n", - ndlp->nlp_DID, icmd->ulpIoTag, + ndlp->nlp_DID, geniocb->iotag, vport->port_state); - geniocb->iocb_cmpl = cmpl; - geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; + geniocb->cmd_cmpl = cmpl; + geniocb->drvrTimeout = tmo + LPFC_DRVR_TIMEOUT; geniocb->vport = vport; geniocb->retry = retry; - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0); + geniocb->ndlp = lpfc_nlp_get(ndlp); + if (!geniocb->ndlp) + goto out; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0); if (rc == IOCB_ERROR) { - lpfc_sli_release_iocbq(phba, geniocb); - return 1; + lpfc_nlp_put(ndlp); + goto out; } return 0; +out: + lpfc_sli_release_iocbq(phba, geniocb); + return 1; } -/** +/* * lpfc_ct_cmd - Build and issue a CT command * @vport: pointer to a host virtual N_Port data structure. * @inmp: Pointer to data buffer for response data. @@ -431,8 +686,8 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, * lpfc_alloc_ct_rsp. */ cnt += 1; - status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0, - cnt, 0, retry); + status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, + phba->fc_eventTag, cnt, 0, retry); if (status) { lpfc_free_ct_rsp(phba, outmp); return -ENOMEM; @@ -462,12 +717,11 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) struct lpfc_nodelist *ndlp; if ((vport->port_type != LPFC_NPIV_PORT) || - (fc4_type == FC_TYPE_FCP) || !(vport->ct_flags & FC_CT_RFF_ID) || !vport->cfg_restrict_login) { ndlp = lpfc_setup_disc_node(vport, Did); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + if (ndlp) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "Parse GID_FTrsp: did:x%x flg:x%x x%x", Did, ndlp->nlp_flag, vport->fc_flag); @@ -502,7 +756,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0239 Skip x%06x NameServer Rsp " - "Data: x%x x%x %p\n", + "Data: x%x x%x x%px\n", Did, vport->fc_flag, vport->fc_rscn_id_cnt, ndlp); } @@ -518,7 +772,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) * Don't even bother to send GFF_ID. */ ndlp = lpfc_findnode_did(vport, Did); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + if (ndlp && (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET))) { if (fc4_type == FC_TYPE_FCP) @@ -550,7 +804,6 @@ lpfc_ns_rsp_audit_did(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) { struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); char *str; if (phba->cfg_ns_query == LPFC_NS_QUERY_GID_FT) @@ -579,12 +832,12 @@ lpfc_ns_rsp_audit_did(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) if (ndlp->nlp_type != NLP_NVME_INITIATOR || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) continue; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); if (ndlp->nlp_DID == Did) ndlp->nlp_flag &= ~NLP_NVMET_RECOV; else ndlp->nlp_flag |= NLP_NVMET_RECOV; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } } } @@ -600,7 +853,6 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint8_t fc4_type, uint32_t Did, CTentry; int Cnt; struct list_head head; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp = NULL; lpfc_set_disctmo(vport); @@ -646,9 +898,9 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint8_t fc4_type, continue; lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NVMET_RECOV; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } } @@ -663,26 +915,33 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp; struct lpfc_dmabuf *outp; struct lpfc_dmabuf *inp; struct lpfc_sli_ct_request *CTrsp; struct lpfc_sli_ct_request *CTreq; struct lpfc_nodelist *ndlp; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); int rc, type; /* First save ndlp, before we overwrite it */ - ndlp = cmdiocb->context_un.ndlp; + ndlp = cmdiocb->ndlp; /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; - inp = (struct lpfc_dmabuf *) cmdiocb->context1; - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - irsp = &rspiocb->iocb; + cmdiocb->rsp_iocb = rspiocb; + inp = cmdiocb->cmd_dmabuf; + outp = cmdiocb->rsp_dmabuf; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "GID_FT cmpl: status:x%x/x%x rtry:%d", - irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry); + ulp_status, ulp_word4, vport->fc_ns_retry); + + /* Ignore response if link flipped after this request was made */ + if (cmdiocb->event_tag != phba->fc_eventTag) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "9043 Event tag mismatch. Ignoring NS rsp\n"); + goto out; + } /* Don't bother processing response if vport is being torn down. */ if (vport->load_flag & FC_UNLOADING) { @@ -699,11 +958,17 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_vport_set_state(vport, FC_VPORT_FAILED); goto out; } - if (lpfc_error_lost_link(irsp)) { + if (lpfc_error_lost_link(ulp_status, ulp_word4)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0226 NS query failed due to link event\n"); + "0226 NS query failed due to link event: " + "ulp_status x%x ulp_word4 x%x fc_flag x%x " + "port_state x%x gidft_inp x%x\n", + ulp_status, ulp_word4, vport->fc_flag, + vport->port_state, vport->gidft_inp); if (vport->fc_flag & FC_RSCN_MODE) lpfc_els_flush_rscn(vport); + if (vport->gidft_inp) + vport->gidft_inp--; goto out; } @@ -715,7 +980,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* This is a GID_FT completing so the gidft_inp counter was * incremented before the GID_FT was issued to the wire. */ - vport->gidft_inp--; + if (vport->gidft_inp) + vport->gidft_inp--; /* * Skip processing the NS response @@ -730,11 +996,11 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } spin_unlock_irq(shost->host_lock); - if (irsp->ulpStatus) { + if (ulp_status) { /* Check for retry */ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { - if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT || - (irsp->un.ulpWord[4] & IOERR_PARAM_MASK) != + if (ulp_status != IOSTAT_LOCAL_REJECT || + (ulp_word4 & IOERR_PARAM_MASK) != IOERR_NO_RESOURCES) vport->fc_ns_retry++; @@ -743,18 +1009,21 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; /* CT command is being retried */ - vport->gidft_inp--; rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, vport->fc_ns_retry, type); if (rc == 0) goto out; + else { /* Unable to send NS cmd */ + if (vport->gidft_inp) + vport->gidft_inp--; + } } if (vport->fc_flag & FC_RSCN_MODE) lpfc_els_flush_rscn(vport); lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0257 GID_FT Query error: 0x%x 0x%x\n", - irsp->ulpStatus, vport->fc_ns_retry); + ulp_status, vport->fc_ns_retry); } else { /* Good status, continue checking */ CTreq = (struct lpfc_sli_ct_request *) inp->virt; @@ -768,12 +1037,12 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, CTreq->un.gid.Fc4Type, vport->num_disc_nodes, vport->gidft_inp, - irsp->un.genreq64.bdl.bdeSize); + get_job_data_placed(phba, rspiocb)); lpfc_ns_rsp(vport, outp, CTreq->un.gid.Fc4Type, - (uint32_t) (irsp->un.genreq64.bdl.bdeSize)); + get_job_data_placed(phba, rspiocb)); } else if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { /* NameServer Rsp Error */ @@ -813,7 +1082,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } else { /* NameServer Rsp Error */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0241 NameServer Rsp Error " "Data: x%x x%x x%x x%x\n", CTrsp->CommandResponse.bits.CmdRsp, @@ -827,7 +1096,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (uint32_t) CTrsp->ReasonCode, (uint32_t) CTrsp->Explanation); } - vport->gidft_inp--; + if (vport->gidft_inp) + vport->gidft_inp--; } lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -856,8 +1126,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_disc_start(vport); } out: - cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */ lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -867,28 +1137,35 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp; struct lpfc_dmabuf *outp; struct lpfc_dmabuf *inp; struct lpfc_sli_ct_request *CTrsp; struct lpfc_sli_ct_request *CTreq; struct lpfc_nodelist *ndlp; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); int rc; /* First save ndlp, before we overwrite it */ - ndlp = cmdiocb->context_un.ndlp; + ndlp = cmdiocb->ndlp; /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; - inp = (struct lpfc_dmabuf *)cmdiocb->context1; - outp = (struct lpfc_dmabuf *)cmdiocb->context2; - irsp = &rspiocb->iocb; + cmdiocb->rsp_iocb = rspiocb; + inp = cmdiocb->cmd_dmabuf; + outp = cmdiocb->rsp_dmabuf; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "GID_PT cmpl: status:x%x/x%x rtry:%d", - irsp->ulpStatus, irsp->un.ulpWord[4], + ulp_status, ulp_word4, vport->fc_ns_retry); + /* Ignore response if link flipped after this request was made */ + if (cmdiocb->event_tag != phba->fc_eventTag) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "9044 Event tag mismatch. Ignoring NS rsp\n"); + goto out; + } + /* Don't bother processing response if vport is being torn down. */ if (vport->load_flag & FC_UNLOADING) { if (vport->fc_flag & FC_RSCN_MODE) @@ -904,11 +1181,17 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_vport_set_state(vport, FC_VPORT_FAILED); goto out; } - if (lpfc_error_lost_link(irsp)) { + if (lpfc_error_lost_link(ulp_status, ulp_word4)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "4166 NS query failed due to link event\n"); + "4166 NS query failed due to link event: " + "ulp_status x%x ulp_word4 x%x fc_flag x%x " + "port_state x%x gidft_inp x%x\n", + ulp_status, ulp_word4, vport->fc_flag, + vport->port_state, vport->gidft_inp); if (vport->fc_flag & FC_RSCN_MODE) lpfc_els_flush_rscn(vport); + if (vport->gidft_inp) + vport->gidft_inp--; goto out; } @@ -920,7 +1203,8 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* This is a GID_PT completing so the gidft_inp counter was * incremented before the GID_PT was issued to the wire. */ - vport->gidft_inp--; + if (vport->gidft_inp) + vport->gidft_inp--; /* * Skip processing the NS response @@ -935,27 +1219,30 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } spin_unlock_irq(shost->host_lock); - if (irsp->ulpStatus) { + if (ulp_status) { /* Check for retry */ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { - if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT || - (irsp->un.ulpWord[4] & IOERR_PARAM_MASK) != + if (ulp_status != IOSTAT_LOCAL_REJECT || + (ulp_word4 & IOERR_PARAM_MASK) != IOERR_NO_RESOURCES) vport->fc_ns_retry++; /* CT command is being retried */ - vport->gidft_inp--; rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_PT, vport->fc_ns_retry, GID_PT_N_PORT); if (rc == 0) goto out; + else { /* Unable to send NS cmd */ + if (vport->gidft_inp) + vport->gidft_inp--; + } } if (vport->fc_flag & FC_RSCN_MODE) lpfc_els_flush_rscn(vport); lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "4103 GID_FT Query error: 0x%x 0x%x\n", - irsp->ulpStatus, vport->fc_ns_retry); + ulp_status, vport->fc_ns_retry); } else { /* Good status, continue checking */ CTreq = (struct lpfc_sli_ct_request *)inp->virt; @@ -969,12 +1256,12 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, CTreq->un.gid.Fc4Type, vport->num_disc_nodes, vport->gidft_inp, - irsp->un.genreq64.bdl.bdeSize); + get_job_data_placed(phba, rspiocb)); lpfc_ns_rsp(vport, outp, CTreq->un.gid.Fc4Type, - (uint32_t)(irsp->un.genreq64.bdl.bdeSize)); + get_job_data_placed(phba, rspiocb)); } else if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { /* NameServer Rsp Error */ @@ -1014,7 +1301,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } else { /* NameServer Rsp Error */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "4109 NameServer Rsp Error " "Data: x%x x%x x%x x%x\n", CTrsp->CommandResponse.bits.CmdRsp, @@ -1029,7 +1316,8 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (uint32_t)CTrsp->ReasonCode, (uint32_t)CTrsp->Explanation); } - vport->gidft_inp--; + if (vport->gidft_inp) + vport->gidft_inp--; } lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -1058,8 +1346,8 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_disc_start(vport); } out: - cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */ lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } static void @@ -1068,22 +1356,30 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1; - struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2; + struct lpfc_dmabuf *inp = cmdiocb->cmd_dmabuf; + struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf; struct lpfc_sli_ct_request *CTrsp; int did, rc, retry; uint8_t fbits; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp = NULL, *free_ndlp = NULL; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId; did = be32_to_cpu(did); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "GFF_ID cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], did); + ulp_status, ulp_word4, did); + + /* Ignore response if link flipped after this request was made */ + if (cmdiocb->event_tag != phba->fc_eventTag) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "9045 Event tag mismatch. Ignoring NS rsp\n"); + goto iocb_free; + } - if (irsp->ulpStatus == IOSTAT_SUCCESS) { + if (ulp_status == IOSTAT_SUCCESS) { /* Good status, continue checking */ CTrsp = (struct lpfc_sli_ct_request *) outp->virt; fbits = CTrsp->un.gff_acc.fbits[FCP_TYPE_FEATURE_OFFSET]; @@ -1113,8 +1409,8 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check for retry */ if (cmdiocb->retry < LPFC_MAX_NS_RETRY) { retry = 1; - if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch ((irsp->un.ulpWord[4] & + if (ulp_status == IOSTAT_LOCAL_REJECT) { + switch ((ulp_word4 & IOERR_PARAM_MASK)) { case IOERR_NO_RESOURCES: @@ -1140,21 +1436,23 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cmdiocb->retry, did); if (rc == 0) { /* success */ + free_ndlp = cmdiocb->ndlp; lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); return; } } } - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0267 NameServer GFF Rsp " "x%x Error (%d %d) Data: x%x x%x\n", - did, irsp->ulpStatus, irsp->un.ulpWord[4], + did, ulp_status, ulp_word4, vport->fc_flag, vport->fc_rscn_id_cnt); } /* This is a target port, unregistered port, or the GFF_ID failed */ ndlp = lpfc_setup_disc_node(vport, did); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + if (ndlp) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0242 Process x%x GFF " "NameServer Rsp Data: x%x x%x x%x\n", @@ -1193,31 +1491,44 @@ out: } lpfc_disc_start(vport); } + +iocb_free: + free_ndlp = cmdiocb->ndlp; lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); return; } static void lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) + struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *)cmdiocb->context1; - struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *)cmdiocb->context2; + struct lpfc_dmabuf *inp = cmdiocb->cmd_dmabuf; + struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf; struct lpfc_sli_ct_request *CTrsp; int did; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp = NULL; + struct lpfc_nodelist *ns_ndlp = cmdiocb->ndlp; uint32_t fc4_data_0, fc4_data_1; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); did = ((struct lpfc_sli_ct_request *)inp->virt)->un.gft.PortId; did = be32_to_cpu(did); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "GFT_ID cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], did); + ulp_status, ulp_word4, did); - if (irsp->ulpStatus == IOSTAT_SUCCESS) { + /* Ignore response if link flipped after this request was made */ + if ((uint32_t)cmdiocb->event_tag != phba->fc_eventTag) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "9046 Event tag mismatch. Ignoring NS rsp\n"); + goto out; + } + + if (ulp_status == IOSTAT_SUCCESS) { /* Good status, continue checking */ CTrsp = (struct lpfc_sli_ct_request *)outp->virt; fc4_data_0 = be32_to_cpu(CTrsp->un.gft_acc.fc4_types[0]); @@ -1232,6 +1543,10 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, (fc4_data_1 & LPFC_FC4_TYPE_BITMASK) ? "NVME" : " "); + /* Lookup the NPort_ID queried in the GFT_ID and find the + * driver's local node. It's an error if the driver + * doesn't have one. + */ ndlp = lpfc_findnode_did(vport, did); if (ndlp) { /* The bitmask value for FCP and NVME FCP types is @@ -1273,10 +1588,12 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } } else - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "3065 GFT_ID failed x%08x\n", irsp->ulpStatus); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "3065 GFT_ID failed x%08x\n", ulp_status); +out: lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ns_ndlp); } static void @@ -1286,22 +1603,22 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; struct lpfc_dmabuf *inp; struct lpfc_dmabuf *outp; - IOCB_t *irsp; struct lpfc_sli_ct_request *CTrsp; struct lpfc_nodelist *ndlp; int cmdcode, rc; uint8_t retry; uint32_t latt; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); /* First save ndlp, before we overwrite it */ - ndlp = cmdiocb->context_un.ndlp; + ndlp = cmdiocb->ndlp; /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; + cmdiocb->rsp_iocb = rspiocb; - inp = (struct lpfc_dmabuf *) cmdiocb->context1; - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - irsp = &rspiocb->iocb; + inp = cmdiocb->cmd_dmabuf; + outp = cmdiocb->rsp_dmabuf; cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)-> CommandResponse.bits.CmdRsp); @@ -1309,28 +1626,28 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, latt = lpfc_els_chk_latt(vport); - /* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */ + /* RFT request completes status <ulp_status> CmdRsp <CmdRsp> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0209 CT Request completes, latt %d, " - "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n", - latt, irsp->ulpStatus, + "ulp_status x%x CmdRsp x%x, Context x%x, Tag x%x\n", + latt, ulp_status, CTrsp->CommandResponse.bits.CmdRsp, - cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag); + get_job_ulpcontext(phba, cmdiocb), cmdiocb->iotag); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "CT cmd cmpl: status:x%x/x%x cmd:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode); + ulp_status, ulp_word4, cmdcode); - if (irsp->ulpStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + if (ulp_status) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0268 NS cmd x%x Error (x%x x%x)\n", - cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]); + cmdcode, ulp_status, ulp_word4); - if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == - IOERR_SLI_DOWN) || - ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == - IOERR_SLI_ABORTED))) + if (ulp_status == IOSTAT_LOCAL_REJECT && + (((ulp_word4 & IOERR_PARAM_MASK) == + IOERR_SLI_DOWN) || + ((ulp_word4 & IOERR_PARAM_MASK) == + IOERR_SLI_ABORTED))) goto out; retry = cmdiocb->retry; @@ -1346,8 +1663,8 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } out: - cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */ lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -1355,15 +1672,15 @@ static void lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - IOCB_t *irsp = &rspiocb->iocb; struct lpfc_vport *vport = cmdiocb->vport; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); - if (irsp->ulpStatus == IOSTAT_SUCCESS) { + if (ulp_status == IOSTAT_SUCCESS) { struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + outp = cmdiocb->rsp_dmabuf; + CTrsp = (struct lpfc_sli_ct_request *)outp->virt; if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) vport->ct_flags |= FC_CT_RFT_ID; @@ -1376,14 +1693,14 @@ static void lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - IOCB_t *irsp = &rspiocb->iocb; struct lpfc_vport *vport = cmdiocb->vport; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); - if (irsp->ulpStatus == IOSTAT_SUCCESS) { + if (ulp_status == IOSTAT_SUCCESS) { struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; - outp = (struct lpfc_dmabuf *) cmdiocb->context2; + outp = cmdiocb->rsp_dmabuf; CTrsp = (struct lpfc_sli_ct_request *) outp->virt; if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) @@ -1397,15 +1714,15 @@ static void lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - IOCB_t *irsp = &rspiocb->iocb; struct lpfc_vport *vport = cmdiocb->vport; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); - if (irsp->ulpStatus == IOSTAT_SUCCESS) { + if (ulp_status == IOSTAT_SUCCESS) { struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + outp = cmdiocb->rsp_dmabuf; + CTrsp = (struct lpfc_sli_ct_request *)outp->virt; if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) vport->ct_flags |= FC_CT_RSPN_ID; @@ -1418,14 +1735,14 @@ static void lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - IOCB_t *irsp = &rspiocb->iocb; struct lpfc_vport *vport = cmdiocb->vport; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); - if (irsp->ulpStatus == IOSTAT_SUCCESS) { + if (ulp_status == IOSTAT_SUCCESS) { struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; - outp = (struct lpfc_dmabuf *) cmdiocb->context2; + outp = cmdiocb->rsp_dmabuf; CTrsp = (struct lpfc_sli_ct_request *) outp->virt; if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) @@ -1451,15 +1768,15 @@ static void lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - IOCB_t *irsp = &rspiocb->iocb; struct lpfc_vport *vport = cmdiocb->vport; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); - if (irsp->ulpStatus == IOSTAT_SUCCESS) { + if (ulp_status == IOSTAT_SUCCESS) { struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + outp = cmdiocb->rsp_dmabuf; + CTrsp = (struct lpfc_sli_ct_request *)outp->virt; if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) vport->ct_flags |= FC_CT_RFF_ID; @@ -1555,7 +1872,7 @@ lpfc_get_gidft_type(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb) struct lpfc_dmabuf *mp; uint32_t type; - mp = cmdiocb->context1; + mp = cmdiocb->cmd_dmabuf; if (mp == NULL) return 0; CtReq = (struct lpfc_sli_ct_request *)mp->virt; @@ -1589,8 +1906,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, int rc = 0; ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) - || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { + if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { rc=1; goto ns_cmd_exit; } @@ -1709,28 +2025,30 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, vport->ct_flags &= ~FC_CT_RFT_ID; CtReq->CommandResponse.bits.CmdRsp = cpu_to_be16(SLI_CTNS_RFT_ID); - CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID); + CtReq->un.rft.port_id = cpu_to_be32(vport->fc_myDID); + + /* Register Application Services type if vmid enabled. */ + if (phba->cfg_vmid_app_header) + CtReq->un.rft.app_serv_reg = + cpu_to_be32(RFT_APP_SERV_REG); /* Register FC4 FCP type if enabled. */ if (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH || vport->cfg_enable_fc4_type == LPFC_ENABLE_FCP) - CtReq->un.rft.fcpReg = 1; + CtReq->un.rft.fcp_reg = cpu_to_be32(RFT_FCP_REG); - /* Register NVME type if enabled. Defined LE and swapped. - * rsvd[0] is used as word1 because of the hard-coded - * word0 usage in the ct_request data structure. - */ + /* Register NVME type if enabled. */ if (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH || vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME) - CtReq->un.rft.rsvd[0] = - cpu_to_be32(LPFC_FC4_TYPE_BITMASK); + CtReq->un.rft.nvme_reg = cpu_to_be32(RFT_NVME_REG); ptr = (uint32_t *)CtReq; lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "6433 Issue RFT (%s %s): %08x %08x %08x %08x " - "%08x %08x %08x %08x\n", - CtReq->un.rft.fcpReg ? "FCP" : " ", - CtReq->un.rft.rsvd[0] ? "NVME" : " ", + "6433 Issue RFT (%s %s %s): %08x %08x %08x " + "%08x %08x %08x %08x %08x\n", + CtReq->un.rft.fcp_reg ? "FCP" : " ", + CtReq->un.rft.nvme_reg ? "NVME" : " ", + CtReq->un.rft.app_serv_reg ? "APPS" : " ", *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4), *(ptr + 5), *(ptr + 6), *(ptr + 7)); @@ -1831,11 +2149,6 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, } rc=6; - /* Decrement ndlp reference count to release ndlp reference held - * for the failed command's callback function. - */ - lpfc_nlp_put(ndlp); - ns_cmd_free_bmpvirt: lpfc_mbuf_free(phba, bmp->virt, bmp->phys); ns_cmd_free_bmp: @@ -1845,13 +2158,48 @@ ns_cmd_free_mpvirt: ns_cmd_free_mp: kfree(mp); ns_cmd_exit: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0266 Issue NameServer Req x%x err %d Data: x%x x%x\n", cmdcode, rc, vport->fc_flag, vport->fc_rscn_id_cnt); return 1; } /** + * lpfc_fdmi_rprt_defer - Check for any deferred FDMI RPRT commands + * @phba: Pointer to HBA context object. + * @mask: Initial port attributes mask + * + * This function checks to see if any vports have deferred their FDMI RPRT. + * A vports RPRT may be deferred if it is issued before the primary ports + * RHBA completes. + */ +static void +lpfc_fdmi_rprt_defer(struct lpfc_hba *phba, uint32_t mask) +{ + struct lpfc_vport **vports; + struct lpfc_vport *vport; + struct lpfc_nodelist *ndlp; + int i; + + phba->hba_flag |= HBA_RHBA_CMPL; + vports = lpfc_create_vport_work_array(phba); + if (vports) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + vport = vports[i]; + ndlp = lpfc_findnode_did(phba->pport, FDMI_DID); + if (!ndlp) + continue; + if (vport->ct_flags & FC_CT_RPRT_DEFER) { + vport->ct_flags &= ~FC_CT_RPRT_DEFER; + vport->fdmi_port_mask = mask; + lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0); + } + } + } + lpfc_destroy_vport_work_array(phba, vports); +} + +/** * lpfc_cmpl_ct_disc_fdmi - Handle a discovery FDMI completion * @phba: Pointer to HBA context object. * @cmdiocb: Pointer to the command IOCBQ. @@ -1865,26 +2213,27 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct lpfc_dmabuf *inp = cmdiocb->context1; - struct lpfc_dmabuf *outp = cmdiocb->context2; + struct lpfc_dmabuf *inp = cmdiocb->cmd_dmabuf; + struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf; struct lpfc_sli_ct_request *CTcmd = inp->virt; struct lpfc_sli_ct_request *CTrsp = outp->virt; uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp; uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp; - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp, *free_ndlp = NULL; uint32_t latt, cmd, err; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); latt = lpfc_els_chk_latt(vport); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "FDMI cmpl: status:x%x/x%x latt:%d", - irsp->ulpStatus, irsp->un.ulpWord[4], latt); + ulp_status, ulp_word4, latt); - if (latt || irsp->ulpStatus) { + if (latt || ulp_status) { /* Look for a retryable error */ - if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) { + if (ulp_status == IOSTAT_LOCAL_REJECT) { + switch ((ulp_word4 & IOERR_PARAM_MASK)) { case IOERR_SLI_ABORTED: case IOERR_SLI_DOWN: /* Driver aborted this IO. No retry as error @@ -1914,29 +2263,36 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0229 FDMI cmd %04x failed, latt = %d " - "ulpStatus: x%x, rid x%x\n", - be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus, - irsp->un.ulpWord[4]); + "ulp_status: x%x, rid x%x\n", + be16_to_cpu(fdmi_cmd), latt, ulp_status, + ulp_word4); } + + free_ndlp = cmdiocb->ndlp; lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); ndlp = lpfc_findnode_did(vport, FDMI_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) return; /* Check for a CT LS_RJT response */ cmd = be16_to_cpu(fdmi_cmd); if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) { /* FDMI rsp failed */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_ELS, "0220 FDMI cmd failed FS_RJT Data: x%x", cmd); /* Should we fallback to FDMI-2 / FDMI-1 ? */ switch (cmd) { case SLI_MGMT_RHBA: if (vport->fdmi_hba_mask == LPFC_FDMI2_HBA_ATTR) { - /* Fallback to FDMI-1 */ + /* Fallback to FDMI-1 for HBA attributes */ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR; + + /* If HBA attributes are FDMI1, so should + * port attributes be for consistency. + */ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR; /* Start over */ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0); @@ -1944,11 +2300,17 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, return; case SLI_MGMT_RPRT: + if (vport->port_type != LPFC_PHYSICAL_PORT) { + ndlp = lpfc_findnode_did(phba->pport, FDMI_DID); + if (!ndlp) + return; + } if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) { /* Fallback to FDMI-1 */ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR; /* Start over */ lpfc_fdmi_cmd(vport, ndlp, cmd, 0); + return; } if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) { vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR; @@ -1958,12 +2320,23 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, return; case SLI_MGMT_RPA: + /* No retry on Vendor, RPA only done on physical port */ + if (phba->link_flag & LS_CT_VEN_RPA) { + phba->link_flag &= ~LS_CT_VEN_RPA; + if (phba->cmf_active_mode == LPFC_CFG_OFF) + return; + lpfc_printf_log(phba, KERN_WARNING, + LOG_DISCOVERY | LOG_ELS, + "6460 VEN FDMI RPA RJT\n"); + return; + } if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) { /* Fallback to FDMI-1 */ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR; vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR; /* Start over */ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0); + return; } if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) { vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR; @@ -1981,6 +2354,9 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ switch (cmd) { case SLI_MGMT_RHBA: + /* Check for any RPRTs deferred till after RHBA completes */ + lpfc_fdmi_rprt_defer(phba, vport->fdmi_port_mask); + lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, 0); break; @@ -1989,10 +2365,60 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, break; case SLI_MGMT_DPRT: - if (vport->port_type == LPFC_PHYSICAL_PORT) + if (vport->port_type == LPFC_PHYSICAL_PORT) { lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA, 0); - else - lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0); + } else { + ndlp = lpfc_findnode_did(phba->pport, FDMI_DID); + if (!ndlp) + return; + + /* Only issue a RPRT for the vport if the RHBA + * for the physical port completes successfully. + * We may have to defer the RPRT accordingly. + */ + if (phba->hba_flag & HBA_RHBA_CMPL) { + lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0); + } else { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY, + "6078 RPRT deferred\n"); + vport->ct_flags |= FC_CT_RPRT_DEFER; + } + } + break; + case SLI_MGMT_RPA: + if (vport->port_type == LPFC_PHYSICAL_PORT && + phba->sli4_hba.pc_sli4_params.mi_ver) { + /* mi is only for the phyical port, no vports */ + if (phba->link_flag & LS_CT_VEN_RPA) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_ELS | + LOG_CGN_MGMT, + "6449 VEN RPA FDMI Success\n"); + phba->link_flag &= ~LS_CT_VEN_RPA; + break; + } + + lpfc_printf_log(phba, KERN_INFO, + LOG_DISCOVERY | LOG_CGN_MGMT, + "6210 Issue Vendor MI FDMI %x\n", + phba->sli4_hba.pc_sli4_params.mi_ver); + + /* CGN is only for the physical port, no vports */ + if (lpfc_fdmi_cmd(vport, ndlp, cmd, + LPFC_FDMI_VENDOR_ATTR_mi) == 0) + phba->link_flag |= LS_CT_VEN_RPA; + lpfc_printf_log(phba, KERN_INFO, + LOG_DISCOVERY | LOG_ELS, + "6458 Send MI FDMI:%x Flag x%x\n", + phba->sli4_hba.pc_sli4_params.mi_ver, + phba->link_flag); + } else { + lpfc_printf_log(phba, KERN_INFO, + LOG_DISCOVERY | LOG_ELS, + "6459 No FDMI VEN MI support - " + "RPA Success\n"); + } break; } return; @@ -2023,7 +2449,7 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport) return; ndlp = lpfc_findnode_did(vport, FDMI_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) return; /* Check if system hostname changed */ @@ -2038,10 +2464,16 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport) * DHBA -> DPRT -> RHBA -> RPA (physical port) * DPRT -> RPRT (vports) */ - if (vport->port_type == LPFC_PHYSICAL_PORT) + if (vport->port_type == LPFC_PHYSICAL_PORT) { + /* For extra Vendor RPA */ + phba->link_flag &= ~LS_CT_VEN_RPA; lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0); - else + } else { + ndlp = lpfc_findnode_did(phba->pport, FDMI_DID); + if (!ndlp) + return; lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0); + } /* Since this code path registers all the port attributes * we can just return without further checking. @@ -2061,914 +2493,625 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport) lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, LPFC_FDMI_PORT_ATTR_num_disc); } else { + ndlp = lpfc_findnode_did(phba->pport, FDMI_DID); + if (!ndlp) + return; lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, LPFC_FDMI_PORT_ATTR_num_disc); } } -/* Routines for all individual HBA attributes */ -static int -lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) +static inline int +lpfc_fdmi_set_attr_u32(void *attr, uint16_t attrtype, uint32_t attrval) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; + struct lpfc_fdmi_attr_u32 *ae = attr; + int size = sizeof(*ae); - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); + ae->type = cpu_to_be16(attrtype); + ae->len = cpu_to_be16(size); + ae->value_u32 = cpu_to_be32(attrval); - memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName, - sizeof(struct lpfc_name)); - size = FOURBYTES + sizeof(struct lpfc_name); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_NODENAME); return size; } -static int -lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) + +static inline int +lpfc_fdmi_set_attr_wwn(void *attr, uint16_t attrtype, struct lpfc_name *wwn) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + struct lpfc_fdmi_attr_wwn *ae = attr; + int size = sizeof(*ae); - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae->type = cpu_to_be16(attrtype); + ae->len = cpu_to_be16(size); + /* WWN's assumed to be bytestreams - Big Endian presentation */ + memcpy(ae->name, wwn, + min_t(size_t, sizeof(struct lpfc_name), sizeof(__be64))); - /* This string MUST be consistent with other FC platforms - * supported by Broadcom. - */ - strncpy(ae->un.AttrString, - "Emulex Corporation", - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER); return size; } -static int -lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) +static inline int +lpfc_fdmi_set_attr_fullwwn(void *attr, uint16_t attrtype, + struct lpfc_name *wwnn, struct lpfc_name *wwpn) { - struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + struct lpfc_fdmi_attr_fullwwn *ae = attr; + u8 *nname = ae->nname; + u8 *pname = ae->pname; + int size = sizeof(*ae); - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae->type = cpu_to_be16(attrtype); + ae->len = cpu_to_be16(size); + /* WWN's assumed to be bytestreams - Big Endian presentation */ + memcpy(nname, wwnn, + min_t(size_t, sizeof(struct lpfc_name), sizeof(__be64))); + memcpy(pname, wwpn, + min_t(size_t, sizeof(struct lpfc_name), sizeof(__be64))); - strncpy(ae->un.AttrString, phba->SerialNumber, - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER); return size; } -static int -lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +static inline int +lpfc_fdmi_set_attr_string(void *attr, uint16_t attrtype, char *attrstring) { - struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + struct lpfc_fdmi_attr_string *ae = attr; + int len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + /* + * We are trusting the caller that if a fdmi string field + * is capped at 64 bytes, the caller passes in a string of + * 64 bytes or less. + */ - strncpy(ae->un.AttrString, phba->ModelName, - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString)); + strncpy(ae->value_string, attrstring, sizeof(ae->value_string)); + len = strnlen(ae->value_string, sizeof(ae->value_string)); + /* round string length to a 32bit boundary. Ensure there's a NULL */ len += (len & 3) ? (4 - (len & 3)) : 4; + /* size is Type/Len (4 bytes) plus string length */ size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_MODEL); + + ae->type = cpu_to_be16(attrtype); + ae->len = cpu_to_be16(size); + return size; } -static int -lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +/* Bitfields for FC4 Types that can be reported */ +#define ATTR_FC4_CT 0x00000001 +#define ATTR_FC4_FCP 0x00000002 +#define ATTR_FC4_NVME 0x00000004 + +static inline int +lpfc_fdmi_set_attr_fc4types(void *attr, uint16_t attrtype, uint32_t typemask) { - struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + struct lpfc_fdmi_attr_fc4types *ae = attr; + int size = sizeof(*ae); - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + ae->type = cpu_to_be16(attrtype); + ae->len = cpu_to_be16(size); + + if (typemask & ATTR_FC4_FCP) + ae->value_types[2] = 0x01; /* Type 0x8 - FCP */ + + if (typemask & ATTR_FC4_CT) + ae->value_types[7] = 0x01; /* Type 0x20 - CT */ + + if (typemask & ATTR_FC4_NVME) + ae->value_types[6] = 0x01; /* Type 0x28 - NVME */ - strncpy(ae->un.AttrString, phba->ModelDesc, - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION); return size; } +/* Routines for all individual HBA attributes */ static int -lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, void *attr) { - struct lpfc_hba *phba = vport->phba; - lpfc_vpd_t *vp = &phba->vpd; - struct lpfc_fdmi_attr_entry *ae; - uint32_t i, j, incr, size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); - - /* Convert JEDEC ID to ascii for hardware version */ - incr = vp->rev.biuRev; - for (i = 0; i < 8; i++) { - j = (incr & 0xf); - if (j <= 9) - ae->un.AttrString[7 - i] = - (char)((uint8_t) 0x30 + - (uint8_t) j); - else - ae->un.AttrString[7 - i] = - (char)((uint8_t) 0x61 + - (uint8_t) (j - 10)); - incr = (incr >> 4); - } - size = FOURBYTES + 8; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION); - return size; + return lpfc_fdmi_set_attr_wwn(attr, RHBA_NODENAME, + &vport->fc_sparam.nodeName); } static int -lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + /* This string MUST be consistent with other FC platforms + * supported by Broadcom. + */ + return lpfc_fdmi_set_attr_string(attr, RHBA_MANUFACTURER, + "Emulex Corporation"); +} - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); +static int +lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, void *attr) +{ + struct lpfc_hba *phba = vport->phba; - strncpy(ae->un.AttrString, lpfc_release_version, - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION); - return size; + return lpfc_fdmi_set_attr_string(attr, RHBA_SERIAL_NUMBER, + phba->SerialNumber); } static int -lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport, void *attr) { struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); - - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1); - else - strncpy(ae->un.AttrString, phba->OptionROMVersion, - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION); - return size; + return lpfc_fdmi_set_attr_string(attr, RHBA_MODEL, + phba->ModelName); } static int -lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport, void *attr) { struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); - lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION); - return size; + return lpfc_fdmi_set_attr_string(attr, RHBA_MODEL_DESCRIPTION, + phba->ModelDesc); } static int -lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + struct lpfc_hba *phba = vport->phba; + lpfc_vpd_t *vp = &phba->vpd; + char buf[16] = { 0 }; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + snprintf(buf, sizeof(buf), "%08x", vp->rev.biuRev); - snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s %s %s", - init_utsname()->sysname, - init_utsname()->release, - init_utsname()->version); + return lpfc_fdmi_set_attr_string(attr, RHBA_HARDWARE_VERSION, buf); +} - len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION); - return size; +static int +lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport, void *attr) +{ + return lpfc_fdmi_set_attr_string(attr, RHBA_DRIVER_VERSION, + lpfc_release_version); } static int -lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; + struct lpfc_hba *phba = vport->phba; + char buf[64] = { 0 }; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + if (phba->sli_rev == LPFC_SLI_REV4) { + lpfc_decode_firmware_rev(phba, buf, 1); - ae->un.AttrInt = cpu_to_be32(LPFC_MAX_CT_SIZE); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN); - return size; + return lpfc_fdmi_set_attr_string(attr, RHBA_OPTION_ROM_VERSION, + buf); + } + + return lpfc_fdmi_set_attr_string(attr, RHBA_OPTION_ROM_VERSION, + phba->OptionROMVersion); } static int -lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + struct lpfc_hba *phba = vport->phba; + char buf[64] = { 0 }; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + lpfc_decode_firmware_rev(phba, buf, 1); - len = lpfc_vport_symbolic_node_name(vport, - ae->un.AttrString, 256); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME); - return size; + return lpfc_fdmi_set_attr_string(attr, RHBA_FIRMWARE_VERSION, buf); } static int -lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; + char buf[256] = { 0 }; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + snprintf(buf, sizeof(buf), "%s %s %s", + init_utsname()->sysname, + init_utsname()->release, + init_utsname()->version); - /* Nothing is defined for this currently */ - ae->un.AttrInt = cpu_to_be32(0); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_VENDOR_INFO); - return size; + return lpfc_fdmi_set_attr_string(attr, RHBA_OS_NAME_VERSION, buf); } static int -lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - - /* Each driver instance corresponds to a single port */ - ae->un.AttrInt = cpu_to_be32(1); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_NUM_PORTS); - return size; + return lpfc_fdmi_set_attr_u32(attr, RHBA_MAX_CT_PAYLOAD_LEN, + LPFC_MAX_CT_SIZE); } static int -lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; + char buf[256] = { 0 }; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); + lpfc_vport_symbolic_node_name(vport, buf, sizeof(buf)); - memcpy(&ae->un.AttrWWN, &vport->fabric_nodename, - sizeof(struct lpfc_name)); - size = FOURBYTES + sizeof(struct lpfc_name); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_FABRIC_WWNN); - return size; + return lpfc_fdmi_set_attr_string(attr, RHBA_SYM_NODENAME, buf); } static int -lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport, void *attr) { - struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + return lpfc_fdmi_set_attr_u32(attr, RHBA_VENDOR_INFO, 0); +} - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); +static int +lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport, void *attr) +{ + /* Each driver instance corresponds to a single port */ + return lpfc_fdmi_set_attr_u32(attr, RHBA_NUM_PORTS, 1); +} - strlcat(ae->un.AttrString, phba->BIOSVersion, - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_BIOS_VERSION); - return size; +static int +lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport, void *attr) +{ + return lpfc_fdmi_set_attr_wwn(attr, RHBA_FABRIC_WWNN, + &vport->fabric_nodename); } static int -lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; + struct lpfc_hba *phba = vport->phba; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + return lpfc_fdmi_set_attr_string(attr, RHBA_BIOS_VERSION, + phba->BIOSVersion); +} +static int +lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport, void *attr) +{ /* Driver doesn't have access to this information */ - ae->un.AttrInt = cpu_to_be32(0); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_BIOS_STATE); - return size; + return lpfc_fdmi_set_attr_u32(attr, RHBA_BIOS_STATE, 0); } static int -lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); - - strncpy(ae->un.AttrString, "EMULEX", - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RHBA_VENDOR_ID); - return size; + return lpfc_fdmi_set_attr_string(attr, RHBA_VENDOR_ID, "EMULEX"); } -/* Routines for all individual PORT attributes */ +/* + * Routines for all individual PORT attributes + */ + static int -lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, void *attr) { struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 32); + u32 fc4types; - ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ - ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ - ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ + fc4types = (ATTR_FC4_CT | ATTR_FC4_FCP); /* Check to see if Firmware supports NVME and on physical port */ if ((phba->sli_rev == LPFC_SLI_REV4) && (vport == phba->pport) && phba->sli4_hba.pc_sli4_params.nvme) - ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */ + fc4types |= ATTR_FC4_NVME; - size = FOURBYTES + 32; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES); - return size; + return lpfc_fdmi_set_attr_fc4types(attr, RPRT_SUPPORTED_FC4_TYPES, + fc4types); } static int -lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport, void *attr) { - struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + struct lpfc_hba *phba = vport->phba; + u32 speeds = 0; + u32 tcfg; + u8 i, cnt; - ae->un.AttrInt = 0; if (!(phba->hba_flag & HBA_FCOE_MODE)) { - if (phba->lmt & LMT_128Gb) - ae->un.AttrInt |= HBA_PORTSPEED_128GFC; - if (phba->lmt & LMT_64Gb) - ae->un.AttrInt |= HBA_PORTSPEED_64GFC; - if (phba->lmt & LMT_32Gb) - ae->un.AttrInt |= HBA_PORTSPEED_32GFC; - if (phba->lmt & LMT_16Gb) - ae->un.AttrInt |= HBA_PORTSPEED_16GFC; - if (phba->lmt & LMT_10Gb) - ae->un.AttrInt |= HBA_PORTSPEED_10GFC; - if (phba->lmt & LMT_8Gb) - ae->un.AttrInt |= HBA_PORTSPEED_8GFC; - if (phba->lmt & LMT_4Gb) - ae->un.AttrInt |= HBA_PORTSPEED_4GFC; - if (phba->lmt & LMT_2Gb) - ae->un.AttrInt |= HBA_PORTSPEED_2GFC; - if (phba->lmt & LMT_1Gb) - ae->un.AttrInt |= HBA_PORTSPEED_1GFC; + cnt = 0; + if (phba->sli_rev == LPFC_SLI_REV4) { + tcfg = phba->sli4_hba.conf_trunk; + for (i = 0; i < 4; i++, tcfg >>= 1) + if (tcfg & 1) + cnt++; + } + + if (cnt > 2) { /* 4 lane trunk group */ + if (phba->lmt & LMT_64Gb) + speeds |= HBA_PORTSPEED_256GFC; + if (phba->lmt & LMT_32Gb) + speeds |= HBA_PORTSPEED_128GFC; + if (phba->lmt & LMT_16Gb) + speeds |= HBA_PORTSPEED_64GFC; + } else if (cnt) { /* 2 lane trunk group */ + if (phba->lmt & LMT_128Gb) + speeds |= HBA_PORTSPEED_256GFC; + if (phba->lmt & LMT_64Gb) + speeds |= HBA_PORTSPEED_128GFC; + if (phba->lmt & LMT_32Gb) + speeds |= HBA_PORTSPEED_64GFC; + if (phba->lmt & LMT_16Gb) + speeds |= HBA_PORTSPEED_32GFC; + } else { + if (phba->lmt & LMT_256Gb) + speeds |= HBA_PORTSPEED_256GFC; + if (phba->lmt & LMT_128Gb) + speeds |= HBA_PORTSPEED_128GFC; + if (phba->lmt & LMT_64Gb) + speeds |= HBA_PORTSPEED_64GFC; + if (phba->lmt & LMT_32Gb) + speeds |= HBA_PORTSPEED_32GFC; + if (phba->lmt & LMT_16Gb) + speeds |= HBA_PORTSPEED_16GFC; + if (phba->lmt & LMT_10Gb) + speeds |= HBA_PORTSPEED_10GFC; + if (phba->lmt & LMT_8Gb) + speeds |= HBA_PORTSPEED_8GFC; + if (phba->lmt & LMT_4Gb) + speeds |= HBA_PORTSPEED_4GFC; + if (phba->lmt & LMT_2Gb) + speeds |= HBA_PORTSPEED_2GFC; + if (phba->lmt & LMT_1Gb) + speeds |= HBA_PORTSPEED_1GFC; + } } else { /* FCoE links support only one speed */ switch (phba->fc_linkspeed) { case LPFC_ASYNC_LINK_SPEED_10GBPS: - ae->un.AttrInt = HBA_PORTSPEED_10GE; + speeds = HBA_PORTSPEED_10GE; break; case LPFC_ASYNC_LINK_SPEED_25GBPS: - ae->un.AttrInt = HBA_PORTSPEED_25GE; + speeds = HBA_PORTSPEED_25GE; break; case LPFC_ASYNC_LINK_SPEED_40GBPS: - ae->un.AttrInt = HBA_PORTSPEED_40GE; + speeds = HBA_PORTSPEED_40GE; break; case LPFC_ASYNC_LINK_SPEED_100GBPS: - ae->un.AttrInt = HBA_PORTSPEED_100GE; + speeds = HBA_PORTSPEED_100GE; break; } } - ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED); - return size; + + return lpfc_fdmi_set_attr_u32(attr, RPRT_SUPPORTED_SPEED, speeds); } static int -lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport, void *attr) { struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + u32 speeds = 0; if (!(phba->hba_flag & HBA_FCOE_MODE)) { switch (phba->fc_linkspeed) { case LPFC_LINK_SPEED_1GHZ: - ae->un.AttrInt = HBA_PORTSPEED_1GFC; + speeds = HBA_PORTSPEED_1GFC; break; case LPFC_LINK_SPEED_2GHZ: - ae->un.AttrInt = HBA_PORTSPEED_2GFC; + speeds = HBA_PORTSPEED_2GFC; break; case LPFC_LINK_SPEED_4GHZ: - ae->un.AttrInt = HBA_PORTSPEED_4GFC; + speeds = HBA_PORTSPEED_4GFC; break; case LPFC_LINK_SPEED_8GHZ: - ae->un.AttrInt = HBA_PORTSPEED_8GFC; + speeds = HBA_PORTSPEED_8GFC; break; case LPFC_LINK_SPEED_10GHZ: - ae->un.AttrInt = HBA_PORTSPEED_10GFC; + speeds = HBA_PORTSPEED_10GFC; break; case LPFC_LINK_SPEED_16GHZ: - ae->un.AttrInt = HBA_PORTSPEED_16GFC; + speeds = HBA_PORTSPEED_16GFC; break; case LPFC_LINK_SPEED_32GHZ: - ae->un.AttrInt = HBA_PORTSPEED_32GFC; + speeds = HBA_PORTSPEED_32GFC; break; case LPFC_LINK_SPEED_64GHZ: - ae->un.AttrInt = HBA_PORTSPEED_64GFC; + speeds = HBA_PORTSPEED_64GFC; break; case LPFC_LINK_SPEED_128GHZ: - ae->un.AttrInt = HBA_PORTSPEED_128GFC; + speeds = HBA_PORTSPEED_128GFC; + break; + case LPFC_LINK_SPEED_256GHZ: + speeds = HBA_PORTSPEED_256GFC; break; default: - ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN; + speeds = HBA_PORTSPEED_UNKNOWN; break; } } else { switch (phba->fc_linkspeed) { case LPFC_ASYNC_LINK_SPEED_10GBPS: - ae->un.AttrInt = HBA_PORTSPEED_10GE; + speeds = HBA_PORTSPEED_10GE; break; case LPFC_ASYNC_LINK_SPEED_25GBPS: - ae->un.AttrInt = HBA_PORTSPEED_25GE; + speeds = HBA_PORTSPEED_25GE; break; case LPFC_ASYNC_LINK_SPEED_40GBPS: - ae->un.AttrInt = HBA_PORTSPEED_40GE; + speeds = HBA_PORTSPEED_40GE; break; case LPFC_ASYNC_LINK_SPEED_100GBPS: - ae->un.AttrInt = HBA_PORTSPEED_100GE; + speeds = HBA_PORTSPEED_100GE; break; default: - ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN; + speeds = HBA_PORTSPEED_UNKNOWN; break; } } - ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED); - return size; + return lpfc_fdmi_set_attr_u32(attr, RPRT_PORT_SPEED, speeds); } static int -lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport, void *attr) { - struct serv_parm *hsp; - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + struct serv_parm *hsp = (struct serv_parm *)&vport->fc_sparam; - hsp = (struct serv_parm *)&vport->fc_sparam; - ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb & 0x0F) << 8) | - (uint32_t) hsp->cmn.bbRcvSizeLsb; - ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE); - return size; + return lpfc_fdmi_set_attr_u32(attr, RPRT_MAX_FRAME_SIZE, + (((uint32_t)hsp->cmn.bbRcvSizeMsb & 0x0F) << 8) | + (uint32_t)hsp->cmn.bbRcvSizeLsb); } static int -lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport, void *attr) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + char buf[64] = { 0 }; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + snprintf(buf, sizeof(buf), "/sys/class/scsi_host/host%d", + shost->host_no); - snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), - "/sys/class/scsi_host/host%d", shost->host_no); - len = strnlen((char *)ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME); - return size; + return lpfc_fdmi_set_attr_string(attr, RPRT_OS_DEVICE_NAME, buf); } static int -lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + char buf[64] = { 0 }; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + scnprintf(buf, sizeof(buf), "%s", vport->phba->os_host_name); - scnprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s", - vport->phba->os_host_name); - - len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_HOST_NAME); - return size; + return lpfc_fdmi_set_attr_string(attr, RPRT_HOST_NAME, buf); } static int -lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); - - memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName, - sizeof(struct lpfc_name)); - size = FOURBYTES + sizeof(struct lpfc_name); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_NODENAME); - return size; + return lpfc_fdmi_set_attr_wwn(attr, RPRT_NODENAME, + &vport->fc_sparam.nodeName); } static int -lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); - - memcpy(&ae->un.AttrWWN, &vport->fc_sparam.portName, - sizeof(struct lpfc_name)); - size = FOURBYTES + sizeof(struct lpfc_name); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_PORTNAME); - return size; + return lpfc_fdmi_set_attr_wwn(attr, RPRT_PORTNAME, + &vport->fc_sparam.portName); } static int -lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; + char buf[256] = { 0 }; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); + lpfc_vport_symbolic_port_name(vport, buf, sizeof(buf)); - len = lpfc_vport_symbolic_port_name(vport, ae->un.AttrString, 256); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME); - return size; + return lpfc_fdmi_set_attr_string(attr, RPRT_SYM_PORTNAME, buf); } static int -lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport, void *attr) { struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) - ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NLPORT); - else - ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NPORT); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE); - return size; + return lpfc_fdmi_set_attr_u32(attr, RPRT_PORT_TYPE, + (phba->fc_topology == LPFC_TOPOLOGY_LOOP) ? + LPFC_FDMI_PORTTYPE_NLPORT : + LPFC_FDMI_PORTTYPE_NPORT); } static int -lpfc_fdmi_port_attr_class(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_class(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - ae->un.AttrInt = cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS); - return size; + return lpfc_fdmi_set_attr_u32(attr, RPRT_SUPPORTED_CLASS, + FC_COS_CLASS2 | FC_COS_CLASS3); } static int -lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, sizeof(struct lpfc_name)); - - memcpy(&ae->un.AttrWWN, &vport->fabric_portname, - sizeof(struct lpfc_name)); - size = FOURBYTES + sizeof(struct lpfc_name); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_FABRICNAME); - return size; + return lpfc_fdmi_set_attr_wwn(attr, RPRT_FABRICNAME, + &vport->fabric_portname); } static int -lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 32); + struct lpfc_hba *phba = vport->phba; + u32 fc4types; - ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ - ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ - ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ + fc4types = (ATTR_FC4_CT | ATTR_FC4_FCP); /* Check to see if NVME is configured or not */ - if (vport->phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) - ae->un.AttrTypes[6] = 0x1; /* Type 0x28 - NVME */ + if (vport == phba->pport && + phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) + fc4types |= ATTR_FC4_NVME; - size = FOURBYTES + 32; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES); - return size; + return lpfc_fdmi_set_attr_fc4types(attr, RPRT_ACTIVE_FC4_TYPES, + fc4types); } static int -lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - /* Link Up - operational */ - ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTSTATE_ONLINE); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_PORT_STATE); - return size; + return lpfc_fdmi_set_attr_u32(attr, RPRT_PORT_STATE, + LPFC_FDMI_PORTSTATE_ONLINE); } static int -lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; vport->fdmi_num_disc = lpfc_find_map_node(vport); - ae->un.AttrInt = cpu_to_be32(vport->fdmi_num_disc); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_DISC_PORT); - return size; + + return lpfc_fdmi_set_attr_u32(attr, RPRT_DISC_PORT, + vport->fdmi_num_disc); } static int -lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - ae->un.AttrInt = cpu_to_be32(vport->fc_myDID); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_PORT_ID); - return size; + return lpfc_fdmi_set_attr_u32(attr, RPRT_PORT_ID, vport->fc_myDID); } static int -lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); - - strncpy(ae->un.AttrString, "Smart SAN Initiator", - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SMART_SERVICE); - return size; + return lpfc_fdmi_set_attr_string(attr, RPRT_SMART_SERVICE, + "Smart SAN Initiator"); } static int -lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); - - memcpy(&ae->un.AttrString, &vport->fc_sparam.nodeName, - sizeof(struct lpfc_name)); - memcpy((((uint8_t *)&ae->un.AttrString) + - sizeof(struct lpfc_name)), - &vport->fc_sparam.portName, sizeof(struct lpfc_name)); - size = FOURBYTES + (2 * sizeof(struct lpfc_name)); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SMART_GUID); - return size; + return lpfc_fdmi_set_attr_fullwwn(attr, RPRT_SMART_GUID, + &vport->fc_sparam.nodeName, + &vport->fc_sparam.portName); } static int -lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); - - strncpy(ae->un.AttrString, "Smart SAN Version 2.0", - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, - sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SMART_VERSION); - return size; + return lpfc_fdmi_set_attr_string(attr, RPRT_SMART_VERSION, + "Smart SAN Version 2.0"); } static int -lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport, void *attr) { struct lpfc_hba *phba = vport->phba; - struct lpfc_fdmi_attr_entry *ae; - uint32_t len, size; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - memset(ae, 0, 256); - - strncpy(ae->un.AttrString, phba->ModelName, - sizeof(ae->un.AttrString)); - len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString)); - len += (len & 3) ? (4 - (len & 3)) : 4; - size = FOURBYTES + len; - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SMART_MODEL); - return size; + return lpfc_fdmi_set_attr_string(attr, RPRT_SMART_MODEL, + phba->ModelName); } static int -lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; - - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - /* SRIOV (type 3) is not supported */ - if (vport->vpi) - ae->un.AttrInt = cpu_to_be32(2); /* NPIV */ - else - ae->un.AttrInt = cpu_to_be32(1); /* Physical */ - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SMART_PORT_INFO); - return size; + + return lpfc_fdmi_set_attr_u32(attr, RPRT_SMART_PORT_INFO, + (vport->vpi) ? 2 /* NPIV */ : 1 /* Physical */); } static int -lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; + return lpfc_fdmi_set_attr_u32(attr, RPRT_SMART_QOS, 0); +} - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - ae->un.AttrInt = cpu_to_be32(0); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SMART_QOS); - return size; +static int +lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport, void *attr) +{ + return lpfc_fdmi_set_attr_u32(attr, RPRT_SMART_SECURITY, 1); } static int -lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport, - struct lpfc_fdmi_attr_def *ad) +lpfc_fdmi_vendor_attr_mi(struct lpfc_vport *vport, void *attr) { - struct lpfc_fdmi_attr_entry *ae; - uint32_t size; + struct lpfc_hba *phba = vport->phba; + char buf[32] = { 0 }; - ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; - ae->un.AttrInt = cpu_to_be32(1); - size = FOURBYTES + sizeof(uint32_t); - ad->AttrLen = cpu_to_be16(size); - ad->AttrType = cpu_to_be16(RPRT_SMART_SECURITY); - return size; + sprintf(buf, "ELXE2EM:%04d", phba->sli4_hba.pc_sli4_params.mi_ver); + + return lpfc_fdmi_set_attr_string(attr, RPRT_VENDOR_MI, buf); } /* RHBA attribute jump table */ int (*lpfc_fdmi_hba_action[]) - (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = { + (struct lpfc_vport *vport, void *attrbuf) = { /* Action routine Mask bit Attribute type */ lpfc_fdmi_hba_attr_wwnn, /* bit0 RHBA_NODENAME */ lpfc_fdmi_hba_attr_manufacturer, /* bit1 RHBA_MANUFACTURER */ @@ -2992,7 +3135,7 @@ int (*lpfc_fdmi_hba_action[]) /* RPA / RPRT attribute jump table */ int (*lpfc_fdmi_port_action[]) - (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = { + (struct lpfc_vport *vport, void *attrbuf) = { /* Action routine Mask bit Attribute type */ lpfc_fdmi_port_attr_fc4type, /* bit0 RPRT_SUPPORT_FC4_TYPES */ lpfc_fdmi_port_attr_support_speed, /* bit1 RPRT_SUPPORTED_SPEED */ @@ -3017,14 +3160,15 @@ int (*lpfc_fdmi_port_action[]) lpfc_fdmi_smart_attr_port_info, /* bit20 RPRT_SMART_PORT_INFO */ lpfc_fdmi_smart_attr_qos, /* bit21 RPRT_SMART_QOS */ lpfc_fdmi_smart_attr_security, /* bit22 RPRT_SMART_SECURITY */ + lpfc_fdmi_vendor_attr_mi, /* bit23 RPRT_VENDOR_MI */ }; /** * lpfc_fdmi_cmd - Build and send a FDMI cmd to the specified NPort * @vport: pointer to a host virtual N_Port data structure. * @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID) - * cmdcode: FDMI command to send - * mask: Mask of HBA or PORT Attributes to send + * @cmdcode: FDMI command to send + * @new_mask: Mask of HBA or PORT Attributes to send * * Builds and sends a FDMI command using the CT subsystem. */ @@ -3033,56 +3177,61 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode, uint32_t new_mask) { struct lpfc_hba *phba = vport->phba; - struct lpfc_dmabuf *mp, *bmp; + struct lpfc_dmabuf *rq, *rsp; struct lpfc_sli_ct_request *CtReq; - struct ulp_bde64 *bpl; + struct ulp_bde64_le *bde; uint32_t bit_pos; - uint32_t size; + uint32_t size, addsz; uint32_t rsp_size; uint32_t mask; struct lpfc_fdmi_reg_hba *rh; struct lpfc_fdmi_port_entry *pe; - struct lpfc_fdmi_reg_portattr *pab = NULL; + struct lpfc_fdmi_reg_portattr *pab = NULL, *base = NULL; struct lpfc_fdmi_attr_block *ab = NULL; - int (*func)(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad); - void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); + int (*func)(struct lpfc_vport *vport, void *attrbuf); + void (*cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) return 0; cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */ /* fill in BDEs for command */ /* Allocate buffer for command payload */ - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) + rq = kmalloc(sizeof(*rq), GFP_KERNEL); + if (!rq) goto fdmi_cmd_exit; - mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys)); - if (!mp->virt) - goto fdmi_cmd_free_mp; + rq->virt = lpfc_mbuf_alloc(phba, 0, &rq->phys); + if (!rq->virt) + goto fdmi_cmd_free_rq; /* Allocate buffer for Buffer ptr list */ - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) - goto fdmi_cmd_free_mpvirt; + rsp = kmalloc(sizeof(*rsp), GFP_KERNEL); + if (!rsp) + goto fdmi_cmd_free_rqvirt; - bmp->virt = lpfc_mbuf_alloc(phba, 0, &(bmp->phys)); - if (!bmp->virt) - goto fdmi_cmd_free_bmp; + rsp->virt = lpfc_mbuf_alloc(phba, 0, &rsp->phys); + if (!rsp->virt) + goto fdmi_cmd_free_rsp; - INIT_LIST_HEAD(&mp->list); - INIT_LIST_HEAD(&bmp->list); + INIT_LIST_HEAD(&rq->list); + INIT_LIST_HEAD(&rsp->list); + + /* mbuf buffers are 1K in length - aka LPFC_BPL_SIZE */ + memset(rq->virt, 0, LPFC_BPL_SIZE); + rsp_size = LPFC_BPL_SIZE; /* FDMI request */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0218 FDMI Request Data: x%x x%x x%x\n", - vport->fc_flag, vport->port_state, cmdcode); - CtReq = (struct lpfc_sli_ct_request *)mp->virt; + "0218 FDMI Request x%x mask x%x Data: x%x x%x x%x\n", + cmdcode, new_mask, vport->fdmi_port_mask, + vport->fc_flag, vport->port_state); + + CtReq = (struct lpfc_sli_ct_request *)rq->virt; /* First populate the CT_IU preamble */ - memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request)); CtReq->RevisionId.bits.Revision = SLI_CT_REVISION; CtReq->RevisionId.bits.InId = 0; @@ -3090,34 +3239,33 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, CtReq->FsSubType = SLI_CT_FDMI_Subtypes; CtReq->CommandResponse.bits.CmdRsp = cpu_to_be16(cmdcode); - rsp_size = LPFC_BPL_SIZE; + size = 0; /* Next fill in the specific FDMI cmd information */ switch (cmdcode) { case SLI_MGMT_RHAT: case SLI_MGMT_RHBA: - rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID; + rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un; /* HBA Identifier */ memcpy(&rh->hi.PortName, &phba->pport->fc_sparam.portName, sizeof(struct lpfc_name)); + size += sizeof(struct lpfc_fdmi_hba_ident); if (cmdcode == SLI_MGMT_RHBA) { /* Registered Port List */ /* One entry (port) per adapter */ rh->rpl.EntryCnt = cpu_to_be32(1); - memcpy(&rh->rpl.pe, &phba->pport->fc_sparam.portName, + memcpy(&rh->rpl.pe.PortName, + &phba->pport->fc_sparam.portName, sizeof(struct lpfc_name)); - - /* point to the HBA attribute block */ - size = 2 * sizeof(struct lpfc_name) + - FOURBYTES; - } else { - size = sizeof(struct lpfc_name); + size += sizeof(struct lpfc_fdmi_reg_port_list); } + ab = (struct lpfc_fdmi_attr_block *)((uint8_t *)rh + size); ab->EntryCnt = 0; - size += FOURBYTES; + size += FOURBYTES; /* add length of EntryCnt field */ + bit_pos = 0; if (new_mask) mask = new_mask; @@ -3128,11 +3276,13 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, while (mask) { if (mask & 0x1) { func = lpfc_fdmi_hba_action[bit_pos]; - size += func(vport, - (struct lpfc_fdmi_attr_def *) - ((uint8_t *)rh + size)); - ab->EntryCnt++; - if ((size + 256) > + addsz = func(vport, ((uint8_t *)rh + size)); + if (addsz) { + ab->EntryCnt++; + size += addsz; + } + /* check if another attribute fits */ + if ((size + FDMI_MAX_ATTRLEN) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) goto hba_out; } @@ -3142,27 +3292,40 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, hba_out: ab->EntryCnt = cpu_to_be32(ab->EntryCnt); /* Total size */ - size = GID_REQUEST_SZ - 4 + size; + size += GID_REQUEST_SZ - 4; break; case SLI_MGMT_RPRT: + if (vport->port_type != LPFC_PHYSICAL_PORT) { + ndlp = lpfc_findnode_did(phba->pport, FDMI_DID); + if (!ndlp) + return 0; + } + fallthrough; case SLI_MGMT_RPA: - pab = (struct lpfc_fdmi_reg_portattr *)&CtReq->un.PortID; + /* Store base ptr right after preamble */ + base = (struct lpfc_fdmi_reg_portattr *)&CtReq->un; + if (cmdcode == SLI_MGMT_RPRT) { - rh = (struct lpfc_fdmi_reg_hba *)pab; + rh = (struct lpfc_fdmi_reg_hba *)base; /* HBA Identifier */ memcpy(&rh->hi.PortName, &phba->pport->fc_sparam.portName, sizeof(struct lpfc_name)); pab = (struct lpfc_fdmi_reg_portattr *) - ((uint8_t *)pab + sizeof(struct lpfc_name)); + ((uint8_t *)base + sizeof(struct lpfc_name)); + size += sizeof(struct lpfc_name); + } else { + pab = base; } memcpy((uint8_t *)&pab->PortName, (uint8_t *)&vport->fc_sparam.portName, sizeof(struct lpfc_name)); - size += sizeof(struct lpfc_name) + FOURBYTES; pab->ab.EntryCnt = 0; + /* add length of name and EntryCnt field */ + size += sizeof(struct lpfc_name) + FOURBYTES; + bit_pos = 0; if (new_mask) mask = new_mask; @@ -3173,11 +3336,13 @@ hba_out: while (mask) { if (mask & 0x1) { func = lpfc_fdmi_port_action[bit_pos]; - size += func(vport, - (struct lpfc_fdmi_attr_def *) - ((uint8_t *)pab + size)); - pab->ab.EntryCnt++; - if ((size + 256) > + addsz = func(vport, ((uint8_t *)base + size)); + if (addsz) { + pab->ab.EntryCnt++; + size += addsz; + } + /* check if another attribute fits */ + if ((size + FDMI_MAX_ATTRLEN) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) goto port_out; } @@ -3186,19 +3351,16 @@ hba_out: } port_out: pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt); - /* Total size */ - if (cmdcode == SLI_MGMT_RPRT) - size += sizeof(struct lpfc_name); - size = GID_REQUEST_SZ - 4 + size; + size += GID_REQUEST_SZ - 4; break; case SLI_MGMT_GHAT: case SLI_MGMT_GRPL: rsp_size = FC_MAX_NS_RSP; - /* fall through */ + fallthrough; case SLI_MGMT_DHBA: case SLI_MGMT_DHAT: - pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID; + pe = (struct lpfc_fdmi_port_entry *)&CtReq->un; memcpy((uint8_t *)&pe->PortName, (uint8_t *)&vport->fc_sparam.portName, sizeof(struct lpfc_name)); @@ -3208,10 +3370,16 @@ port_out: case SLI_MGMT_GPAT: case SLI_MGMT_GPAS: rsp_size = FC_MAX_NS_RSP; - /* fall through */ + fallthrough; case SLI_MGMT_DPRT: + if (vport->port_type != LPFC_PHYSICAL_PORT) { + ndlp = lpfc_findnode_did(phba->pport, FDMI_DID); + if (!ndlp) + return 0; + } + fallthrough; case SLI_MGMT_DPA: - pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID; + pe = (struct lpfc_fdmi_port_entry *)&CtReq->un; memcpy((uint8_t *)&pe->PortName, (uint8_t *)&vport->fc_sparam.portName, sizeof(struct lpfc_name)); @@ -3224,37 +3392,32 @@ port_out: lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY, "0298 FDMI cmdcode x%x not supported\n", cmdcode); - goto fdmi_cmd_free_bmpvirt; + goto fdmi_cmd_free_rspvirt; } CtReq->CommandResponse.bits.Size = cpu_to_be16(rsp_size); - bpl = (struct ulp_bde64 *)bmp->virt; - bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); - bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); - bpl->tus.f.bdeFlags = 0; - bpl->tus.f.bdeSize = size; + bde = (struct ulp_bde64_le *)rsp->virt; + bde->addr_high = cpu_to_le32(putPaddrHigh(rq->phys)); + bde->addr_low = cpu_to_le32(putPaddrLow(rq->phys)); + bde->type_size = cpu_to_le32(ULP_BDE64_TYPE_BDE_64 << + ULP_BDE64_TYPE_SHIFT); + bde->type_size |= cpu_to_le32(size); /* * The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count * to hold ndlp reference for the corresponding callback function. */ - if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, 0)) + if (!lpfc_ct_cmd(vport, rq, rsp, ndlp, cmpl, rsp_size, 0)) return 0; - /* - * Decrement ndlp reference count to release ndlp reference held - * for the failed command's callback function. - */ - lpfc_nlp_put(ndlp); - -fdmi_cmd_free_bmpvirt: - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); -fdmi_cmd_free_bmp: - kfree(bmp); -fdmi_cmd_free_mpvirt: - lpfc_mbuf_free(phba, mp->virt, mp->phys); -fdmi_cmd_free_mp: - kfree(mp); +fdmi_cmd_free_rspvirt: + lpfc_mbuf_free(phba, rsp->virt, rsp->phys); +fdmi_cmd_free_rsp: + kfree(rsp); +fdmi_cmd_free_rqvirt: + lpfc_mbuf_free(phba, rq->virt, rq->phys); +fdmi_cmd_free_rq: + kfree(rq); fdmi_cmd_exit: /* Issue FDMI request failed */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -3265,7 +3428,7 @@ fdmi_cmd_exit: /** * lpfc_delayed_disc_tmo - Timeout handler for delayed discovery timer. - * @ptr - Context object of the timer. + * @t: Context object of the timer. * * This function set the WORKER_DELAYED_DISC_TMO flag and wake up * the worker thread. @@ -3397,3 +3560,258 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag) } return; } + +static void +lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + struct lpfc_dmabuf *inp = cmdiocb->cmd_dmabuf; + struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf; + struct lpfc_sli_ct_request *ctcmd = inp->virt; + struct lpfc_sli_ct_request *ctrsp = outp->virt; + u16 rsp = ctrsp->CommandResponse.bits.CmdRsp; + struct app_id_object *app; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; + u32 cmd, hash, bucket; + struct lpfc_vmid *vmp, *cur; + u8 *data = outp->virt; + int i; + + cmd = be16_to_cpu(ctcmd->CommandResponse.bits.CmdRsp); + if (cmd == SLI_CTAS_DALLAPP_ID) + lpfc_ct_free_iocb(phba, cmdiocb); + + if (lpfc_els_chk_latt(vport) || get_job_ulpstatus(phba, rspiocb)) { + if (cmd != SLI_CTAS_DALLAPP_ID) + goto free_res; + } + /* Check for a CT LS_RJT response */ + if (rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { + if (cmd != SLI_CTAS_DALLAPP_ID) + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "3306 VMID FS_RJT Data: x%x x%x x%x\n", + cmd, ctrsp->ReasonCode, + ctrsp->Explanation); + if ((cmd != SLI_CTAS_DALLAPP_ID) || + (ctrsp->ReasonCode != SLI_CT_UNABLE_TO_PERFORM_REQ) || + (ctrsp->Explanation != SLI_CT_APP_ID_NOT_AVAILABLE)) { + /* If DALLAPP_ID failed retry later */ + if (cmd == SLI_CTAS_DALLAPP_ID) + vport->load_flag |= FC_DEREGISTER_ALL_APP_ID; + goto free_res; + } + } + + switch (cmd) { + case SLI_CTAS_RAPP_IDENT: + app = (struct app_id_object *)(RAPP_IDENT_OFFSET + data); + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "6712 RAPP_IDENT app id %d port id x%x id " + "len %d\n", be32_to_cpu(app->app_id), + be32_to_cpu(app->port_id), + app->obj.entity_id_len); + + if (app->obj.entity_id_len == 0 || app->port_id == 0) + goto free_res; + + hash = lpfc_vmid_hash_fn(app->obj.entity_id, + app->obj.entity_id_len); + vmp = lpfc_get_vmid_from_hashtable(vport, hash, + app->obj.entity_id); + if (vmp) { + write_lock(&vport->vmid_lock); + vmp->un.app_id = be32_to_cpu(app->app_id); + vmp->flag |= LPFC_VMID_REGISTERED; + vmp->flag &= ~LPFC_VMID_REQ_REGISTER; + write_unlock(&vport->vmid_lock); + /* Set IN USE flag */ + vport->vmid_flag |= LPFC_VMID_IN_USE; + } else { + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "6901 No entry found %s hash %d\n", + app->obj.entity_id, hash); + } + break; + case SLI_CTAS_DAPP_IDENT: + app = (struct app_id_object *)(DAPP_IDENT_OFFSET + data); + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "6713 DAPP_IDENT app id %d port id x%x\n", + be32_to_cpu(app->app_id), + be32_to_cpu(app->port_id)); + break; + case SLI_CTAS_DALLAPP_ID: + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "8856 Deregistered all app ids\n"); + read_lock(&vport->vmid_lock); + for (i = 0; i < phba->cfg_max_vmid; i++) { + vmp = &vport->vmid[i]; + if (vmp->flag != LPFC_VMID_SLOT_FREE) + memset(vmp, 0, sizeof(struct lpfc_vmid)); + } + read_unlock(&vport->vmid_lock); + /* for all elements in the hash table */ + if (!hash_empty(vport->hash_table)) + hash_for_each(vport->hash_table, bucket, cur, hnode) + hash_del(&cur->hnode); + vport->load_flag |= FC_ALLOW_VMID; + break; + default: + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "8857 Invalid command code\n"); + } +free_res: + lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); +} + +/** + * lpfc_vmid_cmd - Build and send a FDMI cmd to the specified NPort + * @vport: pointer to a host virtual N_Port data structure. + * @cmdcode: application server command code to send + * @vmid: pointer to vmid info structure + * + * Builds and sends a FDMI command using the CT subsystem. + */ +int +lpfc_vmid_cmd(struct lpfc_vport *vport, + int cmdcode, struct lpfc_vmid *vmid) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_dmabuf *mp, *bmp; + struct lpfc_sli_ct_request *ctreq; + struct ulp_bde64 *bpl; + u32 size; + u32 rsp_size; + u8 *data; + struct lpfc_vmid_rapp_ident_list *rap; + struct lpfc_vmid_dapp_ident_list *dap; + u8 retry = 0; + struct lpfc_nodelist *ndlp; + + void (*cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb); + + ndlp = lpfc_findnode_did(vport, FDMI_DID); + if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) + return 0; + + cmpl = lpfc_cmpl_ct_cmd_vmid; + + /* fill in BDEs for command */ + /* Allocate buffer for command payload */ + mp = kmalloc(sizeof(*mp), GFP_KERNEL); + if (!mp) + goto vmid_free_mp_exit; + + mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); + if (!mp->virt) + goto vmid_free_mp_virt_exit; + + /* Allocate buffer for Buffer ptr list */ + bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); + if (!bmp) + goto vmid_free_bmp_exit; + + bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); + if (!bmp->virt) + goto vmid_free_bmp_virt_exit; + + INIT_LIST_HEAD(&mp->list); + INIT_LIST_HEAD(&bmp->list); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "3275 VMID Request Data: x%x x%x x%x\n", + vport->fc_flag, vport->port_state, cmdcode); + ctreq = (struct lpfc_sli_ct_request *)mp->virt; + data = mp->virt; + /* First populate the CT_IU preamble */ + memset(data, 0, LPFC_BPL_SIZE); + ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; + ctreq->RevisionId.bits.InId = 0; + + ctreq->FsType = SLI_CT_MANAGEMENT_SERVICE; + ctreq->FsSubType = SLI_CT_APP_SEV_Subtypes; + + ctreq->CommandResponse.bits.CmdRsp = cpu_to_be16(cmdcode); + rsp_size = LPFC_BPL_SIZE; + size = 0; + + switch (cmdcode) { + case SLI_CTAS_RAPP_IDENT: + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "1329 RAPP_IDENT for %s\n", vmid->host_vmid); + ctreq->un.PortID = cpu_to_be32(vport->fc_myDID); + rap = (struct lpfc_vmid_rapp_ident_list *) + (DAPP_IDENT_OFFSET + data); + rap->no_of_objects = cpu_to_be32(1); + rap->obj[0].entity_id_len = vmid->vmid_len; + memcpy(rap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len); + size = RAPP_IDENT_OFFSET + + sizeof(struct lpfc_vmid_rapp_ident_list); + retry = 1; + break; + + case SLI_CTAS_GALLAPPIA_ID: + ctreq->un.PortID = cpu_to_be32(vport->fc_myDID); + size = GALLAPPIA_ID_SIZE; + break; + + case SLI_CTAS_DAPP_IDENT: + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "1469 DAPP_IDENT for %s\n", vmid->host_vmid); + ctreq->un.PortID = cpu_to_be32(vport->fc_myDID); + dap = (struct lpfc_vmid_dapp_ident_list *) + (DAPP_IDENT_OFFSET + data); + dap->no_of_objects = cpu_to_be32(1); + dap->obj[0].entity_id_len = vmid->vmid_len; + memcpy(dap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len); + size = DAPP_IDENT_OFFSET + + sizeof(struct lpfc_vmid_dapp_ident_list); + write_lock(&vport->vmid_lock); + vmid->flag &= ~LPFC_VMID_REGISTERED; + write_unlock(&vport->vmid_lock); + retry = 1; + break; + + case SLI_CTAS_DALLAPP_ID: + ctreq->un.PortID = cpu_to_be32(vport->fc_myDID); + size = DALLAPP_ID_SIZE; + break; + + default: + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "7062 VMID cmdcode x%x not supported\n", + cmdcode); + goto vmid_free_all_mem; + } + + ctreq->CommandResponse.bits.Size = cpu_to_be16(rsp_size); + + bpl = (struct ulp_bde64 *)bmp->virt; + bpl->addrHigh = putPaddrHigh(mp->phys); + bpl->addrLow = putPaddrLow(mp->phys); + bpl->tus.f.bdeFlags = 0; + bpl->tus.f.bdeSize = size; + + /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count + * to hold ndlp reference for the corresponding callback function. + */ + if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) + return 0; + + vmid_free_all_mem: + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + vmid_free_bmp_virt_exit: + kfree(bmp); + vmid_free_bmp_exit: + lpfc_mbuf_free(phba, mp->virt, mp->phys); + vmid_free_mp_virt_exit: + kfree(mp); + vmid_free_mp_exit: + + /* Issue CT request failed */ + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY, + "3276 VMID CT request failed Data: x%x\n", cmdcode); + return -EIO; +} diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 819335b16c2e..f5252e45a48a 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -39,8 +39,6 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> -#include <linux/nvme-fc-driver.h> - #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" @@ -50,7 +48,6 @@ #include "lpfc.h" #include "lpfc_scsi.h" #include "lpfc_nvme.h" -#include "lpfc_nvmet.h" #include "lpfc_logmsg.h" #include "lpfc_crtn.h" #include "lpfc_vport.h" @@ -384,7 +381,7 @@ skipit: static int lpfc_debugfs_last_xripool; /** - * lpfc_debugfs_common_xri_data - Dump Hardware Queue info to a buffer + * lpfc_debugfs_commonxripools_data - Dump Hardware Queue info to a buffer * @phba: The HBA to gather host buffer info from. * @buf: The buffer to dump log into. * @size: The maximum amount of data to process. @@ -866,16 +863,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) len += scnprintf(buf+len, size-len, "%s DID:x%06x ", statep, ndlp->nlp_DID); len += scnprintf(buf+len, size-len, - "WWPN x%llx ", + "WWPN x%016llx ", wwn_to_u64(ndlp->nlp_portname.u.wwn)); len += scnprintf(buf+len, size-len, - "WWNN x%llx ", + "WWNN x%016llx ", wwn_to_u64(ndlp->nlp_nodename.u.wwn)); - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) - len += scnprintf(buf+len, size-len, "RPI:%03d ", - ndlp->nlp_rpi); - else - len += scnprintf(buf+len, size-len, "RPI:none "); + len += scnprintf(buf+len, size-len, "RPI:x%04x ", + ndlp->nlp_rpi); len += scnprintf(buf+len, size-len, "flag:x%08x ", ndlp->nlp_flag); if (!ndlp->nlp_type) @@ -898,9 +892,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) if (ndlp->nlp_type & NLP_NVME_INITIATOR) len += scnprintf(buf + len, size - len, "NVME_INITIATOR "); - len += scnprintf(buf+len, size-len, "usgmap:%x ", - ndlp->nlp_usg_map); - len += scnprintf(buf+len, size-len, "refcnt:%x", + len += scnprintf(buf+len, size-len, "refcnt:%d", kref_read(&ndlp->kref)); if (iocnt) { i = atomic_read(&ndlp->cmd_pending); @@ -909,8 +901,11 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) i, ndlp->cmd_qdepth); outio += i; } - len += scnprintf(buf + len, size - len, "defer:%x ", - ndlp->nlp_defer_did); + len += scnprintf(buf+len, size-len, " xpt:x%x", + ndlp->fc4_xpt_flags); + if (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING) + len += scnprintf(buf+len, size-len, " defer:%x", + ndlp->nlp_defer_did); len += scnprintf(buf+len, size-len, "\n"); } spin_unlock_irq(shost->host_lock); @@ -960,13 +955,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) len += scnprintf(buf + len, size - len, "\tRport List:\n"); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { /* local short-hand pointer. */ - spin_lock(&phba->hbalock); + spin_lock(&ndlp->lock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) nrport = rport->remoteport; else nrport = NULL; - spin_unlock(&phba->hbalock); + spin_unlock(&ndlp->lock); if (!nrport) continue; @@ -1035,7 +1030,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) { struct lpfc_hba *phba = vport->phba; struct lpfc_nvmet_tgtport *tgtp; - struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; + struct lpfc_async_xchg_ctx *ctxp, *next_ctxp; struct nvme_fc_local_port *localport; struct lpfc_fc4_ctrl_stat *cstat; struct lpfc_nvme_lport *lport; @@ -1300,8 +1295,88 @@ buffer_done: return len; } +void +lpfc_io_ktime(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) +{ + uint64_t seg1, seg2, seg3, seg4; + uint64_t segsum; + + if (!lpfc_cmd->ts_last_cmd || + !lpfc_cmd->ts_cmd_start || + !lpfc_cmd->ts_cmd_wqput || + !lpfc_cmd->ts_isr_cmpl || + !lpfc_cmd->ts_data_io) + return; + + if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_cmd_start) + return; + if (lpfc_cmd->ts_cmd_start < lpfc_cmd->ts_last_cmd) + return; + if (lpfc_cmd->ts_cmd_wqput < lpfc_cmd->ts_cmd_start) + return; + if (lpfc_cmd->ts_isr_cmpl < lpfc_cmd->ts_cmd_wqput) + return; + if (lpfc_cmd->ts_data_io < lpfc_cmd->ts_isr_cmpl) + return; + /* + * Segment 1 - Time from Last FCP command cmpl is handed + * off to NVME Layer to start of next command. + * Segment 2 - Time from Driver receives a IO cmd start + * from NVME Layer to WQ put is done on IO cmd. + * Segment 3 - Time from Driver WQ put is done on IO cmd + * to MSI-X ISR for IO cmpl. + * Segment 4 - Time from MSI-X ISR for IO cmpl to when + * cmpl is handled off to the NVME Layer. + */ + seg1 = lpfc_cmd->ts_cmd_start - lpfc_cmd->ts_last_cmd; + if (seg1 > 5000000) /* 5 ms - for sequential IOs only */ + seg1 = 0; + + /* Calculate times relative to start of IO */ + seg2 = (lpfc_cmd->ts_cmd_wqput - lpfc_cmd->ts_cmd_start); + segsum = seg2; + seg3 = lpfc_cmd->ts_isr_cmpl - lpfc_cmd->ts_cmd_start; + if (segsum > seg3) + return; + seg3 -= segsum; + segsum += seg3; + + seg4 = lpfc_cmd->ts_data_io - lpfc_cmd->ts_cmd_start; + if (segsum > seg4) + return; + seg4 -= segsum; + + phba->ktime_data_samples++; + phba->ktime_seg1_total += seg1; + if (seg1 < phba->ktime_seg1_min) + phba->ktime_seg1_min = seg1; + else if (seg1 > phba->ktime_seg1_max) + phba->ktime_seg1_max = seg1; + phba->ktime_seg2_total += seg2; + if (seg2 < phba->ktime_seg2_min) + phba->ktime_seg2_min = seg2; + else if (seg2 > phba->ktime_seg2_max) + phba->ktime_seg2_max = seg2; + phba->ktime_seg3_total += seg3; + if (seg3 < phba->ktime_seg3_min) + phba->ktime_seg3_min = seg3; + else if (seg3 > phba->ktime_seg3_max) + phba->ktime_seg3_max = seg3; + phba->ktime_seg4_total += seg4; + if (seg4 < phba->ktime_seg4_min) + phba->ktime_seg4_min = seg4; + else if (seg4 > phba->ktime_seg4_max) + phba->ktime_seg4_max = seg4; + + lpfc_cmd->ts_last_cmd = 0; + lpfc_cmd->ts_cmd_start = 0; + lpfc_cmd->ts_cmd_wqput = 0; + lpfc_cmd->ts_isr_cmpl = 0; + lpfc_cmd->ts_data_io = 0; +} + /** - * lpfc_debugfs_nvmektime_data - Dump target node list to a buffer + * lpfc_debugfs_ioktime_data - Dump target node list to a buffer * @vport: The vport to gather target node info from. * @buf: The buffer to dump log into. * @size: The maximum amount of data to process. @@ -1314,13 +1389,13 @@ buffer_done: * not exceed @size. **/ static int -lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) +lpfc_debugfs_ioktime_data(struct lpfc_vport *vport, char *buf, int size) { struct lpfc_hba *phba = vport->phba; int len = 0; if (phba->nvmet_support == 0) { - /* NVME Initiator */ + /* Initiator */ len += scnprintf(buf + len, PAGE_SIZE - len, "ktime %s: Total Samples: %lld\n", (phba->ktime_on ? "Enabled" : "Disabled"), @@ -1330,8 +1405,8 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) len += scnprintf( buf + len, PAGE_SIZE - len, - "Segment 1: Last NVME Cmd cmpl " - "done -to- Start of next NVME cnd (in driver)\n"); + "Segment 1: Last Cmd cmpl " + "done -to- Start of next Cmd (in driver)\n"); len += scnprintf( buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", @@ -1341,7 +1416,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) phba->ktime_seg1_max); len += scnprintf( buf + len, PAGE_SIZE - len, - "Segment 2: Driver start of NVME cmd " + "Segment 2: Driver start of Cmd " "-to- Firmware WQ doorbell\n"); len += scnprintf( buf + len, PAGE_SIZE - len, @@ -1364,7 +1439,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size) len += scnprintf( buf + len, PAGE_SIZE - len, "Segment 4: MSI-X ISR cmpl -to- " - "NVME cmpl done\n"); + "Cmd cmpl done\n"); len += scnprintf( buf + len, PAGE_SIZE - len, "avg:%08lld min:%08lld max %08lld\n", @@ -1603,89 +1678,124 @@ out: } /** - * lpfc_debugfs_cpucheck_data - Dump target node list to a buffer + * lpfc_debugfs_hdwqstat_data - Dump I/O stats to a buffer * @vport: The vport to gather target node info from. * @buf: The buffer to dump log into. * @size: The maximum amount of data to process. * * Description: - * This routine dumps the NVME statistics associated with @vport + * This routine dumps the NVME + SCSI statistics associated with @vport * * Return Value: * This routine returns the amount of bytes that were dumped into @buf and will * not exceed @size. **/ static int -lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size) +lpfc_debugfs_hdwqstat_data(struct lpfc_vport *vport, char *buf, int size) { struct lpfc_hba *phba = vport->phba; - struct lpfc_sli4_hdw_queue *qp; - int i, j, max_cnt; - int len = 0; + struct lpfc_hdwq_stat *c_stat; + int i, j, len; uint32_t tot_xmt; uint32_t tot_rcv; uint32_t tot_cmpl; + char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0}; - len += scnprintf(buf + len, PAGE_SIZE - len, - "CPUcheck %s ", - (phba->cpucheck_on & LPFC_CHECK_NVME_IO ? - "Enabled" : "Disabled")); - if (phba->nvmet_support) { - len += scnprintf(buf + len, PAGE_SIZE - len, - "%s\n", - (phba->cpucheck_on & LPFC_CHECK_NVMET_RCV ? - "Rcv Enabled\n" : "Rcv Disabled\n")); - } else { - len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); - } - max_cnt = size - LPFC_DEBUG_OUT_LINE_SZ; + scnprintf(tmp, sizeof(tmp), "HDWQ Stats:\n\n"); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; - for (i = 0; i < phba->cfg_hdw_queue; i++) { - qp = &phba->sli4_hba.hdwq[i]; + scnprintf(tmp, sizeof(tmp), "(NVME Accounting: %s) ", + (phba->hdwqstat_on & + (LPFC_CHECK_NVME_IO | LPFC_CHECK_NVMET_IO) ? + "Enabled" : "Disabled")); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + scnprintf(tmp, sizeof(tmp), "(SCSI Accounting: %s) ", + (phba->hdwqstat_on & LPFC_CHECK_SCSI_IO ? + "Enabled" : "Disabled")); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + + scnprintf(tmp, sizeof(tmp), "\n\n"); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + + for (i = 0; i < phba->cfg_hdw_queue; i++) { tot_rcv = 0; tot_xmt = 0; tot_cmpl = 0; - for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) { - tot_xmt += qp->cpucheck_xmt_io[j]; - tot_cmpl += qp->cpucheck_cmpl_io[j]; - if (phba->nvmet_support) - tot_rcv += qp->cpucheck_rcv_io[j]; - } - /* Only display Hardware Qs with something */ - if (!tot_xmt && !tot_cmpl && !tot_rcv) - continue; + for_each_present_cpu(j) { + c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, j); + + /* Only display for this HDWQ */ + if (i != c_stat->hdwq_no) + continue; - len += scnprintf(buf + len, PAGE_SIZE - len, - "HDWQ %03d: ", i); - for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) { /* Only display non-zero counters */ - if (!qp->cpucheck_xmt_io[j] && - !qp->cpucheck_cmpl_io[j] && - !qp->cpucheck_rcv_io[j]) + if (!c_stat->xmt_io && !c_stat->cmpl_io && + !c_stat->rcv_io) continue; + + if (!tot_xmt && !tot_cmpl && !tot_rcv) { + /* Print HDWQ string only the first time */ + scnprintf(tmp, sizeof(tmp), "[HDWQ %d]:\t", i); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + } + + tot_xmt += c_stat->xmt_io; + tot_cmpl += c_stat->cmpl_io; + if (phba->nvmet_support) + tot_rcv += c_stat->rcv_io; + + scnprintf(tmp, sizeof(tmp), "| [CPU %d]: ", j); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + if (phba->nvmet_support) { - len += scnprintf(buf + len, PAGE_SIZE - len, - "CPU %03d: %x/%x/%x ", j, - qp->cpucheck_rcv_io[j], - qp->cpucheck_xmt_io[j], - qp->cpucheck_cmpl_io[j]); + scnprintf(tmp, sizeof(tmp), + "XMT 0x%x CMPL 0x%x RCV 0x%x |", + c_stat->xmt_io, c_stat->cmpl_io, + c_stat->rcv_io); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; } else { - len += scnprintf(buf + len, PAGE_SIZE - len, - "CPU %03d: %x/%x ", j, - qp->cpucheck_xmt_io[j], - qp->cpucheck_cmpl_io[j]); + scnprintf(tmp, sizeof(tmp), + "XMT 0x%x CMPL 0x%x |", + c_stat->xmt_io, c_stat->cmpl_io); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; } } - len += scnprintf(buf + len, PAGE_SIZE - len, - "Total: %x\n", tot_xmt); - if (len >= max_cnt) { - len += scnprintf(buf + len, PAGE_SIZE - len, - "Truncated ...\n"); - return len; + + /* Check if nothing to display */ + if (!tot_xmt && !tot_cmpl && !tot_rcv) + continue; + + scnprintf(tmp, sizeof(tmp), "\t->\t[HDWQ Total: "); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + + if (phba->nvmet_support) { + scnprintf(tmp, sizeof(tmp), + "XMT 0x%x CMPL 0x%x RCV 0x%x]\n\n", + tot_xmt, tot_cmpl, tot_rcv); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; + } else { + scnprintf(tmp, sizeof(tmp), + "XMT 0x%x CMPL 0x%x]\n\n", + tot_xmt, tot_cmpl); + if (strlcat(buf, tmp, size) >= size) + goto buffer_done; } } + +buffer_done: + len = strnlen(buf, size); return len; } @@ -2048,10 +2158,6 @@ lpfc_debugfs_lockstat_write(struct file *file, const char __user *buf, char *pbuf; int i; - /* Protect copy from user */ - if (!access_ok(buf, nbytes)) - return -EFAULT; - memset(mybuf, 0, sizeof(mybuf)); if (copy_from_user(mybuf, buf, nbytes)) @@ -2315,15 +2421,16 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, memset(dstbuf, 0, 33); size = (nbytes < 32) ? nbytes : 32; if (copy_from_user(dstbuf, buf, size)) - return 0; + return -EFAULT; if (dent == phba->debug_InjErrLBA) { - if ((buf[0] == 'o') && (buf[1] == 'f') && (buf[2] == 'f')) + if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') && + (dstbuf[2] == 'f')) tmp = (uint64_t)(-1); } if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp))) - return 0; + return -EINVAL; if (dent == phba->debug_writeGuard) phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp; @@ -2500,12 +2607,8 @@ lpfc_debugfs_multixripools_write(struct file *file, const char __user *buf, struct lpfc_sli4_hdw_queue *qp; struct lpfc_multixri_pool *multixri_pool; - if (nbytes > 64) - nbytes = 64; - - /* Protect copy from user */ - if (!access_ok(buf, nbytes)) - return -EFAULT; + if (nbytes > sizeof(mybuf) - 1) + nbytes = sizeof(mybuf) - 1; memset(mybuf, 0, sizeof(mybuf)); @@ -2585,8 +2688,8 @@ lpfc_debugfs_nvmestat_write(struct file *file, const char __user *buf, if (!phba->targetport) return -ENXIO; - if (nbytes > 64) - nbytes = 64; + if (nbytes > sizeof(mybuf) - 1) + nbytes = sizeof(mybuf) - 1; memset(mybuf, 0, sizeof(mybuf)); @@ -2669,10 +2772,6 @@ lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf, char mybuf[6] = {0}; int i; - /* Protect copy from user */ - if (!access_ok(buf, nbytes)) - return -EFAULT; - if (copy_from_user(mybuf, buf, (nbytes >= sizeof(mybuf)) ? (sizeof(mybuf) - 1) : nbytes)) return -EFAULT; @@ -2689,7 +2788,7 @@ lpfc_debugfs_scsistat_write(struct file *file, const char __user *buf, } static int -lpfc_debugfs_nvmektime_open(struct inode *inode, struct file *file) +lpfc_debugfs_ioktime_open(struct inode *inode, struct file *file) { struct lpfc_vport *vport = inode->i_private; struct lpfc_debug *debug; @@ -2700,14 +2799,14 @@ lpfc_debugfs_nvmektime_open(struct inode *inode, struct file *file) goto out; /* Round to page boundary */ - debug->buffer = kmalloc(LPFC_NVMEKTIME_SIZE, GFP_KERNEL); + debug->buffer = kmalloc(LPFC_IOKTIME_SIZE, GFP_KERNEL); if (!debug->buffer) { kfree(debug); goto out; } - debug->len = lpfc_debugfs_nvmektime_data(vport, debug->buffer, - LPFC_NVMEKTIME_SIZE); + debug->len = lpfc_debugfs_ioktime_data(vport, debug->buffer, + LPFC_IOKTIME_SIZE); debug->i_private = inode->i_private; file->private_data = debug; @@ -2718,8 +2817,8 @@ out: } static ssize_t -lpfc_debugfs_nvmektime_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) +lpfc_debugfs_ioktime_write(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) { struct lpfc_debug *debug = file->private_data; struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private; @@ -2727,8 +2826,8 @@ lpfc_debugfs_nvmektime_write(struct file *file, const char __user *buf, char mybuf[64]; char *pbuf; - if (nbytes > 64) - nbytes = 64; + if (nbytes > sizeof(mybuf) - 1) + nbytes = sizeof(mybuf) - 1; memset(mybuf, 0, sizeof(mybuf)); @@ -2855,8 +2954,8 @@ lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf, char mybuf[64]; char *pbuf; - if (nbytes > 64) - nbytes = 64; + if (nbytes > sizeof(mybuf) - 1) + nbytes = sizeof(mybuf) - 1; memset(mybuf, 0, sizeof(mybuf)); @@ -2921,7 +3020,7 @@ lpfc_debugfs_nvmeio_trc_write(struct file *file, const char __user *buf, } static int -lpfc_debugfs_cpucheck_open(struct inode *inode, struct file *file) +lpfc_debugfs_hdwqstat_open(struct inode *inode, struct file *file) { struct lpfc_vport *vport = inode->i_private; struct lpfc_debug *debug; @@ -2932,14 +3031,14 @@ lpfc_debugfs_cpucheck_open(struct inode *inode, struct file *file) goto out; /* Round to page boundary */ - debug->buffer = kmalloc(LPFC_CPUCHECK_SIZE, GFP_KERNEL); + debug->buffer = kcalloc(1, LPFC_SCSISTAT_SIZE, GFP_KERNEL); if (!debug->buffer) { kfree(debug); goto out; } - debug->len = lpfc_debugfs_cpucheck_data(vport, debug->buffer, - LPFC_CPUCHECK_SIZE); + debug->len = lpfc_debugfs_hdwqstat_data(vport, debug->buffer, + LPFC_SCSISTAT_SIZE); debug->i_private = inode->i_private; file->private_data = debug; @@ -2950,19 +3049,19 @@ out: } static ssize_t -lpfc_debugfs_cpucheck_write(struct file *file, const char __user *buf, +lpfc_debugfs_hdwqstat_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) { struct lpfc_debug *debug = file->private_data; struct lpfc_vport *vport = (struct lpfc_vport *)debug->i_private; struct lpfc_hba *phba = vport->phba; - struct lpfc_sli4_hdw_queue *qp; + struct lpfc_hdwq_stat *c_stat; char mybuf[64]; char *pbuf; - int i, j; + int i; - if (nbytes > 64) - nbytes = 64; + if (nbytes > sizeof(mybuf) - 1) + nbytes = sizeof(mybuf) - 1; memset(mybuf, 0, sizeof(mybuf)); @@ -2972,41 +3071,39 @@ lpfc_debugfs_cpucheck_write(struct file *file, const char __user *buf, if ((strncmp(pbuf, "on", sizeof("on") - 1) == 0)) { if (phba->nvmet_support) - phba->cpucheck_on |= LPFC_CHECK_NVMET_IO; + phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO; else - phba->cpucheck_on |= (LPFC_CHECK_NVME_IO | + phba->hdwqstat_on |= (LPFC_CHECK_NVME_IO | LPFC_CHECK_SCSI_IO); return strlen(pbuf); } else if ((strncmp(pbuf, "nvme_on", sizeof("nvme_on") - 1) == 0)) { if (phba->nvmet_support) - phba->cpucheck_on |= LPFC_CHECK_NVMET_IO; + phba->hdwqstat_on |= LPFC_CHECK_NVMET_IO; else - phba->cpucheck_on |= LPFC_CHECK_NVME_IO; + phba->hdwqstat_on |= LPFC_CHECK_NVME_IO; return strlen(pbuf); } else if ((strncmp(pbuf, "scsi_on", sizeof("scsi_on") - 1) == 0)) { - phba->cpucheck_on |= LPFC_CHECK_SCSI_IO; + if (!phba->nvmet_support) + phba->hdwqstat_on |= LPFC_CHECK_SCSI_IO; return strlen(pbuf); - } else if ((strncmp(pbuf, "rcv", - sizeof("rcv") - 1) == 0)) { - if (phba->nvmet_support) - phba->cpucheck_on |= LPFC_CHECK_NVMET_RCV; - else - return -EINVAL; + } else if ((strncmp(pbuf, "nvme_off", sizeof("nvme_off") - 1) == 0)) { + phba->hdwqstat_on &= ~(LPFC_CHECK_NVME_IO | + LPFC_CHECK_NVMET_IO); + return strlen(pbuf); + } else if ((strncmp(pbuf, "scsi_off", sizeof("scsi_off") - 1) == 0)) { + phba->hdwqstat_on &= ~LPFC_CHECK_SCSI_IO; return strlen(pbuf); } else if ((strncmp(pbuf, "off", sizeof("off") - 1) == 0)) { - phba->cpucheck_on = LPFC_CHECK_OFF; + phba->hdwqstat_on = LPFC_CHECK_OFF; return strlen(pbuf); } else if ((strncmp(pbuf, "zero", sizeof("zero") - 1) == 0)) { - for (i = 0; i < phba->cfg_hdw_queue; i++) { - qp = &phba->sli4_hba.hdwq[i]; - - for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) { - qp->cpucheck_rcv_io[j] = 0; - qp->cpucheck_xmt_io[j] = 0; - qp->cpucheck_cmpl_io[j] = 0; - } + for_each_present_cpu(i) { + c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, i); + c_stat->xmt_io = 0; + c_stat->cmpl_io = 0; + c_stat->rcv_io = 0; } return strlen(pbuf); } @@ -3242,7 +3339,6 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, break; case LPFC_PCI_CFG_BROWSE: /* browse all */ goto pcicfg_browse; - break; default: /* illegal count */ len = 0; @@ -4088,6 +4184,7 @@ lpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count) /** * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index * @pbuffer: The pointer to buffer to copy the read data into. + * @len: Length of the buffer. * @pque: The pointer to the queue to be read. * @index: The index into the queue entry. * @@ -4282,7 +4379,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, } } goto error_out; - break; + case LPFC_IDIAG_CQ: /* MBX complete queue */ if (phba->sli4_hba.mbx_cq && @@ -4334,7 +4431,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, } } goto error_out; - break; + case LPFC_IDIAG_MQ: /* MBX work queue */ if (phba->sli4_hba.mbx_wq && @@ -4348,7 +4445,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } goto error_out; - break; + case LPFC_IDIAG_WQ: /* ELS work queue */ if (phba->sli4_hba.els_wq && @@ -4388,9 +4485,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, } } } - goto error_out; - break; + case LPFC_IDIAG_RQ: /* HDR queue */ if (phba->sli4_hba.hdr_rq && @@ -4415,10 +4511,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } goto error_out; - break; default: goto error_out; - break; } pass_check: @@ -4667,7 +4761,7 @@ error_out: * @phba: The pointer to hba structure. * @pbuffer: The pointer to the buffer to copy the data to. * @len: The length of bytes to copied. - * @drbregid: The id to doorbell registers. + * @ctlregid: The id to doorbell registers. * * Description: * This routine reads a control register and copies its content to the @@ -5057,12 +5151,12 @@ error_out: * This routine is to get the available extent information. * * Returns: - * overall lenth of the data read into the internal buffer. + * overall length of the data read into the internal buffer. **/ static int lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len) { - uint16_t ext_cnt, ext_size; + uint16_t ext_cnt = 0, ext_size = 0; len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, "\nAvailable Extents Information:\n"); @@ -5108,7 +5202,7 @@ lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len) * This routine is to get the allocated extent information. * * Returns: - * overall lenth of the data read into the internal buffer. + * overall length of the data read into the internal buffer. **/ static int lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len) @@ -5180,7 +5274,7 @@ lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len) * This routine is to get the driver extent information. * * Returns: - * overall lenth of the data read into the internal buffer. + * overall length of the data read into the internal buffer. **/ static int lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len) @@ -5335,6 +5429,154 @@ lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes, return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); } +static int +lpfc_cgn_buffer_open(struct inode *inode, struct file *file) +{ + struct lpfc_debug *debug; + int rc = -ENOMEM; + + debug = kmalloc(sizeof(*debug), GFP_KERNEL); + if (!debug) + goto out; + + debug->buffer = vmalloc(LPFC_CGN_BUF_SIZE); + if (!debug->buffer) { + kfree(debug); + goto out; + } + + debug->i_private = inode->i_private; + file->private_data = debug; + + rc = 0; +out: + return rc; +} + +static ssize_t +lpfc_cgn_buffer_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + char *buffer = debug->buffer; + uint32_t *ptr; + int cnt, len = 0; + + if (!phba->sli4_hba.pc_sli4_params.mi_ver || !phba->cgn_i) { + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Congestion Mgmt is not supported\n"); + goto out; + } + ptr = (uint32_t *)phba->cgn_i->virt; + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Congestion Buffer Header\n"); + /* Dump the first 32 bytes */ + cnt = 32; + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "000: %08x %08x %08x %08x %08x %08x %08x %08x\n", + *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), + *(ptr + 4), *(ptr + 5), *(ptr + 6), *(ptr + 7)); + ptr += 8; + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Congestion Buffer Data\n"); + while (cnt < sizeof(struct lpfc_cgn_info)) { + if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) { + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Truncated . . .\n"); + goto out; + } + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "%03x: %08x %08x %08x %08x " + "%08x %08x %08x %08x\n", + cnt, *ptr, *(ptr + 1), *(ptr + 2), + *(ptr + 3), *(ptr + 4), *(ptr + 5), + *(ptr + 6), *(ptr + 7)); + cnt += 32; + ptr += 8; + } + if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) { + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Truncated . . .\n"); + goto out; + } + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Parameter Data\n"); + ptr = (uint32_t *)&phba->cgn_p; + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "%08x %08x %08x %08x\n", + *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3)); +out: + return simple_read_from_buffer(buf, nbytes, ppos, buffer, len); +} + +static int +lpfc_cgn_buffer_release(struct inode *inode, struct file *file) +{ + struct lpfc_debug *debug = file->private_data; + + vfree(debug->buffer); + kfree(debug); + + return 0; +} + +static int +lpfc_rx_monitor_open(struct inode *inode, struct file *file) +{ + struct lpfc_rx_monitor_debug *debug; + int rc = -ENOMEM; + + debug = kmalloc(sizeof(*debug), GFP_KERNEL); + if (!debug) + goto out; + + debug->buffer = vmalloc(MAX_DEBUGFS_RX_INFO_SIZE); + if (!debug->buffer) { + kfree(debug); + goto out; + } + + debug->i_private = inode->i_private; + file->private_data = debug; + + rc = 0; +out: + return rc; +} + +static ssize_t +lpfc_rx_monitor_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) +{ + struct lpfc_rx_monitor_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + char *buffer = debug->buffer; + + if (!phba->rx_monitor) { + scnprintf(buffer, MAX_DEBUGFS_RX_INFO_SIZE, + "Rx Monitor Info is empty.\n"); + } else { + lpfc_rx_monitor_report(phba, phba->rx_monitor, buffer, + MAX_DEBUGFS_RX_INFO_SIZE, + LPFC_MAX_RXMONITOR_ENTRY); + } + + return simple_read_from_buffer(buf, nbytes, ppos, buffer, + strlen(buffer)); +} + +static int +lpfc_rx_monitor_release(struct inode *inode, struct file *file) +{ + struct lpfc_rx_monitor_debug *debug = file->private_data; + + vfree(debug->buffer); + kfree(debug); + + return 0; +} + #undef lpfc_debugfs_op_disc_trc static const struct file_operations lpfc_debugfs_op_disc_trc = { .owner = THIS_MODULE, @@ -5431,13 +5673,13 @@ static const struct file_operations lpfc_debugfs_op_scsistat = { .release = lpfc_debugfs_release, }; -#undef lpfc_debugfs_op_nvmektime -static const struct file_operations lpfc_debugfs_op_nvmektime = { +#undef lpfc_debugfs_op_ioktime +static const struct file_operations lpfc_debugfs_op_ioktime = { .owner = THIS_MODULE, - .open = lpfc_debugfs_nvmektime_open, + .open = lpfc_debugfs_ioktime_open, .llseek = lpfc_debugfs_lseek, .read = lpfc_debugfs_read, - .write = lpfc_debugfs_nvmektime_write, + .write = lpfc_debugfs_ioktime_write, .release = lpfc_debugfs_release, }; @@ -5451,13 +5693,13 @@ static const struct file_operations lpfc_debugfs_op_nvmeio_trc = { .release = lpfc_debugfs_release, }; -#undef lpfc_debugfs_op_cpucheck -static const struct file_operations lpfc_debugfs_op_cpucheck = { +#undef lpfc_debugfs_op_hdwqstat +static const struct file_operations lpfc_debugfs_op_hdwqstat = { .owner = THIS_MODULE, - .open = lpfc_debugfs_cpucheck_open, + .open = lpfc_debugfs_hdwqstat_open, .llseek = lpfc_debugfs_lseek, .read = lpfc_debugfs_read, - .write = lpfc_debugfs_cpucheck_write, + .write = lpfc_debugfs_hdwqstat_write, .release = lpfc_debugfs_release, }; @@ -5563,6 +5805,23 @@ static const struct file_operations lpfc_idiag_op_extAcc = { .write = lpfc_idiag_extacc_write, .release = lpfc_idiag_cmd_release, }; +#undef lpfc_cgn_buffer_op +static const struct file_operations lpfc_cgn_buffer_op = { + .owner = THIS_MODULE, + .open = lpfc_cgn_buffer_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_cgn_buffer_read, + .release = lpfc_cgn_buffer_release, +}; + +#undef lpfc_rx_monitor_op +static const struct file_operations lpfc_rx_monitor_op = { + .owner = THIS_MODULE, + .open = lpfc_rx_monitor_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_rx_monitor_read, + .release = lpfc_rx_monitor_release, +}; #endif /* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command @@ -5813,6 +6072,32 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) goto debug_failed; } + /* Congestion Info Buffer */ + scnprintf(name, sizeof(name), "cgn_buffer"); + phba->debug_cgn_buffer = + debugfs_create_file(name, S_IFREG | 0644, + phba->hba_debugfs_root, + phba, &lpfc_cgn_buffer_op); + if (!phba->debug_cgn_buffer) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "6527 Cannot create debugfs " + "cgn_buffer\n"); + goto debug_failed; + } + + /* RX Monitor */ + scnprintf(name, sizeof(name), "rx_monitor"); + phba->debug_rx_monitor = + debugfs_create_file(name, S_IFREG | 0644, + phba->hba_debugfs_root, + phba, &lpfc_rx_monitor_op); + if (!phba->debug_rx_monitor) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "6528 Cannot create debugfs " + "rx_monitor\n"); + goto debug_failed; + } + /* RAS log */ snprintf(name, sizeof(name), "ras_log"); phba->debug_ras_log = @@ -5842,7 +6127,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) phba, &lpfc_debugfs_op_lockstat); if (!phba->debug_lockstat) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "4610 Cant create debugfs lockstat\n"); + "4610 Can't create debugfs lockstat\n"); goto debug_failed; } #endif @@ -5948,9 +6233,9 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) phba->hba_debugfs_root, phba, &lpfc_debugfs_op_slow_ring_trc); if (!phba->slow_ring_trc) { - phba->slow_ring_trc = kmalloc( - (sizeof(struct lpfc_debugfs_trc) * - lpfc_debugfs_max_slow_ring_trc), + phba->slow_ring_trc = kcalloc( + lpfc_debugfs_max_slow_ring_trc, + sizeof(struct lpfc_debugfs_trc), GFP_KERNEL); if (!phba->slow_ring_trc) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, @@ -5959,9 +6244,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) goto debug_failed; } atomic_set(&phba->slow_ring_trc_cnt, 0); - memset(phba->slow_ring_trc, 0, - (sizeof(struct lpfc_debugfs_trc) * - lpfc_debugfs_max_slow_ring_trc)); } snprintf(name, sizeof(name), "nvmeio_trc"); @@ -6075,17 +6357,22 @@ nvmeio_off: goto debug_failed; } - snprintf(name, sizeof(name), "nvmektime"); - vport->debug_nvmektime = + snprintf(name, sizeof(name), "ioktime"); + vport->debug_ioktime = debugfs_create_file(name, 0644, vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_nvmektime); + vport, &lpfc_debugfs_op_ioktime); + if (!vport->debug_ioktime) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0815 Cannot create debugfs ioktime\n"); + goto debug_failed; + } - snprintf(name, sizeof(name), "cpucheck"); - vport->debug_cpucheck = + snprintf(name, sizeof(name), "hdwqstat"); + vport->debug_hdwqstat = debugfs_create_file(name, 0644, vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_cpucheck); + vport, &lpfc_debugfs_op_hdwqstat); /* * The following section is for additional directories/files for the @@ -6216,11 +6503,11 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(vport->debug_scsistat); /* scsistat */ vport->debug_scsistat = NULL; - debugfs_remove(vport->debug_nvmektime); /* nvmektime */ - vport->debug_nvmektime = NULL; + debugfs_remove(vport->debug_ioktime); /* ioktime */ + vport->debug_ioktime = NULL; - debugfs_remove(vport->debug_cpucheck); /* cpucheck */ - vport->debug_cpucheck = NULL; + debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */ + vport->debug_hdwqstat = NULL; if (vport->vport_debugfs_root) { debugfs_remove(vport->vport_debugfs_root); /* vportX */ @@ -6236,6 +6523,12 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */ phba->debug_hbqinfo = NULL; + debugfs_remove(phba->debug_cgn_buffer); + phba->debug_cgn_buffer = NULL; + + debugfs_remove(phba->debug_rx_monitor); + phba->debug_rx_monitor = NULL; + debugfs_remove(phba->debug_ras_log); phba->debug_ras_log = NULL; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index 20f2537af511..8d2e8d05bbc0 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -46,13 +46,15 @@ /* nvmestat output buffer size */ #define LPFC_NVMESTAT_SIZE 8192 -#define LPFC_NVMEKTIME_SIZE 8192 -#define LPFC_CPUCHECK_SIZE 8192 +#define LPFC_IOKTIME_SIZE 8192 #define LPFC_NVMEIO_TRC_SIZE 8192 /* scsistat output buffer size */ #define LPFC_SCSISTAT_SIZE 8192 +/* Congestion Info Buffer size */ +#define LPFC_CGN_BUF_SIZE 8192 + #define LPFC_DEBUG_OUT_LINE_SZ 80 /* @@ -280,6 +282,12 @@ struct lpfc_idiag { void *ptr_private; }; +#define MAX_DEBUGFS_RX_INFO_SIZE (128 * LPFC_MAX_RXMONITOR_ENTRY) +struct lpfc_rx_monitor_debug { + char *i_private; + char *buffer; +}; + #else #define lpfc_nvmeio_data(phba, fmt, arg...) \ diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 482e4a888dae..f82615d87c4b 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2013 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -41,6 +41,7 @@ enum lpfc_work_type { LPFC_EVT_DEV_LOSS, LPFC_EVT_FASTPATH_MGMT_EVT, LPFC_EVT_RESET_HBA, + LPFC_EVT_RECOVER_PORT }; /* structure used to queue event to the discovery tasklet */ @@ -76,10 +77,29 @@ struct lpfc_node_rrqs { unsigned long xri_bitmap[XRI_BITMAP_ULONGS]; }; +enum lpfc_fc4_xpt_flags { + NLP_XPT_REGD = 0x1, + SCSI_XPT_REGD = 0x2, + NVME_XPT_REGD = 0x4, + NVME_XPT_UNREG_WAIT = 0x8, + NLP_XPT_HAS_HH = 0x10 +}; + +enum lpfc_nlp_save_flags { + /* devloss occurred during recovery */ + NLP_IN_RECOV_POST_DEV_LOSS = 0x1, + /* wait for outstanding LOGO to cmpl */ + NLP_WAIT_FOR_LOGO = 0x2, +}; + struct lpfc_nodelist { struct list_head nlp_listp; + struct serv_parm fc_sparam; /* buffer for service params */ struct lpfc_name nlp_portname; struct lpfc_name nlp_nodename; + + spinlock_t lock; /* Node management lock */ + uint32_t nlp_flag; /* entry flags */ uint32_t nlp_DID; /* FC D_ID of entry */ uint32_t nlp_last_elscmd; /* Last ELS cmd sent */ @@ -113,14 +133,9 @@ struct lpfc_nodelist { uint8_t nlp_fcp_info; /* class info, bits 0-3 */ #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ u8 nlp_nvme_info; /* NVME NSLER Support */ + uint8_t vmid_support; /* destination VMID support */ #define NLP_NVME_NSLER 0x1 /* NVME NSLER device */ - uint16_t nlp_usg_map; /* ndlp management usage bitmap */ -#define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */ -#define NLP_USG_IACT_REQ_BIT 0x2 /* Request to inactivate ndlp */ -#define NLP_USG_FREE_REQ_BIT 0x4 /* Request to invoke ndlp memory free */ -#define NLP_USG_FREE_ACK_BIT 0x8 /* Indicate ndlp memory free invoked */ - struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ struct lpfc_hba *phba; struct fc_rport *rport; /* scsi_transport_fc port structure */ @@ -128,20 +143,25 @@ struct lpfc_nodelist { struct lpfc_vport *vport; struct lpfc_work_evt els_retry_evt; struct lpfc_work_evt dev_loss_evt; + struct lpfc_work_evt recovery_evt; struct kref kref; atomic_t cmd_pending; uint32_t cmd_qdepth; unsigned long last_change_time; unsigned long *active_rrqs_xri_bitmap; - struct lpfc_scsicmd_bkt *lat_data; /* Latency data */ uint32_t fc4_prli_sent; - uint32_t upcall_flags; -#define NLP_WAIT_FOR_UNREG 0x1 + + /* flags to keep ndlp alive until special conditions are met */ + enum lpfc_nlp_save_flags save_flags; + + enum lpfc_fc4_xpt_flags fc4_xpt_flags; uint32_t nvme_fb_size; /* NVME target's supported byte cnt */ #define NVME_FB_BIT_SHIFT 9 /* PRLI Rsp first burst in 512B units. */ uint32_t nlp_defer_did; + wait_queue_head_t *logo_waitq; }; + struct lpfc_node_rrq { struct list_head list; uint16_t xritag; @@ -149,7 +169,6 @@ struct lpfc_node_rrq { uint16_t rxid; uint32_t nlp_DID; /* FC D_ID of entry */ struct lpfc_vport *vport; - struct lpfc_nodelist *ndlp; unsigned long rrq_stop_time; }; @@ -168,9 +187,8 @@ struct lpfc_node_rrq { #define NLP_RNID_SND 0x00000400 /* sent RNID request for this entry */ #define NLP_ELS_SND_MASK 0x000007e0 /* sent ELS request for this entry */ #define NLP_NVMET_RECOV 0x00001000 /* NVMET auditing node for recovery. */ -#define NLP_FCP_PRLI_RJT 0x00002000 /* Rport does not support FCP PRLI. */ #define NLP_UNREG_INP 0x00008000 /* UNREG_RPI cmd is in progress */ -#define NLP_DEFER_RM 0x00010000 /* Remove this ndlp if no longer used */ +#define NLP_DROPPED 0x00010000 /* Init ref count has been dropped */ #define NLP_DELAY_TMO 0x00020000 /* delay timeout is running for node */ #define NLP_NPR_2B_DISC 0x00040000 /* node is included in num_disc_nodes */ #define NLP_RCV_PLOGI 0x00080000 /* Rcv'ed PLOGI from remote system */ @@ -189,32 +207,6 @@ struct lpfc_node_rrq { #define NLP_FIRSTBURST 0x40000000 /* Target supports FirstBurst */ #define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */ - -/* ndlp usage management macros */ -#define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \ - & NLP_USG_NODE_ACT_BIT) \ - && \ - !((ndlp)->nlp_usg_map \ - & NLP_USG_FREE_ACK_BIT)) -#define NLP_SET_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_NODE_ACT_BIT) -#define NLP_INT_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ - = NLP_USG_NODE_ACT_BIT) -#define NLP_CLR_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ - &= ~NLP_USG_NODE_ACT_BIT) -#define NLP_CHK_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ - & NLP_USG_IACT_REQ_BIT) -#define NLP_SET_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_IACT_REQ_BIT) -#define NLP_CHK_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ - & NLP_USG_FREE_REQ_BIT) -#define NLP_SET_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_FREE_REQ_BIT) -#define NLP_CHK_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ - & NLP_USG_FREE_ACK_BIT) -#define NLP_SET_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_FREE_ACK_BIT) - /* There are 4 different double linked lists nodelist entries can reside on. * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used * when Link Up discovery or Registered State Change Notification (RSCN) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 42a2bf38eaea..863b2125fed6 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -25,6 +25,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/delay.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> @@ -55,9 +56,18 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry); static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb); +static void lpfc_cmpl_els_edc(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb); +static void lpfc_cmpl_els_uvem(struct lpfc_hba *, struct lpfc_iocbq *, + struct lpfc_iocbq *); static int lpfc_max_els_tries = 3; +static void lpfc_init_cs_ctl_bitmap(struct lpfc_vport *vport); +static void lpfc_vmid_set_cs_ctl_range(struct lpfc_vport *vport, u32 min, u32 max); +static void lpfc_vmid_put_cs_ctl(struct lpfc_vport *vport, u32 ctcl_vmid); + /** * lpfc_els_chk_latt - Check host link attention event for a vport * @vport: pointer to a host virtual N_Port data structure. @@ -100,7 +110,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) return 0; /* Pending Link Event during Discovery */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0237 Pending Link Event during " "Discovery: State x%x\n", phba->pport->port_state); @@ -124,9 +134,9 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) /** * lpfc_prep_els_iocb - Allocate and prepare a lpfc iocb data structure * @vport: pointer to a host virtual N_Port data structure. - * @expectRsp: flag indicating whether response is expected. - * @cmdSize: size of the ELS command. - * @retry: number of retries to the command IOCB when it fails. + * @expect_rsp: flag indicating whether response is expected. + * @cmd_size: size of the ELS command. + * @retry: number of retries to the command when it fails. * @ndlp: pointer to a node-list data structure. * @did: destination identifier. * @elscmd: the ELS command code. @@ -142,7 +152,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) * 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 IOCB data structure for this IOCB to hold the ndlp + * ndlp of the IOCB data structure for this IOCB to hold the ndlp * reference for the command's callback function to access later. * * Return code @@ -150,25 +160,23 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) * NULL - when els iocb data structure allocation/preparation failed **/ struct lpfc_iocbq * -lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, - uint16_t cmdSize, uint8_t retry, - struct lpfc_nodelist *ndlp, uint32_t did, - uint32_t elscmd) +lpfc_prep_els_iocb(struct lpfc_vport *vport, u8 expect_rsp, + u16 cmd_size, u8 retry, + struct lpfc_nodelist *ndlp, u32 did, + u32 elscmd) { struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; - struct lpfc_dmabuf *pcmd, *prsp, *pbuflist; - struct ulp_bde64 *bpl; - IOCB_t *icmd; - + struct lpfc_dmabuf *pcmd, *prsp, *pbuflist, *bmp; + struct ulp_bde64_le *bpl; + u32 timeout = 0; if (!lpfc_is_link_up(phba)) return NULL; /* Allocate buffer for command iocb */ elsiocb = lpfc_sli_get_iocbq(phba); - - if (elsiocb == NULL) + if (!elsiocb) return NULL; /* @@ -176,35 +184,33 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, * in FIP mode send FLOGI, FDISC and LOGO as FIP frames. */ if ((did == Fabric_DID) && - (phba->hba_flag & HBA_FIP_SUPPORT) && - ((elscmd == ELS_CMD_FLOGI) || - (elscmd == ELS_CMD_FDISC) || - (elscmd == ELS_CMD_LOGO))) + (phba->hba_flag & HBA_FIP_SUPPORT) && + ((elscmd == ELS_CMD_FLOGI) || + (elscmd == ELS_CMD_FDISC) || + (elscmd == ELS_CMD_LOGO))) switch (elscmd) { case ELS_CMD_FLOGI: - elsiocb->iocb_flag |= - ((LPFC_ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT) - & LPFC_FIP_ELS_ID_MASK); - break; + elsiocb->cmd_flag |= + ((LPFC_ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT) + & LPFC_FIP_ELS_ID_MASK); + break; case ELS_CMD_FDISC: - elsiocb->iocb_flag |= - ((LPFC_ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT) - & LPFC_FIP_ELS_ID_MASK); - break; + elsiocb->cmd_flag |= + ((LPFC_ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT) + & LPFC_FIP_ELS_ID_MASK); + break; case ELS_CMD_LOGO: - elsiocb->iocb_flag |= - ((LPFC_ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT) - & LPFC_FIP_ELS_ID_MASK); - break; + elsiocb->cmd_flag |= + ((LPFC_ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT) + & LPFC_FIP_ELS_ID_MASK); + break; } else - elsiocb->iocb_flag &= ~LPFC_FIP_ELS_ID_MASK; - - icmd = &elsiocb->iocb; + elsiocb->cmd_flag &= ~LPFC_FIP_ELS_ID_MASK; /* fill in BDEs for command */ /* Allocate buffer for command payload */ - pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + pcmd = kmalloc(sizeof(*pcmd), GFP_KERNEL); if (pcmd) pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); if (!pcmd || !pcmd->virt) @@ -213,19 +219,20 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, INIT_LIST_HEAD(&pcmd->list); /* Allocate buffer for response payload */ - if (expectRsp) { - prsp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (expect_rsp) { + prsp = kmalloc(sizeof(*prsp), GFP_KERNEL); if (prsp) prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &prsp->phys); if (!prsp || !prsp->virt) goto els_iocb_free_prsp_exit; INIT_LIST_HEAD(&prsp->list); - } else + } else { prsp = NULL; + } /* Allocate buffer for Buffer ptr list */ - pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + pbuflist = kmalloc(sizeof(*pbuflist), GFP_KERNEL); if (pbuflist) pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pbuflist->phys); @@ -234,86 +241,53 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, INIT_LIST_HEAD(&pbuflist->list); - if (expectRsp) { - icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); - icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys); - icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); - - icmd->un.elsreq64.remoteID = did; /* DID */ - icmd->ulpCommand = CMD_ELS_REQUEST64_CR; - if (elscmd == ELS_CMD_FLOGI) - icmd->ulpTimeout = FF_DEF_RATOV * 2; - else if (elscmd == ELS_CMD_LOGO) - icmd->ulpTimeout = phba->fc_ratov; - else - icmd->ulpTimeout = phba->fc_ratov * 2; - } else { - icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); - icmd->un.xseq64.bdl.addrLow = putPaddrLow(pbuflist->phys); - icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - icmd->un.xseq64.bdl.bdeSize = sizeof(struct ulp_bde64); - icmd->un.xseq64.xmit_els_remoteID = did; /* DID */ - icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX; - } - icmd->ulpBdeCount = 1; - icmd->ulpLe = 1; - icmd->ulpClass = CLASS3; - - /* - * If we have NPIV enabled, we want to send ELS traffic by VPI. - * For SLI4, since the driver controls VPIs we also want to include - * all ELS pt2pt protocol traffic as well. - */ - if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) || - ((phba->sli_rev == LPFC_SLI_REV4) && - (vport->fc_flag & FC_PT2PT))) { - - if (expectRsp) { - icmd->un.elsreq64.myID = vport->fc_myDID; - - /* For ELS_REQUEST64_CR, use the VPI by default */ - icmd->ulpContext = phba->vpi_ids[vport->vpi]; + if (expect_rsp) { + switch (elscmd) { + case ELS_CMD_FLOGI: + timeout = FF_DEF_RATOV * 2; + break; + case ELS_CMD_LOGO: + timeout = phba->fc_ratov; + break; + default: + timeout = phba->fc_ratov * 2; } - icmd->ulpCt_h = 0; - /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ - if (elscmd == ELS_CMD_ECHO) - icmd->ulpCt_l = 0; /* context = invalid RPI */ - else - icmd->ulpCt_l = 1; /* context = VPI */ + /* Fill SGE for the num bde count */ + elsiocb->num_bdes = 2; } - bpl = (struct ulp_bde64 *) pbuflist->virt; - bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys)); - bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys)); - bpl->tus.f.bdeSize = cmdSize; - bpl->tus.f.bdeFlags = 0; - bpl->tus.w = le32_to_cpu(bpl->tus.w); + if (phba->sli_rev == LPFC_SLI_REV4) + bmp = pcmd; + else + bmp = pbuflist; + + lpfc_sli_prep_els_req_rsp(phba, elsiocb, vport, bmp, cmd_size, did, + elscmd, timeout, expect_rsp); - if (expectRsp) { + bpl = (struct ulp_bde64_le *)pbuflist->virt; + bpl->addr_low = cpu_to_le32(putPaddrLow(pcmd->phys)); + bpl->addr_high = cpu_to_le32(putPaddrHigh(pcmd->phys)); + bpl->type_size = cpu_to_le32(cmd_size); + bpl->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64); + + if (expect_rsp) { bpl++; - bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys)); - bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys)); - bpl->tus.f.bdeSize = FCELSSIZE; - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl->tus.w = le32_to_cpu(bpl->tus.w); + bpl->addr_low = cpu_to_le32(putPaddrLow(prsp->phys)); + bpl->addr_high = cpu_to_le32(putPaddrHigh(prsp->phys)); + bpl->type_size = cpu_to_le32(FCELSSIZE); + bpl->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64); } - /* prevent preparing iocb with NULL ndlp reference */ - elsiocb->context1 = lpfc_nlp_get(ndlp); - if (!elsiocb->context1) - goto els_iocb_free_pbuf_exit; - elsiocb->context2 = pcmd; - elsiocb->context3 = pbuflist; + elsiocb->cmd_dmabuf = pcmd; + elsiocb->bpl_dmabuf = pbuflist; elsiocb->retry = retry; elsiocb->vport = vport; elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT; - if (prsp) { + if (prsp) list_add(&prsp->list, &pcmd->list); - } - if (expectRsp) { + if (expect_rsp) { /* Xmit ELS command <elsCmd> to remote NPORT <did> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0116 Xmit ELS command x%x to remote " @@ -329,13 +303,14 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, "NPORT x%x I/O tag: x%x, size: x%x " "port_state x%x rpi x%x fc_flag x%x\n", elscmd, ndlp->nlp_DID, elsiocb->iotag, - cmdSize, vport->port_state, + cmd_size, vport->port_state, ndlp->nlp_rpi, vport->fc_flag); } + return elsiocb; els_iocb_free_pbuf_exit: - if (expectRsp) + if (expect_rsp) lpfc_mbuf_free(phba, prsp->virt, prsp->phys); kfree(pbuflist); @@ -370,7 +345,6 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *mp; struct lpfc_nodelist *ndlp; struct serv_parm *sp; int rc; @@ -378,7 +352,7 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) sp = &phba->fc_fabparam; ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { err = 1; goto fail; } @@ -418,10 +392,14 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) * for the callback routine. */ mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) { + err = 6; + goto fail_free_mbox; + } rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - err = 6; + err = 7; goto fail_issue_reg_login; } @@ -432,16 +410,13 @@ fail_issue_reg_login: * for the failed mbox command. */ lpfc_nlp_put(ndlp); - mp = (struct lpfc_dmabuf *)mbox->ctx_buf; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); fail_free_mbox: - mempool_free(mbox, phba->mbox_mem_pool); - + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); fail: lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0249 Cannot issue Register Fabric login: Err %d\n", err); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0249 Cannot issue Register Fabric login: Err %d\n", + err); return -ENXIO; } @@ -470,7 +445,7 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) !(phba->link_flag & LS_LOOPBACK_MODE) && !(vport->fc_flag & FC_PT2PT)) { ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { rc = -ENODEV; goto fail; } @@ -484,48 +459,40 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) /* Supply CSP's only if we are fabric connect or pt-to-pt connect */ if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) { - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!dmabuf) { - rc = -ENOMEM; - goto fail; - } - dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys); - if (!dmabuf->virt) { + rc = lpfc_mbox_rsrc_prep(phba, mboxq); + if (rc) { rc = -ENOMEM; - goto fail; + goto fail_mbox; } + dmabuf = mboxq->ctx_buf; memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(struct serv_parm)); } vport->port_state = LPFC_FABRIC_CFG_LINK; - if (dmabuf) + if (dmabuf) { lpfc_reg_vfi(mboxq, vport, dmabuf->phys); - else + /* lpfc_reg_vfi memsets the mailbox. Restore the ctx_buf. */ + mboxq->ctx_buf = dmabuf; + } else { lpfc_reg_vfi(mboxq, vport, 0); + } mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi; mboxq->vport = vport; - mboxq->ctx_buf = dmabuf; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { rc = -ENXIO; - goto fail; + goto fail_mbox; } return 0; +fail_mbox: + lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED); fail: - if (mboxq) - mempool_free(mboxq, phba->mbox_mem_pool); - if (dmabuf) { - if (dmabuf->virt) - lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); - kfree(dmabuf); - } - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0289 Issue Register VFI failed: Err %d\n", rc); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0289 Issue Register VFI failed: Err %d\n", rc); return rc; } @@ -550,7 +517,7 @@ lpfc_issue_unreg_vfi(struct lpfc_vport *vport) mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2556 UNREG_VFI mbox allocation failed" "HBA state x%x\n", phba->pport->port_state); return -ENOMEM; @@ -562,7 +529,7 @@ lpfc_issue_unreg_vfi(struct lpfc_vport *vport) rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2557 UNREG_VFI issue mbox failed rc x%x " "HBA state x%x\n", rc, phba->pport->port_state); @@ -638,7 +605,7 @@ lpfc_check_clean_addr_bit(struct lpfc_vport *vport, * @vport: pointer to a host virtual N_Port data structure. * @ndlp: pointer to a node-list data structure. * @sp: pointer to service parameter data structure. - * @irsp: pointer to the IOCB within the lpfc response IOCB. + * @ulp_word4: command response value * * This routine is invoked by the lpfc_cmpl_els_flogi() completion callback * function to handle the completion of a Fabric Login (FLOGI) into a fabric @@ -655,7 +622,7 @@ lpfc_check_clean_addr_bit(struct lpfc_vport *vport, **/ static int lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct serv_parm *sp, IOCB_t *irsp) + struct serv_parm *sp, uint32_t ulp_word4) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; @@ -680,7 +647,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock_irq(shost->host_lock); } - vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; + vport->fc_myDID = ulp_word4 & Mask_DID; memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name)); memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof(struct lpfc_name)); ndlp->nlp_class_sup = 0; @@ -730,7 +697,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock_irq(&phba->hbalock); } else { /* Because we asked f/w for NPIV it still expects us - to call reg_vnpid atleast for the physcial host */ + to call reg_vnpid at least for the physical host */ lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS | LOG_VPORT, "1817 Fabric does not support NPIV " @@ -764,14 +731,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ list_for_each_entry_safe(np, next_np, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(np)) - continue; if ((np->nlp_state != NLP_STE_NPR_NODE) || !(np->nlp_flag & NLP_NPR_ADISC)) continue; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&np->lock); np->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&np->lock); lpfc_unreg_rpi(vport, np); } lpfc_cleanup_pending_mbox(vport); @@ -893,10 +858,12 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (rc) vport->fc_myDID = PT2PT_LocalID; - /* Decrement ndlp reference count indicating that ndlp can be - * safely released when other references to it are done. + /* If not registered with a transport, decrement ndlp reference + * count indicating that ndlp can be safely released when other + * references are removed. */ - lpfc_nlp_put(ndlp); + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) + lpfc_nlp_put(ndlp); ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID); if (!ndlp) { @@ -907,11 +874,6 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp = lpfc_nlp_init(vport, PT2PT_RemoteID); if (!ndlp) goto fail; - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if(!ndlp) - goto fail; } memcpy(&ndlp->nlp_portname, &sp->portName, @@ -920,9 +882,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, sizeof(struct lpfc_name)); /* Set state will put ndlp onto node list if not already done */ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) @@ -938,11 +900,12 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, goto fail; } } else { - /* This side will wait for the PLOGI, decrement ndlp reference - * count indicating that ndlp can be released when other - * references to it are done. + /* This side will wait for the PLOGI. If not registered with + * a transport, decrement node reference count indicating that + * ndlp can be released when other references are removed. */ - lpfc_nlp_put(ndlp); + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) + lpfc_nlp_put(ndlp); /* Start discovery - this should just do CLEAR_LA */ lpfc_disc_start(vport); @@ -982,28 +945,40 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_nodelist *ndlp = cmdiocb->context1; - struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; + IOCB_t *irsp; + struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf, *prsp; struct serv_parm *sp; uint16_t fcf_index; int rc; + u32 ulp_status, ulp_word4, tmo; /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { /* One additional decrement on node reference count to * trigger the release of the node */ - lpfc_nlp_put(ndlp); + if (!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) + lpfc_nlp_put(ndlp); goto out; } + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); + + if (phba->sli_rev == LPFC_SLI_REV4) { + tmo = get_wqe_tmo(cmdiocb); + } else { + irsp = &rspiocb->iocb; + tmo = irsp->ulpTimeout; + } + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "FLOGI cmpl: status:x%x/x%x state:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], + ulp_status, ulp_word4, vport->port_state); - if (irsp->ulpStatus) { + if (ulp_status) { /* * In case of FIP mode, perform roundrobin FCF failover * due to new FCF discovery @@ -1014,8 +989,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto stop_rr_fcf_flogi; if ((phba->fcoe_cvl_eventtag_attn == phba->fcoe_cvl_eventtag) && - (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + (ulp_status == IOSTAT_LOCAL_REJECT) && + ((ulp_word4 & IOERR_PARAM_MASK) == IOERR_SLI_ABORTED)) goto stop_rr_fcf_flogi; else @@ -1026,8 +1001,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "status:x%x/x%x, tmo:x%x, perform " "roundrobin FCF failover\n", phba->fcf.current_rec.fcf_indx, - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout); + ulp_status, ulp_word4, tmo); lpfc_sli4_set_fcf_flogi_fail(phba, phba->fcf.current_rec.fcf_indx); fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba); @@ -1038,35 +1012,41 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, stop_rr_fcf_flogi: /* FLOGI failure */ - if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT && - ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + if (!(ulp_status == IOSTAT_LOCAL_REJECT && + ((ulp_word4 & IOERR_PARAM_MASK) == IOERR_LOOP_OPEN_FAILURE))) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2858 FLOGI failure Status:x%x/x%x " - "TMO:x%x Data x%x x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, phba->hba_flag, - phba->fcf.fcf_flag); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2858 FLOGI failure Status:x%x/x%x TMO" + ":x%x Data x%x x%x\n", + ulp_status, ulp_word4, tmo, + phba->hba_flag, phba->fcf.fcf_flag); /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; - lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, + lpfc_printf_vlog(vport, KERN_WARNING, LOG_TRACE_EVENT, "0150 FLOGI failure Status:x%x/x%x " - "xri x%x TMO:x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], - cmdiocb->sli4_xritag, irsp->ulpTimeout); + "xri x%x TMO:x%x refcnt %d\n", + ulp_status, ulp_word4, cmdiocb->sli4_xritag, + tmo, kref_read(&ndlp->kref)); /* If this is not a loop open failure, bail out */ - if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT && - ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == - IOERR_LOOP_OPEN_FAILURE))) + if (!(ulp_status == IOSTAT_LOCAL_REJECT && + ((ulp_word4 & IOERR_PARAM_MASK) == + IOERR_LOOP_OPEN_FAILURE))) { + /* FLOGI failure */ + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0100 FLOGI failure Status:x%x/x%x " + "TMO:x%x\n", + ulp_status, ulp_word4, tmo); goto flogifail; + } /* FLOGI failed, so there is no fabric */ spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); + vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP | + FC_PT2PT_NO_NVME); spin_unlock_irq(shost->host_lock); /* If private loop, then allow max outstanding els to be @@ -1092,8 +1072,9 @@ stop_rr_fcf_flogi: } /* Do not register VFI if the driver aborted FLOGI */ - if (!lpfc_error_lost_link(irsp)) + if (!lpfc_error_lost_link(ulp_status, ulp_word4)) lpfc_issue_reg_vfi(vport); + lpfc_nlp_put(ndlp); goto out; } @@ -1115,12 +1096,17 @@ stop_rr_fcf_flogi: /* FLOGI completes successfully */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0101 FLOGI completes successfully, I/O tag:x%x, " - "xri x%x Data: x%x x%x x%x x%x x%x %x\n", + "0101 FLOGI completes successfully, I/O tag:x%x " + "xri x%x Data: x%x x%x x%x x%x x%x x%x x%x %d\n", cmdiocb->iotag, cmdiocb->sli4_xritag, - irsp->un.ulpWord[4], sp->cmn.e_d_tov, + ulp_word4, sp->cmn.e_d_tov, sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution, - vport->port_state, vport->fc_flag); + vport->port_state, vport->fc_flag, + sp->cmn.priority_tagging, kref_read(&ndlp->kref)); + + if (sp->cmn.priority_tagging) + vport->phba->pport->vmid_flag |= (LPFC_VMID_ISSUE_QFPA | + LPFC_VMID_TYPE_PRIO); if (vport->port_state == LPFC_FLOGI) { /* @@ -1128,12 +1114,12 @@ stop_rr_fcf_flogi: * we are point to point, if Fport we are Fabric. */ if (sp->cmn.fPort) - rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp); + rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, + ulp_word4); else if (!(phba->hba_flag & HBA_FCOE_MODE)) rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp); else { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_FIP | LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2831 FLOGI response with cleared Fabric " "bit fcf_index 0x%x " "Switch Name %02x%02x%02x%02x%02x%02x%02x%02x " @@ -1156,6 +1142,7 @@ stop_rr_fcf_flogi: phba->fcf.current_rec.fabric_name[5], phba->fcf.current_rec.fabric_name[6], phba->fcf.current_rec.fabric_name[7]); + lpfc_nlp_put(ndlp); spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag &= ~FCF_DISCOVERY; @@ -1179,6 +1166,15 @@ stop_rr_fcf_flogi: phba->fcf.fcf_redisc_attempted = 0; /* reset */ goto out; } + } else if (vport->port_state > LPFC_FLOGI && + vport->fc_flag & FC_PT2PT) { + /* + * In a p2p topology, it is possible that discovery has + * already progressed, and this completion can be ignored. + * Recheck the indicated topology. + */ + if (!sp->cmn.fPort) + goto out; } flogifail: @@ -1186,25 +1182,25 @@ flogifail: phba->fcf.fcf_flag &= ~FCF_DISCOVERY; spin_unlock_irq(&phba->hbalock); - lpfc_nlp_put(ndlp); - - if (!lpfc_error_lost_link(irsp)) { + if (!lpfc_error_lost_link(ulp_status, ulp_word4)) { /* FLOGI failed, so just use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); /* Start discovery */ lpfc_disc_start(vport); - } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || - (((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) != + } else if (((ulp_status != IOSTAT_LOCAL_REJECT) || + (((ulp_word4 & IOERR_PARAM_MASK) != IOERR_SLI_ABORTED) && - ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) != + ((ulp_word4 & IOERR_PARAM_MASK) != IOERR_SLI_DOWN))) && (phba->link_state != LPFC_CLEAR_LA)) { /* If FLOGI failed enable link interrupt. */ lpfc_issue_clear_la(phba, vport); } out: + phba->hba_flag &= ~HBA_FLOGI_OUTSTANDING; lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } /** @@ -1219,22 +1215,24 @@ static void lpfc_cmpl_els_link_down(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - IOCB_t *irsp; uint32_t *pcmd; uint32_t cmd; + u32 ulp_status, ulp_word4; - pcmd = (uint32_t *)(((struct lpfc_dmabuf *)cmdiocb->context2)->virt); + pcmd = (uint32_t *)cmdiocb->cmd_dmabuf->virt; cmd = *pcmd; - irsp = &rspiocb->iocb; + + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "6445 ELS completes after LINK_DOWN: " " Status %x/%x cmd x%x flg x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], cmd, - cmdiocb->iocb_flag); + ulp_status, ulp_word4, cmd, + cmdiocb->cmd_flag); - if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) { - cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC; + if (cmdiocb->cmd_flag & LPFC_IO_FABRIC) { + cmdiocb->cmd_flag &= ~LPFC_IO_FABRIC; atomic_dec(&phba->fabric_iocb_count); } lpfc_els_free_iocb(phba, cmdiocb); @@ -1253,10 +1251,9 @@ lpfc_cmpl_els_link_down(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * function field. The lpfc_issue_fabric_iocb routine is invoked to send * out FLOGI ELS command with one outstanding fabric IOCB at a time. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the FLOGI ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the FLOGI ELS command. * * Return code * 0 - successfully issued flogi iocb for @vport @@ -1268,10 +1265,11 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_hba *phba = vport->phba; struct serv_parm *sp; - IOCB_t *icmd; + union lpfc_wqe128 *wqe = NULL; + IOCB_t *icmd = NULL; struct lpfc_iocbq *elsiocb; struct lpfc_iocbq defer_flogi_acc; - uint8_t *pcmd; + u8 *pcmd, ct; uint16_t cmdsize; uint32_t tmo, did; int rc; @@ -1283,8 +1281,9 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; + wqe = &elsiocb->wqe; + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For FLOGI request, remainder of payload is service parameters */ *((uint32_t *) (pcmd)) = ELS_CMD_FLOGI; @@ -1302,15 +1301,30 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (sp->cmn.fcphHigh < FC_PH3) sp->cmn.fcphHigh = FC_PH3; + /* Determine if switch supports priority tagging */ + if (phba->cfg_vmid_priority_tagging) { + sp->cmn.priority_tagging = 1; + /* lpfc_vmid_host_uuid is combination of wwpn and wwnn */ + if (uuid_is_null((uuid_t *)vport->lpfc_vmid_host_uuid)) { + memcpy(vport->lpfc_vmid_host_uuid, phba->wwpn, + sizeof(phba->wwpn)); + memcpy(&vport->lpfc_vmid_host_uuid[8], phba->wwnn, + sizeof(phba->wwnn)); + } + } + if (phba->sli_rev == LPFC_SLI_REV4) { if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_IF_TYPE_0) { - elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1); - elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1); /* FLOGI needs to be 3 for WQE FCFI */ + ct = SLI4_CT_FCFI; + bf_set(wqe_ct, &wqe->els_req.wqe_com, ct); + /* Set the fcfi to the fcfi we registered with */ - elsiocb->iocb.ulpContext = phba->fcf.fcfi; + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->fcf.fcfi); } + /* Can't do SLI4 class2 without support sequence coalescing */ sp->cls2.classValid = 0; sp->cls2.seqDelivery = 0; @@ -1323,13 +1337,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */ icmd->ulpCt_h = 1; icmd->ulpCt_l = 0; - } else + } else { sp->cmn.request_multiple_Nport = 0; - } + } - if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) { - icmd->un.elsreq64.myID = 0; - icmd->un.elsreq64.fl = 1; + if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) { + icmd->un.elsreq64.myID = 0; + icmd->un.elsreq64.fl = 1; + } } tmo = phba->fc_ratov; @@ -1338,26 +1353,55 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->fc_ratov = tmo; phba->fc_stat.elsXmitFLOGI++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi; + elsiocb->cmd_cmpl = lpfc_cmpl_els_flogi; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue FLOGI: opt:x%x", phba->sli3_options, 0, 0); + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + rc = lpfc_issue_fabric_iocb(phba, elsiocb); + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + return 1; + } + + phba->hba_flag |= (HBA_FLOGI_ISSUED | HBA_FLOGI_OUTSTANDING); - phba->hba_flag |= HBA_FLOGI_ISSUED; + /* Clear external loopback plug detected flag */ + phba->link_flag &= ~LS_EXTERNAL_LOOPBACK; /* Check for a deferred FLOGI ACC condition */ if (phba->defer_flogi_acc_flag) { + /* lookup ndlp for received FLOGI */ + ndlp = lpfc_findnode_did(vport, 0); + if (!ndlp) + return 0; + did = vport->fc_myDID; vport->fc_myDID = Fabric_DID; memset(&defer_flogi_acc, 0, sizeof(struct lpfc_iocbq)); - defer_flogi_acc.iocb.ulpContext = phba->defer_flogi_acc_rx_id; - defer_flogi_acc.iocb.unsli3.rcvsli3.ox_id = - phba->defer_flogi_acc_ox_id; + if (phba->sli_rev == LPFC_SLI_REV4) { + bf_set(wqe_ctxt_tag, + &defer_flogi_acc.wqe.xmit_els_rsp.wqe_com, + phba->defer_flogi_acc_rx_id); + bf_set(wqe_rcvoxid, + &defer_flogi_acc.wqe.xmit_els_rsp.wqe_com, + phba->defer_flogi_acc_ox_id); + } else { + icmd = &defer_flogi_acc.iocb; + icmd->ulpContext = phba->defer_flogi_acc_rx_id; + icmd->unsli3.rcvsli3.ox_id = + phba->defer_flogi_acc_ox_id; + } lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3354 Xmit deferred FLOGI ACC: rx_id: x%x," @@ -1370,14 +1414,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp, NULL); phba->defer_flogi_acc_flag = false; - vport->fc_myDID = did; - } - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; + /* Decrement ndlp reference count to indicate the node can be + * released when other references are removed. + */ + lpfc_nlp_put(ndlp); } + return 0; } @@ -1401,7 +1445,7 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba) struct lpfc_sli_ring *pring; struct lpfc_iocbq *iocb, *next_iocb; struct lpfc_nodelist *ndlp; - IOCB_t *icmd; + u32 ulp_command; /* Abort outstanding I/O on NPort <nlp_DID> */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, @@ -1418,14 +1462,22 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba) */ spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { - icmd = &iocb->iocb; - if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { - ndlp = (struct lpfc_nodelist *)(iocb->context1); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (ndlp->nlp_DID == Fabric_DID)) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + ulp_command = get_job_cmnd(phba, iocb); + if (ulp_command == CMD_ELS_REQUEST64_CR) { + ndlp = iocb->ndlp; + if (ndlp && ndlp->nlp_DID == Fabric_DID) { + if ((phba->pport->fc_flag & FC_PT2PT) && + !(phba->pport->fc_flag & FC_PT2PT_PLOGI)) + iocb->fabric_cmd_cmpl = + lpfc_ignore_els_cmpl; + lpfc_sli_issue_abort_iotag(phba, pring, iocb, + NULL); + } } } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + spin_unlock_irq(&phba->hbalock); return 0; @@ -1464,20 +1516,21 @@ lpfc_initial_flogi(struct lpfc_vport *vport) return 0; /* Set the node type */ ndlp->nlp_type |= NLP_FABRIC; + /* Put ndlp onto node list */ lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 0; } + /* Reset the Fabric flag, topology change may have happened */ + vport->fc_flag &= ~FC_FABRIC; if (lpfc_issue_els_flogi(vport, ndlp, 0)) { - /* This decrement of reference count to node shall kick off - * the release of the node. + /* A node reference should be retained while registered with a + * transport or dev-loss-evt work is pending. + * Otherwise, decrement node reference to trigger release. */ - lpfc_nlp_put(ndlp); + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) && + !(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + lpfc_nlp_put(ndlp); return 0; } return 1; @@ -1511,20 +1564,22 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) ndlp = lpfc_nlp_init(vport, Fabric_DID); if (!ndlp) return 0; + + /* NPIV is only supported in Fabrics. */ + ndlp->nlp_type |= NLP_FABRIC; + /* Put ndlp onto node list */ lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 0; } if (lpfc_issue_els_fdisc(vport, ndlp, 0)) { - /* decrement node reference count to trigger the release of - * the node. + /* A node reference should be retained while registered with a + * transport or dev-loss-evt work is pending. + * Otherwise, decrement node reference to trigger release. */ - lpfc_nlp_put(ndlp); + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) && + !(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + lpfc_nlp_put(ndlp); return 0; } return 1; @@ -1562,7 +1617,7 @@ lpfc_more_plogi(struct lpfc_vport *vport) } /** - * lpfc_plogi_confirm_nport - Confirm pologi wwpn matches stored ndlp + * lpfc_plogi_confirm_nport - Confirm plogi wwpn matches stored ndlp * @phba: pointer to lpfc hba data structure. * @prsp: pointer to response IOCB payload. * @ndlp: pointer to a node-list data structure. @@ -1597,19 +1652,14 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, struct lpfc_nodelist *ndlp) { struct lpfc_vport *vport = ndlp->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *new_ndlp; - struct lpfc_rport_data *rdata; - struct fc_rport *rport; struct serv_parm *sp; uint8_t name[sizeof(struct lpfc_name)]; - uint32_t rc, keepDID = 0, keep_nlp_flag = 0; + uint32_t keepDID = 0, keep_nlp_flag = 0; uint32_t keep_new_nlp_flag = 0; uint16_t keep_nlp_state; u32 keep_nlp_fc4_type = 0; struct lpfc_nvme_rport *keep_nrport = NULL; - int put_node; - int put_rport; unsigned long *active_rrqs_xri_bitmap = NULL; /* Fabric nodes can have the same WWPN so we don't bother searching @@ -1627,9 +1677,15 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName); /* return immediately if the WWPN matches ndlp */ - if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp)) + if (!new_ndlp || (new_ndlp == ndlp)) return ndlp; + /* + * Unregister from backend if not done yet. Could have been skipped + * due to ADISC + */ + lpfc_nlp_unreg_node(vport, new_ndlp); + if (phba->sli_rev == LPFC_SLI_REV4) { active_rrqs_xri_bitmap = mempool_alloc(phba->active_rrq_pool, GFP_KERNEL); @@ -1646,52 +1702,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, (new_ndlp ? new_ndlp->nlp_flag : 0), (new_ndlp ? new_ndlp->nlp_fc4_type : 0)); - if (!new_ndlp) { - rc = memcmp(&ndlp->nlp_portname, name, - sizeof(struct lpfc_name)); - if (!rc) { - if (active_rrqs_xri_bitmap) - mempool_free(active_rrqs_xri_bitmap, - phba->active_rrq_pool); - return ndlp; - } - new_ndlp = lpfc_nlp_init(vport, ndlp->nlp_DID); - if (!new_ndlp) { - if (active_rrqs_xri_bitmap) - mempool_free(active_rrqs_xri_bitmap, - phba->active_rrq_pool); - return ndlp; - } - } else if (!NLP_CHK_NODE_ACT(new_ndlp)) { - rc = memcmp(&ndlp->nlp_portname, name, - sizeof(struct lpfc_name)); - if (!rc) { - if (active_rrqs_xri_bitmap) - mempool_free(active_rrqs_xri_bitmap, - phba->active_rrq_pool); - return ndlp; - } - new_ndlp = lpfc_enable_node(vport, new_ndlp, - NLP_STE_UNUSED_NODE); - if (!new_ndlp) { - if (active_rrqs_xri_bitmap) - mempool_free(active_rrqs_xri_bitmap, - phba->active_rrq_pool); - return ndlp; - } - keepDID = new_ndlp->nlp_DID; - if ((phba->sli_rev == LPFC_SLI_REV4) && active_rrqs_xri_bitmap) - memcpy(active_rrqs_xri_bitmap, - new_ndlp->active_rrqs_xri_bitmap, - phba->cfg_rrq_xri_bitmap_sz); - } else { - keepDID = new_ndlp->nlp_DID; - if (phba->sli_rev == LPFC_SLI_REV4 && - active_rrqs_xri_bitmap) - memcpy(active_rrqs_xri_bitmap, - new_ndlp->active_rrqs_xri_bitmap, - phba->cfg_rrq_xri_bitmap_sz); - } + keepDID = new_ndlp->nlp_DID; + + if (phba->sli_rev == LPFC_SLI_REV4 && active_rrqs_xri_bitmap) + memcpy(active_rrqs_xri_bitmap, new_ndlp->active_rrqs_xri_bitmap, + phba->cfg_rrq_xri_bitmap_sz); /* At this point in this routine, we know new_ndlp will be * returned. however, any previous GID_FTs that were done @@ -1711,7 +1726,9 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, ndlp->active_rrqs_xri_bitmap, phba->cfg_rrq_xri_bitmap_sz); - spin_lock_irq(shost->host_lock); + /* Lock both ndlps */ + spin_lock_irq(&ndlp->lock); + spin_lock_irq(&new_ndlp->lock); keep_new_nlp_flag = new_ndlp->nlp_flag; keep_nlp_flag = ndlp->nlp_flag; new_ndlp->nlp_flag = ndlp->nlp_flag; @@ -1728,6 +1745,15 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, else new_ndlp->nlp_flag &= ~NLP_RPI_REGISTERED; + /* + * Retain the DROPPED flag. This will take care of the init + * refcount when affecting the state change + */ + if (keep_new_nlp_flag & NLP_DROPPED) + new_ndlp->nlp_flag |= NLP_DROPPED; + else + new_ndlp->nlp_flag &= ~NLP_DROPPED; + ndlp->nlp_flag = keep_new_nlp_flag; /* if ndlp had NLP_UNREG_INP set, keep it */ @@ -1742,7 +1768,17 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, else ndlp->nlp_flag &= ~NLP_RPI_REGISTERED; - spin_unlock_irq(shost->host_lock); + /* + * Retain the DROPPED flag. This will take care of the init + * refcount when affecting the state change + */ + if (keep_nlp_flag & NLP_DROPPED) + ndlp->nlp_flag |= NLP_DROPPED; + else + ndlp->nlp_flag &= ~NLP_DROPPED; + + spin_unlock_irq(&new_ndlp->lock); + spin_unlock_irq(&ndlp->lock); /* Set nlp_states accordingly */ keep_nlp_state = new_ndlp->nlp_state; @@ -1754,48 +1790,20 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, /* Move this back to NPR state */ if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) { - /* The new_ndlp is replacing ndlp totally, so we need - * to put ndlp on UNUSED list and try to free it. + /* The ndlp doesn't have a portname yet, but does have an + * NPort ID. The new_ndlp portname matches the Rport's + * portname. Reinstantiate the new_ndlp and reset the ndlp. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3179 PLOGI confirm NEW: %x %x\n", new_ndlp->nlp_DID, keepDID); - /* Fix up the rport accordingly */ - rport = ndlp->rport; - if (rport) { - rdata = rport->dd_data; - if (rdata->pnode == ndlp) { - /* break the link before dropping the ref */ - ndlp->rport = NULL; - lpfc_nlp_put(ndlp); - rdata->pnode = lpfc_nlp_get(new_ndlp); - new_ndlp->rport = rport; - } - new_ndlp->nlp_type = ndlp->nlp_type; - } - - /* Fix up the nvme rport */ - if (ndlp->nrport) { - ndlp->nrport = NULL; - lpfc_nlp_put(ndlp); - } - - /* We shall actually free the ndlp with both nlp_DID and - * nlp_portname fields equals 0 to avoid any ndlp on the - * nodelist never to be used. - */ - if (ndlp->nlp_DID == 0) { - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - } - /* Two ndlps cannot have the same did on the nodelist. - * Note: for this case, ndlp has a NULL WWPN so setting - * the nlp_fc4_type isn't required. + * The KeepDID and keep_nlp_fc4_type need to be swapped + * because ndlp is inflight with no WWPN. */ ndlp->nlp_DID = keepDID; + ndlp->nlp_fc4_type = keep_nlp_fc4_type; lpfc_nlp_set_state(vport, ndlp, keep_nlp_state); if (phba->sli_rev == LPFC_SLI_REV4 && active_rrqs_xri_bitmap) @@ -1803,19 +1811,15 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, active_rrqs_xri_bitmap, phba->cfg_rrq_xri_bitmap_sz); - if (!NLP_CHK_NODE_ACT(ndlp)) - lpfc_drop_node(vport, ndlp); - } - else { + } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3180 PLOGI confirm SWAP: %x %x\n", new_ndlp->nlp_DID, keepDID); lpfc_unreg_rpi(vport, ndlp); - /* Two ndlps cannot have the same did and the fc4 - * type must be transferred because the ndlp is in - * flight. + /* The ndlp and new_ndlp both have WWPNs but are swapping + * NPort Ids and attributes. */ ndlp->nlp_DID = keepDID; ndlp->nlp_fc4_type = keep_nlp_fc4_type; @@ -1833,29 +1837,16 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) keep_nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_set_state(vport, ndlp, keep_nlp_state); - - /* Previous ndlp no longer active with nvme host transport. - * Remove reference from earlier registration unless the - * nvme host took care of it. - */ - if (ndlp->nrport) - lpfc_nlp_put(ndlp); ndlp->nrport = keep_nrport; - - /* Fix up the rport accordingly */ - rport = ndlp->rport; - if (rport) { - rdata = rport->dd_data; - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); - } } + + /* + * If ndlp is not associated with any rport we can drop it here else + * let dev_loss_tmo_callbk trigger DEVICE_RM event + */ + if (!ndlp->rport && (ndlp->nlp_state == NLP_STE_NPR_NODE)) + lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); + if (phba->sli_rev == LPFC_SLI_REV4 && active_rrqs_xri_bitmap) mempool_free(active_rrqs_xri_bitmap, @@ -1915,57 +1906,48 @@ lpfc_end_rscn(struct lpfc_vport *vport) static void lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) + struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - IOCB_t *irsp; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; struct lpfc_node_rrq *rrq; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); /* we pass cmdiocb to state machine which needs rspiocb as well */ rrq = cmdiocb->context_un.rrq; - cmdiocb->context_un.rsp_iocb = rspiocb; + cmdiocb->rsp_iocb = rspiocb; - irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "RRQ cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->un.elsreq64.remoteID); + ulp_status, ulp_word4, + get_job_els_rsp64_did(phba, cmdiocb)); - ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ndlp != rrq->ndlp) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2882 RRQ completes to NPort x%x " - "with no ndlp. Data: x%x x%x x%x\n", - irsp->un.elsreq64.remoteID, - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpIoTag); - goto out; - } /* rrq completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "2880 RRQ completes to NPort x%x " + "2880 RRQ completes to DID x%x " "Data: x%x x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, rrq->xritag, rrq->rxid); + ndlp->nlp_DID, ulp_status, ulp_word4, + get_wqe_tmo(cmdiocb), rrq->xritag, rrq->rxid); - if (irsp->ulpStatus) { + if (ulp_status) { /* Check for retry */ /* RRQ failed Don't print the vport to vport rjts */ - if (irsp->ulpStatus != IOSTAT_LS_RJT || - (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) && - ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) || - (phba)->pport->cfg_log_verbose & LOG_ELS) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2881 RRQ failure DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); - } -out: - if (rrq) - lpfc_clr_rrq_active(phba, rrq->xritag, rrq); + if (ulp_status != IOSTAT_LS_RJT || + (((ulp_word4) >> 16 != LSRJT_INVALID_CMD) && + ((ulp_word4) >> 16 != LSRJT_UNABLE_TPC)) || + (phba)->pport->cfg_log_verbose & LOG_ELS) + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2881 RRQ failure DID:%06X Status:" + "x%x/x%x\n", + ndlp->nlp_DID, ulp_status, + ulp_word4); + } + + lpfc_clr_rrq_active(phba, rrq->xritag, rrq); lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } /** @@ -1979,7 +1961,7 @@ out: * ndlp on the vport node list that matches the remote node ID from the * PLOGI response IOCB. If such ndlp does not exist, the PLOGI is simply * ignored and command IOCB released. The PLOGI response IOCB status is - * checked for error conditons. If there is error status reported, PLOGI + * checked for error conditions. If there is error status reported, PLOGI * retry shall be attempted by invoking the lpfc_els_retry() routine. * Otherwise, the lpfc_plogi_confirm_nport() routine shall be invoked on * the ndlp and the NLP_EVT_CMPL_PLOGI state to the Discover State Machine @@ -1995,86 +1977,139 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp, *free_ndlp; struct lpfc_dmabuf *prsp; int disc; + struct serv_parm *sp = NULL; + u32 ulp_status, ulp_word4, did, iotag; + bool release_node = false; /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; + cmdiocb->rsp_iocb = rspiocb; + + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); + did = get_job_els_rsp64_did(phba, cmdiocb); + + if (phba->sli_rev == LPFC_SLI_REV4) { + iotag = get_wqe_reqtag(cmdiocb); + } else { + irsp = &rspiocb->iocb; + iotag = irsp->ulpIoTag; + } - irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "PLOGI cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->un.elsreq64.remoteID); + ulp_status, ulp_word4, did); - ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + ndlp = lpfc_findnode_did(vport, did); + if (!ndlp) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0136 PLOGI completes to NPort x%x " "with no ndlp. Data: x%x x%x x%x\n", - irsp->un.elsreq64.remoteID, - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpIoTag); - goto out; + did, ulp_status, ulp_word4, iotag); + goto out_freeiocb; } /* Since ndlp can be freed in the disc state machine, note if this node * is being used during discovery. */ - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* PLOGI completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0102 PLOGI completes to NPort x%06x " "Data: x%x x%x x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_fc4_type, - irsp->ulpStatus, irsp->un.ulpWord[4], + ulp_status, ulp_word4, disc, vport->num_disc_nodes); /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); goto out; } - if (irsp->ulpStatus) { + if (ulp_status) { /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ if (disc) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } goto out; } /* PLOGI failed Don't print the vport to vport rjts */ - if (irsp->ulpStatus != IOSTAT_LS_RJT || - (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) && - ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) || - (phba)->pport->cfg_log_verbose & LOG_ELS) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2753 PLOGI failure DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); + if (ulp_status != IOSTAT_LS_RJT || + (((ulp_word4) >> 16 != LSRJT_INVALID_CMD) && + ((ulp_word4) >> 16 != LSRJT_UNABLE_TPC)) || + (phba)->pport->cfg_log_verbose & LOG_ELS) + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2753 PLOGI failure DID:%06X " + "Status:x%x/x%x\n", + ndlp->nlp_DID, ulp_status, + ulp_word4); + /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (!lpfc_error_lost_link(irsp)) + if (!lpfc_error_lost_link(ulp_status, ulp_word4)) lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_PLOGI); + + /* If a PLOGI collision occurred, the node needs to continue + * with the reglogin process. + */ + spin_lock_irq(&ndlp->lock); + if ((ndlp->nlp_flag & (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI)) && + ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE) { + spin_unlock_irq(&ndlp->lock); + goto out; + } + + /* No PLOGI collision and the node is not registered with the + * scsi or nvme transport. It is no longer an active node. Just + * start the device remove process. + */ + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + release_node = true; + } + spin_unlock_irq(&ndlp->lock); + + if (release_node) + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_DEVICE_RM); } else { /* Good status, call state machine */ - prsp = list_entry(((struct lpfc_dmabuf *) - cmdiocb->context2)->list.next, + prsp = list_entry(cmdiocb->cmd_dmabuf->list.next, struct lpfc_dmabuf, list); ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp); + + sp = (struct serv_parm *)((u8 *)prsp->virt + + sizeof(u32)); + + ndlp->vmid_support = 0; + if ((phba->cfg_vmid_app_header && sp->cmn.app_hdr_support) || + (phba->cfg_vmid_priority_tagging && + sp->cmn.priority_tagging)) { + lpfc_printf_log(phba, KERN_DEBUG, LOG_ELS, + "4018 app_hdr_support %d tagging %d DID x%x\n", + sp->cmn.app_hdr_support, + sp->cmn.priority_tagging, + ndlp->nlp_DID); + /* if the dest port supports VMID, mark it in ndlp */ + ndlp->vmid_support = 1; + } + lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_PLOGI); + NLP_EVT_CMPL_PLOGI); } if (disc && vport->num_disc_nodes) { @@ -2092,7 +2127,16 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } out: + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, + "PLOGI Cmpl PUT: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + +out_freeiocb: + /* Release the reference on the original I/O request. */ + free_ndlp = cmdiocb->ndlp; + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); return; } @@ -2105,13 +2149,12 @@ out: * This routine issues a Port Login (PLOGI) command to a remote N_Port * (with the @did) for a @vport. Before issuing a PLOGI to a remote N_Port, * the ndlp with the remote N_Port DID must exist on the @vport's ndlp list. - * This routine constructs the proper feilds of the PLOGI IOCB and invokes + * This routine constructs the proper fields of the PLOGI IOCB and invokes * the lpfc_sli_issue_iocb() routine to send out PLOGI ELS command. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the PLOGI ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding + * the ndlp and the reference to ndlp will be stored into the ndlp field + * of the IOCB for the completion callback function to the PLOGI ELS command. * * Return code * 0 - Successfully issued a plogi for @vport @@ -2121,7 +2164,6 @@ int lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) { struct lpfc_hba *phba = vport->phba; - struct Scsi_Host *shost; struct serv_parm *sp; struct lpfc_nodelist *ndlp; struct lpfc_iocbq *elsiocb; @@ -2130,43 +2172,35 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) int ret; ndlp = lpfc_findnode_did(vport, did); + if (!ndlp) + return 1; - if (ndlp) { - /* Defer the processing of the issue PLOGI until after the - * outstanding UNREG_RPI mbox command completes, unless we - * are going offline. This logic does not apply for Fabric DIDs - */ - if ((ndlp->nlp_flag & NLP_UNREG_INP) && - ((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && - !(vport->fc_flag & FC_OFFLINE_MODE)) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "4110 Issue PLOGI x%x deferred " - "on NPort x%x rpi x%x Data: x%px\n", - ndlp->nlp_defer_did, ndlp->nlp_DID, - ndlp->nlp_rpi, ndlp); - - /* We can only defer 1st PLOGI */ - if (ndlp->nlp_defer_did == NLP_EVT_NOTHING_PENDING) - ndlp->nlp_defer_did = did; - return 0; - } - if (!NLP_CHK_NODE_ACT(ndlp)) - ndlp = NULL; + /* Defer the processing of the issue PLOGI until after the + * outstanding UNREG_RPI mbox command completes, unless we + * are going offline. This logic does not apply for Fabric DIDs + */ + if ((ndlp->nlp_flag & NLP_UNREG_INP) && + ((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && + !(vport->fc_flag & FC_OFFLINE_MODE)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "4110 Issue PLOGI x%x deferred " + "on NPort x%x rpi x%x Data: x%px\n", + ndlp->nlp_defer_did, ndlp->nlp_DID, + ndlp->nlp_rpi, ndlp); + + /* We can only defer 1st PLOGI */ + if (ndlp->nlp_defer_did == NLP_EVT_NOTHING_PENDING) + ndlp->nlp_defer_did = did; + return 0; } - /* If ndlp is not NULL, we will bump the reference count on it */ cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, ELS_CMD_PLOGI); if (!elsiocb) return 1; - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_FCP_PRLI_RJT; - spin_unlock_irq(shost->host_lock); - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; /* For PLOGI request, remainder of payload is service parameters */ *((uint32_t *) (pcmd)) = ELS_CMD_PLOGI; @@ -2191,6 +2225,14 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion)); sp->cmn.bbRcvSizeMsb &= 0xF; + /* Check if the destination port supports VMID */ + ndlp->vmid_support = 0; + if (vport->vmid_priority_tagging) + sp->cmn.priority_tagging = 1; + else if (phba->cfg_vmid_app_header && + bf_get(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags)) + sp->cmn.app_hdr_support = 1; + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue PLOGI: did:x%x", did, 0, 0); @@ -2205,13 +2247,24 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) } phba->fc_stat.elsXmitPLOGI++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi; - ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + elsiocb->cmd_cmpl = lpfc_cmpl_els_plogi; - if (ret == IOCB_ERROR) { + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue PLOGI: did:x%x refcnt %d", + did, kref_read(&ndlp->kref), 0); + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); return 1; } + + ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (ret) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + return 1; + } + return 0; } @@ -2233,41 +2286,46 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp; struct lpfc_nodelist *ndlp; char *mode; + u32 loglevel; + u32 ulp_status; + u32 ulp_word4; + bool release_node = false; /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; + cmdiocb->rsp_iocb = rspiocb; - irsp = &(rspiocb->iocb); - ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - spin_lock_irq(shost->host_lock); + ndlp = cmdiocb->ndlp; + + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); + + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_PRLI_SND; /* Driver supports multiple FC4 types. Counters matter. */ vport->fc_prli_sent--; ndlp->fc4_prli_sent--; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "PRLI cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], + ulp_status, ulp_word4, ndlp->nlp_DID); /* PRLI completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0103 PRLI completes to NPort x%06x " "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], + ndlp->nlp_DID, ulp_status, ulp_word4, vport->num_disc_nodes, ndlp->fc4_prli_sent); /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) goto out; - if (irsp->ulpStatus) { + if (ulp_status) { /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ @@ -2278,24 +2336,50 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * could be expected. */ if ((vport->fc_flag & FC_FABRIC) || - (vport->cfg_enable_fc4_type != LPFC_ENABLE_BOTH)) + (vport->cfg_enable_fc4_type != LPFC_ENABLE_BOTH)) { mode = KERN_ERR; - else + loglevel = LOG_TRACE_EVENT; + } else { mode = KERN_INFO; + loglevel = LOG_ELS; + } /* PRLI failed */ - lpfc_printf_vlog(vport, mode, LOG_ELS, + lpfc_printf_vlog(vport, mode, loglevel, "2754 PRLI failure DID:%06X Status:x%x/x%x, " "data: x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4], ndlp->fc4_prli_sent); + ndlp->nlp_DID, ulp_status, + ulp_word4, ndlp->fc4_prli_sent); /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (lpfc_error_lost_link(irsp)) - goto out; - else + if (!lpfc_error_lost_link(ulp_status, ulp_word4)) lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI); + + /* + * For P2P topology, retain the node so that PLOGI can be + * attempted on it again. + */ + if (vport->fc_flag & FC_PT2PT) + goto out; + + /* As long as this node is not registered with the SCSI + * or NVMe transport and no other PRLIs are outstanding, + * it is no longer an active node. Otherwise devloss + * handles the final cleanup. + */ + spin_lock_irq(&ndlp->lock); + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) && + !ndlp->fc4_prli_sent) { + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + release_node = true; + } + spin_unlock_irq(&ndlp->lock); + + if (release_node) + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_DEVICE_RM); } else { /* Good status, call state machine. However, if another * PRLI is outstanding, don't call the state machine @@ -2308,6 +2392,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, out: lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -2323,10 +2408,9 @@ out: * is put to the IOCB completion callback func field before invoking the * routine lpfc_sli_issue_iocb() to send out PRLI command. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the PRLI ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the PRLI ELS command. * * Return code * 0 - successfully issued prli iocb command for @vport @@ -2336,7 +2420,7 @@ int lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + int rc = 0; struct lpfc_hba *phba = vport->phba; PRLI *npr; struct lpfc_nvme_prli *npr_nvme; @@ -2399,7 +2483,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; /* For PRLI request, remainder of payload is service parameters */ memset(pcmd, 0, cmdsize); @@ -2431,7 +2515,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* For FCP support */ npr->prliType = PRLI_FCP_TYPE; npr->initiatorFunc = 1; - elsiocb->iocb_flag |= LPFC_PRLI_FCP_REQ; + elsiocb->cmd_flag |= LPFC_PRLI_FCP_REQ; /* Remove FCP type - processed. */ local_nlp_type &= ~NLP_FC4_FCP; @@ -2465,37 +2549,40 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, npr_nvme->word1 = cpu_to_be32(npr_nvme->word1); npr_nvme->word4 = cpu_to_be32(npr_nvme->word4); - elsiocb->iocb_flag |= LPFC_PRLI_NVME_REQ; + elsiocb->cmd_flag |= LPFC_PRLI_NVME_REQ; /* Remove NVME type - processed. */ local_nlp_type &= ~NLP_FC4_NVME; } + phba->fc_stat.elsXmitPRLI++; + elsiocb->cmd_cmpl = lpfc_cmpl_els_prli; + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue PRLI: did:x%x", - ndlp->nlp_DID, 0, 0); + "Issue PRLI: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } - phba->fc_stat.elsXmitPRLI++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_prli; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_PRLI_SND; + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + return 1; + } /* The vport counters are used for lpfc_scan_finished, but * the ndlp is used to track outstanding PRLIs for different * FC4 types. */ + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag |= NLP_PRLI_SND; vport->fc_prli_sent++; ndlp->fc4_prli_sent++; - spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_PRLI_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - + spin_unlock_irq(&ndlp->lock); /* The driver supports 2 FC4 types. Make sure * a PRLI is issued for all types before exiting. @@ -2503,8 +2590,8 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (phba->sli_rev == LPFC_SLI_REV4 && local_nlp_type & (NLP_FC4_FCP | NLP_FC4_NVME)) goto send_next_prli; - - return 0; + else + return 0; } /** @@ -2556,6 +2643,14 @@ lpfc_adisc_done(struct lpfc_vport *vport) if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && !(vport->fc_flag & FC_RSCN_MODE) && (phba->sli_rev < LPFC_SLI_REV4)) { + + /* + * If link is down, clear_la and reg_vpi will be done after + * flogi following a link up event + */ + if (!lpfc_is_link_up(phba)) + return; + /* The ADISCs are complete. Doesn't matter if they * succeeded or failed because the ADISC completion * routine guarantees to call the state machine and @@ -2645,64 +2740,88 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; struct lpfc_nodelist *ndlp; int disc; + u32 ulp_status, ulp_word4, tmo; + bool release_node = false; /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; + cmdiocb->rsp_iocb = rspiocb; + + ndlp = cmdiocb->ndlp; + + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); - irsp = &(rspiocb->iocb); - ndlp = (struct lpfc_nodelist *) cmdiocb->context1; + if (phba->sli_rev == LPFC_SLI_REV4) { + tmo = get_wqe_tmo(cmdiocb); + } else { + irsp = &rspiocb->iocb; + tmo = irsp->ulpTimeout; + } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "ADISC cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], + ulp_status, ulp_word4, ndlp->nlp_DID); /* Since ndlp can be freed in the disc state machine, note if this node * is being used during discovery. */ - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* ADISC completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0104 ADISC completes to NPort x%x " "Data: x%x x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, disc, vport->num_disc_nodes); + ndlp->nlp_DID, ulp_status, ulp_word4, + tmo, disc, vport->num_disc_nodes); /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); goto out; } - if (irsp->ulpStatus) { + if (ulp_status) { /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ if (disc) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_set_disctmo(vport); } goto out; } /* ADISC failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2755 ADISC failure DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); - /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (!lpfc_error_lost_link(irsp)) + ndlp->nlp_DID, ulp_status, + ulp_word4); + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_CMPL_ADISC); + + /* As long as this node is not registered with the SCSI or NVMe + * transport, it is no longer an active node. Otherwise + * devloss handles the final cleanup. + */ + spin_lock_irq(&ndlp->lock); + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + release_node = true; + } + spin_unlock_irq(&ndlp->lock); + + if (release_node) lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_ADISC); + NLP_EVT_DEVICE_RM); } else /* Good status, call state machine */ lpfc_disc_state_machine(vport, ndlp, cmdiocb, @@ -2713,6 +2832,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_more_adisc(vport); out: lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -2727,10 +2847,9 @@ out: * and states of the ndlp, and invokes the lpfc_sli_issue_iocb() routine * to issue the ADISC ELS command. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the ADISC ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the ADISC ELS command. * * Return code * 0 - successfully issued adisc @@ -2740,7 +2859,7 @@ int lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + int rc = 0; struct lpfc_hba *phba = vport->phba; ADISC *ap; struct lpfc_iocbq *elsiocb; @@ -2753,7 +2872,7 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; /* For ADISC request, remainder of payload is service parameters */ *((uint32_t *) (pcmd)) = ELS_CMD_ADISC; @@ -2766,24 +2885,35 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); ap->DID = be32_to_cpu(vport->fc_myDID); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue ADISC: did:x%x", - ndlp->nlp_DID, 0, 0); - phba->fc_stat.elsXmitADISC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc; - spin_lock_irq(shost->host_lock); + elsiocb->cmd_cmpl = lpfc_cmpl_els_adisc; + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_ADISC_SND; - spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_ADISC_SND; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); - return 1; + goto err; } + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue ADISC: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + goto err; + } + return 0; + +err: + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_ADISC_SND; + spin_unlock_irq(&ndlp->lock); + return 1; } /** @@ -2795,70 +2925,75 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * This routine is the completion function for issuing the ELS Logout (LOGO) * command. If no error status was reported from the LOGO response, the * state machine of the associated ndlp shall be invoked for transition with - * respect to NLP_EVT_CMPL_LOGO event. Otherwise, if error status was reported, - * the lpfc_els_retry() routine will be invoked to retry the LOGO command. + * respect to NLP_EVT_CMPL_LOGO event. **/ static void lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; struct lpfc_vport *vport = ndlp->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfcMboxq *mbox; unsigned long flags; uint32_t skip_recovery = 0; + int wake_up_waiter = 0; + u32 ulp_status; + u32 ulp_word4; + u32 tmo; /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; + cmdiocb->rsp_iocb = rspiocb; - irsp = &(rspiocb->iocb); - spin_lock_irq(shost->host_lock); + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); + + if (phba->sli_rev == LPFC_SLI_REV4) { + tmo = get_wqe_tmo(cmdiocb); + } else { + irsp = &rspiocb->iocb; + tmo = irsp->ulpTimeout; + } + + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); + if (ndlp->save_flags & NLP_WAIT_FOR_LOGO) { + wake_up_waiter = 1; + ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO; + } + spin_unlock_irq(&ndlp->lock); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "LOGO cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], + ulp_status, ulp_word4, ndlp->nlp_DID); /* LOGO completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0105 LOGO completes to NPort x%x " - "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, vport->num_disc_nodes); + "refcnt %d nflags x%x Data: x%x x%x x%x x%x\n", + ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag, + ulp_status, ulp_word4, + tmo, vport->num_disc_nodes); if (lpfc_els_chk_latt(vport)) { skip_recovery = 1; goto out; } - /* Check to see if link went down during discovery */ - if (ndlp->nlp_flag & NLP_TARGET_REMOVE) { - /* NLP_EVT_DEVICE_RM should unregister the RPI - * which should abort all outstanding IOs. - */ - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_DEVICE_RM); - skip_recovery = 1; - goto out; - } - /* The LOGO will not be retried on failure. A LOGO was * issued to the remote rport and a ACC or RJT or no Answer are * all acceptable. Note the failure and move forward with * discovery. The PLOGI will retry. */ - if (irsp->ulpStatus) { + if (ulp_status) { /* LOGO failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2756 LOGO failure, No Retry DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); - /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (lpfc_error_lost_link(irsp)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2756 LOGO failure, No Retry DID:%06X " + "Status:x%x/x%x\n", + ndlp->nlp_DID, ulp_status, + ulp_word4); + + if (lpfc_error_lost_link(ulp_status, ulp_word4)) { skip_recovery = 1; goto out; } @@ -2867,34 +3002,29 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Call state machine. This will unregister the rpi if needed. */ lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO); -out: - lpfc_els_free_iocb(phba, cmdiocb); - /* If we are in pt2pt mode, we could rcv new S_ID on PLOGI */ - if ((vport->fc_flag & FC_PT2PT) && - !(vport->fc_flag & FC_PT2PT_PLOGI)) { - phba->pport->fc_myDID = 0; - - if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || - (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) { - if (phba->nvmet_support) - lpfc_nvmet_update_targetport(phba); - else - lpfc_nvme_update_localport(phba->pport); - } - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox) { - lpfc_config_link(phba, mbox); - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == - MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - skip_recovery = 1; - } - } + /* The driver sets this flag for an NPIV instance that doesn't want to + * log into the remote port. + */ + if (ndlp->nlp_flag & NLP_TARGET_REMOVE) { + spin_lock_irq(&ndlp->lock); + if (phba->sli_rev == LPFC_SLI_REV4) + ndlp->nlp_flag |= NLP_RELEASE_RPI; + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(&ndlp->lock); + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_DEVICE_RM); + goto out_rsrc_free; } +out: + /* At this point, the LOGO processing is complete. NOTE: For a + * pt2pt topology, we are assuming the NPortID will only change + * on link up processing. For a LOGO / PLOGI initiated by the + * Initiator, we are assuming the NPortID is not going to change. + */ + + if (wake_up_waiter && ndlp->logo_waitq) + wake_up(ndlp->logo_waitq); /* * If the node is a target, the handling attempts to recover the port. * For any other port type, the rpi is unregistered as an implicit @@ -2903,19 +3033,40 @@ out: if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET) && skip_recovery == 0) { lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irqsave(shost->host_lock, flags); + spin_lock_irqsave(&ndlp->lock, flags); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irqrestore(shost->host_lock, flags); + spin_unlock_irqrestore(&ndlp->lock, flags); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3187 LOGO completes to NPort x%x: Start " "Recovery Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4], irsp->ulpTimeout, + ndlp->nlp_DID, ulp_status, + ulp_word4, tmo, vport->num_disc_nodes); + + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); + lpfc_disc_start(vport); + return; } - return; + + /* Cleanup path for failed REG_RPI handling. If REG_RPI fails, the + * driver sends a LOGO to the rport to cleanup. For fabric and + * initiator ports cleanup the node as long as it the node is not + * register with the transport. + */ + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(&ndlp->lock); + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_DEVICE_RM); + } +out_rsrc_free: + /* Driver is done with the I/O. */ + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } /** @@ -2929,10 +3080,9 @@ out: * payload of the IOCB, properly sets up the @ndlp state, and invokes the * lpfc_sli_issue_iocb() routine to send out the LOGO ELS command. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the LOGO ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the LOGO ELS command. * * Callers of this routine are expected to unregister the RPI first * @@ -2944,19 +3094,18 @@ int lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; int rc; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); if (ndlp->nlp_flag & NLP_LOGO_SND) { - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return 0; } - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, @@ -2964,7 +3113,7 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; pcmd += sizeof(uint32_t); @@ -2973,30 +3122,40 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, pcmd += sizeof(uint32_t); memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name)); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue LOGO: did:x%x", - ndlp->nlp_DID, 0, 0); - phba->fc_stat.elsXmitLOGO++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_logo; - spin_lock_irq(shost->host_lock); + elsiocb->cmd_cmpl = lpfc_cmpl_els_logo; + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_SND; ndlp->nlp_flag &= ~NLP_ISSUE_LOGO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + goto err; + } + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue LOGO: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); lpfc_els_free_iocb(phba, elsiocb); - return 1; + lpfc_nlp_put(ndlp); + goto err; } - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_prev_state = ndlp->nlp_state; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_nlp_set_state(vport, ndlp, NLP_STE_LOGO_ISSUE); return 0; + +err: + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_LOGO_SND; + spin_unlock_irq(&ndlp->lock); + return 1; } /** @@ -3008,10 +3167,9 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * This routine is a generic completion callback function for ELS commands. * Specifically, it is the callback function which does not need to perform * any command specific operations. It is currently used by the ELS command - * issuing routines for the ELS State Change Request (SCR), - * lpfc_issue_els_scr(), and the ELS Fibre Channel Address Resolution - * Protocol Response (FARPR) routine, lpfc_issue_els_farpr(). Other than - * certain debug loggings, this callback function simply invokes the + * issuing routines for RSCN, lpfc_issue_els_rscn, and the ELS Fibre Channel + * Address Resolution Protocol Response (FARPR) routine, lpfc_issue_els_farpr(). + * Other than certain debug loggings, this callback function simply invokes the * lpfc_els_chk_latt() routine to check whether link went down during the * discovery process. **/ @@ -3020,50 +3178,270 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; + struct lpfc_nodelist *free_ndlp; IOCB_t *irsp; + u32 ulp_status, ulp_word4, tmo, did, iotag; + + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); + did = get_job_els_rsp64_did(phba, cmdiocb); - irsp = &rspiocb->iocb; + if (phba->sli_rev == LPFC_SLI_REV4) { + tmo = get_wqe_tmo(cmdiocb); + iotag = get_wqe_reqtag(cmdiocb); + } else { + irsp = &rspiocb->iocb; + tmo = irsp->ulpTimeout; + iotag = irsp->ulpIoTag; + } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "ELS cmd cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->un.elsreq64.remoteID); + "ELS cmd cmpl: status:x%x/x%x did:x%x", + ulp_status, ulp_word4, did); + /* ELS cmd tag <ulpIoTag> completes */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n", - irsp->ulpIoTag, irsp->ulpStatus, - irsp->un.ulpWord[4], irsp->ulpTimeout); + iotag, ulp_status, ulp_word4, tmo); + /* Check to see if link went down during discovery */ lpfc_els_chk_latt(vport); + + free_ndlp = cmdiocb->ndlp; + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); +} + +/** + * lpfc_reg_fab_ctrl_node - RPI register the fabric controller node. + * @vport: pointer to lpfc_vport data structure. + * @fc_ndlp: pointer to the fabric controller (0xfffffd) node. + * + * This routine registers the rpi assigned to the fabric controller + * NPort_ID (0xfffffd) with the port and moves the node to UNMAPPED + * state triggering a registration with the SCSI transport. + * + * This routine is single out because the fabric controller node + * does not receive a PLOGI. This routine is consumed by the + * SCR and RDF ELS commands. Callers are expected to qualify + * with SLI4 first. + **/ +static int +lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) +{ + int rc = 0; + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ns_ndlp; + LPFC_MBOXQ_t *mbox; + + if (fc_ndlp->nlp_flag & NLP_RPI_REGISTERED) + return rc; + + ns_ndlp = lpfc_findnode_did(vport, NameServer_DID); + if (!ns_ndlp) + return -ENODEV; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "0935 %s: Reg FC RPI x%x on FC DID x%x NSSte: x%x\n", + __func__, fc_ndlp->nlp_rpi, fc_ndlp->nlp_DID, + ns_ndlp->nlp_state); + if (ns_ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) + return -ENODEV; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, + "0936 %s: no memory for reg_login " + "Data: x%x x%x x%x x%x\n", __func__, + fc_ndlp->nlp_DID, fc_ndlp->nlp_state, + fc_ndlp->nlp_flag, fc_ndlp->nlp_rpi); + return -ENOMEM; + } + rc = lpfc_reg_rpi(phba, vport->vpi, fc_ndlp->nlp_DID, + (u8 *)&vport->fc_sparam, mbox, fc_ndlp->nlp_rpi); + if (rc) { + rc = -EACCES; + goto out; + } + + fc_ndlp->nlp_flag |= NLP_REG_LOGIN_SEND; + mbox->mbox_cmpl = lpfc_mbx_cmpl_fc_reg_login; + mbox->ctx_ndlp = lpfc_nlp_get(fc_ndlp); + if (!mbox->ctx_ndlp) { + rc = -ENOMEM; + goto out; + } + + mbox->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + rc = -ENODEV; + lpfc_nlp_put(fc_ndlp); + goto out; + } + /* Success path. Exit. */ + lpfc_nlp_set_state(vport, fc_ndlp, + NLP_STE_REG_LOGIN_ISSUE); + return 0; + + out: + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); + lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, + "0938 %s: failed to format reg_login " + "Data: x%x x%x x%x x%x\n", __func__, + fc_ndlp->nlp_DID, fc_ndlp->nlp_state, + fc_ndlp->nlp_flag, fc_ndlp->nlp_rpi); + return rc; +} + +/** + * lpfc_cmpl_els_disc_cmd - Completion callback function for Discovery ELS cmd + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @rspiocb: pointer to lpfc response iocb data structure. + * + * This routine is a generic completion callback function for Discovery ELS cmd. + * Currently used by the ELS command issuing routines for the ELS State Change + * Request (SCR), lpfc_issue_els_scr() and the ELS RDF, lpfc_issue_els_rdf(). + * These commands will be retried once only for ELS timeout errors. + **/ +static void +lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + IOCB_t *irsp; + struct lpfc_els_rdf_rsp *prdf; + struct lpfc_dmabuf *pcmd, *prsp; + u32 *pdata; + u32 cmd; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; + u32 ulp_status, ulp_word4, tmo, did, iotag; + + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); + did = get_job_els_rsp64_did(phba, cmdiocb); + + if (phba->sli_rev == LPFC_SLI_REV4) { + tmo = get_wqe_tmo(cmdiocb); + iotag = get_wqe_reqtag(cmdiocb); + } else { + irsp = &rspiocb->iocb; + tmo = irsp->ulpTimeout; + iotag = irsp->ulpIoTag; + } + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "ELS cmd cmpl: status:x%x/x%x did:x%x", + ulp_status, ulp_word4, did); + + /* ELS cmd tag <ulpIoTag> completes */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "0217 ELS cmd tag x%x completes Data: x%x x%x x%x x%x\n", + iotag, ulp_status, ulp_word4, tmo, cmdiocb->retry); + + pcmd = cmdiocb->cmd_dmabuf; + if (!pcmd) + goto out; + + pdata = (u32 *)pcmd->virt; + if (!pdata) + goto out; + cmd = *pdata; + + /* Only 1 retry for ELS Timeout only */ + if (ulp_status == IOSTAT_LOCAL_REJECT && + ((ulp_word4 & IOERR_PARAM_MASK) == + IOERR_SEQUENCE_TIMEOUT)) { + cmdiocb->retry++; + if (cmdiocb->retry <= 1) { + switch (cmd) { + case ELS_CMD_SCR: + lpfc_issue_els_scr(vport, cmdiocb->retry); + break; + case ELS_CMD_EDC: + lpfc_issue_els_edc(vport, cmdiocb->retry); + break; + case ELS_CMD_RDF: + lpfc_issue_els_rdf(vport, cmdiocb->retry); + break; + } + goto out; + } + phba->fc_stat.elsRetryExceeded++; + } + if (cmd == ELS_CMD_EDC) { + /* must be called before checking uplStatus and returning */ + lpfc_cmpl_els_edc(phba, cmdiocb, rspiocb); + return; + } + if (ulp_status) { + /* ELS discovery cmd completes with error */ + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS | LOG_CGN_MGMT, + "4203 ELS cmd x%x error: x%x x%X\n", cmd, + ulp_status, ulp_word4); + goto out; + } + + /* The RDF response doesn't have any impact on the running driver + * but the notification descriptors are dumped here for support. + */ + if (cmd == ELS_CMD_RDF) { + int i; + + prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); + if (!prsp) + goto out; + + prdf = (struct lpfc_els_rdf_rsp *)prsp->virt; + if (!prdf) + goto out; + + for (i = 0; i < ELS_RDF_REG_TAG_CNT && + i < be32_to_cpu(prdf->reg_d1.reg_desc.count); i++) + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_CGN_MGMT, + "4677 Fabric RDF Notification Grant " + "Data: 0x%08x Reg: %x %x\n", + be32_to_cpu( + prdf->reg_d1.desc_tags[i]), + phba->cgn_reg_signal, + phba->cgn_reg_fpin); + } + +out: + /* Check to see if link went down during discovery */ + lpfc_els_chk_latt(vport); + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } /** * lpfc_issue_els_scr - Issue a scr to an node on a vport * @vport: pointer to a host virtual N_Port data structure. - * @nportid: N_Port identifier to the remote node. - * @retry: number of retries to the command IOCB. + * @retry: retry counter for the command IOCB. * * This routine issues a State Change Request (SCR) to a fabric node - * on a @vport. The remote node @nportid is passed into the function. It + * on a @vport. The remote node is Fabric Controller (0xfffffd). It * first search the @vport node list to find the matching ndlp. If no such * ndlp is found, a new ndlp shall be created for this (SCR) purpose. An * IOCB is allocated, payload prepared, and the lpfc_sli_issue_iocb() * routine is invoked to send the SCR IOCB. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the SCR ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the SCR ELS command. * * Return code * 0 - Successfully issued scr command * 1 - Failed to issue scr command **/ int -lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) +lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) { + int rc = 0; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; @@ -3072,30 +3450,30 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) cmdsize = (sizeof(uint32_t) + sizeof(SCR)); - ndlp = lpfc_findnode_did(vport, nportid); + ndlp = lpfc_findnode_did(vport, Fabric_Cntl_DID); if (!ndlp) { - ndlp = lpfc_nlp_init(vport, nportid); + ndlp = lpfc_nlp_init(vport, Fabric_Cntl_DID); if (!ndlp) return 1; lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 1; } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_SCR); - - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); + if (!elsiocb) return 1; - } - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + if (phba->sli_rev == LPFC_SLI_REV4) { + rc = lpfc_reg_fab_ctrl_node(vport, ndlp); + if (rc) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, + "0937 %s: Failed to reg fc node, rc %d\n", + __func__, rc); + return 1; + } + } + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_SCR; pcmd += sizeof(uint32_t); @@ -3109,22 +3487,24 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) ndlp->nlp_DID, 0, 0); phba->fc_stat.elsXmitSCR++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the rlease of - * the node. - */ - lpfc_nlp_put(ndlp); + elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); return 1; } - /* This will cause the callback-function lpfc_cmpl_els_cmd to - * trigger the release of node. - */ - if (!(vport->fc_flag & FC_PT2PT)) + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue SCR: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); lpfc_nlp_put(ndlp); + return 1; + } + return 0; } @@ -3139,10 +3519,9 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) * in point-to-point mode. When sent to the Fabric Controller, it will * replay the RSCN to registered recipients. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RSCN ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the RSCN ELS command. * * Return code * 0 - Successfully issued RSCN command @@ -3151,6 +3530,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) { + int rc = 0; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; struct lpfc_nodelist *ndlp; @@ -3181,26 +3561,16 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) if (!ndlp) return 1; lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - return 1; } } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_RSCN_XMT); - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); + if (!elsiocb) return 1; - } - event = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; + event = elsiocb->cmd_dmabuf->virt; event->rscn.rscn_cmd = ELS_RSCN; event->rscn.rscn_page_len = sizeof(struct fc_els_rscn_page); @@ -3213,27 +3583,24 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) event->portid.rscn_fid[1] = (nportid & 0x0000FF00) >> 8; event->portid.rscn_fid[2] = nportid & 0x000000FF; + phba->fc_stat.elsXmitRSCN++; + elsiocb->cmd_cmpl = lpfc_cmpl_els_cmd; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue RSCN: did:x%x", ndlp->nlp_DID, 0, 0); - phba->fc_stat.elsXmitRSCN++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the rlease of - * the node. - */ - lpfc_nlp_put(ndlp); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); return 1; } - /* This will cause the callback-function lpfc_cmpl_els_cmd to - * trigger the release of node. - */ - if (!(vport->fc_flag & FC_PT2PT)) - lpfc_nlp_put(ndlp); return 0; } @@ -3251,10 +3618,9 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) * for this (FARPR) purpose. An IOCB is allocated, payload prepared, and the * lpfc_sli_issue_iocb() routine is invoked to send the FARPR ELS command. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the PARPR ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the FARPR ELS command. * * Return code * 0 - Successfully issued farpr command @@ -3263,6 +3629,7 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) static int lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) { + int rc = 0; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; FARP *fp; @@ -3280,23 +3647,14 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) if (!ndlp) return 1; lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 1; } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, - ndlp->nlp_DID, ELS_CMD_RNID); - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); + ndlp->nlp_DID, ELS_CMD_FARPR); + if (!elsiocb) return 1; - } - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_FARPR; pcmd += sizeof(uint32_t); @@ -3313,7 +3671,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name)); memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); ondlp = lpfc_findnode_did(vport, nportid); - if (ondlp && NLP_CHK_NODE_ACT(ondlp)) { + if (ondlp) { memcpy(&fp->OportName, &ondlp->nlp_portname, sizeof(struct lpfc_name)); memcpy(&fp->OnodeName, &ondlp->nlp_nodename, @@ -3325,22 +3683,627 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) ndlp->nlp_DID, 0, 0); phba->fc_stat.elsXmitFARPR++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { + elsiocb->cmd_cmpl = lpfc_cmpl_els_cmd; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { /* The additional lpfc_nlp_put will cause the following * lpfc_els_free_iocb routine to trigger the release of * the node. */ - lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); return 1; } /* This will cause the callback-function lpfc_cmpl_els_cmd to * trigger the release of the node. */ + /* Don't release reference count as RDF is likely outstanding */ + return 0; +} + +/** + * lpfc_issue_els_rdf - Register for diagnostic functions from the fabric. + * @vport: pointer to a host virtual N_Port data structure. + * @retry: retry counter for the command IOCB. + * + * This routine issues an ELS RDF to the Fabric Controller to register + * for diagnostic functions. + * + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the RDF ELS command. + * + * Return code + * 0 - Successfully issued rdf command + * 1 - Failed to issue rdf command + **/ +int +lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct lpfc_els_rdf_req *prdf; + struct lpfc_nodelist *ndlp; + uint16_t cmdsize; + int rc; + + cmdsize = sizeof(*prdf); + + ndlp = lpfc_findnode_did(vport, Fabric_Cntl_DID); + if (!ndlp) { + ndlp = lpfc_nlp_init(vport, Fabric_Cntl_DID); + if (!ndlp) + return -ENODEV; + lpfc_enqueue_node(vport, ndlp); + } + + /* RDF ELS is not required on an NPIV VN_Port. */ + if (vport->port_type == LPFC_NPIV_PORT) + return -EACCES; + + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, + ndlp->nlp_DID, ELS_CMD_RDF); + if (!elsiocb) + return -ENOMEM; + + /* Configure the payload for the supported FPIN events. */ + prdf = (struct lpfc_els_rdf_req *)elsiocb->cmd_dmabuf->virt; + memset(prdf, 0, cmdsize); + prdf->rdf.fpin_cmd = ELS_RDF; + prdf->rdf.desc_len = cpu_to_be32(sizeof(struct lpfc_els_rdf_req) - + sizeof(struct fc_els_rdf)); + prdf->reg_d1.reg_desc.desc_tag = cpu_to_be32(ELS_DTAG_FPIN_REGISTER); + prdf->reg_d1.reg_desc.desc_len = cpu_to_be32( + FC_TLV_DESC_LENGTH_FROM_SZ(prdf->reg_d1)); + prdf->reg_d1.reg_desc.count = cpu_to_be32(ELS_RDF_REG_TAG_CNT); + prdf->reg_d1.desc_tags[0] = cpu_to_be32(ELS_DTAG_LNK_INTEGRITY); + prdf->reg_d1.desc_tags[1] = cpu_to_be32(ELS_DTAG_DELIVERY); + prdf->reg_d1.desc_tags[2] = cpu_to_be32(ELS_DTAG_PEER_CONGEST); + prdf->reg_d1.desc_tags[3] = cpu_to_be32(ELS_DTAG_CONGESTION); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "6444 Xmit RDF to remote NPORT x%x Reg: %x %x\n", + ndlp->nlp_DID, phba->cgn_reg_signal, + phba->cgn_reg_fpin); + + phba->cgn_fpin_frequency = LPFC_FPIN_INIT_FREQ; + elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return -EIO; + } + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue RDF: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + return -EIO; + } + return 0; +} + + /** + * lpfc_els_rcv_rdf - Receive RDF ELS request from the fabric. + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @ndlp: pointer to a node-list data structure. + * + * A received RDF implies a possible change to fabric supported diagnostic + * functions. This routine sends LS_ACC and then has the Nx_Port issue a new + * RDF request to reregister for supported diagnostic functions. + * + * Return code + * 0 - Success + * -EIO - Failed to process received RDF + **/ +static int +lpfc_els_rcv_rdf(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +{ + /* Send LS_ACC */ + if (lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "1623 Failed to RDF_ACC from x%x for x%x\n", + ndlp->nlp_DID, vport->fc_myDID); + return -EIO; + } + + /* Issue new RDF for reregistering */ + if (lpfc_issue_els_rdf(vport, 0)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "2623 Failed to re register RDF for x%x\n", + vport->fc_myDID); + return -EIO; + } + + return 0; +} + +/** + * lpfc_least_capable_settings - helper function for EDC rsp processing + * @phba: pointer to lpfc hba data structure. + * @pcgd: pointer to congestion detection descriptor in EDC rsp. + * + * This helper routine determines the least capable setting for + * congestion signals, signal freq, including scale, from the + * congestion detection descriptor in the EDC rsp. The routine + * sets @phba values in preparation for a set_featues mailbox. + **/ +static void +lpfc_least_capable_settings(struct lpfc_hba *phba, + struct fc_diag_cg_sig_desc *pcgd) +{ + u32 rsp_sig_cap = 0, drv_sig_cap = 0; + u32 rsp_sig_freq_cyc = 0, rsp_sig_freq_scale = 0; + + /* Get rsp signal and frequency capabilities. */ + rsp_sig_cap = be32_to_cpu(pcgd->xmt_signal_capability); + rsp_sig_freq_cyc = be16_to_cpu(pcgd->xmt_signal_frequency.count); + rsp_sig_freq_scale = be16_to_cpu(pcgd->xmt_signal_frequency.units); + + /* If the Fport does not support signals. Set FPIN only */ + if (rsp_sig_cap == EDC_CG_SIG_NOTSUPPORTED) + goto out_no_support; + + /* Apply the xmt scale to the xmt cycle to get the correct frequency. + * Adapter default is 100 millisSeconds. Convert all xmt cycle values + * to milliSeconds. + */ + switch (rsp_sig_freq_scale) { + case EDC_CG_SIGFREQ_SEC: + rsp_sig_freq_cyc *= MSEC_PER_SEC; + break; + case EDC_CG_SIGFREQ_MSEC: + rsp_sig_freq_cyc = 1; + break; + default: + goto out_no_support; + } + + /* Convenient shorthand. */ + drv_sig_cap = phba->cgn_reg_signal; + + /* Choose the least capable frequency. */ + if (rsp_sig_freq_cyc > phba->cgn_sig_freq) + phba->cgn_sig_freq = rsp_sig_freq_cyc; + + /* Should be some common signals support. Settle on least capable + * signal and adjust FPIN values. Initialize defaults to ease the + * decision. + */ + phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM; + phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED; + if (rsp_sig_cap == EDC_CG_SIG_WARN_ONLY && + (drv_sig_cap == EDC_CG_SIG_WARN_ONLY || + drv_sig_cap == EDC_CG_SIG_WARN_ALARM)) { + phba->cgn_reg_signal = EDC_CG_SIG_WARN_ONLY; + phba->cgn_reg_fpin &= ~LPFC_CGN_FPIN_WARN; + } + if (rsp_sig_cap == EDC_CG_SIG_WARN_ALARM) { + if (drv_sig_cap == EDC_CG_SIG_WARN_ALARM) { + phba->cgn_reg_signal = EDC_CG_SIG_WARN_ALARM; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_NONE; + } + if (drv_sig_cap == EDC_CG_SIG_WARN_ONLY) { + phba->cgn_reg_signal = EDC_CG_SIG_WARN_ONLY; + phba->cgn_reg_fpin &= ~LPFC_CGN_FPIN_WARN; + } + } + + /* We are NOT recording signal frequency in congestion info buffer */ + return; + +out_no_support: + phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED; + phba->cgn_sig_freq = 0; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_ALARM | LPFC_CGN_FPIN_WARN; +} + +DECLARE_ENUM2STR_LOOKUP(lpfc_get_tlv_dtag_nm, fc_ls_tlv_dtag, + FC_LS_TLV_DTAG_INIT); + +/** + * lpfc_cmpl_els_edc - Completion callback function for EDC + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @rspiocb: pointer to lpfc response iocb data structure. + * + * This routine is the completion callback function for issuing the Exchange + * Diagnostic Capabilities (EDC) command. The driver issues an EDC to + * notify the FPort of its Congestion and Link Fault capabilities. This + * routine parses the FPort's response and decides on the least common + * values applicable to both FPort and NPort for Warnings and Alarms that + * are communicated via hardware signals. + **/ +static void +lpfc_cmpl_els_edc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + IOCB_t *irsp_iocb; + struct fc_els_edc_resp *edc_rsp; + struct fc_tlv_desc *tlv; + struct fc_diag_cg_sig_desc *pcgd; + struct fc_diag_lnkflt_desc *plnkflt; + struct lpfc_dmabuf *pcmd, *prsp; + const char *dtag_nm; + u32 *pdata, dtag; + int desc_cnt = 0, bytes_remain; + bool rcv_cap_desc = false; + struct lpfc_nodelist *ndlp; + u32 ulp_status, ulp_word4, tmo, did, iotag; + + ndlp = cmdiocb->ndlp; + + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); + did = get_job_els_rsp64_did(phba, rspiocb); + + if (phba->sli_rev == LPFC_SLI_REV4) { + tmo = get_wqe_tmo(rspiocb); + iotag = get_wqe_reqtag(rspiocb); + } else { + irsp_iocb = &rspiocb->iocb; + tmo = irsp_iocb->ulpTimeout; + iotag = irsp_iocb->ulpIoTag; + } + + lpfc_debugfs_disc_trc(phba->pport, LPFC_DISC_TRC_ELS_CMD, + "EDC cmpl: status:x%x/x%x did:x%x", + ulp_status, ulp_word4, did); + + /* ELS cmd tag <ulpIoTag> completes */ + lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "4201 EDC cmd tag x%x completes Data: x%x x%x x%x\n", + iotag, ulp_status, ulp_word4, tmo); + + pcmd = cmdiocb->cmd_dmabuf; + if (!pcmd) + goto out; + + pdata = (u32 *)pcmd->virt; + if (!pdata) + goto out; + + /* Need to clear signal values, send features MB and RDF with FPIN. */ + if (ulp_status) + goto out; + + prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); + if (!prsp) + goto out; + + edc_rsp = prsp->virt; + if (!edc_rsp) + goto out; + + /* ELS cmd tag <ulpIoTag> completes */ + lpfc_printf_log(phba, KERN_INFO, + LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT, + "4676 Fabric EDC Rsp: " + "0x%02x, 0x%08x\n", + edc_rsp->acc_hdr.la_cmd, + be32_to_cpu(edc_rsp->desc_list_len)); + + /* + * Payload length in bytes is the response descriptor list + * length minus the 12 bytes of Link Service Request + * Information descriptor in the reply. + */ + bytes_remain = be32_to_cpu(edc_rsp->desc_list_len) - + sizeof(struct fc_els_lsri_desc); + if (bytes_remain <= 0) + goto out; + + tlv = edc_rsp->desc; + + /* + * cycle through EDC diagnostic descriptors to find the + * congestion signaling capability descriptor + */ + while (bytes_remain) { + if (bytes_remain < FC_TLV_DESC_HDR_SZ) { + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "6461 Truncated TLV hdr on " + "Diagnostic descriptor[%d]\n", + desc_cnt); + goto out; + } + + dtag = be32_to_cpu(tlv->desc_tag); + switch (dtag) { + case ELS_DTAG_LNK_FAULT_CAP: + if (bytes_remain < FC_TLV_DESC_SZ_FROM_LENGTH(tlv) || + FC_TLV_DESC_SZ_FROM_LENGTH(tlv) != + sizeof(struct fc_diag_lnkflt_desc)) { + lpfc_printf_log(phba, KERN_WARNING, + LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT, + "6462 Truncated Link Fault Diagnostic " + "descriptor[%d]: %d vs 0x%zx 0x%zx\n", + desc_cnt, bytes_remain, + FC_TLV_DESC_SZ_FROM_LENGTH(tlv), + sizeof(struct fc_diag_lnkflt_desc)); + goto out; + } + plnkflt = (struct fc_diag_lnkflt_desc *)tlv; + lpfc_printf_log(phba, KERN_INFO, + LOG_ELS | LOG_LDS_EVENT, + "4617 Link Fault Desc Data: 0x%08x 0x%08x " + "0x%08x 0x%08x 0x%08x\n", + be32_to_cpu(plnkflt->desc_tag), + be32_to_cpu(plnkflt->desc_len), + be32_to_cpu( + plnkflt->degrade_activate_threshold), + be32_to_cpu( + plnkflt->degrade_deactivate_threshold), + be32_to_cpu(plnkflt->fec_degrade_interval)); + break; + case ELS_DTAG_CG_SIGNAL_CAP: + if (bytes_remain < FC_TLV_DESC_SZ_FROM_LENGTH(tlv) || + FC_TLV_DESC_SZ_FROM_LENGTH(tlv) != + sizeof(struct fc_diag_cg_sig_desc)) { + lpfc_printf_log( + phba, KERN_WARNING, LOG_CGN_MGMT, + "6463 Truncated Cgn Signal Diagnostic " + "descriptor[%d]: %d vs 0x%zx 0x%zx\n", + desc_cnt, bytes_remain, + FC_TLV_DESC_SZ_FROM_LENGTH(tlv), + sizeof(struct fc_diag_cg_sig_desc)); + goto out; + } + + pcgd = (struct fc_diag_cg_sig_desc *)tlv; + lpfc_printf_log( + phba, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "4616 CGN Desc Data: 0x%08x 0x%08x " + "0x%08x 0x%04x 0x%04x 0x%08x 0x%04x 0x%04x\n", + be32_to_cpu(pcgd->desc_tag), + be32_to_cpu(pcgd->desc_len), + be32_to_cpu(pcgd->xmt_signal_capability), + be16_to_cpu(pcgd->xmt_signal_frequency.count), + be16_to_cpu(pcgd->xmt_signal_frequency.units), + be32_to_cpu(pcgd->rcv_signal_capability), + be16_to_cpu(pcgd->rcv_signal_frequency.count), + be16_to_cpu(pcgd->rcv_signal_frequency.units)); + + /* Compare driver and Fport capabilities and choose + * least common. + */ + lpfc_least_capable_settings(phba, pcgd); + rcv_cap_desc = true; + break; + default: + dtag_nm = lpfc_get_tlv_dtag_nm(dtag); + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "4919 unknown Diagnostic " + "Descriptor[%d]: tag x%x (%s)\n", + desc_cnt, dtag, dtag_nm); + } + + bytes_remain -= FC_TLV_DESC_SZ_FROM_LENGTH(tlv); + tlv = fc_tlv_next_desc(tlv); + desc_cnt++; + } + +out: + if (!rcv_cap_desc) { + phba->cgn_reg_fpin = LPFC_CGN_FPIN_ALARM | LPFC_CGN_FPIN_WARN; + phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED; + phba->cgn_sig_freq = 0; + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_CGN_MGMT, + "4202 EDC rsp error - sending RDF " + "for FPIN only.\n"); + } + + lpfc_config_cgn_signal(phba); + + /* Check to see if link went down during discovery */ + lpfc_els_chk_latt(phba->pport); + lpfc_debugfs_disc_trc(phba->pport, LPFC_DISC_TRC_ELS_CMD, + "EDC Cmpl: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + lpfc_els_free_iocb(phba, cmdiocb); lpfc_nlp_put(ndlp); +} + +static void +lpfc_format_edc_lft_desc(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct fc_diag_lnkflt_desc *lft = (struct fc_diag_lnkflt_desc *)tlv; + + lft->desc_tag = cpu_to_be32(ELS_DTAG_LNK_FAULT_CAP); + lft->desc_len = cpu_to_be32( + FC_TLV_DESC_LENGTH_FROM_SZ(struct fc_diag_lnkflt_desc)); + + lft->degrade_activate_threshold = + cpu_to_be32(phba->degrade_activate_threshold); + lft->degrade_deactivate_threshold = + cpu_to_be32(phba->degrade_deactivate_threshold); + lft->fec_degrade_interval = cpu_to_be32(phba->fec_degrade_interval); +} + +static void +lpfc_format_edc_cgn_desc(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct fc_diag_cg_sig_desc *cgd = (struct fc_diag_cg_sig_desc *)tlv; + + /* We are assuming cgd was zero'ed before calling this routine */ + + /* Configure the congestion detection capability */ + cgd->desc_tag = cpu_to_be32(ELS_DTAG_CG_SIGNAL_CAP); + + /* Descriptor len doesn't include the tag or len fields. */ + cgd->desc_len = cpu_to_be32( + FC_TLV_DESC_LENGTH_FROM_SZ(struct fc_diag_cg_sig_desc)); + + /* xmt_signal_capability already set to EDC_CG_SIG_NOTSUPPORTED. + * xmt_signal_frequency.count already set to 0. + * xmt_signal_frequency.units already set to 0. + */ + + if (phba->cmf_active_mode == LPFC_CFG_OFF) { + /* rcv_signal_capability already set to EDC_CG_SIG_NOTSUPPORTED. + * rcv_signal_frequency.count already set to 0. + * rcv_signal_frequency.units already set to 0. + */ + phba->cgn_sig_freq = 0; + return; + } + switch (phba->cgn_reg_signal) { + case EDC_CG_SIG_WARN_ONLY: + cgd->rcv_signal_capability = cpu_to_be32(EDC_CG_SIG_WARN_ONLY); + break; + case EDC_CG_SIG_WARN_ALARM: + cgd->rcv_signal_capability = cpu_to_be32(EDC_CG_SIG_WARN_ALARM); + break; + default: + /* rcv_signal_capability left 0 thus no support */ + break; + } + + /* We start negotiation with lpfc_fabric_cgn_frequency, after + * the completion we settle on the higher frequency. + */ + cgd->rcv_signal_frequency.count = + cpu_to_be16(lpfc_fabric_cgn_frequency); + cgd->rcv_signal_frequency.units = + cpu_to_be16(EDC_CG_SIGFREQ_MSEC); +} + +static bool +lpfc_link_is_lds_capable(struct lpfc_hba *phba) +{ + if (!(phba->lmt & LMT_64Gb)) + return false; + if (phba->sli_rev != LPFC_SLI_REV4) + return false; + + if (phba->sli4_hba.conf_trunk) { + if (phba->trunk_link.phy_lnk_speed == LPFC_USER_LINK_SPEED_64G) + return true; + } else if (phba->fc_linkspeed == LPFC_LINK_SPEED_64GHZ) { + return true; + } + return false; +} + + /** + * lpfc_issue_els_edc - Exchange Diagnostic Capabilities with the fabric. + * @vport: pointer to a host virtual N_Port data structure. + * @retry: retry counter for the command iocb. + * + * This routine issues an ELS EDC to the F-Port Controller to communicate + * this N_Port's support of hardware signals in its Congestion + * Capabilities Descriptor. + * + * Note: This routine does not check if one or more signals are + * set in the cgn_reg_signal parameter. The caller makes the + * decision to enforce cgn_reg_signal as nonzero or zero depending + * on the conditions. During Fabric requests, the driver + * requires cgn_reg_signals to be nonzero. But a dynamic request + * to set the congestion mode to OFF from Monitor or Manage + * would correctly issue an EDC with no signals enabled to + * turn off switch functionality and then update the FW. + * + * Return code + * 0 - Successfully issued edc command + * 1 - Failed to issue edc command + **/ +int +lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *elsiocb; + struct fc_els_edc *edc_req; + struct fc_tlv_desc *tlv; + u16 cmdsize; + struct lpfc_nodelist *ndlp; + u8 *pcmd = NULL; + u32 cgn_desc_size, lft_desc_size; + int rc; + + if (vport->port_type == LPFC_NPIV_PORT) + return -EACCES; + + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) + return -ENODEV; + + cgn_desc_size = (phba->cgn_init_reg_signal) ? + sizeof(struct fc_diag_cg_sig_desc) : 0; + lft_desc_size = (lpfc_link_is_lds_capable(phba)) ? + sizeof(struct fc_diag_lnkflt_desc) : 0; + cmdsize = cgn_desc_size + lft_desc_size; + + /* Skip EDC if no applicable descriptors */ + if (!cmdsize) + goto try_rdf; + + cmdsize += sizeof(struct fc_els_edc); + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, + ndlp->nlp_DID, ELS_CMD_EDC); + if (!elsiocb) + goto try_rdf; + + /* Configure the payload for the supported Diagnostics capabilities. */ + pcmd = (u8 *)elsiocb->cmd_dmabuf->virt; + memset(pcmd, 0, cmdsize); + edc_req = (struct fc_els_edc *)pcmd; + edc_req->desc_len = cpu_to_be32(cgn_desc_size + lft_desc_size); + edc_req->edc_cmd = ELS_EDC; + tlv = edc_req->desc; + + if (cgn_desc_size) { + lpfc_format_edc_cgn_desc(phba, tlv); + phba->cgn_sig_freq = lpfc_fabric_cgn_frequency; + tlv = fc_tlv_next_desc(tlv); + } + + if (lft_desc_size) + lpfc_format_edc_lft_desc(phba, tlv); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, + "4623 Xmit EDC to remote " + "NPORT x%x reg_sig x%x reg_fpin:x%x\n", + ndlp->nlp_DID, phba->cgn_reg_signal, + phba->cgn_reg_fpin); + + elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return -EIO; + } + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Issue EDC: did:x%x refcnt %d", + ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + /* The additional lpfc_nlp_put will cause the following + * lpfc_els_free_iocb routine to trigger the rlease of + * the node. + */ + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + goto try_rdf; + } return 0; +try_rdf: + phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM; + phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED; + rc = lpfc_issue_els_rdf(vport, 0); + return rc; } /** @@ -3363,9 +4326,9 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) if (!(nlp->nlp_flag & NLP_DELAY_TMO)) return; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&nlp->lock); nlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&nlp->lock); del_timer_sync(&nlp->nlp_delayfunc); nlp->nlp_last_elscmd = 0; if (!list_empty(&nlp->els_retry_evt.evt_listp)) { @@ -3375,9 +4338,9 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); } if (nlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&nlp->lock); nlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&nlp->lock); if (vport->num_disc_nodes) { if (vport->port_state < LPFC_VPORT_READY) { /* Check if there are more ADISCs to be sent */ @@ -3400,7 +4363,7 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) /** * lpfc_els_retry_delay - Timer function with a ndlp delayed function timer - * @ptr: holder for the pointer to the timer function associated data (ndlp). + * @t: pointer to the timer function associated data (ndlp). * * This routine is invoked by the ndlp delayed-function timer to check * whether there is any pending ELS retry event(s) with the node. If not, it @@ -3453,20 +4416,19 @@ void lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) { struct lpfc_vport *vport = ndlp->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); uint32_t cmd, retry; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); cmd = ndlp->nlp_last_elscmd; ndlp->nlp_last_elscmd = 0; if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return; } ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* * If a discovery event readded nlp_delayfunc after timer * firing and before processing the timer, cancel the @@ -3537,7 +4499,7 @@ lpfc_link_reset(struct lpfc_vport *vport) "2851 Attempt link reset\n"); mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2852 Failed to allocate mbox memory"); return 1; } @@ -3559,7 +4521,7 @@ lpfc_link_reset(struct lpfc_vport *vport) mbox->vport = vport; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2853 Failed to issue INIT_LINK " "mbox command, rc:x%x\n", rc); mempool_free(mbox, phba->mbox_mem_pool); @@ -3578,7 +4540,7 @@ lpfc_link_reset(struct lpfc_vport *vport) * This routine makes a retry decision on an ELS command IOCB, which has * failed. The following ELS IOCBs use this function for retrying the command * when previously issued command responsed with error status: FLOGI, PLOGI, - * PRLI, ADISC, LOGO, and FDISC. Based on the ELS command type and the + * PRLI, ADISC and FDISC. Based on the ELS command type and the * returned error status, it makes the decision whether a retry shall be * issued for the command, and whether a retry shall be made immediately or * delayed. In the former case, the corresponding ELS command issuing-function @@ -3595,10 +4557,9 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + union lpfc_wqe128 *irsp = &rspiocb->wqe; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; + struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf; uint32_t *elscmd; struct ls_rjt stat; int retry = 0, maxretry = lpfc_max_els_tries, delay = 0; @@ -3606,9 +4567,11 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, uint32_t cmd = 0; uint32_t did; int link_reset = 0, rc; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); - /* Note: context2 may be 0 for internal driver abort + /* Note: cmd_dmabuf may be 0 for internal driver abort * of delays ELS command. */ @@ -3617,22 +4580,21 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cmd = *elscmd++; } - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) + if (ndlp) did = ndlp->nlp_DID; else { /* We should only hit this case for retrying PLOGI */ - did = irsp->un.elsreq64.remoteID; + did = get_job_els_rsp64_did(phba, rspiocb); ndlp = lpfc_findnode_did(vport, did); - if ((!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - && (cmd != ELS_CMD_PLOGI)) - return 1; + if (!ndlp && (cmd != ELS_CMD_PLOGI)) + return 0; } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Retry ELS: wd7:x%x wd4:x%x did:x%x", - *(((uint32_t *) irsp) + 7), irsp->un.ulpWord[4], ndlp->nlp_DID); + *(((uint32_t *)irsp) + 7), ulp_word4, did); - switch (irsp->ulpStatus) { + switch (ulp_status) { case IOSTAT_FCP_RSP_ERROR: break; case IOSTAT_REMOTE_STOP: @@ -3646,24 +4608,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } break; case IOSTAT_LOCAL_REJECT: - switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) { + switch ((ulp_word4 & IOERR_PARAM_MASK)) { case IOERR_LOOP_OPEN_FAILURE: - if (cmd == ELS_CMD_FLOGI) { - if (PCI_DEVICE_ID_HORNET == - phba->pcidev->device) { - phba->fc_topology = LPFC_TOPOLOGY_LOOP; - phba->pport->fc_myDID = 0; - phba->alpa_map[0] = 0; - phba->alpa_map[1] = 0; - } - } if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0) delay = 1000; retry = 1; break; case IOERR_ILLEGAL_COMMAND: - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0124 Retry illegal cmd x%x " "retry:x%x delay:x%x\n", cmd, cmdiocb->retry, delay); @@ -3709,12 +4662,25 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, retry = 1; delay = 100; break; + case IOERR_SLI_ABORTED: + /* Retry ELS PLOGI command? + * Possibly the rport just wasn't ready. + */ + if (cmd == ELS_CMD_PLOGI) { + /* No retry if state change */ + if (ndlp && + ndlp->nlp_state != NLP_STE_PLOGI_ISSUE) + goto out_retry; + retry = 1; + maxretry = 2; + } + break; } break; case IOSTAT_NPORT_RJT: case IOSTAT_FABRIC_RJT: - if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) { + if (ulp_word4 & RJT_UNAVAIL_TEMP) { retry = 1; break; } @@ -3727,53 +4693,80 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, break; case IOSTAT_LS_RJT: - stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]); + stat.un.ls_rjt_error_be = cpu_to_be32(ulp_word4); /* Added for Vendor specifc support * Just keep retrying for these Rsn / Exp codes */ + if ((vport->fc_flag & FC_PT2PT) && + cmd == ELS_CMD_NVMEPRLI) { + switch (stat.un.b.lsRjtRsnCode) { + case LSRJT_UNABLE_TPC: + case LSRJT_INVALID_CMD: + case LSRJT_LOGICAL_ERR: + case LSRJT_CMD_UNSUPPORTED: + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, + "0168 NVME PRLI LS_RJT " + "reason %x port doesn't " + "support NVME, disabling NVME\n", + stat.un.b.lsRjtRsnCode); + retry = 0; + vport->fc_flag |= FC_PT2PT_NO_NVME; + goto out_retry; + } + } switch (stat.un.b.lsRjtRsnCode) { case LSRJT_UNABLE_TPC: - /* The driver has a VALID PLOGI but the rport has - * rejected the PRLI - can't do it now. Delay - * for 1 second and try again - don't care about - * the explanation. + /* Special case for PRLI LS_RJTs. Recall that lpfc + * uses a single routine to issue both PRLI FC4 types. + * If the PRLI is rejected because that FC4 type + * isn't really supported, don't retry and cause + * multiple transport registrations. Otherwise, parse + * the reason code/reason code explanation and take the + * appropriate action. */ - if (cmd == ELS_CMD_PRLI || cmd == ELS_CMD_NVMEPRLI) { - delay = 1000; - maxretry = lpfc_max_els_tries + 1; - retry = 1; - break; - } - - /* Legacy bug fix code for targets with PLOGI delays. */ - if (stat.un.b.lsRjtRsnCodeExp == - LSEXP_CMD_IN_PROGRESS) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_ELS | LOG_NODE, + "0153 ELS cmd x%x LS_RJT by x%x. " + "RsnCode x%x RsnCodeExp x%x\n", + cmd, did, stat.un.b.lsRjtRsnCode, + stat.un.b.lsRjtRsnCodeExp); + + switch (stat.un.b.lsRjtRsnCodeExp) { + case LSEXP_CANT_GIVE_DATA: + case LSEXP_CMD_IN_PROGRESS: if (cmd == ELS_CMD_PLOGI) { delay = 1000; maxretry = 48; } retry = 1; break; - } - if (stat.un.b.lsRjtRsnCodeExp == - LSEXP_CANT_GIVE_DATA) { - if (cmd == ELS_CMD_PLOGI) { + case LSEXP_REQ_UNSUPPORTED: + case LSEXP_NO_RSRC_ASSIGN: + /* These explanation codes get no retry. */ + if (cmd == ELS_CMD_PRLI || + cmd == ELS_CMD_NVMEPRLI) + break; + fallthrough; + default: + /* Limit the delay and retry action to a limited + * cmd set. There are other ELS commands where + * a retry is not expected. + */ + if (cmd == ELS_CMD_PLOGI || + cmd == ELS_CMD_PRLI || + cmd == ELS_CMD_NVMEPRLI) { delay = 1000; - maxretry = 48; + maxretry = lpfc_max_els_tries + 1; + retry = 1; } - retry = 1; - break; - } - if (cmd == ELS_CMD_PLOGI) { - delay = 1000; - maxretry = lpfc_max_els_tries + 1; - retry = 1; break; } + if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && (cmd == ELS_CMD_FDISC) && (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0125 FDISC Failed (x%x). " "Fabric out of resources\n", stat.un.lsRjtError); @@ -3812,7 +4805,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, LSEXP_NOTHING_MORE) { vport->fc_sparam.cmn.bbRcvSizeMsb &= 0xf; retry = 1; - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0820 FLOGI Failed (x%x). " "BBCredit Not Supported\n", stat.un.lsRjtError); @@ -3825,7 +4819,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) || (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID)) ) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0122 FDISC Failed (x%x). " "Fabric Detected Bad WWN\n", stat.un.lsRjtError); @@ -3846,12 +4841,9 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * on this rport. */ if (stat.un.b.lsRjtRsnCodeExp == - LSEXP_REQ_UNSUPPORTED && cmd == ELS_CMD_PRLI) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_FCP_PRLI_RJT; - spin_unlock_irq(shost->host_lock); - retry = 0; - goto out_retry; + LSEXP_REQ_UNSUPPORTED) { + if (cmd == ELS_CMD_PRLI) + goto out_retry; } break; } @@ -3883,7 +4875,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if ((cmd == ELS_CMD_FLOGI) && (phba->fc_topology != LPFC_TOPOLOGY_LOOP) && - !lpfc_error_lost_link(irsp)) { + !lpfc_error_lost_link(ulp_status, ulp_word4)) { /* FLOGI retry policy */ retry = 1; /* retry FLOGI forever */ @@ -3896,7 +4888,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, delay = 5000; else if (cmdiocb->retry >= 32) delay = 1000; - } else if ((cmd == ELS_CMD_FDISC) && !lpfc_error_lost_link(irsp)) { + } else if ((cmd == ELS_CMD_FDISC) && + !lpfc_error_lost_link(ulp_status, ulp_word4)) { /* retry FDISCs every second up to devloss */ retry = 1; maxretry = vport->cfg_devloss_tmo; @@ -3933,8 +4926,8 @@ out_retry: cmd, did, cmdiocb->retry, delay); if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) && - ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || - ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) != + ((ulp_status != IOSTAT_LOCAL_REJECT) || + ((ulp_word4 & IOERR_PARAM_MASK) != IOERR_NO_RESOURCES))) { /* Don't reset timer for no resources */ @@ -3945,23 +4938,23 @@ out_retry: } phba->fc_stat.elsXmitRetry++; - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && delay) { + if (ndlp && delay) { phba->fc_stat.elsDelayRetry++; ndlp->nlp_retry = cmdiocb->retry; /* delay is specified in milliseconds */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(delay)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_prev_state = ndlp->nlp_state; if ((cmd == ELS_CMD_PRLI) || (cmd == ELS_CMD_NVMEPRLI)) lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); - else + else if (cmd != ELS_CMD_ADISC) lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); ndlp->nlp_last_elscmd = cmd; @@ -3976,7 +4969,7 @@ out_retry: lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry); return 1; case ELS_CMD_PLOGI: - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + if (ndlp) { ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); @@ -4003,18 +4996,18 @@ out_retry: } /* No retry ELS command <elsCmd> to remote NPORT <did> */ if (logerr) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0137 No retry ELS command x%x to remote " "NPORT x%x: Out of Resources: Error:x%x/%x\n", - cmd, did, irsp->ulpStatus, - irsp->un.ulpWord[4]); + cmd, did, ulp_status, + ulp_word4); } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0108 No retry ELS command x%x to remote " "NPORT x%x Retried:%d Error:x%x/%x\n", - cmd, did, cmdiocb->retry, irsp->ulpStatus, - irsp->un.ulpWord[4]); + cmd, did, cmdiocb->retry, ulp_status, + ulp_word4); } return 0; } @@ -4080,10 +5073,10 @@ lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr) * command IOCB data structure contains the reference to various associated * resources, these fields must be set to NULL if the associated reference * not present: - * context1 - reference to ndlp - * context2 - reference to cmd - * context2->next - reference to rsp - * context3 - reference to bpl + * cmd_dmabuf - reference to cmd. + * cmd_dmabuf->next - reference to rsp + * rsp_dmabuf - unused + * bpl_dmabuf - reference to bpl * * It first properly decrements the reference count held on ndlp for the * IOCB completion callback function. If LPFC_DELAY_MEM_FREE flag is not @@ -4102,37 +5095,20 @@ int lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) { struct lpfc_dmabuf *buf_ptr, *buf_ptr1; - struct lpfc_nodelist *ndlp; - ndlp = (struct lpfc_nodelist *)elsiocb->context1; - if (ndlp) { - if (ndlp->nlp_flag & NLP_DEFER_RM) { - lpfc_nlp_put(ndlp); + /* The I/O iocb is complete. Clear the node and first dmbuf */ + elsiocb->ndlp = NULL; - /* If the ndlp is not being used by another discovery - * thread, free it. - */ - if (!lpfc_nlp_not_used(ndlp)) { - /* If ndlp is being used by another discovery - * thread, just clear NLP_DEFER_RM - */ - ndlp->nlp_flag &= ~NLP_DEFER_RM; - } - } - else - lpfc_nlp_put(ndlp); - elsiocb->context1 = NULL; - } - /* context2 = cmd, context2->next = rsp, context3 = bpl */ - if (elsiocb->context2) { - if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) { + /* cmd_dmabuf = cmd, cmd_dmabuf->next = rsp, bpl_dmabuf = bpl */ + if (elsiocb->cmd_dmabuf) { + if (elsiocb->cmd_flag & LPFC_DELAY_MEM_FREE) { /* Firmware could still be in progress of DMAing * payload, so don't free data buffer till after * a hbeat. */ - elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE; - buf_ptr = elsiocb->context2; - elsiocb->context2 = NULL; + elsiocb->cmd_flag &= ~LPFC_DELAY_MEM_FREE; + buf_ptr = elsiocb->cmd_dmabuf; + elsiocb->cmd_dmabuf = NULL; if (buf_ptr) { buf_ptr1 = NULL; spin_lock_irq(&phba->hbalock); @@ -4151,16 +5127,16 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) spin_unlock_irq(&phba->hbalock); } } else { - buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; + buf_ptr1 = elsiocb->cmd_dmabuf; lpfc_els_free_data(phba, buf_ptr1); - elsiocb->context2 = NULL; + elsiocb->cmd_dmabuf = NULL; } } - if (elsiocb->context3) { - buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; + if (elsiocb->bpl_dmabuf) { + buf_ptr = elsiocb->bpl_dmabuf; lpfc_els_free_bpl(phba, buf_ptr); - elsiocb->context3 = NULL; + elsiocb->bpl_dmabuf = NULL; } lpfc_sli_release_iocbq(phba, elsiocb); return 0; @@ -4176,7 +5152,7 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) * Accept (ACC) Response ELS command. This routine is invoked to indicate * the completion of the LOGO process. It invokes the lpfc_nlp_not_used() to * release the ndlp if it has the last reference remaining (reference count - * is 1). If succeeded (meaning ndlp released), it sets the IOCB context1 + * is 1). If succeeded (meaning ndlp released), it sets the iocb ndlp * field to NULL to inform the following lpfc_els_free_iocb() routine no * ndlp reference count needs to be decremented. Otherwise, the ndlp * reference use-count shall be decremented by the lpfc_els_free_iocb() @@ -4187,41 +5163,62 @@ static void lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; struct lpfc_vport *vport = cmdiocb->vport; - IOCB_t *irsp; + u32 ulp_status, ulp_word4; + + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); - irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, "ACC LOGO cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID); + ulp_status, ulp_word4, ndlp->nlp_DID); /* ACC to LOGO completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0109 ACC to LOGO completes to NPort x%x " + "0109 ACC to LOGO completes to NPort x%x refcnt %d " "Data: x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); + ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag, + ndlp->nlp_state, ndlp->nlp_rpi); + + /* This clause allows the LOGO ACC to complete and free resources + * for the Fabric Domain Controller. It does deliberately skip + * the unreg_rpi and release rpi because some fabrics send RDP + * requests after logging out from the initiator. + */ + if (ndlp->nlp_type & NLP_FABRIC && + ((ndlp->nlp_DID & WELL_KNOWN_DID_MASK) != WELL_KNOWN_DID_MASK)) + goto out; if (ndlp->nlp_state == NLP_STE_NPR_NODE) { + /* If PLOGI is being retried, PLOGI completion will cleanup the + * node. The NLP_NPR_2B_DISC flag needs to be retained to make + * progress on nodes discovered from last RSCN. + */ + if ((ndlp->nlp_flag & NLP_DELAY_TMO) && + (ndlp->nlp_last_elscmd == ELS_CMD_PLOGI)) + goto out; + /* NPort Recovery mode or node is just allocated */ if (!lpfc_nlp_not_used(ndlp)) { - /* If the ndlp is being used by another discovery - * thread, just unregister the RPI. + /* A LOGO is completing and the node is in NPR state. + * Just unregister the RPI because the node is still + * required. */ lpfc_unreg_rpi(vport, ndlp); } else { /* Indicate the node has already released, should * not reference to it from within lpfc_els_free_iocb. */ - cmdiocb->context1 = NULL; + cmdiocb->ndlp = NULL; } } - + out: /* * The driver received a LOGO from the rport and has ACK'd it. * At this point, the driver is done so release the IOCB */ lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } /** @@ -4240,34 +5237,33 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; - - pmb->ctx_buf = NULL; - pmb->ctx_ndlp = NULL; + struct lpfc_nodelist *ndlp = pmb->ctx_ndlp; + u32 mbx_flag = pmb->mbox_flag; + u32 mbx_cmd = pmb->u.mb.mbxCommand; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); if (ndlp) { lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0006 rpi%x DID:%x flg:%x %d map:%x x%px\n", + "0006 rpi x%x DID:%x flg:%x %d x%px " + "mbx_cmd x%x mbx_flag x%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); - if (NLP_CHK_NODE_ACT(ndlp)) { - lpfc_nlp_put(ndlp); - /* This is the end of the default RPI cleanup logic for - * this ndlp. If no other discovery threads are using - * this ndlp, free all resources associated with it. - */ - lpfc_nlp_not_used(ndlp); - } else { - lpfc_drop_node(ndlp->vport, ndlp); - } + kref_read(&ndlp->kref), ndlp, mbx_cmd, + mbx_flag, pmb); + + /* This ends the default/temporary RPI cleanup logic for this + * ndlp and the node and rpi needs to be released. Free the rpi + * first on an UNREG_LOGIN and then release the final + * references. + */ + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + if (mbx_cmd == MBX_UNREG_LOGIN) + ndlp->nlp_flag &= ~NLP_UNREG_INP; + spin_unlock_irq(&ndlp->lock); + lpfc_nlp_put(ndlp); + lpfc_drop_node(ndlp->vport, ndlp); } - return; + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); } /** @@ -4281,109 +5277,85 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * nlp_flag bitmap in the ndlp data structure, if the mbox command reference * field in the command IOCB is not NULL, the referred mailbox command will * be send out, and then invokes the lpfc_els_free_iocb() routine to release - * the IOCB. Under error conditions, such as when a LS_RJT is returned or a - * link down event occurred during the discovery, the lpfc_nlp_not_used() - * routine shall be invoked trying to release the ndlp if no other threads - * are currently referring it. + * the IOCB. **/ static void lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL; struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL; IOCB_t *irsp; - uint8_t *pcmd; LPFC_MBOXQ_t *mbox = NULL; - struct lpfc_dmabuf *mp = NULL; - uint32_t ls_rjt = 0; - - irsp = &rspiocb->iocb; + u32 ulp_status, ulp_word4, tmo, did, iotag; if (!vport) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3177 ELS response failed\n"); goto out; } if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; - /* First determine if this is a LS_RJT cmpl. Note, this callback - * function can have cmdiocb->contest1 (ndlp) field set to NULL. - */ - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) { - /* A LS_RJT associated with Default RPI cleanup has its own - * separate code path. - */ - if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI)) - ls_rjt = 1; + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); + did = get_job_els_rsp64_did(phba, cmdiocb); + + if (phba->sli_rev == LPFC_SLI_REV4) { + tmo = get_wqe_tmo(cmdiocb); + iotag = get_wqe_reqtag(cmdiocb); + } else { + irsp = &rspiocb->iocb; + tmo = irsp->ulpTimeout; + iotag = irsp->ulpIoTag; } /* Check to see if link went down during discovery */ - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || lpfc_els_chk_latt(vport)) { - if (mbox) { - mp = (struct lpfc_dmabuf *)mbox->ctx_buf; - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - mempool_free(mbox, phba->mbox_mem_pool); - } - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (ndlp->nlp_flag & NLP_RM_DFLT_RPI)) - if (lpfc_nlp_not_used(ndlp)) { - ndlp = NULL; - /* Indicate the node has already released, - * should not reference to it from within - * the routine lpfc_els_free_iocb. - */ - cmdiocb->context1 = NULL; - } + if (!ndlp || lpfc_els_chk_latt(vport)) { + if (mbox) + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); goto out; } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, "ELS rsp cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - cmdiocb->iocb.un.elsreq64.remoteID); + ulp_status, ulp_word4, did); /* ELS response tag <ulpIoTag> completes */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0110 ELS response tag x%x completes " - "Data: x%x x%x x%x x%x x%x x%x x%x\n", - cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus, - rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout, + "Data: x%x x%x x%x x%x x%x x%x x%x x%x %p %p\n", + iotag, ulp_status, ulp_word4, tmo, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); + ndlp->nlp_rpi, kref_read(&ndlp->kref), mbox, ndlp); if (mbox) { - if ((rspiocb->iocb.ulpStatus == 0) + if (ulp_status == 0 && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { if (!lpfc_unreg_rpi(vport, ndlp) && - (!(vport->fc_flag & FC_PT2PT)) && - (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || - ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE)) { - lpfc_printf_vlog(vport, KERN_INFO, - LOG_DISCOVERY, - "0314 PLOGI recov DID x%x " - "Data: x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_state, - ndlp->nlp_rpi, ndlp->nlp_flag); - mp = mbox->ctx_buf; - if (mp) { - lpfc_mbuf_free(phba, mp->virt, - mp->phys); - kfree(mp); + (!(vport->fc_flag & FC_PT2PT))) { + if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || + ndlp->nlp_state == + NLP_STE_REG_LOGIN_ISSUE) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY, + "0314 PLOGI recov " + "DID x%x " + "Data: x%x x%x x%x\n", + ndlp->nlp_DID, + ndlp->nlp_state, + ndlp->nlp_rpi, + ndlp->nlp_flag); + goto out_free_mbox; } - mempool_free(mbox, phba->mbox_mem_pool); - goto out; } /* Increment reference count to ndlp to hold the * reference to ndlp for the callback function. */ mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) + goto out_free_mbox; + mbox->vport = vport; if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) { mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; @@ -4408,64 +5380,45 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; /* ELS rsp: Cannot issue reg_login for <NPortid> */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0138 ELS rsp: Cannot issue reg_login for x%x " "Data: x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - - if (lpfc_nlp_not_used(ndlp)) { - ndlp = NULL; - /* Indicate node has already been released, - * should not reference to it from within - * the routine lpfc_els_free_iocb. - */ - cmdiocb->context1 = NULL; - } - } else { - /* Do not drop node for lpfc_els_abort'ed ELS cmds */ - if (!lpfc_error_lost_link(irsp) && - ndlp->nlp_flag & NLP_ACC_REGLOGIN) { - if (lpfc_nlp_not_used(ndlp)) { - ndlp = NULL; - /* Indicate node has already been - * released, should not reference - * to it from within the routine - * lpfc_els_free_iocb. - */ - cmdiocb->context1 = NULL; - } - } - } - mp = (struct lpfc_dmabuf *)mbox->ctx_buf; - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); } - mempool_free(mbox, phba->mbox_mem_pool); +out_free_mbox: + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); } out: - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && shost) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI); - spin_unlock_irq(shost->host_lock); - - /* If the node is not being used by another discovery thread, - * and we are sending a reject, we are done with it. - * Release driver reference count here and free associated - * resources. - */ - if (ls_rjt) - if (lpfc_nlp_not_used(ndlp)) - /* Indicate node has already been released, - * should not reference to it from within - * the routine lpfc_els_free_iocb. - */ - cmdiocb->context1 = NULL; + if (ndlp && shost) { + spin_lock_irq(&ndlp->lock); + if (mbox) + ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN; + ndlp->nlp_flag &= ~NLP_RM_DFLT_RPI; + spin_unlock_irq(&ndlp->lock); + } + /* An SLI4 NPIV instance wants to drop the node at this point under + * these conditions and release the RPI. + */ + if (phba->sli_rev == LPFC_SLI_REV4 && + (vport && vport->port_type == LPFC_NPIV_PORT) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD) && + ndlp->nlp_flag & NLP_RELEASE_RPI) { + if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE && + ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) { + lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); + spin_lock_irq(&ndlp->lock); + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; + ndlp->nlp_flag &= ~NLP_RELEASE_RPI; + spin_unlock_irq(&ndlp->lock); + lpfc_drop_node(vport, ndlp); + } } + /* Release the originating I/O reference. */ lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); return; } @@ -4485,10 +5438,10 @@ out: * field of the IOCB for the completion callback function to issue the * mailbox command to the HBA later when callback is invoked. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the corresponding response ELS IOCB command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the corresponding + * response ELS IOCB command. * * Return code * 0 - Successfully issued acc response @@ -4499,18 +5452,18 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; IOCB_t *icmd; IOCB_t *oldcmd; + union lpfc_wqe128 *wqe; + union lpfc_wqe128 *oldwqe = &oldiocb->wqe; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; struct serv_parm *sp; uint16_t cmdsize; int rc; ELS_PKT *els_pkt_ptr; - - oldcmd = &oldiocb->iocb; + struct fc_els_rdf_resp *rdf_resp; switch (flag) { case ELS_CMD_ACC: @@ -4518,16 +5471,32 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, ndlp->nlp_DID, ELS_CMD_ACC); if (!elsiocb) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return 1; } - icmd = &elsiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + /* XRI / rx_id */ + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, + bf_get(wqe_ctxt_tag, + &oldwqe->xmit_els_rsp.wqe_com)); + + /* oxid */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + bf_get(wqe_rcvoxid, + &oldwqe->xmit_els_rsp.wqe_com)); + } else { + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ + icmd->unsli3.rcvsli3.ox_id = + oldcmd->unsli3.rcvsli3.ox_id; + } + + pcmd = elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof(uint32_t); @@ -4543,10 +5512,26 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + /* XRI / rx_id */ + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, + bf_get(wqe_ctxt_tag, + &oldwqe->xmit_els_rsp.wqe_com)); + + /* oxid */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + bf_get(wqe_rcvoxid, + &oldwqe->xmit_els_rsp.wqe_com)); + } else { + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ + icmd->unsli3.rcvsli3.ox_id = + oldcmd->unsli3.rcvsli3.ox_id; + } + + pcmd = (u8 *)elsiocb->cmd_dmabuf->virt; if (mbox) elsiocb->context_un.mbox = mbox; @@ -4605,12 +5590,28 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + /* XRI / rx_id */ + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, + bf_get(wqe_ctxt_tag, + &oldwqe->xmit_els_rsp.wqe_com)); + + /* oxid */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + bf_get(wqe_rcvoxid, + &oldwqe->xmit_els_rsp.wqe_com)); + } else { + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ + icmd->unsli3.rcvsli3.ox_id = + oldcmd->unsli3.rcvsli3.ox_id; + } - memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt, + pcmd = (u8 *) elsiocb->cmd_dmabuf->virt; + + memcpy(pcmd, oldiocb->cmd_dmabuf->virt, sizeof(uint32_t) + sizeof(PRLO)); *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC; els_pkt_ptr = (ELS_PKT *) pcmd; @@ -4620,33 +5621,88 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, "Issue ACC PRLO: did:x%x flg:x%x", ndlp->nlp_DID, ndlp->nlp_flag, 0); break; + case ELS_CMD_RDF: + cmdsize = sizeof(*rdf_resp); + elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, + ndlp, ndlp->nlp_DID, ELS_CMD_ACC); + if (!elsiocb) + return 1; + + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + /* XRI / rx_id */ + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, + bf_get(wqe_ctxt_tag, + &oldwqe->xmit_els_rsp.wqe_com)); + + /* oxid */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + bf_get(wqe_rcvoxid, + &oldwqe->xmit_els_rsp.wqe_com)); + } else { + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ + icmd->unsli3.rcvsli3.ox_id = + oldcmd->unsli3.rcvsli3.ox_id; + } + + pcmd = (u8 *)elsiocb->cmd_dmabuf->virt; + rdf_resp = (struct fc_els_rdf_resp *)pcmd; + memset(rdf_resp, 0, sizeof(*rdf_resp)); + rdf_resp->acc_hdr.la_cmd = ELS_LS_ACC; + + /* FC-LS-5 specifies desc_list_len shall be set to 12 */ + rdf_resp->desc_list_len = cpu_to_be32(12); + + /* FC-LS-5 specifies LS REQ Information descriptor */ + rdf_resp->lsri.desc_tag = cpu_to_be32(1); + rdf_resp->lsri.desc_len = cpu_to_be32(sizeof(u32)); + rdf_resp->lsri.rqst_w0.cmd = ELS_RDF; + break; default: return 1; } if (ndlp->nlp_flag & NLP_LOGO_ACC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED || ndlp->nlp_flag & NLP_REG_LOGIN_SEND)) ndlp->nlp_flag &= ~NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); - elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc; + spin_unlock_irq(&ndlp->lock); + elsiocb->cmd_cmpl = lpfc_cmpl_els_logo_acc; } else { - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; } phba->fc_stat.elsXmitACC++; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); return 1; } + + /* Xmit ELS ACC response tag <ulpIoTag> */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, " + "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " + "RPI: x%x, fc_flag x%x refcnt %d\n", + rc, elsiocb->iotag, elsiocb->sli4_xritag, + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_rpi, vport->fc_flag, kref_read(&ndlp->kref)); return 0; } /** - * lpfc_els_rsp_reject - Propare and issue a rjt response iocb command + * lpfc_els_rsp_reject - Prepare and issue a rjt response iocb command * @vport: pointer to a virtual N_Port data structure. - * @rejectError: + * @rejectError: reject response to issue * @oldiocb: pointer to the original lpfc command iocb data structure. * @ndlp: pointer to a node-list data structure. * @mbox: pointer to the driver internal queue element for mailbox command. @@ -4656,10 +5712,10 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, * context_un.mbox field of the IOCB for the completion callback function * to issue to the HBA later. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the reject response ELS IOCB command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the reject response + * ELS IOCB command. * * Return code * 0 - Successfully issued reject response @@ -4670,13 +5726,14 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox) { + int rc; struct lpfc_hba *phba = vport->phba; IOCB_t *icmd; IOCB_t *oldcmd; + union lpfc_wqe128 *wqe; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; - int rc; cmdsize = 2 * sizeof(uint32_t); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, @@ -4684,11 +5741,20 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + get_job_ulpcontext(phba, oldiocb)); /* Xri / rx_id */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + get_job_rcvoxid(phba, oldiocb)); + } else { + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ + icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; + } + + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT; pcmd += sizeof(uint32_t); @@ -4703,20 +5769,140 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, " "rpi x%x\n", rejectError, elsiocb->iotag, - elsiocb->iocb.ulpContext, ndlp->nlp_DID, + get_job_ulpcontext(phba, elsiocb), ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, "Issue LS_RJT: did:x%x flg:x%x err:x%x", ndlp->nlp_DID, ndlp->nlp_flag, rejectError); phba->fc_stat.elsXmitLSRJT++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + + /* The NPIV instance is rejecting this unsolicited ELS. Make sure the + * node's assigned RPI gets released provided this node is not already + * registered with the transport. + */ + if (phba->sli_rev == LPFC_SLI_REV4 && + vport->port_type == LPFC_NPIV_PORT && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag |= NLP_RELEASE_RPI; + spin_unlock_irq(&ndlp->lock); + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + return 1; + } + + return 0; +} + + /** + * lpfc_issue_els_edc_rsp - Exchange Diagnostic Capabilities with the fabric. + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to the original lpfc command iocb data structure. + * @ndlp: NPort to where rsp is directed + * + * This routine issues an EDC ACC RSP to the F-Port Controller to communicate + * this N_Port's support of hardware signals in its Congestion + * Capabilities Descriptor. + * + * Return code + * 0 - Successfully issued edc rsp command + * 1 - Failed to issue edc rsp command + **/ +static int +lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_hba *phba = vport->phba; + struct fc_els_edc_resp *edc_rsp; + struct fc_tlv_desc *tlv; + struct lpfc_iocbq *elsiocb; + IOCB_t *icmd, *cmd; + union lpfc_wqe128 *wqe; + u32 cgn_desc_size, lft_desc_size; + u16 cmdsize; + uint8_t *pcmd; + int rc; + cmdsize = sizeof(struct fc_els_edc_resp); + cgn_desc_size = sizeof(struct fc_diag_cg_sig_desc); + lft_desc_size = (lpfc_link_is_lds_capable(phba)) ? + sizeof(struct fc_diag_lnkflt_desc) : 0; + cmdsize += cgn_desc_size + lft_desc_size; + elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, cmdiocb->retry, + ndlp, ndlp->nlp_DID, ELS_CMD_ACC); + if (!elsiocb) + return 1; + + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + get_job_ulpcontext(phba, cmdiocb)); /* Xri / rx_id */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + get_job_rcvoxid(phba, cmdiocb)); + } else { + icmd = &elsiocb->iocb; + cmd = &cmdiocb->iocb; + icmd->ulpContext = cmd->ulpContext; /* Xri / rx_id */ + icmd->unsli3.rcvsli3.ox_id = cmd->unsli3.rcvsli3.ox_id; + } + + pcmd = elsiocb->cmd_dmabuf->virt; + memset(pcmd, 0, cmdsize); + + edc_rsp = (struct fc_els_edc_resp *)pcmd; + edc_rsp->acc_hdr.la_cmd = ELS_LS_ACC; + edc_rsp->desc_list_len = cpu_to_be32(sizeof(struct fc_els_lsri_desc) + + cgn_desc_size + lft_desc_size); + edc_rsp->lsri.desc_tag = cpu_to_be32(ELS_DTAG_LS_REQ_INFO); + edc_rsp->lsri.desc_len = cpu_to_be32( + FC_TLV_DESC_LENGTH_FROM_SZ(struct fc_els_lsri_desc)); + edc_rsp->lsri.rqst_w0.cmd = ELS_EDC; + tlv = edc_rsp->desc; + lpfc_format_edc_cgn_desc(phba, tlv); + tlv = fc_tlv_next_desc(tlv); + if (lft_desc_size) + lpfc_format_edc_lft_desc(phba, tlv); + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, + "Issue EDC ACC: did:x%x flg:x%x refcnt %d", + ndlp->nlp_DID, ndlp->nlp_flag, + kref_read(&ndlp->kref)); + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; + + phba->fc_stat.elsXmitACC++; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); return 1; } + + /* Xmit ELS ACC response tag <ulpIoTag> */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "0152 Xmit EDC ACC response Status: x%x, IoTag: x%x, " + "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " + "RPI: x%x, fc_flag x%x\n", + rc, elsiocb->iotag, elsiocb->sli4_xritag, + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_rpi, vport->fc_flag); + return 0; } @@ -4730,10 +5916,10 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, * Discover (ADISC) ELS command. It simply prepares the payload of the IOCB * and invokes the lpfc_sli_issue_iocb() routine to send out the command. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the ADISC Accept response ELS IOCB command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the ADISC Accept response + * ELS IOCB command. * * Return code * 0 - Successfully issued acc adisc response @@ -4746,10 +5932,12 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, struct lpfc_hba *phba = vport->phba; ADISC *ap; IOCB_t *icmd, *oldcmd; + union lpfc_wqe128 *wqe; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; int rc; + u32 ulp_context; cmdsize = sizeof(uint32_t) + sizeof(ADISC); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, @@ -4757,19 +5945,32 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + /* XRI / rx_id */ + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + get_job_ulpcontext(phba, oldiocb)); + ulp_context = get_job_ulpcontext(phba, elsiocb); + /* oxid */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + get_job_rcvoxid(phba, oldiocb)); + } else { + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ + ulp_context = elsiocb->iocb.ulpContext; + icmd->unsli3.rcvsli3.ox_id = + oldcmd->unsli3.rcvsli3.ox_id; + } /* Xmit ADISC ACC response tag <ulpIoTag> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0130 Xmit ADISC ACC response iotag x%x xri: " "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, + elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof(uint32_t); @@ -4781,25 +5982,24 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, ap->DID = be32_to_cpu(vport->fc_myDID); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC ADISC: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); + "Issue ACC ADISC: did:x%x flg:x%x refcnt %d", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); return 1; } - /* Xmit ELS ACC response tag <ulpIoTag> */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, " - "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " - "RPI: x%x, fc_flag x%x\n", - rc, elsiocb->iotag, elsiocb->sli4_xritag, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi, vport->fc_flag); return 0; } @@ -4813,10 +6013,10 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, * Login (PRLI) ELS command. It simply prepares the payload of the IOCB * and invokes the lpfc_sli_issue_iocb() routine to send out the command. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the PRLI Accept response ELS IOCB command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the PRLI Accept response + * ELS IOCB command. * * Return code * 0 - Successfully issued acc prli response @@ -4832,18 +6032,19 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, lpfc_vpd_t *vpd; IOCB_t *icmd; IOCB_t *oldcmd; + union lpfc_wqe128 *wqe; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; uint32_t prli_fc4_req, *req_payload; struct lpfc_dmabuf *req_buf; int rc; - u32 elsrspcmd; + u32 elsrspcmd, ulp_context; /* Need the incoming PRLI payload to determine if the ACC is for an * FC4 or NVME PRLI type. The PRLI type is at word 1. */ - req_buf = (struct lpfc_dmabuf *)oldiocb->context2; + req_buf = oldiocb->cmd_dmabuf; req_payload = (((uint32_t *)req_buf->virt) + 1); /* PRLI type payload is at byte 3 for FCP or NVME. */ @@ -4856,7 +6057,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, if (prli_fc4_req == PRLI_FCP_TYPE) { cmdsize = sizeof(uint32_t) + sizeof(PRLI); elsrspcmd = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)); - } else if (prli_fc4_req & PRLI_NVME_TYPE) { + } else if (prli_fc4_req == PRLI_NVME_TYPE) { cmdsize = sizeof(uint32_t) + sizeof(struct lpfc_nvme_prli); elsrspcmd = (ELS_CMD_ACC | (ELS_CMD_NVMEPRLI & ~ELS_RSP_MASK)); } else { @@ -4864,23 +6065,34 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, } elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, - ndlp->nlp_DID, elsrspcmd); + ndlp->nlp_DID, elsrspcmd); if (!elsiocb) return 1; - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + get_job_ulpcontext(phba, oldiocb)); /* Xri / rx_id */ + ulp_context = get_job_ulpcontext(phba, elsiocb); + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + get_job_rcvoxid(phba, oldiocb)); + } else { + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ + ulp_context = elsiocb->iocb.ulpContext; + icmd->unsli3.rcvsli3.ox_id = + oldcmd->unsli3.rcvsli3.ox_id; + } /* Xmit PRLI ACC response tag <ulpIoTag> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0131 Xmit PRLI ACC response tag x%x xri x%x, " "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, + elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; memset(pcmd, 0, cmdsize); *((uint32_t *)(pcmd)) = elsrspcmd; @@ -4908,7 +6120,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, npr->ConfmComplAllowed = 1; npr->prliType = PRLI_FCP_TYPE; npr->initiatorFunc = 1; - } else if (prli_fc4_req & PRLI_NVME_TYPE) { + } else if (prli_fc4_req == PRLI_NVME_TYPE) { /* Respond with an NVME PRLI Type */ npr_nvme = (struct lpfc_nvme_prli *) pcmd; bf_set(prli_type_code, npr_nvme, PRLI_NVME_TYPE); @@ -4948,17 +6160,24 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, ndlp->nlp_DID); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC PRLI: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); + "Issue ACC PRLI: did:x%x flg:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); return 1; } + return 0; } @@ -4972,17 +6191,11 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, * This routine issues a Request Node Identification Data (RNID) Accept * (ACC) response. It constructs the RNID ACC response command according to * the proper @format and then calls the lpfc_sli_issue_iocb() routine to - * issue the response. Note that this command does not need to hold the ndlp - * reference count for the callback. So, the ndlp reference count taken by - * the lpfc_prep_els_iocb() routine is put back and the context1 field of - * IOCB is set to NULL to indicate to the lpfc_els_free_iocb() routine that - * there is no ndlp reference available. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function. However, for the RNID Accept Response ELS command, - * this is undone later by this routine after the IOCB is allocated. + * issue the response. + * + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function. * * Return code * 0 - Successfully issued acc rnid response @@ -4995,10 +6208,12 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, struct lpfc_hba *phba = vport->phba; RNID *rn; IOCB_t *icmd, *oldcmd; + union lpfc_wqe128 *wqe; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; int rc; + u32 ulp_context; cmdsize = sizeof(uint32_t) + sizeof(uint32_t) + (2 * sizeof(struct lpfc_name)); @@ -5010,16 +6225,27 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + get_job_ulpcontext(phba, oldiocb)); /* Xri / rx_id */ + ulp_context = get_job_ulpcontext(phba, elsiocb); + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + get_job_rcvoxid(phba, oldiocb)); + } else { + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ + ulp_context = elsiocb->iocb.ulpContext; + icmd->unsli3.rcvsli3.ox_id = + oldcmd->unsli3.rcvsli3.ox_id; + } /* Xmit RNID ACC response tag <ulpIoTag> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0132 Xmit RNID ACC response tag x%x xri x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext); - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + elsiocb->iotag, ulp_context); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof(uint32_t); @@ -5048,17 +6274,24 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC RNID: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); + "Issue ACC RNID: did:x%x flg:x%x refcnt %d", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); return 1; } + return 0; } @@ -5082,7 +6315,7 @@ lpfc_els_clear_rrq(struct lpfc_vport *vport, struct lpfc_node_rrq *prrq; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) iocb->context2)->virt); + pcmd = (uint8_t *)iocb->cmd_dmabuf->virt; pcmd += sizeof(uint32_t); rrq = (struct RRQ *)pcmd; rrq->rrq_exchg = be32_to_cpu(rrq->rrq_exchg); @@ -5094,7 +6327,8 @@ lpfc_els_clear_rrq(struct lpfc_vport *vport, be32_to_cpu(bf_get(rrq_did, rrq)), bf_get(rrq_oxid, rrq), rxid, - iocb->iotag, iocb->iocb.ulpContext); + get_wqe_reqtag(iocb), + get_job_ulpcontext(phba, iocb)); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, "Clear RRQ: did:x%x flg:x%x exchg:x%.08x", @@ -5125,12 +6359,18 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) { struct lpfc_hba *phba = vport->phba; + IOCB_t *icmd, *oldcmd; + union lpfc_wqe128 *wqe; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; int rc; + u32 ulp_context; - cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len; + if (phba->sli_rev == LPFC_SLI_REV4) + cmdsize = oldiocb->wcqe_cmpl.total_data_placed; + else + cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len; /* The accumulated length can exceed the BPL_SIZE. For * now, use this as the limit @@ -5142,30 +6382,50 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, if (!elsiocb) return 1; - elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext; /* Xri / rx_id */ - elsiocb->iocb.unsli3.rcvsli3.ox_id = oldiocb->iocb.unsli3.rcvsli3.ox_id; + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + get_job_ulpcontext(phba, oldiocb)); /* Xri / rx_id */ + ulp_context = get_job_ulpcontext(phba, elsiocb); + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + get_job_rcvoxid(phba, oldiocb)); + } else { + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ + ulp_context = elsiocb->iocb.ulpContext; + icmd->unsli3.rcvsli3.ox_id = + oldcmd->unsli3.rcvsli3.ox_id; + } /* Xmit ECHO ACC response tag <ulpIoTag> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "2876 Xmit ECHO ACC response tag x%x xri x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext); - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + elsiocb->iotag, ulp_context); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof(uint32_t); memcpy(pcmd, data, cmdsize - sizeof(uint32_t)); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC ECHO: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); + "Issue ACC ECHO: did:x%x flg:x%x refcnt %d", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); return 1; } + return 0; } @@ -5197,27 +6457,41 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport) /* go thru NPR nodes and issue any remaining ELS ADISCs */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) + + if (ndlp->nlp_state != NLP_STE_NPR_NODE || + !(ndlp->nlp_flag & NLP_NPR_ADISC)) continue; - if (ndlp->nlp_state == NLP_STE_NPR_NODE && - (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && - (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) { + + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_NPR_ADISC; + spin_unlock_irq(&ndlp->lock); + + if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { + /* This node was marked for ADISC but was not picked + * for discovery. This is possible if the node was + * missing in gidft response. + * + * At time of marking node for ADISC, we skipped unreg + * from backend + */ + lpfc_nlp_unreg_node(vport, ndlp); + lpfc_unreg_rpi(vport, ndlp); + continue; + } + + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); + lpfc_issue_els_adisc(vport, ndlp, 0); + sentadisc++; + vport->num_disc_nodes++; + if (vport->num_disc_nodes >= + vport->cfg_discovery_threads) { spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; + vport->fc_flag |= FC_NLP_MORE; spin_unlock_irq(shost->host_lock); - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); - lpfc_issue_els_adisc(vport, ndlp, 0); - sentadisc++; - vport->num_disc_nodes++; - if (vport->num_disc_nodes >= - vport->cfg_discovery_threads) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_NLP_MORE; - spin_unlock_irq(shost->host_lock); - break; - } + break; } + } if (sentadisc == 0) { spin_lock_irq(shost->host_lock); @@ -5255,8 +6529,6 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) /* go thru NPR nodes and issue any remaining ELS PLOGIs */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_NPR_NODE && (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 && @@ -5631,6 +6903,12 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) case LPFC_LINK_SPEED_64GHZ: rdp_speed = RDP_PS_64GB; break; + case LPFC_LINK_SPEED_128GHZ: + rdp_speed = RDP_PS_128GB; + break; + case LPFC_LINK_SPEED_256GHZ: + rdp_speed = RDP_PS_256GB; + break; default: rdp_speed = RDP_PS_UNKNOWN; break; @@ -5638,6 +6916,8 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) desc->info.port_speed.speed = cpu_to_be16(rdp_speed); + if (phba->lmt & LMT_256Gb) + rdp_cap |= RDP_PS_256GB; if (phba->lmt & LMT_128Gb) rdp_cap |= RDP_PS_128GB; if (phba->lmt & LMT_64Gb) @@ -5717,12 +6997,14 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, struct lpfc_iocbq *elsiocb; struct ulp_bde64 *bpl; IOCB_t *icmd; + union lpfc_wqe128 *wqe; uint8_t *pcmd; struct ls_rjt *stat; struct fc_rdp_res_frame *rdp_res; uint32_t cmdsize, len; uint16_t *flag_ptr; int rc; + u32 ulp_context; if (status != SUCCESS) goto error; @@ -5731,25 +7013,33 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, cmdsize = sizeof(struct fc_rdp_res_frame); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, - lpfc_max_els_tries, rdp_context->ndlp, - rdp_context->ndlp->nlp_DID, ELS_CMD_ACC); - lpfc_nlp_put(ndlp); + lpfc_max_els_tries, rdp_context->ndlp, + rdp_context->ndlp->nlp_DID, ELS_CMD_ACC); if (!elsiocb) goto free_rdp_context; - icmd = &elsiocb->iocb; - icmd->ulpContext = rdp_context->rx_id; - icmd->unsli3.rcvsli3.ox_id = rdp_context->ox_id; + ulp_context = get_job_ulpcontext(phba, elsiocb); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + /* ox-id of the frame */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + rdp_context->ox_id); + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, + rdp_context->rx_id); + } else { + icmd = &elsiocb->iocb; + icmd->ulpContext = rdp_context->rx_id; + icmd->unsli3.rcvsli3.ox_id = rdp_context->ox_id; + } lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "2171 Xmit RDP response tag x%x xri x%x, " "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x", - elsiocb->iotag, elsiocb->iocb.ulpContext, + elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - rdp_res = (struct fc_rdp_res_frame *) - (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + rdp_res = (struct fc_rdp_res_frame *)elsiocb->cmd_dmabuf->virt; + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; memset(pcmd, 0, sizeof(struct fc_rdp_res_frame)); *((uint32_t *) (pcmd)) = ELS_CMD_ACC; @@ -5797,47 +7087,75 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, rdp_context->page_a0, vport); rdp_res->length = cpu_to_be32(len - 8); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; /* Now that we know the true size of the payload, update the BPL */ - bpl = (struct ulp_bde64 *) - (((struct lpfc_dmabuf *)(elsiocb->context3))->virt); + bpl = (struct ulp_bde64 *)elsiocb->bpl_dmabuf->virt; bpl->tus.f.bdeSize = len; bpl->tus.f.bdeFlags = 0; bpl->tus.w = le32_to_cpu(bpl->tus.w); phba->fc_stat.elsXmitACC++; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + goto free_rdp_context; + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) + if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + } - kfree(rdp_context); + goto free_rdp_context; - return; error: cmdsize = 2 * sizeof(uint32_t); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, lpfc_max_els_tries, ndlp, ndlp->nlp_DID, ELS_CMD_LS_RJT); - lpfc_nlp_put(ndlp); if (!elsiocb) goto free_rdp_context; - icmd = &elsiocb->iocb; - icmd->ulpContext = rdp_context->rx_id; - icmd->unsli3.rcvsli3.ox_id = rdp_context->ox_id; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + /* ox-id of the frame */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + rdp_context->ox_id); + bf_set(wqe_ctxt_tag, + &wqe->xmit_els_rsp.wqe_com, + rdp_context->rx_id); + } else { + icmd = &elsiocb->iocb; + icmd->ulpContext = rdp_context->rx_id; + icmd->unsli3.rcvsli3.ox_id = rdp_context->ox_id; + } + + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT; stat = (struct ls_rjt *)(pcmd + sizeof(uint32_t)); stat->un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; phba->fc_stat.elsXmitLSRJT++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + goto free_rdp_context; + } - if (rc == IOCB_ERROR) + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + } + free_rdp_context: + /* This reference put is for the original unsolicited RDP. If the + * prep failed, there is no reference to remove. + */ + lpfc_nlp_put(ndlp); kfree(rdp_context); } @@ -5855,18 +7173,19 @@ lpfc_get_rdp_info(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context) } if (lpfc_sli4_dump_page_a0(phba, mbox)) - goto prep_mbox_fail; + goto rdp_fail; mbox->vport = rdp_context->ndlp->vport; mbox->mbox_cmpl = lpfc_mbx_cmpl_rdp_page_a0; mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - goto issue_mbox_fail; + if (rc == MBX_NOT_FINISHED) { + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); + return 1; + } return 0; -prep_mbox_fail: -issue_mbox_fail: +rdp_fail: mempool_free(mbox, phba->mbox_mem_pool); return 1; } @@ -5897,7 +7216,7 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, uint8_t rjt_err, rjt_expl = LSEXP_NOTHING_MORE; struct fc_rdp_req_frame *rdp_req; struct lpfc_rdp_context *rdp_context; - IOCB_t *cmd = NULL; + union lpfc_wqe128 *cmd = NULL; struct ls_rjt stat; if (phba->sli_rev < LPFC_SLI_REV4 || @@ -5914,7 +7233,7 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, goto error; } - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; rdp_req = (struct fc_rdp_req_frame *) pcmd->virt; lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -5939,10 +7258,17 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, goto error; } - cmd = &cmdiocb->iocb; + cmd = &cmdiocb->wqe; rdp_context->ndlp = lpfc_nlp_get(ndlp); - rdp_context->ox_id = cmd->unsli3.rcvsli3.ox_id; - rdp_context->rx_id = cmd->ulpContext; + if (!rdp_context->ndlp) { + kfree(rdp_context); + rjt_err = LSRJT_UNABLE_TPC; + goto error; + } + rdp_context->ox_id = bf_get(wqe_rcvoxid, + &cmd->xmit_els_rsp.wqe_com); + rdp_context->rx_id = bf_get(wqe_ctxt_tag, + &cmd->xmit_els_rsp.wqe_com); rdp_context->cmpl = lpfc_els_rdp_cmpl; if (lpfc_get_rdp_info(phba, rdp_context)) { lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_ELS, @@ -5972,6 +7298,7 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { MAILBOX_t *mb; IOCB_t *icmd; + union lpfc_wqe128 *wqe; uint8_t *pcmd; struct lpfc_iocbq *elsiocb; struct lpfc_nodelist *ndlp; @@ -6018,43 +7345,67 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (!elsiocb) goto free_lcb_context; - lcb_res = (struct fc_lcb_res_frame *) - (((struct lpfc_dmabuf *)elsiocb->context2)->virt); + lcb_res = (struct fc_lcb_res_frame *)elsiocb->cmd_dmabuf->virt; memset(lcb_res, 0, sizeof(struct fc_lcb_res_frame)); - icmd = &elsiocb->iocb; - icmd->ulpContext = lcb_context->rx_id; - icmd->unsli3.rcvsli3.ox_id = lcb_context->ox_id; - pcmd = (uint8_t *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, lcb_context->rx_id); + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + lcb_context->ox_id); + } else { + icmd = &elsiocb->iocb; + icmd->ulpContext = lcb_context->rx_id; + icmd->unsli3.rcvsli3.ox_id = lcb_context->ox_id; + } + + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *)(pcmd)) = ELS_CMD_ACC; lcb_res->lcb_sub_command = lcb_context->sub_command; lcb_res->lcb_type = lcb_context->type; lcb_res->capability = lcb_context->capability; lcb_res->lcb_frequency = lcb_context->frequency; lcb_res->lcb_duration = lcb_context->duration; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) + + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); + goto out; + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + } + out: kfree(lcb_context); return; error: cmdsize = sizeof(struct fc_lcb_res_frame); elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, - lpfc_max_els_tries, ndlp, - ndlp->nlp_DID, ELS_CMD_LS_RJT); + lpfc_max_els_tries, ndlp, + ndlp->nlp_DID, ELS_CMD_LS_RJT); lpfc_nlp_put(ndlp); if (!elsiocb) goto free_lcb_context; - icmd = &elsiocb->iocb; - icmd->ulpContext = lcb_context->rx_id; - icmd->unsli3.rcvsli3.ox_id = lcb_context->ox_id; - pcmd = (uint8_t *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, lcb_context->rx_id); + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + lcb_context->ox_id); + } else { + icmd = &elsiocb->iocb; + icmd->ulpContext = lcb_context->rx_id; + icmd->unsli3.rcvsli3.ox_id = lcb_context->ox_id; + } + + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *)(pcmd)) = ELS_CMD_LS_RJT; stat = (struct ls_rjt *)(pcmd + sizeof(uint32_t)); @@ -6063,11 +7414,19 @@ error: if (shdr_add_status == ADD_STATUS_OPERATION_ALREADY_ACTIVE) stat->un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitLSRJT++; + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + goto free_lcb_context; + } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) + if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + } free_lcb_context: kfree(lcb_context); } @@ -6167,10 +7526,10 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, uint8_t *lp; struct fc_lcb_request_frame *beacon; struct lpfc_lcb_context *lcb_context; - uint8_t state, rjt_err; + u8 state, rjt_err = 0; struct ls_rjt stat; - pcmd = (struct lpfc_dmabuf *)cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; lp = (uint8_t *)pcmd->virt; beacon = (struct fc_lcb_request_frame *)pcmd->virt; @@ -6210,18 +7569,25 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lcb_context->type = beacon->lcb_type; lcb_context->frequency = beacon->lcb_frequency; lcb_context->duration = beacon->lcb_duration; - lcb_context->ox_id = cmdiocb->iocb.unsli3.rcvsli3.ox_id; - lcb_context->rx_id = cmdiocb->iocb.ulpContext; + lcb_context->ox_id = get_job_rcvoxid(phba, cmdiocb); + lcb_context->rx_id = get_job_ulpcontext(phba, cmdiocb); lcb_context->ndlp = lpfc_nlp_get(ndlp); + if (!lcb_context->ndlp) { + rjt_err = LSRJT_UNABLE_TPC; + goto rjt_free; + } + if (lpfc_sli4_set_beacon(vport, lcb_context, state)) { - lpfc_printf_vlog(ndlp->vport, KERN_ERR, - LOG_ELS, "0193 failed to send mail box"); - kfree(lcb_context); + lpfc_printf_vlog(ndlp->vport, KERN_ERR, LOG_TRACE_EVENT, + "0193 failed to send mail box"); lpfc_nlp_put(ndlp); rjt_err = LSRJT_UNABLE_TPC; - goto rjt; + goto rjt_free; } return 0; + +rjt_free: + kfree(lcb_context); rjt: memset(&stat, 0, sizeof(stat)); stat.un.b.lsRjtRsnCode = rjt_err; @@ -6360,12 +7726,11 @@ return_did_out: static int lpfc_rscn_recovery_check(struct lpfc_vport *vport) { - struct lpfc_nodelist *ndlp = NULL; + struct lpfc_nodelist *ndlp = NULL, *n; /* Move all affected nodes by pending RSCNs to NPR state. */ - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp) || - (ndlp->nlp_state == NLP_STE_UNUSED_NODE) || + list_for_each_entry_safe(ndlp, n, &vport->fc_nodes, nlp_listp) { + if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) || !lpfc_rscn_payload_check(vport, ndlp->nlp_DID)) continue; @@ -6385,13 +7750,6 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) continue; } - /* Check to see if we need to NVME rescan this target - * remoteport. - */ - if (ndlp->nlp_fc4_type & NLP_FC4_NVME && - ndlp->nlp_type & (NLP_NVME_TARGET | NLP_NVME_DISCOVERY)) - lpfc_nvme_rescan_port(vport, ndlp); - lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); lpfc_cancel_retry_delay_tmo(vport, ndlp); @@ -6417,14 +7775,14 @@ lpfc_send_rscn_event(struct lpfc_vport *vport, uint32_t payload_len; struct lpfc_rscn_event_header *rscn_event_data; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; payload_ptr = (uint32_t *) pcmd->virt; payload_len = be32_to_cpu(*payload_ptr & ~ELS_CMD_MASK); rscn_event_data = kmalloc(sizeof(struct lpfc_rscn_event_header) + payload_len, GFP_KERNEL); if (!rscn_event_data) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0147 Failed to allocate memory for RSCN event\n"); return; } @@ -6477,7 +7835,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, int rscn_id = 0, hba_id = 0; int i, tmo; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; lp = (uint32_t *) pcmd->virt; payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK); @@ -6553,6 +7911,13 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); + /* Restart disctmo if its already running */ + if (vport->fc_flag & FC_DISC_TMO) { + tmo = ((phba->fc_ratov * 3) + 3); + mod_timer(&vport->fc_disctmo, + jiffies + + msecs_to_jiffies(1000 * tmo)); + } return 0; } } @@ -6572,7 +7937,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* Get the array count after successfully have the token */ rscn_cnt = vport->fc_rscn_id_cnt; /* If we are already processing an RSCN, save the received - * RSCN payload buffer, cmdiocb->context2 to process later. + * RSCN payload buffer, cmdiocb->cmd_dmabuf to process later. */ if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -6605,10 +7970,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, } else { vport->fc_rscn_id_list[rscn_cnt] = pcmd; vport->fc_rscn_id_cnt++; - /* If we zero, cmdiocb->context2, the calling + /* If we zero, cmdiocb->cmd_dmabuf, the calling * routine will not try to free it. */ - cmdiocb->context2 = NULL; + cmdiocb->cmd_dmabuf = NULL; } /* Deferred RSCN */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -6645,10 +8010,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* Indicate we are done walking fc_rscn_id_list on this vport */ vport->fc_rscn_flush = 0; /* - * If we zero, cmdiocb->context2, the calling routine will + * If we zero, cmdiocb->cmd_dmabuf, the calling routine will * not try to free it. */ - cmdiocb->context2 = NULL; + cmdiocb->cmd_dmabuf = NULL; lpfc_set_disctmo(vport); /* Send back ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); @@ -6700,8 +8065,7 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) vport->num_disc_nodes = 0; ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { /* Good ndlp, issue CT Request to NameServer. Need to * know how many gidfts were issued. If none, then just * flush the RSCN. Otherwise, the outstanding requests @@ -6719,13 +8083,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) } else { /* Nameserver login in question. Revalidate. */ if (ndlp) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_PLOGI_ISSUE); - if (!ndlp) { - lpfc_els_flush_rscn(vport); - return 0; - } ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); } else { ndlp = lpfc_nlp_init(vport, NameServer_DID); if (!ndlp) { @@ -6778,9 +8137,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf; uint32_t *lp = (uint32_t *) pcmd->virt; - IOCB_t *icmd = &cmdiocb->iocb; + union lpfc_wqe128 *wqe = &cmdiocb->wqe; struct serv_parm *sp; LPFC_MBOXQ_t *mbox; uint32_t cmd, did; @@ -6788,6 +8147,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, uint32_t fc_flag = 0; uint32_t port_state = 0; + /* Clear external loopback plug detected flag */ + phba->link_flag &= ~LS_EXTERNAL_LOOPBACK; + cmd = *lp++; sp = (struct serv_parm *) lp; @@ -6797,11 +8159,11 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { /* We should never receive a FLOGI in loop mode, ignore it */ - did = icmd->un.elsreq64.remoteID; + did = bf_get(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest); /* An FLOGI ELS command <elsCmd> was received from DID <did> in Loop Mode */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0113 An FLOGI ELS command x%x was " "received from DID x%x in Loop Mode\n", cmd, did); @@ -6839,6 +8201,12 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 1; } + /* External loopback plug insertion detected */ + phba->link_flag |= LS_EXTERNAL_LOOPBACK; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_LIBDFC, + "1119 External Loopback plug detected\n"); + /* abort the flogi coming back to ourselves * due to external loopback on the port. */ @@ -6893,9 +8261,10 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* Defer ACC response until AFTER we issue a FLOGI */ if (!(phba->hba_flag & HBA_FLOGI_ISSUED)) { - phba->defer_flogi_acc_rx_id = cmdiocb->iocb.ulpContext; - phba->defer_flogi_acc_ox_id = - cmdiocb->iocb.unsli3.rcvsli3.ox_id; + phba->defer_flogi_acc_rx_id = bf_get(wqe_ctxt_tag, + &wqe->xmit_els_rsp.wqe_com); + phba->defer_flogi_acc_ox_id = bf_get(wqe_rcvoxid, + &wqe->xmit_els_rsp.wqe_com); vport->fc_myDID = did; @@ -6944,7 +8313,7 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, RNID *rn; struct ls_rjt stat; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; lp = (uint32_t *) pcmd->virt; lp++; @@ -6985,7 +8354,7 @@ lpfc_els_rcv_echo(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { uint8_t *pcmd; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); + pcmd = (uint8_t *)cmdiocb->cmd_dmabuf->virt; /* skip over first word of echo command to find echo data */ pcmd += sizeof(uint32_t); @@ -7054,23 +8423,25 @@ lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, * * This routine is the completion callback function for the MBX_READ_LNK_STAT * mailbox command. This callback function is to actually send the Accept - * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It + * (ACC) response to a Read Link Status (RLS) unsolicited IOCB event. It * collects the link statistics from the completion of the MBX_READ_LNK_STAT - * mailbox command, constructs the RPS response with the link statistics + * mailbox command, constructs the RLS response with the link statistics * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC - * response to the RPS. + * response to the RLS. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the RLS Accept Response + * ELS IOCB command. * **/ static void lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { + int rc = 0; MAILBOX_t *mb; IOCB_t *icmd; + union lpfc_wqe128 *wqe; struct RLS_RSP *rls_rsp; uint8_t *pcmd; struct lpfc_iocbq *elsiocb; @@ -7078,10 +8449,11 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) uint16_t oxid; uint16_t rxid; uint32_t cmdsize; + u32 ulp_context; mb = &pmb->u.mb; - ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; + ndlp = pmb->ctx_ndlp; rxid = (uint16_t)((unsigned long)(pmb->ctx_buf) & 0xffff); oxid = (uint16_t)(((unsigned long)(pmb->ctx_buf) >> 16) & 0xffff); pmb->ctx_buf = NULL; @@ -7105,11 +8477,19 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) return; } - icmd = &elsiocb->iocb; - icmd->ulpContext = rxid; - icmd->unsli3.rcvsli3.ox_id = oxid; + ulp_context = get_job_ulpcontext(phba, elsiocb); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + /* Xri / rx_id */ + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, rxid); + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, oxid); + } else { + icmd = &elsiocb->iocb; + icmd->ulpContext = rxid; + icmd->unsli3.rcvsli3.ox_id = oxid; + } - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof(uint32_t); /* Skip past command */ rls_rsp = (struct RLS_RSP *)pcmd; @@ -7125,108 +8505,22 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, "2874 Xmit ELS RLS ACC response tag x%x xri x%x, " "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, + elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); -} - -/** - * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * This routine is the completion callback function for the MBX_READ_LNK_STAT - * mailbox command. This callback function is to actually send the Accept - * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It - * collects the link statistics from the completion of the MBX_READ_LNK_STAT - * mailbox command, constructs the RPS response with the link statistics - * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC - * response to the RPS. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. - * - **/ -static void -lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb; - IOCB_t *icmd; - RPS_RSP *rps_rsp; - uint8_t *pcmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_nodelist *ndlp; - uint16_t status; - uint16_t oxid; - uint16_t rxid; - uint32_t cmdsize; - - mb = &pmb->u.mb; - - ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; - rxid = (uint16_t)((unsigned long)(pmb->ctx_buf) & 0xffff); - oxid = (uint16_t)(((unsigned long)(pmb->ctx_buf) >> 16) & 0xffff); - pmb->ctx_ndlp = NULL; - pmb->ctx_buf = NULL; - - if (mb->mbxStatus) { - mempool_free(pmb, phba->mbox_mem_pool); return; } - cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t); - mempool_free(pmb, phba->mbox_mem_pool); - elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, - lpfc_max_els_tries, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - - /* Decrement the ndlp reference count from previous mbox command */ - lpfc_nlp_put(ndlp); - - if (!elsiocb) - return; - - icmd = &elsiocb->iocb; - icmd->ulpContext = rxid; - icmd->unsli3.rcvsli3.ox_id = oxid; - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); /* Skip past command */ - rps_rsp = (RPS_RSP *)pcmd; - - if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) - status = 0x10; - else - status = 0x8; - if (phba->pport->fc_flag & FC_FABRIC) - status |= 0x4; - - rps_rsp->rsvd1 = 0; - rps_rsp->portStatus = cpu_to_be16(status); - rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt); - rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt); - rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt); - rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); - rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); - rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); - /* Xmit ELS RPS ACC response tag <ulpIoTag> */ - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, - "0118 Xmit ELS RPS ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + } return; } @@ -7236,7 +8530,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * @cmdiocb: pointer to lpfc command iocb data structure. * @ndlp: pointer to a node-list data structure. * - * This routine processes Read Port Status (RPL) IOCB received as an + * This routine processes Read Link Status (RLS) IOCB received as an * ELS unsolicited event. It first checks the remote port state. If the * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE * state, it invokes the lpfc_els_rsl_reject() routine to send the reject @@ -7255,19 +8549,22 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mbox; struct ls_rjt stat; + u32 ctx = get_job_ulpcontext(phba, cmdiocb); + u32 ox_id = get_job_rcvoxid(phba, cmdiocb); if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ + /* reject the unsolicited RLS request and done with it */ goto reject_out; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); if (mbox) { lpfc_read_lnk_stat(phba, mbox); mbox->ctx_buf = (void *)((unsigned long) - ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) | - cmdiocb->iocb.ulpContext)); /* rx_id */ + (ox_id << 16 | ctx)); mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) + goto node_err; mbox->vport = vport; mbox->mbox_cmpl = lpfc_els_rsp_rls_acc; if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) @@ -7278,6 +8575,7 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, * command. */ lpfc_nlp_put(ndlp); +node_err: mempool_free(mbox, phba->mbox_mem_pool); } reject_out: @@ -7303,10 +8601,10 @@ reject_out: * response. Otherwise, it sends the Accept(ACC) response to a Read Timeout * Value (RTV) unsolicited IOCB event. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the RTV Accept Response + * ELS IOCB command. * * Return codes * 0 - Successfully processed rtv iocb (currently always return 0) @@ -7315,17 +8613,20 @@ static int lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_nodelist *ndlp) { + int rc = 0; + IOCB_t *icmd; + union lpfc_wqe128 *wqe; struct lpfc_hba *phba = vport->phba; struct ls_rjt stat; struct RTV_RSP *rtv_rsp; uint8_t *pcmd; struct lpfc_iocbq *elsiocb; uint32_t cmdsize; - + u32 ulp_context; if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ + /* reject the unsolicited RTV request and done with it */ goto reject_out; cmdsize = sizeof(struct RTV_RSP) + sizeof(uint32_t); @@ -7336,13 +8637,23 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if (!elsiocb) return 1; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof(uint32_t); /* Skip past command */ + ulp_context = get_job_ulpcontext(phba, elsiocb); /* use the command's xri in the response */ - elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext; /* Xri / rx_id */ - elsiocb->iocb.unsli3.rcvsli3.ox_id = cmdiocb->iocb.unsli3.rcvsli3.ox_id; + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + get_job_ulpcontext(phba, cmdiocb)); + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + get_job_rcvoxid(phba, cmdiocb)); + } else { + icmd = &elsiocb->iocb; + icmd->ulpContext = get_job_ulpcontext(phba, cmdiocb); + icmd->unsli3.rcvsli3.ox_id = get_job_rcvoxid(phba, cmdiocb); + } rtv_rsp = (struct RTV_RSP *)pcmd; @@ -7358,92 +8669,24 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, "2875 Xmit ELS RTV ACC response tag x%x xri x%x, " "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x, " "Data: x%x x%x x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, + elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi, rtv_rsp->ratov, rtv_rsp->edtov, rtv_rsp->qtov); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); - return 0; - -reject_out: - /* issue rejection response */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - return 0; -} - -/* lpfc_els_rcv_rps - Process an unsolicited rps iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Read Port Status (RPS) IOCB received as an - * ELS unsolicited event. It first checks the remote port state. If the - * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE - * state, it invokes the lpfc_els_rsp_reject() routine to send the reject - * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command - * for reading the HBA link statistics. It is for the callback function, - * lpfc_els_rsp_rps_acc(), set to the MBX_READ_LNK_STAT mailbox command - * to actually sending out RPS Accept (ACC) response. - * - * Return codes - * 0 - Successfully processed rps iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - uint32_t *lp; - uint8_t flag; - LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *pcmd; - RPS *rps; - struct ls_rjt stat; - - if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ - goto reject_out; + return 0; + } - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - flag = (be32_to_cpu(*lp++) & 0xf); - rps = (RPS *) lp; - - if ((flag == 0) || - ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) || - ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname, - sizeof(struct lpfc_name)) == 0))) { - - printk("Fix me....\n"); - dump_stack(); - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); - if (mbox) { - lpfc_read_lnk_stat(phba, mbox); - mbox->ctx_buf = (void *)((unsigned long) - ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) | - cmdiocb->iocb.ulpContext)); /* rx_id */ - mbox->ctx_ndlp = lpfc_nlp_get(ndlp); - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_els_rsp_rps_acc; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) - != MBX_NOT_FINISHED) - /* Mbox completion will send ELS Response */ - return 0; - /* Decrement reference count used for the failed mbox - * command. - */ - lpfc_nlp_put(ndlp); - mempool_free(mbox, phba->mbox_mem_pool); - } + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); } + return 0; reject_out: /* issue rejection response */ @@ -7455,7 +8698,7 @@ reject_out: return 0; } -/* lpfc_issue_els_rrq - Process an unsolicited rps iocb +/* lpfc_issue_els_rrq - Process an unsolicited rrq iocb * @vport: pointer to a host virtual N_Port data structure. * @ndlp: pointer to a node-list data structure. * @did: DID of the target. @@ -7479,10 +8722,7 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint16_t cmdsize; int ret; - - if (ndlp != rrq->ndlp) - ndlp = rrq->ndlp; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) return 1; /* If ndlp is not NULL, we will bump the reference count on it */ @@ -7492,7 +8732,7 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; /* For RRQ request, remainder of payload is Exchange IDs */ *((uint32_t *) (pcmd)) = ELS_CMD_RRQ; @@ -7510,14 +8750,22 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "Issue RRQ: did:x%x", did, rrq->xritag, rrq->rxid); elsiocb->context_un.rrq = rrq; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rrq; - ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + elsiocb->cmd_cmpl = lpfc_cmpl_els_rrq; + + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) + goto io_err; + ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (ret == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; + lpfc_nlp_put(ndlp); + goto io_err; } return 0; + + io_err: + lpfc_els_free_iocb(phba, elsiocb); + return 1; } /** @@ -7557,10 +8805,10 @@ lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq) * This routine issuees an Accept (ACC) Read Port List (RPL) ELS command. * It is to be called by the lpfc_els_rcv_rpl() routine to accept the RPL. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPL Accept Response ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the RPL Accept Response + * ELS command. * * Return code * 0 - Successfully issued ACC RPL ELS command @@ -7570,11 +8818,14 @@ static int lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) { + int rc = 0; struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd, *oldcmd; + IOCB_t *icmd; + union lpfc_wqe128 *wqe; RPL_RSP rpl_rsp; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; + u32 ulp_context; elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, ndlp->nlp_DID, ELS_CMD_ACC); @@ -7582,12 +8833,21 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; + ulp_context = get_job_ulpcontext(phba, elsiocb); + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + /* Xri / rx_id */ + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + get_job_ulpcontext(phba, oldiocb)); + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + get_job_rcvoxid(phba, oldiocb)); + } else { + icmd = &elsiocb->iocb; + icmd->ulpContext = get_job_ulpcontext(phba, oldiocb); + icmd->unsli3.rcvsli3.ox_id = get_job_rcvoxid(phba, oldiocb); + } - pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof(uint16_t); *((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize); @@ -7606,16 +8866,24 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, "0120 Xmit ELS RPL ACC response tag x%x " "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, " "rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, + elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; + elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); return 1; } + return 0; } @@ -7659,7 +8927,7 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 0; } - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; lp = (uint32_t *) pcmd->virt; rpl = (RPL *) (lp + 1); maxsize = be32_to_cpu(rpl->maxsize); @@ -7707,13 +8975,11 @@ lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { struct lpfc_dmabuf *pcmd; uint32_t *lp; - IOCB_t *icmd; FARP *fp; uint32_t cnt, did; - icmd = &cmdiocb->iocb; - did = icmd->un.elsreq64.remoteID; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + did = get_job_els_rsp64_did(vport->phba, cmdiocb); + pcmd = cmdiocb->cmd_dmabuf; lp = (uint32_t *) pcmd->virt; lp++; @@ -7780,13 +9046,11 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { struct lpfc_dmabuf *pcmd; uint32_t *lp; - IOCB_t *icmd; uint32_t did; - icmd = &cmdiocb->iocb; - did = icmd->un.elsreq64.remoteID; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; + did = get_job_els_rsp64_did(vport->phba, cmdiocb); + pcmd = cmdiocb->cmd_dmabuf; + lp = (uint32_t *)pcmd->virt; lp++; /* FARP-RSP received from DID <did> */ @@ -7826,7 +9090,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, FAN *fp; lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0265 FAN received\n"); - lp = (uint32_t *)((struct lpfc_dmabuf *)cmdiocb->context2)->virt; + lp = (uint32_t *)cmdiocb->cmd_dmabuf->virt; fp = (FAN *) ++lp; /* FAN received; Fan does not have a reply sequence */ if ((vport == phba->pport) && @@ -7854,8 +9118,140 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, } /** + * lpfc_els_rcv_edc - Process an unsolicited EDC iocb + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @ndlp: pointer to a node-list data structure. + * + * Return code + * 0 - Successfully processed echo iocb (currently always return 0) + **/ +static int +lpfc_els_rcv_edc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +{ + struct lpfc_hba *phba = vport->phba; + struct fc_els_edc *edc_req; + struct fc_tlv_desc *tlv; + uint8_t *payload; + uint32_t *ptr, dtag; + const char *dtag_nm; + int desc_cnt = 0, bytes_remain; + struct fc_diag_lnkflt_desc *plnkflt; + + payload = cmdiocb->cmd_dmabuf->virt; + + edc_req = (struct fc_els_edc *)payload; + bytes_remain = be32_to_cpu(edc_req->desc_len); + + ptr = (uint32_t *)payload; + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT, + "3319 Rcv EDC payload len %d: x%x x%x x%x\n", + bytes_remain, be32_to_cpu(*ptr), + be32_to_cpu(*(ptr + 1)), be32_to_cpu(*(ptr + 2))); + + /* No signal support unless there is a congestion descriptor */ + phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED; + phba->cgn_sig_freq = 0; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_ALARM | LPFC_CGN_FPIN_WARN; + + if (bytes_remain <= 0) + goto out; + + tlv = edc_req->desc; + + /* + * cycle through EDC diagnostic descriptors to find the + * congestion signaling capability descriptor + */ + while (bytes_remain) { + if (bytes_remain < FC_TLV_DESC_HDR_SZ) { + lpfc_printf_log(phba, KERN_WARNING, + LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT, + "6464 Truncated TLV hdr on " + "Diagnostic descriptor[%d]\n", + desc_cnt); + goto out; + } + + dtag = be32_to_cpu(tlv->desc_tag); + switch (dtag) { + case ELS_DTAG_LNK_FAULT_CAP: + if (bytes_remain < FC_TLV_DESC_SZ_FROM_LENGTH(tlv) || + FC_TLV_DESC_SZ_FROM_LENGTH(tlv) != + sizeof(struct fc_diag_lnkflt_desc)) { + lpfc_printf_log(phba, KERN_WARNING, + LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT, + "6465 Truncated Link Fault Diagnostic " + "descriptor[%d]: %d vs 0x%zx 0x%zx\n", + desc_cnt, bytes_remain, + FC_TLV_DESC_SZ_FROM_LENGTH(tlv), + sizeof(struct fc_diag_lnkflt_desc)); + goto out; + } + plnkflt = (struct fc_diag_lnkflt_desc *)tlv; + lpfc_printf_log(phba, KERN_INFO, + LOG_ELS | LOG_LDS_EVENT, + "4626 Link Fault Desc Data: x%08x len x%x " + "da x%x dd x%x interval x%x\n", + be32_to_cpu(plnkflt->desc_tag), + be32_to_cpu(plnkflt->desc_len), + be32_to_cpu( + plnkflt->degrade_activate_threshold), + be32_to_cpu( + plnkflt->degrade_deactivate_threshold), + be32_to_cpu(plnkflt->fec_degrade_interval)); + break; + case ELS_DTAG_CG_SIGNAL_CAP: + if (bytes_remain < FC_TLV_DESC_SZ_FROM_LENGTH(tlv) || + FC_TLV_DESC_SZ_FROM_LENGTH(tlv) != + sizeof(struct fc_diag_cg_sig_desc)) { + lpfc_printf_log( + phba, KERN_WARNING, LOG_CGN_MGMT, + "6466 Truncated cgn signal Diagnostic " + "descriptor[%d]: %d vs 0x%zx 0x%zx\n", + desc_cnt, bytes_remain, + FC_TLV_DESC_SZ_FROM_LENGTH(tlv), + sizeof(struct fc_diag_cg_sig_desc)); + goto out; + } + + phba->cgn_reg_fpin = phba->cgn_init_reg_fpin; + phba->cgn_reg_signal = phba->cgn_init_reg_signal; + + /* We start negotiation with lpfc_fabric_cgn_frequency. + * When we process the EDC, we will settle on the + * higher frequency. + */ + phba->cgn_sig_freq = lpfc_fabric_cgn_frequency; + + lpfc_least_capable_settings( + phba, (struct fc_diag_cg_sig_desc *)tlv); + break; + default: + dtag_nm = lpfc_get_tlv_dtag_nm(dtag); + lpfc_printf_log(phba, KERN_WARNING, + LOG_ELS | LOG_CGN_MGMT | LOG_LDS_EVENT, + "6467 unknown Diagnostic " + "Descriptor[%d]: tag x%x (%s)\n", + desc_cnt, dtag, dtag_nm); + } + bytes_remain -= FC_TLV_DESC_SZ_FROM_LENGTH(tlv); + tlv = fc_tlv_next_desc(tlv); + desc_cnt++; + } +out: + /* Need to send back an ACC */ + lpfc_issue_els_edc_rsp(vport, cmdiocb, ndlp); + + lpfc_config_cgn_signal(phba); + return 0; +} + +/** * lpfc_els_timeout - Handler funciton to the els timer - * @ptr: holder for the timer function associated data. + * @t: timer context used to obtain the vport. * * This routine is invoked by the ELS timer after timeout. It posts the ELS * timer timeout event by setting the WORKER_ELS_TMO bit to the work port @@ -7904,6 +9300,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) uint32_t timeout; uint32_t remote_ID = 0xffffffff; LIST_HEAD(abort_list); + u32 ulp_command = 0, ulp_context = 0, did = 0, iotag = 0; timeout = (uint32_t)(phba->fc_ratov << 1); @@ -7912,31 +9309,35 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) if (unlikely(!pring)) return; - if ((phba->pport->load_flag & FC_UNLOADING)) + if (phba->pport->load_flag & FC_UNLOADING) return; + spin_lock_irq(&phba->hbalock); if (phba->sli_rev == LPFC_SLI_REV4) spin_lock(&pring->ring_lock); - if ((phba->pport->load_flag & FC_UNLOADING)) { - if (phba->sli_rev == LPFC_SLI_REV4) - spin_unlock(&pring->ring_lock); - spin_unlock_irq(&phba->hbalock); - return; - } - list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { - cmd = &piocb->iocb; + ulp_command = get_job_cmnd(phba, piocb); + ulp_context = get_job_ulpcontext(phba, piocb); + did = get_job_els_rsp64_did(phba, piocb); + + if (phba->sli_rev == LPFC_SLI_REV4) { + iotag = get_wqe_reqtag(piocb); + } else { + cmd = &piocb->iocb; + iotag = cmd->ulpIoTag; + } - if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 || - piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || - piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) + if ((piocb->cmd_flag & LPFC_IO_LIBDFC) != 0 || + ulp_command == CMD_ABORT_XRI_CX || + ulp_command == CMD_ABORT_XRI_CN || + ulp_command == CMD_CLOSE_XRI_CN) continue; if (piocb->vport != vport) continue; - pcmd = (struct lpfc_dmabuf *) piocb->context2; + pcmd = piocb->cmd_dmabuf; if (pcmd) els_command = *(uint32_t *) (pcmd->virt); @@ -7954,12 +9355,12 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) } remote_ID = 0xffffffff; - if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR) - remote_ID = cmd->un.elsreq64.remoteID; - else { + if (ulp_command != CMD_GEN_REQUEST64_CR) { + remote_ID = did; + } else { struct lpfc_nodelist *ndlp; - ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) + ndlp = __lpfc_findnode_rpi(vport, ulp_context); + if (ndlp) remote_ID = ndlp->nlp_DID; } list_add_tail(&piocb->dlist, &abort_list); @@ -7969,17 +9370,20 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) spin_unlock_irq(&phba->hbalock); list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { - cmd = &piocb->iocb; - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0127 ELS timeout Data: x%x x%x x%x " "x%x\n", els_command, - remote_ID, cmd->ulpCommand, cmd->ulpIoTag); + remote_ID, ulp_command, iotag); + spin_lock_irq(&phba->hbalock); list_del_init(&piocb->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, piocb); + lpfc_sli_issue_abort_iotag(phba, pring, piocb, NULL); spin_unlock_irq(&phba->hbalock); } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + if (!list_empty(&pring->txcmplq)) if (!(phba->pport->load_flag & FC_UNLOADING)) mod_timer(&vport->els_tmofunc, @@ -8013,7 +9417,7 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) struct lpfc_hba *phba = vport->phba; struct lpfc_sli_ring *pring; struct lpfc_iocbq *tmp_iocb, *piocb; - IOCB_t *cmd = NULL; + u32 ulp_command; unsigned long iflags = 0; lpfc_fabric_abort_vport(vport); @@ -8038,20 +9442,20 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) /* First we need to issue aborts to outstanding cmds on txcmpl */ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { - if (piocb->iocb_flag & LPFC_IO_LIBDFC) + if (piocb->cmd_flag & LPFC_IO_LIBDFC) continue; if (piocb->vport != vport) continue; - if (piocb->iocb_flag & LPFC_DRIVER_ABORTED) + if (piocb->cmd_flag & LPFC_DRIVER_ABORTED) continue; /* On the ELS ring we can have ELS_REQUESTs or * GEN_REQUESTs waiting for a response. */ - cmd = &piocb->iocb; - if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR) { + ulp_command = get_job_cmnd(phba, piocb); + if (ulp_command == CMD_ELS_REQUEST64_CR) { list_add_tail(&piocb->dlist, &abort_list); /* If the link is down when flushing ELS commands @@ -8062,9 +9466,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) * and avoid any retry logic. */ if (phba->link_state == LPFC_LINK_DOWN) - piocb->iocb_cmpl = lpfc_cmpl_els_link_down; + piocb->cmd_cmpl = lpfc_cmpl_els_link_down; } - if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) + if (ulp_command == CMD_GEN_REQUEST64_CR) list_add_tail(&piocb->dlist, &abort_list); } @@ -8076,11 +9480,14 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { spin_lock_irqsave(&phba->hbalock, iflags); list_del_init(&piocb->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, piocb); + lpfc_sli_issue_abort_iotag(phba, pring, piocb, NULL); spin_unlock_irqrestore(&phba->hbalock, iflags); } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + if (!list_empty(&abort_list)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "3387 abort list for txq not empty\n"); INIT_LIST_HEAD(&abort_list); @@ -8092,17 +9499,17 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) * just queue them up for lpfc_sli_cancel_iocbs */ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { - cmd = &piocb->iocb; + ulp_command = get_job_cmnd(phba, piocb); - if (piocb->iocb_flag & LPFC_IO_LIBDFC) { + if (piocb->cmd_flag & LPFC_IO_LIBDFC) continue; - } /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */ - if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN || - cmd->ulpCommand == CMD_QUE_RING_BUF64_CN || - cmd->ulpCommand == CMD_CLOSE_XRI_CN || - cmd->ulpCommand == CMD_ABORT_XRI_CN) + if (ulp_command == CMD_QUE_RING_BUF_CN || + ulp_command == CMD_QUE_RING_BUF64_CN || + ulp_command == CMD_CLOSE_XRI_CN || + ulp_command == CMD_ABORT_XRI_CN || + ulp_command == CMD_ABORT_XRI_CX) continue; if (piocb->vport != vport) @@ -8116,7 +9523,6 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) if (vport == phba->pport) { list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list, list) { - cmd = &piocb->iocb; list_del_init(&piocb->list); list_add_tail(&piocb->list, &abort_list); } @@ -8184,22 +9590,25 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, struct ls_rjt stat; struct lpfc_nodelist *ndlp; uint32_t *pcmd; + u32 ulp_status, ulp_word4; - ndlp = cmdiocbp->context1; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + ndlp = cmdiocbp->ndlp; + if (!ndlp) return; - if (rspiocbp->iocb.ulpStatus == IOSTAT_LS_RJT) { + ulp_status = get_job_ulpstatus(phba, rspiocbp); + ulp_word4 = get_job_word4(phba, rspiocbp); + + if (ulp_status == IOSTAT_LS_RJT) { lsrjt_event.header.event_type = FC_REG_ELS_EVENT; lsrjt_event.header.subcategory = LPFC_EVENT_LSRJT_RCV; memcpy(lsrjt_event.header.wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name)); memcpy(lsrjt_event.header.wwnn, &ndlp->nlp_nodename, sizeof(struct lpfc_name)); - pcmd = (uint32_t *) (((struct lpfc_dmabuf *) - cmdiocbp->context2)->virt); + pcmd = (uint32_t *)cmdiocbp->cmd_dmabuf->virt; lsrjt_event.command = (pcmd != NULL) ? *pcmd : 0; - stat.un.lsRjtError = be32_to_cpu(rspiocbp->iocb.un.ulpWord[4]); + stat.un.ls_rjt_error_be = cpu_to_be32(ulp_word4); lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode; lsrjt_event.explanation = stat.un.b.lsRjtRsnCodeExp; fc_host_post_vendor_event(shost, @@ -8209,10 +9618,10 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, LPFC_NL_VENDOR_ID); return; } - if ((rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) || - (rspiocbp->iocb.ulpStatus == IOSTAT_FABRIC_BSY)) { + if (ulp_status == IOSTAT_NPORT_BSY || + ulp_status == IOSTAT_FABRIC_BSY) { fabric_event.event_type = FC_REG_FABRIC_EVENT; - if (rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) + if (ulp_status == IOSTAT_NPORT_BSY) fabric_event.subcategory = LPFC_EVENT_PORT_BUSY; else fabric_event.subcategory = LPFC_EVENT_FABRIC_BUSY; @@ -8234,7 +9643,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, * lpfc_send_els_event - Posts unsolicited els event * @vport: Pointer to vport object. * @ndlp: Pointer FC node object. - * @cmd: ELS command code. + * @payload: ELS command code type. * * This function posts an event when there is an incoming * unsolicited ELS command. @@ -8251,7 +9660,7 @@ lpfc_send_els_event(struct lpfc_vport *vport, if (*payload == ELS_CMD_LOGO) { logo_data = kmalloc(sizeof(struct lpfc_logo_event), GFP_KERNEL); if (!logo_data) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0148 Failed to allocate memory " "for LOGO event\n"); return; @@ -8261,7 +9670,7 @@ lpfc_send_els_event(struct lpfc_vport *vport, els_data = kmalloc(sizeof(struct lpfc_els_event_header), GFP_KERNEL); if (!els_data) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0149 Failed to allocate memory " "for ELS event\n"); return; @@ -8310,6 +9719,403 @@ lpfc_send_els_event(struct lpfc_vport *vport, } +DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_li_event_nm, fc_fpin_li_event_types, + FC_FPIN_LI_EVT_TYPES_INIT); + +DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_deli_event_nm, fc_fpin_deli_event_types, + FC_FPIN_DELI_EVT_TYPES_INIT); + +DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_congn_event_nm, fc_fpin_congn_event_types, + FC_FPIN_CONGN_EVT_TYPES_INIT); + +DECLARE_ENUM2STR_LOOKUP(lpfc_get_fpin_congn_severity_nm, + fc_fpin_congn_severity_types, + FC_FPIN_CONGN_SEVERITY_INIT); + + +/** + * lpfc_display_fpin_wwpn - Display WWPNs accessible by the attached port + * @phba: Pointer to phba object. + * @wwnlist: Pointer to list of WWPNs in FPIN payload + * @cnt: count of WWPNs in FPIN payload + * + * This routine is called by LI and PC descriptors. + * Limit the number of WWPNs displayed to 6 log messages, 6 per log message + */ +static void +lpfc_display_fpin_wwpn(struct lpfc_hba *phba, __be64 *wwnlist, u32 cnt) +{ + char buf[LPFC_FPIN_WWPN_LINE_SZ]; + __be64 wwn; + u64 wwpn; + int i, len; + int line = 0; + int wcnt = 0; + bool endit = false; + + len = scnprintf(buf, LPFC_FPIN_WWPN_LINE_SZ, "Accessible WWPNs:"); + for (i = 0; i < cnt; i++) { + /* Are we on the last WWPN */ + if (i == (cnt - 1)) + endit = true; + + /* Extract the next WWPN from the payload */ + wwn = *wwnlist++; + wwpn = be64_to_cpu(wwn); + len += scnprintf(buf + len, LPFC_FPIN_WWPN_LINE_SZ - len, + " %016llx", wwpn); + + /* Log a message if we are on the last WWPN + * or if we hit the max allowed per message. + */ + wcnt++; + if (wcnt == LPFC_FPIN_WWPN_LINE_CNT || endit) { + buf[len] = 0; + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "4686 %s\n", buf); + + /* Check if we reached the last WWPN */ + if (endit) + return; + + /* Limit the number of log message displayed per FPIN */ + line++; + if (line == LPFC_FPIN_WWPN_NUM_LINE) { + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "4687 %d WWPNs Truncated\n", + cnt - i - 1); + return; + } + + /* Start over with next log message */ + wcnt = 0; + len = scnprintf(buf, LPFC_FPIN_WWPN_LINE_SZ, + "Additional WWPNs:"); + } + } +} + +/** + * lpfc_els_rcv_fpin_li - Process an FPIN Link Integrity Event. + * @phba: Pointer to phba object. + * @tlv: Pointer to the Link Integrity Notification Descriptor. + * + * This function processes a Link Integrity FPIN event by logging a message. + **/ +static void +lpfc_els_rcv_fpin_li(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct fc_fn_li_desc *li = (struct fc_fn_li_desc *)tlv; + const char *li_evt_str; + u32 li_evt, cnt; + + li_evt = be16_to_cpu(li->event_type); + li_evt_str = lpfc_get_fpin_li_event_nm(li_evt); + cnt = be32_to_cpu(li->pname_count); + + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "4680 FPIN Link Integrity %s (x%x) " + "Detecting PN x%016llx Attached PN x%016llx " + "Duration %d mSecs Count %d Port Cnt %d\n", + li_evt_str, li_evt, + be64_to_cpu(li->detecting_wwpn), + be64_to_cpu(li->attached_wwpn), + be32_to_cpu(li->event_threshold), + be32_to_cpu(li->event_count), cnt); + + lpfc_display_fpin_wwpn(phba, (__be64 *)&li->pname_list, cnt); +} + +/** + * lpfc_els_rcv_fpin_del - Process an FPIN Delivery Event. + * @phba: Pointer to hba object. + * @tlv: Pointer to the Delivery Notification Descriptor TLV + * + * This function processes a Delivery FPIN event by logging a message. + **/ +static void +lpfc_els_rcv_fpin_del(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct fc_fn_deli_desc *del = (struct fc_fn_deli_desc *)tlv; + const char *del_rsn_str; + u32 del_rsn; + __be32 *frame; + + del_rsn = be16_to_cpu(del->deli_reason_code); + del_rsn_str = lpfc_get_fpin_deli_event_nm(del_rsn); + + /* Skip over desc_tag/desc_len header to payload */ + frame = (__be32 *)(del + 1); + + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "4681 FPIN Delivery %s (x%x) " + "Detecting PN x%016llx Attached PN x%016llx " + "DiscHdr0 x%08x " + "DiscHdr1 x%08x DiscHdr2 x%08x DiscHdr3 x%08x " + "DiscHdr4 x%08x DiscHdr5 x%08x\n", + del_rsn_str, del_rsn, + be64_to_cpu(del->detecting_wwpn), + be64_to_cpu(del->attached_wwpn), + be32_to_cpu(frame[0]), + be32_to_cpu(frame[1]), + be32_to_cpu(frame[2]), + be32_to_cpu(frame[3]), + be32_to_cpu(frame[4]), + be32_to_cpu(frame[5])); +} + +/** + * lpfc_els_rcv_fpin_peer_cgn - Process a FPIN Peer Congestion Event. + * @phba: Pointer to hba object. + * @tlv: Pointer to the Peer Congestion Notification Descriptor TLV + * + * This function processes a Peer Congestion FPIN event by logging a message. + **/ +static void +lpfc_els_rcv_fpin_peer_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct fc_fn_peer_congn_desc *pc = (struct fc_fn_peer_congn_desc *)tlv; + const char *pc_evt_str; + u32 pc_evt, cnt; + + pc_evt = be16_to_cpu(pc->event_type); + pc_evt_str = lpfc_get_fpin_congn_event_nm(pc_evt); + cnt = be32_to_cpu(pc->pname_count); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_ELS, + "4684 FPIN Peer Congestion %s (x%x) " + "Duration %d mSecs " + "Detecting PN x%016llx Attached PN x%016llx " + "Impacted Port Cnt %d\n", + pc_evt_str, pc_evt, + be32_to_cpu(pc->event_period), + be64_to_cpu(pc->detecting_wwpn), + be64_to_cpu(pc->attached_wwpn), + cnt); + + lpfc_display_fpin_wwpn(phba, (__be64 *)&pc->pname_list, cnt); +} + +/** + * lpfc_els_rcv_fpin_cgn - Process an FPIN Congestion notification + * @phba: Pointer to hba object. + * @tlv: Pointer to the Congestion Notification Descriptor TLV + * + * This function processes an FPIN Congestion Notifiction. The notification + * could be an Alarm or Warning. This routine feeds that data into driver's + * running congestion algorithm. It also processes the FPIN by + * logging a message. It returns 1 to indicate deliver this message + * to the upper layer or 0 to indicate don't deliver it. + **/ +static int +lpfc_els_rcv_fpin_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv) +{ + struct lpfc_cgn_info *cp; + struct fc_fn_congn_desc *cgn = (struct fc_fn_congn_desc *)tlv; + const char *cgn_evt_str; + u32 cgn_evt; + const char *cgn_sev_str; + u32 cgn_sev; + uint16_t value; + u32 crc; + bool nm_log = false; + int rc = 1; + + cgn_evt = be16_to_cpu(cgn->event_type); + cgn_evt_str = lpfc_get_fpin_congn_event_nm(cgn_evt); + cgn_sev = cgn->severity; + cgn_sev_str = lpfc_get_fpin_congn_severity_nm(cgn_sev); + + /* The driver only takes action on a Credit Stall or Oversubscription + * event type to engage the IO algorithm. The driver prints an + * unmaskable message only for Lost Credit and Credit Stall. + * TODO: Still need to have definition of host action on clear, + * lost credit and device specific event types. + */ + switch (cgn_evt) { + case FPIN_CONGN_LOST_CREDIT: + nm_log = true; + break; + case FPIN_CONGN_CREDIT_STALL: + nm_log = true; + fallthrough; + case FPIN_CONGN_OVERSUBSCRIPTION: + if (cgn_evt == FPIN_CONGN_OVERSUBSCRIPTION) + nm_log = false; + switch (cgn_sev) { + case FPIN_CONGN_SEVERITY_ERROR: + /* Take action here for an Alarm event */ + if (phba->cmf_active_mode != LPFC_CFG_OFF) { + if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_ALARM) { + /* Track of alarm cnt for SYNC_WQE */ + atomic_inc(&phba->cgn_sync_alarm_cnt); + } + /* Track alarm cnt for cgn_info regardless + * of whether CMF is configured for Signals + * or FPINs. + */ + atomic_inc(&phba->cgn_fabric_alarm_cnt); + goto cleanup; + } + break; + case FPIN_CONGN_SEVERITY_WARNING: + /* Take action here for a Warning event */ + if (phba->cmf_active_mode != LPFC_CFG_OFF) { + if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_WARN) { + /* Track of warning cnt for SYNC_WQE */ + atomic_inc(&phba->cgn_sync_warn_cnt); + } + /* Track warning cnt and freq for cgn_info + * regardless of whether CMF is configured for + * Signals or FPINs. + */ + atomic_inc(&phba->cgn_fabric_warn_cnt); +cleanup: + /* Save frequency in ms */ + phba->cgn_fpin_frequency = + be32_to_cpu(cgn->event_period); + value = phba->cgn_fpin_frequency; + if (phba->cgn_i) { + cp = (struct lpfc_cgn_info *) + phba->cgn_i->virt; + cp->cgn_alarm_freq = + cpu_to_le16(value); + cp->cgn_warn_freq = + cpu_to_le16(value); + crc = lpfc_cgn_calc_crc32 + (cp, + LPFC_CGN_INFO_SZ, + LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); + } + + /* Don't deliver to upper layer since + * driver took action on this tlv. + */ + rc = 0; + } + break; + } + break; + } + + /* Change the log level to unmaskable for the following event types. */ + lpfc_printf_log(phba, (nm_log ? KERN_WARNING : KERN_INFO), + LOG_CGN_MGMT | LOG_ELS, + "4683 FPIN CONGESTION %s type %s (x%x) Event " + "Duration %d mSecs\n", + cgn_sev_str, cgn_evt_str, cgn_evt, + be32_to_cpu(cgn->event_period)); + return rc; +} + +void +lpfc_els_rcv_fpin(struct lpfc_vport *vport, void *p, u32 fpin_length) +{ + struct lpfc_hba *phba = vport->phba; + struct fc_els_fpin *fpin = (struct fc_els_fpin *)p; + struct fc_tlv_desc *tlv, *first_tlv, *current_tlv; + const char *dtag_nm; + int desc_cnt = 0, bytes_remain, cnt; + u32 dtag, deliver = 0; + int len; + + /* FPINs handled only if we are in the right discovery state */ + if (vport->port_state < LPFC_DISC_AUTH) + return; + + /* make sure there is the full fpin header */ + if (fpin_length < sizeof(struct fc_els_fpin)) + return; + + /* Sanity check descriptor length. The desc_len value does not + * include space for the ELS command and the desc_len fields. + */ + len = be32_to_cpu(fpin->desc_len); + if (fpin_length < len + sizeof(struct fc_els_fpin)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "4671 Bad ELS FPIN length %d: %d\n", + len, fpin_length); + return; + } + + tlv = (struct fc_tlv_desc *)&fpin->fpin_desc[0]; + first_tlv = tlv; + bytes_remain = fpin_length - offsetof(struct fc_els_fpin, fpin_desc); + bytes_remain = min_t(u32, bytes_remain, be32_to_cpu(fpin->desc_len)); + + /* process each descriptor separately */ + while (bytes_remain >= FC_TLV_DESC_HDR_SZ && + bytes_remain >= FC_TLV_DESC_SZ_FROM_LENGTH(tlv)) { + dtag = be32_to_cpu(tlv->desc_tag); + switch (dtag) { + case ELS_DTAG_LNK_INTEGRITY: + lpfc_els_rcv_fpin_li(phba, tlv); + deliver = 1; + break; + case ELS_DTAG_DELIVERY: + lpfc_els_rcv_fpin_del(phba, tlv); + deliver = 1; + break; + case ELS_DTAG_PEER_CONGEST: + lpfc_els_rcv_fpin_peer_cgn(phba, tlv); + deliver = 1; + break; + case ELS_DTAG_CONGESTION: + deliver = lpfc_els_rcv_fpin_cgn(phba, tlv); + break; + default: + dtag_nm = lpfc_get_tlv_dtag_nm(dtag); + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "4678 unknown FPIN descriptor[%d]: " + "tag x%x (%s)\n", + desc_cnt, dtag, dtag_nm); + + /* If descriptor is bad, drop the rest of the data */ + return; + } + lpfc_cgn_update_stat(phba, dtag); + cnt = be32_to_cpu(tlv->desc_len); + + /* Sanity check descriptor length. The desc_len value does not + * include space for the desc_tag and the desc_len fields. + */ + len -= (cnt + sizeof(struct fc_tlv_desc)); + if (len < 0) { + dtag_nm = lpfc_get_tlv_dtag_nm(dtag); + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "4672 Bad FPIN descriptor TLV length " + "%d: %d %d %s\n", + cnt, len, fpin_length, dtag_nm); + return; + } + + current_tlv = tlv; + bytes_remain -= FC_TLV_DESC_SZ_FROM_LENGTH(tlv); + tlv = fc_tlv_next_desc(tlv); + + /* Format payload such that the FPIN delivered to the + * upper layer is a single descriptor FPIN. + */ + if (desc_cnt) + memcpy(first_tlv, current_tlv, + (cnt + sizeof(struct fc_els_fpin))); + + /* Adjust the length so that it only reflects a + * single descriptor FPIN. + */ + fpin_length = cnt + sizeof(struct fc_els_fpin); + fpin->desc_len = cpu_to_be32(fpin_length); + fpin_length += sizeof(struct fc_els_fpin); /* the entire FPIN */ + + /* Send every descriptor individually to the upper layer */ + if (deliver) + fc_host_fpin_rcv(lpfc_shost_from_vport(vport), + fpin_length, (char *)fpin); + desc_cnt++; + } +} + /** * lpfc_els_unsol_buffer - Process an unsolicited event data buffer * @phba: pointer to lpfc hba data structure. @@ -8328,29 +10134,34 @@ static void lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) { - struct Scsi_Host *shost; struct lpfc_nodelist *ndlp; struct ls_rjt stat; - uint32_t *payload; - uint32_t cmd, did, newnode; + u32 *payload, payload_len; + u32 cmd = 0, did = 0, newnode, status = 0; uint8_t rjt_exp, rjt_err = 0, init_link = 0; - IOCB_t *icmd = &elsiocb->iocb; + struct lpfc_wcqe_complete *wcqe_cmpl = NULL; LPFC_MBOXQ_t *mbox; - if (!vport || !(elsiocb->context2)) + if (!vport || !elsiocb->cmd_dmabuf) goto dropit; newnode = 0; - payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; + wcqe_cmpl = &elsiocb->wcqe_cmpl; + payload = elsiocb->cmd_dmabuf->virt; + if (phba->sli_rev == LPFC_SLI_REV4) + payload_len = wcqe_cmpl->total_data_placed; + else + payload_len = elsiocb->iocb.unsli3.rcvsli3.acc_len; + status = get_job_ulpstatus(phba, elsiocb); cmd = *payload; if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) - lpfc_post_buffer(phba, pring, 1); + lpfc_sli3_post_buffer(phba, pring, 1); - did = icmd->un.rcvels.remoteID; - if (icmd->ulpStatus) { + did = get_job_els_rsp64_did(phba, elsiocb); + if (status) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, "RCV Unsol ELS: status:x%x/x%x did:x%x", - icmd->ulpStatus, icmd->un.ulpWord[4], did); + status, get_job_word4(phba, elsiocb), did); goto dropit; } @@ -8377,20 +10188,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, newnode = 1; if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) ndlp->nlp_type |= NLP_FABRIC; - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto dropit; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - newnode = 1; - if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) - ndlp->nlp_type |= NLP_FABRIC; } else if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { - /* This is similar to the new node path */ - ndlp = lpfc_nlp_get(ndlp); - if (!ndlp) - goto dropit; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); newnode = 1; } @@ -8401,15 +10199,18 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * Do not process any unsolicited ELS commands * if the ndlp is in DEV_LOSS */ - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); if (ndlp->nlp_flag & NLP_IN_DEV_LOSS) { - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); + if (newnode) + lpfc_nlp_put(ndlp); goto dropit; } - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); - elsiocb->context1 = lpfc_nlp_get(ndlp); + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) + goto dropit; elsiocb->vport = vport; if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) { @@ -8418,9 +10219,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* ELS command <elsCmd> received from NPORT <did> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0112 ELS command x%x received from NPORT x%x " - "Data: x%x x%x x%x x%x\n", - cmd, did, vport->port_state, vport->fc_flag, - vport->fc_myDID, vport->fc_prevDID); + "refcnt %d Data: x%x x%x x%x x%x\n", + cmd, did, kref_read(&ndlp->kref), vport->port_state, + vport->fc_flag, vport->fc_myDID, vport->fc_prevDID); /* reject till our FLOGI completes or PLOGI assigned DID via PT2PT */ if ((vport->port_state < LPFC_FABRIC_CFG_LINK) && @@ -8446,7 +10247,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * the vfi. This is done in lpfc_rcv_plogi but * that is called after the reg_vfi. */ - vport->fc_myDID = elsiocb->iocb.un.rcvels.parmRo; + vport->fc_myDID = + bf_get(els_rsp64_sid, + &elsiocb->wqe.xmit_els_rsp); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3312 Remote port assigned DID x%x " "%x\n", vport->fc_myDID, @@ -8471,9 +10274,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_TARGET_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PLOGI); @@ -8499,8 +10302,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } lpfc_els_rcv_flogi(vport, elsiocb, ndlp); + /* retain node if our response is deferred */ + if (phba->defer_flogi_acc_flag) + break; if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_LOGO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8515,6 +10322,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; } lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO); + if (newnode) + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_PRLO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8542,7 +10352,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRSCN++; lpfc_els_rcv_rscn(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_ADISC: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8620,7 +10431,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvLIRR++; lpfc_els_rcv_lirr(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RLS: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8630,17 +10442,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRLS++; lpfc_els_rcv_rls(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_RPS: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RPS: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvRPS++; - lpfc_els_rcv_rps(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RPL: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8650,7 +10453,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRPL++; lpfc_els_rcv_rpl(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RNID: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8660,7 +10464,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRNID++; lpfc_els_rcv_rnid(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RTV: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8669,7 +10474,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRTV++; lpfc_els_rcv_rtv(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_RRQ: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8679,7 +10485,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRRQ++; lpfc_els_rcv_rrq(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_ECHO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8689,7 +10496,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvECHO++; lpfc_els_rcv_echo(vport, elsiocb, ndlp); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; case ELS_CMD_REC: /* receive this due to exchange closed */ @@ -8697,12 +10505,31 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_exp = LSEXP_INVALID_OX_RX; break; case ELS_CMD_FPIN: - /* - * Received FPIN from fabric - pass it to the - * transport FPIN handler. - */ - fc_host_fpin_rcv(shost, elsiocb->iocb.unsli3.rcvsli3.acc_len, - (char *)payload); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, + "RCV FPIN: did:x%x/ste:x%x flg:x%x", + did, vport->port_state, ndlp->nlp_flag); + + lpfc_els_rcv_fpin(vport, (struct fc_els_fpin *)payload, + payload_len); + + /* There are no replies, so no rjt codes */ + break; + case ELS_CMD_EDC: + lpfc_els_rcv_edc(vport, elsiocb, ndlp); + break; + case ELS_CMD_RDF: + phba->fc_stat.elsRcvRDF++; + /* Accept RDF only from fabric controller */ + if (did != Fabric_Cntl_DID) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, + "1115 Received RDF from invalid DID " + "x%x\n", did); + rjt_err = LSRJT_PROTOCOL_ERR; + rjt_exp = LSEXP_NOTHING_MORE; + goto lsrjt; + } + + lpfc_els_rcv_rdf(vport, elsiocb, ndlp); break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -8714,11 +10541,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_exp = LSEXP_NOTHING_MORE; /* Unknown ELS command <elsCmd> received from NPORT <did> */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0115 Unknown ELS command x%x " "received from NPORT x%x\n", cmd, did); if (newnode) - lpfc_nlp_put(ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); break; } @@ -8729,11 +10557,16 @@ lsrjt: stat.un.b.lsRjtRsnCode = rjt_err; stat.un.b.lsRjtRsnCodeExp = rjt_exp; lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp, - NULL); + NULL); + /* Remove the reference from above for new nodes. */ + if (newnode) + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); } - lpfc_nlp_put(elsiocb->context1); - elsiocb->context1 = NULL; + /* Release the reference on this elsiocb, not the ndlp. */ + lpfc_nlp_put(elsiocb->ndlp); + elsiocb->ndlp = NULL; /* Special case. Driver received an unsolicited command that * unsupportable given the driver's current state. Reset the @@ -8759,10 +10592,11 @@ lsrjt: dropit: if (vport && !(vport->load_flag & FC_UNLOADING)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0111 Dropping received ELS cmd " - "Data: x%x x%x x%x\n", - icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout); + "Data: x%x x%x x%x x%x\n", + cmd, status, get_job_word4(phba, elsiocb), did); + phba->fc_stat.elsRcvDrop++; } @@ -8782,77 +10616,93 @@ void lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *elsiocb) { - struct lpfc_vport *vport = phba->pport; - IOCB_t *icmd = &elsiocb->iocb; + struct lpfc_vport *vport = elsiocb->vport; + u32 ulp_command, status, parameter, bde_count = 0; + IOCB_t *icmd; + struct lpfc_wcqe_complete *wcqe_cmpl = NULL; + struct lpfc_dmabuf *bdeBuf1 = elsiocb->cmd_dmabuf; + struct lpfc_dmabuf *bdeBuf2 = elsiocb->bpl_dmabuf; dma_addr_t paddr; - struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2; - struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3; - elsiocb->context1 = NULL; - elsiocb->context2 = NULL; - elsiocb->context3 = NULL; + elsiocb->cmd_dmabuf = NULL; + elsiocb->rsp_dmabuf = NULL; + elsiocb->bpl_dmabuf = NULL; - if (icmd->ulpStatus == IOSTAT_NEED_BUFFER) { + wcqe_cmpl = &elsiocb->wcqe_cmpl; + ulp_command = get_job_cmnd(phba, elsiocb); + status = get_job_ulpstatus(phba, elsiocb); + parameter = get_job_word4(phba, elsiocb); + if (phba->sli_rev == LPFC_SLI_REV4) + bde_count = wcqe_cmpl->word3; + else + bde_count = elsiocb->iocb.ulpBdeCount; + + if (status == IOSTAT_NEED_BUFFER) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); - } else if (icmd->ulpStatus == IOSTAT_LOCAL_REJECT && - (icmd->un.ulpWord[4] & IOERR_PARAM_MASK) == + } else if (status == IOSTAT_LOCAL_REJECT && + (parameter & IOERR_PARAM_MASK) == IOERR_RCV_BUFFER_WAITING) { phba->fc_stat.NoRcvBuf++; /* Not enough posted buffers; Try posting more buffers */ if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_post_buffer(phba, pring, 0); + lpfc_sli3_post_buffer(phba, pring, 0); return; } - if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - (icmd->ulpCommand == CMD_IOCB_RCV_ELS64_CX || - icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) { - if (icmd->unsli3.rcvsli3.vpi == 0xffff) - vport = phba->pport; - else - vport = lpfc_find_vport_by_vpid(phba, + if (phba->sli_rev == LPFC_SLI_REV3) { + icmd = &elsiocb->iocb; + if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && + (ulp_command == CMD_IOCB_RCV_ELS64_CX || + ulp_command == CMD_IOCB_RCV_SEQ64_CX)) { + if (icmd->unsli3.rcvsli3.vpi == 0xffff) + vport = phba->pport; + else + vport = lpfc_find_vport_by_vpid(phba, icmd->unsli3.rcvsli3.vpi); + } } /* If there are no BDEs associated * with this IOCB, there is nothing to do. */ - if (icmd->ulpBdeCount == 0) + if (bde_count == 0) return; - /* type of ELS cmd is first 32bit word - * in packet - */ + /* Account for SLI2 or SLI3 and later unsolicited buffering */ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - elsiocb->context2 = bdeBuf1; + elsiocb->cmd_dmabuf = bdeBuf1; + if (bde_count == 2) + elsiocb->bpl_dmabuf = bdeBuf2; } else { + icmd = &elsiocb->iocb; paddr = getPaddr(icmd->un.cont64[0].addrHigh, icmd->un.cont64[0].addrLow); - elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring, - paddr); + elsiocb->cmd_dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, + paddr); + if (bde_count == 2) { + paddr = getPaddr(icmd->un.cont64[1].addrHigh, + icmd->un.cont64[1].addrLow); + elsiocb->bpl_dmabuf = lpfc_sli_ringpostbuf_get(phba, + pring, + paddr); + } } lpfc_els_unsol_buffer(phba, pring, vport, elsiocb); /* * The different unsolicited event handlers would tell us - * if they are done with "mp" by setting context2 to NULL. + * if they are done with "mp" by setting cmd_dmabuf to NULL. */ - if (elsiocb->context2) { - lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2); - elsiocb->context2 = NULL; - } - - /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */ - if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) && - icmd->ulpBdeCount == 2) { - elsiocb->context2 = bdeBuf2; - lpfc_els_unsol_buffer(phba, pring, vport, elsiocb); - /* free mp if we are done with it */ - if (elsiocb->context2) { - lpfc_in_buf_free(phba, elsiocb->context2); - elsiocb->context2 = NULL; - } + if (elsiocb->cmd_dmabuf) { + lpfc_in_buf_free(phba, elsiocb->cmd_dmabuf); + elsiocb->cmd_dmabuf = NULL; + } + + if (elsiocb->bpl_dmabuf) { + lpfc_in_buf_free(phba, elsiocb->bpl_dmabuf); + elsiocb->bpl_dmabuf = NULL; } + } static void @@ -8873,13 +10723,9 @@ lpfc_start_fdmi(struct lpfc_vport *vport) return; } } - if (!NLP_CHK_NODE_ACT(ndlp)) - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE); - if (ndlp) { - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); - } + lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); + lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); } /** @@ -8909,9 +10755,9 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) spin_lock_irq(shost->host_lock); if (vport->fc_flag & FC_DISC_DELAYED) { spin_unlock_irq(shost->host_lock); - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "3334 Delay fc port discovery for %d seconds\n", - phba->fc_ratov); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "3334 Delay fc port discovery for %d secs\n", + phba->fc_ratov); mod_timer(&vport->delayed_disc_tmo, jiffies + msecs_to_jiffies(1000 * phba->fc_ratov)); return; @@ -8927,30 +10773,19 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) return; } lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0251 NameServer login: no memory\n"); return; } - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) { - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - lpfc_disc_start(vport); - return; - } - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0348 NameServer login: node freed\n"); - return; - } } + ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) { lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0252 Cannot issue NameServer login\n"); return; } @@ -8978,7 +10813,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; + struct lpfc_nodelist *ndlp = pmb->ctx_ndlp; MAILBOX_t *mb = &pmb->u.mb; int rc; @@ -8987,7 +10822,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_unlock_irq(shost->host_lock); if (mb->mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0915 Register VPI failed : Status: x%x" " upd bit: x%x \n", mb->mbxStatus, mb->un.varRegVpi.upd); @@ -9017,15 +10852,15 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, - KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "2732 Failed to issue INIT_VPI" " mailbox command\n"); } else { lpfc_nlp_put(ndlp); return; } - /* fall through */ + fallthrough; default: /* Try to recover from this error */ if (phba->sli_rev == LPFC_SLI_REV4) @@ -9063,8 +10898,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_start_fdiscs(phba); lpfc_do_scr_ns_plogi(phba, vport); } - } else + } else { lpfc_do_scr_ns_plogi(phba, vport); + } } mbox_err_exit: /* Now, we decrement the ndlp reference count held for this @@ -9097,6 +10933,11 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, lpfc_reg_vpi(vport, mbox); mbox->vport = vport; mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) { + mempool_free(mbox, phba->mbox_mem_pool); + goto mbox_err_exit; + } + mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport; if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED) { @@ -9106,12 +10947,12 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, lpfc_nlp_put(ndlp); mempool_free(mbox, phba->mbox_mem_pool); - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0253 Register VPI: Can't send mbox\n"); goto mbox_err_exit; } } else { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0254 Register VPI: no memory\n"); goto mbox_err_exit; } @@ -9169,7 +11010,6 @@ void lpfc_retry_pport_discovery(struct lpfc_hba *phba) { struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; /* Cancel the all vports retry delay retry timers */ lpfc_cancel_all_vport_retry_delay_timer(phba); @@ -9179,11 +11019,10 @@ lpfc_retry_pport_discovery(struct lpfc_hba *phba) if (!ndlp) return; - shost = lpfc_shost_from_vport(phba->pport); mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; phba->pport->port_state = LPFC_FLOGI; return; @@ -9203,9 +11042,11 @@ lpfc_fabric_login_reqd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); - if ((rspiocb->iocb.ulpStatus != IOSTAT_FABRIC_RJT) || - (rspiocb->iocb.un.ulpWord[4] != RJT_LOGIN_REQUIRED)) + if (ulp_status != IOSTAT_FABRIC_RJT || + ulp_word4 != RJT_LOGIN_REQUIRED) return 0; else return 1; @@ -9237,18 +11078,21 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; struct lpfc_nodelist *np; struct lpfc_nodelist *next_np; - IOCB_t *irsp = &rspiocb->iocb; struct lpfc_iocbq *piocb; - struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp; + struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf, *prsp; struct serv_parm *sp; uint8_t fabric_param_changed; + u32 ulp_status, ulp_word4; + + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0123 FDISC completes. x%x/x%x prevDID: x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], + ulp_status, ulp_word4, vport->fc_prevDID); /* Since all FDISCs are being single threaded, we * must reset the discovery timer for ALL vports @@ -9260,9 +11104,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "FDISC cmpl: status:x%x/x%x prevdid:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID); + ulp_status, ulp_word4, vport->fc_prevDID); - if (irsp->ulpStatus) { + if (ulp_status) { if (lpfc_fabric_login_reqd(phba, cmdiocb, rspiocb)) { lpfc_retry_pport_discovery(phba); @@ -9273,11 +11117,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; /* FDISC failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0126 FDISC failed. (x%x/x%x)\n", - irsp->ulpStatus, irsp->un.ulpWord[4]); + ulp_status, ulp_word4); goto fdisc_failed; } + + lpfc_check_nlp_post_devloss(vport, ndlp); + spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_CVL_RCVD; vport->fc_flag &= ~FC_VPORT_LOGO_RCVD; @@ -9286,7 +11133,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, vport->fc_flag |= FC_PUBLIC_LOOP; spin_unlock_irq(shost->host_lock); - vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; + vport->fc_myDID = ulp_word4 & Mask_DID; lpfc_vport_set_state(vport, FC_VPORT_ACTIVE); prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); if (!prsp) @@ -9305,13 +11152,12 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ list_for_each_entry_safe(np, next_np, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp) || - (np->nlp_state != NLP_STE_NPR_NODE) || + if ((np->nlp_state != NLP_STE_NPR_NODE) || !(np->nlp_flag & NLP_NPR_ADISC)) continue; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); np->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_unreg_rpi(vport, np); } lpfc_cleanup_pending_mbox(vport); @@ -9334,6 +11180,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * to update the MAC address. */ lpfc_register_new_vport(phba, vport, ndlp); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); goto out; } @@ -9343,16 +11190,22 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_register_new_vport(phba, vport, ndlp); else lpfc_do_scr_ns_plogi(phba, vport); + + /* The FDISC completed successfully. Move the fabric ndlp to + * UNMAPPED state and register with the transport. + */ + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); goto out; + fdisc_failed: if (vport->fc_vport && (vport->fc_vport->vport_state != FC_VPORT_NO_FABRIC_RSCS)) lpfc_vport_set_state(vport, FC_VPORT_FAILED); /* Cancel discovery timer */ lpfc_can_disctmo(vport); - lpfc_nlp_put(ndlp); out: lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } /** @@ -9366,10 +11219,9 @@ out: * routine to issue the IOCB, which makes sure only one outstanding fabric * IOCB will be sent off HBA at any given time. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the FDISC ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the FDISC ELS command. * * Return code * 0 - Successfully issued fdisc iocb command @@ -9381,6 +11233,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_hba *phba = vport->phba; IOCB_t *icmd; + union lpfc_wqe128 *wqe = NULL; struct lpfc_iocbq *elsiocb; struct serv_parm *sp; uint8_t *pcmd; @@ -9395,25 +11248,24 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ELS_CMD_FDISC); if (!elsiocb) { lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0255 Issue FDISC: no IOCB\n"); return 1; } - icmd = &elsiocb->iocb; - icmd->un.elsreq64.myID = 0; - icmd->un.elsreq64.fl = 1; - - /* - * SLI3 ports require a different context type value than SLI4. - * Catch SLI3 ports here and override the prep. - */ - if (phba->sli_rev == LPFC_SLI_REV3) { + if (phba->sli_rev == LPFC_SLI_REV4) { + wqe = &elsiocb->wqe; + bf_set(els_req64_sid, &wqe->els_req, 0); + bf_set(els_req64_sp, &wqe->els_req, 1); + } else { + icmd = &elsiocb->iocb; + icmd->un.elsreq64.myID = 0; + icmd->un.elsreq64.fl = 1; icmd->ulpCt_h = 1; icmd->ulpCt_l = 0; } - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_FDISC; pcmd += sizeof(uint32_t); /* CSP Word 1 */ memcpy(pcmd, &vport->phba->pport->fc_sparam, sizeof(struct serv_parm)); @@ -9439,22 +11291,31 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_set_disctmo(vport); phba->fc_stat.elsXmitFDISC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_fdisc; + elsiocb->cmd_cmpl = lpfc_cmpl_els_fdisc; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue FDISC: did:x%x", did, 0, 0); + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) + goto err_out; + rc = lpfc_issue_fabric_iocb(phba, elsiocb); if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0256 Issue FDISC: Cannot send IOCB\n"); - return 1; + lpfc_nlp_put(ndlp); + goto err_out; } + lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING); return 0; + + err_out: + lpfc_els_free_iocb(phba, elsiocb); + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0256 Issue FDISC: Cannot send IOCB\n"); + return 1; } /** @@ -9479,33 +11340,56 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; struct lpfc_nodelist *ndlp; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + u32 ulp_status, ulp_word4, did, tmo; - ndlp = (struct lpfc_nodelist *)cmdiocb->context1; - irsp = &rspiocb->iocb; - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "LOGO npiv cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID); + ndlp = cmdiocb->ndlp; - lpfc_els_free_iocb(phba, cmdiocb); - vport->unreg_vpi_cmpl = VPORT_ERROR; + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); - /* Trigger the release of the ndlp after logo */ - lpfc_nlp_put(ndlp); + if (phba->sli_rev == LPFC_SLI_REV4) { + did = get_job_els_rsp64_did(phba, cmdiocb); + tmo = get_wqe_tmo(cmdiocb); + } else { + irsp = &rspiocb->iocb; + did = get_job_els_rsp64_did(phba, rspiocb); + tmo = irsp->ulpTimeout; + } + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "LOGO npiv cmpl: status:x%x/x%x did:x%x", + ulp_status, ulp_word4, did); /* NPIV LOGO completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "2928 NPIV LOGO completes to NPort x%x " - "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, vport->num_disc_nodes); + "Data: x%x x%x x%x x%x x%x x%x x%x\n", + ndlp->nlp_DID, ulp_status, ulp_word4, + tmo, vport->num_disc_nodes, + kref_read(&ndlp->kref), ndlp->nlp_flag, + ndlp->fc4_xpt_flags); - if (irsp->ulpStatus == IOSTAT_SUCCESS) { + if (ulp_status == IOSTAT_SUCCESS) { spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_NDISC_ACTIVE; vport->fc_flag &= ~FC_FABRIC; spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); } + + if (ndlp->save_flags & NLP_WAIT_FOR_LOGO) { + /* Wake up lpfc_vport_delete if waiting...*/ + if (ndlp->logo_waitq) + wake_up(ndlp->logo_waitq); + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~(NLP_ISSUE_LOGO | NLP_LOGO_SND); + ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO; + spin_unlock_irq(&ndlp->lock); + } + + /* Safe to release resources now. */ + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); } /** @@ -9515,10 +11399,9 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * * This routine issues a LOGO ELS command to an @ndlp off a @vport. * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the LOGO ELS command. + * Note that the ndlp reference count will be incremented by 1 for holding the + * ndlp and the reference to ndlp will be stored into the ndlp field of + * the IOCB for the completion callback function to the LOGO ELS command. * * Return codes * 0 - Successfully issued logo off the @vport @@ -9527,7 +11410,7 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, int lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + int rc = 0; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; @@ -9539,7 +11422,7 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!elsiocb) return 1; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); + pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; pcmd += sizeof(uint32_t); @@ -9552,24 +11435,34 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "Issue LOGO npiv did:x%x flg:x%x", ndlp->nlp_DID, ndlp->nlp_flag, 0); - elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo; - spin_lock_irq(shost->host_lock); + elsiocb->cmd_cmpl = lpfc_cmpl_els_npiv_logo; + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); - return 1; + goto err; + } + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + goto err; } return 0; + +err: + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_LOGO_SND; + spin_unlock_irq(&ndlp->lock); + return 1; } /** * lpfc_fabric_block_timeout - Handler function to the fabric block timer - * @ptr: holder for the timer function associated data. + * @t: timer context used to obtain the lpfc hba. * * This routine is invoked by the fabric iocb block timer after * timeout. It posts the fabric iocb block timeout event by setting the @@ -9612,7 +11505,6 @@ lpfc_resume_fabric_iocbs(struct lpfc_hba *phba) struct lpfc_iocbq *iocb; unsigned long iflags; int ret; - IOCB_t *cmd; repeat: iocb = NULL; @@ -9627,31 +11519,28 @@ repeat: } spin_unlock_irqrestore(&phba->hbalock, iflags); if (iocb) { - iocb->fabric_iocb_cmpl = iocb->iocb_cmpl; - iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb; - iocb->iocb_flag |= LPFC_IO_FABRIC; + iocb->fabric_cmd_cmpl = iocb->cmd_cmpl; + iocb->cmd_cmpl = lpfc_cmpl_fabric_iocb; + iocb->cmd_flag |= LPFC_IO_FABRIC; lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD, - "Fabric sched1: ste:x%x", - iocb->vport->port_state, 0, 0); + "Fabric sched1: ste:x%x", + iocb->vport->port_state, 0, 0); ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0); if (ret == IOCB_ERROR) { - iocb->iocb_cmpl = iocb->fabric_iocb_cmpl; - iocb->fabric_iocb_cmpl = NULL; - iocb->iocb_flag &= ~LPFC_IO_FABRIC; - cmd = &iocb->iocb; - cmd->ulpStatus = IOSTAT_LOCAL_REJECT; - cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - iocb->iocb_cmpl(phba, iocb, iocb); + iocb->cmd_cmpl = iocb->fabric_cmd_cmpl; + iocb->fabric_cmd_cmpl = NULL; + iocb->cmd_flag &= ~LPFC_IO_FABRIC; + set_job_ulpstatus(iocb, IOSTAT_LOCAL_REJECT); + iocb->wcqe_cmpl.parameter = IOERR_SLI_ABORTED; + iocb->cmd_cmpl(phba, iocb, iocb); atomic_dec(&phba->fabric_iocb_count); goto repeat; } } - - return; } /** @@ -9702,26 +11591,27 @@ lpfc_block_fabric_iocbs(struct lpfc_hba *phba) * @rspiocb: pointer to lpfc response iocb data structure. * * This routine is the callback function that is put to the fabric iocb's - * callback function pointer (iocb->iocb_cmpl). The original iocb's callback - * function pointer has been stored in iocb->fabric_iocb_cmpl. This callback + * callback function pointer (iocb->cmd_cmpl). The original iocb's callback + * function pointer has been stored in iocb->fabric_cmd_cmpl. This callback * function first restores and invokes the original iocb's callback function * and then invokes the lpfc_resume_fabric_iocbs() routine to issue the next * fabric bound iocb from the driver internal fabric iocb list onto the wire. **/ static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) + struct lpfc_iocbq *rspiocb) { struct ls_rjt stat; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); - BUG_ON((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC); + WARN_ON((cmdiocb->cmd_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC); - switch (rspiocb->iocb.ulpStatus) { + switch (ulp_status) { case IOSTAT_NPORT_RJT: case IOSTAT_FABRIC_RJT: - if (rspiocb->iocb.un.ulpWord[4] & RJT_UNAVAIL_TEMP) { + if (ulp_word4 & RJT_UNAVAIL_TEMP) lpfc_block_fabric_iocbs(phba); - } break; case IOSTAT_NPORT_BSY: @@ -9730,8 +11620,8 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, break; case IOSTAT_LS_RJT: - stat.un.lsRjtError = - be32_to_cpu(rspiocb->iocb.un.ulpWord[4]); + stat.un.ls_rjt_error_be = + cpu_to_be32(ulp_word4); if ((stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC) || (stat.un.b.lsRjtRsnCode == LSRJT_LOGICAL_BSY)) lpfc_block_fabric_iocbs(phba); @@ -9740,10 +11630,10 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, BUG_ON(atomic_read(&phba->fabric_iocb_count) == 0); - cmdiocb->iocb_cmpl = cmdiocb->fabric_iocb_cmpl; - cmdiocb->fabric_iocb_cmpl = NULL; - cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC; - cmdiocb->iocb_cmpl(phba, cmdiocb, rspiocb); + cmdiocb->cmd_cmpl = cmdiocb->fabric_cmd_cmpl; + cmdiocb->fabric_cmd_cmpl = NULL; + cmdiocb->cmd_flag &= ~LPFC_IO_FABRIC; + cmdiocb->cmd_cmpl(phba, cmdiocb, rspiocb); atomic_dec(&phba->fabric_iocb_count); if (!test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags)) { @@ -9794,20 +11684,20 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) atomic_inc(&phba->fabric_iocb_count); spin_unlock_irqrestore(&phba->hbalock, iflags); if (ready) { - iocb->fabric_iocb_cmpl = iocb->iocb_cmpl; - iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb; - iocb->iocb_flag |= LPFC_IO_FABRIC; + iocb->fabric_cmd_cmpl = iocb->cmd_cmpl; + iocb->cmd_cmpl = lpfc_cmpl_fabric_iocb; + iocb->cmd_flag |= LPFC_IO_FABRIC; lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD, - "Fabric sched2: ste:x%x", - iocb->vport->port_state, 0, 0); + "Fabric sched2: ste:x%x", + iocb->vport->port_state, 0, 0); ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0); if (ret == IOCB_ERROR) { - iocb->iocb_cmpl = iocb->fabric_iocb_cmpl; - iocb->fabric_iocb_cmpl = NULL; - iocb->iocb_flag &= ~LPFC_IO_FABRIC; + iocb->cmd_cmpl = iocb->fabric_cmd_cmpl; + iocb->fabric_cmd_cmpl = NULL; + iocb->cmd_flag &= ~LPFC_IO_FABRIC; atomic_dec(&phba->fabric_iocb_count); } } else { @@ -9827,7 +11717,7 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) * driver internal fabric IOCB list. The list contains fabric IOCBs to be * issued to the ELS IOCB ring. This abort function walks the fabric IOCB * list, removes each IOCB associated with the @vport off the list, set the - * status feild to IOSTAT_LOCAL_REJECT, and invokes the callback function + * status field to IOSTAT_LOCAL_REJECT, and invokes the callback function * associated with the IOCB. **/ static void lpfc_fabric_abort_vport(struct lpfc_vport *vport) @@ -9860,7 +11750,7 @@ static void lpfc_fabric_abort_vport(struct lpfc_vport *vport) * driver internal fabric IOCB list. The list contains fabric IOCBs to be * issued to the ELS IOCB ring. This abort function walks the fabric IOCB * list, removes each IOCB associated with the @ndlp off the list, set the - * status feild to IOSTAT_LOCAL_REJECT, and invokes the callback function + * status field to IOSTAT_LOCAL_REJECT, and invokes the callback function * associated with the IOCB. **/ void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp) @@ -9897,7 +11787,7 @@ void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp) * This routine aborts all the IOCBs currently on the driver internal * fabric IOCB list. The list contains fabric IOCBs to be issued to the ELS * IOCB ring. This function takes the entire IOCB list off the fabric IOCB - * list, removes IOCBs off the list, set the status feild to + * list, removes IOCBs off the list, set the status field to * IOSTAT_LOCAL_REJECT, and invokes the callback function associated with * the IOCB. **/ @@ -9926,17 +11816,31 @@ lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; + struct lpfc_nodelist *ndlp = NULL; unsigned long iflag = 0; - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.sgl_list_lock); + spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock, iflag); list_for_each_entry_safe(sglq_entry, sglq_next, &phba->sli4_hba.lpfc_abts_els_sgl_list, list) { - if (sglq_entry->ndlp && sglq_entry->ndlp->vport == vport) + if (sglq_entry->ndlp && sglq_entry->ndlp->vport == vport) { + lpfc_nlp_put(sglq_entry->ndlp); + ndlp = sglq_entry->ndlp; sglq_entry->ndlp = NULL; + + /* If the xri on the abts_els_sgl list is for the Fport + * node and the vport is unloading, the xri aborted wcqe + * likely isn't coming back. Just release the sgl. + */ + if ((vport->load_flag & FC_UNLOADING) && + ndlp->nlp_DID == Fabric_DID) { + list_del(&sglq_entry->list); + sglq_entry->state = SGL_FREED; + list_add_tail(&sglq_entry->list, + &phba->sli4_hba.lpfc_els_sgl_list); + } + } } - spin_unlock(&phba->sli4_hba.sgl_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); + spin_unlock_irqrestore(&phba->sli4_hba.sgl_list_lock, iflag); return; } @@ -9963,8 +11867,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, pring = lpfc_phba_elsring(phba); - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.sgl_list_lock); + spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock, iflag); list_for_each_entry_safe(sglq_entry, sglq_next, &phba->sli4_hba.lpfc_abts_els_sgl_list, list) { if (sglq_entry->sli4_xritag == xri) { @@ -9974,11 +11877,15 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_els_sgl_list); sglq_entry->state = SGL_FREED; - spin_unlock(&phba->sli4_hba.sgl_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_set_rrq_active(phba, ndlp, - sglq_entry->sli4_lxritag, - rxid, 1); + spin_unlock_irqrestore(&phba->sli4_hba.sgl_list_lock, + iflag); + + if (ndlp) { + lpfc_set_rrq_active(phba, ndlp, + sglq_entry->sli4_lxritag, + rxid, 1); + lpfc_nlp_put(ndlp); + } /* Check if TXQ queue needs to be serviced */ if (pring && !list_empty(&pring->txq)) @@ -9986,21 +11893,18 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, return; } } - spin_unlock(&phba->sli4_hba.sgl_list_lock); + spin_unlock_irqrestore(&phba->sli4_hba.sgl_list_lock, iflag); lxri = lpfc_sli4_xri_inrange(phba, xri); - if (lxri == NO_XRI) { - spin_unlock_irqrestore(&phba->hbalock, iflag); + if (lxri == NO_XRI) return; - } - spin_lock(&phba->sli4_hba.sgl_list_lock); + + spin_lock_irqsave(&phba->hbalock, iflag); sglq_entry = __lpfc_get_active_sglq(phba, lxri); if (!sglq_entry || (sglq_entry->sli4_xritag != xri)) { - spin_unlock(&phba->sli4_hba.sgl_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); return; } sglq_entry->state = SGL_XRI_ABORTED; - spin_unlock(&phba->sli4_hba.sgl_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); return; } @@ -10030,8 +11934,7 @@ lpfc_sli_abts_recover_port(struct lpfc_vport *vport, "rport in state 0x%x\n", ndlp->nlp_state); return; } - lpfc_printf_log(phba, KERN_ERR, - LOG_ELS | LOG_FCP_ERROR | LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3094 Start rport recovery on shost id 0x%x " "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " "flags 0x%x\n", @@ -10042,10 +11945,321 @@ lpfc_sli_abts_recover_port(struct lpfc_vport *vport, * The rport is not responding. Remove the FCP-2 flag to prevent * an ADISC in the follow-up recovery code. */ - spin_lock_irqsave(shost->host_lock, flags); + spin_lock_irqsave(&ndlp->lock, flags); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; ndlp->nlp_flag |= NLP_ISSUE_LOGO; - spin_unlock_irqrestore(shost->host_lock, flags); + spin_unlock_irqrestore(&ndlp->lock, flags); lpfc_unreg_rpi(vport, ndlp); } +static void lpfc_init_cs_ctl_bitmap(struct lpfc_vport *vport) +{ + bitmap_zero(vport->vmid_priority_range, LPFC_VMID_MAX_PRIORITY_RANGE); +} + +static void +lpfc_vmid_set_cs_ctl_range(struct lpfc_vport *vport, u32 min, u32 max) +{ + u32 i; + + if ((min > max) || (max > LPFC_VMID_MAX_PRIORITY_RANGE)) + return; + + for (i = min; i <= max; i++) + set_bit(i, vport->vmid_priority_range); +} + +static void lpfc_vmid_put_cs_ctl(struct lpfc_vport *vport, u32 ctcl_vmid) +{ + set_bit(ctcl_vmid, vport->vmid_priority_range); +} + +u32 lpfc_vmid_get_cs_ctl(struct lpfc_vport *vport) +{ + u32 i; + + i = find_first_bit(vport->vmid_priority_range, + LPFC_VMID_MAX_PRIORITY_RANGE); + + if (i == LPFC_VMID_MAX_PRIORITY_RANGE) + return 0; + + clear_bit(i, vport->vmid_priority_range); + return i; +} + +#define MAX_PRIORITY_DESC 255 + +static void +lpfc_cmpl_els_qfpa(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + struct priority_range_desc *desc; + struct lpfc_dmabuf *prsp = NULL; + struct lpfc_vmid_priority_range *vmid_range = NULL; + u32 *data; + struct lpfc_dmabuf *dmabuf = cmdiocb->cmd_dmabuf; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); + u8 *pcmd, max_desc; + u32 len, i; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; + + prsp = list_get_first(&dmabuf->list, struct lpfc_dmabuf, list); + if (!prsp) + goto out; + + pcmd = prsp->virt; + data = (u32 *)pcmd; + if (data[0] == ELS_CMD_LS_RJT) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI, + "3277 QFPA LS_RJT x%x x%x\n", + data[0], data[1]); + goto out; + } + if (ulp_status) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, + "6529 QFPA failed with status x%x x%x\n", + ulp_status, ulp_word4); + goto out; + } + + if (!vport->qfpa_res) { + max_desc = FCELSSIZE / sizeof(*vport->qfpa_res); + vport->qfpa_res = kcalloc(max_desc, sizeof(*vport->qfpa_res), + GFP_KERNEL); + if (!vport->qfpa_res) + goto out; + } + + len = *((u32 *)(pcmd + 4)); + len = be32_to_cpu(len); + memcpy(vport->qfpa_res, pcmd, len + 8); + len = len / LPFC_PRIORITY_RANGE_DESC_SIZE; + + desc = (struct priority_range_desc *)(pcmd + 8); + vmid_range = vport->vmid_priority.vmid_range; + if (!vmid_range) { + vmid_range = kcalloc(MAX_PRIORITY_DESC, sizeof(*vmid_range), + GFP_KERNEL); + if (!vmid_range) { + kfree(vport->qfpa_res); + goto out; + } + vport->vmid_priority.vmid_range = vmid_range; + } + vport->vmid_priority.num_descriptors = len; + + for (i = 0; i < len; i++, vmid_range++, desc++) { + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_ELS, + "6539 vmid values low=%d, high=%d, qos=%d, " + "local ve id=%d\n", desc->lo_range, + desc->hi_range, desc->qos_priority, + desc->local_ve_id); + + vmid_range->low = desc->lo_range << 1; + if (desc->local_ve_id == QFPA_ODD_ONLY) + vmid_range->low++; + if (desc->qos_priority) + vport->vmid_flag |= LPFC_VMID_QOS_ENABLED; + vmid_range->qos = desc->qos_priority; + + vmid_range->high = desc->hi_range << 1; + if ((desc->local_ve_id == QFPA_ODD_ONLY) || + (desc->local_ve_id == QFPA_EVEN_ODD)) + vmid_range->high++; + } + lpfc_init_cs_ctl_bitmap(vport); + for (i = 0; i < vport->vmid_priority.num_descriptors; i++) { + lpfc_vmid_set_cs_ctl_range(vport, + vport->vmid_priority.vmid_range[i].low, + vport->vmid_priority.vmid_range[i].high); + } + + vport->vmid_flag |= LPFC_VMID_QFPA_CMPL; + out: + lpfc_els_free_iocb(phba, cmdiocb); + lpfc_nlp_put(ndlp); +} + +int lpfc_issue_els_qfpa(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + struct lpfc_iocbq *elsiocb; + u8 *pcmd; + int ret; + + ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); + if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) + return -ENXIO; + + elsiocb = lpfc_prep_els_iocb(vport, 1, LPFC_QFPA_SIZE, 2, ndlp, + ndlp->nlp_DID, ELS_CMD_QFPA); + if (!elsiocb) + return -ENOMEM; + + pcmd = (u8 *)elsiocb->cmd_dmabuf->virt; + + *((u32 *)(pcmd)) = ELS_CMD_QFPA; + pcmd += 4; + + elsiocb->cmd_cmpl = lpfc_cmpl_els_qfpa; + + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(vport->phba, elsiocb); + return -ENXIO; + } + + ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 2); + if (ret != IOCB_SUCCESS) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + return -EIO; + } + vport->vmid_flag &= ~LPFC_VMID_QOS_ENABLED; + return 0; +} + +int +lpfc_vmid_uvem(struct lpfc_vport *vport, + struct lpfc_vmid *vmid, bool instantiated) +{ + struct lpfc_vem_id_desc *vem_id_desc; + struct lpfc_nodelist *ndlp; + struct lpfc_iocbq *elsiocb; + struct instantiated_ve_desc *inst_desc; + struct lpfc_vmid_context *vmid_context; + u8 *pcmd; + u32 *len; + int ret = 0; + + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) + return -ENXIO; + + vmid_context = kmalloc(sizeof(*vmid_context), GFP_KERNEL); + if (!vmid_context) + return -ENOMEM; + elsiocb = lpfc_prep_els_iocb(vport, 1, LPFC_UVEM_SIZE, 2, + ndlp, Fabric_DID, ELS_CMD_UVEM); + if (!elsiocb) + goto out; + + lpfc_printf_vlog(vport, KERN_DEBUG, LOG_ELS, + "3427 Host vmid %s %d\n", + vmid->host_vmid, instantiated); + vmid_context->vmp = vmid; + vmid_context->nlp = ndlp; + vmid_context->instantiated = instantiated; + elsiocb->vmid_tag.vmid_context = vmid_context; + pcmd = (u8 *)elsiocb->cmd_dmabuf->virt; + + if (uuid_is_null((uuid_t *)vport->lpfc_vmid_host_uuid)) + memcpy(vport->lpfc_vmid_host_uuid, vmid->host_vmid, + LPFC_COMPRESS_VMID_SIZE); + + *((u32 *)(pcmd)) = ELS_CMD_UVEM; + len = (u32 *)(pcmd + 4); + *len = cpu_to_be32(LPFC_UVEM_SIZE - 8); + + vem_id_desc = (struct lpfc_vem_id_desc *)(pcmd + 8); + vem_id_desc->tag = be32_to_cpu(VEM_ID_DESC_TAG); + vem_id_desc->length = be32_to_cpu(LPFC_UVEM_VEM_ID_DESC_SIZE); + memcpy(vem_id_desc->vem_id, vport->lpfc_vmid_host_uuid, + LPFC_COMPRESS_VMID_SIZE); + + inst_desc = (struct instantiated_ve_desc *)(pcmd + 32); + inst_desc->tag = be32_to_cpu(INSTANTIATED_VE_DESC_TAG); + inst_desc->length = be32_to_cpu(LPFC_UVEM_VE_MAP_DESC_SIZE); + memcpy(inst_desc->global_vem_id, vmid->host_vmid, + LPFC_COMPRESS_VMID_SIZE); + + bf_set(lpfc_instantiated_nport_id, inst_desc, vport->fc_myDID); + bf_set(lpfc_instantiated_local_id, inst_desc, + vmid->un.cs_ctl_vmid); + if (instantiated) { + inst_desc->tag = be32_to_cpu(INSTANTIATED_VE_DESC_TAG); + } else { + inst_desc->tag = be32_to_cpu(DEINSTANTIATED_VE_DESC_TAG); + lpfc_vmid_put_cs_ctl(vport, vmid->un.cs_ctl_vmid); + } + inst_desc->word6 = cpu_to_be32(inst_desc->word6); + + elsiocb->cmd_cmpl = lpfc_cmpl_els_uvem; + + elsiocb->ndlp = lpfc_nlp_get(ndlp); + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(vport->phba, elsiocb); + goto out; + } + + ret = lpfc_sli_issue_iocb(vport->phba, LPFC_ELS_RING, elsiocb, 0); + if (ret != IOCB_SUCCESS) { + lpfc_els_free_iocb(vport->phba, elsiocb); + lpfc_nlp_put(ndlp); + goto out; + } + + return 0; + out: + kfree(vmid_context); + return -EIO; +} + +static void +lpfc_cmpl_els_uvem(struct lpfc_hba *phba, struct lpfc_iocbq *icmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = icmdiocb->vport; + struct lpfc_dmabuf *prsp = NULL; + struct lpfc_vmid_context *vmid_context = + icmdiocb->vmid_tag.vmid_context; + struct lpfc_nodelist *ndlp = icmdiocb->ndlp; + u8 *pcmd; + u32 *data; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); + struct lpfc_dmabuf *dmabuf = icmdiocb->cmd_dmabuf; + struct lpfc_vmid *vmid; + + vmid = vmid_context->vmp; + if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) + ndlp = NULL; + + prsp = list_get_first(&dmabuf->list, struct lpfc_dmabuf, list); + if (!prsp) + goto out; + pcmd = prsp->virt; + data = (u32 *)pcmd; + if (data[0] == ELS_CMD_LS_RJT) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI, + "4532 UVEM LS_RJT %x %x\n", data[0], data[1]); + goto out; + } + if (ulp_status) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI, + "4533 UVEM error status %x: %x\n", + ulp_status, ulp_word4); + goto out; + } + spin_lock(&phba->hbalock); + /* Set IN USE flag */ + vport->vmid_flag |= LPFC_VMID_IN_USE; + phba->pport->vmid_flag |= LPFC_VMID_IN_USE; + spin_unlock(&phba->hbalock); + + if (vmid_context->instantiated) { + write_lock(&vport->vmid_lock); + vmid->flag |= LPFC_VMID_REGISTERED; + vmid->flag &= ~LPFC_VMID_REQ_REGISTER; + write_unlock(&vport->vmid_lock); + } + + out: + kfree(vmid_context); + lpfc_els_free_iocb(phba, icmdiocb); + lpfc_nlp_put(ndlp); +} diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index dcc8999c6a68..d38ebd7281b9 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -36,8 +36,6 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> -#include <linux/nvme-fc-driver.h> - #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_nl.h" @@ -73,36 +71,77 @@ static void lpfc_disc_timeout_handler(struct lpfc_vport *); static void lpfc_disc_flush_list(struct lpfc_vport *vport); static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); static int lpfc_fcf_inuse(struct lpfc_hba *); +static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *); +static void lpfc_check_inactive_vmid(struct lpfc_hba *phba); +static void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba); -void -lpfc_terminate_rport_io(struct fc_rport *rport) +static int +lpfc_valid_xpt_node(struct lpfc_nodelist *ndlp) +{ + if (ndlp->nlp_fc4_type || + ndlp->nlp_type & NLP_FABRIC) + return 1; + return 0; +} +/* The source of a terminate rport I/O is either a dev_loss_tmo + * event or a call to fc_remove_host. While the rport should be + * valid during these downcalls, the transport can call twice + * in a single event. This routine provides somoe protection + * as the NDLP isn't really free, just released to the pool. + */ +static int +lpfc_rport_invalid(struct fc_rport *rport) { struct lpfc_rport_data *rdata; - struct lpfc_nodelist * ndlp; - struct lpfc_hba *phba; + struct lpfc_nodelist *ndlp; + + if (!rport) { + pr_err("**** %s: NULL rport, exit.\n", __func__); + return -EINVAL; + } rdata = rport->dd_data; + if (!rdata) { + pr_err("**** %s: NULL dd_data on rport x%px SID x%x\n", + __func__, rport, rport->scsi_target_id); + return -EINVAL; + } + ndlp = rdata->pnode; + if (!rdata->pnode) { + pr_info("**** %s: NULL ndlp on rport x%px SID x%x\n", + __func__, rport, rport->scsi_target_id); + return -EINVAL; + } - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) - printk(KERN_ERR "Cannot find remote node" - " to terminate I/O Data x%x\n", - rport->port_id); - return; + if (!ndlp->vport) { + pr_err("**** %s: Null vport on ndlp x%px, DID x%x rport x%px " + "SID x%x\n", __func__, ndlp, ndlp->nlp_DID, rport, + rport->scsi_target_id); + return -EINVAL; } + return 0; +} - phba = ndlp->phba; +void +lpfc_terminate_rport_io(struct fc_rport *rport) +{ + struct lpfc_rport_data *rdata; + struct lpfc_nodelist *ndlp; + struct lpfc_vport *vport; - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT, - "rport terminate: sid:x%x did:x%x flg:x%x", - ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); + if (lpfc_rport_invalid(rport)) + return; - if (ndlp->nlp_sid != NLP_NO_SID) { - lpfc_sli_abort_iocb(ndlp->vport, - &phba->sli.sli3_ring[LPFC_FCP_RING], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); - } + rdata = rport->dd_data; + ndlp = rdata->pnode; + vport = ndlp->vport; + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, + "rport terminate: sid:x%x did:x%x flg:x%x", + ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); + + if (ndlp->nlp_sid != NLP_NO_SID) + lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT); } /* @@ -111,19 +150,14 @@ lpfc_terminate_rport_io(struct fc_rport *rport) void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) { - struct lpfc_rport_data *rdata; - struct lpfc_nodelist * ndlp; + struct lpfc_nodelist *ndlp; struct lpfc_vport *vport; - struct Scsi_Host *shost; struct lpfc_hba *phba; struct lpfc_work_evt *evtp; - int put_node; - int put_rport; unsigned long iflags; - rdata = rport->dd_data; - ndlp = rdata->pnode; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + ndlp = ((struct lpfc_rport_data *)rport->dd_data)->pnode; + if (!ndlp) return; vport = ndlp->vport; @@ -134,22 +168,30 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3181 dev_loss_callbk x%06x, rport x%px flg x%x\n", - ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag); - - /* Don't defer this if we are in the process of deleting the vport - * or unloading the driver. The unload will cleanup the node - * appropriately we just need to cleanup the ndlp rport info here. + "3181 dev_loss_callbk x%06x, rport x%px flg x%x " + "load_flag x%x refcnt %d state %d xpt x%x\n", + ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag, + vport->load_flag, kref_read(&ndlp->kref), + ndlp->nlp_state, ndlp->fc4_xpt_flags); + + /* Don't schedule a worker thread event if the vport is going down. + * The teardown process cleans up the node via lpfc_drop_node. */ if (vport->load_flag & FC_UNLOADING) { - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; + ((struct lpfc_rport_data *)rport->dd_data)->pnode = NULL; ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); + + ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; + /* clear the NLP_XPT_REGD if the node is not registered + * with nvme-fc + */ + if (ndlp->fc4_xpt_flags == NLP_XPT_REGD) + ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; + + /* Remove the node reference from remote_port_add now. + * The driver will not call remote_port_delete. + */ + lpfc_nlp_put(ndlp); return; } @@ -157,42 +199,208 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) return; if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, - "6789 rport name %llx != node port name %llx", - rport->port_name, - wwn_to_u64(ndlp->nlp_portname.u.wwn)); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6789 rport name %llx != node port name %llx", + rport->port_name, + wwn_to_u64(ndlp->nlp_portname.u.wwn)); evtp = &ndlp->dev_loss_evt; if (!list_empty(&evtp->evt_listp)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, - "6790 rport name %llx dev_loss_evt pending", - rport->port_name); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6790 rport name %llx dev_loss_evt pending\n", + rport->port_name); return; } - shost = lpfc_shost_from_vport(vport); - spin_lock_irqsave(shost->host_lock, iflags); + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag |= NLP_IN_DEV_LOSS; - spin_unlock_irqrestore(shost->host_lock, iflags); - /* We need to hold the node by incrementing the reference - * count until this queued work is done + /* If there is a PLOGI in progress, and we are in a + * NLP_NPR_2B_DISC state, don't turn off the flag. */ - evtp->evt_arg1 = lpfc_nlp_get(ndlp); + if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE) + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + + /* + * The backend does not expect any more calls associated with this + * rport. Remove the association between rport and ndlp. + */ + ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; + ((struct lpfc_rport_data *)rport->dd_data)->pnode = NULL; + ndlp->rport = NULL; + spin_unlock_irqrestore(&ndlp->lock, iflags); + + if (phba->worker_thread) { + /* We need to hold the node by incrementing the reference + * count until this queued work is done + */ + evtp->evt_arg1 = lpfc_nlp_get(ndlp); + + spin_lock_irqsave(&phba->hbalock, iflags); + if (evtp->evt_arg1) { + evtp->evt = LPFC_EVT_DEV_LOSS; + list_add_tail(&evtp->evt_listp, &phba->work_list); + lpfc_worker_wake_up(phba); + } + spin_unlock_irqrestore(&phba->hbalock, iflags); + } else { + lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, + "3188 worker thread is stopped %s x%06x, " + " rport x%px flg x%x load_flag x%x refcnt " + "%d\n", __func__, ndlp->nlp_DID, + ndlp->rport, ndlp->nlp_flag, + vport->load_flag, kref_read(&ndlp->kref)); + if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) { + spin_lock_irqsave(&ndlp->lock, iflags); + /* Node is in dev loss. No further transaction. */ + ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; + spin_unlock_irqrestore(&ndlp->lock, iflags); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); + } - spin_lock_irqsave(&phba->hbalock, iflags); - if (evtp->evt_arg1) { - evtp->evt = LPFC_EVT_DEV_LOSS; - list_add_tail(&evtp->evt_listp, &phba->work_list); - lpfc_worker_wake_up(phba); } - spin_unlock_irqrestore(&phba->hbalock, iflags); return; } /** + * lpfc_check_inactive_vmid_one - VMID inactivity checker for a vport + * @vport: Pointer to vport context object. + * + * This function checks for idle VMID entries related to a particular vport. If + * found unused/idle, free them accordingly. + **/ +static void lpfc_check_inactive_vmid_one(struct lpfc_vport *vport) +{ + u16 keep; + u32 difftime = 0, r, bucket; + u64 *lta; + int cpu; + struct lpfc_vmid *vmp; + + write_lock(&vport->vmid_lock); + + if (!vport->cur_vmid_cnt) + goto out; + + /* iterate through the table */ + hash_for_each(vport->hash_table, bucket, vmp, hnode) { + keep = 0; + if (vmp->flag & LPFC_VMID_REGISTERED) { + /* check if the particular VMID is in use */ + /* for all available per cpu variable */ + for_each_possible_cpu(cpu) { + /* if last access time is less than timeout */ + lta = per_cpu_ptr(vmp->last_io_time, cpu); + if (!lta) + continue; + difftime = (jiffies) - (*lta); + if ((vport->vmid_inactivity_timeout * + JIFFIES_PER_HR) > difftime) { + keep = 1; + break; + } + } + + /* if none of the cpus have been used by the vm, */ + /* remove the entry if already registered */ + if (!keep) { + /* mark the entry for deregistration */ + vmp->flag = LPFC_VMID_DE_REGISTER; + write_unlock(&vport->vmid_lock); + if (vport->vmid_priority_tagging) + r = lpfc_vmid_uvem(vport, vmp, false); + else + r = lpfc_vmid_cmd(vport, + SLI_CTAS_DAPP_IDENT, + vmp); + + /* decrement number of active vms and mark */ + /* entry in slot as free */ + write_lock(&vport->vmid_lock); + if (!r) { + struct lpfc_vmid *ht = vmp; + + vport->cur_vmid_cnt--; + ht->flag = LPFC_VMID_SLOT_FREE; + free_percpu(ht->last_io_time); + ht->last_io_time = NULL; + hash_del(&ht->hnode); + } + } + } + } + out: + write_unlock(&vport->vmid_lock); +} + +/** + * lpfc_check_inactive_vmid - VMID inactivity checker + * @phba: Pointer to hba context object. + * + * This function is called from the worker thread to determine if an entry in + * the VMID table can be released since there was no I/O activity seen from that + * particular VM for the specified time. When this happens, the entry in the + * table is released and also the resources on the switch cleared. + **/ + +static void lpfc_check_inactive_vmid(struct lpfc_hba *phba) +{ + struct lpfc_vport *vport; + struct lpfc_vport **vports; + int i; + + vports = lpfc_create_vport_work_array(phba); + if (!vports) + return; + + for (i = 0; i <= phba->max_vports; i++) { + if ((!vports[i]) && (i == 0)) + vport = phba->pport; + else + vport = vports[i]; + if (!vport) + break; + + lpfc_check_inactive_vmid_one(vport); + } + lpfc_destroy_vport_work_array(phba, vports); +} + +/** + * lpfc_check_nlp_post_devloss - Check to restore ndlp refcnt after devloss + * @vport: Pointer to vport object. + * @ndlp: Pointer to remote node object. + * + * If NLP_IN_RECOV_POST_DEV_LOSS flag was set due to outstanding recovery of + * node during dev_loss_tmo processing, then this function restores the nlp_put + * kref decrement from lpfc_dev_loss_tmo_handler. + **/ +void +lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp) +{ + unsigned long iflags; + + spin_lock_irqsave(&ndlp->lock, iflags); + if (ndlp->save_flags & NLP_IN_RECOV_POST_DEV_LOSS) { + ndlp->save_flags &= ~NLP_IN_RECOV_POST_DEV_LOSS; + spin_unlock_irqrestore(&ndlp->lock, iflags); + lpfc_nlp_get(ndlp); + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE, + "8438 Devloss timeout reversed on DID x%x " + "refcnt %d ndlp %p flag x%x " + "port_state = x%x\n", + ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp, + ndlp->nlp_flag, vport->port_state); + spin_lock_irqsave(&ndlp->lock, iflags); + } + spin_unlock_irqrestore(&ndlp->lock, iflags); +} + +/** * lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler * @ndlp: Pointer to remote node object. * @@ -205,70 +413,36 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) static int lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) { - struct lpfc_rport_data *rdata; - struct fc_rport *rport; struct lpfc_vport *vport; struct lpfc_hba *phba; - struct Scsi_Host *shost; uint8_t *name; - int put_node; int warn_on = 0; int fcf_inuse = 0; + bool recovering = false; + struct fc_vport *fc_vport = NULL; unsigned long iflags; - rport = ndlp->rport; vport = ndlp->vport; - shost = lpfc_shost_from_vport(vport); + name = (uint8_t *)&ndlp->nlp_portname; + phba = vport->phba; - spin_lock_irqsave(shost->host_lock, iflags); + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; - spin_unlock_irqrestore(shost->host_lock, iflags); - - if (!rport) - return fcf_inuse; - - name = (uint8_t *) &ndlp->nlp_portname; - phba = vport->phba; + spin_unlock_irqrestore(&ndlp->lock, iflags); if (phba->sli_rev == LPFC_SLI_REV4) fcf_inuse = lpfc_fcf_inuse(phba); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport devlosstmo:did:x%x type:x%x id:x%x", - ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); + "rport devlosstmo:did:x%x type:x%x id:x%x", + ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_sid); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3182 dev_loss_tmo_handler x%06x, rport x%px flg x%x\n", - ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag); - - /* - * lpfc_nlp_remove if reached with dangling rport drops the - * reference. To make sure that does not happen clear rport - * pointer in ndlp before lpfc_nlp_put. - */ - rdata = rport->dd_data; - - /* Don't defer this if we are in the process of deleting the vport - * or unloading the driver. The unload will cleanup the node - * appropriately we just need to cleanup the ndlp rport info here. - */ - if (vport->load_flag & FC_UNLOADING) { - if (ndlp->nlp_sid != NLP_NO_SID) { - /* flush the target */ - lpfc_sli_abort_iocb(vport, - &phba->sli.sli3_ring[LPFC_FCP_RING], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); - } - put_node = rdata->pnode != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - put_device(&rport->dev); - - return fcf_inuse; - } + "3182 %s x%06x, nflag x%x xflags x%x refcnt %d\n", + __func__, ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->fc4_xpt_flags, kref_read(&ndlp->kref)); + /* If the driver is recovering the rport, ignore devloss. */ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0284 Devloss timeout Ignored on " @@ -280,33 +454,87 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) return fcf_inuse; } - put_node = rdata->pnode != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - put_device(&rport->dev); + /* Fabric nodes are done. */ + if (ndlp->nlp_type & NLP_FABRIC) { + spin_lock_irqsave(&ndlp->lock, iflags); + /* In massive vport configuration settings, it's possible + * dev_loss_tmo fired during node recovery. So, check if + * fabric nodes are in discovery states outstanding. + */ + switch (ndlp->nlp_DID) { + case Fabric_DID: + fc_vport = vport->fc_vport; + if (fc_vport && + fc_vport->vport_state == FC_VPORT_INITIALIZING) + recovering = true; + break; + case Fabric_Cntl_DID: + if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) + recovering = true; + break; + case FDMI_DID: + fallthrough; + case NameServer_DID: + if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE && + ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE) + recovering = true; + break; + } + spin_unlock_irqrestore(&ndlp->lock, iflags); - if (ndlp->nlp_type & NLP_FABRIC) + /* Mark an NLP_IN_RECOV_POST_DEV_LOSS flag to know if reversing + * the following lpfc_nlp_put is necessary after fabric node is + * recovered. + */ + if (recovering) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_NODE, + "8436 Devloss timeout marked on " + "DID x%x refcnt %d ndlp %p " + "flag x%x port_state = x%x\n", + ndlp->nlp_DID, kref_read(&ndlp->kref), + ndlp, ndlp->nlp_flag, + vport->port_state); + spin_lock_irqsave(&ndlp->lock, iflags); + ndlp->save_flags |= NLP_IN_RECOV_POST_DEV_LOSS; + spin_unlock_irqrestore(&ndlp->lock, iflags); + } else if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { + /* Fabric node fully recovered before this dev_loss_tmo + * queue work is processed. Thus, ignore the + * dev_loss_tmo event. + */ + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_NODE, + "8437 Devloss timeout ignored on " + "DID x%x refcnt %d ndlp %p " + "flag x%x port_state = x%x\n", + ndlp->nlp_DID, kref_read(&ndlp->kref), + ndlp, ndlp->nlp_flag, + vport->port_state); + return fcf_inuse; + } + + lpfc_nlp_put(ndlp); return fcf_inuse; + } if (ndlp->nlp_sid != NLP_NO_SID) { warn_on = 1; - lpfc_sli_abort_iocb(vport, &phba->sli.sli3_ring[LPFC_FCP_RING], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); + lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT); } if (warn_on) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0203 Devloss timeout on " "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " - "NPort x%06x Data: x%x x%x x%x\n", + "NPort x%06x Data: x%x x%x x%x refcnt %d\n", *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7), ndlp->nlp_DID, ndlp->nlp_flag, - ndlp->nlp_state, ndlp->nlp_rpi); + ndlp->nlp_state, ndlp->nlp_rpi, + kref_read(&ndlp->kref)); } else { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_INFO, LOG_TRACE_EVENT, "0204 Devloss timeout on " "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " "NPort x%06x Data: x%x x%x x%x\n", @@ -316,16 +544,46 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ndlp->nlp_state, ndlp->nlp_rpi); } - if (!(ndlp->nlp_flag & NLP_DELAY_TMO) && - !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) && - (ndlp->nlp_state != NLP_STE_PRLI_ISSUE)) + /* If we are devloss, but we are in the process of rediscovering the + * ndlp, don't issue a NLP_EVT_DEVICE_RM event. + */ + if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE && + ndlp->nlp_state <= NLP_STE_PRLI_ISSUE) { + return fcf_inuse; + } + + if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); return fcf_inuse; } +static void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba) +{ + struct lpfc_vport *vport; + struct lpfc_vport **vports; + int i; + + vports = lpfc_create_vport_work_array(phba); + if (!vports) + return; + + for (i = 0; i <= phba->max_vports; i++) { + if ((!vports[i]) && (i == 0)) + vport = phba->pport; + else + vport = vports[i]; + if (!vport) + break; + + if (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA) { + if (!lpfc_issue_els_qfpa(vport)) + vport->vmid_flag &= ~LPFC_VMID_ISSUE_QFPA; + } + } + lpfc_destroy_vport_work_array(phba, vports); +} + /** * lpfc_sli4_post_dev_loss_tmo_handler - SLI4 post devloss timeout handler * @phba: Pointer to hba context object. @@ -522,18 +780,22 @@ lpfc_work_list_done(struct lpfc_hba *phba) int free_evt; int fcf_inuse; uint32_t nlp_did; + bool hba_pci_err; spin_lock_irq(&phba->hbalock); while (!list_empty(&phba->work_list)) { list_remove_head((&phba->work_list), evtp, typeof(*evtp), evt_listp); spin_unlock_irq(&phba->hbalock); + hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags); free_evt = 1; switch (evtp->evt) { case LPFC_EVT_ELS_RETRY: ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); - lpfc_els_retry_delay_handler(ndlp); - free_evt = 0; /* evt is part of ndlp */ + if (!hba_pci_err) { + lpfc_els_retry_delay_handler(ndlp); + free_evt = 0; /* evt is part of ndlp */ + } /* decrement the node reference count held * for this queued work */ @@ -553,6 +815,17 @@ lpfc_work_list_done(struct lpfc_hba *phba) fcf_inuse, nlp_did); break; + case LPFC_EVT_RECOVER_PORT: + ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); + if (!hba_pci_err) { + lpfc_sli_abts_recover_port(ndlp->vport, ndlp); + free_evt = 0; + } + /* decrement the node reference count held for + * this queued work + */ + lpfc_nlp_put(ndlp); + break; case LPFC_EVT_ONLINE: if (phba->link_state < LPFC_LINK_DOWN) *(int *) (evtp->evt_arg1) = lpfc_online(phba); @@ -617,26 +890,52 @@ lpfc_work_done(struct lpfc_hba *phba) struct lpfc_vport **vports; struct lpfc_vport *vport; int i; + bool hba_pci_err; + hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags); spin_lock_irq(&phba->hbalock); ha_copy = phba->work_ha; phba->work_ha = 0; spin_unlock_irq(&phba->hbalock); + if (hba_pci_err) + ha_copy = 0; /* First, try to post the next mailbox command to SLI4 device */ - if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) + if (phba->pci_dev_grp == LPFC_PCI_DEV_OC && !hba_pci_err) lpfc_sli4_post_async_mbox(phba); - if (ha_copy & HA_ERATT) + if (ha_copy & HA_ERATT) { /* Handle the error attention event */ lpfc_handle_eratt(phba); + if (phba->fw_dump_cmpl) { + complete(phba->fw_dump_cmpl); + phba->fw_dump_cmpl = NULL; + } + } + if (ha_copy & HA_MBATT) lpfc_sli_handle_mb_event(phba); if (ha_copy & HA_LATT) lpfc_handle_latt(phba); + /* Handle VMID Events */ + if (lpfc_is_vmid_enabled(phba) && !hba_pci_err) { + if (phba->pport->work_port_events & + WORKER_CHECK_VMID_ISSUE_QFPA) { + lpfc_check_vmid_qfpa_issue(phba); + phba->pport->work_port_events &= + ~WORKER_CHECK_VMID_ISSUE_QFPA; + } + if (phba->pport->work_port_events & + WORKER_CHECK_INACTIVE_VMID) { + lpfc_check_inactive_vmid(phba); + phba->pport->work_port_events &= + ~WORKER_CHECK_INACTIVE_VMID; + } + } + /* Process SLI4 events */ if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { if (phba->hba_flag & HBA_RRQ_ACTIVE) @@ -672,6 +971,8 @@ lpfc_work_done(struct lpfc_hba *phba) work_port_events = vport->work_port_events; vport->work_port_events &= ~work_port_events; spin_unlock_irq(&vport->work_port_lock); + if (hba_pci_err) + continue; if (work_port_events & WORKER_DISC_TMO) lpfc_disc_timeout_handler(vport); if (work_port_events & WORKER_ELS_TMO) @@ -757,7 +1058,7 @@ lpfc_do_work(void *p) || kthread_should_stop())); /* Signal wakeup shall terminate the worker thread */ if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0433 Wakeup on signal: rc=x%x\n", rc); break; } @@ -812,19 +1113,38 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) struct lpfc_nodelist *ndlp, *next_ndlp; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + /* It's possible the FLOGI to the fabric node never + * successfully completed and never registered with the + * transport. In this case there is no way to clean up + * the node. + */ + if (ndlp->nlp_DID == Fabric_DID) { + if (ndlp->nlp_prev_state == + NLP_STE_UNUSED_NODE && + !ndlp->fc4_xpt_flags) + lpfc_nlp_put(ndlp); + } continue; + } + if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || - ((vport->port_type == LPFC_NPIV_PORT) && - (ndlp->nlp_DID == NameServer_DID))) + ((vport->port_type == LPFC_NPIV_PORT) && + ((ndlp->nlp_DID == NameServer_DID) || + (ndlp->nlp_DID == FDMI_DID) || + (ndlp->nlp_DID == Fabric_Cntl_DID)))) lpfc_unreg_rpi(vport, ndlp); /* Leave Fabric nodes alone on link down */ if ((phba->sli_rev < LPFC_SLI_REV4) && (!remove && ndlp->nlp_type & NLP_FABRIC)) continue; + + /* Notify transport of connectivity loss to trigger cleanup. */ + if (phba->nvmet_support && + ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) + lpfc_nvmet_invalidate_host(phba, ndlp); + lpfc_disc_state_machine(vport, ndlp, NULL, remove ? NLP_EVT_DEVICE_RM @@ -863,6 +1183,7 @@ lpfc_port_link_failure(struct lpfc_vport *vport) void lpfc_linkdown_port(struct lpfc_vport *vport) { + struct lpfc_hba *phba = vport->phba; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (vport->cfg_enable_fc4_type != LPFC_ENABLE_NVME) @@ -880,6 +1201,13 @@ lpfc_linkdown_port(struct lpfc_vport *vport) vport->fc_flag &= ~FC_DISC_DELAYED; spin_unlock_irq(shost->host_lock); del_timer_sync(&vport->delayed_disc_tmo); + + if (phba->sli_rev == LPFC_SLI_REV4 && + vport->port_type == LPFC_PHYSICAL_PORT && + phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_CONFIG) { + /* Assume success on link up */ + phba->sli4_hba.fawwpn_flag |= LPFC_FAWWPN_FABRIC; + } } int @@ -890,15 +1218,20 @@ lpfc_linkdown(struct lpfc_hba *phba) struct lpfc_vport **vports; LPFC_MBOXQ_t *mb; int i; + int offline; if (phba->link_state == LPFC_LINK_DOWN) return 0; /* Block all SCSI stack I/Os */ lpfc_scsi_dev_block(phba); + offline = pci_channel_offline(phba->pcidev); phba->defer_flogi_acc_flag = false; + /* Clear external loopback plug detected flag */ + phba->link_flag &= ~LS_EXTERNAL_LOOPBACK; + spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE); spin_unlock_irq(&phba->hbalock); @@ -909,6 +1242,8 @@ lpfc_linkdown(struct lpfc_hba *phba) phba->trunk_link.link1.state = 0; phba->trunk_link.link2.state = 0; phba->trunk_link.link3.state = 0; + phba->trunk_link.phy_lnk_speed = + LPFC_LINK_SPEED_UNKNOWN; phba->sli4_hba.link_state.logical_speed = LPFC_LINK_SPEED_UNKNOWN; } @@ -936,7 +1271,7 @@ lpfc_linkdown(struct lpfc_hba *phba) lpfc_destroy_vport_work_array(phba, vports); /* Clean up any SLI3 firmware default rpi's */ - if (phba->sli_rev > LPFC_SLI_REV3) + if (phba->sli_rev > LPFC_SLI_REV3 || offline) goto skip_unreg_did; mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -978,8 +1313,7 @@ lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; if (ndlp->nlp_type & NLP_FABRIC) { @@ -1021,15 +1355,19 @@ lpfc_linkup_port(struct lpfc_vport *vport) FCH_EVT_LINKUP, 0); spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY | - FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY); + if (phba->defer_flogi_acc_flag) + vport->fc_flag &= ~(FC_ABORT_DISCOVERY | FC_RSCN_MODE | + FC_NLP_MORE | FC_RSCN_DISCOVERY); + else + vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | + FC_ABORT_DISCOVERY | FC_RSCN_MODE | + FC_NLP_MORE | FC_RSCN_DISCOVERY); vport->fc_flag |= FC_NDISC_ACTIVE; vport->fc_ns_retry = 0; spin_unlock_irq(shost->host_lock); + lpfc_setup_fdmi_mask(vport); - if (vport->fc_flag & FC_LBIT) - lpfc_linkup_cleanup_nodes(vport); - + lpfc_linkup_cleanup_nodes(vport); } static int @@ -1059,9 +1397,8 @@ lpfc_linkup(struct lpfc_hba *phba) phba->pport->rcv_flogi_cnt = 0; spin_unlock_irq(shost->host_lock); - /* reinitialize initial FLOGI flag */ - phba->hba_flag &= ~(HBA_FLOGI_ISSUED); - phba->defer_flogi_acc_flag = false; + /* reinitialize initial HBA flag */ + phba->hba_flag &= ~(HBA_FLOGI_ISSUED | HBA_RHBA_CMPL); return 0; } @@ -1088,7 +1425,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Check for error */ if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) { /* CLEAR_LA mbox error <mbxStatus> state <hba_state> */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0320 CLEAR_LA mbxStatus error x%x hba " "state x%x\n", mb->mbxStatus, vport->port_state); @@ -1134,17 +1471,19 @@ out: return; } - void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - - if (pmb->u.mb.mbxStatus) - goto out; + LPFC_MBOXQ_t *sparam_mb; + u16 status = pmb->u.mb.mbxStatus; + int rc; mempool_free(pmb, phba->mbox_mem_pool); + if (status) + goto out; + /* don't perform discovery for SLI4 loopback diagnostic test */ if ((phba->sli_rev == LPFC_SLI_REV4) && !(phba->hba_flag & HBA_FCOE_MODE) && @@ -1163,25 +1502,52 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } /* Start discovery by sending a FLOGI. port_state is identically - * LPFC_FLOGI while waiting for FLOGI cmpl + * LPFC_FLOGI while waiting for FLOGI cmpl. */ - if (vport->port_state != LPFC_FLOGI) - lpfc_initial_flogi(vport); - else if (vport->fc_flag & FC_PT2PT) - lpfc_disc_start(vport); + if (vport->port_state != LPFC_FLOGI) { + /* Issue MBX_READ_SPARAM to update CSPs before FLOGI if + * bb-credit recovery is in place. + */ + if (phba->bbcredit_support && phba->cfg_enable_bbcr && + !(phba->link_flag & LS_LOOPBACK_MODE)) { + sparam_mb = mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!sparam_mb) + goto sparam_out; + + rc = lpfc_read_sparam(phba, sparam_mb, 0); + if (rc) { + mempool_free(sparam_mb, phba->mbox_mem_pool); + goto sparam_out; + } + sparam_mb->vport = vport; + sparam_mb->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; + rc = lpfc_sli_issue_mbox(phba, sparam_mb, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_mbox_rsrc_cleanup(phba, sparam_mb, + MBOX_THD_UNLOCKED); + goto sparam_out; + } + phba->hba_flag |= HBA_DEFER_FLOGI; + } else { + lpfc_initial_flogi(vport); + } + } else { + if (vport->fc_flag & FC_PT2PT) + lpfc_disc_start(vport); + } return; out: - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0306 CONFIG_LINK mbxStatus error x%x " - "HBA state x%x\n", - pmb->u.mb.mbxStatus, vport->port_state); - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0306 CONFIG_LINK mbxStatus error x%x HBA state x%x\n", + status, vport->port_state); +sparam_out: lpfc_linkdown(phba); - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0200 CONFIG_LINK bad hba state x%x\n", vport->port_state); @@ -1191,7 +1557,7 @@ out: /** * lpfc_sli4_clear_fcf_rr_bmask - * @phba pointer to the struct lpfc_hba for this port. + * @phba: pointer to the struct lpfc_hba for this port. * This fucnction resets the round robin bit mask and clears the * fcf priority list. The list deletions are done while holding the * hbalock. The ON_LIST flag and the FLOGI_FAILED flags are cleared @@ -1217,10 +1583,10 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct lpfc_vport *vport = mboxq->vport; if (mboxq->u.mb.mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "2017 REG_FCFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2017 REG_FCFI mbxStatus error x%x " + "HBA state x%x\n", mboxq->u.mb.mbxStatus, + vport->port_state); goto fail_out; } @@ -1290,7 +1656,7 @@ lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record) /** * lpfc_sw_name_match - Check if the fcf switch name match. - * @fab_name: pointer to fabric name. + * @sw_name: pointer to switch name. * @new_fcf_record: pointer to fcf record. * * This routine compare the fcf record's switch name with provided @@ -1353,14 +1719,14 @@ lpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id) } /** - * lpfc_update_fcf_record - Update driver fcf record * __lpfc_update_fcf_record_pri - update the lpfc_fcf_pri record. * @phba: pointer to lpfc hba data structure. * @fcf_index: Index for the lpfc_fcf_record. * @new_fcf_record: pointer to hba fcf record. * * This routine updates the driver FCF priority record from the new HBA FCF - * record. This routine is called with the host lock held. + * record. The hbalock is asserted held in the code path calling this + * routine. **/ static void __lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index, @@ -1369,8 +1735,6 @@ __lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index, { struct lpfc_fcf_pri *fcf_pri; - lockdep_assert_held(&phba->hbalock); - fcf_pri = &phba->fcf.fcf_pri[fcf_index]; fcf_pri->fcf_rec.fcf_index = fcf_index; /* FCF record priority */ @@ -1380,7 +1744,7 @@ __lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index, /** * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba. - * @fcf: pointer to driver fcf record. + * @fcf_rec: pointer to driver fcf record. * @new_fcf_record: pointer to fcf record. * * This routine copies the FCF information from the FCF @@ -1438,7 +1802,7 @@ lpfc_copy_fcf_record(struct lpfc_fcf_rec *fcf_rec, } /** - * lpfc_update_fcf_record - Update driver fcf record + * __lpfc_update_fcf_record - Update driver fcf record * @phba: pointer to lpfc hba data structure. * @fcf_rec: pointer to driver fcf record. * @new_fcf_record: pointer to hba fcf record. @@ -1448,7 +1812,7 @@ lpfc_copy_fcf_record(struct lpfc_fcf_rec *fcf_rec, * * This routine updates the driver FCF record from the new HBA FCF record * together with the address mode, vlan_id, and other informations. This - * routine is called with the host lock held. + * routine is called with the hbalock held. **/ static void __lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec, @@ -1792,8 +2156,8 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) * This function makes an running random selection decision on FCF record to * use through a sequence of @fcf_cnt eligible FCF records with equal * probability. To perform integer manunipulation of random numbers with - * size unit32_t, the lower 16 bits of the 32-bit random number returned - * from prandom_u32() are taken as the random random number generated. + * size unit32_t, a 16-bit random number returned from get_random_u16() is + * taken as the random random number generated. * * Returns true when outcome is for the newly read FCF record should be * chosen; otherwise, return false when outcome is for keeping the previously @@ -1805,7 +2169,7 @@ lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt) uint32_t rand_num; /* Get 16-bit uniform random number */ - rand_num = 0xFFFF & prandom_u32(); + rand_num = get_random_u16(); /* Decision with probability 1/fcf_cnt */ if ((fcf_cnt * rand_num) < 0xFFFF) @@ -1843,7 +2207,7 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); if (unlikely(!mboxq->sge_array)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2524 Failed to get the non-embedded SGE " "virtual address\n"); return NULL; @@ -1859,11 +2223,12 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, if (shdr_status || shdr_add_status) { if (shdr_status == STATUS_FCF_TABLE_EMPTY || if_type == LPFC_SLI_INTF_IF_TYPE_2) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2726 READ_FCF_RECORD Indicates empty " "FCF table.\n"); else - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2521 READ_FCF_RECORD mailbox failed " "with status x%x add_status x%x, " "mbx\n", shdr_status, shdr_add_status); @@ -1947,7 +2312,7 @@ lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba, } /** - lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF + * lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF * @phba: pointer to lpfc hba data structure. * @fcf_rec: pointer to an existing FCF record. * @new_fcf_record: pointer to a new FCF record. @@ -2061,7 +2426,7 @@ stop_flogi_current_fcf: /** * lpfc_sli4_fcf_pri_list_del * @phba: pointer to lpfc hba data structure. - * @fcf_index the index of the fcf record to delete + * @fcf_index: the index of the fcf record to delete * This routine checks the on list flag of the fcf_index to be deleted. * If it is one the list then it is removed from the list, and the flag * is cleared. This routine grab the hbalock before removing the fcf @@ -2091,7 +2456,7 @@ static void lpfc_sli4_fcf_pri_list_del(struct lpfc_hba *phba, /** * lpfc_sli4_set_fcf_flogi_fail * @phba: pointer to lpfc hba data structure. - * @fcf_index the index of the fcf record to update + * @fcf_index: the index of the fcf record to update * This routine acquires the hbalock and then set the LPFC_FCF_FLOGI_FAILED * flag so the the round robin slection for the particular priority level * will try a different fcf record that does not have this bit set. @@ -2111,7 +2476,8 @@ lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *phba, uint16_t fcf_index) /** * lpfc_sli4_fcf_pri_list_add * @phba: pointer to lpfc hba data structure. - * @fcf_index the index of the fcf record to add + * @fcf_index: the index of the fcf record to add + * @new_fcf_record: pointer to a new FCF record. * This routine checks the priority of the fcf_index to be added. * If it is a lower priority than the current head of the fcf_pri list * then it is added to the list in the right order. @@ -2241,7 +2607,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq, &next_fcf_index); if (!new_fcf_record) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2765 Mailbox command READ_FCF_RECORD " "failed to retrieve a FCF record.\n"); /* Let next new FCF event trigger fast failover */ @@ -2285,7 +2651,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) new_fcf_record, LPFC_FCOE_IGNORE_VID)) { if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) != phba->fcf.current_rec.fcf_indx) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2862 FCF (x%x) matches property " "of in-use FCF (x%x)\n", bf_get(lpfc_fcf_record_fcf_index, @@ -2355,7 +2722,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->pport->fc_flag); goto out; } else - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2863 New FCF (x%x) matches " "property of in-use FCF (x%x)\n", bf_get(lpfc_fcf_record_fcf_index, @@ -2603,7 +2970,7 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) uint32_t boot_flag, addr_mode; uint16_t next_fcf_index, fcf_index; uint16_t current_fcf_index; - uint16_t vlan_id; + uint16_t vlan_id = LPFC_FCOE_NULL_VID; int rc; /* If link state is not up, stop the roundrobin failover process */ @@ -2708,7 +3075,7 @@ lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct fcf_record *new_fcf_record; uint32_t boot_flag, addr_mode; uint16_t fcf_index, next_fcf_index; - uint16_t vlan_id; + uint16_t vlan_id = LPFC_FCOE_NULL_VID; int rc; /* If link state is not up, no need to proceed */ @@ -2769,10 +3136,9 @@ lpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != LPFC_SLI_INTF_IF_TYPE_0) && mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, - "2891 Init VFI mailbox failed 0x%x\n", - mboxq->u.mb.mbxStatus); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2891 Init VFI mailbox failed 0x%x\n", + mboxq->u.mb.mbxStatus); mempool_free(mboxq, phba->mbox_mem_pool); lpfc_vport_set_state(vport, FC_VPORT_FAILED); return; @@ -2800,7 +3166,7 @@ lpfc_issue_init_vfi(struct lpfc_vport *vport) mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2892 Failed to allocate " + LOG_TRACE_EVENT, "2892 Failed to allocate " "init_vfi mailbox\n"); return; } @@ -2808,8 +3174,8 @@ lpfc_issue_init_vfi(struct lpfc_vport *vport) mboxq->mbox_cmpl = lpfc_init_vfi_cmpl; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2893 Failed to issue init_vfi mailbox\n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2893 Failed to issue init_vfi mailbox\n"); mempool_free(mboxq, vport->phba->mbox_mem_pool); } } @@ -2829,10 +3195,9 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (mboxq->u.mb.mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, - "2609 Init VPI mailbox failed 0x%x\n", - mboxq->u.mb.mbxStatus); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2609 Init VPI mailbox failed 0x%x\n", + mboxq->u.mb.mbxStatus); mempool_free(mboxq, phba->mbox_mem_pool); lpfc_vport_set_state(vport, FC_VPORT_FAILED); return; @@ -2846,7 +3211,7 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) lpfc_printf_vlog(vport, KERN_ERR, - LOG_DISCOVERY, + LOG_TRACE_EVENT, "2731 Cannot find fabric " "controller node\n"); else @@ -2859,7 +3224,7 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_initial_fdisc(vport); else { lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2606 No NPIV Fabric support\n"); } mempool_free(mboxq, phba->mbox_mem_pool); @@ -2882,8 +3247,7 @@ lpfc_issue_init_vpi(struct lpfc_vport *vport) if ((vport->port_type != LPFC_PHYSICAL_PORT) && (!vport->vpi)) { vpi = lpfc_alloc_vpi(vport->phba); if (!vpi) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "3303 Failed to obtain vport vpi\n"); lpfc_vport_set_state(vport, FC_VPORT_FAILED); return; @@ -2894,7 +3258,7 @@ lpfc_issue_init_vpi(struct lpfc_vport *vport) mboxq = mempool_alloc(vport->phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2607 Failed to allocate " + LOG_TRACE_EVENT, "2607 Failed to allocate " "init_vpi mailbox\n"); return; } @@ -2903,8 +3267,8 @@ lpfc_issue_init_vpi(struct lpfc_vport *vport) mboxq->mbox_cmpl = lpfc_init_vpi_cmpl; rc = lpfc_sli_issue_mbox(vport->phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2608 Failed to issue init_vpi mailbox\n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2608 Failed to issue init_vpi mailbox\n"); mempool_free(mboxq, vport->phba->mbox_mem_pool); } } @@ -2948,7 +3312,7 @@ lpfc_start_fdiscs(struct lpfc_hba *phba) lpfc_vport_set_state(vports[i], FC_VPORT_NO_FABRIC_SUPP); lpfc_printf_vlog(vports[i], KERN_ERR, - LOG_ELS, + LOG_TRACE_EVENT, "0259 No NPIV " "Fabric support\n"); } @@ -2960,7 +3324,6 @@ lpfc_start_fdiscs(struct lpfc_hba *phba) void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { - struct lpfc_dmabuf *dmabuf = mboxq->ctx_buf; struct lpfc_vport *vport = mboxq->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); @@ -2972,10 +3335,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != LPFC_SLI_INTF_IF_TYPE_0) && mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "2018 REG_VFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2018 REG_VFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { /* FLOGI failed, use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); @@ -3041,12 +3404,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) } out_free_mem: - mempool_free(mboxq, phba->mbox_mem_pool); - if (dmabuf) { - lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); - kfree(dmabuf); - } - return; + lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED); } static void @@ -3062,7 +3420,7 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Check for error */ if (mb->mbxStatus) { /* READ_SPARAM mbox error <mbxStatus> state <hba_state> */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0319 READ_SPARAM mbxStatus error x%x " "hba state x%x>\n", mb->mbxStatus, vport->port_state); @@ -3091,18 +3449,20 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) memcpy(&phba->wwpn, &vport->fc_portname, sizeof(phba->wwnn)); } - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); + + /* Check if sending the FLOGI is being deferred to after we get + * up to date CSPs from MBX_READ_SPARAM. + */ + if (phba->hba_flag & HBA_DEFER_FLOGI) { + lpfc_initial_flogi(vport); + phba->hba_flag &= ~HBA_DEFER_FLOGI; + } return; out: - pmb->ctx_buf = NULL; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); lpfc_issue_clear_la(phba, vport); - mempool_free(pmb, phba->mbox_mem_pool); - return; } static void @@ -3112,7 +3472,6 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL; struct Scsi_Host *shost; int i; - struct lpfc_dmabuf *mp; int rc; struct fcf_record *fcf_record; uint32_t fc_flags = 0; @@ -3132,6 +3491,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) case LPFC_LINK_SPEED_32GHZ: case LPFC_LINK_SPEED_64GHZ: case LPFC_LINK_SPEED_128GHZ: + case LPFC_LINK_SPEED_256GHZ: break; default: phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN; @@ -3149,7 +3509,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) } phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la); - phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED; + phba->link_flag &= ~(LS_NPIV_FAB_SUPPORTED | LS_CT_VEN_RPA); shost = lpfc_shost_from_vport(vport); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { @@ -3224,6 +3584,8 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) } lpfc_linkup(phba); + sparam_mbox = NULL; + sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!sparam_mbox) goto out; @@ -3237,10 +3599,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - mp = (struct lpfc_dmabuf *)sparam_mbox->ctx_buf; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(sparam_mbox, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, sparam_mbox, MBOX_THD_UNLOCKED); goto out; } @@ -3269,7 +3628,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) GFP_KERNEL); if (unlikely(!fcf_record)) { lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_SLI, + LOG_TRACE_EVENT, "2554 Could not allocate memory for " "fcf record\n"); rc = -ENODEV; @@ -3281,7 +3640,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) rc = lpfc_sli4_add_fcf_record(phba, fcf_record); if (unlikely(rc)) { lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_SLI, + LOG_TRACE_EVENT, "2013 Could not manually add FCF " "record 0, status %d\n", rc); rc = -ENODEV; @@ -3323,7 +3682,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) return; out: lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0263 Discovery Mailbox error: state: 0x%x : x%px x%px\n", vport->port_state, sparam_mbox, cfglink_mbox); lpfc_issue_clear_la(phba, vport); @@ -3409,18 +3768,8 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } phba->fc_eventTag = la->eventTag; - if (phba->sli_rev < LPFC_SLI_REV4) { - spin_lock_irqsave(&phba->hbalock, iflags); - if (bf_get(lpfc_mbx_read_top_mm, la)) - phba->sli.sli_flag |= LPFC_MENLO_MAINT; - else - phba->sli.sli_flag &= ~LPFC_MENLO_MAINT; - spin_unlock_irqrestore(&phba->hbalock, iflags); - } - phba->link_events++; - if ((attn_type == LPFC_ATT_LINK_UP) && - !(phba->sli.sli_flag & LPFC_MENLO_MAINT)) { + if (attn_type == LPFC_ATT_LINK_UP) { phba->fc_stat.LinkUp++; if (phba->link_flag & LS_LOOPBACK_MODE) { lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, @@ -3434,17 +3783,22 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1303 Link Up Event x%x received " - "Data: x%x x%x x%x x%x x%x x%x %d\n", + "Data: x%x x%x x%x x%x x%x\n", la->eventTag, phba->fc_eventTag, bf_get(lpfc_mbx_read_top_alpa_granted, la), bf_get(lpfc_mbx_read_top_link_spd, la), phba->alpa_map[0], - bf_get(lpfc_mbx_read_top_mm, la), - bf_get(lpfc_mbx_read_top_fa, la), - phba->wait_4_mlo_maint_flg); + bf_get(lpfc_mbx_read_top_fa, la)); } lpfc_mbx_process_link_up(phba, la); + + if (phba->cmf_active_mode != LPFC_CFG_OFF) + lpfc_cmf_signal_init(phba); + + if (phba->lmt & LMT_64Gb) + lpfc_read_lds_params(phba); + } else if (attn_type == LPFC_ATT_LINK_DOWN || attn_type == LPFC_ATT_UNEXP_WWPN) { phba->fc_stat.LinkDown++; @@ -3458,64 +3812,28 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) else if (attn_type == LPFC_ATT_UNEXP_WWPN) lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1313 Link Down Unexpected FA WWPN Event x%x " - "received Data: x%x x%x x%x x%x x%x\n", + "received Data: x%x x%x x%x x%x\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag, - bf_get(lpfc_mbx_read_top_mm, la), bf_get(lpfc_mbx_read_top_fa, la)); else lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1305 Link Down Event x%x received " - "Data: x%x x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%x\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag, - bf_get(lpfc_mbx_read_top_mm, la), bf_get(lpfc_mbx_read_top_fa, la)); lpfc_mbx_issue_link_down(phba); } - if (phba->sli.sli_flag & LPFC_MENLO_MAINT && - attn_type == LPFC_ATT_LINK_UP) { - if (phba->link_state != LPFC_LINK_DOWN) { - phba->fc_stat.LinkDown++; - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1312 Link Down Event x%x received " - "Data: x%x x%x x%x\n", - la->eventTag, phba->fc_eventTag, - phba->pport->port_state, vport->fc_flag); - lpfc_mbx_issue_link_down(phba); - } else - lpfc_enable_la(phba); - - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1310 Menlo Maint Mode Link up Event x%x rcvd " - "Data: x%x x%x x%x\n", - la->eventTag, phba->fc_eventTag, - phba->pport->port_state, vport->fc_flag); - /* - * The cmnd that triggered this will be waiting for this - * signal. - */ - /* WAKEUP for MENLO_SET_MODE or MENLO_RESET command. */ - if (phba->wait_4_mlo_maint_flg) { - phba->wait_4_mlo_maint_flg = 0; - wake_up_interruptible(&phba->wait_4_mlo_m_q); - } - } if ((phba->sli_rev < LPFC_SLI_REV4) && - bf_get(lpfc_mbx_read_top_fa, la)) { - if (phba->sli.sli_flag & LPFC_MENLO_MAINT) - lpfc_issue_clear_la(phba, vport); + bf_get(lpfc_mbx_read_top_fa, la)) lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, "1311 fa %d\n", bf_get(lpfc_mbx_read_top_fa, la)); - } lpfc_mbx_cmpl_read_topology_free_mbuf: - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - return; + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); } /* @@ -3528,18 +3846,21 @@ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); + struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)pmb->ctx_buf; struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + /* The driver calls the state machine with the pmb pointer + * but wants to make sure a stale ctx_buf isn't acted on. + * The ctx_buf is restored later and cleaned up. + */ pmb->ctx_buf = NULL; pmb->ctx_ndlp = NULL; - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "0002 rpi:%x DID:%x flg:%x %d map:%x x%px\n", + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI | LOG_NODE | LOG_DISCOVERY, + "0002 rpi:%x DID:%x flg:%x %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); + ndlp); if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; @@ -3553,9 +3874,9 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * there is another reg login in * process. */ - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* * We cannot leave the RPI registered because @@ -3568,10 +3889,9 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Call state machine */ lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN); + pmb->ctx_buf = mp; + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); /* decrement the node reference count held for this callback * function. */ @@ -3596,7 +3916,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) break; /* If VPI is busy, reset the HBA */ case 0x9700: - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n", vport->vpi, mb->mbxStatus); if (!(phba->pport->load_flag & FC_UNLOADING)) @@ -3607,7 +3927,6 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport->vpi_state &= ~LPFC_VPI_REGISTERED; vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); - vport->unreg_vpi_cmpl = VPORT_OK; mempool_free(pmb, phba->mbox_mem_pool); lpfc_cleanup_vports_rrqs(vport, NULL); /* @@ -3634,10 +3953,9 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1800 Could not issue unreg_vpi\n"); mempool_free(mbox, phba->mbox_mem_pool); - vport->unreg_vpi_cmpl = VPORT_ERROR; return rc; } return 0; @@ -3721,7 +4039,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba) pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0542 lpfc_create_static_vport failed to" " allocate mailbox memory\n"); return; @@ -3731,7 +4049,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba) vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL); if (!vport_info) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0543 lpfc_create_static_vport failed to" " allocate vport_info\n"); mempool_free(pmb, phba->mbox_mem_pool); @@ -3740,11 +4058,15 @@ lpfc_create_static_vport(struct lpfc_hba *phba) vport_buff = (uint8_t *) vport_info; do { - /* free dma buffer from previous round */ + /* While loop iteration forces a free dma buffer from + * the previous loop because the mbox is reused and + * the dump routine is a single-use construct. + */ if (pmb->ctx_buf) { mp = (struct lpfc_dmabuf *)pmb->ctx_buf; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); + pmb->ctx_buf = NULL; } if (lpfc_dump_static_vport(phba, pmb, offset)) goto out; @@ -3792,11 +4114,12 @@ lpfc_create_static_vport(struct lpfc_hba *phba) if ((le32_to_cpu(vport_info->signature) != VPORT_INFO_SIG) || ((le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK) != VPORT_INFO_REV)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0545 lpfc_create_static_vport bad" - " information header 0x%x 0x%x\n", - le32_to_cpu(vport_info->signature), - le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0545 lpfc_create_static_vport bad" + " information header 0x%x 0x%x\n", + le32_to_cpu(vport_info->signature), + le32_to_cpu(vport_info->rev) & + VPORT_INFO_REV_MASK); goto out; } @@ -3828,16 +4151,8 @@ lpfc_create_static_vport(struct lpfc_hba *phba) out: kfree(vport_info); - if (mbx_wait_rc != MBX_TIMEOUT) { - if (pmb->ctx_buf) { - mp = (struct lpfc_dmabuf *)pmb->ctx_buf; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - mempool_free(pmb, phba->mbox_mem_pool); - } - - return; + if (mbx_wait_rc != MBX_TIMEOUT) + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); } /* @@ -3851,22 +4166,16 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; struct Scsi_Host *shost; - ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; pmb->ctx_ndlp = NULL; - pmb->ctx_buf = NULL; if (mb->mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0258 Register Fabric login error: 0x%x\n", mb->mbxStatus); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { /* FLOGI failed, use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); @@ -3908,9 +4217,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_do_scr_ns_plogi(phba, vport); } - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); /* Drop the reference count from the mbox at the end after * all the current reference to the ndlp have been done. @@ -3933,7 +4240,8 @@ lpfc_issue_gidft(struct lpfc_vport *vport) /* Cannot issue NameServer FCP Query, so finish up * discovery */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0604 %s FC TYPE %x %s\n", "Failed to issue GID_FT to ", FC_TYPE_FCP, @@ -3949,7 +4257,8 @@ lpfc_issue_gidft(struct lpfc_vport *vport) /* Cannot issue NameServer NVME Query, so finish up * discovery */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0605 %s FC_TYPE %x %s %d\n", "Failed to issue GID_FT to ", FC_TYPE_NVME, @@ -3981,7 +4290,7 @@ lpfc_issue_gidpt(struct lpfc_vport *vport) /* Cannot issue NameServer FCP Query, so finish up * discovery */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0606 %s Port TYPE %x %s\n", "Failed to issue GID_PT to ", GID_PT_N_PORT, @@ -4002,16 +4311,15 @@ void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; struct lpfc_vport *vport = pmb->vport; + int rc; - pmb->ctx_buf = NULL; pmb->ctx_ndlp = NULL; vport->gidft_inp = 0; if (mb->mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0260 Register NameServer error: 0x%x\n", mb->mbxStatus); @@ -4020,12 +4328,18 @@ out: * callback function. */ lpfc_nlp_put(ndlp); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); - /* If no other thread is using the ndlp, free it */ - lpfc_nlp_not_used(ndlp); + /* If the node is not registered with the scsi or nvme + * transport, remove the fabric node. The failed reg_login + * is terminal. + */ + if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(&ndlp->lock); + lpfc_nlp_not_used(ndlp); + } if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { /* @@ -4048,10 +4362,10 @@ out: ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, - "0003 rpi:%x DID:%x flg:%x %d map%x x%px\n", + "0003 rpi:%x DID:%x flg:%x %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); + ndlp); if (vport->port_state < LPFC_VPORT_READY) { /* Link up discovery requires Fabric registration. */ @@ -4070,7 +4384,28 @@ out: FC_TYPE_NVME); /* Issue SCR just before NameServer GID_FT Query */ - lpfc_issue_els_scr(vport, SCR_DID, 0); + lpfc_issue_els_scr(vport, 0); + + /* Link was bounced or a Fabric LOGO occurred. Start EDC + * with initial FW values provided the congestion mode is + * not off. Note that signals may or may not be supported + * by the adapter but FPIN is provided by default for 1 + * or both missing signals support. + */ + if (phba->cmf_active_mode != LPFC_CFG_OFF) { + phba->cgn_reg_fpin = phba->cgn_init_reg_fpin; + phba->cgn_reg_signal = phba->cgn_init_reg_signal; + rc = lpfc_issue_els_edc(vport, 0); + lpfc_printf_log(phba, KERN_INFO, + LOG_INIT | LOG_ELS | LOG_DISCOVERY, + "4220 Issue EDC status x%x Data x%x\n", + rc, phba->cgn_init_reg_signal); + } else if (phba->lmt & LMT_64Gb) { + /* may send link fault capability descriptor */ + lpfc_issue_els_edc(vport, 0); + } else { + lpfc_issue_els_rdf(vport, 0); + } } vport->fc_ns_retry = 0; @@ -4085,13 +4420,54 @@ out: * callback function. */ lpfc_nlp_put(ndlp); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); return; } +/* + * This routine handles processing a Fabric Controller REG_LOGIN mailbox + * command upon completion. It is setup in the LPFC_MBOXQ + * as the completion routine when the command is handed off to the SLI layer. + */ +void +lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + struct lpfc_vport *vport = pmb->vport; + MAILBOX_t *mb = &pmb->u.mb; + struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; + + pmb->ctx_ndlp = NULL; + if (mb->mbxStatus) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0933 %s: Register FC login error: 0x%x\n", + __func__, mb->mbxStatus); + goto out; + } + + lpfc_check_nlp_post_devloss(vport, ndlp); + + if (phba->sli_rev < LPFC_SLI_REV4) + ndlp->nlp_rpi = mb->un.varWords[0]; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "0934 %s: Complete FC x%x RegLogin rpi x%x ste x%x\n", + __func__, ndlp->nlp_DID, ndlp->nlp_rpi, + ndlp->nlp_state); + + ndlp->nlp_flag |= NLP_RPI_REGISTERED; + ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + ndlp->nlp_type |= NLP_FABRIC; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + + out: + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); + + /* Drop the reference count from the mbox at the end after + * all the current reference to the ndlp have been done. + */ + lpfc_nlp_put(ndlp); +} + static void lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { @@ -4100,6 +4476,7 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) struct lpfc_rport_data *rdata; struct fc_rport_identifiers rport_ids; struct lpfc_hba *phba = vport->phba; + unsigned long flags; if (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME) return; @@ -4110,47 +4487,46 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rport_ids.port_id = ndlp->nlp_DID; rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; - /* - * We leave our node pointer in rport->dd_data when we unregister a - * FCP target port. But fc_remote_port_add zeros the space to which - * rport->dd_data points. So, if we're reusing a previously - * registered port, drop the reference that we took the last time we - * registered the port. - */ - rport = ndlp->rport; - if (rport) { - rdata = rport->dd_data; - /* break the link before dropping the ref */ - ndlp->rport = NULL; - if (rdata) { - if (rdata->pnode == ndlp) - lpfc_nlp_put(ndlp); - rdata->pnode = NULL; - } - /* drop reference for earlier registeration */ - put_device(&rport->dev); - } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport add: did:x%x flg:x%x type x%x", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); + "rport add: did:x%x flg:x%x type x%x", + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); /* Don't add the remote port if unloading. */ if (vport->load_flag & FC_UNLOADING) return; + /* + * Disassociate any older association between this ndlp and rport + */ + if (ndlp->rport) { + rdata = ndlp->rport->dd_data; + rdata->pnode = NULL; + } + ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); - if (!rport || !get_device(&rport->dev)) { + if (!rport) { dev_printk(KERN_WARNING, &phba->pcidev->dev, "Warning: fc_remote_port_add failed\n"); return; } - /* initialize static port data */ + /* Successful port add. Complete initializing node data */ rport->maxframe_size = ndlp->nlp_maxframe; rport->supported_classes = ndlp->nlp_class_sup; rdata = rport->dd_data; rdata->pnode = lpfc_nlp_get(ndlp); + if (!rdata->pnode) { + dev_warn(&phba->pcidev->dev, + "Warning - node ref failed. Unreg rport\n"); + fc_remote_port_delete(rport); + ndlp->rport = NULL; + return; + } + + spin_lock_irqsave(&ndlp->lock, flags); + ndlp->fc4_xpt_flags |= SCSI_XPT_REGD; + spin_unlock_irqrestore(&ndlp->lock, flags); if (ndlp->nlp_type & NLP_FCP_TARGET) rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET; @@ -4167,13 +4543,15 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) fc_remote_port_rolechg(rport, rport_ids.roles); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3183 rport register x%06x, rport x%px role x%x\n", - ndlp->nlp_DID, rport, rport_ids.roles); + "3183 %s rport x%px DID x%x, role x%x refcnt %d\n", + __func__, rport, rport->port_id, rport->roles, + kref_read(&ndlp->kref)); if ((rport->scsi_target_id != -1) && (rport->scsi_target_id < LPFC_MAX_TARGET)) { ndlp->nlp_sid = rport->scsi_target_id; } + return; } @@ -4191,12 +4569,13 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "3184 rport unregister x%06x, rport x%px\n", - ndlp->nlp_DID, rport); + "3184 rport unregister x%06x, rport x%px " + "xptflg x%x refcnt %d\n", + ndlp->nlp_DID, rport, ndlp->fc4_xpt_flags, + kref_read(&ndlp->kref)); fc_remote_port_delete(rport); - - return; + lpfc_nlp_put(ndlp); } static void @@ -4238,11 +4617,164 @@ lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count) spin_unlock_irqrestore(shost->host_lock, iflags); } +/* Register a node with backend if not already done */ +void +lpfc_nlp_reg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + unsigned long iflags; + + lpfc_check_nlp_post_devloss(vport, ndlp); + + spin_lock_irqsave(&ndlp->lock, iflags); + if (ndlp->fc4_xpt_flags & NLP_XPT_REGD) { + /* Already registered with backend, trigger rescan */ + spin_unlock_irqrestore(&ndlp->lock, iflags); + + if (ndlp->fc4_xpt_flags & NVME_XPT_REGD && + ndlp->nlp_type & (NLP_NVME_TARGET | NLP_NVME_DISCOVERY)) { + lpfc_nvme_rescan_port(vport, ndlp); + } + return; + } + + ndlp->fc4_xpt_flags |= NLP_XPT_REGD; + spin_unlock_irqrestore(&ndlp->lock, iflags); + + if (lpfc_valid_xpt_node(ndlp)) { + vport->phba->nport_event_cnt++; + /* + * Tell the fc transport about the port, if we haven't + * already. If we have, and it's a scsi entity, be + */ + lpfc_register_remote_port(vport, ndlp); + } + + /* We are done if we do not have any NVME remote node */ + if (!(ndlp->nlp_fc4_type & NLP_FC4_NVME)) + return; + + /* Notify the NVME transport of this new rport. */ + if (vport->phba->sli_rev >= LPFC_SLI_REV4 && + ndlp->nlp_fc4_type & NLP_FC4_NVME) { + if (vport->phba->nvmet_support == 0) { + /* Register this rport with the transport. + * Only NVME Target Rports are registered with + * the transport. + */ + if (ndlp->nlp_type & NLP_NVME_TARGET) { + vport->phba->nport_event_cnt++; + lpfc_nvme_register_port(vport, ndlp); + } + } else { + /* Just take an NDLP ref count since the + * target does not register rports. + */ + lpfc_nlp_get(ndlp); + } + } +} + +/* Unregister a node with backend if not already done */ +void +lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + unsigned long iflags; + + spin_lock_irqsave(&ndlp->lock, iflags); + if (!(ndlp->fc4_xpt_flags & NLP_XPT_REGD)) { + spin_unlock_irqrestore(&ndlp->lock, iflags); + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "0999 %s Not regd: ndlp x%px rport x%px DID " + "x%x FLG x%x XPT x%x\n", + __func__, ndlp, ndlp->rport, ndlp->nlp_DID, + ndlp->nlp_flag, ndlp->fc4_xpt_flags); + return; + } + + ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; + spin_unlock_irqrestore(&ndlp->lock, iflags); + + if (ndlp->rport && + ndlp->fc4_xpt_flags & SCSI_XPT_REGD) { + vport->phba->nport_event_cnt++; + lpfc_unregister_remote_port(ndlp); + } else if (!ndlp->rport) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "1999 %s NDLP in devloss x%px DID x%x FLG x%x" + " XPT x%x refcnt %d\n", + __func__, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->fc4_xpt_flags, + kref_read(&ndlp->kref)); + } + + if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) { + vport->phba->nport_event_cnt++; + if (vport->phba->nvmet_support == 0) { + /* Start devloss if target. */ + if (ndlp->nlp_type & NLP_NVME_TARGET) + lpfc_nvme_unregister_port(vport, ndlp); + } else { + /* NVMET has no upcall. */ + lpfc_nlp_put(ndlp); + } + } + +} + +/* + * Adisc state change handling + */ +static void +lpfc_handle_adisc_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + int new_state) +{ + switch (new_state) { + /* + * Any state to ADISC_ISSUE + * Do nothing, adisc cmpl handling will trigger state changes + */ + case NLP_STE_ADISC_ISSUE: + break; + + /* + * ADISC_ISSUE to mapped states + * Trigger a registration with backend, it will be nop if + * already registered + */ + case NLP_STE_UNMAPPED_NODE: + ndlp->nlp_type |= NLP_FC_NODE; + fallthrough; + case NLP_STE_MAPPED_NODE: + ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; + lpfc_nlp_reg_node(vport, ndlp); + break; + + /* + * ADISC_ISSUE to non-mapped states + * We are moving from ADISC_ISSUE to a non-mapped state because + * ADISC failed, we would have skipped unregistering with + * backend, attempt it now + */ + case NLP_STE_NPR_NODE: + ndlp->nlp_flag &= ~NLP_RCV_PLOGI; + fallthrough; + default: + lpfc_nlp_unreg_node(vport, ndlp); + break; + } + +} + static void lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int old_state, int new_state) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + /* Trap ADISC changes here */ + if (new_state == NLP_STE_ADISC_ISSUE || + old_state == NLP_STE_ADISC_ISSUE) { + lpfc_handle_adisc_state(vport, ndlp, new_state); + return; + } if (new_state == NLP_STE_UNMAPPED_NODE) { ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; @@ -4253,79 +4785,21 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (new_state == NLP_STE_NPR_NODE) ndlp->nlp_flag &= ~NLP_RCV_PLOGI; - /* FCP and NVME Transport interface */ + /* Reg/Unreg for FCP and NVME Transport interface */ if ((old_state == NLP_STE_MAPPED_NODE || old_state == NLP_STE_UNMAPPED_NODE)) { - if (ndlp->rport) { - vport->phba->nport_event_cnt++; - lpfc_unregister_remote_port(ndlp); - } - - if (ndlp->nlp_fc4_type & NLP_FC4_NVME) { - vport->phba->nport_event_cnt++; - if (vport->phba->nvmet_support == 0) { - /* Start devloss if target. */ - if (ndlp->nlp_type & NLP_NVME_TARGET) - lpfc_nvme_unregister_port(vport, ndlp); - } else { - /* NVMET has no upcall. */ - lpfc_nlp_put(ndlp); - } - } + /* For nodes marked for ADISC, Handle unreg in ADISC cmpl + * if linkup. In linkdown do unreg_node + */ + if (!(ndlp->nlp_flag & NLP_NPR_ADISC) || + !lpfc_is_link_up(vport->phba)) + lpfc_nlp_unreg_node(vport, ndlp); } - /* FCP and NVME Transport interfaces */ - if (new_state == NLP_STE_MAPPED_NODE || - new_state == NLP_STE_UNMAPPED_NODE) { - if (ndlp->nlp_fc4_type || - ndlp->nlp_DID == Fabric_DID || - ndlp->nlp_DID == NameServer_DID || - ndlp->nlp_DID == FDMI_DID) { - vport->phba->nport_event_cnt++; - /* - * Tell the fc transport about the port, if we haven't - * already. If we have, and it's a scsi entity, be - */ - lpfc_register_remote_port(vport, ndlp); - } - /* Notify the NVME transport of this new rport. */ - if (vport->phba->sli_rev >= LPFC_SLI_REV4 && - ndlp->nlp_fc4_type & NLP_FC4_NVME) { - if (vport->phba->nvmet_support == 0) { - /* Register this rport with the transport. - * Only NVME Target Rports are registered with - * the transport. - */ - if (ndlp->nlp_type & NLP_NVME_TARGET) { - vport->phba->nport_event_cnt++; - lpfc_nvme_register_port(vport, ndlp); - } - } else { - /* Just take an NDLP ref count since the - * target does not register rports. - */ - lpfc_nlp_get(ndlp); - } - } - } + new_state == NLP_STE_UNMAPPED_NODE) + lpfc_nlp_reg_node(vport, ndlp); - if ((new_state == NLP_STE_MAPPED_NODE) && - (vport->stat_data_enabled)) { - /* - * A new target is discovered, if there is no buffer for - * statistical data collection allocate buffer. - */ - ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT, - sizeof(struct lpfc_scsicmd_bkt), - GFP_KERNEL); - - if (!ndlp->lat_data) - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, - "0286 lpfc_nlp_state_cleanup failed to " - "allocate statistical data buffer DID " - "0x%x\n", ndlp->nlp_DID); - } /* * If the node just added to Mapped list was an FCP target, * but the remote port registration failed or assigned a target @@ -4337,9 +4811,9 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, (!ndlp->rport || ndlp->rport->scsi_target_id == -1 || ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_TGT_NO_SCSIID; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); } } @@ -4372,6 +4846,7 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); int old_state = ndlp->nlp_state; + int node_dropped = ndlp->nlp_flag & NLP_DROPPED; char name1[16], name2[16]; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, @@ -4384,6 +4859,12 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "node statechg did:x%x old:%d ste:%d", ndlp->nlp_DID, old_state, state); + if (node_dropped && old_state == NLP_STE_UNUSED_NODE && + state != NLP_STE_UNUSED_NODE) { + ndlp->nlp_flag &= ~NLP_DROPPED; + lpfc_nlp_get(ndlp); + } + if (old_state == NLP_STE_NPR_NODE && state != NLP_STE_NPR_NODE) lpfc_cancel_retry_delay_tmo(vport, ndlp); @@ -4431,15 +4912,6 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) NLP_STE_UNUSED_NODE); } -static void -lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - lpfc_cancel_retry_delay_tmo(vport, ndlp); - if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) - lpfc_nlp_counters(vport, ndlp->nlp_state, -1); - lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, - NLP_STE_UNUSED_NODE); -} /** * lpfc_initialize_node - Initialize all fields of node object * @vport: Pointer to Virtual Port object. @@ -4461,128 +4933,19 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); timer_setup(&ndlp->nlp_delayfunc, lpfc_els_retry_delay, 0); + INIT_LIST_HEAD(&ndlp->recovery_evt.evt_listp); + ndlp->nlp_DID = did; ndlp->vport = vport; ndlp->phba = vport->phba; ndlp->nlp_sid = NLP_NO_SID; ndlp->nlp_fc4_type = NLP_FC4_NONE; kref_init(&ndlp->kref); - NLP_INT_NODE_ACT(ndlp); atomic_set(&ndlp->cmd_pending, 0); ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; } -struct lpfc_nodelist * -lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - int state) -{ - struct lpfc_hba *phba = vport->phba; - uint32_t did, flag; - unsigned long flags; - unsigned long *active_rrqs_xri_bitmap = NULL; - int rpi = LPFC_RPI_ALLOC_ERROR; - uint32_t defer_did = 0; - - if (!ndlp) - return NULL; - - if (phba->sli_rev == LPFC_SLI_REV4) { - if (ndlp->nlp_rpi == LPFC_RPI_ALLOC_ERROR) - rpi = lpfc_sli4_alloc_rpi(vport->phba); - else - rpi = ndlp->nlp_rpi; - - if (rpi == LPFC_RPI_ALLOC_ERROR) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0359 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d FAILED RPI " - " ALLOC\n", - __func__, - (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - return NULL; - } - } - - spin_lock_irqsave(&phba->ndlp_lock, flags); - /* The ndlp should not be in memory free mode */ - if (NLP_CHK_FREE_REQ(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0277 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - goto free_rpi; - } - /* The ndlp should not already be in active mode */ - if (NLP_CHK_NODE_ACT(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0278 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - goto free_rpi; - } - - /* First preserve the orginal DID, xri_bitmap and some flags */ - did = ndlp->nlp_DID; - flag = (ndlp->nlp_flag & NLP_UNREG_INP); - if (flag & NLP_UNREG_INP) - defer_did = ndlp->nlp_defer_did; - if (phba->sli_rev == LPFC_SLI_REV4) - active_rrqs_xri_bitmap = ndlp->active_rrqs_xri_bitmap; - - /* Zero ndlp except of ndlp linked list pointer */ - memset((((char *)ndlp) + sizeof (struct list_head)), 0, - sizeof (struct lpfc_nodelist) - sizeof (struct list_head)); - - /* Next reinitialize and restore saved objects */ - lpfc_initialize_node(vport, ndlp, did); - ndlp->nlp_flag |= flag; - if (flag & NLP_UNREG_INP) - ndlp->nlp_defer_did = defer_did; - if (phba->sli_rev == LPFC_SLI_REV4) - ndlp->active_rrqs_xri_bitmap = active_rrqs_xri_bitmap; - - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - if (vport->phba->sli_rev == LPFC_SLI_REV4) { - ndlp->nlp_rpi = rpi; - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0008 rpi:%x DID:%x flg:%x refcnt:%d " - "map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, - kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); - } - - - if (state != NLP_STE_UNUSED_NODE) - lpfc_nlp_set_state(vport, ndlp, state); - else - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0013 rpi:%x DID:%x flg:%x refcnt:%d " - "map:%x x%px STATE=UNUSED\n", - ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, - kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, - "node enable: did:x%x", - ndlp->nlp_DID, 0, 0); - return ndlp; - -free_rpi: - if (phba->sli_rev == LPFC_SLI_REV4) { - lpfc_sli4_free_rpi(vport->phba, rpi); - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - } - return NULL; -} - void lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { @@ -4596,6 +4959,7 @@ lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) return; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); + ndlp->nlp_flag |= NLP_DROPPED; if (vport->phba->sli_rev == LPFC_SLI_REV4) { lpfc_cleanup_vports_rrqs(vport, ndlp); lpfc_unreg_rpi(vport, ndlp); @@ -4662,7 +5026,8 @@ lpfc_can_disctmo(struct lpfc_vport *vport) vport->port_state, vport->fc_ns_retry, vport->fc_flag); /* Turn off discovery timer if its running */ - if (vport->fc_flag & FC_DISC_TMO) { + if (vport->fc_flag & FC_DISC_TMO || + timer_pending(&vport->fc_disctmo)) { spin_lock_irqsave(shost->host_lock, iflags); vport->fc_flag &= ~FC_DISC_TMO; spin_unlock_irqrestore(shost->host_lock, iflags); @@ -4691,26 +5056,31 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, struct lpfc_iocbq *iocb, struct lpfc_nodelist *ndlp) { - IOCB_t *icmd = &iocb->iocb; - struct lpfc_vport *vport = ndlp->vport; + struct lpfc_vport *vport = ndlp->vport; + u8 ulp_command; + u16 ulp_context; + u32 remote_id; if (iocb->vport != vport) return 0; + ulp_command = get_job_cmnd(phba, iocb); + ulp_context = get_job_ulpcontext(phba, iocb); + remote_id = get_job_els_rsp64_did(phba, iocb); + if (pring->ringno == LPFC_ELS_RING) { - switch (icmd->ulpCommand) { + switch (ulp_command) { case CMD_GEN_REQUEST64_CR: - if (iocb->context_un.ndlp == ndlp) + if (iocb->ndlp == ndlp) return 1; - /* fall through */ + fallthrough; case CMD_ELS_REQUEST64_CR: - if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID) + if (remote_id == ndlp->nlp_DID) return 1; - /* fall through */ + fallthrough; case CMD_XMIT_ELS_RSP64_CX: - if (iocb->context1 == (uint8_t *) ndlp) + if (iocb->ndlp == ndlp) return 1; - /* fall through */ } } else if (pring->ringno == LPFC_FCP_RING) { /* Skip match check if waiting to relogin to FCP target */ @@ -4718,9 +5088,8 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, (ndlp->nlp_flag & NLP_DELAY_TMO)) { return 0; } - if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) { + if (ulp_context == ndlp->nlp_rpi) return 1; - } } return 0; } @@ -4820,7 +5189,6 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (!ndlp) return; lpfc_issue_els_logo(vport, ndlp, 0); - mempool_free(pmb, phba->mbox_mem_pool); /* Check to see if there are any deferred events to process */ if ((ndlp->nlp_flag & NLP_UNREG_INP) && @@ -4835,13 +5203,25 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); } else { + /* NLP_RELEASE_RPI is only set for SLI4 ports. */ if (ndlp->nlp_flag & NLP_RELEASE_RPI) { lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_RELEASE_RPI; ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; + spin_unlock_irq(&ndlp->lock); } + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_UNREG_INP; + spin_unlock_irq(&ndlp->lock); } + + /* The node has an outstanding reference for the unreg. Now + * that the LOGO action and cleanup are finished, release + * resources. + */ + lpfc_nlp_put(ndlp); + mempool_free(pmb, phba->mbox_mem_pool); } /* @@ -4855,8 +5235,14 @@ lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, { unsigned long iflags; + /* Driver always gets a reference on the mailbox job + * in support of async jobs. + */ + mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) + return; + if (ndlp->nlp_flag & NLP_ISSUE_LOGO) { - mbox->ctx_ndlp = ndlp; mbox->mbox_cmpl = lpfc_nlp_logo_unreg; } else if (phba->sli_rev == LPFC_SLI_REV4 && @@ -4864,20 +5250,15 @@ lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= LPFC_SLI_INTF_IF_TYPE_2) && (kref_read(&ndlp->kref) > 0)) { - mbox->ctx_ndlp = lpfc_nlp_get(ndlp); mbox->mbox_cmpl = lpfc_sli4_unreg_rpi_cmpl_clr; } else { if (vport->load_flag & FC_UNLOADING) { if (phba->sli_rev == LPFC_SLI_REV4) { - spin_lock_irqsave(&vport->phba->ndlp_lock, - iflags); + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag |= NLP_RELEASE_RPI; - spin_unlock_irqrestore(&vport->phba->ndlp_lock, - iflags); + spin_unlock_irqrestore(&ndlp->lock, iflags); } - lpfc_nlp_get(ndlp); } - mbox->ctx_ndlp = ndlp; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; } } @@ -4935,6 +5316,11 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_unreg_login(phba, vport->vpi, rpi, mbox); mbox->vport = vport; lpfc_set_unreg_login_mbx_cmpl(phba, vport, ndlp, mbox); + if (!mbox->ctx_ndlp) { + mempool_free(mbox, phba->mbox_mem_pool); + return 1; + } + if (mbox->mbox_cmpl == lpfc_sli4_unreg_rpi_cmpl_clr) /* * accept PLOGIs after unreg_rpi_cmpl @@ -4955,9 +5341,34 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { + ndlp->nlp_flag &= ~NLP_UNREG_INP; mempool_free(mbox, phba->mbox_mem_pool); acc_plogi = 1; + lpfc_nlp_put(ndlp); } + } else { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "1444 Failed to allocate mempool " + "unreg_rpi UNREG x%x, " + "DID x%x, flag x%x, " + "ndlp x%px\n", + ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag, ndlp); + + /* Because mempool_alloc failed, we + * will issue a LOGO here and keep the rpi alive if + * not unloading. + */ + if (!(vport->load_flag & FC_UNLOADING)) { + ndlp->nlp_flag &= ~NLP_UNREG_INP; + lpfc_issue_els_logo(vport, ndlp, 0); + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(vport, ndlp, + NLP_STE_NPR_NODE); + } + + return 1; } lpfc_no_rpi(phba, ndlp); out: @@ -4990,8 +5401,8 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (!vports) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "2884 Vport array allocation failed \n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2884 Vport array allocation failed \n"); return; } for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { @@ -5034,9 +5445,10 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport) mempool_free(mbox, phba->mbox_mem_pool); if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, - "1836 Could not issue " - "unreg_login(all_rpis) status %d\n", rc); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "1836 Could not issue " + "unreg_login(all_rpis) status %d\n", + rc); } } @@ -5063,7 +5475,7 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport) mempool_free(mbox, phba->mbox_mem_pool); if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1815 Could not issue " "unreg_did (default rpis) status %d\n", rc); @@ -5077,11 +5489,8 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport) static int lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mb, *nextmb; - struct lpfc_dmabuf *mp; - unsigned long iflags; /* Cleanup node for NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, @@ -5089,22 +5498,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "Data: x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - if (NLP_CHK_FREE_REQ(ndlp)) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0280 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - lpfc_dequeue_node(vport, ndlp); - } else { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0281 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - lpfc_disable_node(vport, ndlp); - } - + lpfc_dequeue_node(vport, ndlp); /* Don't need to clean up REG_LOGIN64 cmds for Default RPI cleanup */ @@ -5134,16 +5528,11 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && !(mb->mbox_flag & LPFC_MBX_IMED_UNREG) && (ndlp == (struct lpfc_nodelist *)mb->ctx_ndlp)) { - mp = (struct lpfc_dmabuf *)(mb->ctx_buf); - if (mp) { - __lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } list_del(&mb->list); - mempool_free(mb, phba->mbox_mem_pool); - /* We shall not invoke the lpfc_nlp_put to decrement - * the ndlp reference count as we are in the process - * of lpfc_nlp_release. + lpfc_mbox_rsrc_cleanup(phba, mb, MBOX_THD_LOCKED); + + /* Don't invoke lpfc_nlp_put. The driver is in + * lpfc_nlp_release context. */ } } @@ -5151,106 +5540,22 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_els_abort(phba, ndlp); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = 0; del_timer_sync(&ndlp->nlp_delayfunc); list_del_init(&ndlp->els_retry_evt.evt_listp); list_del_init(&ndlp->dev_loss_evt.evt_listp); + list_del_init(&ndlp->recovery_evt.evt_listp); lpfc_cleanup_vports_rrqs(vport, ndlp); + if (phba->sli_rev == LPFC_SLI_REV4) ndlp->nlp_flag |= NLP_RELEASE_RPI; - if (!lpfc_unreg_rpi(vport, ndlp)) { - /* Clean up unregistered and non freed rpis */ - if ((ndlp->nlp_flag & NLP_RELEASE_RPI) && - !(ndlp->nlp_rpi == LPFC_RPI_ALLOC_ERROR)) { - lpfc_sli4_free_rpi(vport->phba, - ndlp->nlp_rpi); - spin_lock_irqsave(&vport->phba->ndlp_lock, - iflags); - ndlp->nlp_flag &= ~NLP_RELEASE_RPI; - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - spin_unlock_irqrestore(&vport->phba->ndlp_lock, - iflags); - } - } - return 0; -} - -/* - * Check to see if we can free the nlp back to the freelist. - * If we are in the middle of using the nlp in the discovery state - * machine, defer the free till we reach the end of the state machine. - */ -static void -lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_rport_data *rdata; - struct fc_rport *rport; - LPFC_MBOXQ_t *mbox; - int rc; - lpfc_cancel_retry_delay_tmo(vport, ndlp); - if ((ndlp->nlp_flag & NLP_DEFER_RM) && - !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) && - !(ndlp->nlp_flag & NLP_RPI_REGISTERED) && - phba->sli_rev != LPFC_SLI_REV4) { - /* For this case we need to cleanup the default rpi - * allocated by the firmware. - */ - lpfc_printf_vlog(vport, KERN_INFO, - LOG_NODE | LOG_DISCOVERY, - "0005 Cleanup Default rpi:x%x DID:x%x flg:x%x " - "ref %d map:x%x ndlp x%px\n", - ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); - if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) - != NULL) { - rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID, - (uint8_t *) &vport->fc_sparam, mbox, ndlp->nlp_rpi); - if (rc) { - mempool_free(mbox, phba->mbox_mem_pool); - } - else { - mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; - mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; - mbox->vport = vport; - mbox->ctx_ndlp = ndlp; - rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - } - } - } - } - lpfc_cleanup_node(vport, ndlp); - - /* - * ndlp->rport must be set to NULL before it reaches here - * i.e. break rport/node link before doing lpfc_nlp_put for - * registered rport and then drop the reference of rport. - */ - if (ndlp->rport) { - /* - * extra lpfc_nlp_put dropped the reference of ndlp - * for registered rport so need to cleanup rport - */ - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0940 removed node x%px DID x%x " - "rpi %d rport not null x%px\n", - ndlp, ndlp->nlp_DID, ndlp->nlp_rpi, - ndlp->rport); - rport = ndlp->rport; - rdata = rport->dd_data; - rdata->pnode = NULL; - ndlp->rport = NULL; - put_device(&rport->dev); - } + return 0; } static int @@ -5319,8 +5624,8 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) if (lpfc_matchdid(vport, ndlp, did)) { data1 = (((uint32_t)ndlp->nlp_state << 24) | ((uint32_t)ndlp->nlp_xri << 16) | - ((uint32_t)ndlp->nlp_type << 8) | - ((uint32_t)ndlp->nlp_usg_map & 0xff)); + ((uint32_t)ndlp->nlp_type << 8) + ); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "0929 FIND node DID " "Data: x%px x%x x%x x%x x%x x%px\n", @@ -5388,7 +5693,6 @@ lpfc_findnode_mapped(struct lpfc_vport *vport) struct lpfc_nodelist * lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; ndlp = lpfc_findnode_did(vport, did); @@ -5409,28 +5713,9 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - return ndlp; - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - if (vport->phba->nvmet_support) - return NULL; - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE); - if (!ndlp) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI, - "0014 Could not enable ndlp\n"); - return NULL; - } - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "6454 Setup Enabled Node 2B_DISC x%x " - "Data:x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_flag, - ndlp->nlp_state, vport->fc_flag); - - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp; } @@ -5472,9 +5757,9 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6456 Skip Setup RSCN Node x%x " @@ -5508,9 +5793,9 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) */ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } return ndlp; } @@ -5716,9 +6001,9 @@ static void lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { LIST_HEAD(completions); - IOCB_t *icmd; struct lpfc_iocbq *iocb, *next_iocb; struct lpfc_sli_ring *pring; + u32 ulp_command; pring = lpfc_phba_elsring(phba); if (unlikely(!pring)) @@ -5729,12 +6014,13 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) */ spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { - if (iocb->context1 != ndlp) { + if (iocb->ndlp != ndlp) continue; - } - icmd = &iocb->iocb; - if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) || - (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) { + + ulp_command = get_job_cmnd(phba, iocb); + + if (ulp_command == CMD_ELS_REQUEST64_CR || + ulp_command == CMD_XMIT_ELS_RSP64_CX) { list_move_tail(&iocb->list, &completions); } @@ -5742,17 +6028,21 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) /* Next check the txcmplq */ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { - if (iocb->context1 != ndlp) { + if (iocb->ndlp != ndlp) continue; - } - icmd = &iocb->iocb; - if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR || - icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX) { - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + + ulp_command = get_job_cmnd(phba, iocb); + + if (ulp_command == CMD_ELS_REQUEST64_CR || + ulp_command == CMD_XMIT_ELS_RSP64_CX) { + lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); } } spin_unlock_irq(&phba->hbalock); + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); @@ -5767,8 +6057,6 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { lpfc_free_tx(phba, ndlp); @@ -5777,12 +6065,34 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) } } +/* + * lpfc_notify_xport_npr - notifies xport of node disappearance + * @vport: Pointer to Virtual Port object. + * + * Transitions all ndlps to NPR state. When lpfc_nlp_set_state + * calls lpfc_nlp_state_cleanup, the ndlp->rport is unregistered + * and transport notified that the node is gone. + * Return Code: + * none + */ +static void +lpfc_notify_xport_npr(struct lpfc_vport *vport) +{ + struct lpfc_nodelist *ndlp, *next_ndlp; + + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, + nlp_listp) { + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + } +} void lpfc_cleanup_discovery_resources(struct lpfc_vport *vport) { lpfc_els_flush_rscn(vport); lpfc_els_flush_cmd(vport); lpfc_disc_flush_list(vport); + if (pci_channel_offline(vport->phba->pcidev)) + lpfc_notify_xport_npr(vport); } /*****************************************************************************/ @@ -5856,8 +6166,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) /* Start discovery by sending FLOGI, clean up old rpis */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state != NLP_STE_NPR_NODE) continue; if (ndlp->nlp_type & NLP_FABRIC) { @@ -5884,7 +6192,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_FLOGI: /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ /* Initial FLOGI timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0222 Initial %s timeout\n", vport->vpi ? "FDISC" : "FLOGI"); @@ -5902,12 +6211,13 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_FABRIC_CFG_LINK: /* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for NameServer login */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0223 Timeout while waiting for " "NameServer login\n"); /* Next look for NameServer ndlp */ ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) + if (ndlp) lpfc_els_abort(phba, ndlp); /* ReStart discovery */ @@ -5915,7 +6225,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_NS_QRY: /* Check for wait for NameServer Rsp timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0224 NameServer Query timeout " "Data: x%x x%x\n", vport->fc_ns_retry, LPFC_MAX_NS_RETRY); @@ -5948,7 +6259,8 @@ restart_disc: /* Setup and issue mailbox INITIALIZE LINK command */ initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!initlinkmbox) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0206 Device Discovery " "completion error\n"); phba->link_state = LPFC_HBA_ERROR; @@ -5970,7 +6282,8 @@ restart_disc: case LPFC_DISC_AUTH: /* Node Authentication timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0227 Node Authentication timeout\n"); lpfc_disc_flush_list(vport); @@ -5990,10 +6303,12 @@ restart_disc: case LPFC_VPORT_READY: if (vport->fc_flag & FC_RSCN_MODE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0231 RSCN timeout Data: x%x " - "x%x\n", - vport->fc_ns_retry, LPFC_MAX_NS_RETRY); + "x%x x%x x%x\n", + vport->fc_ns_retry, LPFC_MAX_NS_RETRY, + vport->port_state, vport->gidft_inp); /* Cleanup any outstanding ELS commands */ lpfc_els_flush_cmd(vport); @@ -6004,7 +6319,8 @@ restart_disc: break; default: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0273 Unexpected discovery timeout, " "vport State x%x\n", vport->port_state); break; @@ -6013,21 +6329,23 @@ restart_disc: switch (phba->link_state) { case LPFC_CLEAR_LA: /* CLEAR LA timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0228 CLEAR LA timeout\n"); clrlaerr = 1; break; case LPFC_LINK_UP: lpfc_issue_clear_la(phba, vport); - /* fall through */ + fallthrough; case LPFC_LINK_UNKNOWN: case LPFC_WARM_START: case LPFC_INIT_START: case LPFC_INIT_MBX_CMDS: case LPFC_LINK_DOWN: case LPFC_HBA_ERROR: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0230 Unexpected timeout, hba link " "state x%x\n", phba->link_state); clrlaerr = 1; @@ -6060,11 +6378,9 @@ void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; struct lpfc_vport *vport = pmb->vport; - pmb->ctx_buf = NULL; pmb->ctx_ndlp = NULL; if (phba->sli_rev < LPFC_SLI_REV4) @@ -6073,30 +6389,29 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, - "0004 rpi:%x DID:%x flg:%x %d map:%x x%px\n", + "0004 rpi:%x DID:%x flg:%x %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); + ndlp); /* * Start issuing Fabric-Device Management Interface (FDMI) command to * 0xfffffa (FDMI well known port). * DHBA -> DPRT -> RHBA -> RPA (physical port) * DPRT -> RPRT (vports) */ - if (vport->port_type == LPFC_PHYSICAL_PORT) + if (vport->port_type == LPFC_PHYSICAL_PORT) { + phba->link_flag &= ~LS_CT_VEN_RPA; /* For extra Vendor RPA */ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0); - else + } else { lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0); + } /* decrement the node reference count held for this callback * function. */ lpfc_nlp_put(ndlp); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); return; } @@ -6105,10 +6420,6 @@ lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param) { uint16_t *rpi = param; - /* check for active node */ - if (!NLP_CHK_NODE_ACT(ndlp)) - return 0; - return ndlp->nlp_rpi == *rpi; } @@ -6212,15 +6523,15 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) * Translate the physical vpi to the logical vpi. The * vport stores the logical vpi. */ - for (i = 0; i < phba->max_vpi; i++) { + for (i = 0; i <= phba->max_vpi; i++) { if (vpi == phba->vpi_ids[i]) break; } - if (i >= phba->max_vpi) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "2936 Could not find Vport mapped " - "to vpi %d\n", vpi); + if (i > phba->max_vpi) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2936 Could not find Vport mapped " + "to vpi %d\n", vpi); return NULL; } } @@ -6257,16 +6568,17 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) memset(ndlp, 0, sizeof (struct lpfc_nodelist)); + spin_lock_init(&ndlp->lock); + lpfc_initialize_node(vport, ndlp, did); INIT_LIST_HEAD(&ndlp->nlp_listp); if (vport->phba->sli_rev == LPFC_SLI_REV4) { ndlp->nlp_rpi = rpi; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0007 Init New ndlp x%px, rpi:x%x DID:%x " - "flg:x%x refcnt:%d map:x%x\n", + "flg:x%x refcnt:%d\n", ndlp, ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, kref_read(&ndlp->kref), - ndlp->nlp_usg_map); + ndlp->nlp_flag, kref_read(&ndlp->kref)); ndlp->active_rrqs_xri_bitmap = mempool_alloc(vport->phba->active_rrq_pool, @@ -6291,39 +6603,51 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) static void lpfc_nlp_release(struct kref *kref) { - struct lpfc_hba *phba; - unsigned long flags; struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, kref); + struct lpfc_vport *vport = ndlp->vport; lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, "node release: did:x%x flg:x%x type:x%x", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0279 %s: ndlp:x%px did %x " - "usgmap:x%x refcnt:%d rpi:%x\n", - __func__, - (void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map, - kref_read(&ndlp->kref), ndlp->nlp_rpi); + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "0279 %s: ndlp: x%px did %x refcnt:%d rpi:%x\n", + __func__, ndlp, ndlp->nlp_DID, + kref_read(&ndlp->kref), ndlp->nlp_rpi); /* remove ndlp from action. */ - lpfc_nlp_remove(ndlp->vport, ndlp); + lpfc_cancel_retry_delay_tmo(vport, ndlp); + lpfc_cleanup_node(vport, ndlp); + + /* Not all ELS transactions have registered the RPI with the port. + * In these cases the rpi usage is temporary and the node is + * released when the WQE is completed. Catch this case to free the + * RPI to the pool. Because this node is in the release path, a lock + * is unnecessary. All references are gone and the node has been + * dequeued. + */ + if (ndlp->nlp_flag & NLP_RELEASE_RPI) { + if (ndlp->nlp_rpi != LPFC_RPI_ALLOC_ERROR && + !(ndlp->nlp_flag & (NLP_RPI_REGISTERED | NLP_UNREG_INP))) { + lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; + } + } - /* clear the ndlp active flag for all release cases */ - phba = ndlp->phba; - spin_lock_irqsave(&phba->ndlp_lock, flags); - NLP_CLR_NODE_ACT(ndlp); - spin_unlock_irqrestore(&phba->ndlp_lock, flags); + /* The node is not freed back to memory, it is released to a pool so + * the node fields need to be cleaned up. + */ + ndlp->vport = NULL; + ndlp->nlp_state = NLP_STE_FREED_NODE; + ndlp->nlp_flag = 0; + ndlp->fc4_xpt_flags = 0; /* free ndlp memory for final ndlp release */ - if (NLP_CHK_FREE_REQ(ndlp)) { - kfree(ndlp->lat_data); - if (phba->sli_rev == LPFC_SLI_REV4) - mempool_free(ndlp->active_rrqs_xri_bitmap, - ndlp->phba->active_rrq_pool); - mempool_free(ndlp, ndlp->phba->nlp_mem_pool); - } + if (ndlp->phba->sli_rev == LPFC_SLI_REV4) + mempool_free(ndlp->active_rrqs_xri_bitmap, + ndlp->phba->active_rrq_pool); + mempool_free(ndlp, ndlp->phba->nlp_mem_pool); } /* This routine bumps the reference count for a ndlp structure to ensure @@ -6333,7 +6657,6 @@ lpfc_nlp_release(struct kref *kref) struct lpfc_nodelist * lpfc_nlp_get(struct lpfc_nodelist *ndlp) { - struct lpfc_hba *phba; unsigned long flags; if (ndlp) { @@ -6341,94 +6664,43 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) "node get: did:x%x flg:x%x refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); + /* The check of ndlp usage to prevent incrementing the * ndlp reference count that is in the process of being * released. */ - phba = ndlp->phba; - spin_lock_irqsave(&phba->ndlp_lock, flags); - if (!NLP_CHK_NODE_ACT(ndlp) || NLP_CHK_FREE_ACK(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); + spin_lock_irqsave(&ndlp->lock, flags); + if (!kref_get_unless_zero(&ndlp->kref)) { + spin_unlock_irqrestore(&ndlp->lock, flags); lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0276 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); + "0276 %s: ndlp:x%px refcnt:%d\n", + __func__, (void *)ndlp, kref_read(&ndlp->kref)); return NULL; - } else - kref_get(&ndlp->kref); - spin_unlock_irqrestore(&phba->ndlp_lock, flags); + } + spin_unlock_irqrestore(&ndlp->lock, flags); + } else { + WARN_ONCE(!ndlp, "**** %s, get ref on NULL ndlp!", __func__); } + return ndlp; } /* This routine decrements the reference count for a ndlp structure. If the - * count goes to 0, this indicates the the associated nodelist should be - * freed. Returning 1 indicates the ndlp resource has been released; on the - * other hand, returning 0 indicates the ndlp resource has not been released - * yet. + * count goes to 0, this indicates the associated nodelist should be freed. */ int lpfc_nlp_put(struct lpfc_nodelist *ndlp) { - struct lpfc_hba *phba; - unsigned long flags; - - if (!ndlp) - return 1; - - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node put: did:x%x flg:x%x refcnt:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, - kref_read(&ndlp->kref)); - phba = ndlp->phba; - spin_lock_irqsave(&phba->ndlp_lock, flags); - /* Check the ndlp memory free acknowledge flag to avoid the - * possible race condition that kref_put got invoked again - * after previous one has done ndlp memory free. - */ - if (NLP_CHK_FREE_ACK(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0274 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); - return 1; - } - /* Check the ndlp inactivate log flag to avoid the possible - * race condition that kref_put got invoked again after ndlp - * is already in inactivating state. - */ - if (NLP_CHK_IACT_REQ(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0275 %s: ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - __func__, (void *)ndlp, ndlp->nlp_usg_map, + if (ndlp) { + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node put: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); - return 1; + } else { + WARN_ONCE(!ndlp, "**** %s, put ref on NULL ndlp!", __func__); } - /* For last put, mark the ndlp usage flags to make sure no - * other kref_get and kref_put on the same ndlp shall get - * in between the process when the final kref_put has been - * invoked on this ndlp. - */ - if (kref_read(&ndlp->kref) == 1) { - /* Indicate ndlp is put to inactive state. */ - NLP_SET_IACT_REQ(ndlp); - /* Acknowledge ndlp memory free has been seen. */ - if (NLP_CHK_FREE_REQ(ndlp)) - NLP_SET_FREE_ACK(ndlp); - } - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - /* Note, the kref_put returns 1 when decrementing a reference - * count that was 1, it invokes the release callback function, - * but it still left the reference count as 1 (not actually - * performs the last decrementation). Otherwise, it actually - * decrements the reference count and returns 0. - */ - return kref_put(&ndlp->kref, lpfc_nlp_release); + + return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; } /* This routine free's the specified nodelist if it is not in use @@ -6443,6 +6715,7 @@ lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) "node not used: did:x%x flg:x%x refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); + if (kref_read(&ndlp->kref) == 1) if (lpfc_nlp_put(ndlp)) return 1; @@ -6488,7 +6761,7 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) goto out; } list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport && + if (ndlp->rport && (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { ret = 1; spin_unlock_irq(shost->host_lock); @@ -6524,10 +6797,10 @@ lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); if (mboxq->u.mb.mbxStatus) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2555 UNREG_VFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2555 UNREG_VFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); } spin_lock_irq(shost->host_lock); phba->pport->fc_flag &= ~FC_VFI_REGISTERED; @@ -6549,10 +6822,10 @@ lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct lpfc_vport *vport = mboxq->vport; if (mboxq->u.mb.mbxStatus) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2550 UNREG_FCFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2550 UNREG_FCFI mbxStatus error x%x " + "HBA state x%x\n", + mboxq->u.mb.mbxStatus, vport->port_state); } mempool_free(mboxq, phba->mbox_mem_pool); return; @@ -6641,7 +6914,7 @@ lpfc_sli4_unregister_fcf(struct lpfc_hba *phba) mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2551 UNREG_FCFI mbox allocation failed" "HBA state x%x\n", phba->pport->port_state); return -ENOMEM; @@ -6652,7 +6925,7 @@ lpfc_sli4_unregister_fcf(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2552 Unregister FCFI command failed rc x%x " "HBA state x%x\n", rc, phba->pport->port_state); @@ -6676,7 +6949,7 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba) /* Preparation for unregistering fcf */ rc = lpfc_unregister_fcf_prep(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2748 Failed to prepare for unregistering " "HBA's FCF record: rc=%d\n", rc); return; @@ -6712,7 +6985,7 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag &= ~FCF_INIT_DISC; spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2553 lpfc_unregister_unused_fcf failed " "to read FCF record HBA state x%x\n", phba->pport->port_state); @@ -6734,7 +7007,7 @@ lpfc_unregister_fcf(struct lpfc_hba *phba) /* Preparation for unregistering fcf */ rc = lpfc_unregister_fcf_prep(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2749 Failed to prepare for unregistering " "HBA's FCF record: rc=%d\n", rc); return; @@ -6821,9 +7094,9 @@ lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba, conn_entry = kzalloc(sizeof(struct lpfc_fcf_conn_entry), GFP_KERNEL); if (!conn_entry) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2566 Failed to allocate connection" - " table entry\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2566 Failed to allocate connection" + " table entry\n"); return; } @@ -6967,7 +7240,7 @@ lpfc_parse_fcoe_conf(struct lpfc_hba *phba, /* Check the region signature first */ if (memcmp(buff, LPFC_REGION23_SIGNATURE, 4)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2567 Config region 23 has bad signature\n"); return; } @@ -6976,8 +7249,8 @@ lpfc_parse_fcoe_conf(struct lpfc_hba *phba, /* Check the data structure version */ if (buff[offset] != LPFC_REGION23_VERSION) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2568 Config region 23 has bad version\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2568 Config region 23 has bad version\n"); return; } offset += 4; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 436cdc8c5ef4..5c283936ff08 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -22,7 +22,7 @@ #define FDMI_DID 0xfffffaU #define NameServer_DID 0xfffffcU -#define SCR_DID 0xfffffdU +#define Fabric_Cntl_DID 0xfffffdU #define Fabric_DID 0xfffffeU #define Bcast_DID 0xffffffU #define Mask_DID 0xffffffU @@ -97,6 +97,18 @@ union CtCommandResponse { #define FC4_FEATURE_INIT 0x2 #define FC4_FEATURE_NVME_DISC 0x4 +enum rft_word0 { + RFT_FCP_REG = (0x1 << 8), +}; + +enum rft_word1 { + RFT_NVME_REG = (0x1 << 8), +}; + +enum rft_word3 { + RFT_APP_SERV_REG = (0x1 << 0), +}; + struct lpfc_sli_ct_request { /* Structure is in Big Endian format */ union CtRevisionId RevisionId; @@ -131,25 +143,13 @@ struct lpfc_sli_ct_request { uint8_t Fc4Type; } gid_ff; struct rft { - uint32_t PortId; /* For RFT_ID requests */ + __be32 port_id; /* For RFT_ID requests */ -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd0:16; - uint32_t rsvd1:7; - uint32_t fcpReg:1; /* Type 8 */ - uint32_t rsvd2:2; - uint32_t ipReg:1; /* Type 5 */ - uint32_t rsvd3:5; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t rsvd0:16; - uint32_t fcpReg:1; /* Type 8 */ - uint32_t rsvd1:7; - uint32_t rsvd3:5; - uint32_t ipReg:1; /* Type 5 */ - uint32_t rsvd2:2; -#endif - - uint32_t rsvd[7]; + __be32 fcp_reg; /* rsvd 31:9, fcp_reg 8, rsvd 7:0 */ + __be32 nvme_reg; /* rsvd 31:9, nvme_reg 8, rsvd 7:0 */ + __be32 word2; + __be32 app_serv_reg; /* rsvd 31:1, app_serv_reg 0 */ + __be32 word[4]; } rft; struct rnn { uint32_t PortId; /* For RNN_ID requests */ @@ -275,6 +275,7 @@ struct lpfc_sli_ct_request { #define SLI_CT_ACCESS_DENIED 0x10 #define SLI_CT_INVALID_PORT_ID 0x11 #define SLI_CT_DATABASE_EMPTY 0x12 +#define SLI_CT_APP_ID_NOT_AVAILABLE 0x40 /* * Name Server Command Codes @@ -400,16 +401,16 @@ struct csp { uint16_t altBbCredit:1; /* FC Word 1, bit 27 */ uint16_t edtovResolution:1; /* FC Word 1, bit 26 */ uint16_t multicast:1; /* FC Word 1, bit 25 */ - uint16_t broadcast:1; /* FC Word 1, bit 24 */ + uint16_t app_hdr_support:1; /* FC Word 1, bit 24 */ - uint16_t huntgroup:1; /* FC Word 1, bit 23 */ + uint16_t priority_tagging:1; /* FC Word 1, bit 23 */ uint16_t simplex:1; /* FC Word 1, bit 22 */ uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */ uint16_t dhd:1; /* FC Word 1, bit 18 */ uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */ uint16_t payloadlength:1; /* FC Word 1, bit 16 */ #else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t broadcast:1; /* FC Word 1, bit 24 */ + uint16_t app_hdr_support:1; /* FC Word 1, bit 24 */ uint16_t multicast:1; /* FC Word 1, bit 25 */ uint16_t edtovResolution:1; /* FC Word 1, bit 26 */ uint16_t altBbCredit:1; /* FC Word 1, bit 27 */ @@ -423,7 +424,7 @@ struct csp { uint16_t dhd:1; /* FC Word 1, bit 18 */ uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */ uint16_t simplex:1; /* FC Word 1, bit 22 */ - uint16_t huntgroup:1; /* FC Word 1, bit 23 */ + uint16_t priority_tagging:1; /* FC Word 1, bit 23 */ #endif uint8_t bbRcvSizeMsb; /* Upper nibble is reserved */ @@ -510,8 +511,6 @@ struct class_parms { uint8_t word3Reserved2; /* Fc Word 3, bit 0: 7 */ }; -#define FAPWWN_KEY_VENDOR 0x42524344 /*valid vendor version fawwpn key*/ - struct serv_parm { /* Structure is in Big Endian format */ struct csp cmn; struct lpfc_name portName; @@ -588,6 +587,7 @@ struct fc_vft_header { #define ELS_CMD_RRQ 0x12000000 #define ELS_CMD_REC 0x13000000 #define ELS_CMD_RDP 0x18000000 +#define ELS_CMD_RDF 0x19000000 #define ELS_CMD_PRLI 0x20100014 #define ELS_CMD_NVMEPRLI 0x20140018 #define ELS_CMD_PRLO 0x21100014 @@ -597,7 +597,6 @@ struct fc_vft_header { #define ELS_CMD_ADISC 0x52000000 #define ELS_CMD_FARP 0x54000000 #define ELS_CMD_FARPR 0x55000000 -#define ELS_CMD_RPS 0x56000000 #define ELS_CMD_RPL 0x57000000 #define ELS_CMD_FAN 0x60000000 #define ELS_CMD_RSCN 0x61040000 @@ -607,6 +606,9 @@ struct fc_vft_header { #define ELS_CMD_LIRR 0x7A000000 #define ELS_CMD_LCB 0x81000000 #define ELS_CMD_FPIN 0x16000000 +#define ELS_CMD_EDC 0x17000000 +#define ELS_CMD_QFPA 0xB0000000 +#define ELS_CMD_UVEM 0xB1000000 #else /* __LITTLE_ENDIAN_BITFIELD */ #define ELS_CMD_MASK 0xffff #define ELS_RSP_MASK 0xff @@ -630,6 +632,7 @@ struct fc_vft_header { #define ELS_CMD_RRQ 0x12 #define ELS_CMD_REC 0x13 #define ELS_CMD_RDP 0x18 +#define ELS_CMD_RDF 0x19 #define ELS_CMD_PRLI 0x14001020 #define ELS_CMD_NVMEPRLI 0x18001420 #define ELS_CMD_PRLO 0x14001021 @@ -639,7 +642,6 @@ struct fc_vft_header { #define ELS_CMD_ADISC 0x52 #define ELS_CMD_FARP 0x54 #define ELS_CMD_FARPR 0x55 -#define ELS_CMD_RPS 0x56 #define ELS_CMD_RPL 0x57 #define ELS_CMD_FAN 0x60 #define ELS_CMD_RSCN 0x0461 @@ -649,6 +651,9 @@ struct fc_vft_header { #define ELS_CMD_LIRR 0x7A #define ELS_CMD_LCB 0x81 #define ELS_CMD_FPIN ELS_FPIN +#define ELS_CMD_EDC ELS_EDC +#define ELS_CMD_QFPA 0xB0 +#define ELS_CMD_UVEM 0xB1 #endif /* @@ -657,6 +662,7 @@ struct fc_vft_header { struct ls_rjt { /* Structure is in Big Endian format */ union { + __be32 ls_rjt_error_be; uint32_t lsRjtError; struct { uint8_t lsRjtRsvd0; /* FC Word 0, bit 24:31 */ @@ -697,6 +703,7 @@ struct ls_rjt { /* Structure is in Big Endian format */ #define LSEXP_OUT_OF_RESOURCE 0x29 #define LSEXP_CANT_GIVE_DATA 0x2A #define LSEXP_REQ_UNSUPPORTED 0x2C +#define LSEXP_NO_RSRC_ASSIGN 0x52 uint8_t vendorUnique; /* FC Word 0, bit 0: 7 */ } b; } un; @@ -919,24 +926,6 @@ typedef struct _RNID { /* Structure is in Big Endian format */ } un; } __packed RNID; -typedef struct _RPS { /* Structure is in Big Endian format */ - union { - uint32_t portNum; - struct lpfc_name portName; - } un; -} RPS; - -typedef struct _RPS_RSP { /* Structure is in Big Endian format */ - uint16_t rsvd1; - uint16_t portStatus; - uint32_t linkFailureCnt; - uint32_t lossSyncCnt; - uint32_t lossSignalCnt; - uint32_t primSeqErrCnt; - uint32_t invalidXmitWord; - uint32_t crcCnt; -} RPS_RSP; - struct RLS { /* Structure is in Big Endian format */ uint32_t rls; #define rls_rsvd_SHIFT 24 @@ -1335,48 +1324,174 @@ struct fc_rdp_res_frame { }; +/* UVEM */ + +#define LPFC_UVEM_SIZE 60 +#define LPFC_UVEM_VEM_ID_DESC_SIZE 16 +#define LPFC_UVEM_VE_MAP_DESC_SIZE 20 + +#define VEM_ID_DESC_TAG 0x0001000A +struct lpfc_vem_id_desc { + uint32_t tag; + uint32_t length; + uint8_t vem_id[16]; +}; + +#define LPFC_QFPA_SIZE 4 + +#define INSTANTIATED_VE_DESC_TAG 0x0001000B +struct instantiated_ve_desc { + uint32_t tag; + uint32_t length; + uint8_t global_vem_id[16]; + uint32_t word6; +#define lpfc_instantiated_local_id_SHIFT 0 +#define lpfc_instantiated_local_id_MASK 0x000000ff +#define lpfc_instantiated_local_id_WORD word6 +#define lpfc_instantiated_nport_id_SHIFT 8 +#define lpfc_instantiated_nport_id_MASK 0x00ffffff +#define lpfc_instantiated_nport_id_WORD word6 +}; + +#define DEINSTANTIATED_VE_DESC_TAG 0x0001000C +struct deinstantiated_ve_desc { + uint32_t tag; + uint32_t length; + uint8_t global_vem_id[16]; + uint32_t word6; +#define lpfc_deinstantiated_nport_id_SHIFT 0 +#define lpfc_deinstantiated_nport_id_MASK 0x000000ff +#define lpfc_deinstantiated_nport_id_WORD word6 +#define lpfc_deinstantiated_local_id_SHIFT 24 +#define lpfc_deinstantiated_local_id_MASK 0x00ffffff +#define lpfc_deinstantiated_local_id_WORD word6 +}; + +/* Query Fabric Priority Allocation Response */ +#define LPFC_PRIORITY_RANGE_DESC_SIZE 12 + +struct priority_range_desc { + uint32_t tag; + uint32_t length; + uint8_t lo_range; + uint8_t hi_range; + uint8_t qos_priority; + uint8_t local_ve_id; +}; + +struct fc_qfpa_res { + uint32_t reply_sequence; /* LS_ACC or LS_RJT */ + uint32_t length; /* FC Word 1 */ + struct priority_range_desc desc[1]; +}; + +/* Application Server command code */ +/* VMID */ + +#define SLI_CT_APP_SEV_Subtypes 0x20 /* Application Server subtype */ + +#define SLI_CTAS_GAPPIA_ENT 0x0100 /* Get Application Identifier */ +#define SLI_CTAS_GALLAPPIA 0x0101 /* Get All Application Identifier */ +#define SLI_CTAS_GALLAPPIA_ID 0x0102 /* Get All Application Identifier */ + /* for Nport */ +#define SLI_CTAS_GAPPIA_IDAPP 0x0103 /* Get Application Identifier */ + /* for Nport */ +#define SLI_CTAS_RAPP_IDENT 0x0200 /* Register Application Identifier */ +#define SLI_CTAS_DAPP_IDENT 0x0300 /* Deregister Application */ + /* Identifier */ +#define SLI_CTAS_DALLAPP_ID 0x0301 /* Deregister All Application */ + /* Identifier */ + +struct entity_id_object { + uint8_t entity_id_len; + uint8_t entity_id[255]; /* VM UUID */ +}; + +struct app_id_object { + uint32_t port_id; + uint32_t app_id; + struct entity_id_object obj; +}; + +struct lpfc_vmid_rapp_ident_list { + uint32_t no_of_objects; + struct entity_id_object obj[1]; +}; + +struct lpfc_vmid_dapp_ident_list { + uint32_t no_of_objects; + struct entity_id_object obj[1]; +}; + +#define GALLAPPIA_ID_LAST 0x80 +struct lpfc_vmid_gallapp_ident_list { + uint8_t control; + uint8_t reserved[3]; + struct app_id_object app_id; +}; + +#define RAPP_IDENT_OFFSET (offsetof(struct lpfc_sli_ct_request, un) + 4) +#define DAPP_IDENT_OFFSET (offsetof(struct lpfc_sli_ct_request, un) + 4) +#define GALLAPPIA_ID_SIZE (offsetof(struct lpfc_sli_ct_request, un) + 4) +#define DALLAPP_ID_SIZE (offsetof(struct lpfc_sli_ct_request, un) + 4) + /******** FDMI ********/ /* lpfc_sli_ct_request defines the CT_IU preamble for FDMI commands */ #define SLI_CT_FDMI_Subtypes 0x10 /* Management Service Subtype */ -/* - * Registered Port List Format - */ -struct lpfc_fdmi_reg_port_list { - uint32_t EntryCnt; - uint32_t pe; /* Variable-length array */ +/* Definitions for HBA / Port attribute entries */ + +/* Attribute Entry Structures */ + +struct lpfc_fdmi_attr_u32 { + __be16 type; + __be16 len; + __be32 value_u32; }; +struct lpfc_fdmi_attr_wwn { + __be16 type; + __be16 len; -/* Definitions for HBA / Port attribute entries */ + /* Keep as u8[8] instead of __be64 to avoid accidental zero padding + * by compiler + */ + u8 name[8]; +}; -struct lpfc_fdmi_attr_def { /* Defined in TLV format */ - /* Structure is in Big Endian format */ - uint32_t AttrType:16; - uint32_t AttrLen:16; - uint32_t AttrValue; /* Marks start of Value (ATTRIBUTE_ENTRY) */ +struct lpfc_fdmi_attr_fullwwn { + __be16 type; + __be16 len; + + /* Keep as u8[8] instead of __be64 to avoid accidental zero padding + * by compiler + */ + u8 nname[8]; + u8 pname[8]; }; +struct lpfc_fdmi_attr_fc4types { + __be16 type; + __be16 len; + u8 value_types[32]; +}; -/* Attribute Entry */ -struct lpfc_fdmi_attr_entry { - union { - uint32_t AttrInt; - uint8_t AttrTypes[32]; - uint8_t AttrString[256]; - struct lpfc_name AttrWWN; - } un; +struct lpfc_fdmi_attr_string { + __be16 type; + __be16 len; + char value_string[256]; }; -#define LPFC_FDMI_MAX_AE_SIZE sizeof(struct lpfc_fdmi_attr_entry) +/* Maximum FDMI attribute length is Type+Len (4 bytes) + 256 byte string */ +#define FDMI_MAX_ATTRLEN sizeof(struct lpfc_fdmi_attr_string) /* * HBA Attribute Block */ struct lpfc_fdmi_attr_block { uint32_t EntryCnt; /* Number of HBA attribute entries */ - struct lpfc_fdmi_attr_entry Entry; /* Variable-length array */ + /* Variable Length Attribute Entry TLV's follow */ }; /* @@ -1394,14 +1509,24 @@ struct lpfc_fdmi_hba_ident { }; /* + * Registered Port List Format + */ +struct lpfc_fdmi_reg_port_list { + uint32_t EntryCnt; + struct lpfc_fdmi_port_entry pe; +} __packed; + +/* * Register HBA(RHBA) */ struct lpfc_fdmi_reg_hba { struct lpfc_fdmi_hba_ident hi; - struct lpfc_fdmi_reg_port_list rpl; /* variable-length array */ -/* struct lpfc_fdmi_attr_block ab; */ + struct lpfc_fdmi_reg_port_list rpl; }; +/******** MI MIB ********/ +#define SLI_CT_MIB_Subtypes 0x11 + /* * Register HBA Attributes (RHAT) */ @@ -1487,7 +1612,7 @@ struct lpfc_fdmi_reg_portattr { #define LPFC_FDMI2_HBA_ATTR 0x0002efff /* - * Port Attrubute Types + * Port Attribute Types */ #define RPRT_SUPPORTED_FC4_TYPES 0x1 /* 32 byte binary array */ #define RPRT_SUPPORTED_SPEED 0x2 /* 32-bit unsigned int */ @@ -1505,6 +1630,7 @@ struct lpfc_fdmi_reg_portattr { #define RPRT_PORT_STATE 0x101 /* 32-bit unsigned int */ #define RPRT_DISC_PORT 0x102 /* 32-bit unsigned int */ #define RPRT_PORT_ID 0x103 /* 32-bit unsigned int */ +#define RPRT_VENDOR_MI 0xf047 /* vendor ascii string */ #define RPRT_SMART_SERVICE 0xf100 /* 4 to 256 byte ASCII string */ #define RPRT_SMART_GUID 0xf101 /* 8 byte WWNN + 8 byte WWPN */ #define RPRT_SMART_VERSION 0xf102 /* 4 to 256 byte ASCII string */ @@ -1537,6 +1663,7 @@ struct lpfc_fdmi_reg_portattr { #define LPFC_FDMI_SMART_ATTR_port_info 0x00100000 /* Vendor specific */ #define LPFC_FDMI_SMART_ATTR_qos 0x00200000 /* Vendor specific */ #define LPFC_FDMI_SMART_ATTR_security 0x00400000 /* Vendor specific */ +#define LPFC_FDMI_VENDOR_ATTR_mi 0x00800000 /* Vendor specific */ /* Bit mask for FDMI-1 defined PORT attributes */ #define LPFC_FDMI1_PORT_ATTR 0x0000003f @@ -1595,6 +1722,7 @@ struct lpfc_fdmi_reg_portattr { #define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268 #define PCI_DEVICE_ID_LANCER_G6_FC 0xe300 #define PCI_DEVICE_ID_LANCER_G7_FC 0xf400 +#define PCI_DEVICE_ID_LANCER_G7P_FC 0xf500 #define PCI_DEVICE_ID_SAT_SMB 0xf011 #define PCI_DEVICE_ID_SAT_MID 0xf015 #define PCI_DEVICE_ID_RFLY 0xf095 @@ -1627,7 +1755,6 @@ struct lpfc_fdmi_reg_portattr { #define PCI_DEVICE_ID_HELIOS_SCSP 0xfd11 #define PCI_DEVICE_ID_HELIOS_DCSP 0xfd12 #define PCI_DEVICE_ID_ZEPHYR 0xfe00 -#define PCI_DEVICE_ID_HORNET 0xfe05 #define PCI_DEVICE_ID_ZEPHYR_SCSP 0xfe11 #define PCI_DEVICE_ID_ZEPHYR_DCSP 0xfe12 #define PCI_VENDOR_ID_SERVERENGINE 0x19a2 @@ -1635,6 +1762,28 @@ struct lpfc_fdmi_reg_portattr { #define PCI_DEVICE_ID_TOMCAT 0x0714 #define PCI_DEVICE_ID_SKYHAWK 0x0724 #define PCI_DEVICE_ID_SKYHAWK_VF 0x072c +#define PCI_VENDOR_ID_ATTO 0x117c +#define PCI_DEVICE_ID_CLRY_16XE 0x0064 +#define PCI_DEVICE_ID_CLRY_161E 0x0063 +#define PCI_DEVICE_ID_CLRY_162E 0x0064 +#define PCI_DEVICE_ID_CLRY_164E 0x0065 +#define PCI_DEVICE_ID_CLRY_16XP 0x0094 +#define PCI_DEVICE_ID_CLRY_161P 0x00a0 +#define PCI_DEVICE_ID_CLRY_162P 0x0094 +#define PCI_DEVICE_ID_CLRY_164P 0x00a1 +#define PCI_DEVICE_ID_CLRY_32XE 0x0094 +#define PCI_DEVICE_ID_CLRY_321E 0x00a2 +#define PCI_DEVICE_ID_CLRY_322E 0x00a3 +#define PCI_DEVICE_ID_CLRY_324E 0x00ac +#define PCI_DEVICE_ID_CLRY_32XP 0x00bb +#define PCI_DEVICE_ID_CLRY_321P 0x00bc +#define PCI_DEVICE_ID_CLRY_322P 0x00bd +#define PCI_DEVICE_ID_CLRY_324P 0x00be +#define PCI_DEVICE_ID_TLFC_2 0x0064 +#define PCI_DEVICE_ID_TLFC_2XX2 0x4064 +#define PCI_DEVICE_ID_TLFC_3 0x0094 +#define PCI_DEVICE_ID_TLFC_3162 0x40a6 +#define PCI_DEVICE_ID_TLFC_3322 0x40a7 #define JEDEC_ID_ADDRESS 0x0080001c #define FIREFLY_JEDEC_ID 0x1ACC @@ -1650,7 +1799,6 @@ struct lpfc_fdmi_reg_portattr { #define ZEPHYR_JEDEC_ID 0x0577 #define VIPER_JEDEC_ID 0x4838 #define SATURN_JEDEC_ID 0x1004 -#define HORNET_JDEC_ID 0x2057706D #define JEDEC_ID_MASK 0x0FFFF000 #define JEDEC_ID_SHIFT 12 @@ -2547,19 +2695,26 @@ typedef struct { } READ_SPARM_VAR; /* Structure for MB Command READ_STATUS (14) */ +enum read_status_word1 { + RD_ST_CC = 0x01, + RD_ST_XKB = 0x80, +}; + +enum read_status_word17 { + RD_ST_XMIT_XKB_MASK = 0x3fffff, +}; + +enum read_status_word18 { + RD_ST_RCV_XKB_MASK = 0x3fffff, +}; typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1:31; - uint32_t clrCounters:1; - uint16_t activeXriCnt; - uint16_t activeRpiCnt; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t clrCounters:1; - uint32_t rsvd1:31; - uint16_t activeRpiCnt; - uint16_t activeXriCnt; -#endif + u8 clear_counters; /* rsvd 7:1, cc 0 */ + u8 rsvd5; + u8 rsvd6; + u8 xkb; /* xkb 7, rsvd 6:0 */ + + u32 rsvd8; uint32_t xmitByteCnt; uint32_t rcvByteCnt; @@ -2571,6 +2726,14 @@ typedef struct { uint32_t totalRespExchanges; uint32_t rcvPbsyCnt; uint32_t rcvFbsyCnt; + + u32 drop_frame_no_rq; + u32 empty_rq; + u32 drop_frame_no_xri; + u32 empty_xri; + + u32 xmit_xkb; /* rsvd 31:22, xmit_xkb 21:0 */ + u32 rcv_xkb; /* rsvd 31:22, rcv_xkb 21:0 */ } READ_STATUS_VAR; /* Structure for MB Command READ_RPI (15) */ @@ -2936,7 +3099,6 @@ struct lpfc_mbx_read_top { #define lpfc_mbx_read_top_topology_WORD word3 #define LPFC_TOPOLOGY_PT_PT 0x01 /* Topology is pt-pt / pt-fabric */ #define LPFC_TOPOLOGY_LOOP 0x02 /* Topology is FC-AL */ -#define LPFC_TOPOLOGY_MM 0x05 /* maint mode zephtr to menlo */ /* store the LILP AL_PA position map into */ struct ulp_bde64 lilpBde64; #define LPFC_ALPA_MAP_SIZE 128 @@ -3284,8 +3446,7 @@ typedef struct { #endif #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1 : 19; /* Reserved */ - uint32_t cdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd1 : 20; /* Reserved */ uint32_t casabt : 1; /* Configure async abts status notice */ uint32_t rsvd2 : 2; /* Reserved */ uint32_t cbg : 1; /* Configure BlockGuard */ @@ -3309,12 +3470,10 @@ typedef struct { uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t rsvd2 : 2; /* Reserved */ uint32_t casabt : 1; /* Configure async abts status notice */ - uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd1 : 19; /* Reserved */ + uint32_t rsvd1 : 20; /* Reserved */ #endif #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd3 : 19; /* Reserved */ - uint32_t gdss : 1; /* Configure Data Security SLI */ + uint32_t rsvd3 : 20; /* Reserved */ uint32_t gasabt : 1; /* Grant async abts status notice */ uint32_t rsvd4 : 2; /* Reserved */ uint32_t gbg : 1; /* Grant BlockGuard */ @@ -3338,8 +3497,7 @@ typedef struct { uint32_t gbg : 1; /* Grant BlockGuard */ uint32_t rsvd4 : 2; /* Reserved */ uint32_t gasabt : 1; /* Grant async abts status notice */ - uint32_t gdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd3 : 19; /* Reserved */ + uint32_t rsvd3 : 20; /* Reserved */ #endif #ifdef __BIG_ENDIAN_BITFIELD @@ -3361,15 +3519,11 @@ typedef struct { uint32_t rsvd6; /* Reserved */ #ifdef __BIG_ENDIAN_BITFIELD - uint32_t fips_rev : 3; /* FIPS Spec Revision */ - uint32_t fips_level : 4; /* FIPS Level */ - uint32_t sec_err : 9; /* security crypto error */ + uint32_t rsvd7 : 16; uint32_t max_vpi : 16; /* Max number of virt N-Ports */ #else /* __LITTLE_ENDIAN */ uint32_t max_vpi : 16; /* Max number of virt N-Ports */ - uint32_t sec_err : 9; /* security crypto error */ - uint32_t fips_level : 4; /* FIPS Level */ - uint32_t fips_rev : 3; /* FIPS Spec Revision */ + uint32_t rsvd7 : 16; #endif } CONFIG_PORT_VAR; @@ -3581,19 +3735,26 @@ union sli_var { }; typedef struct { + struct_group_tagged(MAILBOX_word0, bits, + union { + struct { #ifdef __BIG_ENDIAN_BITFIELD - uint16_t mbxStatus; - uint8_t mbxCommand; - uint8_t mbxReserved:6; - uint8_t mbxHc:1; - uint8_t mbxOwner:1; /* Low order bit first word */ + uint16_t mbxStatus; + uint8_t mbxCommand; + uint8_t mbxReserved:6; + uint8_t mbxHc:1; + uint8_t mbxOwner:1; /* Low order bit first word */ #else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t mbxOwner:1; /* Low order bit first word */ - uint8_t mbxHc:1; - uint8_t mbxReserved:6; - uint8_t mbxCommand; - uint16_t mbxStatus; + uint8_t mbxOwner:1; /* Low order bit first word */ + uint8_t mbxHc:1; + uint8_t mbxReserved:6; + uint8_t mbxCommand; + uint16_t mbxStatus; #endif + }; + u32 word0; + }; + ); MAILVARIANTS un; union sli_var us; @@ -3652,7 +3813,7 @@ typedef struct { #define IOERR_ILLEGAL_COMMAND 0x06 #define IOERR_XCHG_DROPPED 0x07 #define IOERR_ILLEGAL_FIELD 0x08 -#define IOERR_BAD_CONTINUE 0x09 +#define IOERR_RPI_SUSPENDED 0x09 #define IOERR_TOO_MANY_BUFFERS 0x0A #define IOERR_RCV_BUFFER_WAITING 0x0B #define IOERR_NO_CONNECTION 0x0C @@ -4275,23 +4436,15 @@ lpfc_is_LC_HBA(unsigned short device) } /* - * Determine if an IOCB failed because of a link event or firmware reset. + * Determine if failed because of a link event or firmware reset. */ - static inline int -lpfc_error_lost_link(IOCB_t *iocbp) +lpfc_error_lost_link(u32 ulp_status, u32 ulp_word4) { - return (iocbp->ulpStatus == IOSTAT_LOCAL_REJECT && - (iocbp->un.ulpWord[4] == IOERR_SLI_ABORTED || - iocbp->un.ulpWord[4] == IOERR_LINK_DOWN || - iocbp->un.ulpWord[4] == IOERR_SLI_DOWN)); + return (ulp_status == IOSTAT_LOCAL_REJECT && + (ulp_word4 == IOERR_SLI_ABORTED || + ulp_word4 == IOERR_LINK_DOWN || + ulp_word4 == IOERR_SLI_DOWN)); } -#define MENLO_TRANSPORT_TYPE 0xfe -#define MENLO_CONTEXT 0 -#define MENLO_PU 3 -#define MENLO_TIMEOUT 30 -#define SETVAR_MLOMNT 0x103107 -#define SETVAR_MLORST 0x103007 - #define BPL_ALIGN_SZ 8 /* 8 byte alignment for bpl and mbufs */ diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 9a064b96e570..5288fc69908a 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -20,6 +20,9 @@ * included with this package. * *******************************************************************/ +#include <uapi/scsi/fc/fc_fs.h> +#include <uapi/scsi/fc/fc_els.h> + /* Macros to deal with bit fields. Each bit field must have 3 #defines * associated with it (_SHIFT, _MASK, and _WORD). * EG. For a bit field that is in the 7th bit of the "field4" field of a @@ -57,6 +60,14 @@ ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \ ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT)))) +#define get_wqe_reqtag(x) (((x)->wqe.words[9] >> 0) & 0xFFFF) +#define get_wqe_tmo(x) (((x)->wqe.words[7] >> 24) & 0x00FF) + +#define get_job_ulpword(x, y) ((x)->iocb.un.ulpWord[y]) + +#define set_job_ulpstatus(x, y) bf_set(lpfc_wcqe_c_status, &(x)->wcqe_cmpl, y) +#define set_job_ulpword4(x, y) ((&(x)->wcqe_cmpl)->parameter = y) + struct dma_address { uint32_t addr_lo; uint32_t addr_hi; @@ -92,6 +103,9 @@ struct lpfc_sli_intf { #define LPFC_SLI_INTF_FAMILY_BE3 0x1 #define LPFC_SLI_INTF_FAMILY_LNCR_A0 0xa #define LPFC_SLI_INTF_FAMILY_LNCR_B0 0xb +#define LPFC_SLI_INTF_FAMILY_G6 0xc +#define LPFC_SLI_INTF_FAMILY_G7 0xd +#define LPFC_SLI_INTF_FAMILY_G7P 0xe #define lpfc_sli_intf_slirev_SHIFT 4 #define lpfc_sli_intf_slirev_MASK 0x0000000F #define lpfc_sli_intf_slirev_WORD word0 @@ -122,6 +136,7 @@ struct lpfc_sli_intf { /* Define SLI4 Alignment requirements. */ #define LPFC_ALIGN_16_BYTE 16 #define LPFC_ALIGN_64_BYTE 64 +#define SLI4_PAGE_SIZE 4096 /* Define SLI4 specific definitions. */ #define LPFC_MQ_CQE_BYTE_OFFSET 256 @@ -223,6 +238,34 @@ struct lpfc_sli_intf { /* PORT_CAPABILITIES constants. */ #define LPFC_MAX_SUPPORTED_PAGES 8 +enum ulp_bde64_word3 { + ULP_BDE64_SIZE_MASK = 0xffffff, + + ULP_BDE64_TYPE_SHIFT = 24, + ULP_BDE64_TYPE_MASK = (0xff << ULP_BDE64_TYPE_SHIFT), + + /* BDE (Host_resident) */ + ULP_BDE64_TYPE_BDE_64 = (0x00 << ULP_BDE64_TYPE_SHIFT), + /* Immediate Data BDE */ + ULP_BDE64_TYPE_BDE_IMMED = (0x01 << ULP_BDE64_TYPE_SHIFT), + /* BDE (Port-resident) */ + ULP_BDE64_TYPE_BDE_64P = (0x02 << ULP_BDE64_TYPE_SHIFT), + /* Input BDE (Host-resident) */ + ULP_BDE64_TYPE_BDE_64I = (0x08 << ULP_BDE64_TYPE_SHIFT), + /* Input BDE (Port-resident) */ + ULP_BDE64_TYPE_BDE_64IP = (0x0A << ULP_BDE64_TYPE_SHIFT), + /* BLP (Host-resident) */ + ULP_BDE64_TYPE_BLP_64 = (0x40 << ULP_BDE64_TYPE_SHIFT), + /* BLP (Port-resident) */ + ULP_BDE64_TYPE_BLP_64P = (0x42 << ULP_BDE64_TYPE_SHIFT), +}; + +struct ulp_bde64_le { + __le32 type_size; /* type 31:24, size 23:0 */ + __le32 addr_low; + __le32 addr_high; +}; + struct ulp_bde64 { union ULP_BDE_TUS { uint32_t w; @@ -270,6 +313,9 @@ struct lpfc_sli4_flags { #define lpfc_vfi_rsrc_rdy_MASK 0x00000001 #define lpfc_vfi_rsrc_rdy_WORD word0 #define LPFC_VFI_RSRC_RDY 1 +#define lpfc_ftr_ashdr_SHIFT 4 +#define lpfc_ftr_ashdr_MASK 0x00000001 +#define lpfc_ftr_ashdr_WORD word0 }; struct sli4_bls_rsp { @@ -387,6 +433,12 @@ struct lpfc_wcqe_complete { #define lpfc_wcqe_c_ersp0_MASK 0x0000FFFF #define lpfc_wcqe_c_ersp0_WORD word0 uint32_t total_data_placed; +#define lpfc_wcqe_c_cmf_cg_SHIFT 31 +#define lpfc_wcqe_c_cmf_cg_MASK 0x00000001 +#define lpfc_wcqe_c_cmf_cg_WORD total_data_placed +#define lpfc_wcqe_c_cmf_bw_SHIFT 0 +#define lpfc_wcqe_c_cmf_bw_MASK 0x0FFFFFFF +#define lpfc_wcqe_c_cmf_bw_WORD total_data_placed uint32_t parameter; #define lpfc_wcqe_c_bg_edir_SHIFT 5 #define lpfc_wcqe_c_bg_edir_MASK 0x00000001 @@ -648,12 +700,19 @@ struct lpfc_register { #define lpfc_sliport_status_oti_SHIFT 29 #define lpfc_sliport_status_oti_MASK 0x1 #define lpfc_sliport_status_oti_WORD word0 +#define lpfc_sliport_status_dip_SHIFT 25 +#define lpfc_sliport_status_dip_MASK 0x1 +#define lpfc_sliport_status_dip_WORD word0 #define lpfc_sliport_status_rn_SHIFT 24 #define lpfc_sliport_status_rn_MASK 0x1 #define lpfc_sliport_status_rn_WORD word0 #define lpfc_sliport_status_rdy_SHIFT 23 #define lpfc_sliport_status_rdy_MASK 0x1 #define lpfc_sliport_status_rdy_WORD word0 +#define lpfc_sliport_status_pldv_SHIFT 0 +#define lpfc_sliport_status_pldv_MASK 0x1 +#define lpfc_sliport_status_pldv_WORD word0 +#define CFG_PLD 0x3C #define MAX_IF_TYPE_2_RESETS 6 #define LPFC_CTL_PORT_CTL_OFFSET 0x408 @@ -678,6 +737,8 @@ struct lpfc_register { #define lpfc_sliport_eqdelay_id_MASK 0xfff #define lpfc_sliport_eqdelay_id_WORD word0 #define LPFC_SEC_TO_USEC 1000000 +#define LPFC_SEC_TO_MSEC 1000 +#define LPFC_MSECS_TO_SECS(msecs) ((msecs) / 1000) /* The following Registers apply to SLI4 if_type 0 UCNAs. They typically * reside in BAR 2. @@ -950,6 +1011,12 @@ union lpfc_sli4_cfg_shdr { #define lpfc_mbox_hdr_add_status_SHIFT 8 #define lpfc_mbox_hdr_add_status_MASK 0x000000FF #define lpfc_mbox_hdr_add_status_WORD word7 +#define LPFC_ADD_STATUS_INCOMPAT_OBJ 0xA2 +#define lpfc_mbox_hdr_add_status_2_SHIFT 16 +#define lpfc_mbox_hdr_add_status_2_MASK 0x000000FF +#define lpfc_mbox_hdr_add_status_2_WORD word7 +#define LPFC_ADD_STATUS_2_INCOMPAT_FLASH 0x01 +#define LPFC_ADD_STATUS_2_INCORRECT_ASIC 0x02 uint32_t response_length; uint32_t actual_response_length; } response; @@ -1006,6 +1073,7 @@ struct mbox_header { #define LPFC_MBOX_OPCODE_SET_HOST_DATA 0x5D #define LPFC_MBOX_OPCODE_SEND_ACTIVATION 0x73 #define LPFC_MBOX_OPCODE_RESET_LICENSES 0x74 +#define LPFC_MBOX_OPCODE_REG_CONGESTION_BUF 0x8E #define LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO 0x9A #define LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT 0x9B #define LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT 0x9C @@ -1114,6 +1182,12 @@ struct lpfc_mbx_sge { uint32_t length; }; +struct lpfc_mbx_host_buf { + uint32_t length; + uint32_t pa_lo; + uint32_t pa_hi; +}; + struct lpfc_mbx_nembed_cmd { struct lpfc_sli4_cfg_mhdr cfg_mhdr; #define LPFC_SLI4_MBX_SGE_MAX_PAGES 19 @@ -1124,6 +1198,31 @@ struct lpfc_mbx_nembed_sge_virt { void *addr[LPFC_SLI4_MBX_SGE_MAX_PAGES]; }; +#define LPFC_MBX_OBJECT_NAME_LEN_DW 26 +struct lpfc_mbx_read_object { /* Version 0 */ + struct mbox_header header; + union { + struct { + uint32_t word0; +#define lpfc_mbx_rd_object_rlen_SHIFT 0 +#define lpfc_mbx_rd_object_rlen_MASK 0x00FFFFFF +#define lpfc_mbx_rd_object_rlen_WORD word0 + uint32_t rd_object_offset; + __le32 rd_object_name[LPFC_MBX_OBJECT_NAME_LEN_DW]; +#define LPFC_OBJ_NAME_SZ 104 /* 26 x sizeof(uint32_t) is 104. */ + uint32_t rd_object_cnt; + struct lpfc_mbx_host_buf rd_object_hbuf[4]; + } request; + struct { + uint32_t rd_object_actual_rlen; + uint32_t word1; +#define lpfc_mbx_rd_object_eof_SHIFT 31 +#define lpfc_mbx_rd_object_eof_MASK 0x1 +#define lpfc_mbx_rd_object_eof_WORD word1 + } response; + } u; +}; + struct lpfc_mbx_eq_create { struct mbox_header header; union { @@ -1546,7 +1645,7 @@ struct rq_context { #define lpfc_rq_context_hdr_size_WORD word1 uint32_t word2; #define lpfc_rq_context_cq_id_SHIFT 16 -#define lpfc_rq_context_cq_id_MASK 0x000003FF +#define lpfc_rq_context_cq_id_MASK 0x0000FFFF #define lpfc_rq_context_cq_id_WORD word2 #define lpfc_rq_context_buf_size_SHIFT 0 #define lpfc_rq_context_buf_size_MASK 0x0000FFFF @@ -2319,6 +2418,7 @@ struct lpfc_mbx_redisc_fcf_tbl { #define ADD_STATUS_OPERATION_ALREADY_ACTIVE 0x67 #define ADD_STATUS_FW_NOT_SUPPORTED 0xEB #define ADD_STATUS_INVALID_REQUEST 0x4B +#define ADD_STATUS_INVALID_OBJECT_NAME 0xA0 #define ADD_STATUS_FW_DOWNLOAD_HW_DISABLED 0x58 struct lpfc_mbx_sli4_config { @@ -2794,6 +2894,15 @@ struct lpfc_mbx_read_config { #define lpfc_mbx_rd_conf_extnts_inuse_SHIFT 31 #define lpfc_mbx_rd_conf_extnts_inuse_MASK 0x00000001 #define lpfc_mbx_rd_conf_extnts_inuse_WORD word1 +#define lpfc_mbx_rd_conf_fawwpn_SHIFT 30 +#define lpfc_mbx_rd_conf_fawwpn_MASK 0x00000001 +#define lpfc_mbx_rd_conf_fawwpn_WORD word1 +#define lpfc_mbx_rd_conf_wcs_SHIFT 28 /* warning signaling */ +#define lpfc_mbx_rd_conf_wcs_MASK 0x00000001 +#define lpfc_mbx_rd_conf_wcs_WORD word1 +#define lpfc_mbx_rd_conf_acs_SHIFT 27 /* alarm signaling */ +#define lpfc_mbx_rd_conf_acs_MASK 0x00000001 +#define lpfc_mbx_rd_conf_acs_WORD word1 uint32_t word2; #define lpfc_mbx_rd_conf_lnk_numb_SHIFT 0 #define lpfc_mbx_rd_conf_lnk_numb_MASK 0x0000003F @@ -2938,6 +3047,9 @@ struct lpfc_mbx_request_features { #define lpfc_mbx_rq_ftr_rq_mrqp_SHIFT 16 #define lpfc_mbx_rq_ftr_rq_mrqp_MASK 0x00000001 #define lpfc_mbx_rq_ftr_rq_mrqp_WORD word2 +#define lpfc_mbx_rq_ftr_rq_ashdr_SHIFT 17 +#define lpfc_mbx_rq_ftr_rq_ashdr_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rq_ashdr_WORD word2 uint32_t word3; #define lpfc_mbx_rq_ftr_rsp_iaab_SHIFT 0 #define lpfc_mbx_rq_ftr_rsp_iaab_MASK 0x00000001 @@ -2969,62 +3081,9 @@ struct lpfc_mbx_request_features { #define lpfc_mbx_rq_ftr_rsp_mrqp_SHIFT 16 #define lpfc_mbx_rq_ftr_rsp_mrqp_MASK 0x00000001 #define lpfc_mbx_rq_ftr_rsp_mrqp_WORD word3 -}; - -struct lpfc_mbx_supp_pages { - uint32_t word1; -#define qs_SHIFT 0 -#define qs_MASK 0x00000001 -#define qs_WORD word1 -#define wr_SHIFT 1 -#define wr_MASK 0x00000001 -#define wr_WORD word1 -#define pf_SHIFT 8 -#define pf_MASK 0x000000ff -#define pf_WORD word1 -#define cpn_SHIFT 16 -#define cpn_MASK 0x000000ff -#define cpn_WORD word1 - uint32_t word2; -#define list_offset_SHIFT 0 -#define list_offset_MASK 0x000000ff -#define list_offset_WORD word2 -#define next_offset_SHIFT 8 -#define next_offset_MASK 0x000000ff -#define next_offset_WORD word2 -#define elem_cnt_SHIFT 16 -#define elem_cnt_MASK 0x000000ff -#define elem_cnt_WORD word2 - uint32_t word3; -#define pn_0_SHIFT 24 -#define pn_0_MASK 0x000000ff -#define pn_0_WORD word3 -#define pn_1_SHIFT 16 -#define pn_1_MASK 0x000000ff -#define pn_1_WORD word3 -#define pn_2_SHIFT 8 -#define pn_2_MASK 0x000000ff -#define pn_2_WORD word3 -#define pn_3_SHIFT 0 -#define pn_3_MASK 0x000000ff -#define pn_3_WORD word3 - uint32_t word4; -#define pn_4_SHIFT 24 -#define pn_4_MASK 0x000000ff -#define pn_4_WORD word4 -#define pn_5_SHIFT 16 -#define pn_5_MASK 0x000000ff -#define pn_5_WORD word4 -#define pn_6_SHIFT 8 -#define pn_6_MASK 0x000000ff -#define pn_6_WORD word4 -#define pn_7_SHIFT 0 -#define pn_7_MASK 0x000000ff -#define pn_7_WORD word4 - uint32_t rsvd[27]; -#define LPFC_SUPP_PAGES 0 -#define LPFC_BLOCK_GUARD_PROFILES 1 -#define LPFC_SLI4_PARAMETERS 2 +#define lpfc_mbx_rq_ftr_rsp_ashdr_SHIFT 17 +#define lpfc_mbx_rq_ftr_rsp_ashdr_MASK 0x00000001 +#define lpfc_mbx_rq_ftr_rsp_ashdr_WORD word3 }; struct lpfc_mbx_memory_dump_type3 { @@ -3243,121 +3302,6 @@ struct user_eeprom { uint8_t reserved191[57]; }; -struct lpfc_mbx_pc_sli4_params { - uint32_t word1; -#define qs_SHIFT 0 -#define qs_MASK 0x00000001 -#define qs_WORD word1 -#define wr_SHIFT 1 -#define wr_MASK 0x00000001 -#define wr_WORD word1 -#define pf_SHIFT 8 -#define pf_MASK 0x000000ff -#define pf_WORD word1 -#define cpn_SHIFT 16 -#define cpn_MASK 0x000000ff -#define cpn_WORD word1 - uint32_t word2; -#define if_type_SHIFT 0 -#define if_type_MASK 0x00000007 -#define if_type_WORD word2 -#define sli_rev_SHIFT 4 -#define sli_rev_MASK 0x0000000f -#define sli_rev_WORD word2 -#define sli_family_SHIFT 8 -#define sli_family_MASK 0x000000ff -#define sli_family_WORD word2 -#define featurelevel_1_SHIFT 16 -#define featurelevel_1_MASK 0x000000ff -#define featurelevel_1_WORD word2 -#define featurelevel_2_SHIFT 24 -#define featurelevel_2_MASK 0x0000001f -#define featurelevel_2_WORD word2 - uint32_t word3; -#define fcoe_SHIFT 0 -#define fcoe_MASK 0x00000001 -#define fcoe_WORD word3 -#define fc_SHIFT 1 -#define fc_MASK 0x00000001 -#define fc_WORD word3 -#define nic_SHIFT 2 -#define nic_MASK 0x00000001 -#define nic_WORD word3 -#define iscsi_SHIFT 3 -#define iscsi_MASK 0x00000001 -#define iscsi_WORD word3 -#define rdma_SHIFT 4 -#define rdma_MASK 0x00000001 -#define rdma_WORD word3 - uint32_t sge_supp_len; -#define SLI4_PAGE_SIZE 4096 - uint32_t word5; -#define if_page_sz_SHIFT 0 -#define if_page_sz_MASK 0x0000ffff -#define if_page_sz_WORD word5 -#define loopbk_scope_SHIFT 24 -#define loopbk_scope_MASK 0x0000000f -#define loopbk_scope_WORD word5 -#define rq_db_window_SHIFT 28 -#define rq_db_window_MASK 0x0000000f -#define rq_db_window_WORD word5 - uint32_t word6; -#define eq_pages_SHIFT 0 -#define eq_pages_MASK 0x0000000f -#define eq_pages_WORD word6 -#define eqe_size_SHIFT 8 -#define eqe_size_MASK 0x000000ff -#define eqe_size_WORD word6 - uint32_t word7; -#define cq_pages_SHIFT 0 -#define cq_pages_MASK 0x0000000f -#define cq_pages_WORD word7 -#define cqe_size_SHIFT 8 -#define cqe_size_MASK 0x000000ff -#define cqe_size_WORD word7 - uint32_t word8; -#define mq_pages_SHIFT 0 -#define mq_pages_MASK 0x0000000f -#define mq_pages_WORD word8 -#define mqe_size_SHIFT 8 -#define mqe_size_MASK 0x000000ff -#define mqe_size_WORD word8 -#define mq_elem_cnt_SHIFT 16 -#define mq_elem_cnt_MASK 0x000000ff -#define mq_elem_cnt_WORD word8 - uint32_t word9; -#define wq_pages_SHIFT 0 -#define wq_pages_MASK 0x0000ffff -#define wq_pages_WORD word9 -#define wqe_size_SHIFT 8 -#define wqe_size_MASK 0x000000ff -#define wqe_size_WORD word9 - uint32_t word10; -#define rq_pages_SHIFT 0 -#define rq_pages_MASK 0x0000ffff -#define rq_pages_WORD word10 -#define rqe_size_SHIFT 8 -#define rqe_size_MASK 0x000000ff -#define rqe_size_WORD word10 - uint32_t word11; -#define hdr_pages_SHIFT 0 -#define hdr_pages_MASK 0x0000000f -#define hdr_pages_WORD word11 -#define hdr_size_SHIFT 8 -#define hdr_size_MASK 0x0000000f -#define hdr_size_WORD word11 -#define hdr_pp_align_SHIFT 16 -#define hdr_pp_align_MASK 0x0000ffff -#define hdr_pp_align_WORD word11 - uint32_t word12; -#define sgl_pages_SHIFT 0 -#define sgl_pages_MASK 0x0000000f -#define sgl_pages_WORD word12 -#define sgl_pp_align_SHIFT 16 -#define sgl_pp_align_MASK 0x0000ffff -#define sgl_pp_align_WORD word12 - uint32_t rsvd_13_63[51]; -}; #define SLI4_PAGE_ALIGN(addr) (((addr)+((SLI4_PAGE_SIZE)-1)) \ &(~((SLI4_PAGE_SIZE)-1))) @@ -3484,25 +3428,35 @@ struct lpfc_sli4_parameters { #define cfg_nosr_SHIFT 9 #define cfg_nosr_MASK 0x00000001 #define cfg_nosr_WORD word19 - #define cfg_bv1s_SHIFT 10 #define cfg_bv1s_MASK 0x00000001 #define cfg_bv1s_WORD word19 -#define cfg_pvl_SHIFT 13 -#define cfg_pvl_MASK 0x00000001 -#define cfg_pvl_WORD word19 #define cfg_nsler_SHIFT 12 #define cfg_nsler_MASK 0x00000001 #define cfg_nsler_WORD word19 +#define cfg_pvl_SHIFT 13 +#define cfg_pvl_MASK 0x00000001 +#define cfg_pvl_WORD word19 + +#define cfg_pbde_SHIFT 20 +#define cfg_pbde_MASK 0x00000001 +#define cfg_pbde_WORD word19 uint32_t word20; #define cfg_max_tow_xri_SHIFT 0 #define cfg_max_tow_xri_MASK 0x0000ffff #define cfg_max_tow_xri_WORD word20 - uint32_t word21; /* RESERVED */ - uint32_t word22; /* RESERVED */ + uint32_t word21; +#define cfg_mi_ver_SHIFT 0 +#define cfg_mi_ver_MASK 0x0000ffff +#define cfg_mi_ver_WORD word21 +#define cfg_cmf_SHIFT 24 +#define cfg_cmf_MASK 0x000000ff +#define cfg_cmf_WORD word21 + + uint32_t mib_size; uint32_t word23; /* RESERVED */ uint32_t word24; @@ -3529,8 +3483,12 @@ struct lpfc_sli4_parameters { }; #define LPFC_SET_UE_RECOVERY 0x10 -#define LPFC_SET_MDS_DIAGS 0x11 +#define LPFC_SET_MDS_DIAGS 0x12 #define LPFC_SET_DUAL_DUMP 0x1e +#define LPFC_SET_CGN_SIGNAL 0x1f +#define LPFC_SET_ENABLE_MI 0x21 +#define LPFC_SET_LD_SIGNAL 0x23 +#define LPFC_SET_ENABLE_CMF 0x24 struct lpfc_mbx_set_feature { struct mbox_header header; uint32_t feature; @@ -3539,12 +3497,15 @@ struct lpfc_mbx_set_feature { #define lpfc_mbx_set_feature_UER_SHIFT 0 #define lpfc_mbx_set_feature_UER_MASK 0x00000001 #define lpfc_mbx_set_feature_UER_WORD word6 -#define lpfc_mbx_set_feature_mds_SHIFT 0 +#define lpfc_mbx_set_feature_mds_SHIFT 2 #define lpfc_mbx_set_feature_mds_MASK 0x00000001 #define lpfc_mbx_set_feature_mds_WORD word6 #define lpfc_mbx_set_feature_mds_deep_loopbk_SHIFT 1 #define lpfc_mbx_set_feature_mds_deep_loopbk_MASK 0x00000001 #define lpfc_mbx_set_feature_mds_deep_loopbk_WORD word6 +#define lpfc_mbx_set_feature_CGN_warn_freq_SHIFT 0 +#define lpfc_mbx_set_feature_CGN_warn_freq_MASK 0x0000ffff +#define lpfc_mbx_set_feature_CGN_warn_freq_WORD word6 #define lpfc_mbx_set_feature_dd_SHIFT 0 #define lpfc_mbx_set_feature_dd_MASK 0x00000001 #define lpfc_mbx_set_feature_dd_WORD word6 @@ -3554,23 +3515,73 @@ struct lpfc_mbx_set_feature { #define LPFC_DISABLE_DUAL_DUMP 0 #define LPFC_ENABLE_DUAL_DUMP 1 #define LPFC_QUERY_OP_DUAL_DUMP 2 - uint32_t word7; +#define lpfc_mbx_set_feature_cmf_SHIFT 0 +#define lpfc_mbx_set_feature_cmf_MASK 0x00000001 +#define lpfc_mbx_set_feature_cmf_WORD word6 +#define lpfc_mbx_set_feature_lds_qry_SHIFT 0 +#define lpfc_mbx_set_feature_lds_qry_MASK 0x00000001 +#define lpfc_mbx_set_feature_lds_qry_WORD word6 +#define LPFC_QUERY_LDS_OP 1 +#define lpfc_mbx_set_feature_mi_SHIFT 0 +#define lpfc_mbx_set_feature_mi_MASK 0x0000ffff +#define lpfc_mbx_set_feature_mi_WORD word6 +#define lpfc_mbx_set_feature_milunq_SHIFT 16 +#define lpfc_mbx_set_feature_milunq_MASK 0x0000ffff +#define lpfc_mbx_set_feature_milunq_WORD word6 + u32 word7; #define lpfc_mbx_set_feature_UERP_SHIFT 0 #define lpfc_mbx_set_feature_UERP_MASK 0x0000ffff #define lpfc_mbx_set_feature_UERP_WORD word7 #define lpfc_mbx_set_feature_UESR_SHIFT 16 #define lpfc_mbx_set_feature_UESR_MASK 0x0000ffff #define lpfc_mbx_set_feature_UESR_WORD word7 +#define lpfc_mbx_set_feature_CGN_alarm_freq_SHIFT 0 +#define lpfc_mbx_set_feature_CGN_alarm_freq_MASK 0x0000ffff +#define lpfc_mbx_set_feature_CGN_alarm_freq_WORD word7 + u32 word8; +#define lpfc_mbx_set_feature_CGN_acqe_freq_SHIFT 0 +#define lpfc_mbx_set_feature_CGN_acqe_freq_MASK 0x000000ff +#define lpfc_mbx_set_feature_CGN_acqe_freq_WORD word8 + u32 word9; + u32 word10; }; #define LPFC_SET_HOST_OS_DRIVER_VERSION 0x2 +#define LPFC_SET_HOST_DATE_TIME 0x4 + +struct lpfc_mbx_set_host_date_time { + uint32_t word6; +#define lpfc_mbx_set_host_month_WORD word6 +#define lpfc_mbx_set_host_month_SHIFT 16 +#define lpfc_mbx_set_host_month_MASK 0xFF +#define lpfc_mbx_set_host_day_WORD word6 +#define lpfc_mbx_set_host_day_SHIFT 8 +#define lpfc_mbx_set_host_day_MASK 0xFF +#define lpfc_mbx_set_host_year_WORD word6 +#define lpfc_mbx_set_host_year_SHIFT 0 +#define lpfc_mbx_set_host_year_MASK 0xFF + uint32_t word7; +#define lpfc_mbx_set_host_hour_WORD word7 +#define lpfc_mbx_set_host_hour_SHIFT 16 +#define lpfc_mbx_set_host_hour_MASK 0xFF +#define lpfc_mbx_set_host_min_WORD word7 +#define lpfc_mbx_set_host_min_SHIFT 8 +#define lpfc_mbx_set_host_min_MASK 0xFF +#define lpfc_mbx_set_host_sec_WORD word7 +#define lpfc_mbx_set_host_sec_SHIFT 0 +#define lpfc_mbx_set_host_sec_MASK 0xFF +}; + struct lpfc_mbx_set_host_data { #define LPFC_HOST_OS_DRIVER_VERSION_SIZE 48 struct mbox_header header; uint32_t param_id; uint32_t param_len; - uint8_t data[LPFC_HOST_OS_DRIVER_VERSION_SIZE]; + union { + uint8_t data[LPFC_HOST_OS_DRIVER_VERSION_SIZE]; + struct lpfc_mbx_set_host_date_time tm; + } un; }; struct lpfc_mbx_set_trunk_mode { @@ -3588,6 +3599,21 @@ struct lpfc_mbx_get_sli4_parameters { struct lpfc_sli4_parameters sli4_parameters; }; +struct lpfc_mbx_reg_congestion_buf { + struct mbox_header header; + uint32_t word0; +#define lpfc_mbx_reg_cgn_buf_type_WORD word0 +#define lpfc_mbx_reg_cgn_buf_type_SHIFT 0 +#define lpfc_mbx_reg_cgn_buf_type_MASK 0xFF +#define lpfc_mbx_reg_cgn_buf_cnt_WORD word0 +#define lpfc_mbx_reg_cgn_buf_cnt_SHIFT 16 +#define lpfc_mbx_reg_cgn_buf_cnt_MASK 0xFF + uint32_t word1; + uint32_t length; + uint32_t addr_lo; + uint32_t addr_hi; +}; + struct lpfc_rscr_desc_generic { #define LPFC_RSRC_DESC_WSIZE 22 uint32_t desc[LPFC_RSRC_DESC_WSIZE]; @@ -3753,6 +3779,9 @@ struct lpfc_controller_attribute { #define lpfc_cntl_attr_eprom_ver_hi_SHIFT 8 #define lpfc_cntl_attr_eprom_ver_hi_MASK 0x000000ff #define lpfc_cntl_attr_eprom_ver_hi_WORD word17 +#define lpfc_cntl_attr_flash_id_SHIFT 16 +#define lpfc_cntl_attr_flash_id_MASK 0x000000ff +#define lpfc_cntl_attr_flash_id_WORD word17 uint32_t mbx_da_struct_ver; uint32_t ep_fw_da_struct_ver; uint32_t ncsi_ver_str[3]; @@ -3894,6 +3923,7 @@ struct lpfc_mbx_get_port_name { #define MB_CEQ_STATUS_QUEUE_FLUSHING 0x4 #define MB_CQE_STATUS_DMA_FAILED 0x5 + #define LPFC_MBX_WR_CONFIG_MAX_BDE 1 struct lpfc_mbx_wr_object { struct mbox_header header; @@ -3910,7 +3940,7 @@ struct lpfc_mbx_wr_object { #define lpfc_wr_object_write_length_MASK 0x00FFFFFF #define lpfc_wr_object_write_length_WORD word4 uint32_t write_offset; - uint32_t object_name[26]; + uint32_t object_name[LPFC_MBX_OBJECT_NAME_LEN_DW]; uint32_t bde_count; struct ulp_bde64 bde[LPFC_MBX_WR_CONFIG_MAX_BDE]; } request; @@ -3959,6 +3989,7 @@ struct lpfc_mqe { struct lpfc_mbx_unreg_fcfi unreg_fcfi; struct lpfc_mbx_mq_create mq_create; struct lpfc_mbx_mq_create_ext mq_create_ext; + struct lpfc_mbx_read_object read_object; struct lpfc_mbx_eq_create eq_create; struct lpfc_mbx_modify_eq_delay eq_delay; struct lpfc_mbx_cq_create cq_create; @@ -3983,9 +4014,8 @@ struct lpfc_mqe { struct lpfc_mbx_post_hdr_tmpl hdr_tmpl; struct lpfc_mbx_query_fw_config query_fw_cfg; struct lpfc_mbx_set_beacon_config beacon_config; - struct lpfc_mbx_supp_pages supp_pages; - struct lpfc_mbx_pc_sli4_params sli4_params; struct lpfc_mbx_get_sli4_parameters get_sli4_parameters; + struct lpfc_mbx_reg_congestion_buf reg_congestion_buf; struct lpfc_mbx_set_link_diag_state link_diag_state; struct lpfc_mbx_set_link_diag_loopback link_diag_loopback; struct lpfc_mbx_run_link_diag_test link_diag_test; @@ -4040,6 +4070,7 @@ struct lpfc_mcqe { #define LPFC_TRAILER_CODE_GRP5 0x5 #define LPFC_TRAILER_CODE_FC 0x10 #define LPFC_TRAILER_CODE_SLI 0x11 +#define LPFC_TRAILER_CODE_CMSTAT 0x13 }; struct lpfc_acqe_link { @@ -4274,10 +4305,23 @@ struct lpfc_acqe_misconfigured_event { #define LPFC_SLI_EVENT_STATUS_UNCERTIFIED 0x05 }; +struct lpfc_acqe_cgn_signal { + u32 word0; +#define lpfc_warn_acqe_SHIFT 0 +#define lpfc_warn_acqe_MASK 0x7FFFFFFF +#define lpfc_warn_acqe_WORD word0 +#define lpfc_imm_acqe_SHIFT 31 +#define lpfc_imm_acqe_MASK 0x1 +#define lpfc_imm_acqe_WORD word0 + u32 alarm_cnt; + u32 word2; + u32 trailer; +}; + struct lpfc_acqe_sli { uint32_t event_data1; uint32_t event_data2; - uint32_t reserved; + uint32_t event_data3; uint32_t trailer; #define LPFC_SLI_EVENT_TYPE_PORT_ERROR 0x1 #define LPFC_SLI_EVENT_TYPE_OVER_TEMP 0x2 @@ -4286,8 +4330,11 @@ struct lpfc_acqe_sli { #define LPFC_SLI_EVENT_TYPE_DIAG_DUMP 0x5 #define LPFC_SLI_EVENT_TYPE_MISCONFIGURED 0x9 #define LPFC_SLI_EVENT_TYPE_REMOTE_DPORT 0xA +#define LPFC_SLI_EVENT_TYPE_PORT_PARAMS_CHG 0xE #define LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN 0xF #define LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE 0x10 +#define LPFC_SLI_EVENT_TYPE_CGN_SIGNAL 0x11 +#define LPFC_SLI_EVENT_TYPE_RD_SIGNAL 0x12 }; /* @@ -4375,9 +4422,14 @@ struct wqe_common { #define wqe_ebde_cnt_SHIFT 0 #define wqe_ebde_cnt_MASK 0x0000000f #define wqe_ebde_cnt_WORD word10 -#define wqe_nvme_SHIFT 4 -#define wqe_nvme_MASK 0x00000001 -#define wqe_nvme_WORD word10 +#define wqe_xchg_SHIFT 4 +#define wqe_xchg_MASK 0x00000001 +#define wqe_xchg_WORD word10 +#define LPFC_SCSI_XCHG 0x0 +#define LPFC_NVME_XCHG 0x1 +#define wqe_appid_SHIFT 5 +#define wqe_appid_MASK 0x00000001 +#define wqe_appid_WORD word10 #define wqe_oas_SHIFT 6 #define wqe_oas_MASK 0x00000001 #define wqe_oas_WORD word10 @@ -4433,12 +4485,8 @@ struct wqe_common { #define wqe_cmd_type_MASK 0x0000000f #define wqe_cmd_type_WORD word11 #define wqe_els_id_SHIFT 4 -#define wqe_els_id_MASK 0x00000003 +#define wqe_els_id_MASK 0x00000007 #define wqe_els_id_WORD word11 -#define LPFC_ELS_ID_FLOGI 3 -#define LPFC_ELS_ID_FDISC 2 -#define LPFC_ELS_ID_LOGO 1 -#define LPFC_ELS_ID_DEFAULT 0 #define wqe_irsp_SHIFT 4 #define wqe_irsp_MASK 0x00000001 #define wqe_irsp_WORD word11 @@ -4448,6 +4496,9 @@ struct wqe_common { #define wqe_sup_SHIFT 6 #define wqe_sup_MASK 0x00000001 #define wqe_sup_WORD word11 +#define wqe_ffrq_SHIFT 6 +#define wqe_ffrq_MASK 0x00000001 +#define wqe_ffrq_WORD word11 #define wqe_wqec_SHIFT 7 #define wqe_wqec_MASK 0x00000001 #define wqe_wqec_WORD word11 @@ -4485,6 +4536,14 @@ struct lpfc_wqe_generic{ uint32_t payload[4]; }; +enum els_request64_wqe_word11 { + LPFC_ELS_ID_DEFAULT, + LPFC_ELS_ID_LOGO, + LPFC_ELS_ID_FDISC, + LPFC_ELS_ID_FLOGI, + LPFC_ELS_ID_PLOGI, +}; + struct els_request64_wqe { struct ulp_bde64 bde; uint32_t payload_len; @@ -4686,10 +4745,75 @@ struct create_xri_wqe { uint32_t rsvd_12_15[4]; /* word 12-15 */ }; -#define INHIBIT_ABORT 1 #define T_REQUEST_TAG 3 #define T_XRI_TAG 1 +struct cmf_sync_wqe { + uint32_t rsrvd[3]; + uint32_t word3; +#define cmf_sync_interval_SHIFT 0 +#define cmf_sync_interval_MASK 0x00000ffff +#define cmf_sync_interval_WORD word3 +#define cmf_sync_afpin_SHIFT 16 +#define cmf_sync_afpin_MASK 0x000000001 +#define cmf_sync_afpin_WORD word3 +#define cmf_sync_asig_SHIFT 17 +#define cmf_sync_asig_MASK 0x000000001 +#define cmf_sync_asig_WORD word3 +#define cmf_sync_op_SHIFT 20 +#define cmf_sync_op_MASK 0x00000000f +#define cmf_sync_op_WORD word3 +#define cmf_sync_ver_SHIFT 24 +#define cmf_sync_ver_MASK 0x0000000ff +#define cmf_sync_ver_WORD word3 +#define LPFC_CMF_SYNC_VER 1 + uint32_t event_tag; + uint32_t word5; +#define cmf_sync_wsigmax_SHIFT 0 +#define cmf_sync_wsigmax_MASK 0x00000ffff +#define cmf_sync_wsigmax_WORD word5 +#define cmf_sync_wsigcnt_SHIFT 16 +#define cmf_sync_wsigcnt_MASK 0x00000ffff +#define cmf_sync_wsigcnt_WORD word5 + uint32_t word6; + uint32_t word7; +#define cmf_sync_cmnd_SHIFT 8 +#define cmf_sync_cmnd_MASK 0x0000000ff +#define cmf_sync_cmnd_WORD word7 + uint32_t word8; + uint32_t word9; +#define cmf_sync_reqtag_SHIFT 0 +#define cmf_sync_reqtag_MASK 0x00000ffff +#define cmf_sync_reqtag_WORD word9 +#define cmf_sync_wfpinmax_SHIFT 16 +#define cmf_sync_wfpinmax_MASK 0x0000000ff +#define cmf_sync_wfpinmax_WORD word9 +#define cmf_sync_wfpincnt_SHIFT 24 +#define cmf_sync_wfpincnt_MASK 0x0000000ff +#define cmf_sync_wfpincnt_WORD word9 + uint32_t word10; +#define cmf_sync_qosd_SHIFT 9 +#define cmf_sync_qosd_MASK 0x00000001 +#define cmf_sync_qosd_WORD word10 + uint32_t word11; +#define cmf_sync_cmd_type_SHIFT 0 +#define cmf_sync_cmd_type_MASK 0x0000000f +#define cmf_sync_cmd_type_WORD word11 +#define cmf_sync_wqec_SHIFT 7 +#define cmf_sync_wqec_MASK 0x00000001 +#define cmf_sync_wqec_WORD word11 +#define cmf_sync_cqid_SHIFT 16 +#define cmf_sync_cqid_MASK 0x0000ffff +#define cmf_sync_cqid_WORD word11 + uint32_t read_bytes; + uint32_t word13; +#define cmf_sync_period_SHIFT 16 +#define cmf_sync_period_MASK 0x0000ffff +#define cmf_sync_period_WORD word13 + uint32_t word14; + uint32_t word15; +}; + struct abort_cmd_wqe { uint32_t rsrvd[3]; uint32_t word3; @@ -4795,6 +4919,23 @@ struct send_frame_wqe { uint32_t fc_hdr_wd5; /* word 15 */ }; +#define ELS_RDF_REG_TAG_CNT 4 +struct lpfc_els_rdf_reg_desc { + struct fc_df_desc_fpin_reg reg_desc; /* descriptor header */ + __be32 desc_tags[ELS_RDF_REG_TAG_CNT]; + /* tags in reg_desc */ +}; + +struct lpfc_els_rdf_req { + struct fc_els_rdf rdf; /* hdr up to descriptors */ + struct lpfc_els_rdf_reg_desc reg_d1; /* 1st descriptor */ +}; + +struct lpfc_els_rdf_rsp { + struct fc_els_rdf_resp rdf_resp; /* hdr up to descriptors */ + struct lpfc_els_rdf_reg_desc reg_d1; /* 1st descriptor */ +}; + union lpfc_wqe { uint32_t words[16]; struct lpfc_wqe_generic generic; @@ -4802,6 +4943,7 @@ union lpfc_wqe { struct fcp_iread64_wqe fcp_iread; struct fcp_iwrite64_wqe fcp_iwrite; struct abort_cmd_wqe abort_cmd; + struct cmf_sync_wqe cmf_sync; struct create_xri_wqe create_xri; struct xmit_bcast64_wqe xmit_bcast64; struct xmit_seq64_wqe xmit_sequence; @@ -4822,6 +4964,7 @@ union lpfc_wqe128 { struct fcp_iread64_wqe fcp_iread; struct fcp_iwrite64_wqe fcp_iwrite; struct abort_cmd_wqe abort_cmd; + struct cmf_sync_wqe cmf_sync; struct create_xri_wqe create_xri; struct xmit_bcast64_wqe xmit_bcast64; struct xmit_seq64_wqe xmit_sequence; @@ -4837,6 +4980,7 @@ union lpfc_wqe128 { #define MAGIC_NUMBER_G6 0xFEAA0003 #define MAGIC_NUMBER_G7 0xFEAA0005 +#define MAGIC_NUMBER_G7P 0xFEAA0020 struct lpfc_grp_hdr { uint32_t size; @@ -4858,10 +5002,13 @@ struct lpfc_grp_hdr { #define NVME_READ_CMD 0x0 #define FCP_COMMAND_DATA_OUT 0x1 #define NVME_WRITE_CMD 0x1 +#define COMMAND_DATA_IN 0x0 +#define COMMAND_DATA_OUT 0x1 #define FCP_COMMAND_TRECEIVE 0x2 #define FCP_COMMAND_TRSP 0x3 #define FCP_COMMAND_TSEND 0x7 #define OTHER_COMMAND 0x8 +#define CMF_SYNC_COMMAND 0xA #define ELS_COMMAND_NON_FIP 0xC #define ELS_COMMAND_FIP 0xD @@ -4883,6 +5030,7 @@ struct lpfc_grp_hdr { #define CMD_FCP_TRECEIVE64_WQE 0xA1 #define CMD_FCP_TRSP64_WQE 0xA3 #define CMD_GEN_REQUEST64_WQE 0xC2 +#define CMD_CMF_SYNC_WQE 0xE8 #define CMD_WQE_MASK 0xff @@ -4890,3 +5038,27 @@ struct lpfc_grp_hdr { #define LPFC_FW_DUMP 1 #define LPFC_FW_RESET 2 #define LPFC_DV_RESET 3 + +/* On some kernels, enum fc_ls_tlv_dtag does not have + * these 2 enums defined, on other kernels it does. + * To get aound this we need to add these 2 defines here. + */ +#ifndef ELS_DTAG_LNK_FAULT_CAP +#define ELS_DTAG_LNK_FAULT_CAP 0x0001000D +#endif +#ifndef ELS_DTAG_CG_SIGNAL_CAP +#define ELS_DTAG_CG_SIGNAL_CAP 0x0001000F +#endif + +/* + * Initializer useful for decoding FPIN string table. + */ +#define FC_FPIN_CONGN_SEVERITY_INIT { \ + { FPIN_CONGN_SEVERITY_WARNING, "Warning" }, \ + { FPIN_CONGN_SEVERITY_ERROR, "Alarm" }, \ +} + +/* Used for logging FPIN messages */ +#define LPFC_FPIN_WWPN_LINE_SZ 128 +#define LPFC_FPIN_WWPN_LINE_CNT 6 +#define LPFC_FPIN_WWPN_NUM_LINE 6 diff --git a/drivers/scsi/lpfc/lpfc_ids.h b/drivers/scsi/lpfc/lpfc_ids.h index d48414e295a0..0b1616e93cf4 100644 --- a/drivers/scsi/lpfc/lpfc_ids.h +++ b/drivers/scsi/lpfc/lpfc_ids.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -60,8 +60,6 @@ const struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR, PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HORNET, - PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_SCSP, PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_DCSP, @@ -118,9 +116,41 @@ const struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G7_FC, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G7P_FC, + PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_16XE, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_161E, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_16XE, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_162E, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_16XE, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_164E, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_16XP, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_161P, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_16XP, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_162P, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_16XP, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_164P, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_32XE, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_321E, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_32XE, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_322E, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_32XE, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_324E, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_32XP, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_321P, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_32XP, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_322P, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_32XP, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_CLRY_324P, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_TLFC_2, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_TLFC_2XX2, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_TLFC_3, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_TLFC_3162, }, + {PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_TLFC_3, + PCI_VENDOR_ID_ATTO, PCI_DEVICE_ID_TLFC_3322, }, { 0 } }; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5a605773dd0a..b535f1fd3010 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -50,8 +50,6 @@ #include <scsi/scsi_tcq.h> #include <scsi/fc/fc_fs.h> -#include <linux/nvme-fc-driver.h> - #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" @@ -61,7 +59,6 @@ #include "lpfc.h" #include "lpfc_scsi.h" #include "lpfc_nvme.h" -#include "lpfc_nvmet.h" #include "lpfc_logmsg.h" #include "lpfc_crtn.h" #include "lpfc_vport.h" @@ -71,6 +68,7 @@ static enum cpuhp_state lpfc_cpuhp_state; /* Used when mapping IRQ vectors in a driver centric manner */ static uint32_t lpfc_present_cpu; +static bool lpfc_pldv_detect; static void __lpfc_cpuhp_remove(struct lpfc_hba *phba); static void lpfc_cpuhp_remove(struct lpfc_hba *phba); @@ -96,11 +94,14 @@ static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t); static void lpfc_sli4_oas_verify(struct lpfc_hba *phba); static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int); static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *); +static int lpfc_sli4_cgn_parm_chg_evt(struct lpfc_hba *); +static void lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba); static struct scsi_transport_template *lpfc_transport_template = NULL; static struct scsi_transport_template *lpfc_vport_transport_template = NULL; static DEFINE_IDR(lpfc_hba_index); #define LPFC_NVMET_BUF_POST 254 +static int lpfc_vmid_res_alloc(struct lpfc_hba *phba, struct lpfc_vport *vport); /** * lpfc_config_port_prep - Perform lpfc initialization prior to config port @@ -156,7 +157,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0324 Config Port initialization " "error, mbxCmd x%x READ_NVPARM, " "mbxStatus x%x\n", @@ -180,7 +181,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) lpfc_read_rev(phba, pmb); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0439 Adapter failed to init, mbxCmd x%x " "READ_REV, mbxStatus x%x\n", mb->mbxCommand, mb->mbxStatus); @@ -195,7 +196,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) */ if (mb->un.varRdRev.rr == 0) { vp->rev.rBit = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0440 Adapter failed to init, READ_REV has " "missing revision information.\n"); mempool_free(pmb, phba->mbox_mem_pool); @@ -256,6 +257,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) */ if (mb->un.varDmp.word_cnt == 0) break; + if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset) mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset; lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, @@ -263,6 +265,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) mb->un.varDmp.word_cnt); offset += mb->un.varDmp.word_cnt; } while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE); + lpfc_parse_vpd(phba, lpfc_vpd_data, offset); kfree(lpfc_vpd_data); @@ -322,8 +325,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) prog_id_word = pmboxq->u.mb.un.varWords[7]; /* Decode the Option rom version word to a readable string */ - if (prg->dist < 4) - dist = dist_char[prg->dist]; + dist = dist_char[prg->dist]; if ((prg->dist == 3) && (prg->num == 0)) snprintf(phba->OptionROMVersion, 32, "%d.%d%d", @@ -338,7 +340,6 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) /** * lpfc_update_vport_wwn - Updates the fc_nodename, fc_portname, - * cfg_soft_wwnn, cfg_soft_wwpn * @vport: pointer to lpfc vport data structure. * * @@ -348,22 +349,13 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) void lpfc_update_vport_wwn(struct lpfc_vport *vport) { - uint8_t vvvl = vport->fc_sparam.cmn.valid_vendor_ver_level; - u32 *fawwpn_key = (u32 *)&vport->fc_sparam.un.vendorVersion[0]; - - /* If the soft name exists then update it using the service params */ - if (vport->phba->cfg_soft_wwnn) - u64_to_wwn(vport->phba->cfg_soft_wwnn, - vport->fc_sparam.nodeName.u.wwn); - if (vport->phba->cfg_soft_wwpn) - u64_to_wwn(vport->phba->cfg_soft_wwpn, - vport->fc_sparam.portName.u.wwn); + struct lpfc_hba *phba = vport->phba; /* * If the name is empty or there exists a soft name * then copy the service params name, otherwise use the fc name */ - if (vport->fc_nodename.u.wwn[0] == 0 || vport->phba->cfg_soft_wwnn) + if (vport->fc_nodename.u.wwn[0] == 0) memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, sizeof(struct lpfc_name)); else @@ -376,22 +368,35 @@ lpfc_update_vport_wwn(struct lpfc_vport *vport) */ if (vport->fc_portname.u.wwn[0] != 0 && memcmp(&vport->fc_portname, &vport->fc_sparam.portName, - sizeof(struct lpfc_name))) + sizeof(struct lpfc_name))) { vport->vport_flag |= FAWWPN_PARAM_CHG; - if (vport->fc_portname.u.wwn[0] == 0 || - vport->phba->cfg_soft_wwpn || - (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR) || - vport->vport_flag & FAWWPN_SET) { + if (phba->sli_rev == LPFC_SLI_REV4 && + vport->port_type == LPFC_PHYSICAL_PORT && + phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_FABRIC) { + if (!(phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_CONFIG)) + phba->sli4_hba.fawwpn_flag &= + ~LPFC_FAWWPN_FABRIC; + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI | LOG_DISCOVERY | LOG_ELS, + "2701 FA-PWWN change WWPN from %llx to " + "%llx: vflag x%x fawwpn_flag x%x\n", + wwn_to_u64(vport->fc_portname.u.wwn), + wwn_to_u64 + (vport->fc_sparam.portName.u.wwn), + vport->vport_flag, + phba->sli4_hba.fawwpn_flag); + memcpy(&vport->fc_portname, &vport->fc_sparam.portName, + sizeof(struct lpfc_name)); + } + } + + if (vport->fc_portname.u.wwn[0] == 0) memcpy(&vport->fc_portname, &vport->fc_sparam.portName, - sizeof(struct lpfc_name)); - vport->vport_flag &= ~FAWWPN_SET; - if (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR) - vport->vport_flag |= FAWWPN_SET; - } + sizeof(struct lpfc_name)); else memcpy(&vport->fc_sparam.portName, &vport->fc_portname, - sizeof(struct lpfc_name)); + sizeof(struct lpfc_name)); } /** @@ -445,20 +450,21 @@ lpfc_config_port_post(struct lpfc_hba *phba) pmb->vport = vport; if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0448 Adapter failed init, mbxCmd x%x " "READ_SPARM mbxStatus x%x\n", mb->mbxCommand, mb->mbxStatus); phba->link_state = LPFC_HBA_ERROR; - mp = (struct lpfc_dmabuf *)pmb->ctx_buf; - mempool_free(pmb, phba->mbox_mem_pool); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); return -EIO; } mp = (struct lpfc_dmabuf *)pmb->ctx_buf; + /* This dmabuf was allocated by lpfc_read_sparam. The dmabuf is no + * longer needed. Prevent unintended ctx_buf access as the mbox is + * reused. + */ memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm)); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); @@ -499,7 +505,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) lpfc_read_config(phba, pmb); pmb->vport = vport; if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0453 Adapter failed to init, mbxCmd x%x " "READ_CONFIG, mbxStatus x%x\n", mb->mbxCommand, mb->mbxStatus); @@ -512,21 +518,12 @@ lpfc_config_port_post(struct lpfc_hba *phba) lpfc_sli_read_link_ste(phba); /* Reset the DFT_HBA_Q_DEPTH to the max xri */ - i = (mb->un.varRdConfig.max_xri + 1); - if (phba->cfg_hba_queue_depth > i) { + if (phba->cfg_hba_queue_depth > mb->un.varRdConfig.max_xri) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "3359 HBA queue depth changed from %d to %d\n", - phba->cfg_hba_queue_depth, i); - phba->cfg_hba_queue_depth = i; - } - - /* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */ - i = (mb->un.varRdConfig.max_xri >> 3); - if (phba->pport->cfg_lun_queue_depth > i) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "3360 LUN queue depth changed from %d to %d\n", - phba->pport->cfg_lun_queue_depth, i); - phba->pport->cfg_lun_queue_depth = i; + phba->cfg_hba_queue_depth, + mb->un.varRdConfig.max_xri); + phba->cfg_hba_queue_depth = mb->un.varRdConfig.max_xri; } phba->lmt = mb->un.varRdConfig.lmt; @@ -557,7 +554,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) } rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0352 Config MSI mailbox command " "failed, mbxCmd x%x, mbxStatus x%x\n", pmb->u.mb.mbxCommand, @@ -601,24 +598,22 @@ lpfc_config_port_post(struct lpfc_hba *phba) /* Set up heart beat (HB) timer */ mod_timer(&phba->hb_tmofunc, jiffies + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); - phba->hb_outstanding = 0; + phba->hba_flag &= ~(HBA_HBEAT_INP | HBA_HBEAT_TMO); phba->last_completion_time = jiffies; /* Set up error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); if (phba->hba_flag & LINK_DISABLED) { - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "2598 Adapter Link is disabled.\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2598 Adapter Link is disabled.\n"); lpfc_down_link(phba, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "2599 Adapter failed to issue DOWN_LINK" - " mbox command rc 0x%x\n", rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2599 Adapter failed to issue DOWN_LINK" + " mbox command rc 0x%x\n", rc); mempool_free(pmb, phba->mbox_mem_pool); return -EIO; @@ -642,9 +637,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0456 Adapter failed to issue " "ASYNCEVT_ENABLE mbox status x%x\n", rc); @@ -664,7 +657,8 @@ lpfc_config_port_post(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed " + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0435 Adapter failed " "to get Option ROM version status x%x\n", rc); mempool_free(pmb, phba->mbox_mem_pool); } @@ -673,6 +667,56 @@ lpfc_config_port_post(struct lpfc_hba *phba) } /** + * lpfc_sli4_refresh_params - update driver copy of params. + * @phba: Pointer to HBA context object. + * + * This is called to refresh driver copy of dynamic fields from the + * common_get_sli4_parameters descriptor. + **/ +int +lpfc_sli4_refresh_params(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + struct lpfc_mqe *mqe; + struct lpfc_sli4_parameters *mbx_sli4_parameters; + int length, rc; + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + + mqe = &mboxq->u.mqe; + /* Read the port's SLI4 Config Parameters */ + length = (sizeof(struct lpfc_mbx_get_sli4_parameters) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS, + length, LPFC_SLI4_MBX_EMBED); + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (unlikely(rc)) { + mempool_free(mboxq, phba->mbox_mem_pool); + return rc; + } + mbx_sli4_parameters = &mqe->un.get_sli4_parameters.sli4_parameters; + + /* Are we forcing MI off via module parameter? */ + if (phba->cfg_enable_mi) + phba->sli4_hba.pc_sli4_params.mi_ver = + bf_get(cfg_mi_ver, mbx_sli4_parameters); + else + phba->sli4_hba.pc_sli4_params.mi_ver = 0; + + phba->sli4_hba.pc_sli4_params.cmf = + bf_get(cfg_cmf, mbx_sli4_parameters); + phba->sli4_hba.pc_sli4_params.pls = + bf_get(cfg_pvl, mbx_sli4_parameters); + + mempool_free(mboxq, phba->mbox_mem_pool); + return rc; +} + +/** * lpfc_hba_init_link - Initialize the FC link * @phba: pointer to lpfc hba data structure. * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT @@ -742,10 +786,10 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_64G) && !(phba->lmt & LMT_64Gb))) { /* Reset link speed to auto */ - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1302 Invalid speed for this board:%d " - "Reset link speed to auto.\n", - phba->cfg_link_speed); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "1302 Invalid speed for this board:%d " + "Reset link speed to auto.\n", + phba->cfg_link_speed); phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; } lpfc_init_link(phba, pmb, fc_topology, phba->cfg_link_speed); @@ -754,10 +798,10 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, lpfc_set_loopback_flag(phba); rc = lpfc_sli_issue_mbox(phba, pmb, flag); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0498 Adapter failed to init, mbxCmd x%x " - "INIT_LINK, mbxStatus x%x\n", - mb->mbxCommand, mb->mbxStatus); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0498 Adapter failed to init, mbxCmd x%x " + "INIT_LINK, mbxStatus x%x\n", + mb->mbxCommand, mb->mbxStatus); if (phba->sli_rev <= LPFC_SLI_REV3) { /* Clear all interrupt enable conditions */ writel(0, phba->HCregaddr); @@ -803,17 +847,15 @@ lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag) return -ENOMEM; } - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "0491 Adapter Link is disabled.\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0491 Adapter Link is disabled.\n"); lpfc_down_link(phba, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox(phba, pmb, flag); if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "2522 Adapter failed to issue DOWN_LINK" - " mbox command rc 0x%x\n", rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2522 Adapter failed to issue DOWN_LINK" + " mbox command rc 0x%x\n", rc); mempool_free(pmb, phba->mbox_mem_pool); return -EIO; @@ -995,7 +1037,7 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba) spin_lock_irq(&pring->ring_lock); list_for_each_entry_safe(piocb, next_iocb, &pring->txcmplq, list) - piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; + piocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; list_splice_init(&pring->txcmplq, &completions); pring->txcmplq_cnt = 0; spin_unlock_irq(&pring->ring_lock); @@ -1008,7 +1050,6 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba) /** * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset - int i; * @phba: pointer to lpfc HBA data structure. * * This routine will do uninitialization after the HBA is reset when bring @@ -1041,7 +1082,7 @@ static int lpfc_hba_down_post_s4(struct lpfc_hba *phba) { struct lpfc_io_buf *psb, *psb_next; - struct lpfc_nvmet_rcv_ctx *ctxp, *ctxp_next; + struct lpfc_async_xchg_ctx *ctxp, *ctxp_next; struct lpfc_sli4_hdw_queue *qp; LIST_HEAD(aborts); LIST_HEAD(nvme_aborts); @@ -1059,12 +1100,11 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) * driver is unloading or reposted if the driver is restarting * the port. */ - spin_lock_irq(&phba->hbalock); /* required for lpfc_els_sgl_list and */ - /* scsl_buf_list */ + /* sgl_list_lock required because worker thread uses this * list. */ - spin_lock(&phba->sli4_hba.sgl_list_lock); + spin_lock_irq(&phba->sli4_hba.sgl_list_lock); list_for_each_entry(sglq_entry, &phba->sli4_hba.lpfc_abts_els_sgl_list, list) sglq_entry->state = SGL_FREED; @@ -1073,11 +1113,12 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) &phba->sli4_hba.lpfc_els_sgl_list); - spin_unlock(&phba->sli4_hba.sgl_list_lock); + spin_unlock_irq(&phba->sli4_hba.sgl_list_lock); /* abts_xxxx_buf_list_lock required because worker thread uses this * list. */ + spin_lock_irq(&phba->hbalock); cnt = 0; for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { qp = &phba->sli4_hba.hdwq[idx]; @@ -1108,7 +1149,7 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) &nvmet_aborts); spin_unlock_irq(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_for_each_entry_safe(ctxp, ctxp_next, &nvmet_aborts, list) { - ctxp->flag &= ~(LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP); + ctxp->flag &= ~(LPFC_NVME_XBUSY | LPFC_NVME_ABORT_OP); lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); } } @@ -1136,7 +1177,7 @@ lpfc_hba_down_post(struct lpfc_hba *phba) /** * lpfc_hb_timeout - The HBA-timer timeout handler - * @ptr: unsigned long holds the pointer to lpfc hba data structure. + * @t: timer context used to obtain the pointer to lpfc hba data structure. * * This is the HBA-timer timeout handler registered to the lpfc driver. When * this timer fires, a HBA timeout event shall be posted to the lpfc driver @@ -1170,7 +1211,7 @@ lpfc_hb_timeout(struct timer_list *t) /** * lpfc_rrq_timeout - The RRQ-timer timeout handler - * @ptr: unsigned long holds the pointer to lpfc hba data structure. + * @t: timer context used to obtain the pointer to lpfc hba data structure. * * This is the RRQ-timer timeout handler registered to the lpfc driver. When * this timer fires, a RRQ timeout event shall be posted to the lpfc driver @@ -1220,10 +1261,10 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) unsigned long drvr_flag; spin_lock_irqsave(&phba->hbalock, drvr_flag); - phba->hb_outstanding = 0; + phba->hba_flag &= ~(HBA_HBEAT_INP | HBA_HBEAT_TMO); spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - /* Check and reset heart-beat timer is necessary */ + /* Check and reset heart-beat timer if necessary */ mempool_free(pmboxq, phba->mbox_mem_pool); if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) && !(phba->link_state == LPFC_HBA_ERROR) && @@ -1234,6 +1275,76 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) return; } +/* + * lpfc_idle_stat_delay_work - idle_stat tracking + * + * This routine tracks per-cq idle_stat and determines polling decisions. + * + * Return codes: + * None + **/ +static void +lpfc_idle_stat_delay_work(struct work_struct *work) +{ + struct lpfc_hba *phba = container_of(to_delayed_work(work), + struct lpfc_hba, + idle_stat_delay_work); + struct lpfc_queue *cq; + struct lpfc_sli4_hdw_queue *hdwq; + struct lpfc_idle_stat *idle_stat; + u32 i, idle_percent; + u64 wall, wall_idle, diff_wall, diff_idle, busy_time; + + if (phba->pport->load_flag & FC_UNLOADING) + return; + + if (phba->link_state == LPFC_HBA_ERROR || + phba->pport->fc_flag & FC_OFFLINE_MODE || + phba->cmf_active_mode != LPFC_CFG_OFF) + goto requeue; + + for_each_present_cpu(i) { + hdwq = &phba->sli4_hba.hdwq[phba->sli4_hba.cpu_map[i].hdwq]; + cq = hdwq->io_cq; + + /* Skip if we've already handled this cq's primary CPU */ + if (cq->chann != i) + continue; + + idle_stat = &phba->sli4_hba.idle_stat[i]; + + /* get_cpu_idle_time returns values as running counters. Thus, + * to know the amount for this period, the prior counter values + * need to be subtracted from the current counter values. + * From there, the idle time stat can be calculated as a + * percentage of 100 - the sum of the other consumption times. + */ + wall_idle = get_cpu_idle_time(i, &wall, 1); + diff_idle = wall_idle - idle_stat->prev_idle; + diff_wall = wall - idle_stat->prev_wall; + + if (diff_wall <= diff_idle) + busy_time = 0; + else + busy_time = diff_wall - diff_idle; + + idle_percent = div64_u64(100 * busy_time, diff_wall); + idle_percent = 100 - idle_percent; + + if (idle_percent < 15) + cq->poll_mode = LPFC_QUEUE_WORK; + else + cq->poll_mode = LPFC_IRQ_POLL; + + idle_stat->prev_idle = wall_idle; + idle_stat->prev_wall = wall; + } + +requeue: + schedule_delayed_work(&phba->idle_stat_delay_work, + msecs_to_jiffies(LPFC_IDLE_STAT_DELAY)); +} + static void lpfc_hb_eq_delay_work(struct work_struct *work) { @@ -1328,6 +1439,60 @@ static void lpfc_hb_mxp_handler(struct lpfc_hba *phba) } /** + * lpfc_issue_hb_mbox - Issues heart-beat mailbox command + * @phba: pointer to lpfc hba data structure. + * + * If a HB mbox is not already in progrees, this routine will allocate + * a LPFC_MBOXQ_t, populate it with a MBX_HEARTBEAT (0x31) command, + * and issue it. The HBA_HBEAT_INP flag means the command is in progress. + **/ +int +lpfc_issue_hb_mbox(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *pmboxq; + int retval; + + /* Is a Heartbeat mbox already in progress */ + if (phba->hba_flag & HBA_HBEAT_INP) + return 0; + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) + return -ENOMEM; + + lpfc_heart_beat(phba, pmboxq); + pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; + pmboxq->vport = phba->pport; + retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); + + if (retval != MBX_BUSY && retval != MBX_SUCCESS) { + mempool_free(pmboxq, phba->mbox_mem_pool); + return -ENXIO; + } + phba->hba_flag |= HBA_HBEAT_INP; + + return 0; +} + +/** + * lpfc_issue_hb_tmo - Signals heartbeat timer to issue mbox command + * @phba: pointer to lpfc hba data structure. + * + * The heartbeat timer (every 5 sec) will fire. If the HBA_HBEAT_TMO + * flag is set, it will force a MBX_HEARTBEAT mbox command, regardless + * of the value of lpfc_enable_hba_heartbeat. + * If lpfc_enable_hba_heartbeat is set, the timeout routine will always + * try to issue a MBX_HEARTBEAT mbox command. + **/ +void +lpfc_issue_hb_tmo(struct lpfc_hba *phba) +{ + if (phba->cfg_enable_hba_heartbeat) + return; + phba->hba_flag |= HBA_HBEAT_TMO; +} + +/** * lpfc_hb_timeout_handler - The HBA-timer timeout handler * @phba: pointer to lpfc hba data structure. * @@ -1347,9 +1512,9 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *phba) { struct lpfc_vport **vports; - LPFC_MBOXQ_t *pmboxq; struct lpfc_dmabuf *buf_ptr; - int retval, i; + int retval = 0; + int i, tmo; struct lpfc_sli *psli = &phba->sli; LIST_HEAD(completions); @@ -1371,24 +1536,6 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) (phba->pport->fc_flag & FC_OFFLINE_MODE)) return; - spin_lock_irq(&phba->pport->work_port_lock); - - if (time_after(phba->last_completion_time + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL), - jiffies)) { - spin_unlock_irq(&phba->pport->work_port_lock); - if (!phba->hb_outstanding) - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); - else - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT)); - return; - } - spin_unlock_irq(&phba->pport->work_port_lock); - if (phba->elsbuf_cnt && (phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) { spin_lock_irq(&phba->hbalock); @@ -1408,37 +1555,43 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) /* If there is no heart beat outstanding, issue a heartbeat command */ if (phba->cfg_enable_hba_heartbeat) { - if (!phba->hb_outstanding) { + /* If IOs are completing, no need to issue a MBX_HEARTBEAT */ + spin_lock_irq(&phba->pport->work_port_lock); + if (time_after(phba->last_completion_time + + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL), + jiffies)) { + spin_unlock_irq(&phba->pport->work_port_lock); + if (phba->hba_flag & HBA_HBEAT_INP) + tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); + else + tmo = (1000 * LPFC_HB_MBOX_INTERVAL); + goto out; + } + spin_unlock_irq(&phba->pport->work_port_lock); + + /* Check if a MBX_HEARTBEAT is already in progress */ + if (phba->hba_flag & HBA_HBEAT_INP) { + /* + * If heart beat timeout called with HBA_HBEAT_INP set + * we need to give the hb mailbox cmd a chance to + * complete or TMO. + */ + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0459 Adapter heartbeat still outstanding: " + "last compl time was %d ms.\n", + jiffies_to_msecs(jiffies + - phba->last_completion_time)); + tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); + } else { if ((!(psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) && (list_empty(&psli->mboxq))) { - pmboxq = mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL); - if (!pmboxq) { - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * - LPFC_HB_MBOX_INTERVAL)); - return; - } - lpfc_heart_beat(phba, pmboxq); - pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; - pmboxq->vport = phba->pport; - retval = lpfc_sli_issue_mbox(phba, pmboxq, - MBX_NOWAIT); - - if (retval != MBX_BUSY && - retval != MBX_SUCCESS) { - mempool_free(pmboxq, - phba->mbox_mem_pool); - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * - LPFC_HB_MBOX_INTERVAL)); - return; + retval = lpfc_issue_hb_mbox(phba); + if (retval) { + tmo = (1000 * LPFC_HB_MBOX_INTERVAL); + goto out; } phba->skipped_hb = 0; - phba->hb_outstanding = 1; } else if (time_before_eq(phba->last_completion_time, phba->skipped_hb)) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -1449,30 +1602,23 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) } else phba->skipped_hb = jiffies; - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT)); - return; - } else { - /* - * If heart beat timeout called with hb_outstanding set - * we need to give the hb mailbox cmd a chance to - * complete or TMO. - */ - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0459 Adapter heartbeat still out" - "standing:last compl time was %d ms.\n", - jiffies_to_msecs(jiffies - - phba->last_completion_time)); - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT)); + tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); + goto out; } } else { - mod_timer(&phba->hb_tmofunc, - jiffies + - msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); + /* Check to see if we want to force a MBX_HEARTBEAT */ + if (phba->hba_flag & HBA_HBEAT_TMO) { + retval = lpfc_issue_hb_mbox(phba); + if (retval) + tmo = (1000 * LPFC_HB_MBOX_INTERVAL); + else + tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); + goto out; + } + tmo = (1000 * LPFC_HB_MBOX_INTERVAL); } +out: + mod_timer(&phba->hb_tmofunc, jiffies + msecs_to_jiffies(tmo)); } /** @@ -1515,6 +1661,11 @@ void lpfc_sli4_offline_eratt(struct lpfc_hba *phba) { spin_lock_irq(&phba->hbalock); + if (phba->link_state == LPFC_HBA_ERROR && + test_bit(HBA_PCI_ERR, &phba->bit_flags)) { + spin_unlock_irq(&phba->hbalock); + return; + } phba->link_state = LPFC_HBA_ERROR; spin_unlock_irq(&phba->hbalock); @@ -1550,11 +1701,11 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) return; } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0479 Deferred Adapter Hardware Error " - "Data: x%x x%x x%x\n", - phba->work_hs, - phba->work_status[0], phba->work_status[1]); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0479 Deferred Adapter Hardware Error " + "Data: x%x x%x x%x\n", + phba->work_hs, phba->work_status[0], + phba->work_status[1]); spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~LPFC_SLI_ACTIVE; @@ -1705,7 +1856,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) temp_event_data.event_code = LPFC_CRIT_TEMP; temp_event_data.data = (uint32_t)temperature; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0406 Adapter maximum temperature exceeded " "(%ld), taking this port offline " "Data: x%x x%x x%x\n", @@ -1729,7 +1880,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) * failure is a value other than FFER6. Do not call the offline * twice. This is the adapter hardware error path. */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0457 Adapter Hardware Error " "Data: x%x x%x x%x\n", phba->work_hs, @@ -1750,7 +1901,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba) * lpfc_sli4_port_sta_fn_reset - The SLI4 function reset due to port status reg * @phba: pointer to lpfc hba data structure. * @mbx_action: flag for mailbox shutdown action. - * + * @en_rn_msg: send reset/port recovery message. * This routine is invoked to perform an SLI4 port PCI function reset in * response to port status register polling attention. It waits for port * status register (ERR, RDY, RN) bits before proceeding with function reset. @@ -1763,6 +1914,7 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, { int rc; uint32_t intr_mode; + LPFC_MBOXQ_t *mboxq; if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= LPFC_SLI_INTF_IF_TYPE_2) { @@ -1777,9 +1929,27 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, /* need reset: attempt for port recovery */ if (en_rn_msg) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2887 Reset Needed: Attempting Port " "Recovery...\n"); + + /* If we are no wait, the HBA has been reset and is not + * functional, thus we should clear + * (LPFC_SLI_ACTIVE | LPFC_SLI_MBOX_ACTIVE) flags. + */ + if (mbx_action == LPFC_MBX_NO_WAIT) { + spin_lock_irq(&phba->hbalock); + phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE; + if (phba->sli.mbox_active) { + mboxq = phba->sli.mbox_active; + mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; + __lpfc_mbox_cmpl_put(phba, mboxq); + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = NULL; + } + spin_unlock_irq(&phba->hbalock); + } + lpfc_offline_prep(phba, mbx_action); lpfc_sli_flush_io_rings(phba); lpfc_offline(phba); @@ -1787,14 +1957,14 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, lpfc_sli4_disable_intr(phba); rc = lpfc_sli_brdrestart(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6309 Failed to restart board\n"); return rc; } /* request and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3175 Failed to enable interrupt\n"); return -EIO; } @@ -1833,9 +2003,9 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) * we cannot communicate with the pci card anyway. */ if (pci_channel_offline(phba->pcidev)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3166 pci channel is offline\n"); - lpfc_sli4_offline_eratt(phba); + lpfc_sli_flush_io_rings(phba); return; } @@ -1856,7 +2026,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) lpfc_sli4_offline_eratt(phba); return; } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "7623 Checking UE recoverable"); for (i = 0; i < phba->sli4_hba.ue_to_sr / 1000; i++) { @@ -1873,7 +2043,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) msleep(1000); } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "4827 smphr_port_status x%x : Waited %dSec", smphr_port_status, i); @@ -1891,14 +2061,14 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) LPFC_MBX_NO_WAIT, en_rn_msg); if (rc == 0) return; - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "4215 Failed to recover UE"); break; } } } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "7624 Firmware not ready: Failing UE recovery," " waited %dSec", i); phba->link_state = LPFC_HBA_ERROR; @@ -1911,7 +2081,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) &portstat_reg.word0); /* consider PCI bus read error as pci_channel_offline */ if (pci_rd_rc1 == -EIO) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3151 PCI bus read access failure: x%x\n", readl(phba->sli4_hba.u.if_type2.STATUSregaddr)); lpfc_sli4_offline_eratt(phba); @@ -1920,10 +2090,10 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr); reg_err2 = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2889 Port Overtemperature event, " - "taking port offline Data: x%x x%x\n", - reg_err1, reg_err2); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2889 Port Overtemperature event, " + "taking port offline Data: x%x x%x\n", + reg_err1, reg_err2); phba->sfp_alarm |= LPFC_TRANSGRESSION_HIGH_TEMPERATURE; temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; @@ -1945,17 +2115,17 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) } if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3143 Port Down: Firmware Update " "Detected\n"); en_rn_msg = false; } else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3144 Port Down: Debug Dump\n"); else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && reg_err2 == SLIPORT_ERR2_REG_FUNC_PROVISON) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3145 Port Down: Provisioning\n"); /* If resets are disabled then leave the HBA alone and return */ @@ -1974,7 +2144,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) break; } /* fall through for not able to recover */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3152 Unrecoverable error\n"); phba->link_state = LPFC_HBA_ERROR; break; @@ -2025,7 +2195,6 @@ lpfc_handle_latt(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; LPFC_MBOXQ_t *pmb; volatile uint32_t control; - struct lpfc_dmabuf *mp; int rc = 0; pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -2034,23 +2203,17 @@ lpfc_handle_latt(struct lpfc_hba *phba) goto lpfc_handle_latt_err_exit; } - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) { + rc = lpfc_mbox_rsrc_prep(phba, pmb); + if (rc) { rc = 2; - goto lpfc_handle_latt_free_pmb; - } - - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp->virt) { - rc = 3; - goto lpfc_handle_latt_free_mp; + mempool_free(pmb, phba->mbox_mem_pool); + goto lpfc_handle_latt_err_exit; } /* Cleanup any outstanding ELS commands */ lpfc_els_flush_all_cmd(phba); - psli->slistat.link_event++; - lpfc_read_topology(phba, pmb, mp); + lpfc_read_topology(phba, pmb, (struct lpfc_dmabuf *)pmb->ctx_buf); pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology; pmb->vport = vport; /* Block ELS IOCBs until we have processed this mbox command */ @@ -2071,11 +2234,7 @@ lpfc_handle_latt(struct lpfc_hba *phba) lpfc_handle_latt_free_mbuf: phba->sli.sli3_ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT; - lpfc_mbuf_free(phba, mp->virt, mp->phys); -lpfc_handle_latt_free_mp: - kfree(mp); -lpfc_handle_latt_free_pmb: - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); lpfc_handle_latt_err_exit: /* Enable Link attention interrupts */ spin_lock_irq(&phba->hbalock); @@ -2092,12 +2251,107 @@ lpfc_handle_latt_err_exit: lpfc_linkdown(phba); phba->link_state = LPFC_HBA_ERROR; - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc); return; } +static void +lpfc_fill_vpd(struct lpfc_hba *phba, uint8_t *vpd, int length, int *pindex) +{ + int i, j; + + while (length > 0) { + /* Look for Serial Number */ + if ((vpd[*pindex] == 'S') && (vpd[*pindex + 1] == 'N')) { + *pindex += 2; + i = vpd[*pindex]; + *pindex += 1; + j = 0; + length -= (3+i); + while (i--) { + phba->SerialNumber[j++] = vpd[(*pindex)++]; + if (j == 31) + break; + } + phba->SerialNumber[j] = 0; + continue; + } else if ((vpd[*pindex] == 'V') && (vpd[*pindex + 1] == '1')) { + phba->vpd_flag |= VPD_MODEL_DESC; + *pindex += 2; + i = vpd[*pindex]; + *pindex += 1; + j = 0; + length -= (3+i); + while (i--) { + phba->ModelDesc[j++] = vpd[(*pindex)++]; + if (j == 255) + break; + } + phba->ModelDesc[j] = 0; + continue; + } else if ((vpd[*pindex] == 'V') && (vpd[*pindex + 1] == '2')) { + phba->vpd_flag |= VPD_MODEL_NAME; + *pindex += 2; + i = vpd[*pindex]; + *pindex += 1; + j = 0; + length -= (3+i); + while (i--) { + phba->ModelName[j++] = vpd[(*pindex)++]; + if (j == 79) + break; + } + phba->ModelName[j] = 0; + continue; + } else if ((vpd[*pindex] == 'V') && (vpd[*pindex + 1] == '3')) { + phba->vpd_flag |= VPD_PROGRAM_TYPE; + *pindex += 2; + i = vpd[*pindex]; + *pindex += 1; + j = 0; + length -= (3+i); + while (i--) { + phba->ProgramType[j++] = vpd[(*pindex)++]; + if (j == 255) + break; + } + phba->ProgramType[j] = 0; + continue; + } else if ((vpd[*pindex] == 'V') && (vpd[*pindex + 1] == '4')) { + phba->vpd_flag |= VPD_PORT; + *pindex += 2; + i = vpd[*pindex]; + *pindex += 1; + j = 0; + length -= (3 + i); + while (i--) { + if ((phba->sli_rev == LPFC_SLI_REV4) && + (phba->sli4_hba.pport_name_sta == + LPFC_SLI4_PPNAME_GET)) { + j++; + (*pindex)++; + } else + phba->Port[j++] = vpd[(*pindex)++]; + if (j == 19) + break; + } + if ((phba->sli_rev != LPFC_SLI_REV4) || + (phba->sli4_hba.pport_name_sta == + LPFC_SLI4_PPNAME_NON)) + phba->Port[j] = 0; + continue; + } else { + *pindex += 2; + i = vpd[*pindex]; + *pindex += 1; + *pindex += i; + length -= (3 + i); + } + } +} + /** * lpfc_parse_vpd - Parse VPD (Vital Product Data) * @phba: pointer to lpfc hba data structure. @@ -2117,7 +2371,7 @@ lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len) { uint8_t lenlo, lenhi; int Length; - int i, j; + int i; int finished = 0; int index = 0; @@ -2150,101 +2404,10 @@ lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len) Length = ((((unsigned short)lenhi) << 8) + lenlo); if (Length > len - index) Length = len - index; - while (Length > 0) { - /* Look for Serial Number */ - if ((vpd[index] == 'S') && (vpd[index+1] == 'N')) { - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - phba->SerialNumber[j++] = vpd[index++]; - if (j == 31) - break; - } - phba->SerialNumber[j] = 0; - continue; - } - else if ((vpd[index] == 'V') && (vpd[index+1] == '1')) { - phba->vpd_flag |= VPD_MODEL_DESC; - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - phba->ModelDesc[j++] = vpd[index++]; - if (j == 255) - break; - } - phba->ModelDesc[j] = 0; - continue; - } - else if ((vpd[index] == 'V') && (vpd[index+1] == '2')) { - phba->vpd_flag |= VPD_MODEL_NAME; - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - phba->ModelName[j++] = vpd[index++]; - if (j == 79) - break; - } - phba->ModelName[j] = 0; - continue; - } - else if ((vpd[index] == 'V') && (vpd[index+1] == '3')) { - phba->vpd_flag |= VPD_PROGRAM_TYPE; - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - phba->ProgramType[j++] = vpd[index++]; - if (j == 255) - break; - } - phba->ProgramType[j] = 0; - continue; - } - else if ((vpd[index] == 'V') && (vpd[index+1] == '4')) { - phba->vpd_flag |= VPD_PORT; - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - if ((phba->sli_rev == LPFC_SLI_REV4) && - (phba->sli4_hba.pport_name_sta == - LPFC_SLI4_PPNAME_GET)) { - j++; - index++; - } else - phba->Port[j++] = vpd[index++]; - if (j == 19) - break; - } - if ((phba->sli_rev != LPFC_SLI_REV4) || - (phba->sli4_hba.pport_name_sta == - LPFC_SLI4_PPNAME_NON)) - phba->Port[j] = 0; - continue; - } - else { - index += 2; - i = vpd[index]; - index += 1; - index += i; - Length -= (3 + i); - } - } - finished = 0; - break; + + lpfc_fill_vpd(phba, vpd, Length, &index); + finished = 0; + break; case 0x78: finished = 1; break; @@ -2258,6 +2421,90 @@ lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len) } /** + * lpfc_get_atto_model_desc - Retrieve ATTO HBA device model name and description + * @phba: pointer to lpfc hba data structure. + * @mdp: pointer to the data structure to hold the derived model name. + * @descp: pointer to the data structure to hold the derived description. + * + * This routine retrieves HBA's description based on its registered PCI device + * ID. The @descp passed into this function points to an array of 256 chars. It + * shall be returned with the model name, maximum speed, and the host bus type. + * The @mdp passed into this function points to an array of 80 chars. When the + * function returns, the @mdp will be filled with the model name. + **/ +static void +lpfc_get_atto_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) +{ + uint16_t sub_dev_id = phba->pcidev->subsystem_device; + char *model = "<Unknown>"; + int tbolt = 0; + + switch (sub_dev_id) { + case PCI_DEVICE_ID_CLRY_161E: + model = "161E"; + break; + case PCI_DEVICE_ID_CLRY_162E: + model = "162E"; + break; + case PCI_DEVICE_ID_CLRY_164E: + model = "164E"; + break; + case PCI_DEVICE_ID_CLRY_161P: + model = "161P"; + break; + case PCI_DEVICE_ID_CLRY_162P: + model = "162P"; + break; + case PCI_DEVICE_ID_CLRY_164P: + model = "164P"; + break; + case PCI_DEVICE_ID_CLRY_321E: + model = "321E"; + break; + case PCI_DEVICE_ID_CLRY_322E: + model = "322E"; + break; + case PCI_DEVICE_ID_CLRY_324E: + model = "324E"; + break; + case PCI_DEVICE_ID_CLRY_321P: + model = "321P"; + break; + case PCI_DEVICE_ID_CLRY_322P: + model = "322P"; + break; + case PCI_DEVICE_ID_CLRY_324P: + model = "324P"; + break; + case PCI_DEVICE_ID_TLFC_2XX2: + model = "2XX2"; + tbolt = 1; + break; + case PCI_DEVICE_ID_TLFC_3162: + model = "3162"; + tbolt = 1; + break; + case PCI_DEVICE_ID_TLFC_3322: + model = "3322"; + tbolt = 1; + break; + default: + model = "Unknown"; + break; + } + + if (mdp && mdp[0] == '\0') + snprintf(mdp, 79, "%s", model); + + if (descp && descp[0] == '\0') + snprintf(descp, 255, + "ATTO %s%s, Fibre Channel Adapter Initiator, Port %s", + (tbolt) ? "ThunderLink FC " : "Celerity FC-", + model, + phba->Port); +} + +/** * lpfc_get_hba_model_desc - Retrieve HBA device model name and description * @phba: pointer to lpfc hba data structure. * @mdp: pointer to the data structure to hold the derived model name. @@ -2287,6 +2534,11 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) && descp && descp[0] != '\0') return; + if (phba->pcidev->vendor == PCI_VENDOR_ID_ATTO) { + lpfc_get_atto_model_desc(phba, mdp, descp); + return; + } + if (phba->lmt & LMT_64Gb) max_speed = 64; else if (phba->lmt & LMT_32Gb) @@ -2436,11 +2688,6 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) case PCI_DEVICE_ID_SAT_S: m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"}; break; - case PCI_DEVICE_ID_HORNET: - m = (typeof(m)){"LP21000", "PCIe", - "Obsolete, Unsupported FCoE Adapter"}; - GE = 1; - break; case PCI_DEVICE_ID_PROTEUS_VF: m = (typeof(m)){"LPev12000", "PCIe IOV", "Obsolete, Unsupported Fibre Channel Adapter"}; @@ -2491,6 +2738,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) case PCI_DEVICE_ID_LANCER_G7_FC: m = (typeof(m)){"LPe36000", "PCIe", "Fibre Channel Adapter"}; break; + case PCI_DEVICE_ID_LANCER_G7P_FC: + m = (typeof(m)){"LPe38000", "PCIe", "Fibre Channel Adapter"}; + break; case PCI_DEVICE_ID_SKYHAWK: case PCI_DEVICE_ID_SKYHAWK_VF: oneConnect = 1; @@ -2526,7 +2776,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) } /** - * lpfc_post_buffer - Post IOCB(s) with DMA buffer descriptor(s) to a IOCB ring + * lpfc_sli3_post_buffer - Post IOCB(s) with DMA buffer descriptor(s) to a IOCB ring * @phba: pointer to lpfc hba data structure. * @pring: pointer to a IOCB ring. * @cnt: the number of IOCBs to be posted to the IOCB ring. @@ -2538,7 +2788,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) * The number of IOCBs NOT able to be posted to the IOCB ring. **/ int -lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt) +lpfc_sli3_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt) { IOCB_t *icmd; struct lpfc_iocbq *iocb; @@ -2644,7 +2894,7 @@ lpfc_post_rcv_buf(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; /* Ring 0, ELS / CT buffers */ - lpfc_post_buffer(phba, &psli->sli3_ring[LPFC_ELS_RING], LPFC_BUF_RING0); + lpfc_sli3_post_buffer(phba, &psli->sli3_ring[LPFC_ELS_RING], LPFC_BUF_RING0); /* Ring 2 - FCP no buffers needed */ return 0; @@ -2790,29 +3040,11 @@ lpfc_cleanup(struct lpfc_vport *vport) if (phba->link_state > LPFC_LINK_DOWN) lpfc_port_link_failure(vport); - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - continue; - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - /* Trigger the release of the ndlp memory */ - lpfc_nlp_put(ndlp); - continue; - } - spin_lock_irq(&phba->ndlp_lock); - if (NLP_CHK_FREE_REQ(ndlp)) { - /* The ndlp should not be in memory free mode already */ - spin_unlock_irq(&phba->ndlp_lock); - continue; - } else - /* Indicate request for freeing ndlp memory */ - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); + /* Clean up VMID resources */ + if (lpfc_is_vmid_enabled(phba)) + lpfc_vmid_vport_cleanup(vport); + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (vport->port_type != LPFC_PHYSICAL_PORT && ndlp->nlp_DID == Fabric_DID) { /* Just free up ndlp with Fabric_DID for vports */ @@ -2820,21 +3052,40 @@ lpfc_cleanup(struct lpfc_vport *vport) continue; } - /* take care of nodes in unused state before the state - * machine taking action. - */ - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + if (ndlp->nlp_DID == Fabric_Cntl_DID && + ndlp->nlp_state == NLP_STE_UNUSED_NODE) { lpfc_nlp_put(ndlp); continue; } - if (ndlp->nlp_type & NLP_FABRIC) + /* Fabric Ports not in UNMAPPED state are cleaned up in the + * DEVICE_RM event. + */ + if (ndlp->nlp_type & NLP_FABRIC && + ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RM); - } + if (!(ndlp->fc4_xpt_flags & (NVME_XPT_REGD|SCSI_XPT_REGD))) + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); + } + + /* This is a special case flush to return all + * IOs before entering this loop. There are + * two points in the code where a flush is + * avoided if the FC_UNLOADING flag is set. + * one is in the multipool destroy, + * (this prevents a crash) and the other is + * in the nvme abort handler, ( also prevents + * a crash). Both of these exceptions are + * cases where the slot is still accessible. + * The flush here is only when the pci slot + * is offline. + */ + if (vport->load_flag & FC_UNLOADING && + pci_channel_offline(phba->pcidev)) + lpfc_sli_flush_io_rings(vport->phba); /* At this point, ALL ndlp's should be gone * because of the previous NLP_EVT_DEVICE_RM. @@ -2842,17 +3093,19 @@ lpfc_cleanup(struct lpfc_vport *vport) */ while (!list_empty(&vport->fc_nodes)) { if (i++ > 3000) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0233 Nodelist not empty\n"); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { lpfc_printf_vlog(ndlp->vport, KERN_ERR, - LOG_NODE, - "0282 did:x%x ndlp:x%px " - "usgmap:x%x refcnt:%d\n", - ndlp->nlp_DID, (void *)ndlp, - ndlp->nlp_usg_map, - kref_read(&ndlp->kref)); + LOG_DISCOVERY, + "0282 did:x%x ndlp:x%px " + "refcnt:%d xflags x%x nflag x%x\n", + ndlp->nlp_DID, (void *)ndlp, + kref_read(&ndlp->kref), + ndlp->fc4_xpt_flags, + ndlp->nlp_flag); } break; } @@ -2922,6 +3175,123 @@ lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba) } /** + * lpfc_cmf_stop - Stop CMF processing + * @phba: pointer to lpfc hba data structure. + * + * This is called when the link goes down or if CMF mode is turned OFF. + * It is also called when going offline or unloaded just before the + * congestion info buffer is unregistered. + **/ +void +lpfc_cmf_stop(struct lpfc_hba *phba) +{ + int cpu; + struct lpfc_cgn_stat *cgs; + + /* We only do something if CMF is enabled */ + if (!phba->sli4_hba.pc_sli4_params.cmf) + return; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6221 Stop CMF / Cancel Timer\n"); + + /* Cancel the CMF timer */ + hrtimer_cancel(&phba->cmf_timer); + + /* Zero CMF counters */ + atomic_set(&phba->cmf_busy, 0); + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + atomic64_set(&cgs->total_bytes, 0); + atomic64_set(&cgs->rcv_bytes, 0); + atomic_set(&cgs->rx_io_cnt, 0); + atomic64_set(&cgs->rx_latency, 0); + } + atomic_set(&phba->cmf_bw_wait, 0); + + /* Resume any blocked IO - Queue unblock on workqueue */ + queue_work(phba->wq, &phba->unblock_request_work); +} + +static inline uint64_t +lpfc_get_max_line_rate(struct lpfc_hba *phba) +{ + uint64_t rate = lpfc_sli_port_speed_get(phba); + + return ((((unsigned long)rate) * 1024 * 1024) / 10); +} + +void +lpfc_cmf_signal_init(struct lpfc_hba *phba) +{ + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6223 Signal CMF init\n"); + + /* Use the new fc_linkspeed to recalculate */ + phba->cmf_interval_rate = LPFC_CMF_INTERVAL; + phba->cmf_max_line_rate = lpfc_get_max_line_rate(phba); + phba->cmf_link_byte_count = div_u64(phba->cmf_max_line_rate * + phba->cmf_interval_rate, 1000); + phba->cmf_max_bytes_per_interval = phba->cmf_link_byte_count; + + /* This is a signal to firmware to sync up CMF BW with link speed */ + lpfc_issue_cmf_sync_wqe(phba, 0, 0); +} + +/** + * lpfc_cmf_start - Start CMF processing + * @phba: pointer to lpfc hba data structure. + * + * This is called when the link comes up or if CMF mode is turned OFF + * to Monitor or Managed. + **/ +void +lpfc_cmf_start(struct lpfc_hba *phba) +{ + struct lpfc_cgn_stat *cgs; + int cpu; + + /* We only do something if CMF is enabled */ + if (!phba->sli4_hba.pc_sli4_params.cmf || + phba->cmf_active_mode == LPFC_CFG_OFF) + return; + + /* Reinitialize congestion buffer info */ + lpfc_init_congestion_buf(phba); + + atomic_set(&phba->cgn_fabric_warn_cnt, 0); + atomic_set(&phba->cgn_fabric_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_warn_cnt, 0); + + atomic_set(&phba->cmf_busy, 0); + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + atomic64_set(&cgs->total_bytes, 0); + atomic64_set(&cgs->rcv_bytes, 0); + atomic_set(&cgs->rx_io_cnt, 0); + atomic64_set(&cgs->rx_latency, 0); + } + phba->cmf_latency.tv_sec = 0; + phba->cmf_latency.tv_nsec = 0; + + lpfc_cmf_signal_init(phba); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6222 Start CMF / Timer\n"); + + phba->cmf_timer_cnt = 0; + hrtimer_start(&phba->cmf_timer, + ktime_set(0, LPFC_CMF_INTERVAL * 1000000), + HRTIMER_MODE_REL); + /* Setup for latency check in IO cmpl routines */ + ktime_get_real_ts64(&phba->cmf_latency); + + atomic_set(&phba->cmf_bw_wait, 0); + atomic_set(&phba->cmf_stop_io, 0); +} + +/** * lpfc_stop_hba_timers - Stop all the timers associated with an HBA * @phba: pointer to lpfc hba data structure. * @@ -2934,6 +3304,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) if (phba->pport) lpfc_stop_vport_timers(phba->pport); cancel_delayed_work_sync(&phba->eq_delay_work); + cancel_delayed_work_sync(&phba->idle_stat_delay_work); del_timer_sync(&phba->sli.mbox_tmo); del_timer_sync(&phba->fabric_block_timer); del_timer_sync(&phba->eratt_poll); @@ -2942,7 +3313,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) del_timer_sync(&phba->rrq_tmr); phba->hba_flag &= ~HBA_RRQ_ACTIVE; } - phba->hb_outstanding = 0; + phba->hba_flag &= ~(HBA_HBEAT_INP | HBA_HBEAT_TMO); switch (phba->pci_dev_grp) { case LPFC_PCI_DEV_LP: @@ -2954,7 +3325,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) lpfc_sli4_stop_fcf_redisc_wait_timer(phba); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0297 Invalid device group (x%x)\n", phba->pci_dev_grp); break; @@ -2965,6 +3336,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) /** * lpfc_block_mgmt_io - Mark a HBA's management interface as blocked * @phba: pointer to lpfc hba data structure. + * @mbx_action: flag for mailbox no wait action. * * This routine marks a HBA's management interface as blocked. Once the HBA's * management interface is marked as blocked, all the user space access to @@ -3001,10 +3373,10 @@ lpfc_block_mgmt_io(struct lpfc_hba *phba, int mbx_action) /* Check active mailbox complete status every 2ms */ msleep(2); if (time_after(jiffies, timeout)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2813 Mgmt IO is Blocked %x " - "- mbox cmd %x still active\n", - phba->sli.sli_flag, actcmd); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2813 Mgmt IO is Blocked %x " + "- mbox cmd %x still active\n", + phba->sli.sli_flag, actcmd); break; } } @@ -3024,7 +3396,6 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) struct lpfc_nodelist *ndlp, *next_ndlp; struct lpfc_vport **vports; int i, rpi; - unsigned long flags; if (phba->sli_rev != LPFC_SLI_REV4) return; @@ -3040,22 +3411,18 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; rpi = lpfc_sli4_alloc_rpi(phba); if (rpi == LPFC_RPI_ALLOC_ERROR) { - spin_lock_irqsave(&phba->ndlp_lock, flags); - NLP_CLR_NODE_ACT(ndlp); - spin_unlock_irqrestore(&phba->ndlp_lock, flags); + /* TODO print log? */ continue; } ndlp->nlp_rpi = rpi; lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0009 Assign RPI x%x to ndlp x%px " - "DID:x%06x flg:x%x map:x%x\n", + "DID:x%06x flg:x%x\n", ndlp->nlp_rpi, ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, ndlp->nlp_usg_map); + ndlp->nlp_flag); } } lpfc_destroy_vport_work_array(phba, vports); @@ -3349,7 +3716,7 @@ lpfc_online(struct lpfc_hba *phba) !phba->nvmet_support) { error = lpfc_nvme_create_localport(phba->pport); if (error) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6132 NVME restore reg failed " "on nvmei error x%x\n", error); } @@ -3415,6 +3782,7 @@ lpfc_unblock_mgmt_io(struct lpfc_hba * phba) /** * lpfc_offline_prep - Prepare a HBA to be brought offline * @phba: pointer to lpfc hba data structure. + * @mbx_action: flag for mailbox shutdown action. * * This routine is invoked to prepare a HBA to be brought offline. It performs * unregistration login to all the nodes on all vports and flushes the mailbox @@ -3428,6 +3796,8 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) struct lpfc_vport **vports; struct Scsi_Host *shost; int i; + int offline; + bool hba_pci_err; if (vport->fc_flag & FC_OFFLINE_MODE) return; @@ -3436,6 +3806,9 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) lpfc_linkdown(phba); + offline = pci_channel_offline(phba->pcidev); + hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags); + /* Issue an unreg_login to all nodes on all vports */ vports = lpfc_create_vport_work_array(phba); if (vports != NULL) { @@ -3453,42 +3826,58 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, nlp_listp) { - if ((!NLP_CHK_NODE_ACT(ndlp)) || - ndlp->nlp_state == NLP_STE_UNUSED_NODE) { - /* Driver must assume RPI is invalid for - * any unused or inactive node. - */ - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - continue; - } - if (ndlp->nlp_type & NLP_FABRIC) { - lpfc_disc_state_machine(vports[i], ndlp, - NULL, NLP_EVT_DEVICE_RECOVERY); - lpfc_disc_state_machine(vports[i], ndlp, - NULL, NLP_EVT_DEVICE_RM); - } - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); + + if (offline || hba_pci_err) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~(NLP_UNREG_INP | + NLP_RPI_REGISTERED); + spin_unlock_irq(&ndlp->lock); + if (phba->sli_rev == LPFC_SLI_REV4) + lpfc_sli_rpi_release(vports[i], + ndlp); + } else { + lpfc_unreg_rpi(vports[i], ndlp); + } /* * Whenever an SLI4 port goes offline, free the * RPI. Get a new RPI when the adapter port * comes back online. */ if (phba->sli_rev == LPFC_SLI_REV4) { - lpfc_printf_vlog(ndlp->vport, KERN_INFO, + lpfc_printf_vlog(vports[i], KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0011 Free RPI x%x on " - "ndlp:x%px did x%x " - "usgmap:x%x\n", + "ndlp: x%px did x%x\n", ndlp->nlp_rpi, ndlp, - ndlp->nlp_DID, - ndlp->nlp_usg_map); + ndlp->nlp_DID); lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; } - lpfc_unreg_rpi(vports[i], ndlp); + + if (ndlp->nlp_type & NLP_FABRIC) { + lpfc_disc_state_machine(vports[i], ndlp, + NULL, NLP_EVT_DEVICE_RECOVERY); + + /* Don't remove the node unless the node + * has been unregistered with the + * transport, and we're not in recovery + * before dev_loss_tmo triggered. + * Otherwise, let dev_loss take care of + * the node. + */ + if (!(ndlp->save_flags & + NLP_IN_RECOV_POST_DEV_LOSS) && + !(ndlp->fc4_xpt_flags & + (NVME_XPT_REGD | SCSI_XPT_REGD))) + lpfc_disc_state_machine + (vports[i], ndlp, + NULL, + NLP_EVT_DEVICE_RM); + } } } } @@ -3550,7 +3939,11 @@ lpfc_offline(struct lpfc_hba *phba) spin_unlock_irq(shost->host_lock); } lpfc_destroy_vport_work_array(phba, vports); - __lpfc_cpuhp_remove(phba); + /* If OFFLINE flag is clear (i.e. unloading), cpuhp removal is handled + * in hba_unset + */ + if (phba->pport->fc_flag & FC_OFFLINE_MODE) + __lpfc_cpuhp_remove(phba); if (phba->cfg_xri_rebalancing) lpfc_destroy_multixri_pools(phba); @@ -3689,7 +4082,8 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); if (sglq_entry == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2562 Failure to allocate an " "ELS sgl entry:%d\n", i); rc = -ENOMEM; @@ -3700,7 +4094,8 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) &sglq_entry->phys); if (sglq_entry->virt == NULL) { kfree(sglq_entry); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2563 Failure to allocate an " "ELS mbuf:%d\n", i); rc = -ENOMEM; @@ -3711,12 +4106,10 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) sglq_entry->state = SGL_FREED; list_add_tail(&sglq_entry->list, &els_sgl_list); } - spin_lock_irq(&phba->hbalock); - spin_lock(&phba->sli4_hba.sgl_list_lock); + spin_lock_irq(&phba->sli4_hba.sgl_list_lock); list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_els_sgl_list); - spin_unlock(&phba->sli4_hba.sgl_list_lock); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->sli4_hba.sgl_list_lock); } else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) { /* els xri-sgl shrinked */ xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt; @@ -3724,8 +4117,7 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) "3158 ELS xri-sgl count decreased from " "%d to %d\n", phba->sli4_hba.els_xri_cnt, els_xri_cnt); - spin_lock_irq(&phba->hbalock); - spin_lock(&phba->sli4_hba.sgl_list_lock); + spin_lock_irq(&phba->sli4_hba.sgl_list_lock); list_splice_init(&phba->sli4_hba.lpfc_els_sgl_list, &els_sgl_list); /* release extra els sgls from list */ @@ -3740,8 +4132,7 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) } list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_els_sgl_list); - spin_unlock(&phba->sli4_hba.sgl_list_lock); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->sli4_hba.sgl_list_lock); } else lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3163 ELS xri-sgl count unchanged: %d\n", @@ -3755,7 +4146,8 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) &phba->sli4_hba.lpfc_els_sgl_list, list) { lxri = lpfc_sli4_next_xritag(phba); if (lxri == NO_XRI) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2400 Failed to allocate xri for " "ELS sgl\n"); rc = -ENOMEM; @@ -3810,7 +4202,8 @@ lpfc_sli4_nvmet_sgl_update(struct lpfc_hba *phba) sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); if (sglq_entry == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6303 Failure to allocate an " "NVMET sgl entry:%d\n", i); rc = -ENOMEM; @@ -3821,7 +4214,8 @@ lpfc_sli4_nvmet_sgl_update(struct lpfc_hba *phba) &sglq_entry->phys); if (sglq_entry->virt == NULL) { kfree(sglq_entry); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6304 Failure to allocate an " "NVMET buf:%d\n", i); rc = -ENOMEM; @@ -3877,7 +4271,8 @@ lpfc_sli4_nvmet_sgl_update(struct lpfc_hba *phba) &phba->sli4_hba.lpfc_nvmet_sgl_list, list) { lxri = lpfc_sli4_next_xritag(phba); if (lxri == NO_XRI) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6307 Failed to allocate xri for " "NVMET sgl\n"); rc = -ENOMEM; @@ -3974,8 +4369,7 @@ lpfc_io_buf_replenish(struct lpfc_hba *phba, struct list_head *cbuf) qp = &phba->sli4_hba.hdwq[idx]; lpfc_cmd->hdwq_no = idx; lpfc_cmd->hdwq = qp; - lpfc_cmd->cur_iocbq.wqe_cmpl = NULL; - lpfc_cmd->cur_iocbq.iocb_cmpl = NULL; + lpfc_cmd->cur_iocbq.cmd_cmpl = NULL; spin_lock(&qp->io_buf_list_put_lock); list_add_tail(&lpfc_cmd->list, &qp->lpfc_io_buf_list_put); @@ -4019,9 +4413,10 @@ lpfc_sli4_io_sgl_update(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "6074 Current allocated XRI sgl count:%d, " - "maximum XRI count:%d\n", + "maximum XRI count:%d els_xri_cnt:%d\n\n", phba->sli4_hba.io_xri_cnt, - phba->sli4_hba.io_xri_max); + phba->sli4_hba.io_xri_max, + els_xri_cnt); cnt = lpfc_io_buf_flush(phba, &io_sgl_list); @@ -4051,7 +4446,8 @@ lpfc_sli4_io_sgl_update(struct lpfc_hba *phba) &io_sgl_list, list) { lxri = lpfc_sli4_next_xritag(phba); if (lxri == NO_XRI) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6075 Failed to allocate xri for " "nvme buffer\n"); rc = -ENOMEM; @@ -4070,8 +4466,8 @@ out_free_mem: /** * lpfc_new_io_buf - IO buffer allocator for HBA with SLI4 IF spec - * @vport: The virtual port for which this call being executed. - * @num_to_allocate: The requested number of buffers to allocate. + * @phba: Pointer to lpfc hba data structure. + * @num_to_alloc: The requested number of buffers to allocate. * * This routine allocates nvme buffers for device with SLI-4 interface spec, * the nvme buffer contains all the necessary information needed to initiate @@ -4121,7 +4517,8 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) if ((phba->sli3_options & LPFC_SLI3_BG_ENABLED) && (((unsigned long)(lpfc_ncmd->data) & (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "3369 Memory alignment err: " "addr=%lx\n", (unsigned long)lpfc_ncmd->data); @@ -4150,7 +4547,7 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) dma_pool_free(phba->lpfc_sg_dma_buf_pool, lpfc_ncmd->data, lpfc_ncmd->dma_handle); kfree(lpfc_ncmd); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6121 Failed to allocate IOTAG for" " XRI:0x%x\n", lxri); lpfc_sli4_free_xri(phba, lxri); @@ -4158,12 +4555,11 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) } pwqeq->sli4_lxritag = lxri; pwqeq->sli4_xritag = phba->sli4_hba.xri_ids[lxri]; - pwqeq->context1 = lpfc_ncmd; /* Initialize local short-hand pointers. */ lpfc_ncmd->dma_sgl = lpfc_ncmd->data; lpfc_ncmd->dma_phys_sgl = lpfc_ncmd->dma_handle; - lpfc_ncmd->cur_iocbq.context1 = lpfc_ncmd; + lpfc_ncmd->cur_iocbq.io_buf = lpfc_ncmd; spin_lock_init(&lpfc_ncmd->buf_lock); /* add the nvme buffer to a post list */ @@ -4172,7 +4568,9 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) } lpfc_printf_log(phba, KERN_INFO, LOG_NVME, "6114 Allocate %d out of %d requested new NVME " - "buffers\n", bcnt, num_to_alloc); + "buffers of size x%zu bytes\n", bcnt, num_to_alloc, + sizeof(*lpfc_ncmd)); + /* post the list of nvme buffer sgls to port if available */ if (!list_empty(&post_nblist)) @@ -4201,7 +4599,7 @@ lpfc_get_wwpn(struct lpfc_hba *phba) lpfc_read_nv(phba, mboxq); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6019 Mailbox failed , mbxCmd x%x " "READ_NV, mbxStatus x%x\n", bf_get(lpfc_mqe_command, &mboxq->u.mqe), @@ -4219,6 +4617,66 @@ lpfc_get_wwpn(struct lpfc_hba *phba) return rol64(wwn, 32); } +static unsigned short lpfc_get_sg_tablesize(struct lpfc_hba *phba) +{ + if (phba->sli_rev == LPFC_SLI_REV4) + if (phba->cfg_xpsgl && !phba->nvmet_support) + return LPFC_MAX_SG_TABLESIZE; + else + return phba->cfg_scsi_seg_cnt; + else + return phba->cfg_sg_seg_cnt; +} + +/** + * lpfc_vmid_res_alloc - Allocates resources for VMID + * @phba: pointer to lpfc hba data structure. + * @vport: pointer to vport data structure + * + * This routine allocated the resources needed for the VMID. + * + * Return codes + * 0 on Success + * Non-0 on Failure + */ +static int +lpfc_vmid_res_alloc(struct lpfc_hba *phba, struct lpfc_vport *vport) +{ + /* VMID feature is supported only on SLI4 */ + if (phba->sli_rev == LPFC_SLI_REV3) { + phba->cfg_vmid_app_header = 0; + phba->cfg_vmid_priority_tagging = 0; + } + + if (lpfc_is_vmid_enabled(phba)) { + vport->vmid = + kcalloc(phba->cfg_max_vmid, sizeof(struct lpfc_vmid), + GFP_KERNEL); + if (!vport->vmid) + return -ENOMEM; + + rwlock_init(&vport->vmid_lock); + + /* Set the VMID parameters for the vport */ + vport->vmid_priority_tagging = phba->cfg_vmid_priority_tagging; + vport->vmid_inactivity_timeout = + phba->cfg_vmid_inactivity_timeout; + vport->max_vmid = phba->cfg_max_vmid; + vport->cur_vmid_cnt = 0; + + vport->vmid_priority_range = bitmap_zalloc + (LPFC_VMID_MAX_PRIORITY_RANGE, GFP_KERNEL); + + if (!vport->vmid_priority_range) { + kfree(vport->vmid); + return -ENOMEM; + } + + hash_init(vport->hash_table); + } + return 0; +} + /** * lpfc_create_port - Create an FC port * @phba: pointer to lpfc hba data structure. @@ -4240,6 +4698,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) { struct lpfc_vport *vport; struct Scsi_Host *shost = NULL; + struct scsi_host_template *template; int error = 0; int i; uint64_t wwn; @@ -4260,7 +4719,8 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) for (i = 0; i < lpfc_no_hba_reset_cnt; i++) { if (wwn == lpfc_no_hba_reset[i]) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6020 Setting use_no_reset port=%llx\n", wwn); use_no_reset_hba = true; @@ -4268,22 +4728,31 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) } } - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) { - if (dev != &phba->pcidev->dev) { - shost = scsi_host_alloc(&lpfc_vport_template, - sizeof(struct lpfc_vport)); + /* Seed template for SCSI host registration */ + if (dev == &phba->pcidev->dev) { + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) { + /* Seed physical port template */ + template = &lpfc_template; + + if (use_no_reset_hba) + /* template is for a no reset SCSI Host */ + template->eh_host_reset_handler = NULL; + + /* Seed updated value of sg_tablesize */ + template->sg_tablesize = lpfc_get_sg_tablesize(phba); } else { - if (!use_no_reset_hba) - shost = scsi_host_alloc(&lpfc_template, - sizeof(struct lpfc_vport)); - else - shost = scsi_host_alloc(&lpfc_template_no_hr, - sizeof(struct lpfc_vport)); + /* NVMET is for physical port only */ + template = &lpfc_template_nvme; } - } else if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - shost = scsi_host_alloc(&lpfc_template_nvme, - sizeof(struct lpfc_vport)); + } else { + /* Seed vport template */ + template = &lpfc_vport_template; + + /* Seed updated value of sg_tablesize */ + template->sg_tablesize = lpfc_get_sg_tablesize(phba); } + + shost = scsi_host_alloc(template, sizeof(struct lpfc_vport)); if (!shost) goto out; @@ -4313,11 +4782,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) shost->dma_boundary = phba->sli4_hba.pc_sli4_params.sge_supp_len-1; - - if (phba->cfg_xpsgl && !phba->nvmet_support) - shost->sg_tablesize = LPFC_MAX_SG_TABLESIZE; - else - shost->sg_tablesize = phba->cfg_scsi_seg_cnt; } else /* SLI-3 has a limited number of hardware queues (3), * thus there is only one for FCP processing. @@ -4338,6 +4802,18 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) vport->port_type = LPFC_PHYSICAL_PORT; } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP, + "9081 CreatePort TMPLATE type %x TBLsize %d " + "SEGcnt %d/%d\n", + vport->port_type, shost->sg_tablesize, + phba->cfg_scsi_seg_cnt, phba->cfg_sg_seg_cnt); + + /* Allocate the resources for VMID */ + rc = lpfc_vmid_res_alloc(phba, vport); + + if (rc) + goto out_put_shost; + /* Initialize all internally managed lists. */ INIT_LIST_HEAD(&vport->fc_nodes); INIT_LIST_HEAD(&vport->rcv_buffer_list); @@ -4354,13 +4830,16 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); if (error) - goto out_put_shost; + goto out_free_vmid; spin_lock_irq(&phba->port_list_lock); list_add_tail(&vport->listentry, &phba->port_list); spin_unlock_irq(&phba->port_list_lock); return vport; +out_free_vmid: + kfree(vport->vmid); + bitmap_free(vport->vmid_priority_range); out_put_shost: scsi_host_put(shost); out: @@ -4476,6 +4955,15 @@ static void lpfc_host_supported_speeds_set(struct Scsi_Host *shost) struct lpfc_hba *phba = vport->phba; fc_host_supported_speeds(shost) = 0; + /* + * Avoid reporting supported link speed for FCoE as it can't be + * controlled via FCoE. + */ + if (phba->hba_flag & HBA_FCOE_MODE) + return; + + if (phba->lmt & LMT_256Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_256GBIT; if (phba->lmt & LMT_128Gb) fc_host_supported_speeds(shost) |= FC_PORTSPEED_128GBIT; if (phba->lmt & LMT_64Gb) @@ -4623,7 +5111,7 @@ lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *phba) /** * lpfc_sli4_fcf_redisc_wait_tmo - FCF table rediscover wait timeout - * @ptr: Map to lpfc_hba data structure pointer. + * @t: Timer context used to obtain the pointer to lpfc hba data structure. * * This routine is invoked when waiting for FCF table rediscover has been * timed out. If new FCF record(s) has (have) been discovered during the @@ -4654,6 +5142,42 @@ lpfc_sli4_fcf_redisc_wait_tmo(struct timer_list *t) } /** + * lpfc_vmid_poll - VMID timeout detection + * @t: Timer context used to obtain the pointer to lpfc hba data structure. + * + * This routine is invoked when there is no I/O on by a VM for the specified + * amount of time. When this situation is detected, the VMID has to be + * deregistered from the switch and all the local resources freed. The VMID + * will be reassigned to the VM once the I/O begins. + **/ +static void +lpfc_vmid_poll(struct timer_list *t) +{ + struct lpfc_hba *phba = from_timer(phba, t, inactive_vmid_poll); + u32 wake_up = 0; + + /* check if there is a need to issue QFPA */ + if (phba->pport->vmid_priority_tagging) { + wake_up = 1; + phba->pport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA; + } + + /* Is the vmid inactivity timer enabled */ + if (phba->pport->vmid_inactivity_timeout || + phba->pport->load_flag & FC_DEREGISTER_ALL_APP_ID) { + wake_up = 1; + phba->pport->work_port_events |= WORKER_CHECK_INACTIVE_VMID; + } + + if (wake_up) + lpfc_worker_wake_up(phba); + + /* restart the timer for the next iteration */ + mod_timer(&phba->inactive_vmid_poll, jiffies + msecs_to_jiffies(1000 * + LPFC_VMID_TIMER)); +} + +/** * lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code * @phba: pointer to lpfc hba data structure. * @acqe_link: pointer to the async link completion queue entry. @@ -4671,7 +5195,7 @@ lpfc_sli4_parse_latt_fault(struct lpfc_hba *phba, case LPFC_ASYNC_LINK_FAULT_LR_LRR: break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0398 Unknown link fault code: x%x\n", bf_get(lpfc_acqe_link_fault, acqe_link)); break; @@ -4707,7 +5231,7 @@ lpfc_sli4_parse_latt_type(struct lpfc_hba *phba, att_type = LPFC_ATT_LINK_UP; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0399 Invalid link attention type: x%x\n", bf_get(lpfc_acqe_link_status, acqe_link)); att_type = LPFC_ATT_RESERVED; @@ -4809,6 +5333,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code, case LPFC_ASYNC_LINK_SPEED_40GBPS: port_speed = 40000; break; + case LPFC_ASYNC_LINK_SPEED_100GBPS: + port_speed = 100000; + break; default: port_speed = 0; } @@ -4845,6 +5372,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code, case LPFC_FC_LA_SPEED_128G: port_speed = 128000; break; + case LPFC_FC_LA_SPEED_256G: + port_speed = 256000; + break; default: port_speed = 0; } @@ -4866,7 +5396,6 @@ static void lpfc_sli4_async_link_evt(struct lpfc_hba *phba, struct lpfc_acqe_link *acqe_link) { - struct lpfc_dmabuf *mp; LPFC_MBOXQ_t *pmb; MAILBOX_t *mb; struct lpfc_mbx_read_top *la; @@ -4879,22 +5408,17 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, phba->fcoe_eventtag = acqe_link->event_tag; pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0395 The mboxq allocation failed\n"); return; } - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0396 The lpfc_dmabuf allocation failed\n"); + + rc = lpfc_mbox_rsrc_prep(phba, pmb); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0396 mailbox allocation failed\n"); goto out_free_pmb; } - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp->virt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0397 The mbuf allocation failed\n"); - goto out_free_dmabuf; - } /* Cleanup any outstanding ELS commands */ lpfc_els_flush_all_cmd(phba); @@ -4906,7 +5430,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, phba->sli.slistat.link_event++; /* Create lpfc_handle_latt mailbox command from link ACQE */ - lpfc_read_topology(phba, pmb, mp); + lpfc_read_topology(phba, pmb, (struct lpfc_dmabuf *)pmb->ctx_buf); pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology; pmb->vport = phba->pport; @@ -4945,7 +5469,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, if (!(phba->hba_flag & HBA_FCOE_MODE)) { rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) - goto out_free_dmabuf; + goto out_free_pmb; return; } /* @@ -4980,17 +5504,14 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, return; -out_free_dmabuf: - kfree(mp); out_free_pmb: - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); } /** * lpfc_async_link_speed_to_read_top - Parse async evt link speed code to read * topology. * @phba: pointer to lpfc hba data structure. - * @evt_code: asynchronous event code. * @speed_code: asynchronous event link speed code. * * This routine is to parse the giving SLI4 async event link speed code into @@ -5039,6 +5560,620 @@ lpfc_async_link_speed_to_read_top(struct lpfc_hba *phba, uint8_t speed_code) return port_speed; } +void +lpfc_cgn_dump_rxmonitor(struct lpfc_hba *phba) +{ + if (!phba->rx_monitor) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "4411 Rx Monitor Info is empty.\n"); + } else { + lpfc_rx_monitor_report(phba, phba->rx_monitor, NULL, 0, + LPFC_MAX_RXMONITOR_DUMP); + } +} + +/** + * lpfc_cgn_update_stat - Save data into congestion stats buffer + * @phba: pointer to lpfc hba data structure. + * @dtag: FPIN descriptor received + * + * Increment the FPIN received counter/time when it happens. + */ +void +lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag) +{ + struct lpfc_cgn_info *cp; + struct tm broken; + struct timespec64 cur_time; + u32 cnt; + u32 value; + + /* Make sure we have a congestion info buffer */ + if (!phba->cgn_i) + return; + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + ktime_get_real_ts64(&cur_time); + time64_to_tm(cur_time.tv_sec, 0, &broken); + + /* Update congestion statistics */ + switch (dtag) { + case ELS_DTAG_LNK_INTEGRITY: + cnt = le32_to_cpu(cp->link_integ_notification); + cnt++; + cp->link_integ_notification = cpu_to_le32(cnt); + + cp->cgn_stat_lnk_month = broken.tm_mon + 1; + cp->cgn_stat_lnk_day = broken.tm_mday; + cp->cgn_stat_lnk_year = broken.tm_year - 100; + cp->cgn_stat_lnk_hour = broken.tm_hour; + cp->cgn_stat_lnk_min = broken.tm_min; + cp->cgn_stat_lnk_sec = broken.tm_sec; + break; + case ELS_DTAG_DELIVERY: + cnt = le32_to_cpu(cp->delivery_notification); + cnt++; + cp->delivery_notification = cpu_to_le32(cnt); + + cp->cgn_stat_del_month = broken.tm_mon + 1; + cp->cgn_stat_del_day = broken.tm_mday; + cp->cgn_stat_del_year = broken.tm_year - 100; + cp->cgn_stat_del_hour = broken.tm_hour; + cp->cgn_stat_del_min = broken.tm_min; + cp->cgn_stat_del_sec = broken.tm_sec; + break; + case ELS_DTAG_PEER_CONGEST: + cnt = le32_to_cpu(cp->cgn_peer_notification); + cnt++; + cp->cgn_peer_notification = cpu_to_le32(cnt); + + cp->cgn_stat_peer_month = broken.tm_mon + 1; + cp->cgn_stat_peer_day = broken.tm_mday; + cp->cgn_stat_peer_year = broken.tm_year - 100; + cp->cgn_stat_peer_hour = broken.tm_hour; + cp->cgn_stat_peer_min = broken.tm_min; + cp->cgn_stat_peer_sec = broken.tm_sec; + break; + case ELS_DTAG_CONGESTION: + cnt = le32_to_cpu(cp->cgn_notification); + cnt++; + cp->cgn_notification = cpu_to_le32(cnt); + + cp->cgn_stat_cgn_month = broken.tm_mon + 1; + cp->cgn_stat_cgn_day = broken.tm_mday; + cp->cgn_stat_cgn_year = broken.tm_year - 100; + cp->cgn_stat_cgn_hour = broken.tm_hour; + cp->cgn_stat_cgn_min = broken.tm_min; + cp->cgn_stat_cgn_sec = broken.tm_sec; + } + if (phba->cgn_fpin_frequency && + phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) { + value = LPFC_CGN_TIMER_TO_MIN / phba->cgn_fpin_frequency; + cp->cgn_stat_npm = value; + } + value = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, + LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(value); +} + +/** + * lpfc_cgn_save_evt_cnt - Save data into registered congestion buffer + * @phba: pointer to lpfc hba data structure. + * + * Save the congestion event data every minute. + * On the hour collapse all the minute data into hour data. Every day + * collapse all the hour data into daily data. Separate driver + * and fabrc congestion event counters that will be saved out + * to the registered congestion buffer every minute. + */ +static void +lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba) +{ + struct lpfc_cgn_info *cp; + struct tm broken; + struct timespec64 cur_time; + uint32_t i, index; + uint16_t value, mvalue; + uint64_t bps; + uint32_t mbps; + uint32_t dvalue, wvalue, lvalue, avalue; + uint64_t latsum; + __le16 *ptr; + __le32 *lptr; + __le16 *mptr; + + /* Make sure we have a congestion info buffer */ + if (!phba->cgn_i) + return; + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + + if (time_before(jiffies, phba->cgn_evt_timestamp)) + return; + phba->cgn_evt_timestamp = jiffies + + msecs_to_jiffies(LPFC_CGN_TIMER_TO_MIN); + phba->cgn_evt_minute++; + + /* We should get to this point in the routine on 1 minute intervals */ + + ktime_get_real_ts64(&cur_time); + time64_to_tm(cur_time.tv_sec, 0, &broken); + + if (phba->cgn_fpin_frequency && + phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) { + value = LPFC_CGN_TIMER_TO_MIN / phba->cgn_fpin_frequency; + cp->cgn_stat_npm = value; + } + + /* Read and clear the latency counters for this minute */ + lvalue = atomic_read(&phba->cgn_latency_evt_cnt); + latsum = atomic64_read(&phba->cgn_latency_evt); + atomic_set(&phba->cgn_latency_evt_cnt, 0); + atomic64_set(&phba->cgn_latency_evt, 0); + + /* We need to store MB/sec bandwidth in the congestion information. + * block_cnt is count of 512 byte blocks for the entire minute, + * bps will get bytes per sec before finally converting to MB/sec. + */ + bps = div_u64(phba->rx_block_cnt, LPFC_SEC_MIN) * 512; + phba->rx_block_cnt = 0; + mvalue = bps / (1024 * 1024); /* convert to MB/sec */ + + /* Every minute */ + /* cgn parameters */ + cp->cgn_info_mode = phba->cgn_p.cgn_param_mode; + cp->cgn_info_level0 = phba->cgn_p.cgn_param_level0; + cp->cgn_info_level1 = phba->cgn_p.cgn_param_level1; + cp->cgn_info_level2 = phba->cgn_p.cgn_param_level2; + + /* Fill in default LUN qdepth */ + value = (uint16_t)(phba->pport->cfg_lun_queue_depth); + cp->cgn_lunq = cpu_to_le16(value); + + /* Record congestion buffer info - every minute + * cgn_driver_evt_cnt (Driver events) + * cgn_fabric_warn_cnt (Congestion Warnings) + * cgn_latency_evt_cnt / cgn_latency_evt (IO Latency) + * cgn_fabric_alarm_cnt (Congestion Alarms) + */ + index = ++cp->cgn_index_minute; + if (cp->cgn_index_minute == LPFC_MIN_HOUR) { + cp->cgn_index_minute = 0; + index = 0; + } + + /* Get the number of driver events in this sample and reset counter */ + dvalue = atomic_read(&phba->cgn_driver_evt_cnt); + atomic_set(&phba->cgn_driver_evt_cnt, 0); + + /* Get the number of warning events - FPIN and Signal for this minute */ + wvalue = 0; + if ((phba->cgn_reg_fpin & LPFC_CGN_FPIN_WARN) || + phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY || + phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) + wvalue = atomic_read(&phba->cgn_fabric_warn_cnt); + atomic_set(&phba->cgn_fabric_warn_cnt, 0); + + /* Get the number of alarm events - FPIN and Signal for this minute */ + avalue = 0; + if ((phba->cgn_reg_fpin & LPFC_CGN_FPIN_ALARM) || + phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) + avalue = atomic_read(&phba->cgn_fabric_alarm_cnt); + atomic_set(&phba->cgn_fabric_alarm_cnt, 0); + + /* Collect the driver, warning, alarm and latency counts for this + * minute into the driver congestion buffer. + */ + ptr = &cp->cgn_drvr_min[index]; + value = (uint16_t)dvalue; + *ptr = cpu_to_le16(value); + + ptr = &cp->cgn_warn_min[index]; + value = (uint16_t)wvalue; + *ptr = cpu_to_le16(value); + + ptr = &cp->cgn_alarm_min[index]; + value = (uint16_t)avalue; + *ptr = cpu_to_le16(value); + + lptr = &cp->cgn_latency_min[index]; + if (lvalue) { + lvalue = (uint32_t)div_u64(latsum, lvalue); + *lptr = cpu_to_le32(lvalue); + } else { + *lptr = 0; + } + + /* Collect the bandwidth value into the driver's congesion buffer. */ + mptr = &cp->cgn_bw_min[index]; + *mptr = cpu_to_le16(mvalue); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "2418 Congestion Info - minute (%d): %d %d %d %d %d\n", + index, dvalue, wvalue, *lptr, mvalue, avalue); + + /* Every hour */ + if ((phba->cgn_evt_minute % LPFC_MIN_HOUR) == 0) { + /* Record congestion buffer info - every hour + * Collapse all minutes into an hour + */ + index = ++cp->cgn_index_hour; + if (cp->cgn_index_hour == LPFC_HOUR_DAY) { + cp->cgn_index_hour = 0; + index = 0; + } + + dvalue = 0; + wvalue = 0; + lvalue = 0; + avalue = 0; + mvalue = 0; + mbps = 0; + for (i = 0; i < LPFC_MIN_HOUR; i++) { + dvalue += le16_to_cpu(cp->cgn_drvr_min[i]); + wvalue += le16_to_cpu(cp->cgn_warn_min[i]); + lvalue += le32_to_cpu(cp->cgn_latency_min[i]); + mbps += le16_to_cpu(cp->cgn_bw_min[i]); + avalue += le16_to_cpu(cp->cgn_alarm_min[i]); + } + if (lvalue) /* Avg of latency averages */ + lvalue /= LPFC_MIN_HOUR; + if (mbps) /* Avg of Bandwidth averages */ + mvalue = mbps / LPFC_MIN_HOUR; + + lptr = &cp->cgn_drvr_hr[index]; + *lptr = cpu_to_le32(dvalue); + lptr = &cp->cgn_warn_hr[index]; + *lptr = cpu_to_le32(wvalue); + lptr = &cp->cgn_latency_hr[index]; + *lptr = cpu_to_le32(lvalue); + mptr = &cp->cgn_bw_hr[index]; + *mptr = cpu_to_le16(mvalue); + lptr = &cp->cgn_alarm_hr[index]; + *lptr = cpu_to_le32(avalue); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "2419 Congestion Info - hour " + "(%d): %d %d %d %d %d\n", + index, dvalue, wvalue, lvalue, mvalue, avalue); + } + + /* Every day */ + if ((phba->cgn_evt_minute % LPFC_MIN_DAY) == 0) { + /* Record congestion buffer info - every hour + * Collapse all hours into a day. Rotate days + * after LPFC_MAX_CGN_DAYS. + */ + index = ++cp->cgn_index_day; + if (cp->cgn_index_day == LPFC_MAX_CGN_DAYS) { + cp->cgn_index_day = 0; + index = 0; + } + + /* Anytime we overwrite daily index 0, after we wrap, + * we will be overwriting the oldest day, so we must + * update the congestion data start time for that day. + * That start time should have previously been saved after + * we wrote the last days worth of data. + */ + if ((phba->hba_flag & HBA_CGN_DAY_WRAP) && index == 0) { + time64_to_tm(phba->cgn_daily_ts.tv_sec, 0, &broken); + + cp->cgn_info_month = broken.tm_mon + 1; + cp->cgn_info_day = broken.tm_mday; + cp->cgn_info_year = broken.tm_year - 100; + cp->cgn_info_hour = broken.tm_hour; + cp->cgn_info_minute = broken.tm_min; + cp->cgn_info_second = broken.tm_sec; + + lpfc_printf_log + (phba, KERN_INFO, LOG_CGN_MGMT, + "2646 CGNInfo idx0 Start Time: " + "%d/%d/%d %d:%d:%d\n", + cp->cgn_info_day, cp->cgn_info_month, + cp->cgn_info_year, cp->cgn_info_hour, + cp->cgn_info_minute, cp->cgn_info_second); + } + + dvalue = 0; + wvalue = 0; + lvalue = 0; + mvalue = 0; + mbps = 0; + avalue = 0; + for (i = 0; i < LPFC_HOUR_DAY; i++) { + dvalue += le32_to_cpu(cp->cgn_drvr_hr[i]); + wvalue += le32_to_cpu(cp->cgn_warn_hr[i]); + lvalue += le32_to_cpu(cp->cgn_latency_hr[i]); + mbps += le16_to_cpu(cp->cgn_bw_hr[i]); + avalue += le32_to_cpu(cp->cgn_alarm_hr[i]); + } + if (lvalue) /* Avg of latency averages */ + lvalue /= LPFC_HOUR_DAY; + if (mbps) /* Avg of Bandwidth averages */ + mvalue = mbps / LPFC_HOUR_DAY; + + lptr = &cp->cgn_drvr_day[index]; + *lptr = cpu_to_le32(dvalue); + lptr = &cp->cgn_warn_day[index]; + *lptr = cpu_to_le32(wvalue); + lptr = &cp->cgn_latency_day[index]; + *lptr = cpu_to_le32(lvalue); + mptr = &cp->cgn_bw_day[index]; + *mptr = cpu_to_le16(mvalue); + lptr = &cp->cgn_alarm_day[index]; + *lptr = cpu_to_le32(avalue); + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "2420 Congestion Info - daily (%d): " + "%d %d %d %d %d\n", + index, dvalue, wvalue, lvalue, mvalue, avalue); + + /* We just wrote LPFC_MAX_CGN_DAYS of data, + * so we are wrapped on any data after this. + * Save this as the start time for the next day. + */ + if (index == (LPFC_MAX_CGN_DAYS - 1)) { + phba->hba_flag |= HBA_CGN_DAY_WRAP; + ktime_get_real_ts64(&phba->cgn_daily_ts); + } + } + + /* Use the frequency found in the last rcv'ed FPIN */ + value = phba->cgn_fpin_frequency; + cp->cgn_warn_freq = cpu_to_le16(value); + cp->cgn_alarm_freq = cpu_to_le16(value); + + lvalue = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, + LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(lvalue); +} + +/** + * lpfc_calc_cmf_latency - latency from start of rxate timer interval + * @phba: The Hba for which this call is being executed. + * + * The routine calculates the latency from the beginning of the CMF timer + * interval to the current point in time. It is called from IO completion + * when we exceed our Bandwidth limitation for the time interval. + */ +uint32_t +lpfc_calc_cmf_latency(struct lpfc_hba *phba) +{ + struct timespec64 cmpl_time; + uint32_t msec = 0; + + ktime_get_real_ts64(&cmpl_time); + + /* This routine works on a ms granularity so sec and usec are + * converted accordingly. + */ + if (cmpl_time.tv_sec == phba->cmf_latency.tv_sec) { + msec = (cmpl_time.tv_nsec - phba->cmf_latency.tv_nsec) / + NSEC_PER_MSEC; + } else { + if (cmpl_time.tv_nsec >= phba->cmf_latency.tv_nsec) { + msec = (cmpl_time.tv_sec - + phba->cmf_latency.tv_sec) * MSEC_PER_SEC; + msec += ((cmpl_time.tv_nsec - + phba->cmf_latency.tv_nsec) / NSEC_PER_MSEC); + } else { + msec = (cmpl_time.tv_sec - phba->cmf_latency.tv_sec - + 1) * MSEC_PER_SEC; + msec += (((NSEC_PER_SEC - phba->cmf_latency.tv_nsec) + + cmpl_time.tv_nsec) / NSEC_PER_MSEC); + } + } + return msec; +} + +/** + * lpfc_cmf_timer - This is the timer function for one congestion + * rate interval. + * @timer: Pointer to the high resolution timer that expired + */ +static enum hrtimer_restart +lpfc_cmf_timer(struct hrtimer *timer) +{ + struct lpfc_hba *phba = container_of(timer, struct lpfc_hba, + cmf_timer); + struct rx_info_entry entry; + uint32_t io_cnt; + uint32_t busy, max_read; + uint64_t total, rcv, lat, mbpi, extra, cnt; + int timer_interval = LPFC_CMF_INTERVAL; + uint32_t ms; + struct lpfc_cgn_stat *cgs; + int cpu; + + /* Only restart the timer if congestion mgmt is on */ + if (phba->cmf_active_mode == LPFC_CFG_OFF || + !phba->cmf_latency.tv_sec) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6224 CMF timer exit: %d %lld\n", + phba->cmf_active_mode, + (uint64_t)phba->cmf_latency.tv_sec); + return HRTIMER_NORESTART; + } + + /* If pport is not ready yet, just exit and wait for + * the next timer cycle to hit. + */ + if (!phba->pport) + goto skip; + + /* Do not block SCSI IO while in the timer routine since + * total_bytes will be cleared + */ + atomic_set(&phba->cmf_stop_io, 1); + + /* First we need to calculate the actual ms between + * the last timer interrupt and this one. We ask for + * LPFC_CMF_INTERVAL, however the actual time may + * vary depending on system overhead. + */ + ms = lpfc_calc_cmf_latency(phba); + + + /* Immediately after we calculate the time since the last + * timer interrupt, set the start time for the next + * interrupt + */ + ktime_get_real_ts64(&phba->cmf_latency); + + phba->cmf_link_byte_count = + div_u64(phba->cmf_max_line_rate * LPFC_CMF_INTERVAL, 1000); + + /* Collect all the stats from the prior timer interval */ + total = 0; + io_cnt = 0; + lat = 0; + rcv = 0; + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + total += atomic64_xchg(&cgs->total_bytes, 0); + io_cnt += atomic_xchg(&cgs->rx_io_cnt, 0); + lat += atomic64_xchg(&cgs->rx_latency, 0); + rcv += atomic64_xchg(&cgs->rcv_bytes, 0); + } + + /* Before we issue another CMF_SYNC_WQE, retrieve the BW + * returned from the last CMF_SYNC_WQE issued, from + * cmf_last_sync_bw. This will be the target BW for + * this next timer interval. + */ + if (phba->cmf_active_mode == LPFC_CFG_MANAGED && + phba->link_state != LPFC_LINK_DOWN && + phba->hba_flag & HBA_SETUP) { + mbpi = phba->cmf_last_sync_bw; + phba->cmf_last_sync_bw = 0; + extra = 0; + + /* Calculate any extra bytes needed to account for the + * timer accuracy. If we are less than LPFC_CMF_INTERVAL + * calculate the adjustment needed for total to reflect + * a full LPFC_CMF_INTERVAL. + */ + if (ms && ms < LPFC_CMF_INTERVAL) { + cnt = div_u64(total, ms); /* bytes per ms */ + cnt *= LPFC_CMF_INTERVAL; /* what total should be */ + + /* If the timeout is scheduled to be shorter, + * this value may skew the data, so cap it at mbpi. + */ + if ((phba->hba_flag & HBA_SHORT_CMF) && cnt > mbpi) + cnt = mbpi; + + extra = cnt - total; + } + lpfc_issue_cmf_sync_wqe(phba, LPFC_CMF_INTERVAL, total + extra); + } else { + /* For Monitor mode or link down we want mbpi + * to be the full link speed + */ + mbpi = phba->cmf_link_byte_count; + extra = 0; + } + phba->cmf_timer_cnt++; + + if (io_cnt) { + /* Update congestion info buffer latency in us */ + atomic_add(io_cnt, &phba->cgn_latency_evt_cnt); + atomic64_add(lat, &phba->cgn_latency_evt); + } + busy = atomic_xchg(&phba->cmf_busy, 0); + max_read = atomic_xchg(&phba->rx_max_read_cnt, 0); + + /* Calculate MBPI for the next timer interval */ + if (mbpi) { + if (mbpi > phba->cmf_link_byte_count || + phba->cmf_active_mode == LPFC_CFG_MONITOR) + mbpi = phba->cmf_link_byte_count; + + /* Change max_bytes_per_interval to what the prior + * CMF_SYNC_WQE cmpl indicated. + */ + if (mbpi != phba->cmf_max_bytes_per_interval) + phba->cmf_max_bytes_per_interval = mbpi; + } + + /* Save rxmonitor information for debug */ + if (phba->rx_monitor) { + entry.total_bytes = total; + entry.cmf_bytes = total + extra; + entry.rcv_bytes = rcv; + entry.cmf_busy = busy; + entry.cmf_info = phba->cmf_active_info; + if (io_cnt) { + entry.avg_io_latency = div_u64(lat, io_cnt); + entry.avg_io_size = div_u64(rcv, io_cnt); + } else { + entry.avg_io_latency = 0; + entry.avg_io_size = 0; + } + entry.max_read_cnt = max_read; + entry.io_cnt = io_cnt; + entry.max_bytes_per_interval = mbpi; + if (phba->cmf_active_mode == LPFC_CFG_MANAGED) + entry.timer_utilization = phba->cmf_last_ts; + else + entry.timer_utilization = ms; + entry.timer_interval = ms; + phba->cmf_last_ts = 0; + + lpfc_rx_monitor_record(phba->rx_monitor, &entry); + } + + if (phba->cmf_active_mode == LPFC_CFG_MONITOR) { + /* If Monitor mode, check if we are oversubscribed + * against the full line rate. + */ + if (mbpi && total > mbpi) + atomic_inc(&phba->cgn_driver_evt_cnt); + } + phba->rx_block_cnt += div_u64(rcv, 512); /* save 512 byte block cnt */ + + /* Each minute save Fabric and Driver congestion information */ + lpfc_cgn_save_evt_cnt(phba); + + phba->hba_flag &= ~HBA_SHORT_CMF; + + /* Since we need to call lpfc_cgn_save_evt_cnt every minute, on the + * minute, adjust our next timer interval, if needed, to ensure a + * 1 minute granularity when we get the next timer interrupt. + */ + if (time_after(jiffies + msecs_to_jiffies(LPFC_CMF_INTERVAL), + phba->cgn_evt_timestamp)) { + timer_interval = jiffies_to_msecs(phba->cgn_evt_timestamp - + jiffies); + if (timer_interval <= 0) + timer_interval = LPFC_CMF_INTERVAL; + else + phba->hba_flag |= HBA_SHORT_CMF; + + /* If we adjust timer_interval, max_bytes_per_interval + * needs to be adjusted as well. + */ + phba->cmf_link_byte_count = div_u64(phba->cmf_max_line_rate * + timer_interval, 1000); + if (phba->cmf_active_mode == LPFC_CFG_MONITOR) + phba->cmf_max_bytes_per_interval = + phba->cmf_link_byte_count; + } + + /* Since total_bytes has already been zero'ed, its okay to unblock + * after max_bytes_per_interval is setup. + */ + if (atomic_xchg(&phba->cmf_bw_wait, 0)) + queue_work(phba->wq, &phba->unblock_request_work); + + /* SCSI IO is now unblocked */ + atomic_set(&phba->cmf_stop_io, 0); + +skip: + hrtimer_forward_now(timer, + ktime_set(0, timer_interval * NSEC_PER_MSEC)); + return HRTIMER_RESTART; +} + #define trunk_link_status(__idx)\ bf_get(lpfc_acqe_fc_la_trunk_config_port##__idx, acqe_fc) ?\ ((phba->trunk_link.link##__idx.state == LPFC_LINK_UP) ?\ @@ -5054,6 +6189,7 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba, { uint8_t port_fault = bf_get(lpfc_acqe_fc_la_trunk_linkmask, acqe_fc); uint8_t err = bf_get(lpfc_acqe_fc_la_trunk_fault, acqe_fc); + u8 cnt = 0; phba->sli4_hba.link_state.speed = lpfc_sli4_port_speed_parse(phba, LPFC_TRAILER_CODE_FC, @@ -5072,27 +6208,37 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba, bf_get(lpfc_acqe_fc_la_trunk_link_status_port0, acqe_fc) ? LPFC_LINK_UP : LPFC_LINK_DOWN; phba->trunk_link.link0.fault = port_fault & 0x1 ? err : 0; + cnt++; } if (bf_get(lpfc_acqe_fc_la_trunk_config_port1, acqe_fc)) { phba->trunk_link.link1.state = bf_get(lpfc_acqe_fc_la_trunk_link_status_port1, acqe_fc) ? LPFC_LINK_UP : LPFC_LINK_DOWN; phba->trunk_link.link1.fault = port_fault & 0x2 ? err : 0; + cnt++; } if (bf_get(lpfc_acqe_fc_la_trunk_config_port2, acqe_fc)) { phba->trunk_link.link2.state = bf_get(lpfc_acqe_fc_la_trunk_link_status_port2, acqe_fc) ? LPFC_LINK_UP : LPFC_LINK_DOWN; phba->trunk_link.link2.fault = port_fault & 0x4 ? err : 0; + cnt++; } if (bf_get(lpfc_acqe_fc_la_trunk_config_port3, acqe_fc)) { phba->trunk_link.link3.state = bf_get(lpfc_acqe_fc_la_trunk_link_status_port3, acqe_fc) ? LPFC_LINK_UP : LPFC_LINK_DOWN; phba->trunk_link.link3.fault = port_fault & 0x8 ? err : 0; + cnt++; } - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + if (cnt) + phba->trunk_link.phy_lnk_speed = + phba->sli4_hba.link_state.logical_speed / (cnt * 1000); + else + phba->trunk_link.phy_lnk_speed = LPFC_LINK_SPEED_UNKNOWN; + + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2910 Async FC Trunking Event - Speed:%d\n" "\tLogical speed:%d " "port0: %s port1: %s port2: %s port3: %s\n", @@ -5101,8 +6247,11 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba, trunk_link_status(0), trunk_link_status(1), trunk_link_status(2), trunk_link_status(3)); + if (phba->cmf_active_mode != LPFC_CFG_OFF) + lpfc_cmf_signal_init(phba); + if (port_fault) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3202 trunk error:0x%x (%s) seen on port0:%s " /* * SLI-4: We have only 0xA error codes @@ -5128,7 +6277,6 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba, static void lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) { - struct lpfc_dmabuf *mp; LPFC_MBOXQ_t *pmb; MAILBOX_t *mb; struct lpfc_mbx_read_top *la; @@ -5136,7 +6284,7 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) if (bf_get(lpfc_trailer_type, acqe_fc) != LPFC_FC_LA_EVENT_TYPE_FC_LINK) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2895 Non FC link Event detected.(%d)\n", bf_get(lpfc_trailer_type, acqe_fc)); return; @@ -5167,7 +6315,7 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) if (bf_get(lpfc_acqe_fc_la_att_type, acqe_fc) == LPFC_FC_LA_TYPE_LINK_DOWN) phba->sli4_hba.link_state.logical_speed = 0; - else if (!phba->sli4_hba.conf_trunk) + else if (!phba->sli4_hba.conf_trunk) phba->sli4_hba.link_state.logical_speed = bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10; @@ -5184,22 +6332,16 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) phba->sli4_hba.link_state.fault); pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2897 The mboxq allocation failed\n"); return; } - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2898 The lpfc_dmabuf allocation failed\n"); + rc = lpfc_mbox_rsrc_prep(phba, pmb); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2898 The mboxq prep failed\n"); goto out_free_pmb; } - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp->virt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2899 The mbuf allocation failed\n"); - goto out_free_dmabuf; - } /* Cleanup any outstanding ELS commands */ lpfc_els_flush_all_cmd(phba); @@ -5211,7 +6353,7 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) phba->sli.slistat.link_event++; /* Create lpfc_handle_latt mailbox command from link ACQE */ - lpfc_read_topology(phba, pmb, mp); + lpfc_read_topology(phba, pmb, (struct lpfc_dmabuf *)pmb->ctx_buf); pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology; pmb->vport = phba->pport; @@ -5256,19 +6398,17 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) - goto out_free_dmabuf; + goto out_free_pmb; return; -out_free_dmabuf: - kfree(mp); out_free_pmb: - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); } /** * lpfc_sli4_async_sli_evt - Process the asynchronous SLI link event * @phba: pointer to lpfc hba data structure. - * @acqe_fc: pointer to the async SLI completion queue entry. + * @acqe_sli: pointer to the async SLI completion queue entry. * * This routine is to handle the SLI4 asynchronous SLI events. **/ @@ -5282,9 +6422,10 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) uint8_t operational = 0; struct temp_event temp_event_data; struct lpfc_acqe_misconfigured_event *misconfigured; + struct lpfc_acqe_cgn_signal *cgn_signal; struct Scsi_Host *shost; struct lpfc_vport **vports; - int rc, i; + int rc, i, cnt; evt_type = bf_get(lpfc_trailer_type, acqe_sli); @@ -5292,7 +6433,7 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) "2901 Async SLI event - Type:%d, Event Data: x%08x " "x%08x x%08x x%08x\n", evt_type, acqe_sli->event_data1, acqe_sli->event_data2, - acqe_sli->reserved, acqe_sli->trailer); + acqe_sli->event_data3, acqe_sli->trailer); port_name = phba->Port[0]; if (port_name == 0x00) @@ -5321,7 +6462,7 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) temp_event_data.event_code = LPFC_NORMAL_TEMP; temp_event_data.data = (uint32_t)acqe_sli->event_data1; - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + lpfc_printf_log(phba, KERN_INFO, LOG_SLI | LOG_LDS_EVENT, "3191 Normal Temperature:%d Celsius - Port Name %c\n", acqe_sli->event_data1, port_name); @@ -5363,7 +6504,7 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) &misconfigured->theEvent); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3296 " "LPFC_SLI_EVENT_TYPE_MISCONFIGURED " "event: Invalid link %d", @@ -5415,10 +6556,17 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) rc = lpfc_sli4_read_config(phba); if (rc) { phba->lmt = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "3194 Unable to retrieve supported " "speeds, rc = 0x%x\n", rc); } + rc = lpfc_sli4_refresh_params(phba); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3174 Unable to update pls support, " + "rc x%x\n", rc); + } vports = lpfc_create_vport_work_array(phba); if (vports != NULL) { for (i = 0; i <= phba->max_vports && vports[i] != NULL; @@ -5439,15 +6587,22 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) "Event Data1:x%08x Event Data2: x%08x\n", acqe_sli->event_data1, acqe_sli->event_data2); break; + case LPFC_SLI_EVENT_TYPE_PORT_PARAMS_CHG: + /* Call FW to obtain active parms */ + lpfc_sli4_cgn_parm_chg_evt(phba); + break; case LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN: /* Misconfigured WWN. Reports that the SLI Port is configured * to use FA-WWN, but the attached device doesn’t support it. - * No driver action is required. * Event Data1 - N.A, Event Data2 - N.A + * This event only happens on the physical port. */ - lpfc_log_msg(phba, KERN_WARNING, LOG_SLI, - "2699 Misconfigured FA-WWN - Attached device does " - "not support FA-WWN\n"); + lpfc_log_msg(phba, KERN_WARNING, LOG_SLI | LOG_DISCOVERY, + "2699 Misconfigured FA-PWWN - Attached device " + "does not support FA-PWWN\n"); + phba->sli4_hba.fawwpn_flag &= ~LPFC_FAWWPN_FABRIC; + memset(phba->pport->fc_portname.u.wwn, 0, + sizeof(struct lpfc_name)); break; case LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE: /* EEPROM failure. No driver action is required */ @@ -5456,6 +6611,44 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) "Event Data1: x%08x Event Data2: x%08x\n", acqe_sli->event_data1, acqe_sli->event_data2); break; + case LPFC_SLI_EVENT_TYPE_CGN_SIGNAL: + if (phba->cmf_active_mode == LPFC_CFG_OFF) + break; + cgn_signal = (struct lpfc_acqe_cgn_signal *) + &acqe_sli->event_data1; + phba->cgn_acqe_cnt++; + + cnt = bf_get(lpfc_warn_acqe, cgn_signal); + atomic64_add(cnt, &phba->cgn_acqe_stat.warn); + atomic64_add(cgn_signal->alarm_cnt, &phba->cgn_acqe_stat.alarm); + + /* no threshold for CMF, even 1 signal will trigger an event */ + + /* Alarm overrides warning, so check that first */ + if (cgn_signal->alarm_cnt) { + if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) { + /* Keep track of alarm cnt for CMF_SYNC_WQE */ + atomic_add(cgn_signal->alarm_cnt, + &phba->cgn_sync_alarm_cnt); + } + } else if (cnt) { + /* signal action needs to be taken */ + if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY || + phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) { + /* Keep track of warning cnt for CMF_SYNC_WQE */ + atomic_add(cnt, &phba->cgn_sync_warn_cnt); + } + } + break; + case LPFC_SLI_EVENT_TYPE_RD_SIGNAL: + /* May be accompanied by a temperature event */ + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI | LOG_LINK_EVENT | LOG_LDS_EVENT, + "2902 Remote Degrade Signaling: x%08x x%08x " + "x%08x\n", + acqe_sli->event_data1, acqe_sli->event_data2, + acqe_sli->event_data3); + break; default: lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3193 Unrecognized SLI event, type: 0x%x", @@ -5491,16 +6684,11 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) /* Cannot find existing Fabric ndlp, so allocate a new one */ ndlp = lpfc_nlp_init(vport, Fabric_DID); if (!ndlp) - return 0; + return NULL; /* Set the node type */ ndlp->nlp_type |= NLP_FABRIC; /* Put ndlp onto node list */ lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 0; } if ((phba->pport->port_state < LPFC_FLOGI) && (phba->pport->port_state != LPFC_VPORT_FAILED)) @@ -5523,7 +6711,7 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) /** * lpfc_sli4_perform_all_vport_cvl - Perform clear virtual link on all vports - * @vport: pointer to lpfc hba data structure. + * @phba: pointer to lpfc hba data structure. * * This routine is to perform Clear Virtual Link (CVL) on all vports in * response to a FCF dead event. @@ -5544,7 +6732,7 @@ lpfc_sli4_perform_all_vport_cvl(struct lpfc_hba *phba) /** * lpfc_sli4_async_fip_evt - Process the asynchronous FCoE FIP event * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async fcoe completion queue entry. + * @acqe_fip: pointer to the async fcoe completion queue entry. * * This routine is to handle the SLI4 asynchronous fcoe event. **/ @@ -5556,7 +6744,6 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, int rc; struct lpfc_vport *vport; struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; int active_vlink_present; struct lpfc_vport **vports; int i; @@ -5567,8 +6754,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, case LPFC_FIP_EVENT_TYPE_NEW_FCF: case LPFC_FIP_EVENT_TYPE_FCF_PARAM_MOD: if (event_type == LPFC_FIP_EVENT_TYPE_NEW_FCF) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2546 New FCF event, evt_tag:x%x, " "index:x%x\n", acqe_fip->event_tag, @@ -5621,23 +6807,24 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); if (rc) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2547 Issue FCF scan read FCF mailbox " "command failed (x%x)\n", rc); break; case LPFC_FIP_EVENT_TYPE_FCF_TABLE_FULL: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2548 FCF Table full count 0x%x tag 0x%x\n", - bf_get(lpfc_acqe_fip_fcf_count, acqe_fip), - acqe_fip->event_tag); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2548 FCF Table full count 0x%x tag 0x%x\n", + bf_get(lpfc_acqe_fip_fcf_count, acqe_fip), + acqe_fip->event_tag); break; case LPFC_FIP_EVENT_TYPE_FCF_DEAD: phba->fcoe_cvl_eventtag = acqe_fip->event_tag; - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, - "2549 FCF (x%x) disconnected from network, " - "tag:x%x\n", acqe_fip->index, acqe_fip->event_tag); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2549 FCF (x%x) disconnected from network, " + "tag:x%x\n", acqe_fip->index, + acqe_fip->event_tag); /* * If we are in the middle of FCF failover process, clear * the corresponding FCF bit in the roundrobin bitmap. @@ -5674,7 +6861,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, rc = lpfc_sli4_redisc_fcf_table(phba); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_FIP | - LOG_DISCOVERY, + LOG_TRACE_EVENT, "2772 Issue FCF rediscover mailbox " "command failed, fail through to FCF " "dead event\n"); @@ -5698,7 +6885,8 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, break; case LPFC_FIP_EVENT_TYPE_CVL: phba->fcoe_cvl_eventtag = acqe_fip->event_tag; - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "2718 Clear Virtual Link Received for VPI 0x%x" " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag); @@ -5736,10 +6924,9 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_FDISC; vport->port_state = LPFC_FDISC; } else { @@ -5765,7 +6952,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, rc = lpfc_sli4_redisc_fcf_table(phba); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_FIP | - LOG_DISCOVERY, + LOG_TRACE_EVENT, "2774 Issue FCF rediscover " "mailbox command failed, " "through to CVL event\n"); @@ -5786,9 +6973,9 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, } break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0288 Unknown FCoE event type 0x%x event tag " - "0x%x\n", event_type, acqe_fip->event_tag); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0288 Unknown FCoE event type 0x%x event tag " + "0x%x\n", event_type, acqe_fip->event_tag); break; } } @@ -5796,7 +6983,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, /** * lpfc_sli4_async_dcbx_evt - Process the asynchronous dcbx event * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async dcbx completion queue entry. + * @acqe_dcbx: pointer to the async dcbx completion queue entry. * * This routine is to handle the SLI4 asynchronous dcbx event. **/ @@ -5805,7 +6992,7 @@ lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba, struct lpfc_acqe_dcbx *acqe_dcbx) { phba->fc_eventTag = acqe_dcbx->event_tag; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0290 The SLI4 DCBX asynchronous event is not " "handled yet\n"); } @@ -5813,7 +7000,7 @@ lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba, /** * lpfc_sli4_async_grp5_evt - Process the asynchronous group5 event * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async grp5 completion queue entry. + * @acqe_grp5: pointer to the async grp5 completion queue entry. * * This routine is to handle the SLI4 asynchronous grp5 event. A grp5 event * is an asynchronous notified of a logical link speed change. The Port @@ -5837,6 +7024,292 @@ lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba, } /** + * lpfc_sli4_async_cmstat_evt - Process the asynchronous cmstat event + * @phba: pointer to lpfc hba data structure. + * + * This routine is to handle the SLI4 asynchronous cmstat event. A cmstat event + * is an asynchronous notification of a request to reset CM stats. + **/ +static void +lpfc_sli4_async_cmstat_evt(struct lpfc_hba *phba) +{ + if (!phba->cgn_i) + return; + lpfc_init_congestion_stat(phba); +} + +/** + * lpfc_cgn_params_val - Validate FW congestion parameters. + * @phba: pointer to lpfc hba data structure. + * @p_cfg_param: pointer to FW provided congestion parameters. + * + * This routine validates the congestion parameters passed + * by the FW to the driver via an ACQE event. + **/ +static void +lpfc_cgn_params_val(struct lpfc_hba *phba, struct lpfc_cgn_param *p_cfg_param) +{ + spin_lock_irq(&phba->hbalock); + + if (!lpfc_rangecheck(p_cfg_param->cgn_param_mode, LPFC_CFG_OFF, + LPFC_CFG_MONITOR)) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6225 CMF mode param out of range: %d\n", + p_cfg_param->cgn_param_mode); + p_cfg_param->cgn_param_mode = LPFC_CFG_OFF; + } + + spin_unlock_irq(&phba->hbalock); +} + +static const char * const lpfc_cmf_mode_to_str[] = { + "OFF", + "MANAGED", + "MONITOR", +}; + +/** + * lpfc_cgn_params_parse - Process a FW cong parm change event + * @phba: pointer to lpfc hba data structure. + * @p_cgn_param: pointer to a data buffer with the FW cong params. + * @len: the size of pdata in bytes. + * + * This routine validates the congestion management buffer signature + * from the FW, validates the contents and makes corrections for + * valid, in-range values. If the signature magic is correct and + * after parameter validation, the contents are copied to the driver's + * @phba structure. If the magic is incorrect, an error message is + * logged. + **/ +static void +lpfc_cgn_params_parse(struct lpfc_hba *phba, + struct lpfc_cgn_param *p_cgn_param, uint32_t len) +{ + struct lpfc_cgn_info *cp; + uint32_t crc, oldmode; + char acr_string[4] = {0}; + + /* Make sure the FW has encoded the correct magic number to + * validate the congestion parameter in FW memory. + */ + if (p_cgn_param->cgn_param_magic == LPFC_CFG_PARAM_MAGIC_NUM) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT, + "4668 FW cgn parm buffer data: " + "magic 0x%x version %d mode %d " + "level0 %d level1 %d " + "level2 %d byte13 %d " + "byte14 %d byte15 %d " + "byte11 %d byte12 %d activeMode %d\n", + p_cgn_param->cgn_param_magic, + p_cgn_param->cgn_param_version, + p_cgn_param->cgn_param_mode, + p_cgn_param->cgn_param_level0, + p_cgn_param->cgn_param_level1, + p_cgn_param->cgn_param_level2, + p_cgn_param->byte13, + p_cgn_param->byte14, + p_cgn_param->byte15, + p_cgn_param->byte11, + p_cgn_param->byte12, + phba->cmf_active_mode); + + oldmode = phba->cmf_active_mode; + + /* Any parameters out of range are corrected to defaults + * by this routine. No need to fail. + */ + lpfc_cgn_params_val(phba, p_cgn_param); + + /* Parameters are verified, move them into driver storage */ + spin_lock_irq(&phba->hbalock); + memcpy(&phba->cgn_p, p_cgn_param, + sizeof(struct lpfc_cgn_param)); + + /* Update parameters in congestion info buffer now */ + if (phba->cgn_i) { + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + cp->cgn_info_mode = phba->cgn_p.cgn_param_mode; + cp->cgn_info_level0 = phba->cgn_p.cgn_param_level0; + cp->cgn_info_level1 = phba->cgn_p.cgn_param_level1; + cp->cgn_info_level2 = phba->cgn_p.cgn_param_level2; + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, + LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); + } + spin_unlock_irq(&phba->hbalock); + + phba->cmf_active_mode = phba->cgn_p.cgn_param_mode; + + switch (oldmode) { + case LPFC_CFG_OFF: + if (phba->cgn_p.cgn_param_mode != LPFC_CFG_OFF) { + /* Turning CMF on */ + lpfc_cmf_start(phba); + + if (phba->link_state >= LPFC_LINK_UP) { + phba->cgn_reg_fpin = + phba->cgn_init_reg_fpin; + phba->cgn_reg_signal = + phba->cgn_init_reg_signal; + lpfc_issue_els_edc(phba->pport, 0); + } + } + break; + case LPFC_CFG_MANAGED: + switch (phba->cgn_p.cgn_param_mode) { + case LPFC_CFG_OFF: + /* Turning CMF off */ + lpfc_cmf_stop(phba); + if (phba->link_state >= LPFC_LINK_UP) + lpfc_issue_els_edc(phba->pport, 0); + break; + case LPFC_CFG_MONITOR: + phba->cmf_max_bytes_per_interval = + phba->cmf_link_byte_count; + + /* Resume blocked IO - unblock on workqueue */ + queue_work(phba->wq, + &phba->unblock_request_work); + break; + } + break; + case LPFC_CFG_MONITOR: + switch (phba->cgn_p.cgn_param_mode) { + case LPFC_CFG_OFF: + /* Turning CMF off */ + lpfc_cmf_stop(phba); + if (phba->link_state >= LPFC_LINK_UP) + lpfc_issue_els_edc(phba->pport, 0); + break; + case LPFC_CFG_MANAGED: + lpfc_cmf_signal_init(phba); + break; + } + break; + } + if (oldmode != LPFC_CFG_OFF || + oldmode != phba->cgn_p.cgn_param_mode) { + if (phba->cgn_p.cgn_param_mode == LPFC_CFG_MANAGED) + scnprintf(acr_string, sizeof(acr_string), "%u", + phba->cgn_p.cgn_param_level0); + else + scnprintf(acr_string, sizeof(acr_string), "NA"); + + dev_info(&phba->pcidev->dev, "%d: " + "4663 CMF: Mode %s acr %s\n", + phba->brd_no, + lpfc_cmf_mode_to_str + [phba->cgn_p.cgn_param_mode], + acr_string); + } + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4669 FW cgn parm buf wrong magic 0x%x " + "version %d\n", p_cgn_param->cgn_param_magic, + p_cgn_param->cgn_param_version); + } +} + +/** + * lpfc_sli4_cgn_params_read - Read and Validate FW congestion parameters. + * @phba: pointer to lpfc hba data structure. + * + * This routine issues a read_object mailbox command to + * get the congestion management parameters from the FW + * parses it and updates the driver maintained values. + * + * Returns + * 0 if the object was empty + * -Eval if an error was encountered + * Count if bytes were read from object + **/ +int +lpfc_sli4_cgn_params_read(struct lpfc_hba *phba) +{ + int ret = 0; + struct lpfc_cgn_param *p_cgn_param = NULL; + u32 *pdata = NULL; + u32 len = 0; + + /* Find out if the FW has a new set of congestion parameters. */ + len = sizeof(struct lpfc_cgn_param); + pdata = kzalloc(len, GFP_KERNEL); + ret = lpfc_read_object(phba, (char *)LPFC_PORT_CFG_NAME, + pdata, len); + + /* 0 means no data. A negative means error. A positive means + * bytes were copied. + */ + if (!ret) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4670 CGN RD OBJ returns no data\n"); + goto rd_obj_err; + } else if (ret < 0) { + /* Some error. Just exit and return it to the caller.*/ + goto rd_obj_err; + } + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT, + "6234 READ CGN PARAMS Successful %d\n", len); + + /* Parse data pointer over len and update the phba congestion + * parameters with values passed back. The receive rate values + * may have been altered in FW, but take no action here. + */ + p_cgn_param = (struct lpfc_cgn_param *)pdata; + lpfc_cgn_params_parse(phba, p_cgn_param, len); + + rd_obj_err: + kfree(pdata); + return ret; +} + +/** + * lpfc_sli4_cgn_parm_chg_evt - Process a FW congestion param change event + * @phba: pointer to lpfc hba data structure. + * + * The FW generated Async ACQE SLI event calls this routine when + * the event type is an SLI Internal Port Event and the Event Code + * indicates a change to the FW maintained congestion parameters. + * + * This routine executes a Read_Object mailbox call to obtain the + * current congestion parameters maintained in FW and corrects + * the driver's active congestion parameters. + * + * The acqe event is not passed because there is no further data + * required. + * + * Returns nonzero error if event processing encountered an error. + * Zero otherwise for success. + **/ +static int +lpfc_sli4_cgn_parm_chg_evt(struct lpfc_hba *phba) +{ + int ret = 0; + + if (!phba->sli4_hba.pc_sli4_params.cmf) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4664 Cgn Evt when E2E off. Drop event\n"); + return -EACCES; + } + + /* If the event is claiming an empty object, it's ok. A write + * could have cleared it. Only error is a negative return + * status. + */ + ret = lpfc_sli4_cgn_params_read(phba); + if (ret < 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4667 Error reading Cgn Params (%d)\n", + ret); + } else if (!ret) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "4673 CGN Event empty object.\n"); + } + return ret; +} + +/** * lpfc_sli4_async_event_proc - Process all the pending asynchronous event * @phba: pointer to lpfc hba data structure. * @@ -5846,18 +7319,21 @@ lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba, void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) { struct lpfc_cq_event *cq_event; + unsigned long iflags; /* First, declare the async event has been handled */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag &= ~ASYNC_EVENT; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); + /* Now, handle all the async events */ + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); while (!list_empty(&phba->sli4_hba.sp_asynce_work_queue)) { - /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); list_remove_head(&phba->sli4_hba.sp_asynce_work_queue, cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, + iflags); + /* Process the asynchronous event */ switch (bf_get(lpfc_trailer_code, &cq_event->cqe.mcqe_cmpl)) { case LPFC_TRAILER_CODE_LINK: @@ -5881,16 +7357,23 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) case LPFC_TRAILER_CODE_SLI: lpfc_sli4_async_sli_evt(phba, &cq_event->cqe.acqe_sli); break; + case LPFC_TRAILER_CODE_CMSTAT: + lpfc_sli4_async_cmstat_evt(phba); + break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "1804 Invalid asynchronous event code: " "x%x\n", bf_get(lpfc_trailer_code, &cq_event->cqe.mcqe_cmpl)); break; } + /* Free the completion event processed to the free pool */ lpfc_sli4_cq_event_release(phba, cq_event); + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); } + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); } /** @@ -5918,7 +7401,7 @@ void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *phba) "2777 Start post-quiescent FCF table scan\n"); rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); if (rc) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2747 Issue FCF scan read FCF mailbox " "command failed 0x%x\n", rc); } @@ -5989,7 +7472,7 @@ static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode) "0480 Enabled MSI-X interrupt mode.\n"); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0482 Illegal interrupt mode.\n"); break; } @@ -5997,29 +7480,6 @@ static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode) } /** - * lpfc_cpumask_of_node_init - initalizes cpumask of phba's NUMA node - * @phba: Pointer to HBA context object. - * - **/ -static void -lpfc_cpumask_of_node_init(struct lpfc_hba *phba) -{ - unsigned int cpu, numa_node; - struct cpumask *numa_mask = &phba->sli4_hba.numa_mask; - - cpumask_clear(numa_mask); - - /* Check if we're a NUMA architecture */ - numa_node = dev_to_node(&phba->pcidev->dev); - if (numa_node == NUMA_NO_NODE) - return; - - for_each_possible_cpu(cpu) - if (cpu_to_node(cpu) == numa_node) - cpumask_set_cpu(cpu, numa_mask); -} - -/** * lpfc_enable_pci_dev - Enable a generic PCI device. * @phba: pointer to lpfc hba data structure. * @@ -6106,10 +7566,14 @@ lpfc_reset_hba(struct lpfc_hba *phba) phba->link_state = LPFC_HBA_ERROR; return; } - if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) + + /* If not LPFC_SLI_ACTIVE, force all IO to be flushed */ + if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) { lpfc_offline_prep(phba, LPFC_MBX_WAIT); - else + } else { lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT); + lpfc_sli_flush_io_rings(phba); + } lpfc_offline(phba); lpfc_sli_brdrestart(phba); lpfc_online(phba); @@ -6161,7 +7625,7 @@ lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn) max_nr_vfn = lpfc_sli_sriov_nr_virtfn_get(phba); if (nr_vfn > max_nr_vfn) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3057 Requested vfs (%d) greater than " "supported vfs (%d)", nr_vfn, max_nr_vfn); return -EINVAL; @@ -6180,6 +7644,15 @@ lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn) return rc; } +static void +lpfc_unblock_requests_work(struct work_struct *work) +{ + struct lpfc_hba *phba = container_of(work, struct lpfc_hba, + unblock_request_work); + + lpfc_unblock_requests(phba); +} + /** * lpfc_setup_driver_resource_phase1 - Phase1 etup driver internal resources. * @phba: pointer to lpfc hba data structure. @@ -6200,17 +7673,16 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) * Driver resources common to all SLI revisions */ atomic_set(&phba->fast_event_count, 0); + atomic_set(&phba->dbg_log_idx, 0); + atomic_set(&phba->dbg_log_cnt, 0); + atomic_set(&phba->dbg_log_dmping, 0); spin_lock_init(&phba->hbalock); - /* Initialize ndlp management spinlock */ - spin_lock_init(&phba->ndlp_lock); - /* Initialize port_list spinlock */ spin_lock_init(&phba->port_list_lock); INIT_LIST_HEAD(&phba->port_list); INIT_LIST_HEAD(&phba->work_list); - init_waitqueue_head(&phba->wait_4_mlo_m_q); /* Initialize the wait queue head for the kernel thread */ init_waitqueue_head(&phba->work_waitq); @@ -6253,6 +7725,9 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) INIT_DELAYED_WORK(&phba->eq_delay_work, lpfc_hb_eq_delay_work); + INIT_DELAYED_WORK(&phba->idle_stat_delay_work, + lpfc_idle_stat_delay_work); + INIT_WORK(&phba->unblock_request_work, lpfc_unblock_requests_work); return 0; } @@ -6291,13 +7766,6 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) if (rc) return -ENODEV; - if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) { - phba->menlo_flag |= HBA_MENLO_SUPPORT; - /* check for menlo minimum sg count */ - if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) - phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT; - } - if (!phba->sli.sli3_ring) phba->sli.sli3_ring = kcalloc(LPFC_SLI3_MAX_RING, sizeof(struct lpfc_sli_ring), @@ -6310,11 +7778,6 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) * used to create the sg_dma_buf_pool must be dynamically calculated. */ - /* Initialize the host templates the configured values. */ - lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template_no_hr.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; - if (phba->sli_rev == LPFC_SLI_REV4) entry_sz = sizeof(struct sli4_sge); else @@ -6355,7 +7818,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) } lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP, - "9088 sg_tablesize:%d dmabuf_size:%d total_bde:%d\n", + "9088 INIT sg_tablesize:%d dmabuf_size:%d total_bde:%d\n", phba->cfg_sg_seg_cnt, phba->cfg_sg_dma_buf_size, phba->cfg_total_seg_cnt); @@ -6451,8 +7914,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) LPFC_MBOXQ_t *mboxq; MAILBOX_t *mb; int rc, i, max_buf_size; - uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0}; - struct lpfc_mqe *mqe; int longs; int extra; uint64_t wwn; @@ -6462,7 +7923,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->sli4_hba.num_present_cpu = lpfc_present_cpu; phba->sli4_hba.num_possible_cpu = cpumask_last(cpu_possible_mask) + 1; phba->sli4_hba.curr_disp_cpu = 0; - lpfc_cpumask_of_node_init(phba); /* Get all the module params for configuring this host */ lpfc_get_cfgparam(phba); @@ -6481,6 +7941,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* The lpfc_wq workqueue for deferred irq use */ phba->wq = alloc_workqueue("lpfc_wq", WQ_MEM_RECLAIM, 0); + if (!phba->wq) + return -ENOMEM; /* * Initialize timers used by driver @@ -6491,6 +7953,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* FCF rediscover timer */ timer_setup(&phba->fcf.redisc_wait, lpfc_sli4_fcf_redisc_wait_tmo, 0); + /* CMF congestion timer */ + hrtimer_init(&phba->cmf_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + phba->cmf_timer.function = lpfc_cmf_timer; + /* * Control structure for handling external multi-buffer mailbox * command pass-through. @@ -6521,6 +7987,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_sli4_rb_alloc; phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_sli4_rb_free; + /* for VMID idle timeout if VMID is enabled */ + if (lpfc_is_vmid_enabled(phba)) + timer_setup(&phba->inactive_vmid_poll, lpfc_vmid_poll, 0); + /* * Initialize the SLI Layer to run with lpfc SLI4 HBAs. */ @@ -6540,6 +8010,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* This abort list used by worker thread */ spin_lock_init(&phba->sli4_hba.sgl_list_lock); spin_lock_init(&phba->sli4_hba.nvmet_io_wait_lock); + spin_lock_init(&phba->sli4_hba.asynce_list_lock); + spin_lock_init(&phba->sli4_hba.els_xri_abrt_list_lock); /* * Initialize driver internal slow-path work queues @@ -6551,8 +8023,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) INIT_LIST_HEAD(&phba->sli4_hba.sp_queue_event); /* Asynchronous event CQ Event work queue list */ INIT_LIST_HEAD(&phba->sli4_hba.sp_asynce_work_queue); - /* Fast-path XRI aborted CQ Event work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue); /* Slow-path XRI aborted CQ Event work queue list */ INIT_LIST_HEAD(&phba->sli4_hba.sp_els_xri_aborted_work_queue); /* Receive queue CQ Event work queue list */ @@ -6576,7 +8046,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Allocate device driver memory */ rc = lpfc_mem_alloc(phba, SGL_ALIGN_SZ); if (rc) - return -ENOMEM; + goto out_destroy_workqueue; /* IF Type 2 ports get initialized now. */ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= @@ -6603,6 +8073,18 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) rc = lpfc_sli4_read_config(phba); if (unlikely(rc)) goto out_free_bsmbx; + + if (phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_CONFIG) { + /* Right now the link is down, if FA-PWWN is configured the + * firmware will try FLOGI before the driver gets a link up. + * If it fails, the driver should get a MISCONFIGURED async + * event which will clear this flag. The only notification + * the driver gets is if it fails, if it succeeds there is no + * notification given. Assume success. + */ + phba->sli4_hba.fawwpn_flag |= LPFC_FAWWPN_FABRIC; + } + rc = lpfc_mem_alloc_active_rrq_pool_s4(phba); if (unlikely(rc)) goto out_free_bsmbx; @@ -6630,7 +8112,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) lpfc_read_nv(phba, mboxq); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6016 Mailbox failed , mbxCmd x%x " "READ_NV, mbxStatus x%x\n", bf_get(lpfc_mqe_command, &mboxq->u.mqe), @@ -6659,17 +8142,26 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->nvmet_support = 1; /* a match */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6017 NVME Target %016llx\n", wwn); #else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "6021 Can't enable NVME Target." " NVME_TARGET_FC infrastructure" " is not in kernel\n"); #endif /* Not supported for NVMET */ phba->cfg_xri_rebalancing = 0; + if (phba->irq_chann_mode == NHT_MODE) { + phba->cfg_irq_chann = + phba->sli4_hba.num_present_cpu; + phba->cfg_hdw_queue = + phba->sli4_hba.num_present_cpu; + phba->irq_chann_mode = NORMAL_MODE; + } break; } } @@ -6677,32 +8169,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) lpfc_nvme_mod_param_dep(phba); - /* Get the Supported Pages if PORT_CAPABILITIES is supported by port. */ - lpfc_supported_pages(mboxq); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (!rc) { - mqe = &mboxq->u.mqe; - memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3), - LPFC_MAX_SUPPORTED_PAGES); - for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) { - switch (pn_page[i]) { - case LPFC_SLI4_PARAMETERS: - phba->sli4_hba.pc_sli4_params.supported = 1; - break; - default: - break; - } - } - /* Read the port's SLI4 Parameters capabilities if supported. */ - if (phba->sli4_hba.pc_sli4_params.supported) - rc = lpfc_pc_sli4_params_get(phba, mboxq); - if (rc) { - mempool_free(mboxq, phba->mbox_mem_pool); - rc = -EIO; - goto out_free_bsmbx; - } - } - /* * Get sli4 parameters that override parameters from Port capabilities. * If this call fails, it isn't critical unless the SLI4 parameters come @@ -6716,9 +8182,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) &phba->sli4_hba.sli_intf); if (phba->sli4_hba.extents_in_use && phba->sli4_hba.rpi_hdrs_in_use) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2999 Unsupported SLI4 Parameters " - "Extents and RPI headers enabled.\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2999 Unsupported SLI4 Parameters " + "Extents and RPI headers enabled.\n"); if (if_type == LPFC_SLI_INTF_IF_TYPE_0 && if_fam == LPFC_SLI_INTF_FAMILY_BE2) { mempool_free(mboxq, phba->mbox_mem_pool); @@ -6825,11 +8291,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt; } - /* Initialize the host templates with the updated values. */ - lpfc_vport_template.sg_tablesize = phba->cfg_scsi_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_scsi_seg_cnt; - lpfc_template_no_hr.sg_tablesize = phba->cfg_scsi_seg_cnt; - lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP, "9087 sg_seg_cnt:%d dmabuf_size:%d " "total:%d scsi:%d nvme:%d\n", @@ -6847,8 +8308,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) &phba->pcidev->dev, phba->cfg_sg_dma_buf_size, i, 0); - if (!phba->lpfc_sg_dma_buf_pool) + if (!phba->lpfc_sg_dma_buf_pool) { + rc = -ENOMEM; goto out_free_bsmbx; + } phba->lpfc_cmd_rsp_buf_pool = dma_pool_create("lpfc_cmd_rsp_buf_pool", @@ -6856,8 +8319,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp), i, 0); - if (!phba->lpfc_cmd_rsp_buf_pool) + if (!phba->lpfc_cmd_rsp_buf_pool) { + rc = -ENOMEM; goto out_free_sg_dma_buf; + } mempool_free(mboxq, phba->mbox_mem_pool); @@ -6883,13 +8348,13 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Allocate and initialize active sgl array */ rc = lpfc_init_active_sgl_array(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1430 Failed to initialize sgl list.\n"); goto out_destroy_cq_event_pool; } rc = lpfc_sli4_init_rpi_hdrs(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1432 Failed to initialize rpi headers.\n"); goto out_free_active_sgl; } @@ -6899,7 +8364,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->fcf.fcf_rr_bmask = kcalloc(longs, sizeof(unsigned long), GFP_KERNEL); if (!phba->fcf.fcf_rr_bmask) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2759 Failed allocate memory for FCF round " "robin failover bmask\n"); rc = -ENOMEM; @@ -6910,7 +8375,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) sizeof(struct lpfc_hba_eq_hdl), GFP_KERNEL); if (!phba->sli4_hba.hba_eq_hdl) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2572 Failed allocate memory for " "fast-path per-EQ handle array\n"); rc = -ENOMEM; @@ -6921,7 +8386,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) sizeof(struct lpfc_vector_map_info), GFP_KERNEL); if (!phba->sli4_hba.cpu_map) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3327 Failed allocate memory for msi-x " "interrupt vector mapping\n"); rc = -ENOMEM; @@ -6930,11 +8395,40 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->sli4_hba.eq_info = alloc_percpu(struct lpfc_eq_intr_info); if (!phba->sli4_hba.eq_info) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3321 Failed allocation for per_cpu stats\n"); rc = -ENOMEM; goto out_free_hba_cpu_map; } + + phba->sli4_hba.idle_stat = kcalloc(phba->sli4_hba.num_possible_cpu, + sizeof(*phba->sli4_hba.idle_stat), + GFP_KERNEL); + if (!phba->sli4_hba.idle_stat) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3390 Failed allocation for idle_stat\n"); + rc = -ENOMEM; + goto out_free_hba_eq_info; + } + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + phba->sli4_hba.c_stat = alloc_percpu(struct lpfc_hdwq_stat); + if (!phba->sli4_hba.c_stat) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3332 Failed allocating per cpu hdwq stats\n"); + rc = -ENOMEM; + goto out_free_hba_idle_stat; + } +#endif + + phba->cmf_stat = alloc_percpu(struct lpfc_cgn_stat); + if (!phba->cmf_stat) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "3331 Failed allocating per cpu cgn stats\n"); + rc = -ENOMEM; + goto out_free_hba_hdwq_info; + } + /* * Enable sr-iov virtual functions if supported and configured * through the module parameter. @@ -6954,6 +8448,14 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) return 0; +out_free_hba_hdwq_info: +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + free_percpu(phba->sli4_hba.c_stat); +out_free_hba_idle_stat: +#endif + kfree(phba->sli4_hba.idle_stat); +out_free_hba_eq_info: + free_percpu(phba->sli4_hba.eq_info); out_free_hba_cpu_map: kfree(phba->sli4_hba.cpu_map); out_free_hba_eq_hdl: @@ -6976,6 +8478,9 @@ out_free_bsmbx: lpfc_destroy_bootstrap_mbox(phba); out_free_mem: lpfc_mem_free(phba); +out_destroy_workqueue: + destroy_workqueue(phba->wq); + phba->wq = NULL; return rc; } @@ -6992,13 +8497,18 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; free_percpu(phba->sli4_hba.eq_info); +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + free_percpu(phba->sli4_hba.c_stat); +#endif + free_percpu(phba->cmf_stat); + kfree(phba->sli4_hba.idle_stat); /* Free memory allocated for msi-x interrupt vector to CPU mapping */ kfree(phba->sli4_hba.cpu_map); phba->sli4_hba.num_possible_cpu = 0; phba->sli4_hba.num_present_cpu = 0; phba->sli4_hba.curr_disp_cpu = 0; - cpumask_clear(&phba->sli4_hba.numa_mask); + cpumask_clear(&phba->sli4_hba.irq_aff_mask); /* Free memory allocated for fast-path work queue handles */ kfree(phba->sli4_hba.hba_eq_hdl); @@ -7070,7 +8580,6 @@ lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) "1431 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } return 0; } @@ -7114,7 +8623,6 @@ static void lpfc_unset_driver_resource_phase2(struct lpfc_hba *phba) { if (phba->wq) { - flush_workqueue(phba->wq); destroy_workqueue(phba->wq); phba->wq = NULL; } @@ -7150,6 +8658,7 @@ lpfc_free_iocb_list(struct lpfc_hba *phba) /** * lpfc_init_iocb_list - Allocate and initialize iocb list. * @phba: pointer to lpfc hba data structure. + * @iocb_count: number of requested iocbs * * This routine is invoked to allocate and initizlize the driver's IOCB * list and set up the IOCB tag array accordingly. @@ -7231,11 +8740,9 @@ lpfc_free_els_sgl_list(struct lpfc_hba *phba) LIST_HEAD(sglq_list); /* Retrieve all els sgls from driver list */ - spin_lock_irq(&phba->hbalock); - spin_lock(&phba->sli4_hba.sgl_list_lock); + spin_lock_irq(&phba->sli4_hba.sgl_list_lock); list_splice_init(&phba->sli4_hba.lpfc_els_sgl_list, &sglq_list); - spin_unlock(&phba->sli4_hba.sgl_list_lock); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->sli4_hba.sgl_list_lock); /* Now free the sgl list */ lpfc_free_sgl_list(phba, &sglq_list); @@ -7361,7 +8868,7 @@ lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba) rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); if (!rpi_hdr) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0391 Error during rpi post operation\n"); lpfc_sli4_remove_rpis(phba); rc = -ENODEV; @@ -7559,6 +9066,36 @@ lpfc_hba_free(struct lpfc_hba *phba) } /** + * lpfc_setup_fdmi_mask - Setup initial FDMI mask for HBA and Port attributes + * @vport: pointer to lpfc vport data structure. + * + * This routine is will setup initial FDMI attribute masks for + * FDMI2 or SmartSAN depending on module parameters. The driver will attempt + * to get these attributes first before falling back, the attribute + * fallback hierarchy is SmartSAN -> FDMI2 -> FMDI1 + **/ +void +lpfc_setup_fdmi_mask(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + + vport->load_flag |= FC_ALLOW_FDMI; + if (phba->cfg_enable_SmartSAN || + phba->cfg_fdmi_on == LPFC_FDMI_SUPPORT) { + /* Setup appropriate attribute masks */ + vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR; + if (phba->cfg_enable_SmartSAN) + vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR; + else + vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR; + } + + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, + "6077 Setup FDMI mask: hba x%x port x%x\n", + vport->fdmi_hba_mask, vport->fdmi_port_mask); +} + +/** * lpfc_create_shost - Create hba physical port with associated scsi host. * @phba: pointer to lpfc hba data structure. * @@ -7601,21 +9138,12 @@ lpfc_create_shost(struct lpfc_hba *phba) /* Put reference to SCSI host to driver's device private data */ pci_set_drvdata(phba->pcidev, shost); + lpfc_setup_fdmi_mask(vport); + /* * At this point we are fully registered with PSA. In addition, * any initial discovery should be completed. */ - vport->load_flag |= FC_ALLOW_FDMI; - if (phba->cfg_enable_SmartSAN || - (phba->cfg_fdmi_on == LPFC_FDMI_SUPPORT)) { - - /* Setup appropriate attribute masks */ - vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR; - if (phba->cfg_enable_SmartSAN) - vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR; - else - vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR; - } return 0; } @@ -7673,7 +9201,7 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) if (phba->cfg_prot_mask && phba->cfg_prot_guard) { if ((old_mask != phba->cfg_prot_mask) || (old_guard != phba->cfg_prot_guard)) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1475 Registering BlockGuard with the " "SCSI layer: mask %d guard %d\n", phba->cfg_prot_mask, @@ -7682,7 +9210,7 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) scsi_host_set_prot(shost, phba->cfg_prot_mask); scsi_host_set_guard(shost, phba->cfg_prot_guard); } else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1479 Not Registering BlockGuard with the SCSI " "layer, Bad protection parameters: %d %d\n", old_mask, old_guard); @@ -7913,7 +9441,7 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) * other register reads as the data may not be valid. Just exit. */ if (port_error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1408 Port Failed POST - portsmphr=0x%x, " "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, scr1=x%x, " "scr2=x%x, hscratch=x%x, pstatus=x%x\n", @@ -7962,7 +9490,8 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) readl(phba->sli4_hba.u.if_type0.UERRHIregaddr); if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) || (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "1422 Unrecoverable Error " "Detected during POST " "uerr_lo_reg=0x%x, " @@ -7989,7 +9518,7 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) phba->work_status[1] = readl(phba->sli4_hba.u.if_type2. ERR2regaddr); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2888 Unrecoverable port error " "following POST: port status reg " "0x%x, port_smphr reg 0x%x, " @@ -7999,7 +9528,15 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) phba->work_status[0], phba->work_status[1]); port_error = -ENODEV; + break; } + + if (lpfc_pldv_detect && + bf_get(lpfc_sli_intf_sli_family, + &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_FAMILY_G6) + pci_write_config_byte(phba->pcidev, + LPFC_SLI_INTF, CFG_PLD); break; case LPFC_SLI_INTF_IF_TYPE_1: default: @@ -8102,6 +9639,7 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type) /** * lpfc_sli4_bar1_register_memmap - Set up SLI4 BAR1 register memory map. * @phba: pointer to lpfc hba data structure. + * @if_type: sli if type to operate on. * * This routine is invoked to set up SLI4 BAR1 register memory map. **/ @@ -8283,20 +9821,19 @@ static const char * const lpfc_topo_to_str[] = { "P2P then Loop", }; +#define LINK_FLAGS_DEF 0x0 +#define LINK_FLAGS_P2P 0x1 +#define LINK_FLAGS_LOOP 0x2 /** * lpfc_map_topology - Map the topology read from READ_CONFIG * @phba: pointer to lpfc hba data structure. - * @rdconf: pointer to read config data + * @rd_config: pointer to read config data * * This routine is invoked to map the topology values as read * from the read config mailbox command. If the persistent * topology feature is supported, the firmware will provide the * saved topology information to be used in INIT_LINK - * **/ -#define LINK_FLAGS_DEF 0x0 -#define LINK_FLAGS_P2P 0x1 -#define LINK_FLAGS_LOOP 0x2 static void lpfc_map_topology(struct lpfc_hba *phba, struct lpfc_mbx_read_config *rd_config) { @@ -8318,9 +9855,12 @@ lpfc_map_topology(struct lpfc_hba *phba, struct lpfc_mbx_read_config *rd_config) } /* FW supports persistent topology - override module parameter value */ phba->hba_flag |= HBA_PERSISTENT_TOPO; - switch (phba->pcidev->device) { - case PCI_DEVICE_ID_LANCER_G7_FC: - case PCI_DEVICE_ID_LANCER_G6_FC: + + /* if ASIC_GEN_NUM >= 0xC) */ + if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_6) || + (bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_FAMILY_G6)) { if (!tf) { phba->cfg_topology = ((pt == LINK_FLAGS_LOOP) ? FLAGS_TOPOLOGY_MODE_LOOP @@ -8328,8 +9868,7 @@ lpfc_map_topology(struct lpfc_hba *phba, struct lpfc_mbx_read_config *rd_config) } else { phba->hba_flag &= ~HBA_PERSISTENT_TOPO; } - break; - default: /* G5 */ + } else { /* G5 */ if (tf) { /* If topology failover set - pt is '0' or '1' */ phba->cfg_topology = (pt ? FLAGS_TOPOLOGY_MODE_PT_LOOP : @@ -8339,7 +9878,6 @@ lpfc_map_topology(struct lpfc_hba *phba, struct lpfc_mbx_read_config *rd_config) ? FLAGS_TOPOLOGY_MODE_PT_PT : FLAGS_TOPOLOGY_MODE_LOOP); } - break; } if (phba->hba_flag & HBA_PERSISTENT_TOPO) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -8378,12 +9916,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) struct lpfc_rsrc_desc_fcfcoe *desc; char *pdesc_0; uint16_t forced_link_speed; - uint32_t if_type, qmin; + uint32_t if_type, qmin, fawwpn; int length, i, rc = 0, rc2; pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2011 Unable to allocate memory for issuing " "SLI_CONFIG_SPECIAL mailbox command\n"); return -ENOMEM; @@ -8393,11 +9931,11 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2012 Mailbox failed , mbxCmd x%x " - "READ_CONFIG, mbxStatus x%x\n", - bf_get(lpfc_mqe_command, &pmb->u.mqe), - bf_get(lpfc_mqe_status, &pmb->u.mqe)); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2012 Mailbox failed , mbxCmd x%x " + "READ_CONFIG, mbxStatus x%x\n", + bf_get(lpfc_mqe_command, &pmb->u.mqe), + bf_get(lpfc_mqe_status, &pmb->u.mqe)); rc = -EIO; } else { rd_config = &pmb->u.mqe.un.rd_config; @@ -8420,10 +9958,24 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->sli4_hba.bbscn_params.word0 = rd_config->word8; } + fawwpn = bf_get(lpfc_mbx_rd_conf_fawwpn, rd_config); + + if (fawwpn) { + lpfc_printf_log(phba, KERN_INFO, + LOG_INIT | LOG_DISCOVERY, + "2702 READ_CONFIG: FA-PWWN is " + "configured on\n"); + phba->sli4_hba.fawwpn_flag |= LPFC_FAWWPN_CONFIG; + } else { + /* Clear FW configured flag, preserve driver flag */ + phba->sli4_hba.fawwpn_flag &= ~LPFC_FAWWPN_CONFIG; + } + phba->sli4_hba.conf_trunk = bf_get(lpfc_mbx_rd_conf_trunk, rd_config); phba->sli4_hba.extents_in_use = bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config); + phba->sli4_hba.max_cfg_param.max_xri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config); /* Reduce resource usage in kdump environment */ @@ -8464,6 +10016,52 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ? (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0; phba->max_vports = phba->max_vpi; + + /* Next decide on FPIN or Signal E2E CGN support + * For congestion alarms and warnings valid combination are: + * 1. FPIN alarms / FPIN warnings + * 2. Signal alarms / Signal warnings + * 3. FPIN alarms / Signal warnings + * 4. Signal alarms / FPIN warnings + * + * Initialize the adapter frequency to 100 mSecs + */ + phba->cgn_reg_fpin = LPFC_CGN_FPIN_BOTH; + phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED; + phba->cgn_sig_freq = lpfc_fabric_cgn_frequency; + + if (lpfc_use_cgn_signal) { + if (bf_get(lpfc_mbx_rd_conf_wcs, rd_config)) { + phba->cgn_reg_signal = EDC_CG_SIG_WARN_ONLY; + phba->cgn_reg_fpin &= ~LPFC_CGN_FPIN_WARN; + } + if (bf_get(lpfc_mbx_rd_conf_acs, rd_config)) { + /* MUST support both alarm and warning + * because EDC does not support alarm alone. + */ + if (phba->cgn_reg_signal != + EDC_CG_SIG_WARN_ONLY) { + /* Must support both or none */ + phba->cgn_reg_fpin = LPFC_CGN_FPIN_BOTH; + phba->cgn_reg_signal = + EDC_CG_SIG_NOTSUPPORTED; + } else { + phba->cgn_reg_signal = + EDC_CG_SIG_WARN_ALARM; + phba->cgn_reg_fpin = + LPFC_CGN_FPIN_NONE; + } + } + } + + /* Set the congestion initial signal and fpin values. */ + phba->cgn_init_reg_fpin = phba->cgn_reg_fpin; + phba->cgn_init_reg_signal = phba->cgn_reg_signal; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6446 READ_CONFIG reg_sig x%x reg_fpin:x%x\n", + phba->cgn_reg_signal, phba->cgn_reg_fpin); + lpfc_map_topology(phba, rd_config); lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2003 cfg params Extents? %d " @@ -8471,7 +10069,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) "VPI(B:%d M:%d) " "VFI(B:%d M:%d) " "RPI(B:%d M:%d) " - "FCFI:%d EQ:%d CQ:%d WQ:%d RQ:%d\n", + "FCFI:%d EQ:%d CQ:%d WQ:%d RQ:%d lmt:x%x\n", phba->sli4_hba.extents_in_use, phba->sli4_hba.max_cfg_param.xri_base, phba->sli4_hba.max_cfg_param.max_xri, @@ -8485,7 +10083,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->sli4_hba.max_cfg_param.max_eq, phba->sli4_hba.max_cfg_param.max_cq, phba->sli4_hba.max_cfg_param.max_wq, - phba->sli4_hba.max_cfg_param.max_rq); + phba->sli4_hba.max_cfg_param.max_rq, + phba->lmt); /* * Calculate queue resources based on how @@ -8507,8 +10106,9 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) /* Check to see if there is enough for NVME */ if ((phba->cfg_irq_chann > qmin) || (phba->cfg_hdw_queue > qmin)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2005 Reducing Queues: " + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2005 Reducing Queues - " + "FW resource limitation: " "WQ %d CQ %d EQ %d: min %d: " "IRQ %d HDWQ %d\n", phba->sli4_hba.max_cfg_param.max_wq, @@ -8573,7 +10173,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) LPFC_USER_LINK_SPEED_AUTO; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "0047 Unrecognized link " "speed : %d\n", forced_link_speed); @@ -8610,7 +10211,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (rc2 || shdr_status || shdr_add_status) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3026 Mailbox failed , mbxCmd x%x " "GET_FUNCTION_CONFIG, mbxStatus x%x\n", bf_get(lpfc_mqe_command, &pmb->u.mqe), @@ -8647,7 +10248,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) "vf_number:%d\n", phba->sli4_hba.iov.pf_number, phba->sli4_hba.iov.vf_number); else - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3028 GET_FUNCTION_CONFIG: failed to find " "Resource Descriptor:x%x\n", LPFC_RSRC_DESC_TYPE_FCFCOE); @@ -8684,7 +10285,7 @@ lpfc_setup_endian_order(struct lpfc_hba *phba) mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0492 Unable to allocate memory for " "issuing SLI_CONFIG_SPECIAL mailbox " "command\n"); @@ -8699,7 +10300,7 @@ lpfc_setup_endian_order(struct lpfc_hba *phba) memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data)); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0493 SLI_CONFIG_SPECIAL mailbox " "failed with status x%x\n", rc); @@ -8779,8 +10380,9 @@ lpfc_alloc_io_wq_cq(struct lpfc_hba *phba, int idx) phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0499 Failed allocate fast-path IO CQ (%d)\n", idx); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0499 Failed allocate fast-path IO CQ (%d)\n", + idx); return 1; } qdesc->qe_valid = 1; @@ -8802,7 +10404,7 @@ lpfc_alloc_io_wq_cq(struct lpfc_hba *phba, int idx) phba->sli4_hba.wq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0503 Failed allocate fast-path IO WQ (%d)\n", idx); return 1; @@ -8858,7 +10460,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->cfg_hdw_queue, sizeof(struct lpfc_sli4_hdw_queue), GFP_KERNEL); if (!phba->sli4_hba.hdwq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6427 Failed allocate memory for " "fast-path Hardware Queue array\n"); goto out_error; @@ -8890,7 +10492,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) sizeof(struct lpfc_queue *), GFP_KERNEL); if (!phba->sli4_hba.nvmet_cqset) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3121 Fail allocate memory for " "fast-path CQ set array\n"); goto out_error; @@ -8900,7 +10502,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) sizeof(struct lpfc_queue *), GFP_KERNEL); if (!phba->sli4_hba.nvmet_mrq_hdr) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3122 Fail allocate memory for " "fast-path RQ set hdr array\n"); goto out_error; @@ -8910,7 +10512,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) sizeof(struct lpfc_queue *), GFP_KERNEL); if (!phba->sli4_hba.nvmet_mrq_data) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3124 Fail allocate memory for " "fast-path RQ set data array\n"); goto out_error; @@ -8938,7 +10540,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.eq_esize, phba->sli4_hba.eq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0497 Failed allocate EQ (%d)\n", cpup->hdwq); goto out_error; @@ -8992,7 +10594,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3142 Failed allocate NVME " "CQ Set (%d)\n", idx); goto out_error; @@ -9014,7 +10616,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0500 Failed allocate slow-path mailbox CQ\n"); goto out_error; } @@ -9026,7 +10628,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0501 Failed allocate slow-path ELS CQ\n"); goto out_error; } @@ -9045,7 +10647,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.mq_esize, phba->sli4_hba.mq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0505 Failed allocate slow-path MQ\n"); goto out_error; } @@ -9061,7 +10663,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.wq_esize, phba->sli4_hba.wq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0504 Failed allocate slow-path ELS WQ\n"); goto out_error; } @@ -9075,7 +10677,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6079 Failed allocate NVME LS CQ\n"); goto out_error; } @@ -9088,7 +10690,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.wq_esize, phba->sli4_hba.wq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6080 Failed allocate NVME LS WQ\n"); goto out_error; } @@ -9106,7 +10708,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.rq_esize, phba->sli4_hba.rq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0506 Failed allocate receive HRQ\n"); goto out_error; } @@ -9117,7 +10719,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.rq_esize, phba->sli4_hba.rq_ecount, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0507 Failed allocate receive DRQ\n"); goto out_error; } @@ -9135,7 +10737,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) LPFC_NVMET_RQE_DEF_COUNT, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3146 Failed allocate " "receive HRQ\n"); goto out_error; @@ -9148,7 +10750,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) GFP_KERNEL, cpu_to_node(cpu)); if (qdesc->rqbp == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6131 Failed allocate " "Header RQBP\n"); goto out_error; @@ -9164,7 +10766,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) LPFC_NVMET_RQE_DEF_COUNT, cpu); if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3156 Failed allocate " "receive DRQ\n"); goto out_error; @@ -9235,6 +10837,7 @@ lpfc_sli4_release_hdwq(struct lpfc_hba *phba) /* Free the CQ/WQ corresponding to the Hardware Queue */ lpfc_sli4_queue_free(hdwq[idx].io_cq); lpfc_sli4_queue_free(hdwq[idx].io_wq); + hdwq[idx].hba_eq = NULL; hdwq[idx].io_cq = NULL; hdwq[idx].io_wq = NULL; if (phba->cfg_xpsgl && !phba->nvmet_support) @@ -9354,7 +10957,7 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, int rc; if (!eq || !cq || !wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6085 Fast-path %s (%d) not allocated\n", ((eq) ? ((cq) ? "WQ" : "CQ") : "EQ"), qidx); return -ENOMEM; @@ -9364,9 +10967,9 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, rc = lpfc_cq_create(phba, cq, eq, (qtype == LPFC_MBOX) ? LPFC_MCQ : LPFC_WCQ, qtype); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "6086 Failed setup of CQ (%d), rc = 0x%x\n", - qidx, (uint32_t)rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6086 Failed setup of CQ (%d), rc = 0x%x\n", + qidx, (uint32_t)rc); return rc; } @@ -9382,7 +10985,7 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, /* create the wq */ rc = lpfc_wq_create(phba, wq, cq, qtype); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "4618 Fail setup fastpath WQ (%d), rc = 0x%x\n", qidx, (uint32_t)rc); /* no need to tear down cq - caller will do so */ @@ -9400,9 +11003,9 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, } else { rc = lpfc_mq_create(phba, wq, cq, LPFC_MBOX); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0539 Failed setup of slow-path MQ: " - "rc = 0x%x\n", rc); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0539 Failed setup of slow-path MQ: " + "rc = 0x%x\n", rc); /* no need to tear down cq - caller will do so */ return rc; } @@ -9475,7 +11078,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) /* Check for dual-ULP support */ mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3249 Unable to allocate memory for " "QUERY_FW_CFG mailbox command\n"); return -ENOMEM; @@ -9493,12 +11096,11 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3250 QUERY_FW_CFG mailbox failed with status " "x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); + mempool_free(mboxq, phba->mbox_mem_pool); rc = -ENXIO; goto out_error; } @@ -9514,8 +11116,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) "ulp1_mode:x%x\n", phba->sli4_hba.fw_func_mode, phba->sli4_hba.ulp0_mode, phba->sli4_hba.ulp1_mode); - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); + mempool_free(mboxq, phba->mbox_mem_pool); /* * Set up HBA Event Queues (EQs) @@ -9524,7 +11125,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) /* Set up HBA event queue */ if (!qp) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3147 Fast-path EQs not allocated\n"); rc = -ENOMEM; goto out_error; @@ -9548,7 +11149,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) rc = lpfc_eq_create(phba, qp[cpup->hdwq].hba_eq, phba->cfg_fcp_imax); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0523 Failed setup of fast-path" " EQ (%d), rc = 0x%x\n", cpup->eq, (uint32_t)rc); @@ -9580,7 +11181,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) qidx, LPFC_IO); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0535 Failed to setup fastpath " "IO WQ/CQ (%d), rc = 0x%x\n", qidx, (uint32_t)rc); @@ -9595,7 +11196,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) /* Set up slow-path MBOX CQ/MQ */ if (!phba->sli4_hba.mbx_cq || !phba->sli4_hba.mbx_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0528 %s not allocated\n", phba->sli4_hba.mbx_cq ? "Mailbox WQ" : "Mailbox CQ"); @@ -9608,14 +11209,14 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.mbx_wq, NULL, 0, LPFC_MBOX); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0529 Failed setup of mailbox WQ/CQ: rc = 0x%x\n", (uint32_t)rc); goto out_destroy; } if (phba->nvmet_support) { if (!phba->sli4_hba.nvmet_cqset) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3165 Fast-path NVME CQ Set " "array not allocated\n"); rc = -ENOMEM; @@ -9627,7 +11228,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) qp, LPFC_WCQ, LPFC_NVMET); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3164 Failed setup of NVME CQ " "Set, rc = 0x%x\n", (uint32_t)rc); @@ -9639,7 +11240,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) qp[0].hba_eq, LPFC_WCQ, LPFC_NVMET); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6089 Failed setup NVMET CQ: " "rc = 0x%x\n", (uint32_t)rc); goto out_destroy; @@ -9656,7 +11257,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) /* Set up slow-path ELS WQ/CQ */ if (!phba->sli4_hba.els_cq || !phba->sli4_hba.els_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0530 ELS %s not allocated\n", phba->sli4_hba.els_cq ? "WQ" : "CQ"); rc = -ENOMEM; @@ -9667,7 +11268,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.els_wq, NULL, 0, LPFC_ELS); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0525 Failed setup of ELS WQ/CQ: rc = 0x%x\n", (uint32_t)rc); goto out_destroy; @@ -9680,7 +11281,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { /* Set up NVME LS Complete Queue */ if (!phba->sli4_hba.nvmels_cq || !phba->sli4_hba.nvmels_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6091 LS %s not allocated\n", phba->sli4_hba.nvmels_cq ? "WQ" : "CQ"); rc = -ENOMEM; @@ -9691,7 +11292,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.nvmels_wq, NULL, 0, LPFC_NVME_LS); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0526 Failed setup of NVVME LS WQ/CQ: " "rc = 0x%x\n", (uint32_t)rc); goto out_destroy; @@ -9711,7 +11312,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if ((!phba->sli4_hba.nvmet_cqset) || (!phba->sli4_hba.nvmet_mrq_hdr) || (!phba->sli4_hba.nvmet_mrq_data)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6130 MRQ CQ Queues not " "allocated\n"); rc = -ENOMEM; @@ -9724,7 +11325,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.nvmet_cqset, LPFC_NVMET); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6098 Failed setup of NVMET " "MRQ: rc = 0x%x\n", (uint32_t)rc); @@ -9738,7 +11339,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.nvmet_cqset[0], LPFC_NVMET); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6057 Failed setup of NVMET " "Receive Queue: rc = 0x%x\n", (uint32_t)rc); @@ -9757,7 +11358,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) } if (!phba->sli4_hba.hdr_rq || !phba->sli4_hba.dat_rq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0540 Receive Queue not allocated\n"); rc = -ENOMEM; goto out_destroy; @@ -9766,7 +11367,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) rc = lpfc_rq_create(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq, phba->sli4_hba.els_cq, LPFC_USOL); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0541 Failed setup of Receive Queue: " "rc = 0x%x\n", (uint32_t)rc); goto out_destroy; @@ -9794,7 +11395,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.cq_lookup = kcalloc((phba->sli4_hba.cq_max + 1), sizeof(struct lpfc_queue *), GFP_KERNEL); if (!phba->sli4_hba.cq_lookup) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0549 Failed setup of CQ Lookup table: " "size 0x%x\n", phba->sli4_hba.cq_max); rc = -ENOMEM; @@ -10041,26 +11642,28 @@ lpfc_sli4_cq_event_release(struct lpfc_hba *phba, static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba) { - LIST_HEAD(cqelist); - struct lpfc_cq_event *cqe; + LIST_HEAD(cq_event_list); + struct lpfc_cq_event *cq_event; unsigned long iflags; /* Retrieve all the pending WCQEs from pending WCQE lists */ - spin_lock_irqsave(&phba->hbalock, iflags); - /* Pending FCP XRI abort events */ - list_splice_init(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue, - &cqelist); + /* Pending ELS XRI abort events */ + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); list_splice_init(&phba->sli4_hba.sp_els_xri_aborted_work_queue, - &cqelist); + &cq_event_list); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); + /* Pending asynnc events */ + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); list_splice_init(&phba->sli4_hba.sp_asynce_work_queue, - &cqelist); - spin_unlock_irqrestore(&phba->hbalock, iflags); + &cq_event_list); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); - while (!list_empty(&cqelist)) { - list_remove_head(&cqelist, cqe, struct lpfc_cq_event, list); - lpfc_sli4_cq_event_release(phba, cqe); + while (!list_empty(&cq_event_list)) { + list_remove_head(&cq_event_list, cq_event, + struct lpfc_cq_event, list); + lpfc_sli4_cq_event_release(phba, cq_event); } } @@ -10094,7 +11697,7 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0494 Unable to allocate memory for " "issuing SLI_FUNCTION_RESET mailbox " "command\n"); @@ -10111,10 +11714,9 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); + mempool_free(mboxq, phba->mbox_mem_pool); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0495 SLI_FUNCTION_RESET mailbox " "failed with status x%x add_status x%x," " mbx status x%x\n", @@ -10146,7 +11748,7 @@ wait: phba->sli4_hba.u.if_type2.ERR1regaddr); phba->work_status[1] = readl( phba->sli4_hba.u.if_type2.ERR2regaddr); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2890 Port not ready, port status reg " "0x%x error 1=0x%x, error 2=0x%x\n", reg_data.word0, @@ -10156,6 +11758,9 @@ wait: goto out; } + if (bf_get(lpfc_sliport_status_pldv, ®_data)) + lpfc_pldv_detect = true; + if (!port_reset) { /* * Reset the port now @@ -10188,7 +11793,7 @@ wait: out: /* Catch the not-ready port failure after a port reset. */ if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3317 HBA not functional: IP Reset Failed " "try: echo fw_reset > board_mode\n"); rc = -ENODEV; @@ -10513,7 +12118,7 @@ lpfc_sli_enable_msix(struct lpfc_hba *phba) if (!pmb) { rc = -ENOMEM; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0474 Unable to allocate memory for issuing " "MBOX_CONFIG_MSI command\n"); goto mem_fail_out; @@ -10576,7 +12181,7 @@ lpfc_sli_enable_msi(struct lpfc_hba *phba) rc = pci_enable_msi(phba->pcidev); if (!rc) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0462 PCI enable MSI mode success.\n"); + "0012 PCI enable MSI mode success.\n"); else { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0471 PCI enable MSI mode failed (%d)\n", rc); @@ -10596,6 +12201,7 @@ lpfc_sli_enable_msi(struct lpfc_hba *phba) /** * lpfc_sli_enable_intr - Enable device interrupt to SLI-3 device. * @phba: pointer to lpfc hba data structure. + * @cfg_mode: Interrupt configuration mode (INTx, MSI or MSI-X). * * This routine is invoked to enable device interrupt and associate driver's * interrupt handler(s) to interrupt vector(s) to device with SLI-3 interface @@ -10615,17 +12221,19 @@ lpfc_sli_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) uint32_t intr_mode = LPFC_INTR_ERROR; int retval; + /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ + retval = lpfc_sli_config_port(phba, LPFC_SLI_REV3); + if (retval) + return intr_mode; + phba->hba_flag &= ~HBA_NEEDS_CFG_PORT; + if (cfg_mode == 2) { - /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ - retval = lpfc_sli_config_port(phba, LPFC_SLI_REV3); + /* Now, try to enable MSI-X interrupt mode */ + retval = lpfc_sli_enable_msix(phba); if (!retval) { - /* Now, try to enable MSI-X interrupt mode */ - retval = lpfc_sli_enable_msix(phba); - if (!retval) { - /* Indicate initialization to MSI-X mode */ - phba->intr_type = MSIX; - intr_mode = 2; - } + /* Indicate initialization to MSI-X mode */ + phba->intr_type = MSIX; + intr_mode = 2; } } @@ -10805,7 +12413,7 @@ lpfc_hba_eq_hdl_array_init(struct lpfc_hba *phba) for (i = 0; i < phba->cfg_irq_chann; i++) { eqhdl = lpfc_get_eq_hdl(i); - eqhdl->irq = LPFC_VECTOR_MAP_EMPTY; + eqhdl->irq = LPFC_IRQ_EMPTY; eqhdl->phba = phba; } } @@ -10831,6 +12439,9 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) #ifdef CONFIG_X86 struct cpuinfo_x86 *cpuinfo; #endif +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + struct lpfc_hdwq_stat *c_stat; +#endif max_phys_id = 0; min_phys_id = LPFC_VECTOR_MAP_EMPTY; @@ -10990,7 +12601,7 @@ found_any: /* 1 to 1, the first LPFC_CPU_FIRST_IRQ cpus to a unique hdwq */ cpup->hdwq = idx; idx++; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3333 Set Affinity: CPU %d (phys %d core %d): " "hdwq %d eq %d flg x%x\n", cpu, cpup->phys_id, cpup->core_id, @@ -11068,7 +12679,7 @@ found_any: start_cpu = first_cpu; cpup->hdwq = new_cpup->hdwq; logit: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3335 Set Affinity: CPU %d (phys %d core %d): " "hdwq %d eq %d flg x%x\n", cpu, cpup->phys_id, cpup->core_id, @@ -11082,10 +12693,17 @@ found_any: idx = 0; for_each_possible_cpu(cpu) { cpup = &phba->sli4_hba.cpu_map[cpu]; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + c_stat = per_cpu_ptr(phba->sli4_hba.c_stat, cpu); + c_stat->hdwq_no = cpup->hdwq; +#endif if (cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) continue; cpup->hdwq = idx++ % phba->cfg_hdw_queue; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + c_stat->hdwq_no = cpup->hdwq; +#endif lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3340 Set Affinity: not present " "CPU %d hdwq %d\n", @@ -11103,17 +12721,21 @@ found_any: * * @phba: pointer to lpfc hba data structure. * @cpu: cpu going offline - * @eqlist: + * @eqlist: eq list to append to */ -static void +static int lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, struct list_head *eqlist) { const struct cpumask *maskp; struct lpfc_queue *eq; - cpumask_t tmp; + struct cpumask *tmp; u16 idx; + tmp = kzalloc(cpumask_size(), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + for (idx = 0; idx < phba->cfg_irq_chann; idx++) { maskp = pci_irq_get_affinity(phba->pcidev, idx); if (!maskp) @@ -11123,7 +12745,7 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, * then we don't need to poll the eq attached * to it. */ - if (!cpumask_and(&tmp, maskp, cpumask_of(cpu))) + if (!cpumask_and(tmp, maskp, cpumask_of(cpu))) continue; /* get the cpus that are online and are affini- * tized to this irq vector. If the count is @@ -11131,8 +12753,8 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, * down this vector. Since this cpu has not * gone offline yet, we need >1. */ - cpumask_and(&tmp, maskp, cpu_online_mask); - if (cpumask_weight(&tmp) > 1) + cpumask_and(tmp, maskp, cpu_online_mask); + if (cpumask_weight(tmp) > 1) continue; /* Now that we have an irq to shutdown, get the eq @@ -11143,6 +12765,8 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, eq = phba->sli4_hba.hba_eq_hdl[idx].eq; list_add(&eq->_poll_list, eqlist); } + kfree(tmp); + return 0; } static void __lpfc_cpuhp_remove(struct lpfc_hba *phba) @@ -11162,7 +12786,7 @@ static void __lpfc_cpuhp_remove(struct lpfc_hba *phba) static void lpfc_cpuhp_remove(struct lpfc_hba *phba) { - if (phba->pport->fc_flag & FC_OFFLINE_MODE) + if (phba->pport && (phba->pport->fc_flag & FC_OFFLINE_MODE)) return; __lpfc_cpuhp_remove(phba); @@ -11175,11 +12799,9 @@ static void lpfc_cpuhp_add(struct lpfc_hba *phba) rcu_read_lock(); - if (!list_empty(&phba->poll_list)) { - timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0); + if (!list_empty(&phba->poll_list)) mod_timer(&phba->cpuhp_poll_timer, jiffies + msecs_to_jiffies(LPFC_POLL_HB)); - } rcu_read_unlock(); @@ -11215,7 +12837,7 @@ lpfc_irq_set_aff(struct lpfc_hba_eq_hdl *eqhdl, unsigned int cpu) cpumask_clear(&eqhdl->aff_mask); cpumask_set_cpu(cpu, &eqhdl->aff_mask); irq_set_status_flags(eqhdl->irq, IRQ_NO_BALANCING); - irq_set_affinity_hint(eqhdl->irq, &eqhdl->aff_mask); + irq_set_affinity(eqhdl->irq, &eqhdl->aff_mask); } /** @@ -11228,7 +12850,6 @@ lpfc_irq_clear_aff(struct lpfc_hba_eq_hdl *eqhdl) { cpumask_clear(&eqhdl->aff_mask); irq_clear_status_flags(eqhdl->irq, IRQ_NO_BALANCING); - irq_set_affinity_hint(eqhdl->irq, &eqhdl->aff_mask); } /** @@ -11238,11 +12859,12 @@ lpfc_irq_clear_aff(struct lpfc_hba_eq_hdl *eqhdl) * @offline: true, cpu is going offline. false, cpu is coming online. * * If cpu is going offline, we'll try our best effort to find the next - * online cpu on the phba's NUMA node and migrate all offlining IRQ affinities. + * online cpu on the phba's original_mask and migrate all offlining IRQ + * affinities. * - * If cpu is coming online, reaffinitize the IRQ back to the onlineng cpu. + * If cpu is coming online, reaffinitize the IRQ back to the onlining cpu. * - * Note: Call only if cfg_irq_numa is enabled, otherwise rely on + * Note: Call only if NUMA or NHT mode is enabled, otherwise rely on * PCI_IRQ_AFFINITY to auto-manage IRQ affinity. * **/ @@ -11252,14 +12874,14 @@ lpfc_irq_rebalance(struct lpfc_hba *phba, unsigned int cpu, bool offline) struct lpfc_vector_map_info *cpup; struct cpumask *aff_mask; unsigned int cpu_select, cpu_next, idx; - const struct cpumask *numa_mask; + const struct cpumask *orig_mask; - if (!phba->cfg_irq_numa) + if (phba->irq_chann_mode == NORMAL_MODE) return; - numa_mask = &phba->sli4_hba.numa_mask; + orig_mask = &phba->sli4_hba.irq_aff_mask; - if (!cpumask_test_cpu(cpu, numa_mask)) + if (!cpumask_test_cpu(cpu, orig_mask)) return; cpup = &phba->sli4_hba.cpu_map[cpu]; @@ -11268,9 +12890,9 @@ lpfc_irq_rebalance(struct lpfc_hba *phba, unsigned int cpu, bool offline) return; if (offline) { - /* Find next online CPU on NUMA node */ - cpu_next = cpumask_next_wrap(cpu, numa_mask, cpu, true); - cpu_select = lpfc_next_online_numa_cpu(numa_mask, cpu_next); + /* Find next online CPU on original mask */ + cpu_next = cpumask_next_wrap(cpu, orig_mask, cpu, true); + cpu_select = lpfc_next_online_cpu(orig_mask, cpu_next); /* Found a valid CPU */ if ((cpu_select < nr_cpu_ids) && (cpu_select != cpu)) { @@ -11313,7 +12935,9 @@ static int lpfc_cpu_offline(unsigned int cpu, struct hlist_node *node) lpfc_irq_rebalance(phba, cpu, true); - lpfc_cpuhp_get_eq(phba, cpu, &eqlist); + retval = lpfc_cpuhp_get_eq(phba, cpu, &eqlist); + if (retval) + return retval; /* start polling on these eq's */ list_for_each_entry_safe(eq, next, &eqlist, _poll_list) { @@ -11383,26 +13007,28 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) { int vectors, rc, index; char *name; - const struct cpumask *numa_mask = NULL; + const struct cpumask *aff_mask = NULL; unsigned int cpu = 0, cpu_cnt = 0, cpu_select = nr_cpu_ids; + struct lpfc_vector_map_info *cpup; struct lpfc_hba_eq_hdl *eqhdl; const struct cpumask *maskp; - bool first; unsigned int flags = PCI_IRQ_MSIX; /* Set up MSI-X multi-message vectors */ vectors = phba->cfg_irq_chann; - if (phba->cfg_irq_numa) { - numa_mask = &phba->sli4_hba.numa_mask; - cpu_cnt = cpumask_weight(numa_mask); + if (phba->irq_chann_mode != NORMAL_MODE) + aff_mask = &phba->sli4_hba.irq_aff_mask; + + if (aff_mask) { + cpu_cnt = cpumask_weight(aff_mask); vectors = min(phba->cfg_irq_chann, cpu_cnt); - /* cpu: iterates over numa_mask including offline or online - * cpu_select: iterates over online numa_mask to set affinity + /* cpu: iterates over aff_mask including offline or online + * cpu_select: iterates over online aff_mask to set affinity */ - cpu = cpumask_first(numa_mask); - cpu_select = lpfc_next_online_numa_cpu(numa_mask, cpu); + cpu = cpumask_first(aff_mask); + cpu_select = lpfc_next_online_cpu(aff_mask, cpu); } else { flags |= PCI_IRQ_AFFINITY; } @@ -11424,9 +13050,17 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) LPFC_DRIVER_HANDLER_NAME"%d", index); eqhdl->idx = index; - rc = request_irq(pci_irq_vector(phba->pcidev, index), - &lpfc_sli4_hba_intr_handler, 0, - name, eqhdl); + rc = pci_irq_vector(phba->pcidev, index); + if (rc < 0) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0489 MSI-X fast-path (%d) " + "pci_irq_vec failed (%d)\n", index, rc); + goto cfg_fail_out; + } + eqhdl->irq = rc; + + rc = request_irq(eqhdl->irq, &lpfc_sli4_hba_intr_handler, 0, + name, eqhdl); if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0486 MSI-X fast-path (%d) " @@ -11434,9 +13068,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) goto cfg_fail_out; } - eqhdl->irq = pci_irq_vector(phba->pcidev, index); - - if (phba->cfg_irq_numa) { + if (aff_mask) { /* If found a neighboring online cpu, set affinity */ if (cpu_select < nr_cpu_ids) lpfc_irq_set_aff(eqhdl, cpu_select); @@ -11446,11 +13078,11 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) LPFC_CPU_FIRST_IRQ, cpu); - /* Iterate to next offline or online cpu in numa_mask */ - cpu = cpumask_next(cpu, numa_mask); + /* Iterate to next offline or online cpu in aff_mask */ + cpu = cpumask_next(cpu, aff_mask); - /* Find next online cpu in numa_mask to set affinity */ - cpu_select = lpfc_next_online_numa_cpu(numa_mask, cpu); + /* Find next online cpu in aff_mask to set affinity */ + cpu_select = lpfc_next_online_cpu(aff_mask, cpu); } else if (vectors == 1) { cpu = cpumask_first(cpu_present_mask); lpfc_assign_eq_map_info(phba, index, LPFC_CPU_FIRST_IRQ, @@ -11458,24 +13090,34 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) } else { maskp = pci_irq_get_affinity(phba->pcidev, index); - first = true; /* Loop through all CPUs associated with vector index */ for_each_cpu_and(cpu, maskp, cpu_present_mask) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + /* If this is the first CPU thats assigned to * this vector, set LPFC_CPU_FIRST_IRQ. + * + * With certain platforms its possible that irq + * vectors are affinitized to all the cpu's. + * This can result in each cpu_map.eq to be set + * to the last vector, resulting in overwrite + * of all the previous cpu_map.eq. Ensure that + * each vector receives a place in cpu_map. + * Later call to lpfc_cpu_affinity_check will + * ensure we are nicely balanced out. */ + if (cpup->eq != LPFC_VECTOR_MAP_EMPTY) + continue; lpfc_assign_eq_map_info(phba, index, - first ? - LPFC_CPU_FIRST_IRQ : 0, + LPFC_CPU_FIRST_IRQ, cpu); - if (first) - first = false; + break; } } } if (vectors != phba->cfg_irq_chann) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3238 Reducing IO channels to match number of " "MSI-X vectors, requested %d got %d\n", phba->cfg_irq_chann, vectors); @@ -11490,7 +13132,6 @@ cfg_fail_out: for (--index; index >= 0; index--) { eqhdl = lpfc_get_eq_hdl(index); lpfc_irq_clear_aff(eqhdl); - irq_set_affinity_hint(eqhdl->irq, NULL); free_irq(eqhdl->irq, eqhdl); } @@ -11543,7 +13184,14 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) } eqhdl = lpfc_get_eq_hdl(0); - eqhdl->irq = pci_irq_vector(phba->pcidev, 0); + rc = pci_irq_vector(phba->pcidev, 0); + if (rc < 0) { + pci_free_irq_vectors(phba->pcidev); + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0496 MSI pci_irq_vec failed (%d)\n", rc); + return rc; + } + eqhdl->irq = rc; cpu = cpumask_first(cpu_present_mask); lpfc_assign_eq_map_info(phba, 0, LPFC_CPU_FIRST_IRQ, cpu); @@ -11559,6 +13207,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) /** * lpfc_sli4_enable_intr - Enable device interrupt to SLI-4 device * @phba: pointer to lpfc hba data structure. + * @cfg_mode: Interrupt configuration mode (INTx, MSI or MSI-X). * * This routine is invoked to enable device interrupt and associate driver's * interrupt handler(s) to interrupt vector(s) to device with SLI-4 @@ -11569,8 +13218,8 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) * MSI-X -> MSI -> IRQ. * * Return codes - * 0 - successful - * other values - error + * Interrupt mode (2, 1, 0) - successful + * LPFC_INTR_ERROR - error **/ static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) @@ -11615,7 +13264,14 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) intr_mode = 0; eqhdl = lpfc_get_eq_hdl(0); - eqhdl->irq = pci_irq_vector(phba->pcidev, 0); + retval = pci_irq_vector(phba->pcidev, 0); + if (retval < 0) { + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0502 INTR pci_irq_vec failed (%d)\n", + retval); + return LPFC_INTR_ERROR; + } + eqhdl->irq = retval; cpu = cpumask_first(cpu_present_mask); lpfc_assign_eq_map_info(phba, 0, LPFC_CPU_FIRST_IRQ, @@ -11650,7 +13306,6 @@ lpfc_sli4_disable_intr(struct lpfc_hba *phba) for (index = 0; index < phba->cfg_irq_chann; index++) { eqhdl = lpfc_get_eq_hdl(index); lpfc_irq_clear_aff(eqhdl); - irq_set_affinity_hint(eqhdl->irq, NULL); free_irq(eqhdl->irq, eqhdl); } } else { @@ -11748,17 +13403,17 @@ lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba) while (!els_xri_cmpl || !io_xri_cmpl || !nvmet_xri_cmpl) { if (wait_time > LPFC_XRI_EXCH_BUSY_WAIT_TMO) { if (!nvmet_xri_cmpl) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6424 NVMET XRI exchange busy " "wait time: %d seconds.\n", wait_time/1000); if (!io_xri_cmpl) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6100 IO XRI exchange busy " "wait time: %d seconds.\n", wait_time/1000); if (!els_xri_cmpl) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2878 ELS XRI exchange busy " "wait time: %d seconds.\n", wait_time/1000); @@ -11808,6 +13463,8 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) struct pci_dev *pdev = phba->pcidev; lpfc_stop_hba_timers(phba); + hrtimer_cancel(&phba->cmf_timer); + if (phba->pport) phba->sli4_hba.intr_enable = 0; @@ -11840,11 +13497,13 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) /* Abort all iocbs associated with the hba */ lpfc_sli_hba_iocb_abort(phba); - /* Wait for completion of device XRI exchange busy */ - lpfc_sli4_xri_exchange_busy_wait(phba); + if (!pci_channel_offline(phba->pcidev)) + /* Wait for completion of device XRI exchange busy */ + lpfc_sli4_xri_exchange_busy_wait(phba); /* per-phba callback de-registration for hotplug event */ - lpfc_cpuhp_remove(phba); + if (phba->pport) + lpfc_cpuhp_remove(phba); /* Disable PCI subsystem interrupt */ lpfc_sli4_disable_intr(phba); @@ -11859,15 +13518,12 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) /* Disable FW logging to host memory */ lpfc_ras_stop_fwlog(phba); - /* Unset the queues shared with the hardware then release all - * allocated resources. - */ - lpfc_sli4_queue_unset(phba); - lpfc_sli4_queue_destroy(phba); - /* Reset SLI4 HBA FCoE function */ lpfc_pci_function_reset(phba); + /* release all queue allocated resources. */ + lpfc_sli4_queue_destroy(phba); + /* Free RAS DMA memory */ if (phba->ras_fwlog.ras_enabled) lpfc_sli4_ras_dma_free(phba); @@ -11877,76 +13533,236 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) phba->pport->work_port_events = 0; } - /** - * lpfc_pc_sli4_params_get - Get the SLI4_PARAMS port capabilities. - * @phba: Pointer to HBA context object. - * @mboxq: Pointer to the mailboxq memory for the mailbox command response. - * - * This function is called in the SLI4 code path to read the port's - * sli4 capabilities. - * - * This function may be be called from any context that can block-wait - * for the completion. The expectation is that this routine is called - * typically from probe_one or from the online routine. - **/ -int -lpfc_pc_sli4_params_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) +static uint32_t +lpfc_cgn_crc32(uint32_t crc, u8 byte) { - int rc; - struct lpfc_mqe *mqe; - struct lpfc_pc_sli4_params *sli4_params; - uint32_t mbox_tmo; + uint32_t msb = 0; + uint32_t bit; - rc = 0; - mqe = &mboxq->u.mqe; + for (bit = 0; bit < 8; bit++) { + msb = (crc >> 31) & 1; + crc <<= 1; - /* Read the port's SLI4 Parameters port capabilities */ - lpfc_pc_sli4_params(mboxq); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); + if (msb ^ (byte & 1)) { + crc ^= LPFC_CGN_CRC32_MAGIC_NUMBER; + crc |= 1; + } + byte >>= 1; } + return crc; +} - if (unlikely(rc)) - return 1; +static uint32_t +lpfc_cgn_reverse_bits(uint32_t wd) +{ + uint32_t result = 0; + uint32_t i; - sli4_params = &phba->sli4_hba.pc_sli4_params; - sli4_params->if_type = bf_get(if_type, &mqe->un.sli4_params); - sli4_params->sli_rev = bf_get(sli_rev, &mqe->un.sli4_params); - sli4_params->sli_family = bf_get(sli_family, &mqe->un.sli4_params); - sli4_params->featurelevel_1 = bf_get(featurelevel_1, - &mqe->un.sli4_params); - sli4_params->featurelevel_2 = bf_get(featurelevel_2, - &mqe->un.sli4_params); - sli4_params->proto_types = mqe->un.sli4_params.word3; - sli4_params->sge_supp_len = mqe->un.sli4_params.sge_supp_len; - sli4_params->if_page_sz = bf_get(if_page_sz, &mqe->un.sli4_params); - sli4_params->rq_db_window = bf_get(rq_db_window, &mqe->un.sli4_params); - sli4_params->loopbk_scope = bf_get(loopbk_scope, &mqe->un.sli4_params); - sli4_params->eq_pages_max = bf_get(eq_pages, &mqe->un.sli4_params); - sli4_params->eqe_size = bf_get(eqe_size, &mqe->un.sli4_params); - sli4_params->cq_pages_max = bf_get(cq_pages, &mqe->un.sli4_params); - sli4_params->cqe_size = bf_get(cqe_size, &mqe->un.sli4_params); - sli4_params->mq_pages_max = bf_get(mq_pages, &mqe->un.sli4_params); - sli4_params->mqe_size = bf_get(mqe_size, &mqe->un.sli4_params); - sli4_params->mq_elem_cnt = bf_get(mq_elem_cnt, &mqe->un.sli4_params); - sli4_params->wq_pages_max = bf_get(wq_pages, &mqe->un.sli4_params); - sli4_params->wqe_size = bf_get(wqe_size, &mqe->un.sli4_params); - sli4_params->rq_pages_max = bf_get(rq_pages, &mqe->un.sli4_params); - sli4_params->rqe_size = bf_get(rqe_size, &mqe->un.sli4_params); - sli4_params->hdr_pages_max = bf_get(hdr_pages, &mqe->un.sli4_params); - sli4_params->hdr_size = bf_get(hdr_size, &mqe->un.sli4_params); - sli4_params->hdr_pp_align = bf_get(hdr_pp_align, &mqe->un.sli4_params); - sli4_params->sgl_pages_max = bf_get(sgl_pages, &mqe->un.sli4_params); - sli4_params->sgl_pp_align = bf_get(sgl_pp_align, &mqe->un.sli4_params); + for (i = 0; i < 32; i++) { + result <<= 1; + result |= (1 & (wd >> i)); + } + return result; +} - /* Make sure that sge_supp_len can be handled by the driver */ - if (sli4_params->sge_supp_len > LPFC_MAX_SGE_SIZE) - sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE; +/* + * The routine corresponds with the algorithm the HBA firmware + * uses to validate the data integrity. + */ +uint32_t +lpfc_cgn_calc_crc32(void *ptr, uint32_t byteLen, uint32_t crc) +{ + uint32_t i; + uint32_t result; + uint8_t *data = (uint8_t *)ptr; - return rc; + for (i = 0; i < byteLen; ++i) + crc = lpfc_cgn_crc32(crc, data[i]); + + result = ~lpfc_cgn_reverse_bits(crc); + return result; +} + +void +lpfc_init_congestion_buf(struct lpfc_hba *phba) +{ + struct lpfc_cgn_info *cp; + struct timespec64 cmpl_time; + struct tm broken; + uint16_t size; + uint32_t crc; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6235 INIT Congestion Buffer %p\n", phba->cgn_i); + + if (!phba->cgn_i) + return; + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + + atomic_set(&phba->cgn_fabric_warn_cnt, 0); + atomic_set(&phba->cgn_fabric_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_warn_cnt, 0); + + atomic_set(&phba->cgn_driver_evt_cnt, 0); + atomic_set(&phba->cgn_latency_evt_cnt, 0); + atomic64_set(&phba->cgn_latency_evt, 0); + phba->cgn_evt_minute = 0; + phba->hba_flag &= ~HBA_CGN_DAY_WRAP; + + memset(cp, 0xff, offsetof(struct lpfc_cgn_info, cgn_stat)); + cp->cgn_info_size = cpu_to_le16(LPFC_CGN_INFO_SZ); + cp->cgn_info_version = LPFC_CGN_INFO_V3; + + /* cgn parameters */ + cp->cgn_info_mode = phba->cgn_p.cgn_param_mode; + cp->cgn_info_level0 = phba->cgn_p.cgn_param_level0; + cp->cgn_info_level1 = phba->cgn_p.cgn_param_level1; + cp->cgn_info_level2 = phba->cgn_p.cgn_param_level2; + + ktime_get_real_ts64(&cmpl_time); + time64_to_tm(cmpl_time.tv_sec, 0, &broken); + + cp->cgn_info_month = broken.tm_mon + 1; + cp->cgn_info_day = broken.tm_mday; + cp->cgn_info_year = broken.tm_year - 100; /* relative to 2000 */ + cp->cgn_info_hour = broken.tm_hour; + cp->cgn_info_minute = broken.tm_min; + cp->cgn_info_second = broken.tm_sec; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT, + "2643 CGNInfo Init: Start Time " + "%d/%d/%d %d:%d:%d\n", + cp->cgn_info_day, cp->cgn_info_month, + cp->cgn_info_year, cp->cgn_info_hour, + cp->cgn_info_minute, cp->cgn_info_second); + + /* Fill in default LUN qdepth */ + if (phba->pport) { + size = (uint16_t)(phba->pport->cfg_lun_queue_depth); + cp->cgn_lunq = cpu_to_le16(size); + } + + /* last used Index initialized to 0xff already */ + + cp->cgn_warn_freq = cpu_to_le16(LPFC_FPIN_INIT_FREQ); + cp->cgn_alarm_freq = cpu_to_le16(LPFC_FPIN_INIT_FREQ); + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); + + phba->cgn_evt_timestamp = jiffies + + msecs_to_jiffies(LPFC_CGN_TIMER_TO_MIN); +} + +void +lpfc_init_congestion_stat(struct lpfc_hba *phba) +{ + struct lpfc_cgn_info *cp; + struct timespec64 cmpl_time; + struct tm broken; + uint32_t crc; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6236 INIT Congestion Stat %p\n", phba->cgn_i); + + if (!phba->cgn_i) + return; + + cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; + memset(&cp->cgn_stat, 0, sizeof(cp->cgn_stat)); + + ktime_get_real_ts64(&cmpl_time); + time64_to_tm(cmpl_time.tv_sec, 0, &broken); + + cp->cgn_stat_month = broken.tm_mon + 1; + cp->cgn_stat_day = broken.tm_mday; + cp->cgn_stat_year = broken.tm_year - 100; /* relative to 2000 */ + cp->cgn_stat_hour = broken.tm_hour; + cp->cgn_stat_minute = broken.tm_min; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT, + "2647 CGNstat Init: Start Time " + "%d/%d/%d %d:%d\n", + cp->cgn_stat_day, cp->cgn_stat_month, + cp->cgn_stat_year, cp->cgn_stat_hour, + cp->cgn_stat_minute); + + crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED); + cp->cgn_info_crc = cpu_to_le32(crc); +} + +/** + * __lpfc_reg_congestion_buf - register congestion info buffer with HBA + * @phba: Pointer to hba context object. + * @reg: flag to determine register or unregister. + */ +static int +__lpfc_reg_congestion_buf(struct lpfc_hba *phba, int reg) +{ + struct lpfc_mbx_reg_congestion_buf *reg_congestion_buf; + union lpfc_sli4_cfg_shdr *shdr; + uint32_t shdr_status, shdr_add_status; + LPFC_MBOXQ_t *mboxq; + int length, rc; + + if (!phba->cgn_i) + return -ENXIO; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "2641 REG_CONGESTION_BUF mbox allocation fail: " + "HBA state x%x reg %d\n", + phba->pport->port_state, reg); + return -ENOMEM; + } + + length = (sizeof(struct lpfc_mbx_reg_congestion_buf) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_REG_CONGESTION_BUF, length, + LPFC_SLI4_MBX_EMBED); + reg_congestion_buf = &mboxq->u.mqe.un.reg_congestion_buf; + bf_set(lpfc_mbx_reg_cgn_buf_type, reg_congestion_buf, 1); + if (reg > 0) + bf_set(lpfc_mbx_reg_cgn_buf_cnt, reg_congestion_buf, 1); + else + bf_set(lpfc_mbx_reg_cgn_buf_cnt, reg_congestion_buf, 0); + reg_congestion_buf->length = sizeof(struct lpfc_cgn_info); + reg_congestion_buf->addr_lo = + putPaddrLow(phba->cgn_i->phys); + reg_congestion_buf->addr_hi = + putPaddrHigh(phba->cgn_i->phys); + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + shdr = (union lpfc_sli4_cfg_shdr *) + &mboxq->u.mqe.un.sli4_config.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, + &shdr->response); + mempool_free(mboxq, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2642 REG_CONGESTION_BUF mailbox " + "failed with status x%x add_status x%x," + " mbx status x%x reg %d\n", + shdr_status, shdr_add_status, rc, reg); + return -ENXIO; + } + return 0; +} + +int +lpfc_unreg_congestion_buf(struct lpfc_hba *phba) +{ + lpfc_cmf_stop(phba); + return __lpfc_reg_congestion_buf(phba, 0); +} + +int +lpfc_reg_congestion_buf(struct lpfc_hba *phba) +{ + return __lpfc_reg_congestion_buf(phba, 1); } /** @@ -12007,7 +13823,8 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) else phba->sli3_options &= ~LPFC_SLI4_PHWQ_ENABLED; sli4_params->sge_supp_len = mbx_sli4_parameters->sge_supp_len; - sli4_params->loopbk_scope = bf_get(loopbk_scope, mbx_sli4_parameters); + sli4_params->loopbk_scope = bf_get(cfg_loopbk_scope, + mbx_sli4_parameters); sli4_params->oas_supported = bf_get(cfg_oas, mbx_sli4_parameters); sli4_params->cqv = bf_get(cfg_cqv, mbx_sli4_parameters); sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters); @@ -12056,7 +13873,6 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) bf_get(cfg_xib, mbx_sli4_parameters), phba->cfg_enable_fc4_type); fcponly: - phba->nvme_support = 0; phba->nvmet_support = 0; phba->cfg_nvmet_mrq = 0; phba->cfg_nvme_seg_cnt = 0; @@ -12074,9 +13890,10 @@ fcponly: if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) phba->cfg_sg_seg_cnt = LPFC_MAX_NVME_SEG_CNT; - /* Only embed PBDE for if_type 6, PBDE support requires xib be set */ - if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_6) || (!bf_get(cfg_xib, mbx_sli4_parameters))) + /* Enable embedded Payload BDE if support is indicated */ + if (bf_get(cfg_pbde, mbx_sli4_parameters)) + phba->cfg_enable_pbde = 1; + else phba->cfg_enable_pbde = 0; /* @@ -12114,7 +13931,7 @@ fcponly: "6422 XIB %d PBDE %d: FCP %d NVME %d %d %d\n", bf_get(cfg_xib, mbx_sli4_parameters), phba->cfg_enable_pbde, - phba->fcp_embed_io, phba->nvme_support, + phba->fcp_embed_io, sli4_params->nvme, phba->cfg_nvme_embed_cmd, phba->cfg_suppress_rsp); if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == @@ -12252,14 +14069,14 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) /* Configure and enable interrupt */ intr_mode = lpfc_sli_enable_intr(phba, cfg_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0431 Failed to enable interrupt.\n"); error = -ENODEV; goto out_free_sysfs_attr; } /* SLI-3 HBA setup */ if (lpfc_sli_hba_setup(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1477 Failed to set up hba\n"); error = -ENODEV; goto out_remove_device; @@ -12351,10 +14168,11 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) } lpfc_destroy_vport_work_array(phba, vports); - /* Remove FC host and then SCSI host with the physical port */ + /* Remove FC host with the physical port */ fc_remove_host(shost); scsi_remove_host(shost); + /* Clean up all nodes, mailboxes and IOs. */ lpfc_cleanup(vport); /* @@ -12417,8 +14235,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) /** * lpfc_pci_suspend_one_s3 - PCI func to suspend SLI-3 device for power mgmnt - * @pdev: pointer to PCI device - * @msg: power management message + * @dev_d: pointer to device * * This routine is to be called from the kernel's PCI subsystem to support * system Power Management (PM) to device with SLI-3 interface spec. When @@ -12436,10 +14253,10 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg) +static int __maybe_unused +lpfc_pci_suspend_one_s3(struct device *dev_d) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev_d); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -12453,16 +14270,12 @@ lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg) /* Disable interrupt from device */ lpfc_sli_disable_intr(phba); - /* Save device state to PCI config space */ - pci_save_state(pdev); - pci_set_power_state(pdev, PCI_D3hot); - return 0; } /** * lpfc_pci_resume_one_s3 - PCI func to resume SLI-3 device for power mgmnt - * @pdev: pointer to PCI device + * @dev_d: pointer to device * * This routine is to be called from the kernel's PCI subsystem to support * system Power Management (PM) to device with SLI-3 interface spec. When PM @@ -12479,10 +14292,10 @@ lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_resume_one_s3(struct pci_dev *pdev) +static int __maybe_unused +lpfc_pci_resume_one_s3(struct device *dev_d) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev_d); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; uint32_t intr_mode; int error; @@ -12490,19 +14303,6 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0452 PCI device Power Management resume.\n"); - /* Restore device state from PCI config space */ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - /* - * As the new kernel behavior of pci_restore_state() API call clears - * device saved_state flag, need to save the restored state again. - */ - pci_save_state(pdev); - - if (pdev->is_busmaster) - pci_set_master(pdev); - /* Startup the kernel thread for this host adapter. */ phba->worker_thread = kthread_run(lpfc_do_work, phba, "lpfc_worker_%d", phba->brd_no); @@ -12514,10 +14314,14 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) return error; } + /* Init cpu_map array */ + lpfc_cpu_map_array_init(phba); + /* Init hba_eq_hdl array */ + lpfc_hba_eq_hdl_array_init(phba); /* Configure and enable interrupt */ intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0430 PM resume Failed to enable interrupt\n"); return -EIO; } else @@ -12543,7 +14347,7 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) static void lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2723 PCI channel I/O abort preparing for recovery\n"); /* @@ -12564,7 +14368,7 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) static void lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2710 PCI channel disable preparing for reset\n"); /* Block any management I/Os to the device */ @@ -12595,10 +14399,11 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) static void lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2711 PCI channel permanent disable for failure\n"); /* Block all SCSI devices' I/Os on the host */ lpfc_scsi_dev_block(phba); + lpfc_sli4_prep_dev_for_reset(phba); /* stop all timers */ lpfc_stop_hba_timers(phba); @@ -12646,7 +14451,7 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_DISCONNECT; default: /* Unknown state, prepare and request slot reset */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0472 Unknown PCI error state: x%x\n", state); lpfc_sli_prep_dev_for_reset(phba); return PCI_ERS_RESULT_NEED_RESET; @@ -12704,7 +14509,7 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev) /* Configure and enable interrupt */ intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0427 Cannot re-enable interrupt after " "slot reset.\n"); return PCI_ERS_RESULT_DISCONNECT; @@ -12795,7 +14600,9 @@ lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, const struct firmware *fw) { int rc; + u8 sli_family; + sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf); /* Three cases: (1) FW was not supported on the detected adapter. * (2) FW update has been locked out administratively. * (3) Some other error during FW update. @@ -12803,11 +14610,13 @@ lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, * for admin diagnosis. */ if (offset == ADD_STATUS_FW_NOT_SUPPORTED || - (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC && + (sli_family == LPFC_SLI_INTF_FAMILY_G6 && magic_number != MAGIC_NUMBER_G6) || - (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC && - magic_number != MAGIC_NUMBER_G7)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + (sli_family == LPFC_SLI_INTF_FAMILY_G7 && + magic_number != MAGIC_NUMBER_G7) || + (sli_family == LPFC_SLI_INTF_FAMILY_G7P && + magic_number != MAGIC_NUMBER_G7P)) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3030 This firmware version is not supported on" " this HBA model. Device:%x Magic:%x Type:%x " "ID:%x Size %d %zd\n", @@ -12815,7 +14624,7 @@ lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, fsize, fw->size); rc = -EINVAL; } else if (offset == ADD_STATUS_FW_DOWNLOAD_HW_DISABLED) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3021 Firmware downloads have been prohibited " "by a system configuration setting on " "Device:%x Magic:%x Type:%x ID:%x Size %d " @@ -12824,7 +14633,7 @@ lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, fsize, fw->size); rc = -EACCES; } else { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3022 FW Download failed. Add Status x%x " "Device:%x Magic:%x Type:%x ID:%x Size %d " "%zd\n", @@ -12839,7 +14648,6 @@ lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, * lpfc_write_firmware - attempt to write a firmware image to the port * @fw: pointer to firmware image returned from request_firmware. * @context: pointer to firmware image returned from request_firmware. - * @ret: return value this routine provides to the caller. * **/ static void @@ -12869,7 +14677,7 @@ lpfc_write_firmware(const struct firmware *fw, void *context) INIT_LIST_HEAD(&dma_buffer_list); lpfc_decode_firmware_rev(phba, fwrev, 1); if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3023 Updating Firmware, Current Version:%s " "New Version:%s\n", fwrev, image->revision); @@ -12919,7 +14727,7 @@ lpfc_write_firmware(const struct firmware *fw, void *context) } rc = offset; } else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3029 Skipped Firmware update, Current " "Version:%s New Version:%s\n", fwrev, image->revision); @@ -12934,16 +14742,17 @@ release_out: release_firmware(fw); out: if (rc < 0) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3062 Firmware update error, status %d.\n", rc); else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3024 Firmware update success: size %d.\n", rc); } /** * lpfc_sli4_request_firmware_update - Request linux generic firmware upgrade * @phba: pointer to lpfc hba data structure. + * @fw_upgrade: which firmware to update. * * This routine is called to perform Linux generic firmware upgrade on device * that supports such feature. @@ -12963,7 +14772,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) snprintf(file_name, ELX_MODEL_NAME_SIZE, "%s.grp", phba->ModelName); if (fw_upgrade == INT_FW_UPGRADE) { - ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, file_name, &phba->pcidev->dev, GFP_KERNEL, (void *)phba, lpfc_write_firmware); @@ -13010,6 +14819,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) if (!phba) return -ENOMEM; + INIT_LIST_HEAD(&phba->poll_list); + /* Perform generic PCI device enabling operation */ error = lpfc_enable_pci_dev(phba); if (error) @@ -13066,7 +14877,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Configure and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, cfg_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0426 Failed to enable interrupt.\n"); error = -ENODEV; goto out_unset_driver_resource; @@ -13101,7 +14912,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Set up SLI-4 HBA */ if (lpfc_sli4_hba_setup(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1421 Failed to set up hba\n"); error = -ENODEV; goto out_free_sysfs_attr; @@ -13126,7 +14937,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) */ error = lpfc_nvme_create_localport(vport); if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6004 NVME registration " "failed, error x%x\n", error); @@ -13141,10 +14952,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Check if there are static vports to be created. */ lpfc_create_static_vport(phba); - /* Enable RAS FW log support */ - lpfc_sli4_ras_setup(phba); - - INIT_LIST_HEAD(&phba->poll_list); + timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0); cpuhp_state_add_instance_nocalls(lpfc_cpuhp_state, &phba->cpuhp); return 0; @@ -13192,8 +15000,9 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) spin_lock_irq(&phba->hbalock); vport->load_flag |= FC_UNLOADING; spin_unlock_irq(&phba->hbalock); + if (phba->cgn_i) + lpfc_unreg_congestion_buf(phba); - /* Free the HBA sysfs attributes */ lpfc_free_sysfs_attr(vport); /* Release all the vports against this physical port */ @@ -13206,7 +15015,7 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) } lpfc_destroy_vport_work_array(phba, vports); - /* Remove FC host and then SCSI host with the physical port */ + /* Remove FC host with the physical port */ fc_remove_host(shost); scsi_remove_host(shost); @@ -13258,8 +15067,7 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) /** * lpfc_pci_suspend_one_s4 - PCI func to suspend SLI-4 device for power mgmnt - * @pdev: pointer to PCI device - * @msg: power management message + * @dev_d: pointer to device * * This routine is called from the kernel's PCI subsystem to support system * Power Management (PM) to device with SLI-4 interface spec. When PM invokes @@ -13277,10 +15085,10 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) +static int __maybe_unused +lpfc_pci_suspend_one_s4(struct device *dev_d) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev_d); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -13295,16 +15103,12 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) lpfc_sli4_disable_intr(phba); lpfc_sli4_queue_destroy(phba); - /* Save device state to PCI config space */ - pci_save_state(pdev); - pci_set_power_state(pdev, PCI_D3hot); - return 0; } /** * lpfc_pci_resume_one_s4 - PCI func to resume SLI-4 device for power mgmnt - * @pdev: pointer to PCI device + * @dev_d: pointer to device * * This routine is called from the kernel's PCI subsystem to support system * Power Management (PM) to device with SLI-4 interface spac. When PM invokes @@ -13321,10 +15125,10 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_resume_one_s4(struct pci_dev *pdev) +static int __maybe_unused +lpfc_pci_resume_one_s4(struct device *dev_d) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev_d); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; uint32_t intr_mode; int error; @@ -13332,19 +15136,6 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0292 PCI device Power Management resume.\n"); - /* Restore device state from PCI config space */ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - /* - * As the new kernel behavior of pci_restore_state() API call clears - * device saved_state flag, need to save the restored state again. - */ - pci_save_state(pdev); - - if (pdev->is_busmaster) - pci_set_master(pdev); - /* Startup the kernel thread for this host adapter. */ phba->worker_thread = kthread_run(lpfc_do_work, phba, "lpfc_worker_%d", phba->brd_no); @@ -13359,7 +15150,7 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) /* Configure and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0294 PM resume Failed to enable interrupt\n"); return -EIO; } else @@ -13385,7 +15176,7 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) static void lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2828 PCI channel I/O abort preparing for recovery\n"); /* * There may be errored I/Os through HBA, abort all I/Os on txcmplq @@ -13405,24 +15196,28 @@ lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) static void lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) { + int offline = pci_channel_offline(phba->pcidev); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2826 PCI channel disable preparing for reset\n"); + "2826 PCI channel disable preparing for reset offline" + " %d\n", offline); /* Block any management I/Os to the device */ lpfc_block_mgmt_io(phba, LPFC_MBX_NO_WAIT); - /* Block all SCSI devices' I/Os on the host */ - lpfc_scsi_dev_block(phba); + /* HBA_PCI_ERR was set in io_error_detect */ + lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT); /* Flush all driver's outstanding I/Os as we are to reset */ lpfc_sli_flush_io_rings(phba); + lpfc_offline(phba); /* stop all timers */ lpfc_stop_hba_timers(phba); + lpfc_sli4_queue_destroy(phba); /* Disable interrupt and pci device */ lpfc_sli4_disable_intr(phba); - lpfc_sli4_queue_destroy(phba); pci_disable_device(phba->pcidev); } @@ -13437,7 +15232,7 @@ lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) static void lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2827 PCI channel permanent disable for failure\n"); /* Block all SCSI devices' I/Os on the host */ @@ -13471,6 +15266,7 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + bool hba_pci_err; switch (state) { case pci_channel_io_normal: @@ -13478,16 +15274,26 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) lpfc_sli4_prep_dev_for_recover(phba); return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: + hba_pci_err = test_and_set_bit(HBA_PCI_ERR, &phba->bit_flags); /* Fatal error, prepare for slot reset */ - lpfc_sli4_prep_dev_for_reset(phba); + if (!hba_pci_err) + lpfc_sli4_prep_dev_for_reset(phba); + else + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2832 Already handling PCI error " + "state: x%x\n", state); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: + set_bit(HBA_PCI_ERR, &phba->bit_flags); /* Permanent failure, prepare for device down */ lpfc_sli4_prep_dev_for_perm_failure(phba); return PCI_ERS_RESULT_DISCONNECT; default: + hba_pci_err = test_and_set_bit(HBA_PCI_ERR, &phba->bit_flags); + if (!hba_pci_err) + lpfc_sli4_prep_dev_for_reset(phba); /* Unknown state, prepare and request slot reset */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2825 Unknown PCI error state: x%x\n", state); lpfc_sli4_prep_dev_for_reset(phba); return PCI_ERS_RESULT_NEED_RESET; @@ -13519,16 +15325,21 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; struct lpfc_sli *psli = &phba->sli; uint32_t intr_mode; + bool hba_pci_err; dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); if (pci_enable_device_mem(pdev)) { printk(KERN_ERR "lpfc: Cannot re-enable " - "PCI device after reset.\n"); + "PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } pci_restore_state(pdev); + hba_pci_err = test_and_clear_bit(HBA_PCI_ERR, &phba->bit_flags); + if (!hba_pci_err) + dev_info(&pdev->dev, + "hba_pci_err was not set, recovering slot reset.\n"); /* * As the new kernel behavior of pci_restore_state() API call clears * device saved_state flag, need to save the restored state again. @@ -13542,15 +15353,18 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); + /* Init cpu_map array */ + lpfc_cpu_map_array_init(phba); /* Configure and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2824 Cannot re-enable interrupt after " "slot reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } else phba->intr_mode = intr_mode; + lpfc_cpu_affinity_check(phba, phba->cfg_irq_chann); /* Log the current active interrupt mode */ lpfc_log_intr_mode(phba, phba->intr_mode); @@ -13582,8 +15396,6 @@ lpfc_io_resume_s4(struct pci_dev *pdev) */ if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) { /* Perform device reset */ - lpfc_offline_prep(phba, LPFC_MBX_WAIT); - lpfc_offline(phba); lpfc_sli_brdrestart(phba); /* Bring the device back online */ lpfc_online(phba); @@ -13650,7 +15462,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) lpfc_pci_remove_one_s4(pdev); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1424 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13660,8 +15472,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) /** * lpfc_pci_suspend_one - lpfc PCI func to suspend dev for power management - * @pdev: pointer to PCI device - * @msg: power management message + * @dev: pointer to device * * This routine is to be registered to the kernel's PCI subsystem to support * system Power Management (PM). When PM invokes this method, it dispatches @@ -13672,22 +15483,22 @@ lpfc_pci_remove_one(struct pci_dev *pdev) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) +static int __maybe_unused +lpfc_pci_suspend_one(struct device *dev) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; int rc = -ENODEV; switch (phba->pci_dev_grp) { case LPFC_PCI_DEV_LP: - rc = lpfc_pci_suspend_one_s3(pdev, msg); + rc = lpfc_pci_suspend_one_s3(dev); break; case LPFC_PCI_DEV_OC: - rc = lpfc_pci_suspend_one_s4(pdev, msg); + rc = lpfc_pci_suspend_one_s4(dev); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1425 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13697,7 +15508,7 @@ lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) /** * lpfc_pci_resume_one - lpfc PCI func to resume dev for power management - * @pdev: pointer to PCI device + * @dev: pointer to device * * This routine is to be registered to the kernel's PCI subsystem to support * system Power Management (PM). When PM invokes this method, it dispatches @@ -13708,22 +15519,22 @@ lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) * 0 - driver suspended the device * Error otherwise **/ -static int -lpfc_pci_resume_one(struct pci_dev *pdev) +static int __maybe_unused +lpfc_pci_resume_one(struct device *dev) { - struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct Scsi_Host *shost = dev_get_drvdata(dev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; int rc = -ENODEV; switch (phba->pci_dev_grp) { case LPFC_PCI_DEV_LP: - rc = lpfc_pci_resume_one_s3(pdev); + rc = lpfc_pci_resume_one_s3(dev); break; case LPFC_PCI_DEV_OC: - rc = lpfc_pci_resume_one_s4(pdev); + rc = lpfc_pci_resume_one_s4(dev); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1426 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13753,6 +15564,10 @@ lpfc_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; + if (phba->link_state == LPFC_HBA_ERROR && + phba->hba_flag & HBA_IOQ_FLUSH) + return PCI_ERS_RESULT_NEED_RESET; + switch (phba->pci_dev_grp) { case LPFC_PCI_DEV_LP: rc = lpfc_io_error_detected_s3(pdev, state); @@ -13761,7 +15576,7 @@ lpfc_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) rc = lpfc_io_error_detected_s4(pdev, state); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1427 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13798,7 +15613,7 @@ lpfc_io_slot_reset(struct pci_dev *pdev) rc = lpfc_io_slot_reset_s4(pdev); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1428 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13830,7 +15645,7 @@ lpfc_io_resume(struct pci_dev *pdev) lpfc_io_resume_s4(pdev); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1429 Invalid PCI device group: 0x%x\n", phba->pci_dev_grp); break; @@ -13876,17 +15691,18 @@ lpfc_sli4_oas_verify(struct lpfc_hba *phba) void lpfc_sli4_ras_init(struct lpfc_hba *phba) { - switch (phba->pcidev->device) { - case PCI_DEVICE_ID_LANCER_G6_FC: - case PCI_DEVICE_ID_LANCER_G7_FC: + /* if ASIC_GEN_NUM >= 0xC) */ + if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_6) || + (bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_FAMILY_G6)) { phba->ras_fwlog.ras_hwsupport = true; if (phba->cfg_ras_fwlog_func == PCI_FUNC(phba->pcidev->devfn) && phba->cfg_ras_fwlog_buffsize) phba->ras_fwlog.ras_enabled = true; else phba->ras_fwlog.ras_enabled = false; - break; - default: + } else { phba->ras_fwlog.ras_hwsupport = false; } } @@ -13900,14 +15716,17 @@ static const struct pci_error_handlers lpfc_err_handler = { .resume = lpfc_io_resume, }; +static SIMPLE_DEV_PM_OPS(lpfc_pci_pm_ops_one, + lpfc_pci_suspend_one, + lpfc_pci_resume_one); + static struct pci_driver lpfc_driver = { .name = LPFC_DRIVER_NAME, .id_table = lpfc_id_table, .probe = lpfc_pci_probe_one, .remove = lpfc_pci_remove_one, .shutdown = lpfc_pci_remove_one, - .suspend = lpfc_pci_suspend_one, - .resume = lpfc_pci_resume_one, + .driver.pm = &lpfc_pci_pm_ops_one, .err_handler = &lpfc_err_handler, }; @@ -13938,32 +15757,35 @@ lpfc_init(void) { int error = 0; - printk(LPFC_MODULE_DESC "\n"); - printk(LPFC_COPYRIGHT "\n"); + pr_info(LPFC_MODULE_DESC "\n"); + pr_info(LPFC_COPYRIGHT "\n"); error = misc_register(&lpfc_mgmt_dev); if (error) printk(KERN_ERR "Could not register lpfcmgmt device, " "misc_register returned with status %d", error); + error = -ENOMEM; lpfc_transport_functions.vport_create = lpfc_vport_create; lpfc_transport_functions.vport_delete = lpfc_vport_delete; lpfc_transport_template = fc_attach_transport(&lpfc_transport_functions); if (lpfc_transport_template == NULL) - return -ENOMEM; + goto unregister; lpfc_vport_transport_template = fc_attach_transport(&lpfc_vport_transport_functions); if (lpfc_vport_transport_template == NULL) { fc_release_transport(lpfc_transport_template); - return -ENOMEM; + goto unregister; } - lpfc_nvme_cmd_template(); + lpfc_wqe_cmd_template(); lpfc_nvmet_cmd_template(); /* Initialize in case vector mapping is needed */ lpfc_present_cpu = num_present_cpus(); + lpfc_pldv_detect = false; + error = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "lpfc/sli4:online", lpfc_cpu_online, lpfc_cpu_offline); @@ -13982,10 +15804,91 @@ unwind: cpuhp_failure: fc_release_transport(lpfc_transport_template); fc_release_transport(lpfc_vport_transport_template); +unregister: + misc_deregister(&lpfc_mgmt_dev); return error; } +void lpfc_dmp_dbg(struct lpfc_hba *phba) +{ + unsigned int start_idx; + unsigned int dbg_cnt; + unsigned int temp_idx; + int i; + int j = 0; + unsigned long rem_nsec; + + if (atomic_cmpxchg(&phba->dbg_log_dmping, 0, 1) != 0) + return; + + start_idx = (unsigned int)atomic_read(&phba->dbg_log_idx) % DBG_LOG_SZ; + dbg_cnt = (unsigned int)atomic_read(&phba->dbg_log_cnt); + if (!dbg_cnt) + goto out; + temp_idx = start_idx; + if (dbg_cnt >= DBG_LOG_SZ) { + dbg_cnt = DBG_LOG_SZ; + temp_idx -= 1; + } else { + if ((start_idx + dbg_cnt) > (DBG_LOG_SZ - 1)) { + temp_idx = (start_idx + dbg_cnt) % DBG_LOG_SZ; + } else { + if (start_idx < dbg_cnt) + start_idx = DBG_LOG_SZ - (dbg_cnt - start_idx); + else + start_idx -= dbg_cnt; + } + } + dev_info(&phba->pcidev->dev, "start %d end %d cnt %d\n", + start_idx, temp_idx, dbg_cnt); + + for (i = 0; i < dbg_cnt; i++) { + if ((start_idx + i) < DBG_LOG_SZ) + temp_idx = (start_idx + i) % DBG_LOG_SZ; + else + temp_idx = j++; + rem_nsec = do_div(phba->dbg_log[temp_idx].t_ns, NSEC_PER_SEC); + dev_info(&phba->pcidev->dev, "%d: [%5lu.%06lu] %s", + temp_idx, + (unsigned long)phba->dbg_log[temp_idx].t_ns, + rem_nsec / 1000, + phba->dbg_log[temp_idx].log); + } +out: + atomic_set(&phba->dbg_log_cnt, 0); + atomic_set(&phba->dbg_log_dmping, 0); +} + +__printf(2, 3) +void lpfc_dbg_print(struct lpfc_hba *phba, const char *fmt, ...) +{ + unsigned int idx; + va_list args; + int dbg_dmping = atomic_read(&phba->dbg_log_dmping); + struct va_format vaf; + + + va_start(args, fmt); + if (unlikely(dbg_dmping)) { + vaf.fmt = fmt; + vaf.va = &args; + dev_info(&phba->pcidev->dev, "%pV", &vaf); + va_end(args); + return; + } + idx = (unsigned int)atomic_fetch_add(1, &phba->dbg_log_idx) % + DBG_LOG_SZ; + + atomic_inc(&phba->dbg_log_cnt); + + vscnprintf(phba->dbg_log[idx].log, + sizeof(phba->dbg_log[idx].log), fmt, args); + va_end(args); + + phba->dbg_log[idx].t_ns = local_clock(); +} + /** * lpfc_exit - lpfc module removal routine * diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index 148d02a27b58..b39cefcd8703 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -35,7 +35,7 @@ #define LOG_FCP_ERROR 0x00001000 /* log errors, not underruns */ #define LOG_LIBDFC 0x00002000 /* Libdfc events */ #define LOG_VPORT 0x00004000 /* NPIV events */ -#define LOG_SECURITY 0x00008000 /* Security events */ +#define LOG_LDS_EVENT 0x00008000 /* Link Degrade Signaling events */ #define LOG_EVENT 0x00010000 /* CT,TEMP,DUMP, logging */ #define LOG_FIP 0x00020000 /* FIP events */ #define LOG_FCP_UNDER 0x00040000 /* FCP underruns errors */ @@ -44,7 +44,14 @@ #define LOG_NVME_DISC 0x00200000 /* NVME Discovery/Connect events. */ #define LOG_NVME_ABTS 0x00400000 /* NVME ABTS events. */ #define LOG_NVME_IOERR 0x00800000 /* NVME IO Error events. */ -#define LOG_ALL_MSG 0xffffffff /* LOG all messages */ +#define LOG_RSVD1 0x01000000 /* Reserved */ +#define LOG_RSVD2 0x02000000 /* Reserved */ +#define LOG_CGN_MGMT 0x04000000 /* Congestion Mgmt events */ +#define LOG_TRACE_EVENT 0x80000000 /* Dmp the DBG log on this err */ +#define LOG_ALL_MSG 0x7fffffff /* LOG all messages */ + +void lpfc_dmp_dbg(struct lpfc_hba *phba); +void lpfc_dbg_print(struct lpfc_hba *phba, const char *fmt, ...); /* generate message by verbose log setting or severity */ #define lpfc_vlog_msg(vport, level, mask, fmt, arg...) \ @@ -65,9 +72,15 @@ do { \ #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \ do { \ - { if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) \ + { if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) { \ + if ((mask) & LOG_TRACE_EVENT && !(vport)->cfg_log_verbose) \ + lpfc_dmp_dbg((vport)->phba); \ dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \ - fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } \ + fmt, (vport)->phba->brd_no, vport->vpi, ##arg); \ + } else if (!(vport)->cfg_log_verbose) \ + lpfc_dbg_print((vport)->phba, "%d:(%d):" fmt, \ + (vport)->phba->brd_no, (vport)->vpi, ##arg); \ + } \ } while (0) #define lpfc_printf_log(phba, level, mask, fmt, arg...) \ @@ -75,8 +88,12 @@ do { \ { uint32_t log_verbose = (phba)->pport ? \ (phba)->pport->cfg_log_verbose : \ (phba)->cfg_log_verbose; \ - if (((mask) & log_verbose) || (level[1] <= '3')) \ + if (((mask) & log_verbose) || (level[1] <= '3')) { \ + if ((mask) & LOG_TRACE_EVENT && !log_verbose) \ + lpfc_dmp_dbg(phba); \ dev_printk(level, &((phba)->pcidev)->dev, "%d:" \ - fmt, phba->brd_no, ##arg); \ + fmt, phba->brd_no, ##arg); \ + } else if (!log_verbose)\ + lpfc_dbg_print(phba, "%d:" fmt, phba->brd_no, ##arg); \ } \ } while (0) diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index d1773c01d2b3..9858b1743769 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -44,6 +44,80 @@ #include "lpfc_compat.h" /** + * lpfc_mbox_rsrc_prep - Prepare a mailbox with DMA buffer memory. + * @phba: pointer to lpfc hba data structure. + * @mbox: pointer to the driver internal queue element for mailbox command. + * + * A mailbox command consists of the pool memory for the command, @mbox, and + * one or more DMA buffers for the data transfer. This routine provides + * a standard framework for allocating the dma buffer and assigning to the + * @mbox. Callers should cleanup the mbox with a call to + * lpfc_mbox_rsrc_cleanup. + * + * The lpfc_mbuf_alloc routine acquires the hbalock so the caller is + * responsible to ensure the hbalock is released. Also note that the + * driver design is a single dmabuf/mbuf per mbox in the ctx_buf. + * + **/ +int +lpfc_mbox_rsrc_prep(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) +{ + struct lpfc_dmabuf *mp; + + mp = kmalloc(sizeof(*mp), GFP_KERNEL); + if (!mp) + return -ENOMEM; + + mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); + if (!mp->virt) { + kfree(mp); + return -ENOMEM; + } + + memset(mp->virt, 0, LPFC_BPL_SIZE); + + /* Initialization only. Driver does not use a list of dmabufs. */ + INIT_LIST_HEAD(&mp->list); + mbox->ctx_buf = mp; + return 0; +} + +/** + * lpfc_mbox_rsrc_cleanup - Free the mailbox DMA buffer and virtual memory. + * @phba: pointer to lpfc hba data structure. + * @mbox: pointer to the driver internal queue element for mailbox command. + * @locked: value that indicates if the hbalock is held (1) or not (0). + * + * A mailbox command consists of the pool memory for the command, @mbox, and + * possibly a DMA buffer for the data transfer. This routine provides + * a standard framework for releasing any dma buffers and freeing all + * memory resources in it as well as releasing the @mbox back to the @phba pool. + * Callers should use this routine for cleanup for all mailboxes prepped with + * lpfc_mbox_rsrc_prep. + * + **/ +void +lpfc_mbox_rsrc_cleanup(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, + enum lpfc_mbox_ctx locked) +{ + struct lpfc_dmabuf *mp; + + mp = (struct lpfc_dmabuf *)mbox->ctx_buf; + mbox->ctx_buf = NULL; + + /* Release the generic BPL buffer memory. */ + if (mp) { + if (locked == MBOX_THD_LOCKED) + __lpfc_mbuf_free(phba, mp->virt, mp->phys); + else + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + + mempool_free(mbox, phba->mbox_mem_pool); +} + +/** * lpfc_dump_static_vport - Dump HBA's static vport information. * @phba: pointer to lpfc hba data structure. * @pmb: pointer to the driver internal queue element for mailbox command. @@ -61,6 +135,7 @@ lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, { MAILBOX_t *mb; struct lpfc_dmabuf *mp; + int rc; mb = &pmb->u.mb; @@ -79,22 +154,15 @@ lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, return 0; } - /* For SLI4 HBAs driver need to allocate memory */ - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (mp) - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - - if (!mp || !mp->virt) { - kfree(mp); + rc = lpfc_mbox_rsrc_prep(phba, pmb); + if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "2605 lpfc_dump_static_vport: memory" - " allocation failed\n"); + "2605 %s: memory allocation failed\n", + __func__); return 1; } - memset(mp->virt, 0, LPFC_BPL_SIZE); - INIT_LIST_HEAD(&mp->list); - /* save address for completion */ - pmb->ctx_buf = (uint8_t *)mp; + + mp = pmb->ctx_buf; mb->un.varWords[3] = putPaddrLow(mp->phys); mb->un.varWords[4] = putPaddrHigh(mp->phys); mb->un.varDmp.sli4_length = sizeof(struct static_vport_info); @@ -429,7 +497,7 @@ lpfc_config_msi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); /* - * SLI-3, Message Signaled Interrupt Fearure. + * SLI-3, Message Signaled Interrupt Feature. */ /* Multi-message attention configuration */ @@ -513,8 +581,9 @@ lpfc_init_link(struct lpfc_hba * phba, break; } - if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC || - phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) && + /* Topology handling for ASIC_GEN_NUM 0xC and later */ + if ((phba->sli4_hba.pc_sli4_params.sli_family == LPFC_SLI_INTF_FAMILY_G6 || + phba->sli4_hba.pc_sli4_params.if_type == LPFC_SLI_INTF_IF_TYPE_6) && !(phba->sli4_hba.pc_sli4_params.pls) && mb->un.varInitLnk.link_flags & FLAGS_TOPOLOGY_MODE_LOOP) { mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; @@ -522,7 +591,8 @@ lpfc_init_link(struct lpfc_hba * phba, } /* Enable asynchronous ABTS responses from firmware */ - mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT; + if (phba->sli_rev == LPFC_SLI_REV3 && !phba->cfg_fcp_wait_abts_rsp) + mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT; /* NEW_FEATURE * Setting up the link speed @@ -604,26 +674,21 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) { struct lpfc_dmabuf *mp; MAILBOX_t *mb; + int rc; - mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->mbxOwner = OWN_HOST; - /* Get a buffer to hold the HBAs Service Parameters */ - - mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (mp) - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp || !mp->virt) { - kfree(mp); - mb->mbxCommand = MBX_READ_SPARM64; - /* READ_SPARAM: no buffers */ + rc = lpfc_mbox_rsrc_prep(phba, pmb); + if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, "0301 READ_SPARAM: no buffers\n"); - return (1); + return 1; } - INIT_LIST_HEAD(&mp->list); + + mp = pmb->ctx_buf; + mb = &pmb->u.mb; + mb->mbxOwner = OWN_HOST; mb->mbxCommand = MBX_READ_SPARM64; mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm); mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys); @@ -631,9 +696,6 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) if (phba->sli_rev >= LPFC_SLI_REV3) mb->un.varRdSparm.vpi = phba->vpi_ids[vpi]; - /* save address for completion */ - pmb->ctx_buf = mp; - return (0); } @@ -754,6 +816,7 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, MAILBOX_t *mb = &pmb->u.mb; uint8_t *sparam; struct lpfc_dmabuf *mp; + int rc; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); @@ -764,12 +827,10 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, mb->un.varRegLogin.vpi = phba->vpi_ids[vpi]; mb->un.varRegLogin.did = did; mb->mbxOwner = OWN_HOST; + /* Get a buffer to hold NPorts Service Parameters */ - mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (mp) - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp || !mp->virt) { - kfree(mp); + rc = lpfc_mbox_rsrc_prep(phba, pmb); + if (rc) { mb->mbxCommand = MBX_REG_LOGIN64; /* REG_LOGIN: no buffers */ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, @@ -777,15 +838,13 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, "rpi x%x\n", vpi, did, rpi); return 1; } - INIT_LIST_HEAD(&mp->list); - sparam = mp->virt; /* Copy param's into a new buffer */ + mp = pmb->ctx_buf; + sparam = mp->virt; memcpy(sparam, param, sizeof (struct serv_parm)); - /* save address for completion */ - pmb->ctx_buf = (uint8_t *)mp; - + /* Finish initializing the mailbox. */ mb->mbxCommand = MBX_REG_LOGIN64; mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm); mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys); @@ -868,9 +927,7 @@ lpfc_sli4_unreg_all_rpis(struct lpfc_vport *vport) /** * lpfc_reg_vpi - Prepare a mailbox command for registering vport identifier - * @phba: pointer to lpfc hba data structure. - * @vpi: virtual N_Port identifier. - * @sid: Fibre Channel S_ID (N_Port_ID assigned to a virtual N_Port). + * @vport: pointer to a vport object. * @pmb: pointer to the driver internal queue element for mailbox command. * * The registration vport identifier mailbox command is used to activate a @@ -1199,7 +1256,7 @@ lpfc_config_hbq(struct lpfc_hba *phba, uint32_t id, /** * lpfc_config_ring - Prepare a mailbox command for configuring an IOCB ring * @phba: pointer to lpfc hba data structure. - * @ring: + * @ring: ring number/index * @pmb: pointer to the driver internal queue element for mailbox command. * * The configure ring mailbox command is used to configure an IOCB ring. This @@ -1299,8 +1356,6 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) { if (phba->cfg_enable_bg) mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */ - if (phba->cfg_enable_dss) - mb->un.varCfgPort.cdss = 1; /* Configure Security */ mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */ mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count(); @@ -1380,7 +1435,8 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) */ if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) { - phba->host_gp = &phba->mbox->us.s2.host[0]; + phba->host_gp = (struct lpfc_hgp __iomem *) + &phba->mbox->us.s2.host[0]; phba->hbq_put = NULL; offset = (uint8_t *)&phba->mbox->us.s2.host - (uint8_t *)phba->slim2p.virt; @@ -1614,7 +1670,7 @@ lpfc_mbox_dev_check(struct lpfc_hba *phba) /** * lpfc_mbox_tmo_val - Retrieve mailbox command timeout value * @phba: pointer to lpfc hba data structure. - * @cmd: mailbox command code. + * @mboxq: pointer to the driver internal queue element for mailbox command. * * This routine retrieves the proper timeout value according to the mailbox * command code. @@ -1701,6 +1757,7 @@ lpfc_sli4_mbx_sge_set(struct lpfcMboxq *mbox, uint32_t sgentry, * lpfc_sli4_mbx_sge_get - Get a sge entry from non-embedded mailbox command * @mbox: pointer to lpfc mbox command. * @sgentry: sge entry index. + * @sge: pointer to lpfc mailbox sge to load into. * * This routine gets an entry from the non-embedded mailbox command at the sge * index location. @@ -1723,7 +1780,9 @@ lpfc_sli4_mbx_sge_get(struct lpfcMboxq *mbox, uint32_t sgentry, * @phba: pointer to lpfc hba data structure. * @mbox: pointer to lpfc mbox command. * - * This routine frees SLI4 specific mailbox command for sending IOCTL command. + * This routine cleans up and releases an SLI4 mailbox command that was + * configured using lpfc_sli4_config. It accounts for the embedded and + * non-embedded config types. **/ void lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox) @@ -1768,6 +1827,7 @@ lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox) * @subsystem: The sli4 config sub mailbox subsystem. * @opcode: The sli4 config sub mailbox command opcode. * @length: Length of the sli4 config mailbox command (including sub-header). + * @emb: True if embedded mbox command should be setup. * * This routine sets up the header fields of SLI4 specific mailbox command * for sending IOCTL command. @@ -2013,6 +2073,7 @@ lpfc_sli_config_mbox_opcode_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) /** * lpfc_sli4_mbx_read_fcf_rec - Allocate and construct read fcf mbox cmd * @phba: pointer to lpfc hba data structure. + * @mboxq: pointer to lpfc mbox command. * @fcf_index: index to fcf table. * * This routine routine allocates and constructs non-embedded mailbox command @@ -2069,6 +2130,7 @@ lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *phba, /** * lpfc_request_features: Configure SLI4 REQUEST_FEATURES mailbox + * @phba: pointer to lpfc hba data structure. * @mboxq: pointer to lpfc mbox command. * * This routine sets up the mailbox for an SLI4 REQUEST_FEATURES @@ -2099,6 +2161,12 @@ lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq) bf_set(lpfc_mbx_rq_ftr_rq_iaab, &mboxq->u.mqe.un.req_ftrs, 0); bf_set(lpfc_mbx_rq_ftr_rq_iaar, &mboxq->u.mqe.un.req_ftrs, 0); } + + /* Enable Application Services Header for appheader VMID */ + if (phba->cfg_vmid_app_header) { + bf_set(lpfc_mbx_rq_ftr_rq_ashdr, &mboxq->u.mqe.un.req_ftrs, 1); + bf_set(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags, 1); + } return; } @@ -2268,33 +2336,24 @@ lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *phba, struct lpfcMboxq *mbox) { struct lpfc_dmabuf *mp = NULL; MAILBOX_t *mb; + int rc; memset(mbox, 0, sizeof(*mbox)); mb = &mbox->u.mb; - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (mp) - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - - if (!mp || !mp->virt) { - kfree(mp); - /* dump config region 23 failed to allocate memory */ + rc = lpfc_mbox_rsrc_prep(phba, mbox); + if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "2569 lpfc dump config region 23: memory" - " allocation failed\n"); + "2569 %s: memory allocation failed\n", + __func__); return 1; } - memset(mp->virt, 0, LPFC_BPL_SIZE); - INIT_LIST_HEAD(&mp->list); - - /* save address for completion */ - mbox->ctx_buf = (uint8_t *)mp; - mb->mbxCommand = MBX_DUMP_MEMORY; mb->un.varDmp.type = DMP_NV_PARAMS; mb->un.varDmp.region_id = DMP_REGION_23; mb->un.varDmp.sli4_length = DMP_RGN23_SIZE; + mp = mbox->ctx_buf; mb->un.varWords[3] = putPaddrLow(mp->phys); mb->un.varWords[4] = putPaddrHigh(mp->phys); return 0; @@ -2317,7 +2376,7 @@ lpfc_mbx_cmpl_rdp_link_stat(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) rc = SUCCESS; mbx_failed: - lpfc_sli4_mbox_cmd_free(phba, mboxq); + lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED); rdp_context->cmpl(phba, rdp_context, rc); } @@ -2329,30 +2388,25 @@ lpfc_mbx_cmpl_rdp_page_a2(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) (struct lpfc_rdp_context *)(mbox->ctx_ndlp); if (bf_get(lpfc_mqe_status, &mbox->u.mqe)) - goto error_mbuf_free; + goto error_mbox_free; lpfc_sli_bemem_bcopy(mp->virt, &rdp_context->page_a2, DMP_SFF_PAGE_A2_SIZE); - /* We don't need dma buffer for link stat. */ - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - - memset(mbox, 0, sizeof(*mbox)); lpfc_read_lnk_stat(phba, mbox); mbox->vport = rdp_context->ndlp->vport; + + /* Save the dma buffer for cleanup in the final completion. */ + mbox->ctx_buf = mp; mbox->mbox_cmpl = lpfc_mbx_cmpl_rdp_link_stat; mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context; if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED) - goto error_cmd_free; + goto error_mbox_free; return; -error_mbuf_free: - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); -error_cmd_free: - lpfc_sli4_mbox_cmd_free(phba, mbox); +error_mbox_free: + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); rdp_context->cmpl(phba, rdp_context, FAILURE); } @@ -2400,15 +2454,13 @@ lpfc_mbx_cmpl_rdp_page_a0(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) return; error: - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - lpfc_sli4_mbox_cmd_free(phba, mbox); + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); rdp_context->cmpl(phba, rdp_context, FAILURE); } /* - * lpfc_sli4_dump_sfp_pagea0 - Dump sli4 read SFP Diagnostic. + * lpfc_sli4_dump_page_a0 - Dump sli4 read SFP Diagnostic. * @phba: pointer to the hba structure containing. * @mbox: pointer to lpfc mbox command to initialize. * @@ -2418,27 +2470,19 @@ error: int lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox) { + int rc; struct lpfc_dmabuf *mp = NULL; memset(mbox, 0, sizeof(*mbox)); - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (mp) - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp || !mp->virt) { - kfree(mp); + rc = lpfc_mbox_rsrc_prep(phba, mbox); + if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, "3569 dump type 3 page 0xA0 allocation failed\n"); return 1; } - memset(mp->virt, 0, LPFC_BPL_SIZE); - INIT_LIST_HEAD(&mp->list); - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_DUMP_MEMORY); - /* save address for completion */ - mbox->ctx_buf = mp; - bf_set(lpfc_mbx_memory_dump_type3_type, &mbox->u.mqe.un.mem_dump_type3, DMP_LMSD); bf_set(lpfc_mbx_memory_dump_type3_link, @@ -2447,6 +2491,8 @@ lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox) &mbox->u.mqe.un.mem_dump_type3, DMP_PAGE_A0); bf_set(lpfc_mbx_memory_dump_type3_length, &mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A0_SIZE); + + mp = mbox->ctx_buf; mbox->u.mqe.un.mem_dump_type3.addr_lo = putPaddrLow(mp->phys); mbox->u.mqe.un.mem_dump_type3.addr_hi = putPaddrHigh(mp->phys); @@ -2623,39 +2669,3 @@ lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp) resume_rpi->event_tag = ndlp->phba->fc_eventTag; } -/** - * lpfc_supported_pages - Initialize the PORT_CAPABILITIES supported pages - * mailbox command. - * @mbox: pointer to lpfc mbox command to initialize. - * - * The PORT_CAPABILITIES supported pages mailbox command is issued to - * retrieve the particular feature pages supported by the port. - **/ -void -lpfc_supported_pages(struct lpfcMboxq *mbox) -{ - struct lpfc_mbx_supp_pages *supp_pages; - - memset(mbox, 0, sizeof(*mbox)); - supp_pages = &mbox->u.mqe.un.supp_pages; - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_PORT_CAPABILITIES); - bf_set(cpn, supp_pages, LPFC_SUPP_PAGES); -} - -/** - * lpfc_pc_sli4_params - Initialize the PORT_CAPABILITIES SLI4 Params mbox cmd. - * @mbox: pointer to lpfc mbox command to initialize. - * - * The PORT_CAPABILITIES SLI4 parameters mailbox command is issued to - * retrieve the particular SLI4 features supported by the port. - **/ -void -lpfc_pc_sli4_params(struct lpfcMboxq *mbox) -{ - struct lpfc_mbx_pc_sli4_params *sli4_params; - - memset(mbox, 0, sizeof(*mbox)); - sli4_params = &mbox->u.mqe.un.sli4_params; - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_PORT_CAPABILITIES); - bf_set(cpn, sli4_params, LPFC_SLI4_PARAMETERS); -} diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 7082279e4c01..89cbeba06aea 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -31,8 +31,6 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> -#include <linux/nvme-fc-driver.h> - #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" @@ -41,14 +39,14 @@ #include "lpfc_disc.h" #include "lpfc.h" #include "lpfc_scsi.h" -#include "lpfc_nvme.h" -#include "lpfc_nvmet.h" #include "lpfc_crtn.h" #include "lpfc_logmsg.h" #define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */ #define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */ #define LPFC_DEVICE_DATA_POOL_SIZE 64 /* max elements in device data pool */ +#define LPFC_RRQ_POOL_SIZE 256 /* max elements in non-DMA pool */ +#define LPFC_MBX_POOL_SIZE 256 /* max elements in MBX non-DMA pool */ int lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) { @@ -71,6 +69,7 @@ lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) { /** * lpfc_mem_alloc - create and allocate all PCI and memory pools * @phba: HBA to allocate pools for + * @align: alignment requirement for blocks; must be a power of two * * Description: Creates and allocates PCI pools lpfc_mbuf_pool, * lpfc_hrb_pool. Creates and allocates kmalloc-backed mempools @@ -113,8 +112,8 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) pool->current_count++; } - phba->mbox_mem_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE, - sizeof(LPFC_MBOXQ_t)); + phba->mbox_mem_pool = mempool_create_kmalloc_pool(LPFC_MBX_POOL_SIZE, + sizeof(LPFC_MBOXQ_t)); if (!phba->mbox_mem_pool) goto fail_free_mbuf_pool; @@ -125,7 +124,7 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) if (phba->sli_rev == LPFC_SLI_REV4) { phba->rrq_pool = - mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE, + mempool_create_kmalloc_pool(LPFC_RRQ_POOL_SIZE, sizeof(struct lpfc_node_rrq)); if (!phba->rrq_pool) goto fail_free_nlp_mem_pool; @@ -336,6 +335,22 @@ lpfc_mem_free_all(struct lpfc_hba *phba) dma_pool_destroy(phba->lpfc_cmd_rsp_buf_pool); phba->lpfc_cmd_rsp_buf_pool = NULL; + /* Free Congestion Data buffer */ + if (phba->cgn_i) { + dma_free_coherent(&phba->pcidev->dev, + sizeof(struct lpfc_cgn_info), + phba->cgn_i->virt, phba->cgn_i->phys); + kfree(phba->cgn_i); + phba->cgn_i = NULL; + } + + /* Free RX Monitor */ + if (phba->rx_monitor) { + lpfc_rx_monitor_destroy_ring(phba->rx_monitor); + kfree(phba->rx_monitor); + phba->rx_monitor = NULL; + } + /* Free the iocb lookup array */ kfree(psli->iocbq_lookup); psli->iocbq_lookup = NULL; @@ -590,8 +605,6 @@ lpfc_sli4_rb_free(struct lpfc_hba *phba, struct hbq_dmabuf *dmab) * Description: Allocates a DMA-mapped receive buffer from the lpfc_hrb_pool PCI * pool along a non-DMA-mapped container for it. * - * Notes: Not interrupt-safe. Must be called with no locks held. - * * Returns: * pointer to HBQ on success * NULL on failure @@ -601,7 +614,7 @@ lpfc_sli4_nvmet_alloc(struct lpfc_hba *phba) { struct rqb_dmabuf *dma_buf; - dma_buf = kzalloc(sizeof(struct rqb_dmabuf), GFP_KERNEL); + dma_buf = kzalloc(sizeof(*dma_buf), GFP_KERNEL); if (!dma_buf) return NULL; @@ -724,7 +737,6 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys); rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe); if (rc < 0) { - (rqbp->rqb_free_buffer)(phba, rqb_entry); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "6409 Cannot post to HRQ %d: %x %x %x " "DRQ %x %x\n", @@ -734,6 +746,7 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) rqb_entry->hrq->entry_count, rqb_entry->drq->host_index, rqb_entry->drq->hba_index); + (rqbp->rqb_free_buffer)(phba, rqb_entry); } else { list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list); rqbp->buffer_count++; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index a024e5a3918f..b86ff9fcdf0c 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -32,8 +32,6 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> -#include <linux/nvme-fc-driver.h> - #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" @@ -154,7 +152,7 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name)); return 1; bad_service_param: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0207 Device %x " "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent " "invalid service parameters. Ignoring device.\n", @@ -173,12 +171,11 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf *pcmd, *prsp; uint32_t *lp; void *ptr = NULL; - IOCB_t *irsp; + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); - irsp = &rspiocb->iocb; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; - /* For lpfc_els_abort, context2 could be zero'ed to delay + /* For lpfc_els_abort, cmd_dmabuf could be zero'ed to delay * freeing associated memory till after ABTS completes. */ if (pcmd) { @@ -189,10 +186,16 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ptr = (void *)((uint8_t *)lp + sizeof(uint32_t)); } } else { - /* Force ulpStatus error since we are returning NULL ptr */ - if (!(irsp->ulpStatus)) { - irsp->ulpStatus = IOSTAT_LOCAL_REJECT; - irsp->un.ulpWord[4] = IOERR_SLI_ABORTED; + /* Force ulp_status error since we are returning NULL ptr */ + if (!(ulp_status)) { + if (phba->sli_rev == LPFC_SLI_REV4) { + bf_set(lpfc_wcqe_c_status, &rspiocb->wcqe_cmpl, + IOSTAT_LOCAL_REJECT); + rspiocb->wcqe_cmpl.parameter = IOERR_SLI_ABORTED; + } else { + rspiocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; + rspiocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; + } } ptr = NULL; } @@ -249,9 +252,11 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) { spin_lock_irq(&phba->hbalock); list_del_init(&iocb->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); spin_unlock_irq(&phba->hbalock); } + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); INIT_LIST_HEAD(&abort_list); @@ -279,118 +284,52 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); } -/* lpfc_defer_pt2pt_acc - Complete SLI3 pt2pt processing on link up +/* lpfc_defer_plogi_acc - Issue PLOGI ACC after reg_login completes * @phba: pointer to lpfc hba data structure. - * @link_mbox: pointer to CONFIG_LINK mailbox object + * @login_mbox: pointer to REG_RPI mailbox object * - * This routine is only called if we are SLI3, direct connect pt2pt - * mode and the remote NPort issues the PLOGI after link up. + * The ACC for a rcv'ed PLOGI is deferred until AFTER the REG_RPI completes */ static void -lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox) +lpfc_defer_plogi_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *login_mbox) { - LPFC_MBOXQ_t *login_mbox; - MAILBOX_t *mb = &link_mbox->u.mb; struct lpfc_iocbq *save_iocb; struct lpfc_nodelist *ndlp; + MAILBOX_t *mb = &login_mbox->u.mb; + int rc; - ndlp = link_mbox->ctx_ndlp; - login_mbox = link_mbox->context3; + ndlp = login_mbox->ctx_ndlp; save_iocb = login_mbox->context3; - link_mbox->context3 = NULL; - login_mbox->context3 = NULL; - /* Check for CONFIG_LINK error */ - if (mb->mbxStatus) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "4575 CONFIG_LINK fails pt2pt discovery: %x\n", - mb->mbxStatus); - mempool_free(login_mbox, phba->mbox_mem_pool); - mempool_free(link_mbox, phba->mbox_mem_pool); - kfree(save_iocb); - return; - } - - /* Now that CONFIG_LINK completed, and our SID is configured, - * we can now proceed with sending the PLOGI ACC. - */ - rc = lpfc_els_rsp_acc(link_mbox->vport, ELS_CMD_PLOGI, - save_iocb, ndlp, login_mbox); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "4576 PLOGI ACC fails pt2pt discovery: %x\n", - rc); - mempool_free(login_mbox, phba->mbox_mem_pool); + if (mb->mbxStatus == MBX_SUCCESS) { + /* Now that REG_RPI completed successfully, + * we can now proceed with sending the PLOGI ACC. + */ + rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI, + save_iocb, ndlp, NULL); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "4576 PLOGI ACC fails pt2pt discovery: " + "DID %x Data: %x\n", ndlp->nlp_DID, rc); + } } - mempool_free(link_mbox, phba->mbox_mem_pool); + /* Now process the REG_RPI cmpl */ + lpfc_mbx_cmpl_reg_login(phba, login_mbox); + ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN; kfree(save_iocb); } -/** - * lpfc_defer_tgt_acc - Progress SLI4 target rcv PLOGI handler - * @phba: Pointer to HBA context object. - * @pmb: Pointer to mailbox object. - * - * This function provides the unreg rpi mailbox completion handler for a tgt. - * The routine frees the memory resources associated with the completed - * mailbox command and transmits the ELS ACC. - * - * This routine is only called if we are SLI4, acting in target - * mode and the remote NPort issues the PLOGI after link up. - **/ -static void -lpfc_defer_acc_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_vport *vport = pmb->vport; - struct lpfc_nodelist *ndlp = pmb->ctx_ndlp; - LPFC_MBOXQ_t *mbox = pmb->context3; - struct lpfc_iocbq *piocb = NULL; - int rc; - - if (mbox) { - pmb->context3 = NULL; - piocb = mbox->context3; - mbox->context3 = NULL; - } - - /* - * Complete the unreg rpi mbx request, and update flags. - * This will also restart any deferred events. - */ - lpfc_nlp_get(ndlp); - lpfc_sli4_unreg_rpi_cmpl_clr(phba, pmb); - - if (!piocb) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY | LOG_ELS, - "4578 PLOGI ACC fail\n"); - if (mbox) - mempool_free(mbox, phba->mbox_mem_pool); - goto out; - } - - rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, piocb, ndlp, mbox); - if (rc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY | LOG_ELS, - "4579 PLOGI ACC fail %x\n", rc); - if (mbox) - mempool_free(mbox, phba->mbox_mem_pool); - } - kfree(piocb); -out: - lpfc_nlp_put(ndlp); -} - static int lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *cmdiocb) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; uint64_t nlp_portwwn = 0; uint32_t *lp; + union lpfc_wqe128 *wqe; IOCB_t *icmd; struct serv_parm *sp; uint32_t ed_tov; @@ -399,16 +338,16 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *save_iocb; struct ls_rjt stat; uint32_t vid, flag; - u16 rpi; - int rc, defer_acc; + int rc; + u32 remote_did; memset(&stat, 0, sizeof (struct ls_rjt)); - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; lp = (uint32_t *) pcmd->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); if (wwn_to_u64(sp->portName.u.wwn) == 0) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0140 PLOGI Reject: invalid nname\n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0140 PLOGI Reject: invalid pname\n"); stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME; lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, @@ -416,8 +355,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 0; } if (wwn_to_u64(sp->nodeName.u.wwn) == 0) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0141 PLOGI Reject: invalid pname\n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0141 PLOGI Reject: invalid nname\n"); stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME; lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, @@ -434,7 +373,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, NULL); return 0; } - icmd = &cmdiocb->iocb; + + if (phba->sli_rev == LPFC_SLI_REV4) + wqe = &cmdiocb->wqe; + else + icmd = &cmdiocb->iocb; /* PLOGI chkparm OK */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -449,7 +392,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, else ndlp->nlp_fcp_info |= CLASS3; - defer_acc = 0; ndlp->nlp_class_sup = 0; if (sp->cls1.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS1; @@ -466,7 +408,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, case NLP_STE_NPR_NODE: if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) break; - /* fall through */ + fallthrough; case NLP_STE_REG_LOGIN_ISSUE: case NLP_STE_PRLI_ISSUE: case NLP_STE_UNMAPPED_NODE: @@ -477,13 +419,22 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ if (!(ndlp->nlp_type & NLP_FABRIC) && !(phba->nvmet_support)) { + /* Clear ndlp info, since follow up PRLI may have + * updated ndlp information + */ + ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); + ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; + ndlp->nlp_flag &= ~NLP_FIRSTBURST; + lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); return 1; } if (nlp_portwwn != 0 && nlp_portwwn != wwn_to_u64(sp->portName.u.wwn)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0143 PLOGI recv'd from DID: x%x " "WWPN changed: old %llx new %llx\n", ndlp->nlp_DID, @@ -491,6 +442,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, (unsigned long long) wwn_to_u64(sp->portName.u.wwn)); + /* Notify transport of connectivity loss to trigger cleanup. */ + if (phba->nvmet_support && + ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) + lpfc_nvmet_invalidate_host(phba, ndlp); + ndlp->nlp_prev_state = ndlp->nlp_state; /* rport needs to be unregistered first */ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); @@ -500,6 +456,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; ndlp->nlp_flag &= ~NLP_FIRSTBURST; login_mbox = NULL; @@ -510,7 +467,22 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if ((vport->fc_flag & FC_PT2PT) && !(vport->fc_flag & FC_PT2PT_PLOGI)) { /* rcv'ed PLOGI decides what our NPortId will be */ - vport->fc_myDID = icmd->un.rcvels.parmRo; + if (phba->sli_rev == LPFC_SLI_REV4) { + vport->fc_myDID = bf_get(els_rsp64_sid, + &cmdiocb->wqe.xmit_els_rsp); + } else { + vport->fc_myDID = icmd->un.rcvels.parmRo; + } + + /* If there is an outstanding FLOGI, abort it now. + * The remote NPort is not going to ACC our FLOGI + * if its already issuing a PLOGI for pt2pt mode. + * This indicates our FLOGI was dropped; however, we + * must have ACCed the remote NPorts FLOGI to us + * to make it here. + */ + if (phba->hba_flag & HBA_FLOGI_OUTSTANDING) + lpfc_els_abort_flogi(phba); ed_tov = be32_to_cpu(sp->cmn.e_d_tov); if (sp->cmn.edtovResolution) { @@ -528,27 +500,30 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm)); - /* Issue config_link / reg_vfi to account for updated TOV's */ - + /* Issue CONFIG_LINK for SLI3 or REG_VFI for SLI4, + * to account for updated TOV's / parameters + */ if (phba->sli_rev == LPFC_SLI_REV4) lpfc_issue_reg_vfi(vport); else { - defer_acc = 1; link_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!link_mbox) goto out; lpfc_config_link(phba, link_mbox); - link_mbox->mbox_cmpl = lpfc_defer_pt2pt_acc; + link_mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; link_mbox->vport = vport; + + /* The default completion handling for CONFIG_LINK + * does not require the ndlp so no reference is needed. + */ link_mbox->ctx_ndlp = ndlp; - save_iocb = kzalloc(sizeof(*save_iocb), GFP_KERNEL); - if (!save_iocb) + rc = lpfc_sli_issue_mbox(phba, link_mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + mempool_free(link_mbox, phba->mbox_mem_pool); goto out; - /* Save info from cmd IOCB used in rsp */ - memcpy((uint8_t *)save_iocb, (uint8_t *)cmdiocb, - sizeof(struct lpfc_iocbq)); + } } lpfc_can_disctmo(vport); @@ -567,56 +542,32 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!login_mbox) goto out; - /* Registering an existing RPI behaves differently for SLI3 vs SLI4 */ - if (phba->nvmet_support && !defer_acc) { - link_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!link_mbox) - goto out; - - /* As unique identifiers such as iotag would be overwritten - * with those from the cmdiocb, allocate separate temporary - * storage for the copy. - */ - save_iocb = kzalloc(sizeof(*save_iocb), GFP_KERNEL); - if (!save_iocb) - goto out; - - /* Unreg RPI is required for SLI4. */ - rpi = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - lpfc_unreg_login(phba, vport->vpi, rpi, link_mbox); - link_mbox->vport = vport; - link_mbox->ctx_ndlp = ndlp; - link_mbox->mbox_cmpl = lpfc_defer_acc_rsp; - - if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && - (!(vport->fc_flag & FC_OFFLINE_MODE))) - ndlp->nlp_flag |= NLP_UNREG_INP; + save_iocb = kzalloc(sizeof(*save_iocb), GFP_KERNEL); + if (!save_iocb) + goto out; - /* Save info from cmd IOCB used in rsp */ - memcpy(save_iocb, cmdiocb, sizeof(*save_iocb)); + /* Save info from cmd IOCB to be used in rsp after all mbox completes */ + memcpy((uint8_t *)save_iocb, (uint8_t *)cmdiocb, + sizeof(struct lpfc_iocbq)); - /* Delay sending ACC till unreg RPI completes. */ - defer_acc = 1; - } else if (phba->sli_rev == LPFC_SLI_REV4) + /* Registering an existing RPI behaves differently for SLI3 vs SLI4 */ + if (phba->sli_rev == LPFC_SLI_REV4) lpfc_unreg_rpi(vport, ndlp); - rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID, + /* Issue REG_LOGIN first, before ACCing the PLOGI, thus we will + * always be deferring the ACC. + */ + if (phba->sli_rev == LPFC_SLI_REV4) + remote_did = bf_get(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest); + else + remote_did = icmd->un.rcvels.remoteID; + rc = lpfc_reg_rpi(phba, vport->vpi, remote_did, (uint8_t *)sp, login_mbox, ndlp->nlp_rpi); if (rc) goto out; - /* ACC PLOGI rsp command needs to execute first, - * queue this login_mbox command to be processed later. - */ login_mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; - /* - * login_mbox->ctx_ndlp = lpfc_nlp_get(ndlp) deferred until mailbox - * command issued in lpfc_cmpl_els_acc(). - */ login_mbox->vport = vport; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI); - spin_unlock_irq(shost->host_lock); /* * If there is an outstanding PLOGI issued, abort it before @@ -640,58 +591,72 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* no deferred ACC */ kfree(save_iocb); - /* In order to preserve RPIs, we want to cleanup - * the default RPI the firmware created to rcv - * this ELS request. The only way to do this is - * to register, then unregister the RPI. + /* This is an NPIV SLI4 instance that does not need to register + * a default RPI. */ - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_RM_DFLT_RPI; - spin_unlock_irq(shost->host_lock); + if (phba->sli_rev == LPFC_SLI_REV4) { + lpfc_mbox_rsrc_cleanup(phba, login_mbox, + MBOX_THD_UNLOCKED); + login_mbox = NULL; + } else { + /* In order to preserve RPIs, we want to cleanup + * the default RPI the firmware created to rcv + * this ELS request. The only way to do this is + * to register, then unregister the RPI. + */ + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag |= (NLP_RM_DFLT_RPI | NLP_ACC_REGLOGIN | + NLP_RCV_PLOGI); + spin_unlock_irq(&ndlp->lock); + } + stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD; stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, - ndlp, login_mbox); - if (rc) - mempool_free(login_mbox, phba->mbox_mem_pool); + ndlp, login_mbox); + if (rc && login_mbox) + lpfc_mbox_rsrc_cleanup(phba, login_mbox, + MBOX_THD_UNLOCKED); return 1; } - if (defer_acc) { - /* So the order here should be: - * SLI3 pt2pt - * Issue CONFIG_LINK mbox - * CONFIG_LINK cmpl - * SLI4 tgt - * Issue UNREG RPI mbx - * UNREG RPI cmpl - * Issue PLOGI ACC - * PLOGI ACC cmpl - * Issue REG_LOGIN mbox - */ - /* Save the REG_LOGIN mbox for and rcv IOCB copy later */ - link_mbox->context3 = login_mbox; - login_mbox->context3 = save_iocb; + /* So the order here should be: + * SLI3 pt2pt + * Issue CONFIG_LINK mbox + * CONFIG_LINK cmpl + * SLI4 pt2pt + * Issue REG_VFI mbox + * REG_VFI cmpl + * SLI4 + * Issue UNREG RPI mbx + * UNREG RPI cmpl + * Issue REG_RPI mbox + * REG RPI cmpl + * Issue PLOGI ACC + * PLOGI ACC cmpl + */ + login_mbox->mbox_cmpl = lpfc_defer_plogi_acc; + login_mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!login_mbox->ctx_ndlp) + goto out; - /* Start the ball rolling by issuing CONFIG_LINK here */ - rc = lpfc_sli_issue_mbox(phba, link_mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - goto out; - return 1; + login_mbox->context3 = save_iocb; /* For PLOGI ACC */ + + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI); + spin_unlock_irq(&ndlp->lock); + + /* Start the ball rolling by issuing REG_LOGIN here */ + rc = lpfc_sli_issue_mbox(phba, login_mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_nlp_put(ndlp); + goto out; } + lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); - rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, login_mbox); - if (rc) - mempool_free(login_mbox, phba->mbox_mem_pool); return 1; out: - if (defer_acc) - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "4577 discovery failure: %p %p %p\n", - save_iocb, link_mbox, login_mbox); kfree(save_iocb); - if (link_mbox) - mempool_free(link_mbox, phba->mbox_mem_pool); if (login_mbox) mempool_free(login_mbox, phba->mbox_mem_pool); @@ -728,6 +693,10 @@ lpfc_mbx_cmpl_resume_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, elsiocb, ndlp, NULL); } + + /* This nlp_put pairs with lpfc_sli4_resume_rpi */ + lpfc_nlp_put(ndlp); + kfree(elsiocb); mempool_free(mboxq, phba->mbox_mem_pool); } @@ -736,18 +705,17 @@ static int lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *cmdiocb) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; struct lpfc_dmabuf *pcmd; struct serv_parm *sp; struct lpfc_name *pnn, *ppn; struct ls_rjt stat; ADISC *ap; - IOCB_t *icmd; uint32_t *lp; uint32_t cmd; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; lp = (uint32_t *) pcmd->virt; cmd = *lp++; @@ -761,8 +729,8 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ppn = (struct lpfc_name *) & sp->portName; } - icmd = &cmdiocb->iocb; - if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) { + if (get_job_ulpstatus(phba, cmdiocb) == 0 && + lpfc_check_adisc(vport, ndlp, pnn, ppn)) { /* * As soon as we send ACC, the remote NPort can @@ -773,7 +741,6 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, elsiocb = kmalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL); if (elsiocb) { - /* Save info from cmd IOCB used in rsp */ memcpy((uint8_t *)elsiocb, (uint8_t *)cmdiocb, sizeof(struct lpfc_iocbq)); @@ -794,11 +761,21 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp, NULL); } out: - /* If we are authenticated, move to the proper state */ - if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET)) - lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); - else - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + /* If we are authenticated, move to the proper state. + * It is possible an ADISC arrived and the remote nport + * is already in MAPPED or UNMAPPED state. Catch this + * condition and don't set the nlp_state again because + * it causes an unnecessary transport unregister/register. + * + * Nodes marked for ADISC will move MAPPED or UNMAPPED state + * after issuing ADISC + */ + if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET)) { + if ((ndlp->nlp_state != NLP_STE_MAPPED_NODE) && + !(ndlp->nlp_flag & NLP_NPR_ADISC)) + lpfc_nlp_set_state(vport, ndlp, + NLP_STE_MAPPED_NODE); + } return 1; } @@ -812,9 +789,9 @@ out: /* 1 sec timeout */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); @@ -834,15 +811,31 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary * PLOGIs during LOGO storms from a device. */ - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); if (els_cmd == ELS_CMD_PRLO) lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); else lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); + + /* This clause allows the initiator to ACC the LOGO back to the + * Fabric Domain Controller. It does deliberately skip all other + * steps because some fabrics send RDP requests after logging out + * from the initiator. + */ + if (ndlp->nlp_type & NLP_FABRIC && + ((ndlp->nlp_DID & WELL_KNOWN_DID_MASK) != WELL_KNOWN_DID_MASK)) + return 0; + + /* Notify transport of connectivity loss to trigger cleanup. */ + if (phba->nvmet_support && + ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) + lpfc_nvmet_invalidate_host(phba, ndlp); + if (ndlp->nlp_DID == Fabric_DID) { - if (vport->port_state <= LPFC_FDISC) + if (vport->port_state <= LPFC_FDISC || + vport->fc_flag & FC_PT2PT) goto out; lpfc_linkdown_port(vport); spin_lock_irq(shost->host_lock); @@ -875,9 +868,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_FDISC; vport->port_state = LPFC_FDISC; } else { @@ -888,24 +881,32 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } } else if ((!(ndlp->nlp_type & NLP_FABRIC) && ((ndlp->nlp_type & NLP_FCP_TARGET) || - !(ndlp->nlp_type & NLP_FCP_INITIATOR))) || + (ndlp->nlp_type & NLP_NVME_TARGET) || + (vport->fc_flag & FC_PT2PT))) || (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { - /* Only try to re-login if this is NOT a Fabric Node */ + /* Only try to re-login if this is NOT a Fabric Node + * AND the remote NPORT is a FCP/NVME Target or we + * are in pt2pt mode. NLP_STE_ADISC_ISSUE is a special + * case for LOGO as a response to ADISC behavior. + */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; } out: + /* Unregister from backend, could have been skipped due to ADISC */ + lpfc_nlp_unreg_node(vport, ndlp); + ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* The driver has to wait until the ACC completes before it continues * processing the LOGO. The action will resume in * lpfc_cmpl_els_logo_acc routine. Since part of processing includes an @@ -923,7 +924,7 @@ lpfc_rcv_prli_support_check(struct lpfc_vport *vport, uint32_t *payload; uint32_t cmd; - payload = ((struct lpfc_dmabuf *)cmdiocb->context2)->virt; + payload = cmdiocb->cmd_dmabuf->virt; cmd = *payload; if (vport->phba->nvmet_support) { /* Must be a NVME PRLI */ @@ -960,9 +961,9 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct fc_rport *rport = ndlp->rport; u32 roles; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - npr = (PRLI *) ((uint8_t *) lp + sizeof (uint32_t)); + pcmd = cmdiocb->cmd_dmabuf; + lp = (uint32_t *)pcmd->virt; + npr = (PRLI *)((uint8_t *)lp + sizeof(uint32_t)); if ((npr->prliType == PRLI_FCP_TYPE) || (npr->prliType == PRLI_NVME_TYPE)) { @@ -998,7 +999,12 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_fc4_type |= NLP_FC4_NVME; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); } - if (npr->prliType == PRLI_FCP_TYPE) + + /* Fabric Controllers send FCP PRLI as an initiator but should + * not get recognized as FCP type and registered with transport. + */ + if (npr->prliType == PRLI_FCP_TYPE && + !(ndlp->nlp_type & NLP_FABRIC)) ndlp->nlp_fc4_type |= NLP_FC4_FCP; } if (rport) { @@ -1021,12 +1027,10 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, static uint32_t lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return 0; } @@ -1035,16 +1039,16 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (vport->cfg_use_adisc && ((vport->fc_flag & FC_RSCN_MODE) || ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && (ndlp->nlp_type & NLP_FCP_TARGET)))) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return 1; } } - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_unreg_rpi(vport, ndlp); return 0; } @@ -1053,6 +1057,7 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * lpfc_release_rpi - Release a RPI by issuing unreg_login mailbox cmd. * @phba : Pointer to lpfc_hba structure. * @vport: Pointer to lpfc_vport structure. + * @ndlp: Pointer to lpfc_nodelist structure. * @rpi : rpi to be release. * * This function will send a unreg_login mailbox command to the firmware @@ -1082,13 +1087,17 @@ lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport, pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "2796 mailbox memory allocation failed \n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2796 mailbox memory allocation failed \n"); else { lpfc_unreg_login(phba, vport->vpi, rpi, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; pmb->vport = vport; - pmb->ctx_ndlp = ndlp; + pmb->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!pmb->ctx_ndlp) { + mempool_free(pmb, phba->mbox_mem_pool); + return; + } if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && (!(vport->fc_flag & FC_OFFLINE_MODE))) @@ -1100,8 +1109,10 @@ lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport, ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + lpfc_nlp_put(ndlp); mempool_free(pmb, phba->mbox_mem_pool); + } } } @@ -1121,7 +1132,7 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, rpi = pmb->u.mb.un.varWords[0]; lpfc_release_rpi(phba, vport, ndlp, rpi); } - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0271 Illegal State Transition: node x%x " "event x%x, state x%x Data: x%x x%x\n", ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, @@ -1139,11 +1150,11 @@ lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * to stop it. */ if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0272 Illegal State Transition: node x%x " - "event x%x, state x%x Data: x%x x%x\n", - ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, - ndlp->nlp_flag); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0272 Illegal State Transition: node x%x " + "event x%x, state x%x Data: x%x x%x\n", + ndlp->nlp_DID, evt, ndlp->nlp_state, + ndlp->nlp_rpi, ndlp->nlp_flag); } return ndlp->nlp_state; } @@ -1176,12 +1187,11 @@ static uint32_t lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return ndlp->nlp_state; @@ -1216,7 +1226,7 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb = arg; - struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf; uint32_t *lp = (uint32_t *) pcmd->virt; struct serv_parm *sp = (struct serv_parm *) (lp + 1); struct ls_rjt stat; @@ -1242,9 +1252,9 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (lpfc_rcv_plogi(vport, ndlp, cmdiocb) && (ndlp->nlp_flag & NLP_NPR_2B_DISC) && (vport->num_disc_nodes)) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); /* Check if there are more PLOGIs to be sent */ lpfc_more_plogi(vport); if (vport->num_disc_nodes == 0) { @@ -1294,7 +1304,6 @@ static uint32_t lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; @@ -1309,9 +1318,9 @@ lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Put ndlp in npr state set plogi timer for 1 sec */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); @@ -1326,31 +1335,31 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, uint32_t evt) { struct lpfc_hba *phba = vport->phba; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb, *rspiocb; - struct lpfc_dmabuf *pcmd, *prsp, *mp; + struct lpfc_dmabuf *pcmd, *prsp; uint32_t *lp; uint32_t vid, flag; - IOCB_t *irsp; struct serv_parm *sp; uint32_t ed_tov; LPFC_MBOXQ_t *mbox; int rc; + u32 ulp_status; + u32 did; cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; + rspiocb = cmdiocb->rsp_iocb; + + ulp_status = get_job_ulpstatus(phba, rspiocb); if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) { /* Recovery from PLOGI collision logic */ return ndlp->nlp_state; } - irsp = &rspiocb->iocb; - - if (irsp->ulpStatus) + if (ulp_status) goto out; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + pcmd = cmdiocb->cmd_dmabuf; prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); if (!prsp) @@ -1363,7 +1372,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, if ((ndlp->nlp_DID != FDMI_DID) && (wwn_to_u64(sp->portName.u.wwn) == 0 || wwn_to_u64(sp->nodeName.u.wwn) == 0)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0142 PLOGI RSP: Invalid WWN.\n"); goto out; } @@ -1425,7 +1434,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, } else { mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, + LOG_TRACE_EVENT, "0133 PLOGI: no memory " "for config_link " "Data: x%x x%x x%x x%x\n", @@ -1450,7 +1460,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0018 PLOGI: no memory for reg_login " "Data: x%x x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_state, @@ -1458,11 +1468,15 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, goto out; } - if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID, + did = get_job_els_rsp64_did(phba, cmdiocb); + + if (lpfc_reg_rpi(phba, vport->vpi, did, (uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) { switch (ndlp->nlp_DID) { case NameServer_DID: mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login; + /* Fabric Controller Node needs these parameters. */ + memcpy(&ndlp->fc_sparam, sp, sizeof(struct serv_parm)); break; case FDMI_DID: mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login; @@ -1471,7 +1485,11 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ndlp->nlp_flag |= NLP_REG_LOGIN_SEND; mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; } + mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + if (!mbox->ctx_ndlp) + goto out; + mbox->vport = vport; if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) != MBX_NOT_FINISHED) { @@ -1485,12 +1503,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, * command */ lpfc_nlp_put(ndlp); - mp = (struct lpfc_dmabuf *)mbox->ctx_buf; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(mbox, phba->mbox_mem_pool); - - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0134 PLOGI: cannot issue reg_login " "Data: x%x x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_state, @@ -1498,7 +1512,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, } else { mempool_free(mbox, phba->mbox_mem_pool); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0135 PLOGI: cannot format reg_login " "Data: x%x x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_state, @@ -1509,7 +1523,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, out: if (ndlp->nlp_DID == NameServer_DID) { lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0261 Cannot Register NameServer login\n"); } @@ -1520,9 +1534,6 @@ out: ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DEFER_RM; - spin_unlock_irq(shost->host_lock); return NLP_STE_FREED_NODE; } @@ -1556,12 +1567,10 @@ static uint32_t lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } else { /* software abort outstanding PLOGI */ @@ -1578,7 +1587,6 @@ lpfc_device_recov_plogi_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; /* Don't do anything that will mess up processing of the @@ -1592,9 +1600,9 @@ lpfc_device_recov_plogi_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } @@ -1603,7 +1611,6 @@ static uint32_t lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb; @@ -1614,9 +1621,9 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); if (vport->num_disc_nodes) lpfc_more_adisc(vport); } @@ -1687,32 +1694,29 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb, *rspiocb; - IOCB_t *irsp; ADISC *ap; int rc; + u32 ulp_status; cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; + rspiocb = cmdiocb->rsp_iocb; + + ulp_status = get_job_ulpstatus(phba, rspiocb); ap = (ADISC *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb); - irsp = &rspiocb->iocb; - if ((irsp->ulpStatus) || + if ((ulp_status) || (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) { /* 1 sec timeout */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; - memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name)); - memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name)); - ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); lpfc_unreg_rpi(vport, ndlp); @@ -1728,7 +1732,13 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, } } - if (ndlp->nlp_type & NLP_FCP_TARGET) { + if (ndlp->nlp_type & NLP_FCP_TARGET) + ndlp->nlp_fc4_type |= NLP_FC4_FCP; + + if (ndlp->nlp_type & NLP_NVME_TARGET) + ndlp->nlp_fc4_type |= NLP_FC4_NVME; + + if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET)) { ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); } else { @@ -1743,12 +1753,10 @@ static uint32_t lpfc_device_rm_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } else { /* software abort outstanding ADISC */ @@ -1765,7 +1773,6 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; /* Don't do anything that will mess up processing of the @@ -1779,9 +1786,9 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -1847,7 +1854,6 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; LPFC_MBOXQ_t *mb; LPFC_MBOXQ_t *nextmb; - struct lpfc_dmabuf *mp; struct lpfc_nodelist *ns_ndlp; cmdiocb = (struct lpfc_iocbq *) arg; @@ -1867,16 +1873,11 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *)mb->ctx_ndlp)) { - mp = (struct lpfc_dmabuf *)(mb->ctx_buf); - if (mp) { - __lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; lpfc_nlp_put(ndlp); list_del(&mb->list); phba->sli.mboxq_cnt--; - mempool_free(mb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, mb, MBOX_THD_LOCKED); } } spin_unlock_irq(&phba->hbalock); @@ -1884,7 +1885,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, /* software abort if any GID_FT is outstanding */ if (vport->cfg_enable_fc4_type != LPFC_ENABLE_FCP) { ns_ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ns_ndlp && NLP_CHK_NODE_ACT(ns_ndlp)) + if (ns_ndlp) lpfc_els_abort(phba, ns_ndlp); } @@ -1923,7 +1924,6 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; MAILBOX_t *mb = &pmb->u.mb; @@ -1931,8 +1931,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, if (mb->mbxStatus) { /* RegLogin failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0246 RegLogin failed Data: x%x x%x x%x x%x " + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "0246 RegLogin failed Data: x%x x%x x%x x%x " "x%x\n", did, mb->mbxStatus, vport->port_state, mb->un.varRegLogin.vpi, @@ -1950,14 +1950,12 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, /* Put ndlp in npr state set plogi timer for 1 sec */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; lpfc_issue_els_logo(vport, ndlp, 0); - ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); return ndlp->nlp_state; } @@ -1984,8 +1982,9 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, * is configured try it. */ ndlp->nlp_fc4_type |= NLP_FC4_FCP; - if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || - (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) { + if ((!(vport->fc_flag & FC_PT2PT_NO_NVME)) && + (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH || + vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) { ndlp->nlp_fc4_type |= NLP_FC4_NVME; /* We need to update the localport also */ lpfc_nvme_update_localport(vport); @@ -2022,6 +2021,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, * must complete PRLI. */ if (ndlp->nlp_type & NLP_FABRIC) { + ndlp->nlp_fc4_type &= ~NLP_FC4_FCP; ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); } @@ -2035,12 +2035,10 @@ lpfc_device_rm_reglogin_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } else { lpfc_drop_node(vport, ndlp); @@ -2054,8 +2052,6 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - /* Don't do anything that will mess up processing of the * previous RSCN. */ @@ -2064,7 +2060,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); /* If we are a target we won't immediately transition into PRLI, * so if REG_LOGIN already completed we don't need to ignore it. @@ -2074,7 +2070,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, ndlp->nlp_flag |= NLP_IGNR_REG_CMPL; ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2099,6 +2095,7 @@ lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb)) return ndlp->nlp_state; + lpfc_rcv_prli(vport, ndlp, cmdiocb); lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); return ndlp->nlp_state; } @@ -2145,16 +2142,17 @@ static uint32_t lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb, *rspiocb; struct lpfc_hba *phba = vport->phba; - IOCB_t *irsp; PRLI *npr; struct lpfc_nvme_prli *nvpr; void *temp_ptr; + u32 ulp_status; cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; + rspiocb = cmdiocb->rsp_iocb; + + ulp_status = get_job_ulpstatus(phba, rspiocb); /* A solicited PRLI is either FCP or NVME. The PRLI cmd/rsp * format is different so NULL the two PRLI types so that the @@ -2163,13 +2161,12 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, npr = NULL; nvpr = NULL; temp_ptr = lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb); - if (cmdiocb->iocb_flag & LPFC_PRLI_FCP_REQ) + if (cmdiocb->cmd_flag & LPFC_PRLI_FCP_REQ) npr = (PRLI *) temp_ptr; - else if (cmdiocb->iocb_flag & LPFC_PRLI_NVME_REQ) + else if (cmdiocb->cmd_flag & LPFC_PRLI_NVME_REQ) nvpr = (struct lpfc_nvme_prli *) temp_ptr; - irsp = &rspiocb->iocb; - if (irsp->ulpStatus) { + if (ulp_status) { if ((vport->port_type == LPFC_NPIV_PORT) && vport->cfg_restrict_login) { goto out; @@ -2267,9 +2264,9 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, (vport->port_type == LPFC_NPIV_PORT) && vport->cfg_restrict_login) { out: - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_TARGET_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_issue_els_logo(vport, ndlp, 0); ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; @@ -2321,12 +2318,10 @@ static uint32_t lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } else { /* software abort outstanding PLOGI */ @@ -2360,7 +2355,6 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; /* Don't do anything that will mess up processing of the @@ -2374,9 +2368,9 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2413,12 +2407,11 @@ static uint32_t lpfc_rcv_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)arg; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return ndlp->nlp_state; } @@ -2455,13 +2448,11 @@ static uint32_t lpfc_cmpl_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - ndlp->nlp_prev_state = NLP_STE_LOGO_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2550,19 +2541,27 @@ lpfc_rcv_prlo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } static uint32_t +lpfc_device_rm_unmap_node(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, + void *arg, + uint32_t evt) +{ + lpfc_drop_node(vport, ndlp); + return NLP_STE_FREED_NODE; +} + +static uint32_t lpfc_device_recov_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; @@ -2615,12 +2614,10 @@ static uint32_t lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; /* flush the target */ - lpfc_sli_abort_iocb(vport, &phba->sli.sli3_ring[LPFC_FCP_RING], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); + lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT); /* Treat like rcv logo */ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO); @@ -2633,15 +2630,14 @@ lpfc_device_recov_mapped_node(struct lpfc_vport *vport, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + lpfc_disc_set_adisc(vport, ndlp); ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); - spin_unlock_irq(shost->host_lock); - lpfc_disc_set_adisc(vport, ndlp); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } @@ -2649,7 +2645,6 @@ static uint32_t lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; /* Ignore PLOGI if we have an outstanding LOGO */ @@ -2657,9 +2652,9 @@ lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp->nlp_state; if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } else if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { /* send PLOGI immediately, move to PLOGI issue state */ if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { @@ -2675,7 +2670,6 @@ static uint32_t lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; struct ls_rjt stat; @@ -2685,14 +2679,13 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { - if (ndlp->nlp_flag & NLP_NPR_ADISC) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - spin_unlock_irq(shost->host_lock); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); - lpfc_issue_els_adisc(vport, ndlp, 0); - } else { + /* + * ADISC nodes will be handled in regular discovery path after + * receiving response from NS. + * + * For other nodes, Send PLOGI to trigger an implicit LOGO. + */ + if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); @@ -2725,12 +2718,13 @@ lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ if (!(ndlp->nlp_flag & NLP_DELAY_TMO) && !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { - if (ndlp->nlp_flag & NLP_NPR_ADISC) { - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); - lpfc_issue_els_adisc(vport, ndlp, 0); - } else { + /* + * ADISC nodes will be handled in regular discovery path after + * receiving response from NS. + * + * For other nodes, Send PLOGI to trigger an implicit LOGO. + */ + if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); @@ -2743,27 +2737,26 @@ static uint32_t lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) { mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_DELAY_TMO; ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; } else { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); } return ndlp->nlp_state; } @@ -2772,20 +2765,18 @@ static uint32_t lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { + struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb, *rspiocb; - IOCB_t *irsp; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + u32 ulp_status; cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; + rspiocb = cmdiocb->rsp_iocb; - irsp = &rspiocb->iocb; - if (irsp->ulpStatus) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DEFER_RM; - spin_unlock_irq(shost->host_lock); + ulp_status = get_job_ulpstatus(phba, rspiocb); + + if (ulp_status) return NLP_STE_FREED_NODE; - } + return ndlp->nlp_state; } @@ -2793,14 +2784,16 @@ static uint32_t lpfc_cmpl_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { + struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb, *rspiocb; - IOCB_t *irsp; + u32 ulp_status; cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; + rspiocb = cmdiocb->rsp_iocb; - irsp = &rspiocb->iocb; - if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { + ulp_status = get_job_ulpstatus(phba, rspiocb); + + if (ulp_status && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -2827,14 +2820,16 @@ static uint32_t lpfc_cmpl_adisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { + struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *cmdiocb, *rspiocb; - IOCB_t *irsp; + u32 ulp_status; cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; + rspiocb = cmdiocb->rsp_iocb; + + ulp_status = get_job_ulpstatus(phba, rspiocb); - irsp = &rspiocb->iocb; - if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { + if (ulp_status && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -2870,12 +2865,10 @@ static uint32_t lpfc_device_rm_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } lpfc_drop_node(vport, ndlp); @@ -2886,8 +2879,6 @@ static uint32_t lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - /* Don't do anything that will mess up processing of the * previous RSCN. */ @@ -2895,10 +2886,10 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp->nlp_state; lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; } @@ -3057,7 +3048,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) lpfc_disc_illegal, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_ADISC */ lpfc_disc_illegal, /* CMPL_REG_LOGIN */ - lpfc_disc_illegal, /* DEVICE_RM */ + lpfc_device_rm_unmap_node, /* DEVICE_RM */ lpfc_device_recov_unmap_node, /* DEVICE_RECOVERY */ lpfc_rcv_plogi_mapped_node, /* RCV_PLOGI MAPPED_NODE */ diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index f6c8963c915d..152245f7cacc 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -36,9 +36,6 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> -#include <linux/nvme.h> -#include <linux/nvme-fc-driver.h> -#include <linux/nvme-fc.h> #include "lpfc_version.h" #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -65,180 +62,11 @@ lpfc_release_nvme_buf(struct lpfc_hba *, struct lpfc_io_buf *); static struct nvme_fc_port_template lpfc_nvme_template; -static union lpfc_wqe128 lpfc_iread_cmd_template; -static union lpfc_wqe128 lpfc_iwrite_cmd_template; -static union lpfc_wqe128 lpfc_icmnd_cmd_template; - -/* Setup WQE templates for NVME IOs */ -void -lpfc_nvme_cmd_template(void) -{ - union lpfc_wqe128 *wqe; - - /* IREAD template */ - wqe = &lpfc_iread_cmd_template; - memset(wqe, 0, sizeof(union lpfc_wqe128)); - - /* Word 0, 1, 2 - BDE is variable */ - - /* Word 3 - cmd_buff_len, payload_offset_len is zero */ - - /* Word 4 - total_xfer_len is variable */ - - /* Word 5 - is zero */ - - /* Word 6 - ctxt_tag, xri_tag is variable */ - - /* Word 7 */ - bf_set(wqe_cmnd, &wqe->fcp_iread.wqe_com, CMD_FCP_IREAD64_WQE); - bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, PARM_READ_CHECK); - bf_set(wqe_class, &wqe->fcp_iread.wqe_com, CLASS3); - bf_set(wqe_ct, &wqe->fcp_iread.wqe_com, SLI4_CT_RPI); - - /* Word 8 - abort_tag is variable */ - - /* Word 9 - reqtag is variable */ - - /* Word 10 - dbde, wqes is variable */ - bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0); - bf_set(wqe_nvme, &wqe->fcp_iread.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); - bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4); - bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0); - bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1); - - /* Word 11 - pbde is variable */ - bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, NVME_READ_CMD); - bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 1); - - /* Word 12 - is zero */ - - /* Word 13, 14, 15 - PBDE is variable */ - - /* IWRITE template */ - wqe = &lpfc_iwrite_cmd_template; - memset(wqe, 0, sizeof(union lpfc_wqe128)); - - /* Word 0, 1, 2 - BDE is variable */ - - /* Word 3 - cmd_buff_len, payload_offset_len is zero */ - - /* Word 4 - total_xfer_len is variable */ - - /* Word 5 - initial_xfer_len is variable */ - - /* Word 6 - ctxt_tag, xri_tag is variable */ - - /* Word 7 */ - bf_set(wqe_cmnd, &wqe->fcp_iwrite.wqe_com, CMD_FCP_IWRITE64_WQE); - bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, PARM_READ_CHECK); - bf_set(wqe_class, &wqe->fcp_iwrite.wqe_com, CLASS3); - bf_set(wqe_ct, &wqe->fcp_iwrite.wqe_com, SLI4_CT_RPI); - - /* Word 8 - abort_tag is variable */ - - /* Word 9 - reqtag is variable */ - - /* Word 10 - dbde, wqes is variable */ - bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0); - bf_set(wqe_nvme, &wqe->fcp_iwrite.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4); - bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); - bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); - - /* Word 11 - pbde is variable */ - bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, NVME_WRITE_CMD); - bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 1); - - /* Word 12 - is zero */ - - /* Word 13, 14, 15 - PBDE is variable */ - - /* ICMND template */ - wqe = &lpfc_icmnd_cmd_template; - memset(wqe, 0, sizeof(union lpfc_wqe128)); - - /* Word 0, 1, 2 - BDE is variable */ - - /* Word 3 - payload_offset_len is variable */ - - /* Word 4, 5 - is zero */ - - /* Word 6 - ctxt_tag, xri_tag is variable */ - - /* Word 7 */ - bf_set(wqe_cmnd, &wqe->fcp_icmd.wqe_com, CMD_FCP_ICMND64_WQE); - bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0); - bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, CLASS3); - bf_set(wqe_ct, &wqe->fcp_icmd.wqe_com, SLI4_CT_RPI); - - /* Word 8 - abort_tag is variable */ - - /* Word 9 - reqtag is variable */ - - /* Word 10 - dbde, wqes is variable */ - bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_nvme, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_NONE); - bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE); - bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0); - bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1); - - /* Word 11 */ - bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, FCP_COMMAND); - bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0); - - /* Word 12, 13, 14, 15 - is zero */ -} - -/** - * lpfc_nvme_prep_abort_wqe - set up 'abort' work queue entry. - * @pwqeq: Pointer to command iocb. - * @xritag: Tag that uniqely identifies the local exchange resource. - * @opt: Option bits - - * bit 0 = inhibit sending abts on the link - * - * This function is called with hbalock held. - **/ -void -lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt) -{ - union lpfc_wqe128 *wqe = &pwqeq->wqe; - - /* WQEs are reused. Clear stale data and set key fields to - * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. - */ - memset(wqe, 0, sizeof(*wqe)); - - if (opt & INHIBIT_ABORT) - bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); - /* Abort specified xri tag, with the mask deliberately zeroed */ - bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); - - bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); - - /* Abort the IO associated with this outstanding exchange ID. */ - wqe->abort_cmd.wqe_com.abort_tag = xritag; - - /* iotag for the wqe completion. */ - bf_set(wqe_reqtag, &wqe->abort_cmd.wqe_com, pwqeq->iotag); - - bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); - - bf_set(wqe_cmd_type, &wqe->abort_cmd.wqe_com, OTHER_COMMAND); - bf_set(wqe_wqec, &wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_cqid, &wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); -} - /** * lpfc_nvme_create_queue - - * @lpfc_pnvme: Pointer to the driver's nvme instance data + * @pnvme_lport: Transport localport that LS is to be issued from * @qidx: An cpu index used to affinitize IO queues and MSIX vectors. + * @qsize: Size of the queue in bytes * @handle: An opaque driver handle used in follow-up calls. * * Driver registers this routine to preallocate and initialize any @@ -265,6 +93,11 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport, lport = (struct lpfc_nvme_lport *)pnvme_lport->private; vport = lport->vport; + + if (!vport || vport->load_flag & FC_UNLOADING || + vport->phba->hba_flag & HBA_IOQ_FLUSH) + return -ENODEV; + qhandle = kzalloc(sizeof(struct lpfc_nvme_qhandle), GFP_KERNEL); if (qhandle == NULL) return -ENOMEM; @@ -295,7 +128,7 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport, /** * lpfc_nvme_delete_queue - - * @lpfc_pnvme: Pointer to the driver's nvme instance data + * @pnvme_lport: Transport localport that LS is to be issued from * @qidx: An cpu index used to affinitize IO queues and MSIX vectors. * @handle: An opaque driver handle from lpfc_nvme_create_queue * @@ -358,108 +191,205 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) struct lpfc_nvme_rport *rport = remoteport->private; struct lpfc_vport *vport; struct lpfc_nodelist *ndlp; + u32 fc4_xpt_flags; ndlp = rport->ndlp; - if (!ndlp) + if (!ndlp) { + pr_err("**** %s: NULL ndlp on rport x%px remoteport x%px\n", + __func__, rport, remoteport); goto rport_err; + } vport = ndlp->vport; - if (!vport) + if (!vport) { + pr_err("**** %s: Null vport on ndlp x%px, ste x%x rport x%px\n", + __func__, ndlp, ndlp->nlp_state, rport); goto rport_err; + } + + fc4_xpt_flags = NVME_XPT_REGD | SCSI_XPT_REGD; /* Remove this rport from the lport's list - memory is owned by the * transport. Remove the ndlp reference for the NVME transport before * calling state machine to remove the node. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6146 remoteport delete of remoteport x%px\n", - remoteport); - spin_lock_irq(&vport->phba->hbalock); + "6146 remoteport delete of remoteport x%px, ndlp x%px " + "DID x%x xflags x%x\n", + remoteport, ndlp, ndlp->nlp_DID, ndlp->fc4_xpt_flags); + spin_lock_irq(&ndlp->lock); /* The register rebind might have occurred before the delete * downcall. Guard against this race. */ - if (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG) { - ndlp->nrport = NULL; - ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG; - } - spin_unlock_irq(&vport->phba->hbalock); + if (ndlp->fc4_xpt_flags & NVME_XPT_UNREG_WAIT) + ndlp->fc4_xpt_flags &= ~(NVME_XPT_UNREG_WAIT | NVME_XPT_REGD); + + spin_unlock_irq(&ndlp->lock); - /* Remove original register reference. The host transport - * won't reference this rport/remoteport any further. + /* On a devloss timeout event, one more put is executed provided the + * NVME and SCSI rport unregister requests are complete. If the vport + * is unloading, this extra put is executed by lpfc_drop_node. */ - lpfc_nlp_put(ndlp); + if (!(ndlp->fc4_xpt_flags & fc4_xpt_flags)) + lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); rport_err: return; } -static void -lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, - struct lpfc_wcqe_complete *wcqe) +/** + * lpfc_nvme_handle_lsreq - Process an unsolicited 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 nvme-fc transport via nvme_fc_rcv_ls_req(). + * + * The calling sequence should be: nvme_fc_rcv_ls_req() -> (processing) + * -> lpfc_nvme_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_nvme_handle_lsreq(struct lpfc_hba *phba, + struct lpfc_async_xchg_ctx *axchg) { - struct lpfc_vport *vport = cmdwqe->vport; +#if (IS_ENABLED(CONFIG_NVME_FC)) + struct lpfc_vport *vport; + struct lpfc_nvme_rport *lpfc_rport; + struct nvme_fc_remote_port *remoteport; struct lpfc_nvme_lport *lport; - uint32_t status; + uint32_t *payload = axchg->payload; + int rc; + + vport = axchg->ndlp->vport; + lpfc_rport = axchg->ndlp->nrport; + if (!lpfc_rport) + return -EINVAL; + + remoteport = lpfc_rport->remoteport; + if (!vport->localport || + vport->phba->hba_flag & HBA_IOQ_FLUSH) + return -EINVAL; + + lport = vport->localport->private; + if (!lport) + return -EINVAL; + + rc = nvme_fc_rcv_ls_req(remoteport, &axchg->ls_rsp, axchg->payload, + axchg->size); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, + "6205 NVME Unsol rcv: sz %d rc %d: %08x %08x %08x " + "%08x %08x %08x\n", + axchg->size, rc, + *payload, *(payload+1), *(payload+2), + *(payload+3), *(payload+4), *(payload+5)); + + if (!rc) + return 0; +#endif + return 1; +} + +/** + * __lpfc_nvme_ls_req_cmp - Generic completion handler for a NVME + * LS request. + * @phba: Pointer to HBA context object + * @vport: The local port that issued the LS + * @cmdwqe: Pointer to driver command WQE object. + * @wcqe: Pointer to driver response CQE object. + * + * This function is the generic completion handler for NVME LS requests. + * The function updates any states and statistics, calls the transport + * ls_req done() routine, then tears down the command and buffers used + * for the LS request. + **/ +void +__lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport, + struct lpfc_iocbq *cmdwqe, + struct lpfc_wcqe_complete *wcqe) +{ struct nvmefc_ls_req *pnvme_lsreq; struct lpfc_dmabuf *buf_ptr; struct lpfc_nodelist *ndlp; + uint32_t status; - pnvme_lsreq = (struct nvmefc_ls_req *)cmdwqe->context2; - status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; + pnvme_lsreq = cmdwqe->context_un.nvme_lsreq; + ndlp = cmdwqe->ndlp; + buf_ptr = cmdwqe->bpl_dmabuf; - if (vport->localport) { - lport = (struct lpfc_nvme_lport *)vport->localport->private; - if (lport) { - atomic_inc(&lport->fc4NvmeLsCmpls); - if (status) { - if (bf_get(lpfc_wcqe_c_xb, wcqe)) - atomic_inc(&lport->cmpl_ls_xb); - atomic_inc(&lport->cmpl_ls_err); - } - } - } + status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; - ndlp = (struct lpfc_nodelist *)cmdwqe->context1; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6047 nvme cmpl Enter " - "Data %px DID %x Xri: %x status %x reason x%x " - "cmd:x%px lsreg:x%px bmp:x%px ndlp:x%px\n", + "6047 NVMEx LS REQ x%px cmpl DID %x Xri: %x " + "status %x reason x%x cmd:x%px lsreg:x%px bmp:x%px " + "ndlp:x%px\n", pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0, cmdwqe->sli4_xritag, status, (wcqe->parameter & 0xffff), - cmdwqe, pnvme_lsreq, cmdwqe->context3, ndlp); + cmdwqe, pnvme_lsreq, cmdwqe->bpl_dmabuf, + ndlp); - lpfc_nvmeio_data(phba, "NVME LS CMPL: xri x%x stat x%x parm x%x\n", + lpfc_nvmeio_data(phba, "NVMEx LS CMPL: xri x%x stat x%x parm x%x\n", cmdwqe->sli4_xritag, status, wcqe->parameter); - if (cmdwqe->context3) { - buf_ptr = (struct lpfc_dmabuf *)cmdwqe->context3; + if (buf_ptr) { lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); kfree(buf_ptr); - cmdwqe->context3 = NULL; + cmdwqe->bpl_dmabuf = NULL; } if (pnvme_lsreq->done) pnvme_lsreq->done(pnvme_lsreq, status); else - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, - "6046 nvme cmpl without done call back? " - "Data %px DID %x Xri: %x status %x\n", + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6046 NVMEx cmpl without done call back? " + "Data x%px DID %x Xri: %x status %x\n", pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0, cmdwqe->sli4_xritag, status); if (ndlp) { lpfc_nlp_put(ndlp); - cmdwqe->context1 = NULL; + cmdwqe->ndlp = NULL; } lpfc_sli_release_iocbq(phba, cmdwqe); } +static void +lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + struct lpfc_iocbq *rspwqe) +{ + struct lpfc_vport *vport = cmdwqe->vport; + struct lpfc_nvme_lport *lport; + uint32_t status; + struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl; + + status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; + + if (vport->localport) { + lport = (struct lpfc_nvme_lport *)vport->localport->private; + if (lport) { + atomic_inc(&lport->fc4NvmeLsCmpls); + if (status) { + if (bf_get(lpfc_wcqe_c_xb, wcqe)) + atomic_inc(&lport->cmpl_ls_xb); + atomic_inc(&lport->cmpl_ls_err); + } + } + } + + __lpfc_nvme_ls_req_cmp(phba, vport, cmdwqe, wcqe); +} + static int lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, struct lpfc_dmabuf *inp, struct nvmefc_ls_req *pnvme_lsreq, void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_wcqe_complete *), + struct lpfc_iocbq *), struct lpfc_nodelist *ndlp, uint32_t num_entry, uint32_t tmo, uint8_t retry) { @@ -479,12 +409,19 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, /* Initialize only 64 bytes */ memset(wqe, 0, sizeof(union lpfc_wqe)); - genwqe->context3 = (uint8_t *)bmp; - genwqe->iocb_flag |= LPFC_IO_NVME_LS; + genwqe->bpl_dmabuf = bmp; + genwqe->cmd_flag |= LPFC_IO_NVME_LS; /* Save for completion so we can release these resources */ - genwqe->context1 = lpfc_nlp_get(ndlp); - genwqe->context2 = (uint8_t *)pnvme_lsreq; + genwqe->ndlp = lpfc_nlp_get(ndlp); + if (!genwqe->ndlp) { + dev_warn(&phba->pcidev->dev, + "Warning: Failed node ref, not sending LS_REQ\n"); + lpfc_sli_release_iocbq(phba, genwqe); + return 1; + } + + genwqe->context_un.nvme_lsreq = pnvme_lsreq; /* Fill in payload, bp points to frame payload */ if (!tmo) @@ -504,7 +441,7 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, first_len = xmit_len; } - genwqe->rsvd2 = num_entry; + genwqe->num_bdes = num_entry; genwqe->hba_wqidx = 0; /* Words 0 - 2 */ @@ -531,7 +468,7 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, bf_set(wqe_xri_tag, &wqe->gen_req.wqe_com, genwqe->sli4_xritag); /* Word 7 */ - bf_set(wqe_tmo, &wqe->gen_req.wqe_com, (vport->phba->fc_ratov-1)); + bf_set(wqe_tmo, &wqe->gen_req.wqe_com, tmo); bf_set(wqe_class, &wqe->gen_req.wqe_com, CLASS3); bf_set(wqe_cmnd, &wqe->gen_req.wqe_com, CMD_GEN_REQUEST64_WQE); bf_set(wqe_ct, &wqe->gen_req.wqe_com, SLI4_CT_RPI); @@ -555,15 +492,7 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, /* Issue GEN REQ WQE for NPORT <did> */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "6050 Issue GEN REQ WQE to NPORT x%x " - "Data: x%x x%x wq:x%px lsreq:x%px bmp:x%px " - "xmit:%d 1st:%d\n", - ndlp->nlp_DID, genwqe->iotag, - vport->port_state, - genwqe, pnvme_lsreq, bmp, xmit_len, first_len); - genwqe->wqe_cmpl = cmpl; - genwqe->iocb_cmpl = NULL; + genwqe->cmd_cmpl = cmpl; genwqe->drvrTimeout = tmo + LPFC_DRVR_TIMEOUT; genwqe->vport = vport; genwqe->retry = retry; @@ -573,105 +502,110 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, rc = lpfc_sli4_issue_wqe(phba, &phba->sli4_hba.hdwq[0], genwqe); if (rc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6045 Issue GEN REQ WQE to NPORT x%x " - "Data: x%x x%x\n", + "Data: x%x x%x rc x%x\n", ndlp->nlp_DID, genwqe->iotag, - vport->port_state); + vport->port_state, rc); + lpfc_nlp_put(ndlp); lpfc_sli_release_iocbq(phba, genwqe); return 1; } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_ELS, + "6050 Issue GEN REQ WQE to NPORT x%x " + "Data: oxid: x%x state: x%x wq:x%px lsreq:x%px " + "bmp:x%px xmit:%d 1st:%d\n", + ndlp->nlp_DID, genwqe->sli4_xritag, + vport->port_state, + genwqe, pnvme_lsreq, bmp, xmit_len, first_len); return 0; } + /** - * lpfc_nvme_ls_req - Issue an Link Service request - * @lpfc_pnvme: Pointer to the driver's nvme instance data - * @lpfc_nvme_lport: Pointer to the driver's local port data - * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq + * __lpfc_nvme_ls_req - Generic service routine to issue an NVME LS request + * @vport: The local port issuing the LS + * @ndlp: The remote port to send the LS to + * @pnvme_lsreq: Pointer to LS request structure from the transport + * @gen_req_cmp: Completion call-back * - * Driver registers this routine to handle any link service request - * from the nvme_fc transport to a remote nvme-aware port. + * Routine validates the ndlp, builds buffers and sends a GEN_REQUEST + * WQE to perform the LS operation. * * Return value : * 0 - Success - * TODO: What are the failure codes. + * non-zero: various error codes, in form of -Exxx **/ -static int -lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, - struct nvme_fc_remote_port *pnvme_rport, - struct nvmefc_ls_req *pnvme_lsreq) +int +__lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + struct nvmefc_ls_req *pnvme_lsreq, + void (*gen_req_cmp)(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdwqe, + struct lpfc_iocbq *rspwqe)) { - int ret = 0; - struct lpfc_nvme_lport *lport; - struct lpfc_nvme_rport *rport; - struct lpfc_vport *vport; - struct lpfc_nodelist *ndlp; - struct ulp_bde64 *bpl; struct lpfc_dmabuf *bmp; + struct ulp_bde64 *bpl; + int ret; uint16_t ntype, nstate; - /* there are two dma buf in the request, actually there is one and - * the second one is just the start address + cmd size. - * Before calling lpfc_nvme_gen_req these buffers need to be wrapped - * in a lpfc_dmabuf struct. When freeing we just free the wrapper - * because the nvem layer owns the data bufs. - * We do not have to break these packets open, we don't care what is in - * them. And we do not have to look at the resonse data, we only care - * that we got a response. All of the caring is going to happen in the - * nvme-fc layer. - */ - - lport = (struct lpfc_nvme_lport *)pnvme_lport->private; - rport = (struct lpfc_nvme_rport *)pnvme_rport->private; - if (unlikely(!lport) || unlikely(!rport)) - return -EINVAL; - - vport = lport->vport; - - if (vport->load_flag & FC_UNLOADING) - return -ENODEV; - - /* Need the ndlp. It is stored in the driver's rport. */ - ndlp = rport->ndlp; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, - "6051 Remoteport x%px, rport has invalid ndlp. " - "Failing LS Req\n", pnvme_rport); + if (!ndlp) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6051 NVMEx LS REQ: Bad NDLP x%px, Failing " + "LS Req\n", + ndlp); return -ENODEV; } - /* The remote node has to be a mapped nvme target or an - * unmapped nvme initiator or it's an error. - */ ntype = ndlp->nlp_type; nstate = ndlp->nlp_state; if ((ntype & NLP_NVME_TARGET && nstate != NLP_STE_MAPPED_NODE) || (ntype & NLP_NVME_INITIATOR && nstate != NLP_STE_UNMAPPED_NODE)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, - "6088 DID x%06x not ready for " - "IO. State x%x, Type x%x\n", - pnvme_rport->port_id, - ndlp->nlp_state, ndlp->nlp_type); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6088 NVMEx LS REQ: Fail DID x%06x not " + "ready for IO. Type x%x, State x%x\n", + ndlp->nlp_DID, ntype, nstate); return -ENODEV; } - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) { + if (vport->phba->hba_flag & HBA_IOQ_FLUSH) + return -ENODEV; + + if (!vport->phba->sli4_hba.nvmels_wq) + return -ENOMEM; + + /* + * there are two dma buf in the request, actually there is one and + * the second one is just the start address + cmd size. + * Before calling lpfc_nvme_gen_req these buffers need to be wrapped + * in a lpfc_dmabuf struct. When freeing we just free the wrapper + * because the nvem layer owns the data bufs. + * We do not have to break these packets open, we don't care what is + * in them. And we do not have to look at the resonse data, we only + * care that we got a response. All of the caring is going to happen + * in the nvme-fc layer. + */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, - "6044 Could not find node for DID %x\n", - pnvme_rport->port_id); - return 2; + bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); + if (!bmp) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6044 NVMEx LS REQ: Could not alloc LS buf " + "for DID %x\n", + ndlp->nlp_DID); + return -ENOMEM; } - INIT_LIST_HEAD(&bmp->list); + bmp->virt = lpfc_mbuf_alloc(vport->phba, MEM_PRI, &(bmp->phys)); if (!bmp->virt) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, - "6042 Could not find node for DID %x\n", - pnvme_rport->port_id); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6042 NVMEx LS REQ: Could not alloc mbuf " + "for DID %x\n", + ndlp->nlp_DID); kfree(bmp); - return 3; + return -ENOMEM; } + + INIT_LIST_HEAD(&bmp->list); + bpl = (struct ulp_bde64 *)bmp->virt; bpl->addrHigh = le32_to_cpu(putPaddrHigh(pnvme_lsreq->rqstdma)); bpl->addrLow = le32_to_cpu(putPaddrLow(pnvme_lsreq->rqstdma)); @@ -686,118 +620,202 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, bpl->tus.f.bdeSize = pnvme_lsreq->rsplen; bpl->tus.w = le32_to_cpu(bpl->tus.w); - /* Expand print to include key fields. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6149 Issue LS Req to DID 0x%06x lport x%px, " - "rport x%px lsreq x%px rqstlen:%d rsplen:%d " - "%pad %pad\n", - ndlp->nlp_DID, pnvme_lport, pnvme_rport, - pnvme_lsreq, pnvme_lsreq->rqstlen, - pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma, - &pnvme_lsreq->rspdma); + "6149 NVMEx LS REQ: Issue to DID 0x%06x lsreq x%px, " + "rqstlen:%d rsplen:%d %pad %pad\n", + ndlp->nlp_DID, pnvme_lsreq, pnvme_lsreq->rqstlen, + pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma, + &pnvme_lsreq->rspdma); - atomic_inc(&lport->fc4NvmeLsRequests); - - /* Hardcode the wait to 30 seconds. Connections are failing otherwise. - * This code allows it all to work. - */ ret = lpfc_nvme_gen_req(vport, bmp, pnvme_lsreq->rqstaddr, - pnvme_lsreq, lpfc_nvme_cmpl_gen_req, - ndlp, 2, 30, 0); + pnvme_lsreq, gen_req_cmp, ndlp, 2, + pnvme_lsreq->timeout, 0); if (ret != WQE_SUCCESS) { - atomic_inc(&lport->xmt_ls_err); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, - "6052 EXIT. issue ls wqe failed lport x%px, " - "rport x%px lsreq x%px Status %x DID %x\n", - pnvme_lport, pnvme_rport, pnvme_lsreq, - ret, ndlp->nlp_DID); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6052 NVMEx REQ: EXIT. issue ls wqe failed " + "lsreq x%px Status %x DID %x\n", + pnvme_lsreq, ret, ndlp->nlp_DID); lpfc_mbuf_free(vport->phba, bmp->virt, bmp->phys); kfree(bmp); - return ret; + return -EIO; } - /* Stub in routine and return 0 for now. */ - return ret; + return 0; } /** - * lpfc_nvme_ls_abort - Issue an Link Service request - * @lpfc_pnvme: Pointer to the driver's nvme instance data - * @lpfc_nvme_lport: Pointer to the driver's local port data - * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq + * lpfc_nvme_ls_req - Issue an NVME Link Service request + * @pnvme_lport: Transport localport that LS is to be issued from. + * @pnvme_rport: Transport remoteport that LS is to be sent to. + * @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 - * TODO: What are the failure codes. + * non-zero: various error codes, in form of -Exxx **/ -static void -lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, - struct nvme_fc_remote_port *pnvme_rport, - struct nvmefc_ls_req *pnvme_lsreq) +static int +lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, + struct nvme_fc_remote_port *pnvme_rport, + struct nvmefc_ls_req *pnvme_lsreq) { struct lpfc_nvme_lport *lport; + struct lpfc_nvme_rport *rport; struct lpfc_vport *vport; - struct lpfc_hba *phba; - struct lpfc_nodelist *ndlp; - LIST_HEAD(abort_list); - struct lpfc_sli_ring *pring; - struct lpfc_iocbq *wqe, *next_wqe; + int ret; lport = (struct lpfc_nvme_lport *)pnvme_lport->private; - if (unlikely(!lport)) - return; + rport = (struct lpfc_nvme_rport *)pnvme_rport->private; + if (unlikely(!lport) || unlikely(!rport)) + return -EINVAL; + vport = lport->vport; - phba = vport->phba; + if (vport->load_flag & FC_UNLOADING || + vport->phba->hba_flag & HBA_IOQ_FLUSH) + return -ENODEV; - if (vport->load_flag & FC_UNLOADING) - return; + atomic_inc(&lport->fc4NvmeLsRequests); + + ret = __lpfc_nvme_ls_req(vport, rport->ndlp, pnvme_lsreq, + lpfc_nvme_ls_req_cmp); + if (ret) + atomic_inc(&lport->xmt_ls_err); + + return ret; +} + +/** + * __lpfc_nvme_ls_abort - Generic service routine to abort a prior + * NVME LS request + * @vport: The local port that issued the LS + * @ndlp: The remote port the LS was sent to + * @pnvme_lsreq: Pointer to LS request structure from the transport + * + * The driver validates the ndlp, looks for the LS, and aborts the + * LS if found. + * + * Returns: + * 0 : if LS found and aborted + * non-zero: various error conditions in form -Exxx + **/ +int +__lpfc_nvme_ls_abort(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + struct nvmefc_ls_req *pnvme_lsreq) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_sli_ring *pring; + struct lpfc_iocbq *wqe, *next_wqe; + bool foundit = false; - ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id); if (!ndlp) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, - "6049 Could not find node for DID %x\n", - pnvme_rport->port_id); - return; + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "6049 NVMEx LS REQ Abort: Bad NDLP x%px DID " + "x%06x, Failing LS Req\n", + ndlp, ndlp ? ndlp->nlp_DID : 0); + return -EINVAL; } - /* Expand print to include key fields. */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, - "6040 ENTER. lport x%px, rport x%px lsreq x%px rqstlen:%d " - "rsplen:%d %pad %pad\n", - pnvme_lport, pnvme_rport, + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_NVME_ABTS, + "6040 NVMEx LS REQ Abort: Issue LS_ABORT for lsreq " + "x%px rqstlen:%d rsplen:%d %pad %pad\n", pnvme_lsreq, pnvme_lsreq->rqstlen, pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma, &pnvme_lsreq->rspdma); /* - * Lock the ELS ring txcmplq and build a local list of all ELS IOs - * that need an ABTS. The IOs need to stay on the txcmplq so that - * the abort operation completes them successfully. + * Lock the ELS ring txcmplq and look for the wqe that matches + * this ELS. If found, issue an abort on the wqe. */ pring = phba->sli4_hba.nvmels_wq->pring; spin_lock_irq(&phba->hbalock); spin_lock(&pring->ring_lock); list_for_each_entry_safe(wqe, next_wqe, &pring->txcmplq, list) { - /* Add to abort_list on on NDLP match. */ - if (lpfc_check_sli_ndlp(phba, pring, wqe, ndlp)) { - wqe->iocb_flag |= LPFC_DRIVER_ABORTED; - list_add_tail(&wqe->dlist, &abort_list); + if (wqe->context_un.nvme_lsreq == pnvme_lsreq) { + wqe->cmd_flag |= LPFC_DRIVER_ABORTED; + foundit = true; + break; } } spin_unlock(&pring->ring_lock); + + if (foundit) + lpfc_sli_issue_abort_iotag(phba, pring, wqe, NULL); spin_unlock_irq(&phba->hbalock); - /* Abort the targeted IOs and remove them from the abort list. */ - list_for_each_entry_safe(wqe, next_wqe, &abort_list, dlist) { - atomic_inc(&lport->xmt_ls_abort); - spin_lock_irq(&phba->hbalock); - list_del_init(&wqe->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, wqe); - spin_unlock_irq(&phba->hbalock); + if (foundit) + return 0; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_NVME_ABTS, + "6213 NVMEx LS REQ Abort: Unable to locate req x%px\n", + pnvme_lsreq); + return -EINVAL; +} + +static int +lpfc_nvme_xmt_ls_rsp(struct nvme_fc_local_port *localport, + struct nvme_fc_remote_port *remoteport, + struct nvmefc_ls_rsp *ls_rsp) +{ + struct lpfc_async_xchg_ctx *axchg = + container_of(ls_rsp, struct lpfc_async_xchg_ctx, ls_rsp); + struct lpfc_nvme_lport *lport; + int rc; + + if (axchg->phba->pport->load_flag & FC_UNLOADING) + return -ENODEV; + + lport = (struct lpfc_nvme_lport *)localport->private; + + rc = __lpfc_nvme_xmt_ls_rsp(axchg, ls_rsp, __lpfc_nvme_xmt_ls_rsp_cmp); + + if (rc) { + /* + * unless the failure is due to having already sent + * the response, an abort will be generated for the + * exchange if the rsp can't be sent. + */ + if (rc != -EALREADY) + atomic_inc(&lport->xmt_ls_abort); + return rc; } + + return 0; +} + +/** + * lpfc_nvme_ls_abort - Abort a prior NVME LS request + * @pnvme_lport: Transport localport that LS is to be issued from. + * @pnvme_rport: Transport remoteport that LS is to be sent to. + * @pnvme_lsreq: the transport nvme_ls_req structure for the LS + * + * Driver registers this routine to abort a NVME LS request that is + * in progress (from the transports perspective). + **/ +static void +lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, + struct nvme_fc_remote_port *pnvme_rport, + struct nvmefc_ls_req *pnvme_lsreq) +{ + struct lpfc_nvme_lport *lport; + struct lpfc_vport *vport; + struct lpfc_nodelist *ndlp; + int ret; + + lport = (struct lpfc_nvme_lport *)pnvme_lport->private; + if (unlikely(!lport)) + return; + vport = lport->vport; + + if (vport->load_flag & FC_UNLOADING) + return; + + ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id); + + ret = __lpfc_nvme_ls_abort(vport, ndlp, pnvme_lsreq); + if (!ret) + atomic_inc(&lport->xmt_ls_abort); } /* Fix up the existing sgls for NVME IO. */ @@ -897,94 +915,9 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport, sgl->sge_len = cpu_to_le32(nCmd->rsplen); } -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS -static void -lpfc_nvme_ktime(struct lpfc_hba *phba, - struct lpfc_io_buf *lpfc_ncmd) -{ - uint64_t seg1, seg2, seg3, seg4; - uint64_t segsum; - - if (!lpfc_ncmd->ts_last_cmd || - !lpfc_ncmd->ts_cmd_start || - !lpfc_ncmd->ts_cmd_wqput || - !lpfc_ncmd->ts_isr_cmpl || - !lpfc_ncmd->ts_data_nvme) - return; - - if (lpfc_ncmd->ts_data_nvme < lpfc_ncmd->ts_cmd_start) - return; - if (lpfc_ncmd->ts_cmd_start < lpfc_ncmd->ts_last_cmd) - return; - if (lpfc_ncmd->ts_cmd_wqput < lpfc_ncmd->ts_cmd_start) - return; - if (lpfc_ncmd->ts_isr_cmpl < lpfc_ncmd->ts_cmd_wqput) - return; - if (lpfc_ncmd->ts_data_nvme < lpfc_ncmd->ts_isr_cmpl) - return; - /* - * Segment 1 - Time from Last FCP command cmpl is handed - * off to NVME Layer to start of next command. - * Segment 2 - Time from Driver receives a IO cmd start - * from NVME Layer to WQ put is done on IO cmd. - * Segment 3 - Time from Driver WQ put is done on IO cmd - * to MSI-X ISR for IO cmpl. - * Segment 4 - Time from MSI-X ISR for IO cmpl to when - * cmpl is handled off to the NVME Layer. - */ - seg1 = lpfc_ncmd->ts_cmd_start - lpfc_ncmd->ts_last_cmd; - if (seg1 > 5000000) /* 5 ms - for sequential IOs only */ - seg1 = 0; - - /* Calculate times relative to start of IO */ - seg2 = (lpfc_ncmd->ts_cmd_wqput - lpfc_ncmd->ts_cmd_start); - segsum = seg2; - seg3 = lpfc_ncmd->ts_isr_cmpl - lpfc_ncmd->ts_cmd_start; - if (segsum > seg3) - return; - seg3 -= segsum; - segsum += seg3; - - seg4 = lpfc_ncmd->ts_data_nvme - lpfc_ncmd->ts_cmd_start; - if (segsum > seg4) - return; - seg4 -= segsum; - - phba->ktime_data_samples++; - phba->ktime_seg1_total += seg1; - if (seg1 < phba->ktime_seg1_min) - phba->ktime_seg1_min = seg1; - else if (seg1 > phba->ktime_seg1_max) - phba->ktime_seg1_max = seg1; - phba->ktime_seg2_total += seg2; - if (seg2 < phba->ktime_seg2_min) - phba->ktime_seg2_min = seg2; - else if (seg2 > phba->ktime_seg2_max) - phba->ktime_seg2_max = seg2; - phba->ktime_seg3_total += seg3; - if (seg3 < phba->ktime_seg3_min) - phba->ktime_seg3_min = seg3; - else if (seg3 > phba->ktime_seg3_max) - phba->ktime_seg3_max = seg3; - phba->ktime_seg4_total += seg4; - if (seg4 < phba->ktime_seg4_min) - phba->ktime_seg4_min = seg4; - else if (seg4 > phba->ktime_seg4_max) - phba->ktime_seg4_max = seg4; - - lpfc_ncmd->ts_last_cmd = 0; - lpfc_ncmd->ts_cmd_start = 0; - lpfc_ncmd->ts_cmd_wqput = 0; - lpfc_ncmd->ts_isr_cmpl = 0; - lpfc_ncmd->ts_data_nvme = 0; -} -#endif -/** - * lpfc_nvme_io_cmd_wqe_cmpl - Complete an NVME-over-FCP IO - * @lpfc_pnvme: Pointer to the driver's nvme instance data - * @lpfc_nvme_lport: Pointer to the driver's local port data - * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq +/* + * lpfc_nvme_io_cmd_cmpl - Complete an NVME-over-FCP IO * * Driver registers this routine as it io request handler. This * routine issues an fcp WQE with data from the @lpfc_nvme_fcpreq @@ -995,11 +928,11 @@ lpfc_nvme_ktime(struct lpfc_hba *phba, * TODO: What are the failure codes. **/ static void -lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, - struct lpfc_wcqe_complete *wcqe) +lpfc_nvme_io_cmd_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, + struct lpfc_iocbq *pwqeOut) { - struct lpfc_io_buf *lpfc_ncmd = - (struct lpfc_io_buf *)pwqeIn->context1; + struct lpfc_io_buf *lpfc_ncmd = pwqeIn->io_buf; + struct lpfc_wcqe_complete *wcqe = &pwqeOut->wcqe_cmpl; struct lpfc_vport *vport = pwqeIn->vport; struct nvmefc_fcp_req *nCmd; struct nvme_fc_ersp_iu *ep; @@ -1010,11 +943,16 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, uint32_t code, status, idx; uint16_t cid, sqhd, data; uint32_t *ptr; + uint32_t lat; + bool call_done = false; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + int cpu; +#endif + int offline = 0; /* Sanity check on return of outstanding command */ if (!lpfc_ncmd) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_NODE | LOG_NVME_IOERR, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6071 Null lpfc_ncmd pointer. No " "release, skip completion\n"); return; @@ -1025,7 +963,7 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, if (!lpfc_ncmd->nvmeCmd) { spin_unlock(&lpfc_ncmd->buf_lock); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6066 Missing cmpl ptrs: lpfc_ncmd x%px, " "nvmeCmd x%px\n", lpfc_ncmd, lpfc_ncmd->nvmeCmd); @@ -1057,8 +995,8 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, * transport is still transitioning. */ ndlp = lpfc_ncmd->ndlp; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, + if (!ndlp) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6062 Ignoring NVME cmpl. No ndlp\n"); goto out_err; } @@ -1126,16 +1064,38 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, nCmd->transferred_length = wcqe->total_data_placed; nCmd->rcv_rsplen = wcqe->parameter; nCmd->status = 0; - /* Sanity check */ - if (nCmd->rcv_rsplen == LPFC_NVME_ERSP_LEN) + + /* Get the NVME cmd details for this unique error. */ + cp = (struct nvme_fc_cmd_iu *)nCmd->cmdaddr; + ep = (struct nvme_fc_ersp_iu *)nCmd->rspaddr; + + /* Check if this is really an ERSP */ + if (nCmd->rcv_rsplen == LPFC_NVME_ERSP_LEN) { + lpfc_ncmd->status = IOSTAT_SUCCESS; + lpfc_ncmd->result = 0; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, + "6084 NVME FCP_ERR ERSP: " + "xri %x placed x%x opcode x%x cmd_id " + "x%x cqe_status x%x\n", + lpfc_ncmd->cur_iocbq.sli4_xritag, + wcqe->total_data_placed, + cp->sqe.common.opcode, + cp->sqe.common.command_id, + ep->cqe.status); break; - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, + } + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6081 NVME Completion Protocol Error: " "xri %x status x%x result x%x " - "placed x%x\n", + "placed x%x opcode x%x cmd_id x%x, " + "cqe_status x%x\n", lpfc_ncmd->cur_iocbq.sli4_xritag, lpfc_ncmd->status, lpfc_ncmd->result, - wcqe->total_data_placed); + wcqe->total_data_placed, + cp->sqe.common.opcode, + cp->sqe.common.command_id, + ep->cqe.status); break; case IOSTAT_LOCAL_REJECT: /* Let fall through to set command final state. */ @@ -1148,7 +1108,7 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, lpfc_ncmd, nCmd, lpfc_ncmd->cur_iocbq.sli4_xritag, bf_get(lpfc_wcqe_c_xb, wcqe)); - /* fall through */ + fallthrough; default: out_err: lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, @@ -1162,11 +1122,12 @@ out_err: nCmd->transferred_length = 0; nCmd->rcv_rsplen = 0; nCmd->status = NVME_SC_INTERNAL; + offline = pci_channel_offline(vport->phba->pcidev); } } /* pick up SLI4 exhange busy condition */ - if (bf_get(lpfc_wcqe_c_xb, wcqe)) + if (bf_get(lpfc_wcqe_c_xb, wcqe) && !offline) lpfc_ncmd->flags |= LPFC_SBUF_XBUSY; else lpfc_ncmd->flags &= ~LPFC_SBUF_XBUSY; @@ -1178,23 +1139,19 @@ out_err: #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (lpfc_ncmd->ts_cmd_start) { lpfc_ncmd->ts_isr_cmpl = pwqeIn->isr_timestamp; - lpfc_ncmd->ts_data_nvme = ktime_get_ns(); - phba->ktime_last_cmd = lpfc_ncmd->ts_data_nvme; - lpfc_nvme_ktime(phba, lpfc_ncmd); + lpfc_ncmd->ts_data_io = ktime_get_ns(); + phba->ktime_last_cmd = lpfc_ncmd->ts_data_io; + lpfc_io_ktime(phba, lpfc_ncmd); } - if (unlikely(phba->cpucheck_on & LPFC_CHECK_NVME_IO)) { - uint32_t cpu; - idx = lpfc_ncmd->cur_iocbq.hba_wqidx; + if (unlikely(phba->hdwqstat_on & LPFC_CHECK_NVME_IO)) { cpu = raw_smp_processor_id(); - if (cpu < LPFC_CHECK_CPU_CNT) { - if (lpfc_ncmd->cpu != cpu) - lpfc_printf_vlog(vport, - KERN_INFO, LOG_NVME_IOERR, - "6701 CPU Check cmpl: " - "cpu %d expect %d\n", - cpu, lpfc_ncmd->cpu); - phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++; - } + this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io); + if (lpfc_ncmd->cpu != cpu) + lpfc_printf_vlog(vport, + KERN_INFO, LOG_NVME_IOERR, + "6701 CPU Check cmpl: " + "cpu %d expect %d\n", + cpu, lpfc_ncmd->cpu); } #endif @@ -1206,10 +1163,21 @@ out_err: freqpriv = nCmd->private; freqpriv->nvme_buf = NULL; lpfc_ncmd->nvmeCmd = NULL; - spin_unlock(&lpfc_ncmd->buf_lock); + call_done = true; + } + spin_unlock(&lpfc_ncmd->buf_lock); + + /* Check if IO qualified for CMF */ + if (phba->cmf_active_mode != LPFC_CFG_OFF && + nCmd->io_dir == NVMEFC_FCP_READ && + nCmd->payload_length) { + /* Used when calculating average latency */ + lat = ktime_get_ns() - lpfc_ncmd->rx_cmd_start; + lpfc_update_cmf_cmpl(phba, lat, nCmd->payload_length, NULL); + } + + if (call_done) nCmd->done(nCmd); - } else - spin_unlock(&lpfc_ncmd->buf_lock); /* Call release with XB=1 to queue the IO into the abort list. */ lpfc_release_nvme_buf(phba, lpfc_ncmd); @@ -1218,11 +1186,10 @@ out_err: /** * lpfc_nvme_prep_io_cmd - Issue an NVME-over-FCP IO - * @lpfc_pnvme: Pointer to the driver's nvme instance data - * @lpfc_nvme_lport: Pointer to the driver's local port data - * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq - * @lpfc_nvme_fcreq: IO request from nvme fc to driver. - * @hw_queue_handle: Driver-returned handle in lpfc_nvme_create_queue + * @vport: pointer to a host virtual N_Port data structure + * @lpfc_ncmd: Pointer to lpfc scsi command + * @pnode: pointer to a node-list data structure + * @cstat: pointer to the control status structure * * Driver registers this routine as it io request handler. This * routine issues an fcp WQE with data from the @lpfc_nvme_fcpreq @@ -1240,13 +1207,11 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, { struct lpfc_hba *phba = vport->phba; struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd; - struct lpfc_iocbq *pwqeq = &(lpfc_ncmd->cur_iocbq); + struct nvme_common_command *sqe; + struct lpfc_iocbq *pwqeq = &lpfc_ncmd->cur_iocbq; union lpfc_wqe128 *wqe = &pwqeq->wqe; uint32_t req_len; - if (!NLP_CHK_NODE_ACT(pnode)) - return -EINVAL; - /* * There are three possibilities here - use scatter-gather segment, use * the single mapping, or neither. @@ -1287,6 +1252,10 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, /* Word 5 */ wqe->fcp_iread.rsrvd5 = 0; + /* For a CMF Managed port, iod must be zero'ed */ + if (phba->cmf_active_mode == LPFC_CFG_MANAGED) + bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, + LPFC_WQE_IOD_NONE); cstat->input_requests++; } } else { @@ -1296,8 +1265,14 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, cstat->control_requests++; } - if (pnode->nlp_nvme_info & NLP_NVME_NSLER) + if (pnode->nlp_nvme_info & NLP_NVME_NSLER) { bf_set(wqe_erp, &wqe->generic.wqe_com, 1); + sqe = &((struct nvme_fc_cmd_iu *) + nCmd->cmdaddr)->sqe.common; + if (sqe->opcode == nvme_admin_async_event) + bf_set(wqe_ffrq, &wqe->generic.wqe_com, 1); + } + /* * Finish initializing those WQE fields that are independent * of the nvme_cmnd request_buffer @@ -1318,8 +1293,24 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, /* Word 9 */ bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag); + /* Word 10 */ + bf_set(wqe_xchg, &wqe->fcp_iwrite.wqe_com, LPFC_NVME_XCHG); + /* Words 13 14 15 are for PBDE support */ + /* add the VMID tags as per switch response */ + if (unlikely(lpfc_ncmd->cur_iocbq.cmd_flag & LPFC_IO_VMID)) { + if (phba->pport->vmid_priority_tagging) { + bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com, + lpfc_ncmd->cur_iocbq.vmid_tag.cs_ctl_vmid); + } else { + bf_set(wqe_appid, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); + wqe->words[31] = lpfc_ncmd->cur_iocbq.vmid_tag.app_id; + } + } + pwqeq->vport = vport; return 0; } @@ -1327,11 +1318,8 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, /** * lpfc_nvme_prep_io_dma - Issue an NVME-over-FCP IO - * @lpfc_pnvme: Pointer to the driver's nvme instance data - * @lpfc_nvme_lport: Pointer to the driver's local port data - * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq - * @lpfc_nvme_fcreq: IO request from nvme fc to driver. - * @hw_queue_handle: Driver-returned handle in lpfc_nvme_create_queue + * @vport: pointer to a host virtual N_Port data structure + * @lpfc_ncmd: Pointer to lpfc scsi command * * Driver registers this routine as it io request handler. This * routine issues an fcp WQE with data from the @lpfc_nvme_fcpreq @@ -1354,7 +1342,6 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, struct sli4_sge *first_data_sgl; struct ulp_bde64 *bde; dma_addr_t physaddr = 0; - uint32_t num_bde = 0; uint32_t dma_len = 0; uint32_t dma_offset = 0; int nseg, i, j; @@ -1377,7 +1364,7 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, first_data_sgl = sgl; lpfc_ncmd->seg_cnt = nCmd->sg_cnt; if (lpfc_ncmd->seg_cnt > lpfc_nvme_template.max_sgl_segments) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6058 Too many sg segments from " "NVME Transport. Max %d, " "nvmeIO sg_cnt %d\n", @@ -1400,7 +1387,7 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, j = 2; for (i = 0; i < nseg; i++) { if (data_sg == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6059 dptr err %d, nseg %d\n", i, nseg); lpfc_ncmd->seg_cnt = 0; @@ -1408,7 +1395,7 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, } sgl->word2 = 0; - if ((num_bde + 1) == nseg) { + if (nseg == 1) { bf_set(lpfc_sli4_sge_last, sgl, 1); bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); @@ -1446,8 +1433,8 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, if ((nseg - 1) == i) bf_set(lpfc_sli4_sge_last, sgl, 1); - physaddr = data_sg->dma_address; - dma_len = data_sg->length; + physaddr = sg_dma_address(data_sg); + dma_len = sg_dma_len(data_sg); sgl->addr_lo = cpu_to_le32( putPaddrLow(physaddr)); sgl->addr_hi = cpu_to_le32( @@ -1477,8 +1464,9 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, j++; } - if (phba->cfg_enable_pbde) { - /* Use PBDE support for first SGL only, offset == 0 */ + + /* PBDE support for first data SGE only */ + if (nseg == 1 && phba->cfg_enable_pbde) { /* Words 13-15 */ bde = (struct ulp_bde64 *) &wqe->words[13]; @@ -1488,10 +1476,12 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, le32_to_cpu(first_data_sgl->sge_len); bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; bde->tus.w = cpu_to_le32(bde->tus.w); - /* wqe_pbde is 1 in template */ + + /* Word 11 - set PBDE bit */ + bf_set(wqe_pbde, &wqe->generic.wqe_com, 1); } else { memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); - bf_set(wqe_pbde, &wqe->generic.wqe_com, 0); + /* Word 11 - PBDE bit disabled by default template */ } } else { @@ -1501,7 +1491,7 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, * and sg_cnt must zero. */ if (nCmd->payload_length != 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6063 NVME DMA Prep Err: sg_cnt %d " "payload_length x%x\n", nCmd->sg_cnt, nCmd->payload_length); @@ -1513,16 +1503,14 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, /** * lpfc_nvme_fcp_io_submit - Issue an NVME-over-FCP IO - * @lpfc_pnvme: Pointer to the driver's nvme instance data - * @lpfc_nvme_lport: Pointer to the driver's local port data - * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq - * @lpfc_nvme_fcreq: IO request from nvme fc to driver. + * @pnvme_lport: Pointer to the driver's local port data + * @pnvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq * @hw_queue_handle: Driver-returned handle in lpfc_nvme_create_queue + * @pnvme_fcreq: IO request from nvme fc to driver. * * Driver registers this routine as it io request handler. This * routine issues an fcp WQE with data from the @lpfc_nvme_fcpreq - * data structure to the rport - indicated in @lpfc_nvme_rport. + * data structure to the rport indicated in @lpfc_nvme_rport. * * Return value : * 0 - Success @@ -1547,8 +1535,11 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, struct lpfc_nvme_qhandle *lpfc_queue_info; struct lpfc_nvme_fcpreq_priv *freqpriv; struct nvme_common_command *sqe; -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint64_t start = 0; +#if (IS_ENABLED(CONFIG_NVME_FC)) + u8 *uuid = NULL; + int err; + enum dma_data_direction iodir; #endif /* Validate pointers. LLDD fault handling with transport does @@ -1572,12 +1563,8 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, phba = vport->phba; - if (vport->load_flag & FC_UNLOADING) { - ret = -ENODEV; - goto out_fail; - } - - if (unlikely(vport->load_flag & FC_UNLOADING)) { + if ((unlikely(vport->load_flag & FC_UNLOADING)) || + phba->hba_flag & HBA_IOQ_FLUSH) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, "6124 Fail IO, Driver unload\n"); atomic_inc(&lport->xmt_fcp_err); @@ -1606,7 +1593,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, * transport is still transitioning. */ ndlp = rport->ndlp; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_NVME_IOERR, "6053 Busy IO, ndlp not ready: rport x%px " "ndlp x%px, DID x%06x\n", @@ -1624,7 +1611,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, "IO. State x%x, Type x%x Flg x%x\n", pnvme_rport->port_id, ndlp->nlp_state, ndlp->nlp_type, - ndlp->upcall_flags); + ndlp->fc4_xpt_flags); atomic_inc(&lport->xmt_fcp_bad_ndlp); ret = -EBUSY; goto out_fail; @@ -1642,6 +1629,19 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, expedite = 1; } + /* Check if IO qualifies for CMF */ + if (phba->cmf_active_mode != LPFC_CFG_OFF && + pnvme_fcreq->io_dir == NVMEFC_FCP_READ && + pnvme_fcreq->payload_length) { + ret = lpfc_update_cmf_cmd(phba, pnvme_fcreq->payload_length); + if (ret) { + ret = -EBUSY; + goto out_fail; + } + /* Get start time for IO latency */ + start = ktime_get_ns(); + } + /* The node is shared with FCP IO, make sure the IO pending count does * not exceed the programmed depth. */ @@ -1656,7 +1656,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, ndlp->cmd_qdepth); atomic_inc(&lport->xmt_fcp_qdepth); ret = -EBUSY; - goto out_fail; + goto out_fail1; } } @@ -1676,7 +1676,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, "idx %d DID %x\n", lpfc_queue_info->index, ndlp->nlp_DID); ret = -EBUSY; - goto out_fail; + goto out_fail1; } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (start) { @@ -1686,6 +1686,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, lpfc_ncmd->ts_cmd_start = 0; } #endif + lpfc_ncmd->rx_cmd_start = start; /* * Store the data needed by the driver to issue, abort, and complete @@ -1698,6 +1699,33 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, lpfc_ncmd->ndlp = ndlp; lpfc_ncmd->qidx = lpfc_queue_info->qidx; +#if (IS_ENABLED(CONFIG_NVME_FC)) + /* check the necessary and sufficient condition to support VMID */ + if (lpfc_is_vmid_enabled(phba) && + (ndlp->vmid_support || + phba->pport->vmid_priority_tagging == + LPFC_VMID_PRIO_TAG_ALL_TARGETS)) { + /* is the I/O generated by a VM, get the associated virtual */ + /* entity id */ + uuid = nvme_fc_io_getuuid(pnvme_fcreq); + + if (uuid) { + if (pnvme_fcreq->io_dir == NVMEFC_FCP_WRITE) + iodir = DMA_TO_DEVICE; + else if (pnvme_fcreq->io_dir == NVMEFC_FCP_READ) + iodir = DMA_FROM_DEVICE; + else + iodir = DMA_NONE; + + err = lpfc_vmid_get_appid(vport, uuid, iodir, + (union lpfc_vmid_io_tag *) + &lpfc_ncmd->cur_iocbq.vmid_tag); + if (!err) + lpfc_ncmd->cur_iocbq.cmd_flag |= LPFC_IO_VMID; + } + } +#endif + /* * Issue the IO on the WQ indicated by index in the hw_queue_handle. * This identfier was create in our hardware queue create callback @@ -1743,19 +1771,17 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, if (lpfc_ncmd->ts_cmd_start) lpfc_ncmd->ts_cmd_wqput = ktime_get_ns(); - if (phba->cpucheck_on & LPFC_CHECK_NVME_IO) { + if (phba->hdwqstat_on & LPFC_CHECK_NVME_IO) { cpu = raw_smp_processor_id(); - if (cpu < LPFC_CHECK_CPU_CNT) { - lpfc_ncmd->cpu = cpu; - if (idx != cpu) - lpfc_printf_vlog(vport, - KERN_INFO, LOG_NVME_IOERR, - "6702 CPU Check cmd: " - "cpu %d wq %d\n", - lpfc_ncmd->cpu, - lpfc_queue_info->index); - phba->sli4_hba.hdwq[idx].cpucheck_xmt_io[cpu]++; - } + this_cpu_inc(phba->sli4_hba.c_stat->xmt_io); + lpfc_ncmd->cpu = cpu; + if (idx != cpu) + lpfc_printf_vlog(vport, + KERN_INFO, LOG_NVME_IOERR, + "6702 CPU Check cmd: " + "cpu %d wq %d\n", + lpfc_ncmd->cpu, + lpfc_queue_info->index); } #endif return 0; @@ -1769,6 +1795,9 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, } else cstat->control_requests--; lpfc_release_nvme_buf(phba, lpfc_ncmd); + out_fail1: + lpfc_update_cmf_cmpl(phba, LPFC_CGN_NOT_SENT, + pnvme_fcreq->payload_length, NULL); out_fail: return ret; } @@ -1786,15 +1815,16 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, **/ void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_wcqe_complete *abts_cmpl) + struct lpfc_iocbq *rspiocb) { + struct lpfc_wcqe_complete *abts_cmpl = &rspiocb->wcqe_cmpl; + lpfc_printf_log(phba, KERN_INFO, LOG_NVME, "6145 ABORT_XRI_CN completing on rpi x%x " "original iotag x%x, abort cmd iotag x%x " "req_tag x%x, status x%x, hwstatus x%x\n", - cmdiocb->iocb.un.acxri.abortContextTag, - cmdiocb->iocb.un.acxri.abortIoTag, - cmdiocb->iotag, + bf_get(wqe_ctxt_tag, &cmdiocb->wqe.generic.wqe_com), + get_job_abtsiotag(phba, cmdiocb), cmdiocb->iotag, bf_get(lpfc_wcqe_c_request_tag, abts_cmpl), bf_get(lpfc_wcqe_c_status, abts_cmpl), bf_get(lpfc_wcqe_c_hw_status, abts_cmpl)); @@ -1803,11 +1833,10 @@ lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /** * lpfc_nvme_fcp_abort - Issue an NVME-over-FCP ABTS - * @lpfc_pnvme: Pointer to the driver's nvme instance data - * @lpfc_nvme_lport: Pointer to the driver's local port data - * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq - * @lpfc_nvme_fcreq: IO request from nvme fc to driver. + * @pnvme_lport: Pointer to the driver's local port data + * @pnvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq * @hw_queue_handle: Driver-returned handle in lpfc_nvme_create_queue + * @pnvme_fcreq: IO request from nvme fc to driver. * * Driver registers this routine as its nvme request io abort handler. This * routine issues an fcp Abort WQE with data from the @lpfc_nvme_fcpreq @@ -1828,11 +1857,11 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, struct lpfc_vport *vport; struct lpfc_hba *phba; struct lpfc_io_buf *lpfc_nbuf; - struct lpfc_iocbq *abts_buf; struct lpfc_iocbq *nvmereq_wqe; struct lpfc_nvme_fcpreq_priv *freqpriv; unsigned long flags; int ret_val; + struct nvme_fc_cmd_iu *cp; /* Validate pointers. LLDD fault handling with transport does * have timing races. @@ -1871,7 +1900,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* driver queued commands are in process of being flushed */ if (phba->hba_flag & HBA_IOQ_FLUSH) { spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6139 Driver in reset cleanup - flushing " "NVME Req now. hba_flag x%x\n", phba->hba_flag); @@ -1881,13 +1910,13 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, lpfc_nbuf = freqpriv->nvme_buf; if (!lpfc_nbuf) { spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6140 NVME IO req has no matching lpfc nvme " "io buffer. Skipping abort req.\n"); return; } else if (!lpfc_nbuf->nvmeCmd) { spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6141 lpfc NVME IO req has no nvme_fcreq " "io buffer. Skipping abort req.\n"); return; @@ -1905,7 +1934,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, * has not seen it yet. */ if (lpfc_nbuf->nvmeCmd != pnvme_fcreq) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6143 NVME req mismatch: " "lpfc_nbuf x%px nvmeCmd x%px, " "pnvme_fcreq x%px. Skipping Abort xri x%x\n", @@ -1915,8 +1944,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, } /* Don't abort IOs no longer on the pending queue. */ - if (!(nvmereq_wqe->iocb_flag & LPFC_IO_ON_TXCMPLQ)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + if (!(nvmereq_wqe->cmd_flag & LPFC_IO_ON_TXCMPLQ)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6142 NVME IO req x%px not queued - skipping " "abort req xri x%x\n", pnvme_fcreq, nvmereq_wqe->sli4_xritag); @@ -1929,52 +1958,43 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, nvmereq_wqe->hba_wqidx, pnvme_rport->port_id); /* Outstanding abort is in progress */ - if (nvmereq_wqe->iocb_flag & LPFC_DRIVER_ABORTED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + if (nvmereq_wqe->cmd_flag & LPFC_DRIVER_ABORTED) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6144 Outstanding NVME I/O Abort Request " "still pending on nvme_fcreq x%px, " - "lpfc_ncmd %px xri x%x\n", + "lpfc_ncmd x%px xri x%x\n", pnvme_fcreq, lpfc_nbuf, nvmereq_wqe->sli4_xritag); goto out_unlock; } - abts_buf = __lpfc_sli_get_iocbq(phba); - if (!abts_buf) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, - "6136 No available abort wqes. Skipping " - "Abts req for nvme_fcreq x%px xri x%x\n", - pnvme_fcreq, nvmereq_wqe->sli4_xritag); - goto out_unlock; - } - - /* Ready - mark outstanding as aborted by driver. */ - nvmereq_wqe->iocb_flag |= LPFC_DRIVER_ABORTED; + ret_val = lpfc_sli4_issue_abort_iotag(phba, nvmereq_wqe, + lpfc_nvme_abort_fcreq_cmpl); - lpfc_nvme_prep_abort_wqe(abts_buf, nvmereq_wqe->sli4_xritag, 0); - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abts_buf->iocb_flag |= LPFC_IO_NVME; - abts_buf->hba_wqidx = nvmereq_wqe->hba_wqidx; - abts_buf->vport = vport; - abts_buf->wqe_cmpl = lpfc_nvme_abort_fcreq_cmpl; - ret_val = lpfc_sli4_issue_wqe(phba, lpfc_nbuf->hdwq, abts_buf); spin_unlock(&lpfc_nbuf->buf_lock); spin_unlock_irqrestore(&phba->hbalock, flags); - if (ret_val) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, + + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + + if (ret_val != WQE_SUCCESS) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6137 Failed abts issue_wqe with status x%x " "for nvme_fcreq x%px.\n", ret_val, pnvme_fcreq); - lpfc_sli_release_iocbq(phba, abts_buf); return; } + /* + * Get Command Id from cmd to plug into response. This + * code is not needed in the next NVME Transport drop. + */ + cp = (struct nvme_fc_cmd_iu *)lpfc_nbuf->nvmeCmd->cmdaddr; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, "6138 Transport Abort NVME Request Issued for " - "ox_id x%x on reqtag x%x\n", - nvmereq_wqe->sli4_xritag, - abts_buf->iotag); + "ox_id x%x nvme opcode x%x nvme cmd_id x%x\n", + nvmereq_wqe->sli4_xritag, cp->sqe.common.opcode, + cp->sqe.common.command_id); return; out_unlock: @@ -1985,8 +2005,6 @@ out_unlock: /* Declare and initialization an instance of the FC NVME template. */ static struct nvme_fc_port_template lpfc_nvme_template = { - .module = THIS_MODULE, - /* initiator-based functions */ .localport_delete = lpfc_nvme_localport_delete, .remoteport_delete = lpfc_nvme_remoteport_delete, @@ -1996,6 +2014,7 @@ static struct nvme_fc_port_template lpfc_nvme_template = { .fcp_io = lpfc_nvme_fcp_io_submit, .ls_abort = lpfc_nvme_ls_abort, .fcp_abort = lpfc_nvme_fcp_abort, + .xmt_ls_rsp = lpfc_nvme_xmt_ls_rsp, .max_hw_queues = 1, .max_sgl_segments = LPFC_NVME_DEFAULT_SEGS, @@ -2011,9 +2030,8 @@ static struct nvme_fc_port_template lpfc_nvme_template = { .fcprqst_priv_sz = sizeof(struct lpfc_nvme_fcpreq_priv), }; -/** +/* * lpfc_get_nvme_buf - Get a nvme buffer from io_buf_list of the HBA - * @phba: The HBA for which this call is being executed. * * This routine removes a nvme buffer from head of @hdwq io_buf_list * and returns to caller. @@ -2041,8 +2059,8 @@ lpfc_get_nvme_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, /* Setup key fields in buffer that may have been changed * if other protocols used this buffer. */ - pwqeq->iocb_flag = LPFC_IO_NVME; - pwqeq->wqe_cmpl = lpfc_nvme_io_cmd_wqe_cmpl; + pwqeq->cmd_flag = LPFC_IO_NVME; + pwqeq->cmd_cmpl = lpfc_nvme_io_cmd_cmpl; lpfc_ncmd->start_time = jiffies; lpfc_ncmd->flags = 0; @@ -2113,7 +2131,7 @@ lpfc_release_nvme_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd) /** * lpfc_nvme_create_localport - Create/Bind an nvme localport instance. - * @pvport - the lpfc_vport instance requesting a localport. + * @vport: the lpfc_vport instance requesting a localport. * * This routine is invoked to create an nvme localport instance to bind * to the nvme_fc_transport. It is called once during driver load @@ -2191,6 +2209,7 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) atomic_set(&lport->cmpl_fcp_err, 0); atomic_set(&lport->cmpl_ls_xb, 0); atomic_set(&lport->cmpl_ls_err, 0); + atomic_set(&lport->fc4NvmeLsRequests, 0); atomic_set(&lport->fc4NvmeLsCmpls, 0); } @@ -2218,6 +2237,8 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, int ret, i, pending = 0; struct lpfc_sli_ring *pring; struct lpfc_hba *phba = vport->phba; + struct lpfc_sli4_hdw_queue *qp; + int abts_scsi, abts_nvme; /* Host transport has to clean up and confirm requiring an indefinite * wait. Print a message if a 10 second wait expires and renew the @@ -2228,17 +2249,31 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, ret = wait_for_completion_timeout(lport_unreg_cmp, wait_tmo); if (unlikely(!ret)) { pending = 0; + abts_scsi = 0; + abts_nvme = 0; for (i = 0; i < phba->cfg_hdw_queue; i++) { - pring = phba->sli4_hba.hdwq[i].io_wq->pring; + qp = &phba->sli4_hba.hdwq[i]; + if (!vport->localport || !qp || !qp->io_wq) + return; + + pring = qp->io_wq->pring; if (!pring) continue; - if (pring->txcmplq_cnt) - pending += pring->txcmplq_cnt; + pending += pring->txcmplq_cnt; + abts_scsi += qp->abts_scsi_io_bufs; + abts_nvme += qp->abts_nvme_io_bufs; } - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, + if (!vport->localport || + test_bit(HBA_PCI_ERR, &vport->phba->bit_flags) || + vport->load_flag & FC_UNLOADING) + return; + + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6176 Lport x%px Localport x%px wait " - "timed out. Pending %d. Renewing.\n", - lport, vport->localport, pending); + "timed out. Pending %d [%d:%d]. " + "Renewing.\n", + lport, vport->localport, pending, + abts_scsi, abts_nvme); continue; } break; @@ -2251,7 +2286,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, /** * lpfc_nvme_destroy_localport - Destroy lpfc_nvme bound to nvme transport. - * @pnvme: pointer to lpfc nvme data structure. + * @vport: pointer to a host virtual N_Port data structure * * This routine is invoked to destroy all lports bound to the phba. * The lport memory was allocated by the nvme fc transport and is @@ -2272,6 +2307,8 @@ lpfc_nvme_destroy_localport(struct lpfc_vport *vport) return; localport = vport->localport; + if (!localport) + return; lport = (struct lpfc_nvme_lport *)localport->private; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, @@ -2357,6 +2394,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) struct nvme_fc_remote_port *remote_port; struct nvme_fc_port_info rpinfo; struct lpfc_nodelist *prev_ndlp = NULL; + struct fc_rport *srport = ndlp->rport; lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NVME_DISC, "6006 Register NVME PORT. DID x%06x nlptype x%x\n", @@ -2386,15 +2424,28 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rpinfo.port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn); rpinfo.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn); + if (srport) + rpinfo.dev_loss_tmo = srport->dev_loss_tmo; + else + rpinfo.dev_loss_tmo = vport->cfg_devloss_tmo; + + spin_lock_irq(&ndlp->lock); - spin_lock_irq(&vport->phba->hbalock); + /* If an oldrport exists, so does the ndlp reference. If not + * a new reference is needed because either the node has never + * been registered or it's been unregistered and getting deleted. + */ oldrport = lpfc_ndlp_get_nrport(ndlp); if (oldrport) { prev_ndlp = oldrport->ndlp; - spin_unlock_irq(&vport->phba->hbalock); + spin_unlock_irq(&ndlp->lock); } else { - spin_unlock_irq(&vport->phba->hbalock); - lpfc_nlp_get(ndlp); + spin_unlock_irq(&ndlp->lock); + if (!lpfc_nlp_get(ndlp)) { + dev_warn(&vport->phba->pcidev->dev, + "Warning - No node ref - exit register\n"); + return 0; + } } ret = nvme_fc_register_remoteport(localport, &rpinfo, &remote_port); @@ -2406,52 +2457,21 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* Guard against an unregister/reregister * race that leaves the WAIT flag set. */ - spin_lock_irq(&vport->phba->hbalock); - ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG; - spin_unlock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); + ndlp->fc4_xpt_flags &= ~NVME_XPT_UNREG_WAIT; + ndlp->fc4_xpt_flags |= NVME_XPT_REGD; + spin_unlock_irq(&ndlp->lock); rport = remote_port->private; if (oldrport) { - /* New remoteport record does not guarantee valid - * host private memory area. - */ - if (oldrport == remote_port->private) { - /* Same remoteport - ndlp should match. - * Just reuse. - */ - lpfc_printf_vlog(ndlp->vport, KERN_INFO, - LOG_NVME_DISC, - "6014 Rebind lport to current " - "remoteport x%px wwpn 0x%llx, " - "Data: x%x x%x x%px x%px x%x " - " x%06x\n", - remote_port, - remote_port->port_name, - remote_port->port_id, - remote_port->port_role, - oldrport->ndlp, - ndlp, - ndlp->nlp_type, - ndlp->nlp_DID); - - /* It's a complete rebind only if the driver - * is registering with the same ndlp. Otherwise - * the driver likely executed a node swap - * prior to this registration and the ndlp to - * remoteport binding needs to be redone. - */ - if (prev_ndlp == ndlp) - return 0; - - } /* Sever the ndlp<->rport association * before dropping the ndlp ref from * register. */ - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); ndlp->nrport = NULL; - ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG; - spin_unlock_irq(&vport->phba->hbalock); + ndlp->fc4_xpt_flags &= ~NVME_XPT_UNREG_WAIT; + spin_unlock_irq(&ndlp->lock); rport->ndlp = NULL; rport->remoteport = NULL; @@ -2460,8 +2480,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * reference would cause a premature cleanup. */ if (prev_ndlp && prev_ndlp != ndlp) { - if ((!NLP_CHK_NODE_ACT(prev_ndlp)) || - (!prev_ndlp->nrport)) + if (!prev_ndlp->nrport) lpfc_nlp_put(prev_ndlp); } } @@ -2470,9 +2489,9 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rport->remoteport = remote_port; rport->lport = lport; rport->ndlp = ndlp; - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); ndlp->nrport = rport; - spin_unlock_irq(&vport->phba->hbalock); + spin_unlock_irq(&ndlp->lock); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_NODE, "6022 Bind lport x%px to remoteport x%px " @@ -2485,7 +2504,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp, prev_ndlp); } else { lpfc_printf_vlog(vport, KERN_ERR, - LOG_NVME_DISC | LOG_NODE, + LOG_TRACE_EVENT, "6031 RemotePort Registration failed " "err: %d, DID x%06x\n", ret, ndlp->nlp_DID); @@ -2497,7 +2516,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) #endif } -/** +/* * lpfc_nvme_rescan_port - Check to see if we should rescan this remoteport * * If the ndlp represents an NVME Target, that we are logged into, @@ -2511,11 +2530,11 @@ lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) struct lpfc_nvme_rport *nrport; struct nvme_fc_remote_port *remoteport = NULL; - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); nrport = lpfc_ndlp_get_nrport(ndlp); if (nrport) remoteport = nrport->remoteport; - spin_unlock_irq(&vport->phba->hbalock); + spin_unlock_irq(&ndlp->lock); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6170 Rescan NPort DID x%06x type x%x " @@ -2526,12 +2545,12 @@ lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!nrport || !remoteport) goto rescan_exit; - /* Only rescan if we are an NVME target in the MAPPED state */ + /* Rescan an NVME target in MAPPED state with DISCOVERY role set */ if (remoteport->port_role & FC_PORT_ROLE_NVME_DISCOVERY && ndlp->nlp_state == NLP_STE_MAPPED_NODE) { nvme_fc_rescan_remoteport(remoteport); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6172 NVME rescanned DID x%06x " "port_state x%x\n", ndlp->nlp_DID, remoteport->port_state); @@ -2578,20 +2597,21 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!lport) goto input_err; - spin_lock_irq(&vport->phba->hbalock); + spin_lock_irq(&ndlp->lock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) remoteport = rport->remoteport; - spin_unlock_irq(&vport->phba->hbalock); + spin_unlock_irq(&ndlp->lock); if (!remoteport) goto input_err; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6033 Unreg nvme remoteport x%px, portname x%llx, " - "port_id x%06x, portstate x%x port type x%x\n", + "port_id x%06x, portstate x%x port type x%x " + "refcnt %d\n", remoteport, remoteport->port_name, remoteport->port_id, remoteport->port_state, - ndlp->nlp_type); + ndlp->nlp_type, kref_read(&ndlp->kref)); /* Sanity check ndlp type. Only call for NVME ports. Don't * clear any rport state until the transport calls back. @@ -2601,7 +2621,9 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* No concern about the role change on the nvme remoteport. * The transport will update it. */ - ndlp->upcall_flags |= NLP_WAIT_FOR_UNREG; + spin_lock_irq(&vport->phba->hbalock); + ndlp->fc4_xpt_flags |= NVME_XPT_UNREG_WAIT; + spin_unlock_irq(&vport->phba->hbalock); /* Don't let the host nvme transport keep sending keep-alives * on this remoteport. Vport is unloading, no recovery. The @@ -2612,9 +2634,16 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) (void)nvme_fc_set_remoteport_devloss(remoteport, 0); ret = nvme_fc_unregister_remoteport(remoteport); + + /* The driver no longer knows if the nrport memory is valid. + * because the controller teardown process has begun and + * is asynchronous. Break the binding in the ndlp. Also + * remove the register ndlp reference to setup node release. + */ + ndlp->nrport = NULL; + lpfc_nlp_put(ndlp); if (ret != 0) { - lpfc_nlp_put(ndlp); - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6167 NVME unregister failed %d " "port_state x%x\n", ret, remoteport->port_state); @@ -2624,12 +2653,48 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) input_err: #endif - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6168 State error: lport x%px, rport x%px FCID x%06x\n", vport->localport, ndlp->rport, ndlp->nlp_DID); } /** + * lpfc_sli4_nvme_pci_offline_aborted - Fast-path process of NVME xri abort + * @phba: pointer to lpfc hba data structure. + * @lpfc_ncmd: The nvme job structure for the request being aborted. + * + * This routine is invoked by the worker thread to process a SLI4 fast-path + * NVME aborted xri. Aborted NVME IO commands are completed to the transport + * here. + **/ +void +lpfc_sli4_nvme_pci_offline_aborted(struct lpfc_hba *phba, + struct lpfc_io_buf *lpfc_ncmd) +{ + struct nvmefc_fcp_req *nvme_cmd = NULL; + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6533 %s nvme_cmd %p tag x%x abort complete and " + "xri released\n", __func__, + lpfc_ncmd->nvmeCmd, + lpfc_ncmd->cur_iocbq.iotag); + + /* Aborted NVME commands are required to not complete + * before the abort exchange command fully completes. + * Once completed, it is available via the put list. + */ + if (lpfc_ncmd->nvmeCmd) { + nvme_cmd = lpfc_ncmd->nvmeCmd; + nvme_cmd->transferred_length = 0; + nvme_cmd->rcv_rsplen = 0; + nvme_cmd->status = NVME_SC_INTERNAL; + nvme_cmd->done(nvme_cmd); + lpfc_ncmd->nvmeCmd = NULL; + } + lpfc_release_nvme_buf(phba, lpfc_ncmd); +} + +/** * lpfc_sli4_nvme_xri_aborted - Fast-path process of NVME xri abort * @phba: pointer to lpfc hba data structure. * @axri: pointer to the fcp xri abort wcqe structure. @@ -2709,23 +2774,30 @@ lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba) * dump a message. Something is wrong. */ if ((wait_cnt % 1000) == 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6178 NVME IO not empty, " "cnt %d\n", wait_cnt); } } } + + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + } void -lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn) +lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, + uint32_t stat, uint32_t param) { #if (IS_ENABLED(CONFIG_NVME_FC)) struct lpfc_io_buf *lpfc_ncmd; struct nvmefc_fcp_req *nCmd; - struct lpfc_nvme_fcpreq_priv *freqpriv; + struct lpfc_wcqe_complete wcqe; + struct lpfc_wcqe_complete *wcqep = &wcqe; - if (!pwqeIn->context1) { + lpfc_ncmd = pwqeIn->io_buf; + if (!lpfc_ncmd) { lpfc_sli_release_iocbq(phba, pwqeIn); return; } @@ -2735,31 +2807,31 @@ lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn) lpfc_sli_release_iocbq(phba, pwqeIn); return; } - lpfc_ncmd = (struct lpfc_io_buf *)pwqeIn->context1; spin_lock(&lpfc_ncmd->buf_lock); - if (!lpfc_ncmd->nvmeCmd) { + nCmd = lpfc_ncmd->nvmeCmd; + if (!nCmd) { spin_unlock(&lpfc_ncmd->buf_lock); lpfc_release_nvme_buf(phba, lpfc_ncmd); return; } + spin_unlock(&lpfc_ncmd->buf_lock); - nCmd = lpfc_ncmd->nvmeCmd; lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, "6194 NVME Cancel xri %x\n", lpfc_ncmd->cur_iocbq.sli4_xritag); - nCmd->transferred_length = 0; - nCmd->rcv_rsplen = 0; - nCmd->status = NVME_SC_INTERNAL; - freqpriv = nCmd->private; - freqpriv->nvme_buf = NULL; - lpfc_ncmd->nvmeCmd = NULL; - - spin_unlock(&lpfc_ncmd->buf_lock); - nCmd->done(nCmd); + wcqep->word0 = 0; + bf_set(lpfc_wcqe_c_status, wcqep, stat); + wcqep->parameter = param; + wcqep->total_data_placed = 0; + wcqep->word3 = 0; /* xb is 0 */ /* Call release with XB=1 to queue the IO into the abort list. */ - lpfc_release_nvme_buf(phba, lpfc_ncmd); + if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) + bf_set(lpfc_wcqe_c_xb, wcqep, 1); + + memcpy(&pwqeIn->wcqe_cmpl, wcqep, sizeof(*wcqep)); + (pwqeIn->cmd_cmpl)(phba, pwqeIn, pwqeIn); #endif } diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h index 593c48ff634e..733c277948c0 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.h +++ b/drivers/scsi/lpfc/lpfc_nvme.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -21,6 +21,10 @@ * included with this package. * ********************************************************************/ +#include <linux/nvme.h> +#include <linux/nvme-fc-driver.h> +#include <linux/nvme-fc.h> + #define LPFC_NVME_DEFAULT_SEGS (64 + 1) /* 256K IOs */ #define LPFC_NVME_ERSP_LEN 0x20 @@ -30,11 +34,8 @@ #define LPFC_NVME_FB_SHIFT 9 #define LPFC_NVME_MAX_FB (1 << 20) /* 1M */ -#define LPFC_MAX_NVME_INFO_TMP_LEN 100 -#define LPFC_NVME_INFO_MORE_STR "\nCould be more info...\n" - -#define lpfc_ndlp_get_nrport(ndlp) \ - ((!ndlp->nrport || (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG)) \ +#define lpfc_ndlp_get_nrport(ndlp) \ + ((!ndlp->nrport || (ndlp->fc4_xpt_flags & NVME_XPT_UNREG_WAIT))\ ? NULL : ndlp->nrport) struct lpfc_nvme_qhandle { @@ -74,3 +75,179 @@ struct lpfc_nvme_rport { struct lpfc_nvme_fcpreq_priv { struct lpfc_io_buf *nvme_buf; }; + +/* + * set NVME LS request timeouts to 30s. It is larger than the 2*R_A_TOV + * set by the spec, which appears to have issues with some devices. + */ +#define LPFC_NVME_LS_TIMEOUT 30 + + +#define LPFC_NVMET_DEFAULT_SEGS (64 + 1) /* 256K IOs */ +#define LPFC_NVMET_RQE_MIN_POST 128 +#define LPFC_NVMET_RQE_DEF_POST 512 +#define LPFC_NVMET_RQE_DEF_COUNT 2048 +#define LPFC_NVMET_SUCCESS_LEN 12 + +#define LPFC_NVMET_MRQ_AUTO 0 +#define LPFC_NVMET_MRQ_MAX 16 + +#define LPFC_NVMET_WAIT_TMO (5 * MSEC_PER_SEC) + +/* Used for NVME Target */ +#define LPFC_NVMET_INV_HOST_ACTIVE 1 + +struct lpfc_nvmet_tgtport { + struct lpfc_hba *phba; + struct completion *tport_unreg_cmp; + atomic_t state; /* tracks nvmet hosthandle invalidation */ + + /* Stats counters - lpfc_nvmet_unsol_ls_buffer */ + atomic_t rcv_ls_req_in; + atomic_t rcv_ls_req_out; + atomic_t rcv_ls_req_drop; + atomic_t xmt_ls_abort; + atomic_t xmt_ls_abort_cmpl; + + /* Stats counters - lpfc_nvmet_xmt_ls_rsp */ + atomic_t xmt_ls_rsp; + atomic_t xmt_ls_drop; + + /* Stats counters - lpfc_nvmet_xmt_ls_rsp_cmp */ + atomic_t xmt_ls_rsp_error; + atomic_t xmt_ls_rsp_aborted; + atomic_t xmt_ls_rsp_xb_set; + atomic_t xmt_ls_rsp_cmpl; + + /* Stats counters - lpfc_nvmet_unsol_fcp_buffer */ + atomic_t rcv_fcp_cmd_in; + atomic_t rcv_fcp_cmd_out; + atomic_t rcv_fcp_cmd_drop; + atomic_t rcv_fcp_cmd_defer; + atomic_t xmt_fcp_release; + + /* Stats counters - lpfc_nvmet_xmt_fcp_op */ + atomic_t xmt_fcp_drop; + atomic_t xmt_fcp_read_rsp; + atomic_t xmt_fcp_read; + atomic_t xmt_fcp_write; + atomic_t xmt_fcp_rsp; + + /* Stats counters - lpfc_nvmet_xmt_fcp_op_cmp */ + atomic_t xmt_fcp_rsp_xb_set; + atomic_t xmt_fcp_rsp_cmpl; + atomic_t xmt_fcp_rsp_error; + atomic_t xmt_fcp_rsp_aborted; + atomic_t xmt_fcp_rsp_drop; + + /* Stats counters - lpfc_nvmet_xmt_fcp_abort */ + atomic_t xmt_fcp_xri_abort_cqe; + atomic_t xmt_fcp_abort; + atomic_t xmt_fcp_abort_cmpl; + atomic_t xmt_abort_sol; + atomic_t xmt_abort_unsol; + atomic_t xmt_abort_rsp; + atomic_t xmt_abort_rsp_error; + + /* Stats counters - defer IO */ + atomic_t defer_ctx; + atomic_t defer_fod; + atomic_t defer_wqfull; +}; + +struct lpfc_nvmet_ctx_info { + struct list_head nvmet_ctx_list; + spinlock_t nvmet_ctx_list_lock; /* lock per CPU */ + struct lpfc_nvmet_ctx_info *nvmet_ctx_next_cpu; + struct lpfc_nvmet_ctx_info *nvmet_ctx_start_cpu; + uint16_t nvmet_ctx_list_cnt; + char pad[16]; /* pad to a cache-line */ +}; + +/* This retrieves the context info associated with the specified cpu / mrq */ +#define lpfc_get_ctx_list(phba, cpu, mrq) \ + (phba->sli4_hba.nvmet_ctx_info + ((cpu * phba->cfg_nvmet_mrq) + mrq)) + +/* Values for state field of struct lpfc_async_xchg_ctx */ +#define LPFC_NVME_STE_LS_RCV 1 +#define LPFC_NVME_STE_LS_ABORT 2 +#define LPFC_NVME_STE_LS_RSP 3 +#define LPFC_NVME_STE_RCV 4 +#define LPFC_NVME_STE_DATA 5 +#define LPFC_NVME_STE_ABORT 6 +#define LPFC_NVME_STE_DONE 7 +#define LPFC_NVME_STE_FREE 0xff + +/* Values for flag field of struct lpfc_async_xchg_ctx */ +#define LPFC_NVME_IO_INP 0x1 /* IO is in progress on exchange */ +#define LPFC_NVME_ABORT_OP 0x2 /* Abort WQE issued on exchange */ +#define LPFC_NVME_XBUSY 0x4 /* XB bit set on IO cmpl */ +#define LPFC_NVME_CTX_RLS 0x8 /* ctx free requested */ +#define LPFC_NVME_ABTS_RCV 0x10 /* ABTS received on exchange */ +#define LPFC_NVME_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */ +#define LPFC_NVME_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ +#define LPFC_NVME_TNOTIFY 0x80 /* notify transport of abts */ + +struct lpfc_async_xchg_ctx { + union { + struct nvmefc_tgt_fcp_req fcp_req; + } hdlrctx; + struct list_head list; + struct lpfc_hba *phba; + struct lpfc_nodelist *ndlp; + struct nvmefc_ls_req *ls_req; + struct nvmefc_ls_rsp ls_rsp; + struct lpfc_iocbq *wqeq; + struct lpfc_iocbq *abort_wqeq; + spinlock_t ctxlock; /* protect flag access */ + uint32_t sid; + uint32_t offset; + uint16_t oxid; + uint16_t size; + uint16_t entry_cnt; + uint16_t cpu; + uint16_t idx; + uint16_t state; + uint16_t flag; + void *payload; + struct rqb_dmabuf *rqb_buffer; + struct lpfc_nvmet_ctxbuf *ctxbuf; + struct lpfc_sli4_hdw_queue *hdwq; + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + uint64_t ts_isr_cmd; + uint64_t ts_cmd_nvme; + uint64_t ts_nvme_data; + uint64_t ts_data_wqput; + uint64_t ts_isr_data; + uint64_t ts_data_nvme; + uint64_t ts_nvme_status; + uint64_t ts_status_wqput; + uint64_t ts_isr_status; + uint64_t ts_status_nvme; +#endif +}; + + +/* routines found in lpfc_nvme.c */ +int __lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + struct nvmefc_ls_req *pnvme_lsreq, + void (*gen_req_cmp)(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdwqe, + struct lpfc_iocbq *rspwqe)); +void __lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport, + struct lpfc_iocbq *cmdwqe, struct lpfc_wcqe_complete *wcqe); +int __lpfc_nvme_ls_abort(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, struct nvmefc_ls_req *pnvme_lsreq); + +/* routines found in lpfc_nvmet.c */ +int lpfc_nvme_unsol_ls_issue_abort(struct lpfc_hba *phba, + struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, + uint16_t xri); +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)); +void __lpfc_nvme_xmt_ls_rsp_cmp(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdwqe, struct lpfc_iocbq *rspwqe); diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 9dc9afe1c255..f7cfac0da9b6 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * - * Fibre Channsel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2017-2022 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. * @@ -36,10 +36,6 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> -#include <linux/nvme.h> -#include <linux/nvme-fc-driver.h> -#include <linux/nvme-fc.h> - #include "lpfc_version.h" #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -50,29 +46,25 @@ #include "lpfc.h" #include "lpfc_scsi.h" #include "lpfc_nvme.h" -#include "lpfc_nvmet.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_nvmet_rcv_ctx *, + 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_nvmet_rcv_ctx *); + struct lpfc_async_xchg_ctx *); static int lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *, - struct lpfc_nvmet_rcv_ctx *, + struct lpfc_async_xchg_ctx *, uint32_t, uint16_t); static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *, - struct lpfc_nvmet_rcv_ctx *, + struct lpfc_async_xchg_ctx *, uint32_t, uint16_t); -static int lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *, - struct lpfc_nvmet_rcv_ctx *, - uint32_t, uint16_t); static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *, struct lpfc_queue *, - struct lpfc_nvmet_rcv_ctx *); + 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); @@ -113,7 +105,7 @@ lpfc_nvmet_cmd_template(void) /* Word 9 - reqtag, rcvoxid is variable */ /* Word 10 - wqes, xc is variable */ - bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1); + bf_set(wqe_xchg, &wqe->fcp_tsend.wqe_com, LPFC_NVME_XCHG); bf_set(wqe_dbde, &wqe->fcp_tsend.wqe_com, 1); bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0); bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1); @@ -161,7 +153,7 @@ lpfc_nvmet_cmd_template(void) /* Word 10 - xc is variable */ bf_set(wqe_dbde, &wqe->fcp_treceive.wqe_com, 1); bf_set(wqe_wqes, &wqe->fcp_treceive.wqe_com, 0); - bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1); + bf_set(wqe_xchg, &wqe->fcp_treceive.wqe_com, LPFC_NVME_XCHG); bf_set(wqe_iod, &wqe->fcp_treceive.wqe_com, LPFC_WQE_IOD_READ); bf_set(wqe_lenloc, &wqe->fcp_treceive.wqe_com, LPFC_WQE_LENLOC_WORD12); bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1); @@ -203,7 +195,7 @@ lpfc_nvmet_cmd_template(void) /* Word 10 wqes, xc is variable */ bf_set(wqe_dbde, &wqe->fcp_trsp.wqe_com, 1); - bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1); + bf_set(wqe_xchg, &wqe->fcp_trsp.wqe_com, LPFC_NVME_XCHG); bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 0); bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, 0); bf_set(wqe_iod, &wqe->fcp_trsp.wqe_com, LPFC_WQE_IOD_NONE); @@ -221,10 +213,10 @@ lpfc_nvmet_cmd_template(void) } #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) -static struct lpfc_nvmet_rcv_ctx * +static struct lpfc_async_xchg_ctx * lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri) { - struct lpfc_nvmet_rcv_ctx *ctxp; + struct lpfc_async_xchg_ctx *ctxp; unsigned long iflag; bool found = false; @@ -243,10 +235,10 @@ lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri) return NULL; } -static struct lpfc_nvmet_rcv_ctx * +static struct lpfc_async_xchg_ctx * lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid) { - struct lpfc_nvmet_rcv_ctx *ctxp; + struct lpfc_async_xchg_ctx *ctxp; unsigned long iflag; bool found = false; @@ -267,7 +259,8 @@ 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_nvmet_rcv_ctx *ctxp) +lpfc_nvmet_defer_release(struct lpfc_hba *phba, + struct lpfc_async_xchg_ctx *ctxp) { lockdep_assert_held(&ctxp->ctxlock); @@ -275,10 +268,10 @@ lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp) "6313 NVMET Defer ctx release oxid x%x flg x%x\n", ctxp->oxid, ctxp->flag); - if (ctxp->flag & LPFC_NVMET_CTX_RLS) + if (ctxp->flag & LPFC_NVME_CTX_RLS) return; - ctxp->flag |= LPFC_NVMET_CTX_RLS; + ctxp->flag |= LPFC_NVME_CTX_RLS; spin_lock(&phba->sli4_hba.t_active_list_lock); list_del(&ctxp->list); spin_unlock(&phba->sli4_hba.t_active_list_lock); @@ -288,40 +281,79 @@ lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp) } /** - * lpfc_nvmet_xmt_ls_rsp_cmp - Completion handler for LS Response + * __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. - * @wcqe: Pointer to driver response CQE 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 frees memory resources used for the NVME commands. + * lock held. The function frees memory resources used for the command + * used to send the NVME LS RSP. **/ -static void -lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, - struct lpfc_wcqe_complete *wcqe) +void +__lpfc_nvme_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + struct lpfc_iocbq *rspwqe) { - struct lpfc_nvmet_tgtport *tgtp; - struct nvmefc_tgt_ls_req *rsp; - struct lpfc_nvmet_rcv_ctx *ctxp; + struct lpfc_async_xchg_ctx *axchg = cmdwqe->context_un.axchg; + struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl; + struct nvmefc_ls_rsp *ls_rsp = &axchg->ls_rsp; uint32_t status, result; - status = bf_get(lpfc_wcqe_c_status, wcqe); + status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; result = wcqe->parameter; - ctxp = cmdwqe->context2; - if (ctxp->state != LPFC_NVMET_STE_LS_RSP || ctxp->entry_cnt != 2) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6410 NVMET LS cmpl state mismatch IO x%x: " + if (axchg->state != LPFC_NVME_STE_LS_RSP || axchg->entry_cnt != 2) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6410 NVMEx LS cmpl state mismatch IO x%x: " "%d %d\n", - ctxp->oxid, ctxp->state, ctxp->entry_cnt); + axchg->oxid, axchg->state, axchg->entry_cnt); } + lpfc_nvmeio_data(phba, "NVMEx LS CMPL: xri x%x stat x%x result x%x\n", + axchg->oxid, status, result); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, + "6038 NVMEx LS rsp cmpl: %d %d oxid x%x\n", + status, result, axchg->oxid); + + lpfc_nlp_put(cmdwqe->ndlp); + cmdwqe->context_un.axchg = NULL; + cmdwqe->bpl_dmabuf = NULL; + lpfc_sli_release_iocbq(phba, cmdwqe); + ls_rsp->done(ls_rsp); + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, + "6200 NVMEx LS rsp cmpl done status %d oxid x%x\n", + status, axchg->oxid); + kfree(axchg); +} + +/** + * 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) +{ + struct lpfc_nvmet_tgtport *tgtp; + uint32_t status, result; + struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl; + if (!phba->targetport) - goto out; + goto finish; - tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; + result = wcqe->parameter; + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; if (tgtp) { if (status) { atomic_inc(&tgtp->xmt_ls_rsp_error); @@ -334,29 +366,14 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, } } -out: - rsp = &ctxp->ctx.ls_req; - - lpfc_nvmeio_data(phba, "NVMET LS CMPL: xri x%x stat x%x result x%x\n", - ctxp->oxid, status, result); - - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, - "6038 NVMET LS rsp cmpl: %d %d oxid x%x\n", - status, result, ctxp->oxid); - - lpfc_nlp_put(cmdwqe->context1); - cmdwqe->context2 = NULL; - cmdwqe->context3 = NULL; - lpfc_sli_release_iocbq(phba, cmdwqe); - rsp->done(rsp); - kfree(ctxp); +finish: + __lpfc_nvme_xmt_ls_rsp_cmp(phba, cmdwqe, rspwqe); } /** * lpfc_nvmet_ctxbuf_post - Repost a NVMET RQ DMA buffer and clean up context * @phba: HBA buffer is associated with - * @ctxp: context to clean up - * @mp: Buffer to free + * @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. @@ -369,7 +386,7 @@ void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) { #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) - struct lpfc_nvmet_rcv_ctx *ctxp = ctx_buf->context; + struct lpfc_async_xchg_ctx *ctxp = ctx_buf->context; struct lpfc_nvmet_tgtport *tgtp; struct fc_frame_header *fc_hdr; struct rqb_dmabuf *nvmebuf; @@ -378,8 +395,8 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) int cpu; unsigned long iflag; - if (ctxp->state == LPFC_NVMET_STE_FREE) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + if (ctxp->state == LPFC_NVME_STE_FREE) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6411 NVMET free, already free IO x%x: %d %d\n", ctxp->oxid, ctxp->state, ctxp->entry_cnt); } @@ -390,8 +407,8 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) /* check if freed in another path whilst acquiring lock */ if (nvmebuf) { ctxp->rqb_buffer = NULL; - if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { - ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ; + if (ctxp->flag & LPFC_NVME_CTX_REUSE_WQ) { + ctxp->flag &= ~LPFC_NVME_CTX_REUSE_WQ; spin_unlock_irqrestore(&ctxp->ctxlock, iflag); nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); @@ -404,7 +421,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) spin_unlock_irqrestore(&ctxp->ctxlock, iflag); } } - ctxp->state = LPFC_NVMET_STE_FREE; + ctxp->state = LPFC_NVME_STE_FREE; spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag); if (phba->sli4_hba.nvmet_io_wait_cnt) { @@ -421,14 +438,14 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) size = nvmebuf->bytes_recv; sid = sli4_sid_from_fc_hdr(fc_hdr); - ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context; + ctxp = (struct lpfc_async_xchg_ctx *)ctx_buf->context; ctxp->wqeq = NULL; ctxp->offset = 0; ctxp->phba = phba; ctxp->size = size; ctxp->oxid = oxid; ctxp->sid = sid; - ctxp->state = LPFC_NVMET_STE_RCV; + ctxp->state = LPFC_NVME_STE_RCV; ctxp->entry_cnt = 1; ctxp->flag = 0; ctxp->ctxbuf = ctx_buf; @@ -453,12 +470,12 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) /* Indicate that a replacement buffer has been posted */ spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->flag |= LPFC_NVMET_CTX_REUSE_WQ; + ctxp->flag |= LPFC_NVME_CTX_REUSE_WQ; spin_unlock_irqrestore(&ctxp->ctxlock, iflag); if (!queue_work(phba->wq, &ctx_buf->defer_work)) { atomic_inc(&tgtp->rcv_fcp_cmd_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6181 Unable to queue deferred work " "for oxid x%x. " "FCP Drop IO [x%x x%x x%x]\n", @@ -495,7 +512,7 @@ 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_nvmet_rcv_ctx *ctxp) + struct lpfc_async_xchg_ctx *ctxp) { uint64_t seg1, seg2, seg3, seg4, seg5; uint64_t seg6, seg7, seg8, seg9, seg10; @@ -692,7 +709,7 @@ out: * lpfc_nvmet_xmt_fcp_op_cmp - Completion handler for FCP Response * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. - * @wcqe: Pointer to driver response CQE 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 @@ -700,20 +717,21 @@ out: **/ static void lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, - struct lpfc_wcqe_complete *wcqe) + struct lpfc_iocbq *rspwqe) { struct lpfc_nvmet_tgtport *tgtp; struct nvmefc_tgt_fcp_req *rsp; - struct lpfc_nvmet_rcv_ctx *ctxp; - uint32_t status, result, op, start_clean, logerr; + struct lpfc_async_xchg_ctx *ctxp; + uint32_t status, result, op, logerr; + struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - uint32_t id; + int id; #endif - ctxp = cmdwqe->context2; - ctxp->flag &= ~LPFC_NVMET_IO_INP; + ctxp = cmdwqe->context_un.axchg; + ctxp->flag &= ~LPFC_NVME_IO_INP; - rsp = &ctxp->ctx.fcp_req; + rsp = &ctxp->hdlrctx.fcp_req; op = rsp->op; status = bf_get(lpfc_wcqe_c_status, wcqe); @@ -740,13 +758,13 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, /* pick up SLI4 exhange busy condition */ if (bf_get(lpfc_wcqe_c_xb, wcqe)) { - ctxp->flag |= LPFC_NVMET_XBUSY; + ctxp->flag |= LPFC_NVME_XBUSY; logerr |= LOG_NVME_ABTS; if (tgtp) atomic_inc(&tgtp->xmt_fcp_rsp_xb_set); } else { - ctxp->flag &= ~LPFC_NVMET_XBUSY; + ctxp->flag &= ~LPFC_NVME_XBUSY; } lpfc_printf_log(phba, KERN_INFO, logerr, @@ -768,7 +786,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, if ((op == NVMET_FCOP_READDATA_RSP) || (op == NVMET_FCOP_RSP)) { /* Sanity check */ - ctxp->state = LPFC_NVMET_STE_DONE; + ctxp->state = LPFC_NVME_STE_DONE; ctxp->entry_cnt++; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -802,9 +820,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, /* lpfc_nvmet_xmt_fcp_release() will recycle the context */ } else { ctxp->entry_cnt++; - start_clean = offsetof(struct lpfc_iocbq, iocb_flag); - memset(((char *)cmdwqe) + start_clean, 0, - (sizeof(struct lpfc_iocbq) - start_clean)); + memset_startat(cmdwqe, 0, cmd_flag); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (ctxp->ts_cmd_nvme) { ctxp->ts_isr_data = cmdwqe->isr_timestamp; @@ -814,31 +830,44 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, rsp->done(rsp); } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) { + if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) { id = raw_smp_processor_id(); - if (id < LPFC_CHECK_CPU_CNT) { - if (ctxp->cpu != id) - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, - "6704 CPU Check cmdcmpl: " - "cpu %d expect %d\n", - id, ctxp->cpu); - phba->sli4_hba.hdwq[rsp->hwqid].cpucheck_cmpl_io[id]++; - } + this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io); + if (ctxp->cpu != id) + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, + "6704 CPU Check cmdcmpl: " + "cpu %d expect %d\n", + id, ctxp->cpu); } #endif } -static int -lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, - struct nvmefc_tgt_ls_req *rsp) +/** + * __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)) { - struct lpfc_nvmet_rcv_ctx *ctxp = - container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.ls_req); - struct lpfc_hba *phba = ctxp->phba; - struct hbq_dmabuf *nvmebuf = - (struct hbq_dmabuf *)ctxp->rqb_buffer; + struct lpfc_hba *phba = axchg->phba; + struct hbq_dmabuf *nvmebuf = (struct hbq_dmabuf *)axchg->rqb_buffer; struct lpfc_iocbq *nvmewqeq; - struct lpfc_nvmet_tgtport *nvmep = tgtport->private; struct lpfc_dmabuf dmabuf; struct ulp_bde64 bpl; int rc; @@ -846,76 +875,134 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, if (phba->pport->load_flag & FC_UNLOADING) return -ENODEV; - if (phba->pport->load_flag & FC_UNLOADING) - return -ENODEV; - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, - "6023 NVMET LS rsp oxid x%x\n", ctxp->oxid); + "6023 NVMEx LS rsp oxid x%x\n", axchg->oxid); - if ((ctxp->state != LPFC_NVMET_STE_LS_RCV) || - (ctxp->entry_cnt != 1)) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6412 NVMET LS rsp state mismatch " + if (axchg->state != LPFC_NVME_STE_LS_RCV || axchg->entry_cnt != 1) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6412 NVMEx LS rsp state mismatch " "oxid x%x: %d %d\n", - ctxp->oxid, ctxp->state, ctxp->entry_cnt); + axchg->oxid, axchg->state, axchg->entry_cnt); + return -EALREADY; } - ctxp->state = LPFC_NVMET_STE_LS_RSP; - ctxp->entry_cnt++; + axchg->state = LPFC_NVME_STE_LS_RSP; + axchg->entry_cnt++; - nvmewqeq = lpfc_nvmet_prep_ls_wqe(phba, ctxp, rsp->rspdma, - rsp->rsplen); + nvmewqeq = lpfc_nvmet_prep_ls_wqe(phba, axchg, ls_rsp->rspdma, + ls_rsp->rsplen); if (nvmewqeq == NULL) { - atomic_inc(&nvmep->xmt_ls_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6150 LS Drop IO x%x: Prep\n", - ctxp->oxid); - lpfc_in_buf_free(phba, &nvmebuf->dbuf); - atomic_inc(&nvmep->xmt_ls_abort); - lpfc_nvmet_unsol_ls_issue_abort(phba, ctxp, - ctxp->sid, ctxp->oxid); - return -ENOMEM; + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6150 NVMEx LS Drop Rsp x%x: Prep\n", + axchg->oxid); + rc = -ENOMEM; + goto out_free_buf; } /* Save numBdes for bpl2sgl */ - nvmewqeq->rsvd2 = 1; + nvmewqeq->num_bdes = 1; nvmewqeq->hba_wqidx = 0; - nvmewqeq->context3 = &dmabuf; + nvmewqeq->bpl_dmabuf = &dmabuf; dmabuf.virt = &bpl; bpl.addrLow = nvmewqeq->wqe.xmit_sequence.bde.addrLow; bpl.addrHigh = nvmewqeq->wqe.xmit_sequence.bde.addrHigh; - bpl.tus.f.bdeSize = rsp->rsplen; + bpl.tus.f.bdeSize = ls_rsp->rsplen; bpl.tus.f.bdeFlags = 0; bpl.tus.w = le32_to_cpu(bpl.tus.w); + /* + * Note: although we're using stack space for the dmabuf, the + * call to lpfc_sli4_issue_wqe is synchronous, so it will not + * be referenced after it returns back to this routine. + */ - nvmewqeq->wqe_cmpl = lpfc_nvmet_xmt_ls_rsp_cmp; - nvmewqeq->iocb_cmpl = NULL; - nvmewqeq->context2 = ctxp; + nvmewqeq->cmd_cmpl = xmt_ls_rsp_cmp; + nvmewqeq->context_un.axchg = axchg; - lpfc_nvmeio_data(phba, "NVMET LS RESP: xri x%x wqidx x%x len x%x\n", - ctxp->oxid, nvmewqeq->hba_wqidx, rsp->rsplen); + lpfc_nvmeio_data(phba, "NVMEx LS RSP: xri x%x wqidx x%x len x%x\n", + axchg->oxid, nvmewqeq->hba_wqidx, ls_rsp->rsplen); + + rc = lpfc_sli4_issue_wqe(phba, axchg->hdwq, nvmewqeq); + + /* clear to be sure there's no reference */ + nvmewqeq->bpl_dmabuf = NULL; - rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, nvmewqeq); if (rc == WQE_SUCCESS) { /* * Okay to repost buffer here, but wait till cmpl * before freeing ctxp and iocbq. */ lpfc_in_buf_free(phba, &nvmebuf->dbuf); - atomic_inc(&nvmep->xmt_ls_rsp); return 0; } - /* Give back resources */ - atomic_inc(&nvmep->xmt_ls_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6151 LS Drop IO x%x: Issue %d\n", - ctxp->oxid, rc); - lpfc_nlp_put(nvmewqeq->context1); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6151 NVMEx LS RSP x%x: failed to transmit %d\n", + axchg->oxid, rc); + + rc = -ENXIO; + + lpfc_nlp_put(nvmewqeq->ndlp); +out_free_buf: + /* Give back resources */ lpfc_in_buf_free(phba, &nvmebuf->dbuf); - atomic_inc(&nvmep->xmt_ls_abort); - lpfc_nvmet_unsol_ls_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); - return -ENXIO; + + /* + * As transport doesn't track completions of responses, if the rsp + * fails to send, the transport will effectively ignore the rsp + * and consider the LS done. However, the driver has an active + * exchange open for the LS - so be sure to abort the exchange + * if the response isn't sent. + */ + lpfc_nvme_unsol_ls_issue_abort(phba, axchg, axchg->sid, axchg->oxid); + return rc; +} + +/** + * 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) +{ + struct lpfc_async_xchg_ctx *axchg = + container_of(ls_rsp, struct lpfc_async_xchg_ctx, ls_rsp); + struct lpfc_nvmet_tgtport *nvmep = tgtport->private; + int rc; + + if (axchg->phba->pport->load_flag & FC_UNLOADING) + return -ENODEV; + + rc = __lpfc_nvme_xmt_ls_rsp(axchg, ls_rsp, lpfc_nvmet_xmt_ls_rsp_cmp); + + if (rc) { + atomic_inc(&nvmep->xmt_ls_drop); + /* + * unless the failure is due to having already sent + * the response, an abort will be generated for the + * exchange if the rsp can't be sent. + */ + if (rc != -EALREADY) + atomic_inc(&nvmep->xmt_ls_abort); + return rc; + } + + atomic_inc(&nvmep->xmt_ls_rsp); + return 0; } static int @@ -923,19 +1010,17 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, struct nvmefc_tgt_fcp_req *rsp) { struct lpfc_nvmet_tgtport *lpfc_nvmep = tgtport->private; - struct lpfc_nvmet_rcv_ctx *ctxp = - container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); + struct lpfc_async_xchg_ctx *ctxp = + container_of(rsp, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); struct lpfc_hba *phba = ctxp->phba; struct lpfc_queue *wq; struct lpfc_iocbq *nvmewqeq; struct lpfc_sli_ring *pring; unsigned long iflags; int rc; - - if (phba->pport->load_flag & FC_UNLOADING) { - rc = -ENODEV; - goto aerr; - } +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + int id; +#endif if (phba->pport->load_flag & FC_UNLOADING) { rc = -ENODEV; @@ -954,25 +1039,23 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, if (!ctxp->hdwq) ctxp->hdwq = &phba->sli4_hba.hdwq[rsp->hwqid]; - if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) { - int id = raw_smp_processor_id(); - if (id < LPFC_CHECK_CPU_CNT) { - if (rsp->hwqid != id) - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, - "6705 CPU Check OP: " - "cpu %d expect %d\n", - id, rsp->hwqid); - phba->sli4_hba.hdwq[rsp->hwqid].cpucheck_xmt_io[id]++; - } + if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) { + id = raw_smp_processor_id(); + this_cpu_inc(phba->sli4_hba.c_stat->xmt_io); + if (rsp->hwqid != id) + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, + "6705 CPU Check OP: " + "cpu %d expect %d\n", + id, rsp->hwqid); ctxp->cpu = id; /* Setup cpu for cmpl check */ } #endif /* Sanity check */ - if ((ctxp->flag & LPFC_NVMET_ABTS_RCV) || - (ctxp->state == LPFC_NVMET_STE_ABORT)) { + if ((ctxp->flag & LPFC_NVME_ABTS_RCV) || + (ctxp->state == LPFC_NVME_STE_ABORT)) { atomic_inc(&lpfc_nvmep->xmt_fcp_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6102 IO oxid x%x aborted\n", ctxp->oxid); rc = -ENXIO; @@ -982,23 +1065,22 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, nvmewqeq = lpfc_nvmet_prep_fcp_wqe(phba, ctxp); if (nvmewqeq == NULL) { atomic_inc(&lpfc_nvmep->xmt_fcp_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6152 FCP Drop IO x%x: Prep\n", ctxp->oxid); rc = -ENXIO; goto aerr; } - nvmewqeq->wqe_cmpl = lpfc_nvmet_xmt_fcp_op_cmp; - nvmewqeq->iocb_cmpl = NULL; - nvmewqeq->context2 = ctxp; - nvmewqeq->iocb_flag |= LPFC_IO_NVMET; + nvmewqeq->cmd_cmpl = lpfc_nvmet_xmt_fcp_op_cmp; + nvmewqeq->context_un.axchg = ctxp; + nvmewqeq->cmd_flag |= LPFC_IO_NVMET; ctxp->wqeq->hba_wqidx = rsp->hwqid; lpfc_nvmeio_data(phba, "NVMET FCP CMND: xri x%x op x%x len x%x\n", ctxp->oxid, rsp->op, rsp->rsplen); - ctxp->flag |= LPFC_NVMET_IO_INP; + ctxp->flag |= LPFC_NVME_IO_INP; rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, nvmewqeq); if (rc == WQE_SUCCESS) { #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -1017,7 +1099,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, * WQ was full, so queue nvmewqeq to be sent after * WQE release CQE */ - ctxp->flag |= LPFC_NVMET_DEFER_WQFULL; + ctxp->flag |= LPFC_NVME_DEFER_WQFULL; wq = ctxp->hdwq->io_wq; pring = wq->pring; spin_lock_irqsave(&pring->ring_lock, iflags); @@ -1030,13 +1112,13 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, /* Give back resources */ atomic_inc(&lpfc_nvmep->xmt_fcp_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6153 FCP Drop IO x%x: Issue: %d\n", ctxp->oxid, rc); ctxp->wqeq->hba_wqidx = 0; - nvmewqeq->context2 = NULL; - nvmewqeq->context3 = NULL; + nvmewqeq->context_un.axchg = NULL; + nvmewqeq->bpl_dmabuf = NULL; rc = -EBUSY; aerr: return rc; @@ -1057,8 +1139,8 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, struct nvmefc_tgt_fcp_req *req) { struct lpfc_nvmet_tgtport *lpfc_nvmep = tgtport->private; - struct lpfc_nvmet_rcv_ctx *ctxp = - container_of(req, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); + struct lpfc_async_xchg_ctx *ctxp = + container_of(req, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); struct lpfc_hba *phba = ctxp->phba; struct lpfc_queue *wq; unsigned long flags; @@ -1066,9 +1148,6 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, if (phba->pport->load_flag & FC_UNLOADING) return; - if (phba->pport->load_flag & FC_UNLOADING) - return; - if (!ctxp->hdwq) ctxp->hdwq = &phba->sli4_hba.hdwq[0]; @@ -1086,13 +1165,13 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, /* Since iaab/iaar are NOT set, we need to check * if the firmware is in process of aborting IO */ - if (ctxp->flag & (LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP)) { + if (ctxp->flag & (LPFC_NVME_XBUSY | LPFC_NVME_ABORT_OP)) { spin_unlock_irqrestore(&ctxp->ctxlock, flags); return; } - ctxp->flag |= LPFC_NVMET_ABORT_OP; + ctxp->flag |= LPFC_NVME_ABORT_OP; - if (ctxp->flag & LPFC_NVMET_DEFER_WQFULL) { + if (ctxp->flag & LPFC_NVME_DEFER_WQFULL) { spin_unlock_irqrestore(&ctxp->ctxlock, flags); lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); @@ -1102,11 +1181,11 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, } spin_unlock_irqrestore(&ctxp->ctxlock, flags); - /* An state of LPFC_NVMET_STE_RCV means we have just received + /* A state of LPFC_NVME_STE_RCV means we have just received * the NVME command and have not started processing it. * (by issuing any IO WQEs on this exchange yet) */ - if (ctxp->state == LPFC_NVMET_STE_RCV) + if (ctxp->state == LPFC_NVME_STE_RCV) lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); else @@ -1119,26 +1198,26 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport, struct nvmefc_tgt_fcp_req *rsp) { struct lpfc_nvmet_tgtport *lpfc_nvmep = tgtport->private; - struct lpfc_nvmet_rcv_ctx *ctxp = - container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); + struct lpfc_async_xchg_ctx *ctxp = + container_of(rsp, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); struct lpfc_hba *phba = ctxp->phba; unsigned long flags; bool aborting = false; spin_lock_irqsave(&ctxp->ctxlock, flags); - if (ctxp->flag & LPFC_NVMET_XBUSY) + if (ctxp->flag & LPFC_NVME_XBUSY) lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, "6027 NVMET release with XBUSY flag x%x" " oxid x%x\n", ctxp->flag, ctxp->oxid); - else if (ctxp->state != LPFC_NVMET_STE_DONE && - ctxp->state != LPFC_NVMET_STE_ABORT) - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + else if (ctxp->state != LPFC_NVME_STE_DONE && + ctxp->state != LPFC_NVME_STE_ABORT) + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6413 NVMET release bad state %d %d oxid x%x\n", ctxp->state, ctxp->entry_cnt, ctxp->oxid); - if ((ctxp->flag & LPFC_NVMET_ABORT_OP) || - (ctxp->flag & LPFC_NVMET_XBUSY)) { + if ((ctxp->flag & LPFC_NVME_ABORT_OP) || + (ctxp->flag & LPFC_NVME_XBUSY)) { aborting = true; /* let the abort path do the real release */ lpfc_nvmet_defer_release(phba, ctxp); @@ -1149,7 +1228,7 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport, ctxp->state, aborting); atomic_inc(&lpfc_nvmep->xmt_fcp_release); - ctxp->flag &= ~LPFC_NVMET_TNOTIFY; + ctxp->flag &= ~LPFC_NVME_TNOTIFY; if (aborting) return; @@ -1162,8 +1241,8 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, struct nvmefc_tgt_fcp_req *rsp) { struct lpfc_nvmet_tgtport *tgtp; - struct lpfc_nvmet_rcv_ctx *ctxp = - container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); + struct lpfc_async_xchg_ctx *ctxp = + container_of(rsp, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer; struct lpfc_hba *phba = ctxp->phba; unsigned long iflag; @@ -1191,6 +1270,122 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, spin_unlock_irqrestore(&ctxp->ctxlock, iflag); } +/** + * 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) +{ + struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl; + __lpfc_nvme_ls_req_cmp(phba, cmdwqe->vport, cmdwqe, wcqe); +} + +/** + * 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) +{ + struct lpfc_nvmet_tgtport *lpfc_nvmet = targetport->private; + struct lpfc_hba *phba; + struct lpfc_nodelist *ndlp; + int ret; + u32 hstate; + + if (!lpfc_nvmet) + return -EINVAL; + + phba = lpfc_nvmet->phba; + if (phba->pport->load_flag & FC_UNLOADING) + return -EINVAL; + + hstate = atomic_read(&lpfc_nvmet->state); + if (hstate == LPFC_NVMET_INV_HOST_ACTIVE) + return -EACCES; + + ndlp = (struct lpfc_nodelist *)hosthandle; + + ret = __lpfc_nvme_ls_req(phba->pport, ndlp, pnvme_lsreq, + lpfc_nvmet_ls_req_cmp); + + return ret; +} + +/** + * 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) +{ + struct lpfc_nvmet_tgtport *lpfc_nvmet = targetport->private; + struct lpfc_hba *phba; + struct lpfc_nodelist *ndlp; + int ret; + + phba = lpfc_nvmet->phba; + if (phba->pport->load_flag & FC_UNLOADING) + return; + + ndlp = (struct lpfc_nodelist *)hosthandle; + + ret = __lpfc_nvme_ls_abort(phba->pport, ndlp, pnvme_lsreq); + if (!ret) + atomic_inc(&lpfc_nvmet->xmt_ls_abort); +} + +static void +lpfc_nvmet_host_release(void *hosthandle) +{ + struct lpfc_nodelist *ndlp = hosthandle; + struct lpfc_hba *phba = ndlp->phba; + struct lpfc_nvmet_tgtport *tgtp; + + if (!phba->targetport || !phba->targetport->private) + return; + + lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + "6202 NVMET XPT releasing hosthandle x%px " + "DID x%x xflags x%x refcnt %d\n", + hosthandle, ndlp->nlp_DID, ndlp->fc4_xpt_flags, + kref_read(&ndlp->kref)); + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + spin_lock_irq(&ndlp->lock); + ndlp->fc4_xpt_flags &= ~NLP_XPT_HAS_HH; + spin_unlock_irq(&ndlp->lock); + lpfc_nlp_put(ndlp); + atomic_set(&tgtp->state, 0); +} + static void lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport) { @@ -1202,7 +1397,7 @@ lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport) phba = tgtp->phba; rc = lpfc_issue_els_rscn(phba->pport, 0); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6420 NVMET subsystem change: Notification %s\n", (rc) ? "Failed" : "Sent"); } @@ -1215,6 +1410,9 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = { .fcp_req_release = lpfc_nvmet_xmt_fcp_release, .defer_rcv = lpfc_nvmet_defer_rcv, .discovery_event = lpfc_nvmet_discovery_event, + .ls_req = lpfc_nvmet_ls_req, + .ls_abort = lpfc_nvmet_ls_abort, + .host_release = lpfc_nvmet_host_release, .max_hw_queues = 1, .max_sgl_segments = LPFC_NVMET_DEFAULT_SEGS, @@ -1225,6 +1423,7 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = { .target_features = 0, /* sizes of additional private data for data structures */ .target_priv_sz = sizeof(struct lpfc_nvmet_tgtport), + .lsrqst_priv_sz = 0, }; static void @@ -1241,7 +1440,10 @@ __lpfc_nvmet_clean_io_for_cpu(struct lpfc_hba *phba, list_del_init(&ctx_buf->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + spin_lock(&phba->hbalock); __lpfc_clear_active_sglq(phba, ctx_buf->sglq->sli4_lxritag); + spin_unlock(&phba->hbalock); + ctx_buf->sglq->state = SGL_FREED; ctx_buf->sglq->ndlp = NULL; @@ -1296,7 +1498,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) phba->sli4_hba.num_possible_cpu * phba->cfg_nvmet_mrq, sizeof(struct lpfc_nvmet_ctx_info), GFP_KERNEL); if (!phba->sli4_hba.nvmet_ctx_info) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6419 Failed allocate memory for " "nvmet context lists\n"); return -ENOMEM; @@ -1354,7 +1556,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) for (i = 0; i < phba->sli4_hba.nvmet_xri_cnt; i++) { ctx_buf = kzalloc(sizeof(*ctx_buf), GFP_KERNEL); if (!ctx_buf) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6404 Ran out of memory for NVMET\n"); return -ENOMEM; } @@ -1363,30 +1565,30 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) GFP_KERNEL); if (!ctx_buf->context) { kfree(ctx_buf); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6405 Ran out of NVMET " "context memory\n"); return -ENOMEM; } ctx_buf->context->ctxbuf = ctx_buf; - ctx_buf->context->state = LPFC_NVMET_STE_FREE; + ctx_buf->context->state = LPFC_NVME_STE_FREE; ctx_buf->iocbq = lpfc_sli_get_iocbq(phba); if (!ctx_buf->iocbq) { kfree(ctx_buf->context); kfree(ctx_buf); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6406 Ran out of NVMET iocb/WQEs\n"); return -ENOMEM; } - ctx_buf->iocbq->iocb_flag = LPFC_IO_NVMET; + ctx_buf->iocbq->cmd_flag = LPFC_IO_NVMET; nvmewqe = ctx_buf->iocbq; wqe = &nvmewqe->wqe; /* Initialize WQE */ memset(wqe, 0, sizeof(union lpfc_wqe)); - ctx_buf->iocbq->context1 = NULL; + ctx_buf->iocbq->cmd_dmabuf = NULL; spin_lock(&phba->sli4_hba.sgl_list_lock); ctx_buf->sglq = __lpfc_sli_get_nvmet_sglq(phba, ctx_buf->iocbq); spin_unlock(&phba->sli4_hba.sgl_list_lock); @@ -1394,7 +1596,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) lpfc_sli_release_iocbq(phba, ctx_buf->iocbq); kfree(ctx_buf->context); kfree(ctx_buf); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6407 Ran out of NVMET XRIs\n"); return -ENOMEM; } @@ -1473,7 +1675,7 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) error = -ENOENT; #endif if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6025 Cannot register NVME targetport x%x: " "portnm %llx nodenm %llx segs %d qs %d\n", error, @@ -1569,7 +1771,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); - struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; + struct lpfc_async_xchg_ctx *ctxp, *next_ctxp; struct lpfc_nvmet_tgtport *tgtp; struct nvmefc_tgt_fcp_req *req = NULL; struct lpfc_nodelist *ndlp; @@ -1588,31 +1790,33 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, atomic_inc(&tgtp->xmt_fcp_xri_abort_cqe); } - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + spin_lock_irqsave(&phba->sli4_hba.abts_nvmet_buf_list_lock, iflag); list_for_each_entry_safe(ctxp, next_ctxp, &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, list) { if (ctxp->ctxbuf->sglq->sli4_xritag != xri) continue; - spin_lock(&ctxp->ctxlock); + spin_unlock_irqrestore(&phba->sli4_hba.abts_nvmet_buf_list_lock, + iflag); + + spin_lock_irqsave(&ctxp->ctxlock, iflag); /* Check if we already received a free context call * and we have completed processing an abort situation. */ - if (ctxp->flag & LPFC_NVMET_CTX_RLS && - !(ctxp->flag & LPFC_NVMET_ABORT_OP)) { + if (ctxp->flag & LPFC_NVME_CTX_RLS && + !(ctxp->flag & LPFC_NVME_ABORT_OP)) { + spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_del_init(&ctxp->list); + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } - ctxp->flag &= ~LPFC_NVMET_XBUSY; - spin_unlock(&ctxp->ctxlock); - spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + ctxp->flag &= ~LPFC_NVME_XBUSY; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); rrq_empty = list_empty(&phba->active_rrq_list); - spin_unlock_irqrestore(&phba->hbalock, iflag); ndlp = lpfc_findnode_did(phba->pport, ctxp->sid); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + if (ndlp && (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE || ndlp->nlp_state == NLP_STE_MAPPED_NODE)) { lpfc_set_rrq_active(phba, ndlp, @@ -1631,9 +1835,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, lpfc_worker_wake_up(phba); return; } - spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - + spin_unlock_irqrestore(&phba->sli4_hba.abts_nvmet_buf_list_lock, iflag); ctxp = lpfc_nvmet_get_ctx_for_xri(phba, xri); if (ctxp) { /* @@ -1647,15 +1849,15 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, rxid); spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->flag |= LPFC_NVMET_ABTS_RCV; - ctxp->state = LPFC_NVMET_STE_ABORT; + ctxp->flag |= LPFC_NVME_ABTS_RCV; + ctxp->state = LPFC_NVME_STE_ABORT; spin_unlock_irqrestore(&ctxp->ctxlock, iflag); lpfc_nvmeio_data(phba, "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", xri, raw_smp_processor_id(), 0); - req = &ctxp->ctx.fcp_req; + req = &ctxp->hdlrctx.fcp_req; if (req) nvmet_fc_rcv_fcp_abort(phba->targetport, req); } @@ -1668,7 +1870,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, { #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) struct lpfc_hba *phba = vport->phba; - struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; + struct lpfc_async_xchg_ctx *ctxp, *next_ctxp; struct nvmefc_tgt_fcp_req *rsp; uint32_t sid; uint16_t oxid, xri; @@ -1677,8 +1879,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, sid = sli4_sid_from_fc_hdr(fc_hdr); oxid = be16_to_cpu(fc_hdr->fh_ox_id); - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + spin_lock_irqsave(&phba->sli4_hba.abts_nvmet_buf_list_lock, iflag); list_for_each_entry_safe(ctxp, next_ctxp, &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, list) { @@ -1687,11 +1888,10 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, xri = ctxp->ctxbuf->sglq->sli4_xritag; - spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - + spin_unlock_irqrestore(&phba->sli4_hba.abts_nvmet_buf_list_lock, + iflag); spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->flag |= LPFC_NVMET_ABTS_RCV; + ctxp->flag |= LPFC_NVME_ABTS_RCV; spin_unlock_irqrestore(&ctxp->ctxlock, iflag); lpfc_nvmeio_data(phba, @@ -1701,16 +1901,14 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, "6319 NVMET Rcv ABTS:acc xri x%x\n", xri); - rsp = &ctxp->ctx.fcp_req; + rsp = &ctxp->hdlrctx.fcp_req; nvmet_fc_rcv_fcp_abort(phba->targetport, rsp); /* Respond with BA_ACC accordingly */ lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); return 0; } - spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - + spin_unlock_irqrestore(&phba->sli4_hba.abts_nvmet_buf_list_lock, iflag); /* check the wait list */ if (phba->sli4_hba.nvmet_io_wait_cnt) { struct rqb_dmabuf *nvmebuf; @@ -1760,7 +1958,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, xri = ctxp->ctxbuf->sglq->sli4_xritag; spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->flag |= (LPFC_NVMET_ABTS_RCV | LPFC_NVMET_ABORT_OP); + ctxp->flag |= (LPFC_NVME_ABTS_RCV | LPFC_NVME_ABORT_OP); spin_unlock_irqrestore(&ctxp->ctxlock, iflag); lpfc_nvmeio_data(phba, @@ -1772,10 +1970,10 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, "flag x%x state x%x\n", ctxp->oxid, xri, ctxp->flag, ctxp->state); - if (ctxp->flag & LPFC_NVMET_TNOTIFY) { + if (ctxp->flag & LPFC_NVME_TNOTIFY) { /* Notify the transport */ nvmet_fc_rcv_fcp_abort(phba->targetport, - &ctxp->ctx.fcp_req); + &ctxp->hdlrctx.fcp_req); } else { cancel_work_sync(&ctxp->ctxbuf->defer_work); spin_lock_irqsave(&ctxp->ctxlock, iflag); @@ -1803,7 +2001,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq, - struct lpfc_nvmet_rcv_ctx *ctxp) + struct lpfc_async_xchg_ctx *ctxp) { struct lpfc_sli_ring *pring; struct lpfc_iocbq *nvmewqeq; @@ -1825,12 +2023,14 @@ lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq, &wq->wqfull_list, list) { if (ctxp) { /* Checking for a specific IO to flush */ - if (nvmewqeq->context2 == ctxp) { + if (nvmewqeq->context_un.axchg == ctxp) { list_del(&nvmewqeq->list); spin_unlock_irqrestore(&pring->ring_lock, iflags); + memcpy(&nvmewqeq->wcqe_cmpl, wcqep, + sizeof(*wcqep)); lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, - wcqep); + nvmewqeq); return; } continue; @@ -1838,7 +2038,8 @@ lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq, /* Flush all IOs */ list_del(&nvmewqeq->list); spin_unlock_irqrestore(&pring->ring_lock, iflags); - lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, wcqep); + memcpy(&nvmewqeq->wcqe_cmpl, wcqep, sizeof(*wcqep)); + lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, nvmewqeq); spin_lock_irqsave(&pring->ring_lock, iflags); } } @@ -1854,7 +2055,7 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) struct lpfc_sli_ring *pring; struct lpfc_iocbq *nvmewqeq; - struct lpfc_nvmet_rcv_ctx *ctxp; + struct lpfc_async_xchg_ctx *ctxp; unsigned long iflags; int rc; @@ -1868,7 +2069,7 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, list_remove_head(&wq->wqfull_list, nvmewqeq, struct lpfc_iocbq, list); spin_unlock_irqrestore(&pring->ring_lock, iflags); - ctxp = (struct lpfc_nvmet_rcv_ctx *)nvmewqeq->context2; + ctxp = nvmewqeq->context_un.axchg; rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, nvmewqeq); spin_lock_irqsave(&pring->ring_lock, iflags); if (rc == -EBUSY) { @@ -1880,7 +2081,7 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, if (rc == WQE_SUCCESS) { #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (ctxp->ts_cmd_nvme) { - if (ctxp->ctx.fcp_req.op == NVMET_FCOP_RSP) + if (ctxp->hdlrctx.fcp_req.op == NVMET_FCOP_RSP) ctxp->ts_status_wqput = ktime_get_ns(); else ctxp->ts_data_wqput = ktime_get_ns(); @@ -1915,9 +2116,9 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) } tgtp->tport_unreg_cmp = &tport_unreg_cmp; nvmet_fc_unregister_targetport(phba->targetport); - if (!wait_for_completion_timeout(tgtp->tport_unreg_cmp, + if (!wait_for_completion_timeout(&tport_unreg_cmp, msecs_to_jiffies(LPFC_NVMET_WAIT_TMO))) - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6179 Unreg targetport x%px timeout " "reached.\n", phba->targetport); lpfc_nvmet_cleanup_io_context(phba); @@ -1927,114 +2128,61 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) } /** - * lpfc_nvmet_unsol_ls_buffer - Process an unsolicited event data buffer + * lpfc_nvmet_handle_lsreq - Process an NVME LS request * @phba: pointer to lpfc hba data structure. - * @pring: pointer to a SLI ring. - * @nvmebuf: pointer to lpfc nvme command HBQ data structure. + * @axchg: pointer to exchange context for the NVME LS request * - * 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_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct hbq_dmabuf *nvmebuf) + * 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) { #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) - struct lpfc_nvmet_tgtport *tgtp; - struct fc_frame_header *fc_hdr; - struct lpfc_nvmet_rcv_ctx *ctxp; - uint32_t *payload; - uint32_t size, oxid, sid, rc; - - - if (!nvmebuf || !phba->targetport) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6154 LS Drop IO\n"); - oxid = 0; - size = 0; - sid = 0; - ctxp = NULL; - goto dropit; - } - - fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt); - oxid = be16_to_cpu(fc_hdr->fh_ox_id); - - tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; - payload = (uint32_t *)(nvmebuf->dbuf.virt); - size = bf_get(lpfc_rcqe_length, &nvmebuf->cq_event.cqe.rcqe_cmpl); - sid = sli4_sid_from_fc_hdr(fc_hdr); + struct lpfc_nvmet_tgtport *tgtp = phba->targetport->private; + uint32_t *payload = axchg->payload; + int rc; - ctxp = kzalloc(sizeof(struct lpfc_nvmet_rcv_ctx), GFP_ATOMIC); - if (ctxp == NULL) { - atomic_inc(&tgtp->rcv_ls_req_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6155 LS Drop IO x%x: Alloc\n", - oxid); -dropit: - lpfc_nvmeio_data(phba, "NVMET LS DROP: " - "xri x%x sz %d from %06x\n", - oxid, size, sid); - lpfc_in_buf_free(phba, &nvmebuf->dbuf); - return; - } - ctxp->phba = phba; - ctxp->size = size; - ctxp->oxid = oxid; - ctxp->sid = sid; - ctxp->wqeq = NULL; - ctxp->state = LPFC_NVMET_STE_LS_RCV; - ctxp->entry_cnt = 1; - ctxp->rqb_buffer = (void *)nvmebuf; - ctxp->hdwq = &phba->sli4_hba.hdwq[0]; + atomic_inc(&tgtp->rcv_ls_req_in); - lpfc_nvmeio_data(phba, "NVMET LS RCV: xri x%x sz %d from %06x\n", - oxid, size, sid); /* - * The calling sequence should be: - * nvmet_fc_rcv_ls_req -> lpfc_nvmet_xmt_ls_rsp/cmp ->_req->done - * lpfc_nvmet_xmt_ls_rsp_cmp should free the allocated ctxp. + * Driver passes the ndlp as the hosthandle argument allowing + * the transport to generate LS requests for any associateions + * that are created. */ - atomic_inc(&tgtp->rcv_ls_req_in); - rc = nvmet_fc_rcv_ls_req(phba->targetport, &ctxp->ctx.ls_req, - payload, size); + rc = nvmet_fc_rcv_ls_req(phba->targetport, axchg->ndlp, &axchg->ls_rsp, + axchg->payload, axchg->size); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, "6037 NVMET Unsol rcv: sz %d rc %d: %08x %08x %08x " - "%08x %08x %08x\n", size, rc, + "%08x %08x %08x\n", axchg->size, rc, *payload, *(payload+1), *(payload+2), *(payload+3), *(payload+4), *(payload+5)); - if (rc == 0) { + if (!rc) { atomic_inc(&tgtp->rcv_ls_req_out); - return; + return 0; } - lpfc_nvmeio_data(phba, "NVMET LS DROP: xri x%x sz %d from %06x\n", - oxid, size, sid); - atomic_inc(&tgtp->rcv_ls_req_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6156 LS Drop IO x%x: nvmet_fc_rcv_ls_req %d\n", - ctxp->oxid, rc); - - /* We assume a rcv'ed cmd ALWAYs fits into 1 buffer */ - lpfc_in_buf_free(phba, &nvmebuf->dbuf); - - atomic_inc(&tgtp->xmt_ls_abort); - lpfc_nvmet_unsol_ls_issue_abort(phba, ctxp, sid, oxid); #endif + return 1; } static void lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) { #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) - struct lpfc_nvmet_rcv_ctx *ctxp = ctx_buf->context; + struct lpfc_async_xchg_ctx *ctxp = ctx_buf->context; struct lpfc_hba *phba = ctxp->phba; struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer; struct lpfc_nvmet_tgtport *tgtp; @@ -2043,7 +2191,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) unsigned long iflags; if (!nvmebuf) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6159 process_rcv_fcp_req, nvmebuf is NULL, " "oxid: x%x flg: x%x state: x%x\n", ctxp->oxid, ctxp->flag, ctxp->state); @@ -2055,8 +2203,8 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) return; } - if (ctxp->flag & LPFC_NVMET_ABTS_RCV) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + if (ctxp->flag & LPFC_NVME_ABTS_RCV) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6324 IO oxid x%x aborted\n", ctxp->oxid); return; @@ -2064,7 +2212,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) payload = (uint32_t *)(nvmebuf->dbuf.virt); tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; - ctxp->flag |= LPFC_NVMET_TNOTIFY; + ctxp->flag |= LPFC_NVME_TNOTIFY; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (ctxp->ts_isr_cmd) ctxp->ts_cmd_nvme = ktime_get_ns(); @@ -2078,13 +2226,13 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) * A buffer has already been reposted for this IO, so just free * the nvmebuf. */ - rc = nvmet_fc_rcv_fcp_req(phba->targetport, &ctxp->ctx.fcp_req, + rc = nvmet_fc_rcv_fcp_req(phba->targetport, &ctxp->hdlrctx.fcp_req, payload, ctxp->size); /* Process FCP command */ if (rc == 0) { atomic_inc(&tgtp->rcv_fcp_cmd_out); spin_lock_irqsave(&ctxp->ctxlock, iflags); - if ((ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) || + if ((ctxp->flag & LPFC_NVME_CTX_REUSE_WQ) || (nvmebuf != ctxp->rqb_buffer)) { spin_unlock_irqrestore(&ctxp->ctxlock, iflags); return; @@ -2103,7 +2251,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) atomic_inc(&tgtp->rcv_fcp_cmd_out); atomic_inc(&tgtp->defer_fod); spin_lock_irqsave(&ctxp->ctxlock, iflags); - if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { + if (ctxp->flag & LPFC_NVME_CTX_REUSE_WQ) { spin_unlock_irqrestore(&ctxp->ctxlock, iflags); return; } @@ -2118,9 +2266,9 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) phba->sli4_hba.nvmet_mrq_data[qno], 1, qno); return; } - ctxp->flag &= ~LPFC_NVMET_TNOTIFY; + ctxp->flag &= ~LPFC_NVME_TNOTIFY; atomic_inc(&tgtp->rcv_fcp_cmd_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n", ctxp->oxid, rc, atomic_read(&tgtp->rcv_fcp_cmd_in), @@ -2225,7 +2373,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, uint64_t isr_timestamp, uint8_t cqflag) { - struct lpfc_nvmet_rcv_ctx *ctxp; + struct lpfc_async_xchg_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; struct fc_frame_header *fc_hdr; struct lpfc_nvmet_ctxbuf *ctx_buf; @@ -2239,7 +2387,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, ctx_buf = NULL; if (!nvmebuf || !phba->targetport) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6157 NVMET FCP Drop IO\n"); if (nvmebuf) lpfc_rq_buf_free(phba, &nvmebuf->hbuf); @@ -2270,15 +2418,13 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, size = nvmebuf->bytes_recv; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (phba->cpucheck_on & LPFC_CHECK_NVMET_RCV) { - if (current_cpu < LPFC_CHECK_CPU_CNT) { - if (idx != current_cpu) - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, - "6703 CPU Check rcv: " - "cpu %d expect %d\n", - current_cpu, idx); - phba->sli4_hba.hdwq[idx].cpucheck_rcv_io[current_cpu]++; - } + if (phba->hdwqstat_on & LPFC_CHECK_NVMET_IO) { + this_cpu_inc(phba->sli4_hba.c_stat->rcv_io); + if (idx != current_cpu) + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, + "6703 CPU Check rcv: " + "cpu %d expect %d\n", + current_cpu, idx); } #endif @@ -2309,12 +2455,12 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, sid = sli4_sid_from_fc_hdr(fc_hdr); - ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context; + ctxp = (struct lpfc_async_xchg_ctx *)ctx_buf->context; spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); list_add_tail(&ctxp->list, &phba->sli4_hba.t_active_ctx_list); spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); - if (ctxp->state != LPFC_NVMET_STE_FREE) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + if (ctxp->state != LPFC_NVME_STE_FREE) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6414 NVMET Context corrupt %d %d oxid x%x\n", ctxp->state, ctxp->entry_cnt, ctxp->oxid); } @@ -2325,7 +2471,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, ctxp->oxid = oxid; ctxp->sid = sid; ctxp->idx = idx; - ctxp->state = LPFC_NVMET_STE_RCV; + ctxp->state = LPFC_NVME_STE_RCV; ctxp->entry_cnt = 1; ctxp->flag = 0; ctxp->ctxbuf = ctx_buf; @@ -2356,7 +2502,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, if (!queue_work(phba->wq, &ctx_buf->defer_work)) { atomic_inc(&tgtp->rcv_fcp_cmd_drop); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6325 Unable to queue work for oxid x%x. " "FCP Drop IO [x%x x%x x%x]\n", ctxp->oxid, @@ -2372,40 +2518,6 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, } /** - * lpfc_nvmet_unsol_ls_event - Process an unsolicited event from an nvme nport - * @phba: pointer to lpfc hba data structure. - * @pring: pointer to a SLI ring. - * @nvmebuf: pointer to received nvme data structure. - * - * 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_ls_buffer() after properly set up the buffer from the - * SLI RQ on which the unsolicited event was received. - **/ -void -lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *piocb) -{ - struct lpfc_dmabuf *d_buf; - struct hbq_dmabuf *nvmebuf; - - d_buf = piocb->context2; - nvmebuf = container_of(d_buf, struct hbq_dmabuf, dbuf); - - if (!nvmebuf) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "3015 LS Drop IO\n"); - return; - } - if (phba->nvmet_support == 0) { - lpfc_in_buf_free(phba, &nvmebuf->dbuf); - return; - } - lpfc_nvmet_unsol_ls_buffer(phba, pring, nvmebuf); -} - -/** * 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 @@ -2427,7 +2539,7 @@ lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint8_t cqflag) { if (!nvmebuf) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3167 NVMET FCP Drop IO\n"); return; } @@ -2465,7 +2577,7 @@ lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, **/ static struct lpfc_iocbq * lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, - struct lpfc_nvmet_rcv_ctx *ctxp, + struct lpfc_async_xchg_ctx *ctxp, dma_addr_t rspbuf, uint16_t rspsize) { struct lpfc_nodelist *ndlp; @@ -2473,7 +2585,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, union lpfc_wqe128 *wqe; if (!lpfc_is_link_up(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6104 NVMET prep LS wqe: link err: " "NPORT x%x oxid:x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2483,7 +2595,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, /* Allocate buffer for command wqe */ nvmewqe = lpfc_sli_get_iocbq(phba); if (nvmewqe == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6105 NVMET prep LS wqe: No WQE: " "NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2491,10 +2603,10 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, } ndlp = lpfc_findnode_did(phba->pport, ctxp->sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6106 NVMET prep LS wqe: No ndlp: " "NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2503,10 +2615,10 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, ctxp->wqeq = nvmewqe; /* prevent preparing wqe with NULL ndlp reference */ - nvmewqe->context1 = lpfc_nlp_get(ndlp); - if (nvmewqe->context1 == NULL) + nvmewqe->ndlp = lpfc_nlp_get(ndlp); + if (!nvmewqe->ndlp) goto nvme_wqe_free_wqeq_exit; - nvmewqe->context2 = ctxp; + nvmewqe->context_un.axchg = ctxp; wqe = &nvmewqe->wqe; memset(wqe, 0, sizeof(union lpfc_wqe)); @@ -2567,7 +2679,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, nvmewqe->retry = 1; nvmewqe->vport = phba->pport; nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT; - nvmewqe->iocb_flag |= LPFC_IO_NVME_LS; + nvmewqe->cmd_flag |= LPFC_IO_NVME_LS; /* Xmit NVMET response to remote NPORT <did> */ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, @@ -2578,8 +2690,9 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, return nvmewqe; nvme_wqe_free_wqeq_exit: - nvmewqe->context2 = NULL; - nvmewqe->context3 = NULL; + nvmewqe->context_un.axchg = NULL; + nvmewqe->ndlp = NULL; + nvmewqe->bpl_dmabuf = NULL; lpfc_sli_release_iocbq(phba, nvmewqe); return NULL; } @@ -2587,9 +2700,9 @@ nvme_wqe_free_wqeq_exit: static struct lpfc_iocbq * lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, - struct lpfc_nvmet_rcv_ctx *ctxp) + struct lpfc_async_xchg_ctx *ctxp) { - struct nvmefc_tgt_fcp_req *rsp = &ctxp->ctx.fcp_req; + struct nvmefc_tgt_fcp_req *rsp = &ctxp->hdlrctx.fcp_req; struct lpfc_nvmet_tgtport *tgtp; struct sli4_sge *sgl; struct lpfc_nodelist *ndlp; @@ -2598,12 +2711,12 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, union lpfc_wqe128 *wqe; struct ulp_bde64 *bde; dma_addr_t physaddr; - int i, cnt; - int do_pbde; + int i, cnt, nsegs; + bool use_pbde = false; int xc = 1; if (!lpfc_is_link_up(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6107 NVMET prep FCP wqe: link err:" "NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2611,10 +2724,10 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, } ndlp = lpfc_findnode_did(phba->pport, ctxp->sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6108 NVMET prep FCP wqe: no ndlp: " "NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2622,13 +2735,14 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, } if (rsp->sg_cnt > lpfc_tgttemplate.max_sgl_segments) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6109 NVMET prep FCP wqe: seg cnt err: " "NPORT x%x oxid x%x ste %d cnt %d\n", ctxp->sid, ctxp->oxid, ctxp->state, phba->cfg_nvme_seg_cnt); return NULL; } + nsegs = rsp->sg_cnt; tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; nvmewqe = ctxp->wqeq; @@ -2636,7 +2750,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, /* Allocate buffer for command wqe */ nvmewqe = ctxp->ctxbuf->iocbq; if (nvmewqe == NULL) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6110 NVMET prep FCP wqe: No " "WQE: NPORT x%x oxid x%x ste %d\n", ctxp->sid, ctxp->oxid, ctxp->state); @@ -2649,12 +2763,12 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, } /* Sanity check */ - if (((ctxp->state == LPFC_NVMET_STE_RCV) && + if (((ctxp->state == LPFC_NVME_STE_RCV) && (ctxp->entry_cnt == 1)) || - (ctxp->state == LPFC_NVMET_STE_DATA)) { + (ctxp->state == LPFC_NVME_STE_DATA)) { wqe = &nvmewqe->wqe; } else { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6111 Wrong state NVMET FCP: %d cnt %d\n", ctxp->state, ctxp->entry_cnt); return NULL; @@ -2706,9 +2820,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, if (!xc) bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 0); - /* Word 11 - set sup, irsp, irsplen later */ - do_pbde = 0; - /* Word 12 */ wqe->fcp_tsend.fcp_data_len = rsp->transfer_length; @@ -2786,12 +2897,13 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, if (!xc) bf_set(wqe_xc, &wqe->fcp_treceive.wqe_com, 0); - /* Word 11 - set pbde later */ - if (phba->cfg_enable_pbde) { - do_pbde = 1; + /* Word 11 - check for pbde */ + if (nsegs == 1 && phba->cfg_enable_pbde) { + use_pbde = true; + /* Word 11 - PBDE bit already preset by template */ } else { + /* Overwrite default template setting */ bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 0); - do_pbde = 0; } /* Word 12 */ @@ -2862,13 +2974,12 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, ((rsp->rsplen >> 2) - 1)); memcpy(&wqe->words[16], rsp->rspaddr, rsp->rsplen); } - do_pbde = 0; /* Word 12 */ wqe->fcp_trsp.rsvd_12_15[0] = 0; /* Use rspbuf, NOT sg list */ - rsp->sg_cnt = 0; + nsegs = 0; sgl->word2 = 0; atomic_inc(&tgtp->xmt_fcp_rsp); break; @@ -2883,9 +2994,9 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, nvmewqe->retry = 1; nvmewqe->vport = phba->pport; nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT; - nvmewqe->context1 = ndlp; + nvmewqe->ndlp = ndlp; - for_each_sg(rsp->sg, sgel, rsp->sg_cnt, i) { + for_each_sg(rsp->sg, sgel, nsegs, i) { physaddr = sg_dma_address(sgel); cnt = sg_dma_len(sgel); sgl->addr_hi = putPaddrHigh(physaddr); @@ -2897,24 +3008,25 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, bf_set(lpfc_sli4_sge_last, sgl, 1); sgl->word2 = cpu_to_le32(sgl->word2); sgl->sge_len = cpu_to_le32(cnt); - if (i == 0) { - bde = (struct ulp_bde64 *)&wqe->words[13]; - if (do_pbde) { - /* Words 13-15 (PBDE) */ - bde->addrLow = sgl->addr_lo; - bde->addrHigh = sgl->addr_hi; - bde->tus.f.bdeSize = - le32_to_cpu(sgl->sge_len); - bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bde->tus.w = cpu_to_le32(bde->tus.w); - } else { - memset(bde, 0, sizeof(struct ulp_bde64)); - } - } sgl++; ctxp->offset += cnt; } - ctxp->state = LPFC_NVMET_STE_DATA; + + bde = (struct ulp_bde64 *)&wqe->words[13]; + if (use_pbde) { + /* decrement sgl ptr backwards once to first data sge */ + sgl--; + + /* Words 13-15 (PBDE) */ + bde->addrLow = sgl->addr_lo; + bde->addrHigh = sgl->addr_hi; + bde->tus.f.bdeSize = le32_to_cpu(sgl->sge_len); + bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bde->tus.w = cpu_to_le32(bde->tus.w); + } else { + memset(bde, 0, sizeof(struct ulp_bde64)); + } + ctxp->state = LPFC_NVME_STE_DATA; ctxp->entry_cnt++; return nvmewqe; } @@ -2923,7 +3035,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, * lpfc_nvmet_sol_fcp_abort_cmp - Completion handler for ABTS * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. - * @wcqe: Pointer to driver response CQE 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 @@ -2931,35 +3043,36 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, **/ static void lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, - struct lpfc_wcqe_complete *wcqe) + struct lpfc_iocbq *rspwqe) { - struct lpfc_nvmet_rcv_ctx *ctxp; + struct lpfc_async_xchg_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; uint32_t result; unsigned long flags; bool released = false; + struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl; - ctxp = cmdwqe->context2; + ctxp = cmdwqe->context_un.axchg; result = wcqe->parameter; tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; - if (ctxp->flag & LPFC_NVMET_ABORT_OP) + if (ctxp->flag & LPFC_NVME_ABORT_OP) atomic_inc(&tgtp->xmt_fcp_abort_cmpl); spin_lock_irqsave(&ctxp->ctxlock, flags); - ctxp->state = LPFC_NVMET_STE_DONE; + ctxp->state = LPFC_NVME_STE_DONE; /* Check if we already received a free context call * and we have completed processing an abort situation. */ - if ((ctxp->flag & LPFC_NVMET_CTX_RLS) && - !(ctxp->flag & LPFC_NVMET_XBUSY)) { + if ((ctxp->flag & LPFC_NVME_CTX_RLS) && + !(ctxp->flag & LPFC_NVME_XBUSY)) { spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_del_init(&ctxp->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } - ctxp->flag &= ~LPFC_NVMET_ABORT_OP; + ctxp->flag &= ~LPFC_NVME_ABORT_OP; spin_unlock_irqrestore(&ctxp->ctxlock, flags); atomic_inc(&tgtp->xmt_abort_rsp); @@ -2970,8 +3083,8 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, wcqe->word0, wcqe->total_data_placed, result, wcqe->word3); - cmdwqe->context2 = NULL; - cmdwqe->context3 = NULL; + cmdwqe->rsp_dmabuf = NULL; + cmdwqe->bpl_dmabuf = NULL; /* * if transport has released ctx, then can reuse it. Otherwise, * will be recycled by transport release call. @@ -2983,7 +3096,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, lpfc_sli_release_iocbq(phba, cmdwqe); /* Since iaab/iaar are NOT set, there is no work left. - * For LPFC_NVMET_XBUSY, lpfc_sli4_nvmet_xri_aborted + * For LPFC_NVME_XBUSY, lpfc_sli4_nvmet_xri_aborted * should have been called already. */ } @@ -2992,7 +3105,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, * lpfc_nvmet_unsol_fcp_abort_cmp - Completion handler for ABTS * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. - * @wcqe: Pointer to driver response CQE 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 @@ -3000,15 +3113,16 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, **/ static void lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, - struct lpfc_wcqe_complete *wcqe) + struct lpfc_iocbq *rspwqe) { - struct lpfc_nvmet_rcv_ctx *ctxp; + struct lpfc_async_xchg_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; unsigned long flags; uint32_t result; bool released = false; + struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl; - ctxp = cmdwqe->context2; + ctxp = cmdwqe->context_un.axchg; result = wcqe->parameter; if (!ctxp) { @@ -3022,12 +3136,12 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; spin_lock_irqsave(&ctxp->ctxlock, flags); - if (ctxp->flag & LPFC_NVMET_ABORT_OP) + if (ctxp->flag & LPFC_NVME_ABORT_OP) atomic_inc(&tgtp->xmt_fcp_abort_cmpl); /* Sanity check */ - if (ctxp->state != LPFC_NVMET_STE_ABORT) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + if (ctxp->state != LPFC_NVME_STE_ABORT) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6112 ABTS Wrong state:%d oxid x%x\n", ctxp->state, ctxp->oxid); } @@ -3035,15 +3149,15 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, /* Check if we already received a free context call * and we have completed processing an abort situation. */ - ctxp->state = LPFC_NVMET_STE_DONE; - if ((ctxp->flag & LPFC_NVMET_CTX_RLS) && - !(ctxp->flag & LPFC_NVMET_XBUSY)) { + ctxp->state = LPFC_NVME_STE_DONE; + if ((ctxp->flag & LPFC_NVME_CTX_RLS) && + !(ctxp->flag & LPFC_NVME_XBUSY)) { spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_del_init(&ctxp->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } - ctxp->flag &= ~LPFC_NVMET_ABORT_OP; + ctxp->flag &= ~LPFC_NVME_ABORT_OP; spin_unlock_irqrestore(&ctxp->ctxlock, flags); atomic_inc(&tgtp->xmt_abort_rsp); @@ -3054,8 +3168,8 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, wcqe->word0, wcqe->total_data_placed, result, wcqe->word3); - cmdwqe->context2 = NULL; - cmdwqe->context3 = NULL; + cmdwqe->rsp_dmabuf = NULL; + cmdwqe->bpl_dmabuf = NULL; /* * if transport has released ctx, then can reuse it. Otherwise, * will be recycled by transport release call. @@ -3064,7 +3178,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); /* Since iaab/iaar are NOT set, there is no work left. - * For LPFC_NVMET_XBUSY, lpfc_sli4_nvmet_xri_aborted + * For LPFC_NVME_XBUSY, lpfc_sli4_nvmet_xri_aborted * should have been called already. */ } @@ -3073,7 +3187,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, * lpfc_nvmet_xmt_ls_abort_cmp - Completion handler for ABTS * @phba: Pointer to HBA context object. * @cmdwqe: Pointer to driver command WQE object. - * @wcqe: Pointer to driver response CQE 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 @@ -3081,17 +3195,20 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, **/ static void lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, - struct lpfc_wcqe_complete *wcqe) + struct lpfc_iocbq *rspwqe) { - struct lpfc_nvmet_rcv_ctx *ctxp; + struct lpfc_async_xchg_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; uint32_t result; + struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl; - ctxp = cmdwqe->context2; + ctxp = cmdwqe->context_un.axchg; result = wcqe->parameter; - tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; - atomic_inc(&tgtp->xmt_ls_abort_cmpl); + if (phba->nvmet_support) { + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + atomic_inc(&tgtp->xmt_ls_abort_cmpl); + } lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, "6083 Abort cmpl: ctx x%px WCQE:%08x %08x %08x %08x\n", @@ -3099,7 +3216,7 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, result, wcqe->word3); if (!ctxp) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6415 NVMET LS Abort No ctx: WCQE: " "%08x %08x %08x %08x\n", wcqe->word0, wcqe->total_data_placed, @@ -3109,25 +3226,25 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, return; } - if (ctxp->state != LPFC_NVMET_STE_LS_ABORT) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + if (ctxp->state != LPFC_NVME_STE_LS_ABORT) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6416 NVMET LS abort cmpl state mismatch: " "oxid x%x: %d %d\n", ctxp->oxid, ctxp->state, ctxp->entry_cnt); } - cmdwqe->context2 = NULL; - cmdwqe->context3 = NULL; + cmdwqe->rsp_dmabuf = NULL; + cmdwqe->bpl_dmabuf = NULL; lpfc_sli_release_iocbq(phba, cmdwqe); kfree(ctxp); } static int lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, - struct lpfc_nvmet_rcv_ctx *ctxp, + struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, uint16_t xri) { - struct lpfc_nvmet_tgtport *tgtp; + struct lpfc_nvmet_tgtport *tgtp = NULL; struct lpfc_iocbq *abts_wqeq; union lpfc_wqe128 *wqe_abts; struct lpfc_nodelist *ndlp; @@ -3136,14 +3253,16 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, "6067 ABTS: sid %x xri x%x/x%x\n", sid, xri, ctxp->wqeq->sli4_xritag); - tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + if (phba->nvmet_support && phba->targetport) + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; ndlp = lpfc_findnode_did(phba->pport, sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { - atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + if (tgtp) + atomic_inc(&tgtp->xmt_abort_rsp_error); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6134 Drop ABTS - wrong NDLP state x%x.\n", (ndlp) ? ndlp->nlp_state : NLP_STE_MAX_STATE); @@ -3189,7 +3308,6 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, bf_set(wqe_rcvoxid, &wqe_abts->xmit_sequence.wqe_com, xri); /* Word 10 */ - bf_set(wqe_dbde, &wqe_abts->xmit_sequence.wqe_com, 1); bf_set(wqe_iod, &wqe_abts->xmit_sequence.wqe_com, LPFC_WQE_IOD_WRITE); bf_set(wqe_lenloc, &wqe_abts->xmit_sequence.wqe_com, LPFC_WQE_LENLOC_WORD12); @@ -3203,10 +3321,10 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, OTHER_COMMAND); abts_wqeq->vport = phba->pport; - abts_wqeq->context1 = ndlp; - abts_wqeq->context2 = ctxp; - abts_wqeq->context3 = NULL; - abts_wqeq->rsvd2 = 0; + abts_wqeq->ndlp = ndlp; + abts_wqeq->context_un.axchg = ctxp; + abts_wqeq->bpl_dmabuf = NULL; + abts_wqeq->num_bdes = 0; /* hba_wqidx should already be setup from command we are aborting */ abts_wqeq->iocb.ulpCommand = CMD_XMIT_SEQUENCE64_CR; abts_wqeq->iocb.ulpLe = 1; @@ -3219,14 +3337,14 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, static int lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, - struct lpfc_nvmet_rcv_ctx *ctxp, + struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, uint16_t xri) { struct lpfc_nvmet_tgtport *tgtp; struct lpfc_iocbq *abts_wqeq; struct lpfc_nodelist *ndlp; unsigned long flags; - u8 opt; + bool ia; int rc; tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; @@ -3236,17 +3354,17 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, } ndlp = lpfc_findnode_did(phba->pport, sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6160 Drop ABORT - wrong NDLP state x%x.\n", (ndlp) ? ndlp->nlp_state : NLP_STE_MAX_STATE); /* No failure to an ABTS request. */ spin_lock_irqsave(&ctxp->ctxlock, flags); - ctxp->flag &= ~LPFC_NVMET_ABORT_OP; + ctxp->flag &= ~LPFC_NVME_ABORT_OP; spin_unlock_irqrestore(&ctxp->ctxlock, flags); return 0; } @@ -3256,17 +3374,17 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, spin_lock_irqsave(&ctxp->ctxlock, flags); if (!ctxp->abort_wqeq) { atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6161 ABORT failed: No wqeqs: " "xri: x%x\n", ctxp->oxid); /* No failure to an ABTS request. */ - ctxp->flag &= ~LPFC_NVMET_ABORT_OP; + ctxp->flag &= ~LPFC_NVME_ABORT_OP; spin_unlock_irqrestore(&ctxp->ctxlock, flags); return 0; } abts_wqeq = ctxp->abort_wqeq; - ctxp->state = LPFC_NVMET_STE_ABORT; - opt = (ctxp->flag & LPFC_NVMET_ABTS_RCV) ? INHIBIT_ABORT : 0; + ctxp->state = LPFC_NVME_STE_ABORT; + ia = (ctxp->flag & LPFC_NVME_ABTS_RCV) ? true : false; spin_unlock_irqrestore(&ctxp->ctxlock, flags); /* Announce entry to new IO submit field. */ @@ -3283,43 +3401,44 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, if (phba->hba_flag & HBA_IOQ_FLUSH) { spin_unlock_irqrestore(&phba->hbalock, flags); atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6163 Driver in reset cleanup - flushing " "NVME Req now. hba_flag x%x oxid x%x\n", phba->hba_flag, ctxp->oxid); lpfc_sli_release_iocbq(phba, abts_wqeq); spin_lock_irqsave(&ctxp->ctxlock, flags); - ctxp->flag &= ~LPFC_NVMET_ABORT_OP; + ctxp->flag &= ~LPFC_NVME_ABORT_OP; spin_unlock_irqrestore(&ctxp->ctxlock, flags); return 0; } /* Outstanding abort is in progress */ - if (abts_wqeq->iocb_flag & LPFC_DRIVER_ABORTED) { + if (abts_wqeq->cmd_flag & LPFC_DRIVER_ABORTED) { spin_unlock_irqrestore(&phba->hbalock, flags); atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6164 Outstanding NVME I/O Abort Request " "still pending on oxid x%x\n", ctxp->oxid); lpfc_sli_release_iocbq(phba, abts_wqeq); spin_lock_irqsave(&ctxp->ctxlock, flags); - ctxp->flag &= ~LPFC_NVMET_ABORT_OP; + ctxp->flag &= ~LPFC_NVME_ABORT_OP; spin_unlock_irqrestore(&ctxp->ctxlock, flags); return 0; } /* Ready - mark outstanding as aborted by driver. */ - abts_wqeq->iocb_flag |= LPFC_DRIVER_ABORTED; + abts_wqeq->cmd_flag |= LPFC_DRIVER_ABORTED; - lpfc_nvme_prep_abort_wqe(abts_wqeq, ctxp->wqeq->sli4_xritag, opt); + lpfc_sli_prep_abort_xri(phba, abts_wqeq, ctxp->wqeq->sli4_xritag, + abts_wqeq->iotag, CLASS3, + LPFC_WQE_CQ_ID_DEFAULT, ia, true); /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abts_wqeq->hba_wqidx = ctxp->wqeq->hba_wqidx; - abts_wqeq->wqe_cmpl = lpfc_nvmet_sol_fcp_abort_cmp; - abts_wqeq->iocb_cmpl = NULL; - abts_wqeq->iocb_flag |= LPFC_IO_NVME; - abts_wqeq->context2 = ctxp; + abts_wqeq->cmd_cmpl = lpfc_nvmet_sol_fcp_abort_cmp; + abts_wqeq->cmd_flag |= LPFC_IO_NVME; + abts_wqeq->context_un.axchg = ctxp; abts_wqeq->vport = phba->pport; if (!ctxp->hdwq) ctxp->hdwq = &phba->sli4_hba.hdwq[abts_wqeq->hba_wqidx]; @@ -3333,10 +3452,10 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, atomic_inc(&tgtp->xmt_abort_rsp_error); spin_lock_irqsave(&ctxp->ctxlock, flags); - ctxp->flag &= ~LPFC_NVMET_ABORT_OP; + ctxp->flag &= ~LPFC_NVME_ABORT_OP; spin_unlock_irqrestore(&ctxp->ctxlock, flags); lpfc_sli_release_iocbq(phba, abts_wqeq); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6166 Failed ABORT issue_wqe with status x%x " "for oxid x%x.\n", rc, ctxp->oxid); @@ -3345,7 +3464,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, - struct lpfc_nvmet_rcv_ctx *ctxp, + struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, uint16_t xri) { struct lpfc_nvmet_tgtport *tgtp; @@ -3360,14 +3479,14 @@ lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, ctxp->wqeq->hba_wqidx = 0; } - if (ctxp->state == LPFC_NVMET_STE_FREE) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + if (ctxp->state == LPFC_NVME_STE_FREE) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6417 NVMET ABORT ctx freed %d %d oxid x%x\n", ctxp->state, ctxp->entry_cnt, ctxp->oxid); rc = WQE_BUSY; goto aerr; } - ctxp->state = LPFC_NVMET_STE_ABORT; + ctxp->state = LPFC_NVME_STE_ABORT; ctxp->entry_cnt++; rc = lpfc_nvmet_unsol_issue_abort(phba, ctxp, sid, xri); if (rc == 0) @@ -3375,9 +3494,8 @@ lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, spin_lock_irqsave(&phba->hbalock, flags); abts_wqeq = ctxp->wqeq; - abts_wqeq->wqe_cmpl = lpfc_nvmet_unsol_fcp_abort_cmp; - abts_wqeq->iocb_cmpl = NULL; - abts_wqeq->iocb_flag |= LPFC_IO_NVMET; + abts_wqeq->cmd_cmpl = lpfc_nvmet_unsol_fcp_abort_cmp; + abts_wqeq->cmd_flag |= LPFC_IO_NVMET; if (!ctxp->hdwq) ctxp->hdwq = &phba->sli4_hba.hdwq[abts_wqeq->hba_wqidx]; @@ -3389,17 +3507,17 @@ lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, aerr: spin_lock_irqsave(&ctxp->ctxlock, flags); - if (ctxp->flag & LPFC_NVMET_CTX_RLS) { + if (ctxp->flag & LPFC_NVME_CTX_RLS) { spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_del_init(&ctxp->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } - ctxp->flag &= ~(LPFC_NVMET_ABORT_OP | LPFC_NVMET_CTX_RLS); + ctxp->flag &= ~(LPFC_NVME_ABORT_OP | LPFC_NVME_CTX_RLS); spin_unlock_irqrestore(&ctxp->ctxlock, flags); atomic_inc(&tgtp->xmt_abort_rsp_error); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6135 Failed to Issue ABTS for oxid x%x. Status x%x " "(%x)\n", ctxp->oxid, rc, released); @@ -3408,34 +3526,44 @@ aerr: return 1; } -static int -lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, - struct lpfc_nvmet_rcv_ctx *ctxp, +/** + * 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) { - struct lpfc_nvmet_tgtport *tgtp; + struct lpfc_nvmet_tgtport *tgtp = NULL; struct lpfc_iocbq *abts_wqeq; unsigned long flags; int rc; - if ((ctxp->state == LPFC_NVMET_STE_LS_RCV && ctxp->entry_cnt == 1) || - (ctxp->state == LPFC_NVMET_STE_LS_RSP && ctxp->entry_cnt == 2)) { - ctxp->state = LPFC_NVMET_STE_LS_ABORT; + if ((ctxp->state == LPFC_NVME_STE_LS_RCV && ctxp->entry_cnt == 1) || + (ctxp->state == LPFC_NVME_STE_LS_RSP && ctxp->entry_cnt == 2)) { + ctxp->state = LPFC_NVME_STE_LS_ABORT; ctxp->entry_cnt++; } else { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6418 NVMET LS abort state mismatch " "IO x%x: %d %d\n", ctxp->oxid, ctxp->state, ctxp->entry_cnt); - ctxp->state = LPFC_NVMET_STE_LS_ABORT; + ctxp->state = LPFC_NVME_STE_LS_ABORT; } - tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + if (phba->nvmet_support && phba->targetport) + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + if (!ctxp->wqeq) { /* Issue ABTS for this WQE based on iotag */ ctxp->wqeq = lpfc_sli_get_iocbq(phba); if (!ctxp->wqeq) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6068 Abort failed: No wqeqs: " "xri: x%x\n", xri); /* No failure to an ABTS request. */ @@ -3451,22 +3579,67 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, } spin_lock_irqsave(&phba->hbalock, flags); - abts_wqeq->wqe_cmpl = lpfc_nvmet_xmt_ls_abort_cmp; - abts_wqeq->iocb_cmpl = NULL; - abts_wqeq->iocb_flag |= LPFC_IO_NVME_LS; + abts_wqeq->cmd_cmpl = lpfc_nvmet_xmt_ls_abort_cmp; + abts_wqeq->cmd_flag |= LPFC_IO_NVME_LS; rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, abts_wqeq); spin_unlock_irqrestore(&phba->hbalock, flags); if (rc == WQE_SUCCESS) { - atomic_inc(&tgtp->xmt_abort_unsol); + if (tgtp) + atomic_inc(&tgtp->xmt_abort_unsol); return 0; } out: - atomic_inc(&tgtp->xmt_abort_rsp_error); - abts_wqeq->context2 = NULL; - abts_wqeq->context3 = NULL; + if (tgtp) + atomic_inc(&tgtp->xmt_abort_rsp_error); + abts_wqeq->rsp_dmabuf = NULL; + abts_wqeq->bpl_dmabuf = NULL; lpfc_sli_release_iocbq(phba, abts_wqeq); - kfree(ctxp); - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6056 Failed to Issue ABTS. Status x%x\n", rc); - return 0; + return 1; +} + +/** + * 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) +{ + u32 ndlp_has_hh; + struct lpfc_nvmet_tgtport *tgtp; + + lpfc_printf_log(phba, KERN_INFO, + LOG_NVME | LOG_NVME_ABTS | LOG_NVME_DISC, + "6203 Invalidating hosthandle x%px\n", + ndlp); + + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + atomic_set(&tgtp->state, LPFC_NVMET_INV_HOST_ACTIVE); + + spin_lock_irq(&ndlp->lock); + ndlp_has_hh = ndlp->fc4_xpt_flags & NLP_XPT_HAS_HH; + spin_unlock_irq(&ndlp->lock); + + /* Do not invalidate any nodes that do not have a hosthandle. + * The host_release callbk will cause a node reference + * count imbalance and a crash. + */ + if (!ndlp_has_hh) { + lpfc_printf_log(phba, KERN_INFO, + LOG_NVME | LOG_NVME_ABTS | LOG_NVME_DISC, + "6204 Skip invalidate on node x%px DID x%x\n", + ndlp, ndlp->nlp_DID); + return; + } + +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + /* Need to get the nvmet_fc_target_port pointer here.*/ + nvmet_fc_invalidate_host(phba->targetport, ndlp); +#endif } diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h deleted file mode 100644 index b80b1639b9a7..000000000000 --- a/drivers/scsi/lpfc/lpfc_nvmet.h +++ /dev/null @@ -1,158 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 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. * - ********************************************************************/ - -#define LPFC_NVMET_DEFAULT_SEGS (64 + 1) /* 256K IOs */ -#define LPFC_NVMET_RQE_MIN_POST 128 -#define LPFC_NVMET_RQE_DEF_POST 512 -#define LPFC_NVMET_RQE_DEF_COUNT 2048 -#define LPFC_NVMET_SUCCESS_LEN 12 - -#define LPFC_NVMET_MRQ_AUTO 0 -#define LPFC_NVMET_MRQ_MAX 16 - -#define LPFC_NVMET_WAIT_TMO (5 * MSEC_PER_SEC) - -/* Used for NVME Target */ -struct lpfc_nvmet_tgtport { - struct lpfc_hba *phba; - struct completion *tport_unreg_cmp; - - /* Stats counters - lpfc_nvmet_unsol_ls_buffer */ - atomic_t rcv_ls_req_in; - atomic_t rcv_ls_req_out; - atomic_t rcv_ls_req_drop; - atomic_t xmt_ls_abort; - atomic_t xmt_ls_abort_cmpl; - - /* Stats counters - lpfc_nvmet_xmt_ls_rsp */ - atomic_t xmt_ls_rsp; - atomic_t xmt_ls_drop; - - /* Stats counters - lpfc_nvmet_xmt_ls_rsp_cmp */ - atomic_t xmt_ls_rsp_error; - atomic_t xmt_ls_rsp_aborted; - atomic_t xmt_ls_rsp_xb_set; - atomic_t xmt_ls_rsp_cmpl; - - /* Stats counters - lpfc_nvmet_unsol_fcp_buffer */ - atomic_t rcv_fcp_cmd_in; - atomic_t rcv_fcp_cmd_out; - atomic_t rcv_fcp_cmd_drop; - atomic_t rcv_fcp_cmd_defer; - atomic_t xmt_fcp_release; - - /* Stats counters - lpfc_nvmet_xmt_fcp_op */ - atomic_t xmt_fcp_drop; - atomic_t xmt_fcp_read_rsp; - atomic_t xmt_fcp_read; - atomic_t xmt_fcp_write; - atomic_t xmt_fcp_rsp; - - /* Stats counters - lpfc_nvmet_xmt_fcp_op_cmp */ - atomic_t xmt_fcp_rsp_xb_set; - atomic_t xmt_fcp_rsp_cmpl; - atomic_t xmt_fcp_rsp_error; - atomic_t xmt_fcp_rsp_aborted; - atomic_t xmt_fcp_rsp_drop; - - /* Stats counters - lpfc_nvmet_xmt_fcp_abort */ - atomic_t xmt_fcp_xri_abort_cqe; - atomic_t xmt_fcp_abort; - atomic_t xmt_fcp_abort_cmpl; - atomic_t xmt_abort_sol; - atomic_t xmt_abort_unsol; - atomic_t xmt_abort_rsp; - atomic_t xmt_abort_rsp_error; - - /* Stats counters - defer IO */ - atomic_t defer_ctx; - atomic_t defer_fod; - atomic_t defer_wqfull; -}; - -struct lpfc_nvmet_ctx_info { - struct list_head nvmet_ctx_list; - spinlock_t nvmet_ctx_list_lock; /* lock per CPU */ - struct lpfc_nvmet_ctx_info *nvmet_ctx_next_cpu; - struct lpfc_nvmet_ctx_info *nvmet_ctx_start_cpu; - uint16_t nvmet_ctx_list_cnt; - char pad[16]; /* pad to a cache-line */ -}; - -/* This retrieves the context info associated with the specified cpu / mrq */ -#define lpfc_get_ctx_list(phba, cpu, mrq) \ - (phba->sli4_hba.nvmet_ctx_info + ((cpu * phba->cfg_nvmet_mrq) + mrq)) - -struct lpfc_nvmet_rcv_ctx { - union { - struct nvmefc_tgt_ls_req ls_req; - struct nvmefc_tgt_fcp_req fcp_req; - } ctx; - struct list_head list; - struct lpfc_hba *phba; - struct lpfc_iocbq *wqeq; - struct lpfc_iocbq *abort_wqeq; - spinlock_t ctxlock; /* protect flag access */ - uint32_t sid; - uint32_t offset; - uint16_t oxid; - uint16_t size; - uint16_t entry_cnt; - uint16_t cpu; - uint16_t idx; - uint16_t state; - /* States */ -#define LPFC_NVMET_STE_LS_RCV 1 -#define LPFC_NVMET_STE_LS_ABORT 2 -#define LPFC_NVMET_STE_LS_RSP 3 -#define LPFC_NVMET_STE_RCV 4 -#define LPFC_NVMET_STE_DATA 5 -#define LPFC_NVMET_STE_ABORT 6 -#define LPFC_NVMET_STE_DONE 7 -#define LPFC_NVMET_STE_FREE 0xff - uint16_t flag; -#define LPFC_NVMET_IO_INP 0x1 /* IO is in progress on exchange */ -#define LPFC_NVMET_ABORT_OP 0x2 /* Abort WQE issued on exchange */ -#define LPFC_NVMET_XBUSY 0x4 /* XB bit set on IO cmpl */ -#define LPFC_NVMET_CTX_RLS 0x8 /* ctx free requested */ -#define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */ -#define LPFC_NVMET_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */ -#define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ -#define LPFC_NVMET_TNOTIFY 0x80 /* notify transport of abts */ - struct rqb_dmabuf *rqb_buffer; - struct lpfc_nvmet_ctxbuf *ctxbuf; - struct lpfc_sli4_hdw_queue *hdwq; - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - uint64_t ts_isr_cmd; - uint64_t ts_cmd_nvme; - uint64_t ts_nvme_data; - uint64_t ts_data_wqput; - uint64_t ts_isr_data; - uint64_t ts_data_nvme; - uint64_t ts_nvme_status; - uint64_t ts_status_wqput; - uint64_t ts_isr_status; - uint64_t ts_status_nvme; -#endif -}; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 2c7e0b22db2f..7a1563564df7 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2022 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 * @@ -28,6 +28,7 @@ #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> @@ -87,30 +88,6 @@ 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); -static inline unsigned -lpfc_cmd_blksize(struct scsi_cmnd *sc) -{ - return sc->device->sector_size; -} - -#define LPFC_CHECK_PROTECT_GUARD 1 -#define LPFC_CHECK_PROTECT_REF 2 -static inline unsigned -lpfc_cmd_protect(struct scsi_cmnd *sc, int flag) -{ - return 1; -} - -static inline unsigned -lpfc_cmd_guard_csum(struct scsi_cmnd *sc) -{ - if (lpfc_prot_group_type(NULL, sc) == LPFC_PG_TYPE_NO_DIF) - return 0; - if (scsi_host_get_guard(sc->device->host) == SHOST_DIX_GUARD_IP) - return 1; - return 0; -} - /** * lpfc_sli4_set_rsp_sgl_last - Set the last bit in the response sge. * @phba: Pointer to HBA object. @@ -132,61 +109,7 @@ lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, } } -/** - * lpfc_update_stats - Update statistical data for the command completion - * @vport: The virtual port on which this call is executing. - * @lpfc_cmd: lpfc scsi command object pointer. - * - * This function is called when there is a command completion and this - * function updates the statistical data for the command completion. - **/ -static void -lpfc_update_stats(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_rport_data *rdata; - struct lpfc_nodelist *pnode; - struct scsi_cmnd *cmd = lpfc_cmd->pCmd; - unsigned long flags; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - unsigned long latency; - int i; - - if (!vport->stat_data_enabled || - vport->stat_data_blocked || - (cmd->result)) - return; - - latency = jiffies_to_msecs((long)jiffies - (long)lpfc_cmd->start_time); - rdata = lpfc_cmd->rdata; - pnode = rdata->pnode; - - spin_lock_irqsave(shost->host_lock, flags); - if (!pnode || - !pnode->lat_data || - (phba->bucket_type == LPFC_NO_BUCKET)) { - spin_unlock_irqrestore(shost->host_lock, flags); - return; - } - - if (phba->bucket_type == LPFC_LINEAR_BUCKET) { - i = (latency + phba->bucket_step - 1 - phba->bucket_base)/ - phba->bucket_step; - /* check array subscript bounds */ - if (i < 0) - i = 0; - else if (i >= LPFC_MAX_BUCKET_COUNT) - i = LPFC_MAX_BUCKET_COUNT - 1; - } else { - for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++) - if (latency <= (phba->bucket_base + - ((1<<i)*phba->bucket_step))) - break; - } - - pnode->lat_data[i].cmd_count++; - spin_unlock_irqrestore(shost->host_lock, flags); -} +#define LPFC_INVALID_REFTAG ((u32)-1) /** * lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread @@ -313,7 +236,7 @@ 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_allocate: The requested number of buffers to allocate. + * @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 @@ -375,7 +298,7 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) kfree(psb); break; } - psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; + psb->cur_iocbq.cmd_flag |= LPFC_IO_FCP; psb->fcp_cmnd = psb->data; psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd); @@ -446,7 +369,7 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) iocb->ulpClass = CLASS3; psb->status = IOSTAT_SUCCESS; /* Put it back into the SCSI buffer list */ - psb->cur_iocbq.context1 = psb; + psb->cur_iocbq.io_buf = psb; spin_lock_init(&psb->buf_lock); lpfc_release_scsi_buf_s3(phba, psb); @@ -481,7 +404,7 @@ lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport) spin_lock(&qp->abts_io_buf_list_lock); list_for_each_entry_safe(psb, next_psb, &qp->lpfc_abts_io_buf_list, list) { - if (psb->cur_iocbq.iocb_flag & LPFC_IO_NVME) + if (psb->cur_iocbq.cmd_flag & LPFC_IO_NVME) continue; if (psb->rdata && psb->rdata->pnode && @@ -497,6 +420,7 @@ 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. @@ -505,8 +429,8 @@ void lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri, int idx) { - uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); - uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); + u16 xri = 0; + u16 rxid = 0; struct lpfc_io_buf *psb, *next_psb; struct lpfc_sli4_hdw_queue *qp; unsigned long iflag = 0; @@ -515,25 +439,40 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp; int rrq_empty = 0; struct lpfc_sli_ring *pring = phba->sli4_hba.els_wq->pring; + struct scsi_cmnd *cmd; + int offline = 0; if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) return; - + offline = pci_channel_offline(phba->pcidev); + if (!offline) { + xri = bf_get(lpfc_wcqe_xa_xri, axri); + rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); + } qp = &phba->sli4_hba.hdwq[idx]; spin_lock_irqsave(&phba->hbalock, iflag); spin_lock(&qp->abts_io_buf_list_lock); list_for_each_entry_safe(psb, next_psb, &qp->lpfc_abts_io_buf_list, list) { + if (offline) + xri = psb->cur_iocbq.sli4_xritag; if (psb->cur_iocbq.sli4_xritag == xri) { list_del_init(&psb->list); psb->flags &= ~LPFC_SBUF_XBUSY; psb->status = IOSTAT_SUCCESS; - if (psb->cur_iocbq.iocb_flag & LPFC_IO_NVME) { + if (psb->cur_iocbq.cmd_flag & LPFC_IO_NVME) { qp->abts_nvme_io_bufs--; spin_unlock(&qp->abts_io_buf_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_sli4_nvme_xri_aborted(phba, axri, psb); - return; + if (!offline) { + lpfc_sli4_nvme_xri_aborted(phba, axri, + psb); + return; + } + lpfc_sli4_nvme_pci_offline_aborted(phba, psb); + spin_lock_irqsave(&phba->hbalock, iflag); + spin_lock(&qp->abts_io_buf_list_lock); + continue; } qp->abts_scsi_io_bufs--; spin_unlock(&qp->abts_io_buf_list_lock); @@ -545,33 +484,63 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, rrq_empty = list_empty(&phba->active_rrq_list); spin_unlock_irqrestore(&phba->hbalock, iflag); - if (ndlp) { + if (ndlp && !offline) { lpfc_set_rrq_active(phba, ndlp, psb->cur_iocbq.sli4_lxritag, rxid, 1); lpfc_sli4_abts_err_handler(phba, ndlp, axri); } + + if (phba->cfg_fcp_wait_abts_rsp || offline) { + spin_lock_irqsave(&psb->buf_lock, iflag); + cmd = psb->pCmd; + psb->pCmd = NULL; + spin_unlock_irqrestore(&psb->buf_lock, iflag); + + /* The sdev is not guaranteed to be valid post + * scsi_done upcall. + */ + if (cmd) + scsi_done(cmd); + + /* + * We expect there is an abort thread waiting + * for command completion wake up the thread. + */ + spin_lock_irqsave(&psb->buf_lock, iflag); + psb->cur_iocbq.cmd_flag &= + ~LPFC_DRIVER_ABORTED; + if (psb->waitq) + wake_up(psb->waitq); + spin_unlock_irqrestore(&psb->buf_lock, iflag); + } + lpfc_release_scsi_buf_s4(phba, psb); if (rrq_empty) lpfc_worker_wake_up(phba); - return; + if (!offline) + return; + spin_lock_irqsave(&phba->hbalock, iflag); + spin_lock(&qp->abts_io_buf_list_lock); + continue; } } spin_unlock(&qp->abts_io_buf_list_lock); - for (i = 1; i <= phba->sli.last_iotag; i++) { - iocbq = phba->sli.iocbq_lookup[i]; - - if (!(iocbq->iocb_flag & LPFC_IO_FCP) || - (iocbq->iocb_flag & LPFC_IO_LIBDFC)) - continue; - if (iocbq->sli4_xritag != xri) - continue; - psb = container_of(iocbq, struct lpfc_io_buf, cur_iocbq); - psb->flags &= ~LPFC_SBUF_XBUSY; - spin_unlock_irqrestore(&phba->hbalock, iflag); - if (!list_empty(&pring->txq)) - lpfc_worker_wake_up(phba); - return; + if (!offline) { + for (i = 1; i <= phba->sli.last_iotag; i++) { + iocbq = phba->sli.iocbq_lookup[i]; + if (!(iocbq->cmd_flag & LPFC_IO_FCP) || + (iocbq->cmd_flag & LPFC_IO_LIBDFC)) + continue; + if (iocbq->sli4_xritag != xri) + continue; + psb = container_of(iocbq, struct lpfc_io_buf, cur_iocbq); + psb->flags &= ~LPFC_SBUF_XBUSY; + spin_unlock_irqrestore(&phba->hbalock, iflag); + if (!list_empty(&pring->txq)) + lpfc_worker_wake_up(phba); + return; + } } spin_unlock_irqrestore(&phba->hbalock, iflag); } @@ -579,6 +548,8 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, /** * 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. @@ -618,6 +589,8 @@ lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, /** * 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. @@ -633,7 +606,6 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct lpfc_io_buf *lpfc_cmd; struct lpfc_sli4_hdw_queue *qp; struct sli4_sge *sgl; - IOCB_t *iocb; dma_addr_t pdma_phys_fcp_rsp; dma_addr_t pdma_phys_fcp_cmd; uint32_t cpu, idx; @@ -642,7 +614,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, cpu = raw_smp_processor_id(); if (cmnd && phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) { - tag = blk_mq_unique_tag(cmnd->request); + tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); idx = blk_mq_unique_tag_to_hwq(tag); } else { idx = phba->sli4_hba.cpu_map[cpu].hdwq; @@ -659,7 +631,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, /* Setup key fields in buffer that may have been changed * if other protocols used this buffer. */ - lpfc_cmd->cur_iocbq.iocb_flag = LPFC_IO_FCP; + lpfc_cmd->cur_iocbq.cmd_flag = LPFC_IO_FCP; lpfc_cmd->prot_seg_cnt = 0; lpfc_cmd->seg_cnt = 0; lpfc_cmd->timeout = 0; @@ -671,8 +643,10 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, lpfc_cmd->prot_data_type = 0; #endif tmp = lpfc_get_cmd_rsp_buf_per_hdwq(phba, lpfc_cmd); - if (!tmp) + if (!tmp) { + lpfc_release_io_buf(phba, lpfc_cmd, lpfc_cmd->hdwq); return NULL; + } lpfc_cmd->fcp_cmnd = tmp->fcp_cmnd; lpfc_cmd->fcp_rsp = tmp->fcp_rsp; @@ -701,24 +675,6 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, sgl->word2 = cpu_to_le32(sgl->word2); sgl->sge_len = cpu_to_le32(sizeof(struct fcp_rsp)); - /* - * Since the IOCB for the FCP I/O is built into this - * lpfc_io_buf, initialize it with all known data now. - */ - iocb = &lpfc_cmd->cur_iocbq.iocb; - iocb->un.fcpi64.bdl.ulpIoTag32 = 0; - iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_64; - /* setting the BLP size to 2 * sizeof BDE may not be correct. - * We are setting the bpl to point to out sgl. An sgl's - * entries are 16 bytes, a bpl entries are 12 bytes. - */ - iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); - iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_fcp_cmd); - iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_fcp_cmd); - iocb->ulpBdeCount = 1; - iocb->ulpLe = 1; - iocb->ulpClass = CLASS3; - if (lpfc_ndlp_check_qdepth(phba, ndlp)) { atomic_inc(&ndlp->cmd_pending); lpfc_cmd->flags |= LPFC_SBUF_BUMP_QDEPTH; @@ -728,6 +684,8 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, /** * 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. @@ -744,7 +702,7 @@ lpfc_get_scsi_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, } /** - * lpfc_release_scsi_buf - Return a scsi buffer back to hba scsi buf list + * 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. * @@ -761,7 +719,7 @@ lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb) spin_lock_irqsave(&phba->scsi_buf_list_put_lock, iflag); psb->pCmd = NULL; - psb->cur_iocbq.iocb_flag = LPFC_IO_FCP; + psb->cur_iocbq.cmd_flag = LPFC_IO_FCP; list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list_put); spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, iflag); } @@ -788,7 +746,8 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb) qp = psb->hdwq; if (psb->flags & LPFC_SBUF_XBUSY) { spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag); - psb->pCmd = NULL; + if (!phba->cfg_fcp_wait_abts_rsp) + psb->pCmd = NULL; list_add_tail(&psb->list, &qp->lpfc_abts_io_buf_list); qp->abts_scsi_io_bufs++; spin_unlock_irqrestore(&qp->abts_io_buf_list_lock, iflag); @@ -816,6 +775,25 @@ 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) +{ + int i, j; + + for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); + i += sizeof(uint32_t), j++) { + ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); + } +} + +/** * 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. @@ -852,7 +830,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) bpl += 2; if (scsi_sg_count(scsi_cmnd)) { /* - * The driver stores the segment count returned from pci_map_sg + * The driver stores the segment count returned from dma_map_sg * because this a count of dma-mappings used to map the use_sg * pages. They are not guaranteed to be the same for those * architectures that implement an IOMMU. @@ -865,11 +843,11 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) lpfc_cmd->seg_cnt = nseg; if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9064 BLKGRD: %s: Too many sg segments from " - "dma_map_sg. Config %d, seg_cnt %d\n", - __func__, phba->cfg_sg_seg_cnt, - lpfc_cmd->seg_cnt); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "9064 BLKGRD: %s: Too many sg segments" + " from dma_map_sg. Config %d, seg_cnt" + " %d\n", __func__, phba->cfg_sg_seg_cnt, + lpfc_cmd->seg_cnt); WARN_ON_ONCE(lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt); lpfc_cmd->seg_cnt = 0; scsi_dma_unmap(scsi_cmnd); @@ -889,7 +867,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) physaddr = sg_dma_address(sgel); if (phba->sli_rev == 3 && !(phba->sli3_options & LPFC_SLI3_BG_ENABLED) && - !(iocbq->iocb_flag & DSS_SECURITY_OP) && + !(iocbq->cmd_flag & DSS_SECURITY_OP) && nseg <= LPFC_EXT_DATA_BDE_COUNT) { data_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; data_bde->tus.f.bdeSize = sg_dma_len(sgel); @@ -917,7 +895,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) */ if (phba->sli_rev == 3 && !(phba->sli3_options & LPFC_SLI3_BG_ENABLED) && - !(iocbq->iocb_flag & DSS_SECURITY_OP)) { + !(iocbq->cmd_flag & DSS_SECURITY_OP)) { if (num_bde > LPFC_EXT_DATA_BDE_COUNT) { /* * The extended IOCB format can only fit 3 BDE or a BPL. @@ -951,6 +929,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * we need to set word 4 of IOCB here */ iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); + lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); return 0; } @@ -962,10 +941,10 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) #define BG_ERR_TGT 0x2 /* Return BG_ERR_SWAP if swapping CSUM<-->CRC is required for error injection */ #define BG_ERR_SWAP 0x10 -/** +/* * Return BG_ERR_CHECK if disabling Guard/Ref/App checking is required for * error injection - **/ + */ #define BG_ERR_CHECK 0x20 /** @@ -974,7 +953,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * @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 + * @new_guard: (in) Value to replace CRC with if needed * * Returns BG_ERR_* bit mask or 0 if request ignored **/ @@ -990,7 +969,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t op = scsi_get_prot_op(sc); uint32_t blksize; uint32_t numblks; - sector_t lba; + u32 lba; int rc = 0; int blockoff = 0; @@ -998,19 +977,21 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, return 0; sgpe = scsi_prot_sglist(sc); - lba = scsi_get_lba(sc); + lba = scsi_prot_ref_tag(sc); + if (lba == LPFC_INVALID_REFTAG) + return 0; /* First check if we need to match the LBA */ if (phba->lpfc_injerr_lba != LPFC_INJERR_LBA_OFF) { - blksize = lpfc_cmd_blksize(sc); + blksize = scsi_prot_interval(sc); numblks = (scsi_bufflen(sc) + blksize - 1) / blksize; /* Make sure we have the right LBA if one is specified */ - if ((phba->lpfc_injerr_lba < lba) || - (phba->lpfc_injerr_lba >= (lba + numblks))) + if (phba->lpfc_injerr_lba < (u64)lba || + (phba->lpfc_injerr_lba >= (u64)(lba + numblks))) return 0; if (sgpe) { - blockoff = phba->lpfc_injerr_lba - lba; + blockoff = phba->lpfc_injerr_lba - (u64)lba; numblks = sg_dma_len(sgpe) / sizeof(struct scsi_dif_tuple); if (numblks < blockoff) @@ -1059,7 +1040,8 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, * inserted in middle of the IO. */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "9076 BLKGRD: Injecting reftag error: " "write lba x%lx + x%x oldrefTag x%x\n", (unsigned long)lba, blockoff, @@ -1090,7 +1072,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, break; } - /* fall through */ + fallthrough; case SCSI_PROT_WRITE_INSERT: /* * For WRITE_INSERT, force the error @@ -1109,7 +1091,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_TGT | BG_ERR_CHECK; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9078 BLKGRD: Injecting reftag error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1130,7 +1112,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_INIT; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9077 BLKGRD: Injecting reftag error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1157,7 +1139,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_INIT; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9079 BLKGRD: Injecting reftag error: " "read lba x%lx\n", (unsigned long)lba); break; @@ -1179,7 +1161,8 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, * inserted in middle of the IO. */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, "9080 BLKGRD: Injecting apptag error: " "write lba x%lx + x%x oldappTag x%x\n", (unsigned long)lba, blockoff, @@ -1209,7 +1192,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, rc = BG_ERR_TGT | BG_ERR_CHECK; break; } - /* fall through */ + fallthrough; case SCSI_PROT_WRITE_INSERT: /* * For WRITE_INSERT, force the @@ -1228,7 +1211,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_TGT | BG_ERR_CHECK; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0813 BLKGRD: Injecting apptag error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1249,7 +1232,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_INIT; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0812 BLKGRD: Injecting apptag error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1276,7 +1259,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, } rc = BG_ERR_INIT; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0814 BLKGRD: Injecting apptag error: " "read lba x%lx\n", (unsigned long)lba); break; @@ -1291,7 +1274,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, switch (op) { case SCSI_PROT_WRITE_PASS: rc = BG_ERR_CHECK; - /* fall through */ + fallthrough; case SCSI_PROT_WRITE_INSERT: /* @@ -1311,7 +1294,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, rc |= BG_ERR_TGT | BG_ERR_SWAP; /* Signals the caller to swap CRC->CSUM */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0817 BLKGRD: Injecting guard error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1333,7 +1316,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, rc = BG_ERR_INIT | BG_ERR_SWAP; /* Signals the caller to swap CRC->CSUM */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0816 BLKGRD: Injecting guard error: " "write lba x%lx\n", (unsigned long)lba); break; @@ -1361,7 +1344,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, rc = BG_ERR_INIT | BG_ERR_SWAP; /* Signals the caller to swap CRC->CSUM */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0818 BLKGRD: Injecting guard error: " "read lba x%lx\n", (unsigned long)lba); } @@ -1377,8 +1360,8 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, * the specified SCSI command. * @phba: The Hba for which this call is being executed. * @sc: The SCSI command to examine - * @txopt: (out) BlockGuard operation for transmitted data - * @rxopt: (out) BlockGuard operation for received data + * @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 * @@ -1389,7 +1372,7 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, { uint8_t ret = 0; - if (lpfc_cmd_guard_csum(sc)) { + if (sc->prot_flags & SCSI_PROT_IP_CHECKSUM) { switch (scsi_get_prot_op(sc)) { case SCSI_PROT_READ_INSERT: case SCSI_PROT_WRITE_STRIP: @@ -1411,7 +1394,7 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, case SCSI_PROT_NORMAL: default: - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9063 BLKGRD: Bad op/guard:%d/IP combination\n", scsi_get_prot_op(sc)); ret = 1; @@ -1440,7 +1423,7 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, case SCSI_PROT_NORMAL: default: - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9075 BLKGRD: Bad op/guard:%d/CRC combination\n", scsi_get_prot_op(sc)); ret = 1; @@ -1457,8 +1440,8 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, * 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 - * @txopt: (out) BlockGuard operation for transmitted data - * @rxopt: (out) BlockGuard operation for received data + * @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 * @@ -1467,9 +1450,8 @@ static int lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint8_t *txop, uint8_t *rxop) { - uint8_t ret = 0; - if (lpfc_cmd_guard_csum(sc)) { + if (sc->prot_flags & SCSI_PROT_IP_CHECKSUM) { switch (scsi_get_prot_op(sc)) { case SCSI_PROT_READ_INSERT: case SCSI_PROT_WRITE_STRIP: @@ -1520,7 +1502,7 @@ lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, } } - return ret; + return 0; } #endif @@ -1529,7 +1511,7 @@ lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, * @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 + * @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 @@ -1577,7 +1559,9 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, goto out; /* extract some info from the scsi command for pde*/ - reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ + reftag = scsi_prot_ref_tag(sc); + if (reftag == LPFC_INVALID_REFTAG) + goto out; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); @@ -1614,12 +1598,12 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, * protection data is automatically generated, not checked. */ if (datadir == DMA_FROM_DEVICE) { - if (lpfc_cmd_protect(sc, LPFC_CHECK_PROTECT_GUARD)) + if (sc->prot_flags & SCSI_PROT_GUARD_CHECK) bf_set(pde6_ce, pde6, checking); else bf_set(pde6_ce, pde6, 0); - if (lpfc_cmd_protect(sc, LPFC_CHECK_PROTECT_REF)) + if (sc->prot_flags & SCSI_PROT_REF_CHECK) bf_set(pde6_re, pde6, checking); else bf_set(pde6_re, pde6, 0); @@ -1726,7 +1710,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgde = scsi_sglist(sc); if (!sgpe || !sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9020 Invalid s/g entry: data=x%px prot=x%px\n", sgpe, sgde); return 0; @@ -1737,8 +1721,10 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, goto out; /* extract some info from the scsi command */ - blksize = lpfc_cmd_blksize(sc); - reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ + blksize = scsi_prot_interval(sc); + reftag = scsi_prot_ref_tag(sc); + if (reftag == LPFC_INVALID_REFTAG) + goto out; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); @@ -1776,12 +1762,12 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(pde6_optx, pde6, txop); bf_set(pde6_oprx, pde6, rxop); - if (lpfc_cmd_protect(sc, LPFC_CHECK_PROTECT_GUARD)) + if (sc->prot_flags & SCSI_PROT_GUARD_CHECK) bf_set(pde6_ce, pde6, checking); else bf_set(pde6_ce, pde6, 0); - if (lpfc_cmd_protect(sc, LPFC_CHECK_PROTECT_REF)) + if (sc->prot_flags & SCSI_PROT_REF_CHECK) bf_set(pde6_re, pde6, checking); else bf_set(pde6_re, pde6, 0); @@ -1838,7 +1824,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, return num_bde + 1; if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9065 BLKGRD:%s Invalid data segment\n", __func__); return 0; @@ -1901,8 +1887,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, reftag += protgrp_blks; } else { /* if we're here, we have a bug */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9054 BLKGRD: bug in %s\n", __func__); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "9054 BLKGRD: bug in %s\n", __func__); } } while (!alldone); @@ -1916,7 +1902,8 @@ out: * @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 + * @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 @@ -1966,7 +1953,9 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, goto out; /* extract some info from the scsi command for pde*/ - reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ + reftag = scsi_prot_ref_tag(sc); + if (reftag == LPFC_INVALID_REFTAG) + goto out; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); @@ -1992,12 +1981,12 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, * protection data is automatically generated, not checked. */ if (sc->sc_data_direction == DMA_FROM_DEVICE) { - if (lpfc_cmd_protect(sc, LPFC_CHECK_PROTECT_GUARD)) + if (sc->prot_flags & SCSI_PROT_GUARD_CHECK) bf_set(lpfc_sli4_sge_dif_ce, diseed, checking); else bf_set(lpfc_sli4_sge_dif_ce, diseed, 0); - if (lpfc_cmd_protect(sc, LPFC_CHECK_PROTECT_REF)) + if (sc->prot_flags & SCSI_PROT_REF_CHECK) bf_set(lpfc_sli4_sge_dif_re, diseed, checking); else bf_set(lpfc_sli4_sge_dif_re, diseed, 0); @@ -2090,6 +2079,7 @@ out: * @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 @@ -2152,7 +2142,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgde = scsi_sglist(sc); if (!sgpe || !sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9082 Invalid s/g entry: data=x%px prot=x%px\n", sgpe, sgde); return 0; @@ -2163,8 +2153,10 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, goto out; /* extract some info from the scsi command */ - blksize = lpfc_cmd_blksize(sc); - reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ + blksize = scsi_prot_interval(sc); + reftag = scsi_prot_ref_tag(sc); + if (reftag == LPFC_INVALID_REFTAG) + goto out; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); @@ -2219,9 +2211,8 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, diseed->ref_tag = cpu_to_le32(reftag); diseed->ref_tag_tran = diseed->ref_tag; - if (lpfc_cmd_protect(sc, LPFC_CHECK_PROTECT_GUARD)) { + if (sc->prot_flags & SCSI_PROT_GUARD_CHECK) { bf_set(lpfc_sli4_sge_dif_ce, diseed, checking); - } else { bf_set(lpfc_sli4_sge_dif_ce, diseed, 0); /* @@ -2238,7 +2229,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, } - if (lpfc_cmd_protect(sc, LPFC_CHECK_PROTECT_REF)) + if (sc->prot_flags & SCSI_PROT_REF_CHECK) bf_set(lpfc_sli4_sge_dif_re, diseed, checking); else bf_set(lpfc_sli4_sge_dif_re, diseed, 0); @@ -2305,7 +2296,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, return num_sge + 1; if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9086 BLKGRD:%s Invalid data segment\n", __func__); return 0; @@ -2410,8 +2401,8 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, reftag += protgrp_blks; } else { /* if we're here, we have a bug */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9085 BLKGRD: bug in %s\n", __func__); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "9085 BLKGRD: bug in %s\n", __func__); } } while (!alldone); @@ -2451,7 +2442,7 @@ lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc) break; default: if (phba) - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9021 Unsupported protection op:%d\n", op); break; @@ -2495,7 +2486,7 @@ lpfc_bg_scsi_adjust_dl(struct lpfc_hba *phba, * DIF (trailer) attached to it. Must ajust FCP data length * to account for the protection data. */ - fcpdl += (fcpdl / lpfc_cmd_blksize(sc)) * 8; + fcpdl += (fcpdl / scsi_prot_interval(sc)) * 8; return fcpdl; } @@ -2534,7 +2525,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, bpl += 2; if (scsi_sg_count(scsi_cmnd)) { /* - * The driver stores the segment count returned from pci_map_sg + * The driver stores the segment count returned from dma_map_sg * because this a count of dma-mappings used to map the use_sg * pages. They are not guaranteed to be the same for those * architectures that implement an IOMMU. @@ -2615,7 +2606,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, scsi_dma_unmap(scsi_cmnd); lpfc_cmd->seg_cnt = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9022 Unexpected protection group %i\n", prot_group_type); return 2; @@ -2659,7 +2650,7 @@ err: scsi_prot_sg_count(scsi_cmnd), scsi_cmnd->sc_data_direction); - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9023 Cannot setup S/G List for HBA" "IO segs %d/%d BPL %d SCSI %d: %d %d\n", lpfc_cmd->seg_cnt, lpfc_cmd->prot_seg_cnt, @@ -2749,14 +2740,16 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * data length is a multiple of the blksize. */ sgde = scsi_sglist(cmd); - blksize = lpfc_cmd_blksize(cmd); + blksize = scsi_prot_interval(cmd); data_src = (uint8_t *)sg_virt(sgde); data_len = sgde->length; if ((data_len & (blksize - 1)) == 0) chk_guard = 1; src = (struct scsi_dif_tuple *)sg_virt(sgpe); - start_ref_tag = (uint32_t)scsi_get_lba(cmd); /* Truncate LBA */ + start_ref_tag = scsi_prot_ref_tag(cmd); + if (start_ref_tag == LPFC_INVALID_REFTAG) + goto out; start_app_tag = src->app_tag; len = sgpe->length; while (src && protsegcnt) { @@ -2775,7 +2768,8 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) /* First Guard Tag checking */ if (chk_guard) { guard_tag = src->guard_tag; - if (lpfc_cmd_guard_csum(cmd)) + if (cmd->prot_flags + & SCSI_PROT_IP_CHECKSUM) sum = lpfc_bg_csum(data_src, blksize); else @@ -2841,43 +2835,36 @@ skipit: } out: if (err_type == BGS_GUARD_ERR_MASK) { - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x1); - cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 | - SAM_STAT_CHECK_CONDITION; + scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x1); + set_host_byte(cmd, DID_ABORT); phba->bg_guard_err_cnt++; lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, - "9069 BLKGRD: LBA %lx grd_tag error %x != %x\n", - (unsigned long)scsi_get_lba(cmd), + "9069 BLKGRD: reftag %x grd_tag err %x != %x\n", + scsi_prot_ref_tag(cmd), sum, guard_tag); } else if (err_type == BGS_REFTAG_ERR_MASK) { - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x3); - cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 | - SAM_STAT_CHECK_CONDITION; + scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x3); + set_host_byte(cmd, DID_ABORT); phba->bg_reftag_err_cnt++; lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, - "9066 BLKGRD: LBA %lx ref_tag error %x != %x\n", - (unsigned long)scsi_get_lba(cmd), + "9066 BLKGRD: reftag %x ref_tag err %x != %x\n", + scsi_prot_ref_tag(cmd), ref_tag, start_ref_tag); } else if (err_type == BGS_APPTAG_ERR_MASK) { - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x2); - cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 | - SAM_STAT_CHECK_CONDITION; + scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x2); + set_host_byte(cmd, DID_ABORT); phba->bg_apptag_err_cnt++; lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, - "9041 BLKGRD: LBA %lx app_tag error %x != %x\n", - (unsigned long)scsi_get_lba(cmd), + "9041 BLKGRD: reftag %x app_tag err %x != %x\n", + scsi_prot_ref_tag(cmd), app_tag, start_app_tag); } } - /* * This function checks for BlockGuard errors detected by * the HBA. In case of errors, the ASC/ASCQ fields in the @@ -2895,20 +2882,63 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd, struct lpfc_iocbq *pIocbOut) { struct scsi_cmnd *cmd = lpfc_cmd->pCmd; - struct sli3_bg_fields *bgf = &pIocbOut->iocb.unsli3.sli3_bg; + struct sli3_bg_fields *bgf; int ret = 0; - uint32_t bghm = bgf->bghm; - uint32_t bgstat = bgf->bgstat; - uint64_t failing_sector = 0; + struct lpfc_wcqe_complete *wcqe; + u32 status; + u32 bghm = 0; + u32 bgstat = 0; + u64 failing_sector = 0; + + if (phba->sli_rev == LPFC_SLI_REV4) { + wcqe = &pIocbOut->wcqe_cmpl; + status = bf_get(lpfc_wcqe_c_status, wcqe); + + if (status == CQE_STATUS_DI_ERROR) { + /* Guard Check failed */ + if (bf_get(lpfc_wcqe_c_bg_ge, wcqe)) + bgstat |= BGS_GUARD_ERR_MASK; + + /* AppTag Check failed */ + if (bf_get(lpfc_wcqe_c_bg_ae, wcqe)) + bgstat |= BGS_APPTAG_ERR_MASK; + + /* RefTag Check failed */ + if (bf_get(lpfc_wcqe_c_bg_re, wcqe)) + bgstat |= BGS_REFTAG_ERR_MASK; + + /* Check to see if there was any good data before the + * error + */ + if (bf_get(lpfc_wcqe_c_bg_tdpv, wcqe)) { + bgstat |= BGS_HI_WATER_MARK_PRESENT_MASK; + bghm = wcqe->total_data_placed; + } + + /* + * Set ALL the error bits to indicate we don't know what + * type of error it is. + */ + if (!bgstat) + bgstat |= (BGS_REFTAG_ERR_MASK | + BGS_APPTAG_ERR_MASK | + BGS_GUARD_ERR_MASK); + } + + } else { + bgf = &pIocbOut->iocb.unsli3.sli3_bg; + bghm = bgf->bghm; + bgstat = bgf->bgstat; + } if (lpfc_bgs_get_invalid_prof(bgstat)) { cmd->result = DID_ERROR << 16; lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, - "9072 BLKGRD: Invalid BG Profile in cmd" - " 0x%x lba 0x%llx blk cnt 0x%x " + "9072 BLKGRD: Invalid BG Profile in cmd " + "0x%x reftag 0x%x blk cnt 0x%x " "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], - (unsigned long long)scsi_get_lba(cmd), - blk_rq_sectors(cmd->request), bgstat, bghm); + scsi_prot_ref_tag(cmd), + scsi_logical_block_count(cmd), bgstat, bghm); ret = (-1); goto out; } @@ -2916,63 +2946,52 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd, if (lpfc_bgs_get_uninit_dif_block(bgstat)) { cmd->result = DID_ERROR << 16; lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, - "9073 BLKGRD: Invalid BG PDIF Block in cmd" - " 0x%x lba 0x%llx blk cnt 0x%x " + "9073 BLKGRD: Invalid BG PDIF Block in cmd " + "0x%x reftag 0x%x blk cnt 0x%x " "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], - (unsigned long long)scsi_get_lba(cmd), - blk_rq_sectors(cmd->request), bgstat, bghm); + scsi_prot_ref_tag(cmd), + scsi_logical_block_count(cmd), bgstat, bghm); ret = (-1); goto out; } if (lpfc_bgs_get_guard_err(bgstat)) { ret = 1; - - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x1); - cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 | - SAM_STAT_CHECK_CONDITION; + scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x1); + set_host_byte(cmd, DID_ABORT); phba->bg_guard_err_cnt++; lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, - "9055 BLKGRD: Guard Tag error in cmd" - " 0x%x lba 0x%llx blk cnt 0x%x " + "9055 BLKGRD: Guard Tag error in cmd " + "0x%x reftag 0x%x blk cnt 0x%x " "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], - (unsigned long long)scsi_get_lba(cmd), - blk_rq_sectors(cmd->request), bgstat, bghm); + scsi_prot_ref_tag(cmd), + scsi_logical_block_count(cmd), bgstat, bghm); } if (lpfc_bgs_get_reftag_err(bgstat)) { ret = 1; - - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x3); - cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 | - SAM_STAT_CHECK_CONDITION; - + scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x3); + set_host_byte(cmd, DID_ABORT); phba->bg_reftag_err_cnt++; lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, - "9056 BLKGRD: Ref Tag error in cmd" - " 0x%x lba 0x%llx blk cnt 0x%x " + "9056 BLKGRD: Ref Tag error in cmd " + "0x%x reftag 0x%x blk cnt 0x%x " "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], - (unsigned long long)scsi_get_lba(cmd), - blk_rq_sectors(cmd->request), bgstat, bghm); + scsi_prot_ref_tag(cmd), + scsi_logical_block_count(cmd), bgstat, bghm); } if (lpfc_bgs_get_apptag_err(bgstat)) { ret = 1; - - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x2); - cmd->result = DRIVER_SENSE << 24 | DID_ABORT << 16 | - SAM_STAT_CHECK_CONDITION; - + scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x2); + set_host_byte(cmd, DID_ABORT); phba->bg_apptag_err_cnt++; lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, - "9061 BLKGRD: App Tag error in cmd" - " 0x%x lba 0x%llx blk cnt 0x%x " + "9061 BLKGRD: App Tag error in cmd " + "0x%x reftag 0x%x blk cnt 0x%x " "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], - (unsigned long long)scsi_get_lba(cmd), - blk_rq_sectors(cmd->request), bgstat, bghm); + scsi_prot_ref_tag(cmd), + scsi_logical_block_count(cmd), bgstat, bghm); } if (lpfc_bgs_get_hi_water_mark_present(bgstat)) { @@ -3012,13 +3031,13 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd, if (!ret) { /* No error was reported - problem in FW? */ lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, - "9057 BLKGRD: Unknown error in cmd" - " 0x%x lba 0x%llx blk cnt 0x%x " + "9057 BLKGRD: Unknown error in cmd " + "0x%x reftag 0x%x blk cnt 0x%x " "bgstat=x%x bghm=x%x\n", cmd->cmnd[0], - (unsigned long long)scsi_get_lba(cmd), - blk_rq_sectors(cmd->request), bgstat, bghm); + scsi_prot_ref_tag(cmd), + scsi_logical_block_count(cmd), bgstat, bghm); - /* Calcuate what type of error it was */ + /* Calculate what type of error it was */ lpfc_calc_bg_err(phba, lpfc_cmd); } out: @@ -3046,9 +3065,10 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; struct sli4_sge *first_data_sgl; - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + struct lpfc_iocbq *pwqeq = &lpfc_cmd->cur_iocbq; + struct lpfc_vport *vport = phba->pport; + union lpfc_wqe128 *wqe = &pwqeq->wqe; dma_addr_t physaddr; - uint32_t num_bde = 0; uint32_t dma_len; uint32_t dma_offset = 0; int nseg, i, j; @@ -3064,7 +3084,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) */ if (scsi_sg_count(scsi_cmnd)) { /* - * The driver stores the segment count returned from pci_map_sg + * The driver stores the segment count returned from dma_map_sg * because this a count of dma-mappings used to map the use_sg * pages. They are not guaranteed to be the same for those * architectures that implement an IOMMU. @@ -3083,11 +3103,12 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) lpfc_cmd->seg_cnt = nseg; if (!phba->cfg_xpsgl && lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9074 BLKGRD:" - " %s: Too many sg segments from " - "dma_map_sg. Config %d, seg_cnt %d\n", - __func__, phba->cfg_sg_seg_cnt, - lpfc_cmd->seg_cnt); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "9074 BLKGRD:" + " %s: Too many sg segments from " + "dma_map_sg. Config %d, seg_cnt %d\n", + __func__, phba->cfg_sg_seg_cnt, + lpfc_cmd->seg_cnt); WARN_ON_ONCE(lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt); lpfc_cmd->seg_cnt = 0; scsi_dma_unmap(scsi_cmnd); @@ -3109,7 +3130,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) j = 2; for (i = 0; i < nseg; i++) { sgl->word2 = 0; - if ((num_bde + 1) == nseg) { + if (nseg == 1) { bf_set(lpfc_sli4_sge_last, sgl, 1); bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); @@ -3178,25 +3199,33 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) j++; } - /* - * Setup the first Payload BDE. For FCoE we just key off - * Performance Hints, for FC we use lpfc_enable_pbde. - * We populate words 13-15 of IOCB/WQE. + + /* PBDE support for first data SGE only. + * For FCoE, we key off Performance Hints. + * For FC, we key off lpfc_enable_pbde. */ - if ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || - phba->cfg_enable_pbde) { + if (nseg == 1 && + ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || + phba->cfg_enable_pbde)) { + /* Words 13-15 */ bde = (struct ulp_bde64 *) - &(iocb_cmd->unsli3.sli3Words[5]); + &wqe->words[13]; bde->addrLow = first_data_sgl->addr_lo; bde->addrHigh = first_data_sgl->addr_hi; bde->tus.f.bdeSize = le32_to_cpu(first_data_sgl->sge_len); bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; bde->tus.w = cpu_to_le32(bde->tus.w); + + /* Word 11 - set PBDE bit */ + bf_set(wqe_pbde, &wqe->generic.wqe_com, 1); + } else { + memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); + /* Word 11 - PBDE bit disabled by default template */ } } else { sgl += 1; - /* clear the last flag in the fcp_rsp map entry */ + /* set the last flag in the fcp_rsp map entry */ sgl->word2 = le32_to_cpu(sgl->word2); bf_set(lpfc_sli4_sge_last, sgl, 1); sgl->word2 = cpu_to_le32(sgl->word2); @@ -3204,7 +3233,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) if ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || phba->cfg_enable_pbde) { bde = (struct ulp_bde64 *) - &(iocb_cmd->unsli3.sli3Words[5]); + &wqe->words[13]; memset(bde, 0, (sizeof(uint32_t) * 3)); } } @@ -3216,12 +3245,23 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * all iocb memory resources are reused. */ fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd)); - - /* - * Due to difference in data length between DIF/non-DIF paths, - * we need to set word 4 of IOCB here - */ - iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); + /* Set first-burst provided it was successfully negotiated */ + if (!(phba->hba_flag & HBA_FCOE_MODE) && + vport->cfg_first_burst_size && + scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) { + u32 init_len, total_len; + + total_len = be32_to_cpu(fcp_cmnd->fcpDl); + init_len = min(total_len, vport->cfg_first_burst_size); + + /* Word 4 & 5 */ + wqe->fcp_iwrite.initial_xfer_len = init_len; + wqe->fcp_iwrite.total_xfer_len = total_len; + } else { + /* Word 4 */ + wqe->fcp_iwrite.total_xfer_len = + be32_to_cpu(fcp_cmnd->fcpDl); + } /* * If the OAS driver feature is enabled and the lun is enabled for @@ -3229,9 +3269,20 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) */ if ((phba->cfg_fof) && ((struct lpfc_device_data *) scsi_cmnd->device->hostdata)->oas_enabled) { - lpfc_cmd->cur_iocbq.iocb_flag |= (LPFC_IO_OAS | LPFC_IO_FOF); + lpfc_cmd->cur_iocbq.cmd_flag |= (LPFC_IO_OAS | LPFC_IO_FOF); lpfc_cmd->cur_iocbq.priority = ((struct lpfc_device_data *) scsi_cmnd->device->hostdata)->priority; + + /* Word 10 */ + bf_set(wqe_oas, &wqe->generic.wqe_com, 1); + bf_set(wqe_ccpe, &wqe->generic.wqe_com, 1); + + if (lpfc_cmd->cur_iocbq.priority) + bf_set(wqe_ccp, &wqe->generic.wqe_com, + (lpfc_cmd->cur_iocbq.priority << 1)); + else + bf_set(wqe_ccp, &wqe->generic.wqe_com, + (phba->cfg_XLanePriority << 1)); } return 0; @@ -3257,7 +3308,8 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; struct sli4_sge *sgl = (struct sli4_sge *)(lpfc_cmd->dma_sgl); - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + struct lpfc_iocbq *pwqeq = &lpfc_cmd->cur_iocbq; + union lpfc_wqe128 *wqe = &pwqeq->wqe; uint32_t num_sge = 0; int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction; int prot_group_type = 0; @@ -3271,7 +3323,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, */ if (scsi_sg_count(scsi_cmnd)) { /* - * The driver stores the segment count returned from pci_map_sg + * The driver stores the segment count returned from dma_map_sg * because this a count of dma-mappings used to map the use_sg * pages. They are not guaranteed to be the same for those * architectures that implement an IOMMU. @@ -3364,7 +3416,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, scsi_dma_unmap(scsi_cmnd); lpfc_cmd->seg_cnt = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9083 Unexpected protection group %i\n", prot_group_type); return 2; @@ -3374,42 +3426,64 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, switch (scsi_get_prot_op(scsi_cmnd)) { case SCSI_PROT_WRITE_STRIP: case SCSI_PROT_READ_STRIP: - lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_DIF_STRIP; + lpfc_cmd->cur_iocbq.cmd_flag |= LPFC_IO_DIF_STRIP; break; case SCSI_PROT_WRITE_INSERT: case SCSI_PROT_READ_INSERT: - lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_DIF_INSERT; + lpfc_cmd->cur_iocbq.cmd_flag |= LPFC_IO_DIF_INSERT; break; case SCSI_PROT_WRITE_PASS: case SCSI_PROT_READ_PASS: - lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_DIF_PASS; + lpfc_cmd->cur_iocbq.cmd_flag |= LPFC_IO_DIF_PASS; break; } fcpdl = lpfc_bg_scsi_adjust_dl(phba, lpfc_cmd); fcp_cmnd->fcpDl = be32_to_cpu(fcpdl); - /* - * Due to difference in data length between DIF/non-DIF paths, - * we need to set word 4 of IOCB here - */ - iocb_cmd->un.fcpi.fcpi_parm = fcpdl; + /* Set first-burst provided it was successfully negotiated */ + if (!(phba->hba_flag & HBA_FCOE_MODE) && + vport->cfg_first_burst_size && + scsi_cmnd->sc_data_direction == DMA_TO_DEVICE) { + u32 init_len, total_len; - /* - * For First burst, we may need to adjust the initial transfer - * length for DIF - */ - if (iocb_cmd->un.fcpi.fcpi_XRdy && - (fcpdl < vport->cfg_first_burst_size)) - iocb_cmd->un.fcpi.fcpi_XRdy = fcpdl; + total_len = be32_to_cpu(fcp_cmnd->fcpDl); + init_len = min(total_len, vport->cfg_first_burst_size); + + /* Word 4 & 5 */ + wqe->fcp_iwrite.initial_xfer_len = init_len; + wqe->fcp_iwrite.total_xfer_len = total_len; + } else { + /* Word 4 */ + wqe->fcp_iwrite.total_xfer_len = + be32_to_cpu(fcp_cmnd->fcpDl); + } /* * If the OAS driver feature is enabled and the lun is enabled for * OAS, set the oas iocb related flags. */ if ((phba->cfg_fof) && ((struct lpfc_device_data *) - scsi_cmnd->device->hostdata)->oas_enabled) - lpfc_cmd->cur_iocbq.iocb_flag |= (LPFC_IO_OAS | LPFC_IO_FOF); + scsi_cmnd->device->hostdata)->oas_enabled) { + lpfc_cmd->cur_iocbq.cmd_flag |= (LPFC_IO_OAS | LPFC_IO_FOF); + + /* Word 10 */ + bf_set(wqe_oas, &wqe->generic.wqe_com, 1); + bf_set(wqe_ccpe, &wqe->generic.wqe_com, 1); + bf_set(wqe_ccp, &wqe->generic.wqe_com, + (phba->cfg_XLanePriority << 1)); + } + + /* Word 7. DIF Flags */ + if (lpfc_cmd->cur_iocbq.cmd_flag & LPFC_IO_DIF_PASS) + bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_PASSTHRU); + else if (lpfc_cmd->cur_iocbq.cmd_flag & LPFC_IO_DIF_STRIP) + bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_STRIP); + else if (lpfc_cmd->cur_iocbq.cmd_flag & LPFC_IO_DIF_INSERT) + bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_INSERT); + + lpfc_cmd->cur_iocbq.cmd_flag &= ~(LPFC_IO_DIF_PASS | + LPFC_IO_DIF_STRIP | LPFC_IO_DIF_INSERT); return 0; err: @@ -3420,7 +3494,7 @@ err: scsi_prot_sg_count(scsi_cmnd), scsi_cmnd->sc_data_direction); - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9084 Cannot setup S/G List for HBA" "IO segs %d/%d SGL %d SCSI %d: %d %d\n", lpfc_cmd->seg_cnt, lpfc_cmd->prot_seg_cnt, @@ -3470,28 +3544,47 @@ 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) +{ + return vport->phba->lpfc_scsi_prep_cmnd_buf(vport, lpfc_cmd, 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. - * @rsp_iocb: Pointer to response iocb object which reported 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, struct lpfc_iocbq *rsp_iocb) { + struct lpfc_io_buf *lpfc_cmd, uint32_t fcpi_parm) { struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; uint32_t resp_info = fcprsp->rspStatus2; uint32_t scsi_status = fcprsp->rspStatus3; - uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; struct lpfc_fast_path_event *fast_path_evt = NULL; struct lpfc_nodelist *pnode = lpfc_cmd->rdata->pnode; unsigned long flags; - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) + if (!pnode) return; /* If there is queuefull or busy condition send a scsi event */ @@ -3590,10 +3683,148 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_io_buf *psb) } /** - * lpfc_handler_fcp_err - FCP response handler + * 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) +{ + struct lpfc_vport **vports; + struct Scsi_Host *shost; + int i; + + if (phba->sli_rev == LPFC_SLI_REV4 && + !phba->sli4_hba.max_cfg_param.vpi_used) { + shost = lpfc_shost_from_vport(phba->pport); + scsi_unblock_requests(shost); + return; + } + + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + shost = lpfc_shost_from_vport(vports[i]); + scsi_unblock_requests(shost); + } + lpfc_destroy_vport_work_array(phba, vports); +} + +/** + * 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) +{ + struct lpfc_vport **vports; + struct Scsi_Host *shost; + int i; + + if (atomic_read(&phba->cmf_stop_io)) + return; + + if (phba->sli_rev == LPFC_SLI_REV4 && + !phba->sli4_hba.max_cfg_param.vpi_used) { + shost = lpfc_shost_from_vport(phba->pport); + scsi_block_requests(shost); + return; + } + + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + shost = lpfc_shost_from_vport(vports[i]); + scsi_block_requests(shost); + } + lpfc_destroy_vport_work_array(phba, vports); +} + +/** + * 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) +{ + struct lpfc_cgn_stat *cgs; + + if (time != LPFC_CGN_NOT_SENT) { + /* lat is ns coming in, save latency in us */ + if (time < 1000) + time = 1; + else + time = div_u64(time + 500, 1000); /* round it */ + + cgs = per_cpu_ptr(phba->cmf_stat, raw_smp_processor_id()); + atomic64_add(size, &cgs->rcv_bytes); + atomic64_add(time, &cgs->rx_latency); + atomic_inc(&cgs->rx_io_cnt); + } + return 0; +} + +/** + * 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) +{ + uint64_t total; + struct lpfc_cgn_stat *cgs; + int cpu; + + /* At this point we are either LPFC_CFG_MANAGED or LPFC_CFG_MONITOR */ + if (phba->cmf_active_mode == LPFC_CFG_MANAGED && + phba->cmf_max_bytes_per_interval) { + total = 0; + for_each_present_cpu(cpu) { + cgs = per_cpu_ptr(phba->cmf_stat, cpu); + total += atomic64_read(&cgs->total_bytes); + } + if (total >= phba->cmf_max_bytes_per_interval) { + if (!atomic_xchg(&phba->cmf_bw_wait, 1)) { + lpfc_block_requests(phba); + phba->cmf_last_ts = + lpfc_calc_cmf_latency(phba); + } + atomic_inc(&phba->cmf_busy); + return -EBUSY; + } + if (size > atomic_read(&phba->rx_max_read_cnt)) + atomic_set(&phba->rx_max_read_cnt, size); + } + + cgs = per_cpu_ptr(phba->cmf_stat, raw_smp_processor_id()); + atomic64_add(size, &cgs->total_bytes); + return 0; +} + +/** + * 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. - * @rsp_iocb: The response IOCB which contains FCP error. + * @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 @@ -3601,13 +3832,11 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_io_buf *psb) **/ static void lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, - struct lpfc_iocbq *rsp_iocb) + uint32_t fcpi_parm) { - struct lpfc_hba *phba = vport->phba; struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd; struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; - uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; uint32_t resp_info = fcprsp->rspStatus2; uint32_t scsi_status = fcprsp->rspStatus3; uint32_t *lp; @@ -3630,17 +3859,17 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, if (resp_info & RSP_LEN_VALID) { rsplen = be32_to_cpu(fcprsp->rspRspLen); if (rsplen != 0 && rsplen != 4 && rsplen != 8) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "2719 Invalid response length: " - "tgt x%x lun x%llx cmnd x%x rsplen x%x\n", - cmnd->device->id, - cmnd->device->lun, cmnd->cmnd[0], - rsplen); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "2719 Invalid response length: " + "tgt x%x lun x%llx cmnd x%x rsplen " + "x%x\n", cmnd->device->id, + cmnd->device->lun, cmnd->cmnd[0], + rsplen); host_status = DID_ERROR; goto out; } if (fcprsp->rspInfo3 != RSP_NO_FAILURE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2757 Protocol failure detected during " "processing of FCP I/O op: " "tgt x%x lun x%llx cmnd x%x rspInfo3 x%x\n", @@ -3742,13 +3971,10 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, */ } else if (fcpi_parm) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, - "9029 FCP %s Check Error xri x%x Data: " + "9029 FCP %s Check Error Data: " "x%x x%x x%x x%x x%x\n", ((cmnd->sc_data_direction == DMA_FROM_DEVICE) ? "Read" : "Write"), - ((phba->sli_rev == LPFC_SLI_REV4) ? - lpfc_cmd->cur_iocbq.sli4_xritag : - rsp_iocb->iocb.ulpContext), fcpDl, be32_to_cpu(fcprsp->rspResId), fcpi_parm, cmnd->cmnd[0], scsi_status); @@ -3775,7 +4001,342 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, out: cmnd->result = host_status << 16 | scsi_status; - lpfc_send_scsi_error_event(vport->phba, vport, lpfc_cmd, rsp_iocb); + lpfc_send_scsi_error_event(vport->phba, vport, lpfc_cmd, 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) +{ + struct lpfc_io_buf *lpfc_cmd = pwqeIn->io_buf; + struct lpfc_wcqe_complete *wcqe = &pwqeOut->wcqe_cmpl; + struct lpfc_vport *vport = pwqeIn->vport; + struct lpfc_rport_data *rdata; + struct lpfc_nodelist *ndlp; + struct scsi_cmnd *cmd; + unsigned long flags; + struct lpfc_fast_path_event *fast_path_evt; + struct Scsi_Host *shost; + u32 logit = LOG_FCP; + u32 status, idx; + u32 lat; + u8 wait_xb_clr = 0; + + /* Sanity check on return of outstanding command */ + if (!lpfc_cmd) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "9032 Null lpfc_cmd pointer. No " + "release, skip completion\n"); + return; + } + + rdata = lpfc_cmd->rdata; + ndlp = rdata->pnode; + + /* Sanity check on return of outstanding command */ + cmd = lpfc_cmd->pCmd; + if (!cmd) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "9042 I/O completion: Not an active IO\n"); + lpfc_release_scsi_buf(phba, lpfc_cmd); + return; + } + /* Guard against abort handler being called at same time */ + spin_lock(&lpfc_cmd->buf_lock); + idx = lpfc_cmd->cur_iocbq.hba_wqidx; + if (phba->sli4_hba.hdwq) + phba->sli4_hba.hdwq[idx].scsi_cstat.io_cmpls++; + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO)) + this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io); +#endif + shost = cmd->device->host; + + status = bf_get(lpfc_wcqe_c_status, wcqe); + lpfc_cmd->status = (status & LPFC_IOCB_STATUS_MASK); + lpfc_cmd->result = (wcqe->parameter & IOERR_PARAM_MASK); + + lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY; + if (bf_get(lpfc_wcqe_c_xb, wcqe)) { + lpfc_cmd->flags |= LPFC_SBUF_XBUSY; + if (phba->cfg_fcp_wait_abts_rsp) + wait_xb_clr = 1; + } + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (lpfc_cmd->prot_data_type) { + struct scsi_dif_tuple *src = NULL; + + src = (struct scsi_dif_tuple *)lpfc_cmd->prot_data_segment; + /* + * Used to restore any changes to protection + * data for error injection. + */ + switch (lpfc_cmd->prot_data_type) { + case LPFC_INJERR_REFTAG: + src->ref_tag = + lpfc_cmd->prot_data; + break; + case LPFC_INJERR_APPTAG: + src->app_tag = + (uint16_t)lpfc_cmd->prot_data; + break; + case LPFC_INJERR_GUARD: + src->guard_tag = + (uint16_t)lpfc_cmd->prot_data; + break; + default: + break; + } + + lpfc_cmd->prot_data = 0; + lpfc_cmd->prot_data_type = 0; + lpfc_cmd->prot_data_segment = NULL; + } +#endif + if (unlikely(lpfc_cmd->status)) { + if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && + (lpfc_cmd->result & IOERR_DRVR_MASK)) + lpfc_cmd->status = IOSTAT_DRIVER_REJECT; + else if (lpfc_cmd->status >= IOSTAT_CNT) + lpfc_cmd->status = IOSTAT_DEFAULT; + if (lpfc_cmd->status == IOSTAT_FCP_RSP_ERROR && + !lpfc_cmd->fcp_rsp->rspStatus3 && + (lpfc_cmd->fcp_rsp->rspStatus2 & RESID_UNDER) && + !(vport->cfg_log_verbose & LOG_FCP_UNDER)) + logit = 0; + else + logit = LOG_FCP | LOG_FCP_UNDER; + lpfc_printf_vlog(vport, KERN_WARNING, logit, + "9034 FCP cmd x%x failed <%d/%lld> " + "status: x%x result: x%x " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x x%x\n", + cmd->cmnd[0], + cmd->device ? cmd->device->id : 0xffff, + cmd->device ? cmd->device->lun : 0xffff, + lpfc_cmd->status, lpfc_cmd->result, + vport->fc_myDID, + (ndlp) ? ndlp->nlp_DID : 0, + lpfc_cmd->cur_iocbq.sli4_xritag, + wcqe->parameter, wcqe->total_data_placed, + lpfc_cmd->cur_iocbq.iotag); + } + + switch (lpfc_cmd->status) { + case IOSTAT_SUCCESS: + cmd->result = DID_OK << 16; + break; + case IOSTAT_FCP_RSP_ERROR: + lpfc_handle_fcp_err(vport, lpfc_cmd, + pwqeIn->wqe.fcp_iread.total_xfer_len - + wcqe->total_data_placed); + break; + case IOSTAT_NPORT_BSY: + case IOSTAT_FABRIC_BSY: + cmd->result = DID_TRANSPORT_DISRUPTED << 16; + fast_path_evt = lpfc_alloc_fast_evt(phba); + if (!fast_path_evt) + break; + fast_path_evt->un.fabric_evt.event_type = + FC_REG_FABRIC_EVENT; + fast_path_evt->un.fabric_evt.subcategory = + (lpfc_cmd->status == IOSTAT_NPORT_BSY) ? + LPFC_EVENT_PORT_BUSY : LPFC_EVENT_FABRIC_BUSY; + if (ndlp) { + memcpy(&fast_path_evt->un.fabric_evt.wwpn, + &ndlp->nlp_portname, + sizeof(struct lpfc_name)); + memcpy(&fast_path_evt->un.fabric_evt.wwnn, + &ndlp->nlp_nodename, + sizeof(struct lpfc_name)); + } + fast_path_evt->vport = vport; + fast_path_evt->work_evt.evt = + LPFC_EVT_FASTPATH_MGMT_EVT; + spin_lock_irqsave(&phba->hbalock, flags); + list_add_tail(&fast_path_evt->work_evt.evt_listp, + &phba->work_list); + spin_unlock_irqrestore(&phba->hbalock, flags); + lpfc_worker_wake_up(phba); + lpfc_printf_vlog(vport, KERN_WARNING, logit, + "9035 Fabric/Node busy FCP cmd x%x failed" + " <%d/%lld> " + "status: x%x result: x%x " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x x%x\n", + cmd->cmnd[0], + cmd->device ? cmd->device->id : 0xffff, + cmd->device ? cmd->device->lun : 0xffff, + lpfc_cmd->status, lpfc_cmd->result, + vport->fc_myDID, + (ndlp) ? ndlp->nlp_DID : 0, + lpfc_cmd->cur_iocbq.sli4_xritag, + wcqe->parameter, + wcqe->total_data_placed, + lpfc_cmd->cur_iocbq.iocb.ulpIoTag); + break; + case IOSTAT_REMOTE_STOP: + if (ndlp) { + /* This I/O was aborted by the target, we don't + * know the rxid and because we did not send the + * ABTS we cannot generate and RRQ. + */ + lpfc_set_rrq_active(phba, ndlp, + lpfc_cmd->cur_iocbq.sli4_lxritag, + 0, 0); + } + fallthrough; + case IOSTAT_LOCAL_REJECT: + if (lpfc_cmd->result & IOERR_DRVR_MASK) + lpfc_cmd->status = IOSTAT_DRIVER_REJECT; + if (lpfc_cmd->result == IOERR_ELXSEC_KEY_UNWRAP_ERROR || + lpfc_cmd->result == + IOERR_ELXSEC_KEY_UNWRAP_COMPARE_ERROR || + lpfc_cmd->result == IOERR_ELXSEC_CRYPTO_ERROR || + lpfc_cmd->result == + IOERR_ELXSEC_CRYPTO_COMPARE_ERROR) { + cmd->result = DID_NO_CONNECT << 16; + break; + } + if (lpfc_cmd->result == IOERR_INVALID_RPI || + lpfc_cmd->result == IOERR_LINK_DOWN || + lpfc_cmd->result == IOERR_NO_RESOURCES || + lpfc_cmd->result == IOERR_ABORT_REQUESTED || + lpfc_cmd->result == IOERR_RPI_SUSPENDED || + lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) { + cmd->result = DID_TRANSPORT_DISRUPTED << 16; + break; + } + if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED || + lpfc_cmd->result == IOERR_TX_DMA_FAILED) && + status == CQE_STATUS_DI_ERROR) { + if (scsi_get_prot_op(cmd) != + SCSI_PROT_NORMAL) { + /* + * This is a response for a BG enabled + * cmd. Parse BG error + */ + lpfc_parse_bg_err(phba, lpfc_cmd, pwqeOut); + break; + } else { + lpfc_printf_vlog(vport, KERN_WARNING, + LOG_BG, + "9040 non-zero BGSTAT " + "on unprotected cmd\n"); + } + } + lpfc_printf_vlog(vport, KERN_WARNING, logit, + "9036 Local Reject FCP cmd x%x failed" + " <%d/%lld> " + "status: x%x result: x%x " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x x%x\n", + cmd->cmnd[0], + cmd->device ? cmd->device->id : 0xffff, + cmd->device ? cmd->device->lun : 0xffff, + lpfc_cmd->status, lpfc_cmd->result, + vport->fc_myDID, + (ndlp) ? ndlp->nlp_DID : 0, + lpfc_cmd->cur_iocbq.sli4_xritag, + wcqe->parameter, + wcqe->total_data_placed, + lpfc_cmd->cur_iocbq.iocb.ulpIoTag); + fallthrough; + default: + if (lpfc_cmd->status >= IOSTAT_CNT) + lpfc_cmd->status = IOSTAT_DEFAULT; + cmd->result = DID_ERROR << 16; + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, + "9037 FCP Completion Error: xri %x " + "status x%x result x%x [x%x] " + "placed x%x\n", + lpfc_cmd->cur_iocbq.sli4_xritag, + lpfc_cmd->status, lpfc_cmd->result, + wcqe->parameter, + wcqe->total_data_placed); + } + if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) { + u32 *lp = (u32 *)cmd->sense_buffer; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, + "9039 Iodone <%d/%llu> cmd x%px, error " + "x%x SNS x%x x%x LBA x%llx Data: x%x x%x\n", + cmd->device->id, cmd->device->lun, cmd, + cmd->result, *lp, *(lp + 3), + (u64)scsi_get_lba(cmd), + cmd->retries, scsi_get_resid(cmd)); + } + + if (vport->cfg_max_scsicmpl_time && + time_after(jiffies, lpfc_cmd->start_time + + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { + spin_lock_irqsave(shost->host_lock, flags); + if (ndlp) { + if (ndlp->cmd_qdepth > + atomic_read(&ndlp->cmd_pending) && + (atomic_read(&ndlp->cmd_pending) > + LPFC_MIN_TGT_QDEPTH) && + (cmd->cmnd[0] == READ_10 || + cmd->cmnd[0] == WRITE_10)) + ndlp->cmd_qdepth = + atomic_read(&ndlp->cmd_pending); + + ndlp->last_change_time = jiffies; + } + spin_unlock_irqrestore(shost->host_lock, flags); + } + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (lpfc_cmd->ts_cmd_start) { + lpfc_cmd->ts_isr_cmpl = lpfc_cmd->cur_iocbq.isr_timestamp; + lpfc_cmd->ts_data_io = ktime_get_ns(); + phba->ktime_last_cmd = lpfc_cmd->ts_data_io; + lpfc_io_ktime(phba, lpfc_cmd); + } +#endif + if (likely(!wait_xb_clr)) + lpfc_cmd->pCmd = NULL; + spin_unlock(&lpfc_cmd->buf_lock); + + /* Check if IO qualified for CMF */ + if (phba->cmf_active_mode != LPFC_CFG_OFF && + cmd->sc_data_direction == DMA_FROM_DEVICE && + (scsi_sg_count(cmd))) { + /* Used when calculating average latency */ + lat = ktime_get_ns() - lpfc_cmd->rx_cmd_start; + lpfc_update_cmf_cmpl(phba, lat, scsi_bufflen(cmd), shost); + } + + if (wait_xb_clr) + goto out; + + /* The sdev is not guaranteed to be valid post scsi_done upcall. */ + scsi_done(cmd); + + /* + * If there is an abort thread waiting for command completion + * wake up the thread. + */ + spin_lock(&lpfc_cmd->buf_lock); + lpfc_cmd->cur_iocbq.cmd_flag &= ~LPFC_DRIVER_ABORTED; + if (lpfc_cmd->waitq) + wake_up(lpfc_cmd->waitq); + spin_unlock(&lpfc_cmd->buf_lock); +out: + lpfc_release_scsi_buf(phba, lpfc_cmd); } /** @@ -3793,7 +4354,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct lpfc_iocbq *pIocbOut) { struct lpfc_io_buf *lpfc_cmd = - (struct lpfc_io_buf *) pIocbIn->context1; + (struct lpfc_io_buf *) pIocbIn->io_buf; struct lpfc_vport *vport = pIocbIn->vport; struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *pnode = rdata->pnode; @@ -3803,9 +4364,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct Scsi_Host *shost; int idx; uint32_t logit = LOG_FCP; -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - int cpu; -#endif /* Guard against abort handler being called at same time */ spin_lock(&lpfc_cmd->buf_lock); @@ -3813,7 +4371,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, /* Sanity check on return of outstanding command */ cmd = lpfc_cmd->pCmd; if (!cmd || !phba) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2621 IO completion: Not an active IO\n"); spin_unlock(&lpfc_cmd->buf_lock); return; @@ -3824,21 +4382,17 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, phba->sli4_hba.hdwq[idx].scsi_cstat.io_cmpls++; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) { - cpu = raw_smp_processor_id(); - if (cpu < LPFC_CHECK_CPU_CNT && phba->sli4_hba.hdwq) - phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++; - } + if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO)) + this_cpu_inc(phba->sli4_hba.c_stat->cmpl_io); #endif shost = cmd->device->host; lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK); lpfc_cmd->status = pIocbOut->iocb.ulpStatus; - /* pick up SLI4 exhange busy status from HBA */ - if (pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY) + /* pick up SLI4 exchange busy status from HBA */ + lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY; + if (pIocbOut->cmd_flag & LPFC_EXCHANGE_BUSY) lpfc_cmd->flags |= LPFC_SBUF_XBUSY; - else - lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (lpfc_cmd->prot_data_type) { @@ -3904,7 +4458,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, switch (lpfc_cmd->status) { case IOSTAT_FCP_RSP_ERROR: /* Call FCP RSP handler to determine result */ - lpfc_handle_fcp_err(vport, lpfc_cmd, pIocbOut); + lpfc_handle_fcp_err(vport, lpfc_cmd, + pIocbOut->iocb.un.fcpi.fcpi_parm); break; case IOSTAT_NPORT_BSY: case IOSTAT_FABRIC_BSY: @@ -3917,7 +4472,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, fast_path_evt->un.fabric_evt.subcategory = (lpfc_cmd->status == IOSTAT_NPORT_BSY) ? LPFC_EVENT_PORT_BUSY : LPFC_EVENT_FABRIC_BUSY; - if (pnode && NLP_CHK_NODE_ACT(pnode)) { + if (pnode) { memcpy(&fast_path_evt->un.fabric_evt.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); @@ -3949,7 +4504,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_cmd->result == IOERR_NO_RESOURCES || lpfc_cmd->result == IOERR_ABORT_REQUESTED || lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) { - cmd->result = DID_REQUEUE << 16; + cmd->result = DID_TRANSPORT_DISRUPTED << 16; break; } if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED || @@ -3972,7 +4527,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } if ((lpfc_cmd->status == IOSTAT_REMOTE_STOP) && (phba->sli_rev == LPFC_SLI_REV4) - && (pnode && NLP_CHK_NODE_ACT(pnode))) { + && pnode) { /* This IO was aborted by the target, we don't * know the rxid and because we did not send the * ABTS we cannot generate and RRQ. @@ -3981,14 +4536,13 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_cmd->cur_iocbq.sli4_lxritag, 0, 0); } - /* fall through */ + fallthrough; default: cmd->result = DID_ERROR << 16; break; } - if (!pnode || !NLP_CHK_NODE_ACT(pnode) - || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) + if (!pnode || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) cmd->result = DID_TRANSPORT_DISRUPTED << 16 | SAM_STAT_BUSY; } else @@ -4005,12 +4559,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, scsi_get_resid(cmd)); } - lpfc_update_stats(vport, lpfc_cmd); if (vport->cfg_max_scsicmpl_time && time_after(jiffies, lpfc_cmd->start_time + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { spin_lock_irqsave(shost->host_lock, flags); - if (pnode && NLP_CHK_NODE_ACT(pnode)) { + if (pnode) { if (pnode->cmd_qdepth > atomic_read(&pnode->cmd_pending) && (atomic_read(&pnode->cmd_pending) > @@ -4029,15 +4582,24 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_cmd->pCmd = NULL; spin_unlock(&lpfc_cmd->buf_lock); +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (lpfc_cmd->ts_cmd_start) { + lpfc_cmd->ts_isr_cmpl = pIocbIn->isr_timestamp; + lpfc_cmd->ts_data_io = ktime_get_ns(); + phba->ktime_last_cmd = lpfc_cmd->ts_data_io; + lpfc_io_ktime(phba, lpfc_cmd); + } +#endif + /* The sdev is not guaranteed to be valid post scsi_done upcall. */ - cmd->scsi_done(cmd); + scsi_done(cmd); /* * If there is an abort thread waiting for command completion * wake up the thread. */ spin_lock(&lpfc_cmd->buf_lock); - lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_DRIVER_ABORTED; + lpfc_cmd->cur_iocbq.cmd_flag &= ~LPFC_DRIVER_ABORTED; if (lpfc_cmd->waitq) wake_up(lpfc_cmd->waitq); spin_unlock(&lpfc_cmd->buf_lock); @@ -4046,72 +4608,30 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } /** - * 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. + * 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 * - * 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(uint8_t *data, struct fcp_cmnd *fcp_cmnd) -{ - int i, j; - for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); - i += sizeof(uint32_t), j++) { - ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); - } -} - -/** - * 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. + * 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 * - * This routine initializes fcp_cmnd and iocb data structure from scsi command - * to transfer for device with SLI3 interface spec. + * RETURNS 0 - SUCCESS, **/ -static void -lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, - struct lpfc_nodelist *pnode) +static int lpfc_scsi_prep_cmnd_buf_s3(struct lpfc_vport *vport, + struct lpfc_io_buf *lpfc_cmd, + uint8_t tmo) { - struct lpfc_hba *phba = vport->phba; + IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; + struct lpfc_iocbq *piocbq = &lpfc_cmd->cur_iocbq; struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; - struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); - struct lpfc_sli4_hdw_queue *hdwq = NULL; + struct lpfc_nodelist *pnode = lpfc_cmd->ndlp; int datadir = scsi_cmnd->sc_data_direction; - int idx; - uint8_t *ptr; - bool sli4; - uint32_t fcpdl; - - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) - return; - - lpfc_cmd->fcp_rsp->rspSnsLen = 0; - /* clear task management bits */ - lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; - - int_to_scsilun(lpfc_cmd->pCmd->device->lun, - &lpfc_cmd->fcp_cmnd->fcp_lun); - - ptr = &fcp_cmnd->fcpCdb[0]; - memcpy(ptr, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); - if (scsi_cmnd->cmd_len < LPFC_FCP_CDB_LEN) { - ptr += scsi_cmnd->cmd_len; - memset(ptr, 0, (LPFC_FCP_CDB_LEN - scsi_cmnd->cmd_len)); - } - - fcp_cmnd->fcpCntl1 = SIMPLE_Q; + u32 fcpdl; - sli4 = (phba->sli_rev == LPFC_SLI_REV4); piocbq->iocb.un.fcpi.fcpi_XRdy = 0; - idx = lpfc_cmd->hdwq_no; - if (phba->sli4_hba.hdwq) - hdwq = &phba->sli4_hba.hdwq[idx]; /* * There are three possibilities here - use scatter-gather segment, use @@ -4125,56 +4645,199 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, iocb_cmd->ulpPU = PARM_READ_CHECK; if (vport->cfg_first_burst_size && (pnode->nlp_flag & NLP_FIRSTBURST)) { + u32 xrdy_len; + fcpdl = scsi_bufflen(scsi_cmnd); - if (fcpdl < vport->cfg_first_burst_size) - piocbq->iocb.un.fcpi.fcpi_XRdy = fcpdl; - else - piocbq->iocb.un.fcpi.fcpi_XRdy = - vport->cfg_first_burst_size; + xrdy_len = min(fcpdl, + vport->cfg_first_burst_size); + piocbq->iocb.un.fcpi.fcpi_XRdy = xrdy_len; } fcp_cmnd->fcpCntl3 = WRITE_DATA; - if (hdwq) - hdwq->scsi_cstat.output_requests++; } else { iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR; iocb_cmd->ulpPU = PARM_READ_CHECK; fcp_cmnd->fcpCntl3 = READ_DATA; - if (hdwq) - hdwq->scsi_cstat.input_requests++; } } else { iocb_cmd->ulpCommand = CMD_FCP_ICMND64_CR; iocb_cmd->un.fcpi.fcpi_parm = 0; iocb_cmd->ulpPU = 0; fcp_cmnd->fcpCntl3 = 0; - if (hdwq) - hdwq->scsi_cstat.control_requests++; } - if (phba->sli_rev == 3 && - !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) - lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); + /* * Finish initializing those IOCB fields that are independent * of the scsi_cmnd request_buffer */ piocbq->iocb.ulpContext = pnode->nlp_rpi; - if (sli4) - piocbq->iocb.ulpContext = - phba->sli4_hba.rpi_ids[pnode->nlp_rpi]; if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE) piocbq->iocb.ulpFCP2Rcvy = 1; else piocbq->iocb.ulpFCP2Rcvy = 0; piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f); - piocbq->context1 = lpfc_cmd; - piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; - piocbq->iocb.ulpTimeout = lpfc_cmd->timeout; + piocbq->io_buf = lpfc_cmd; + if (!piocbq->cmd_cmpl) + piocbq->cmd_cmpl = lpfc_scsi_cmd_iocb_cmpl; + piocbq->iocb.ulpTimeout = tmo; piocbq->vport = vport; + return 0; +} + +/** + * 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) +{ + struct lpfc_hba *phba = vport->phba; + struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; + struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; + struct lpfc_sli4_hdw_queue *hdwq = NULL; + struct lpfc_iocbq *pwqeq = &lpfc_cmd->cur_iocbq; + struct lpfc_nodelist *pnode = lpfc_cmd->ndlp; + union lpfc_wqe128 *wqe = &pwqeq->wqe; + u16 idx = lpfc_cmd->hdwq_no; + int datadir = scsi_cmnd->sc_data_direction; + + hdwq = &phba->sli4_hba.hdwq[idx]; + + /* Initialize 64 bytes only */ + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* + * There are three possibilities here - use scatter-gather segment, use + * the single mapping, or neither. + */ + if (scsi_sg_count(scsi_cmnd)) { + if (datadir == DMA_TO_DEVICE) { + /* From the iwrite template, initialize words 7 - 11 */ + memcpy(&wqe->words[7], + &lpfc_iwrite_cmd_template.words[7], + sizeof(uint32_t) * 5); + + fcp_cmnd->fcpCntl3 = WRITE_DATA; + if (hdwq) + hdwq->scsi_cstat.output_requests++; + } else { + /* From the iread template, initialize words 7 - 11 */ + memcpy(&wqe->words[7], + &lpfc_iread_cmd_template.words[7], + sizeof(uint32_t) * 5); + + /* Word 7 */ + bf_set(wqe_tmo, &wqe->fcp_iread.wqe_com, tmo); + + fcp_cmnd->fcpCntl3 = READ_DATA; + if (hdwq) + hdwq->scsi_cstat.input_requests++; + + /* For a CMF Managed port, iod must be zero'ed */ + if (phba->cmf_active_mode == LPFC_CFG_MANAGED) + bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, + LPFC_WQE_IOD_NONE); + } + } else { + /* From the icmnd template, initialize words 4 - 11 */ + memcpy(&wqe->words[4], &lpfc_icmnd_cmd_template.words[4], + sizeof(uint32_t) * 8); + + /* Word 7 */ + bf_set(wqe_tmo, &wqe->fcp_icmd.wqe_com, tmo); + + fcp_cmnd->fcpCntl3 = 0; + if (hdwq) + hdwq->scsi_cstat.control_requests++; + } + + /* + * Finish initializing those WQE fields that are independent + * of the request_buffer + */ + + /* Word 3 */ + bf_set(payload_offset_len, &wqe->fcp_icmd, + sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); + + /* Word 6 */ + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, + phba->sli4_hba.rpi_ids[pnode->nlp_rpi]); + bf_set(wqe_xri_tag, &wqe->generic.wqe_com, pwqeq->sli4_xritag); + + /* Word 7*/ + if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE) + bf_set(wqe_erp, &wqe->generic.wqe_com, 1); + + bf_set(wqe_class, &wqe->generic.wqe_com, + (pnode->nlp_fcp_info & 0x0f)); + + /* Word 8 */ + wqe->generic.wqe_com.abort_tag = pwqeq->iotag; + + /* Word 9 */ + bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag); + + pwqeq->vport = vport; + pwqeq->io_buf = lpfc_cmd; + pwqeq->hba_wqidx = lpfc_cmd->hdwq_no; + pwqeq->cmd_cmpl = lpfc_fcp_io_cmd_wqe_cmpl; + + return 0; } /** - * lpfc_scsi_prep_task_mgmt_cmd - Convert SLI3 scsi TM cmd to FCP info unit + * 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) +{ + struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; + struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; + u8 *ptr; + + if (!pnode) + return 0; + + lpfc_cmd->fcp_rsp->rspSnsLen = 0; + /* clear task management bits */ + lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; + + int_to_scsilun(lpfc_cmd->pCmd->device->lun, + &lpfc_cmd->fcp_cmnd->fcp_lun); + + ptr = &fcp_cmnd->fcpCdb[0]; + memcpy(ptr, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); + if (scsi_cmnd->cmd_len < LPFC_FCP_CDB_LEN) { + ptr += scsi_cmnd->cmd_len; + memset(ptr, 0, (LPFC_FCP_CDB_LEN - scsi_cmnd->cmd_len)); + } + + fcp_cmnd->fcpCntl1 = SIMPLE_Q; + + lpfc_scsi_prep_cmnd_buf(vport, lpfc_cmd, lpfc_cmd->timeout); + + return 0; +} + +/** + * 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. @@ -4188,10 +4851,9 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd, * 1 - Success **/ static int -lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, - struct lpfc_io_buf *lpfc_cmd, - uint64_t lun, - uint8_t task_mgmt_cmd) +lpfc_scsi_prep_task_mgmt_cmd_s3(struct lpfc_vport *vport, + struct lpfc_io_buf *lpfc_cmd, + u64 lun, u8 task_mgmt_cmd) { struct lpfc_iocbq *piocbq; IOCB_t *piocb; @@ -4199,8 +4861,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *ndlp = rdata->pnode; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || - ndlp->nlp_state != NLP_STE_MAPPED_NODE) + if (!ndlp || ndlp->nlp_state != NLP_STE_MAPPED_NODE) return 0; piocbq = &(lpfc_cmd->cur_iocbq); @@ -4213,15 +4874,10 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd)); int_to_scsilun(lun, &fcp_cmnd->fcp_lun); fcp_cmnd->fcpCntl2 = task_mgmt_cmd; - if (vport->phba->sli_rev == 3 && - !(vport->phba->sli3_options & LPFC_SLI3_BG_ENABLED)) + if (!(vport->phba->sli3_options & LPFC_SLI3_BG_ENABLED)) lpfc_fcpcmd_to_iocb(piocb->unsli3.fcp_ext.icd, fcp_cmnd); piocb->ulpCommand = CMD_FCP_ICMND64_CR; piocb->ulpContext = ndlp->nlp_rpi; - if (vport->phba->sli_rev == LPFC_SLI_REV4) { - piocb->ulpContext = - vport->phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - } piocb->ulpFCP2Rcvy = (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) ? 1 : 0; piocb->ulpClass = (ndlp->nlp_fcp_info & 0x0f); piocb->ulpPU = 0; @@ -4237,8 +4893,79 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, } else piocb->ulpTimeout = lpfc_cmd->timeout; - if (vport->phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_set_rsp_sgl_last(vport->phba, lpfc_cmd); + return 1; +} + +/** + * 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) +{ + struct lpfc_iocbq *pwqeq = &lpfc_cmd->cur_iocbq; + union lpfc_wqe128 *wqe = &pwqeq->wqe; + struct fcp_cmnd *fcp_cmnd; + struct lpfc_rport_data *rdata = lpfc_cmd->rdata; + struct lpfc_nodelist *ndlp = rdata->pnode; + + if (!ndlp || ndlp->nlp_state != NLP_STE_MAPPED_NODE) + return 0; + + pwqeq->vport = vport; + /* Initialize 64 bytes only */ + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* From the icmnd template, initialize words 4 - 11 */ + memcpy(&wqe->words[4], &lpfc_icmnd_cmd_template.words[4], + sizeof(uint32_t) * 8); + + fcp_cmnd = lpfc_cmd->fcp_cmnd; + /* Clear out any old data in the FCP command area */ + memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd)); + int_to_scsilun(lun, &fcp_cmnd->fcp_lun); + fcp_cmnd->fcpCntl3 = 0; + fcp_cmnd->fcpCntl2 = task_mgmt_cmd; + + bf_set(payload_offset_len, &wqe->fcp_icmd, + sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); + bf_set(cmd_buff_len, &wqe->fcp_icmd, 0); + bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com, /* ulpContext */ + vport->phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); + bf_set(wqe_erp, &wqe->fcp_icmd.wqe_com, + ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) ? 1 : 0)); + bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, + (ndlp->nlp_fcp_info & 0x0f)); + + /* ulpTimeout is only one byte */ + if (lpfc_cmd->timeout > 0xff) { + /* + * Do not timeout the command at the firmware level. + * The driver will provide the timeout mechanism. + */ + bf_set(wqe_tmo, &wqe->fcp_icmd.wqe_com, 0); + } else { + bf_set(wqe_tmo, &wqe->fcp_icmd.wqe_com, lpfc_cmd->timeout); + } + + lpfc_prep_embed_io(vport->phba, lpfc_cmd); + bf_set(wqe_xri_tag, &wqe->generic.wqe_com, pwqeq->sli4_xritag); + wqe->generic.wqe_com.abort_tag = pwqeq->iotag; + bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag); + + lpfc_sli4_set_rsp_sgl_last(vport->phba, lpfc_cmd); return 1; } @@ -4257,7 +4984,6 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) { phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf; - phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd; switch (dev_grp) { case LPFC_PCI_DEV_LP: @@ -4265,19 +4991,24 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s3; phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3; phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s3; + phba->lpfc_scsi_prep_cmnd_buf = lpfc_scsi_prep_cmnd_buf_s3; + phba->lpfc_scsi_prep_task_mgmt_cmd = + lpfc_scsi_prep_task_mgmt_cmd_s3; break; case LPFC_PCI_DEV_OC: phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4; phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s4; phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4; phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4; + phba->lpfc_scsi_prep_cmnd_buf = lpfc_scsi_prep_cmnd_buf_s4; + phba->lpfc_scsi_prep_task_mgmt_cmd = + lpfc_scsi_prep_task_mgmt_cmd_s4; break; default: lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "1418 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth; phba->lpfc_scsi_cmd_iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; @@ -4285,7 +5016,7 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) } /** - * lpfc_taskmgmt_def_cmpl - IOCB completion routine for task management command + * 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. @@ -4298,8 +5029,7 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq, struct lpfc_iocbq *rspiocbq) { - struct lpfc_io_buf *lpfc_cmd = - (struct lpfc_io_buf *) cmdiocbq->context1; + struct lpfc_io_buf *lpfc_cmd = cmdiocbq->io_buf; if (lpfc_cmd) lpfc_release_scsi_buf(phba, lpfc_cmd); return; @@ -4320,7 +5050,7 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, * 0, successful */ int -lpfc_check_pci_resettable(const struct lpfc_hba *phba) +lpfc_check_pci_resettable(struct lpfc_hba *phba) { const struct pci_dev *pdev = phba->pcidev; struct pci_dev *ptr = NULL; @@ -4337,14 +5067,10 @@ lpfc_check_pci_resettable(const struct lpfc_hba *phba) } /* Check for valid Emulex Device ID */ - switch (ptr->device) { - case PCI_DEVICE_ID_LANCER_FC: - case PCI_DEVICE_ID_LANCER_G6_FC: - case PCI_DEVICE_ID_LANCER_G7_FC: - break; - default: + if (phba->sli_rev != LPFC_SLI_REV4 || + phba->hba_flag & HBA_FCOE_MODE) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "8347 Invalid device found: " + "8347 Incapable PCI reset device: " "0x%04x\n", ptr->device); return -EBADSLT; } @@ -4430,7 +5156,7 @@ buffer_done: } /** - * lpfc_poll_rearm_time - Routine to modify fcp_poll timer of hba + * 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. @@ -4459,12 +5185,11 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba) /** * lpfc_poll_timeout - Restart polling timer - * @ptr: Map to lpfc_hba data structure pointer. + * @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) { struct lpfc_hba *phba = from_timer(phba, t, fcp_poll_timer); @@ -4478,10 +5203,24 @@ 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) +{ + struct bio *bio = scsi_cmd_to_rq(cmd)->bio; + + if (!IS_ENABLED(CONFIG_BLK_CGROUP_FC_APPID) || !bio) + return NULL; + return blkcg_get_fc_appid(bio); +} + /** * lpfc_queuecommand - scsi_host_template queuecommand entry point + * @shost: kernel scsi host pointer. * @cmnd: Pointer to scsi_cmnd data structure. - * @done: Pointer to done routine. * * 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. @@ -4496,15 +5235,16 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) { struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + struct lpfc_iocbq *cur_iocbq = NULL; struct lpfc_rport_data *rdata; struct lpfc_nodelist *ndlp; struct lpfc_io_buf *lpfc_cmd; struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); int err, idx; -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - int cpu; -#endif + u8 *uuid = NULL; + uint64_t start; + start = ktime_get_ns(); rdata = lpfc_rport_data_from_scsi_device(cmnd->device); /* sanity check on references */ @@ -4521,7 +5261,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) if ((scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) && (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED))) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "9058 BLKGRD: ERROR: rcvd protected cmd:%02x" " op:%02x str=%s without registering for" " BlockGuard - Rejecting command\n", @@ -4534,8 +5274,19 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) * Catch race where our node has transitioned, but the * transport is still transitioning. */ - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - goto out_tgt_busy; + if (!ndlp) + goto out_tgt_busy1; + + /* Check if IO qualifies for CMF */ + if (phba->cmf_active_mode != LPFC_CFG_OFF && + cmnd->sc_data_direction == DMA_FROM_DEVICE && + (scsi_sg_count(cmnd))) { + /* Latency start time saved in rx_cmd_start later in routine */ + err = lpfc_update_cmf_cmd(phba, scsi_bufflen(cmnd)); + if (err) + goto out_tgt_busy1; + } + if (lpfc_ndlp_check_qdepth(phba, ndlp)) { if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) { lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_ERROR, @@ -4563,7 +5314,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) ndlp->nlp_portname.u.wwn[5], ndlp->nlp_portname.u.wwn[6], ndlp->nlp_portname.u.wwn[7]); - goto out_tgt_busy; + goto out_tgt_busy2; } } @@ -4576,7 +5327,9 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) "IO busied\n"); goto out_host_busy; } + lpfc_cmd->rx_cmd_start = start; + cur_iocbq = &lpfc_cmd->cur_iocbq; /* * Store the midlayer's command structure for the completion phase * and complete the command initialization. @@ -4584,18 +5337,23 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) lpfc_cmd->pCmd = cmnd; lpfc_cmd->rdata = rdata; lpfc_cmd->ndlp = ndlp; + cur_iocbq->cmd_cmpl = NULL; cmnd->host_scribble = (unsigned char *)lpfc_cmd; + err = lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); + if (err) + goto out_host_busy_release_buf; + if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { if (vport->phba->cfg_enable_bg) { lpfc_printf_vlog(vport, KERN_INFO, LOG_SCSI_CMD, "9033 BLKGRD: rcvd %s cmd:x%x " - "sector x%llx cnt %u pt %x\n", + "reftag x%x cnt %u pt %x\n", dif_op_str[scsi_get_prot_op(cmnd)], cmnd->cmnd[0], - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), + scsi_prot_ref_tag(cmnd), + scsi_logical_block_count(cmnd), (cmnd->cmnd[1]>>5)); } err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); @@ -4604,10 +5362,10 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) lpfc_printf_vlog(vport, KERN_INFO, LOG_SCSI_CMD, "9038 BLKGRD: rcvd PROT_NORMAL cmd: " - "x%x sector x%llx cnt %u pt %x\n", + "x%x reftag x%x cnt %u pt %x\n", cmnd->cmnd[0], - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), + scsi_prot_ref_tag(cmnd), + scsi_logical_block_count(cmnd), (cmnd->cmnd[1]>>5)); } err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); @@ -4621,40 +5379,66 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) goto out_host_busy_free_buf; } - lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); + /* check the necessary and sufficient condition to support VMID */ + if (lpfc_is_vmid_enabled(phba) && + (ndlp->vmid_support || + phba->pport->vmid_priority_tagging == + LPFC_VMID_PRIO_TAG_ALL_TARGETS)) { + /* is the I/O generated by a VM, get the associated virtual */ + /* entity id */ + uuid = lpfc_is_command_vm_io(cmnd); + + if (uuid) { + err = lpfc_vmid_get_appid(vport, uuid, + cmnd->sc_data_direction, + (union lpfc_vmid_io_tag *) + &cur_iocbq->vmid_tag); + if (!err) + cur_iocbq->cmd_flag |= LPFC_IO_VMID; + } + } #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) { - cpu = raw_smp_processor_id(); - if (cpu < LPFC_CHECK_CPU_CNT) { - struct lpfc_sli4_hdw_queue *hdwq = - &phba->sli4_hba.hdwq[lpfc_cmd->hdwq_no]; - hdwq->cpucheck_xmt_io[cpu]++; - } + if (unlikely(phba->hdwqstat_on & LPFC_CHECK_SCSI_IO)) + this_cpu_inc(phba->sli4_hba.c_stat->xmt_io); +#endif + /* Issue I/O to adapter */ + err = lpfc_sli_issue_fcp_io(phba, LPFC_FCP_RING, cur_iocbq, + SLI_IOCB_RET_IOCB); +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (start) { + lpfc_cmd->ts_cmd_start = start; + lpfc_cmd->ts_last_cmd = phba->ktime_last_cmd; + lpfc_cmd->ts_cmd_wqput = ktime_get_ns(); + } else { + lpfc_cmd->ts_cmd_start = 0; } #endif - err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, - &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); if (err) { lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "3376 FCP could not issue IOCB err %x" + "3376 FCP could not issue iocb err %x " "FCP cmd x%x <%d/%llu> " "sid: x%x did: x%x oxid: x%x " "Data: x%x x%x x%x x%x\n", err, cmnd->cmnd[0], cmnd->device ? cmnd->device->id : 0xffff, - cmnd->device ? cmnd->device->lun : (u64) -1, + cmnd->device ? cmnd->device->lun : (u64)-1, vport->fc_myDID, ndlp->nlp_DID, phba->sli_rev == LPFC_SLI_REV4 ? - lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff, - lpfc_cmd->cur_iocbq.iocb.ulpContext, - lpfc_cmd->cur_iocbq.iocb.ulpIoTag, - lpfc_cmd->cur_iocbq.iocb.ulpTimeout, - (uint32_t) - (cmnd->request->timeout / 1000)); + cur_iocbq->sli4_xritag : 0xffff, + phba->sli_rev == LPFC_SLI_REV4 ? + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi] : + cur_iocbq->iocb.ulpContext, + cur_iocbq->iotag, + phba->sli_rev == LPFC_SLI_REV4 ? + bf_get(wqe_tmo, + &cur_iocbq->wqe.generic.wqe_com) : + cur_iocbq->iocb.ulpTimeout, + (uint32_t)(scsi_cmd_to_rq(cmnd)->timeout / 1000)); goto out_host_busy_free_buf; } + if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_handle_fast_ring_event(phba, &phba->sli.sli3_ring[LPFC_FCP_RING], HA_R0RE_REQ); @@ -4683,21 +5467,54 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) phba->sli4_hba.hdwq[idx].scsi_cstat.control_requests--; } } + out_host_busy_release_buf: lpfc_release_scsi_buf(phba, lpfc_cmd); out_host_busy: + lpfc_update_cmf_cmpl(phba, LPFC_CGN_NOT_SENT, scsi_bufflen(cmnd), + shost); return SCSI_MLQUEUE_HOST_BUSY; - out_tgt_busy: + out_tgt_busy2: + lpfc_update_cmf_cmpl(phba, LPFC_CGN_NOT_SENT, scsi_bufflen(cmnd), + shost); + out_tgt_busy1: return SCSI_MLQUEUE_TARGET_BUSY; out_fail_command_release_buf: lpfc_release_scsi_buf(phba, lpfc_cmd); + lpfc_update_cmf_cmpl(phba, LPFC_CGN_NOT_SENT, scsi_bufflen(cmnd), + shost); out_fail_command: - cmnd->scsi_done(cmnd); + scsi_done(cmnd); return 0; } +/* + * 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) +{ + u32 bucket; + struct lpfc_vmid *cur; + + if (vport->port_type == LPFC_PHYSICAL_PORT) + del_timer_sync(&vport->phba->inactive_vmid_poll); + + kfree(vport->qfpa_res); + kfree(vport->vmid_priority.vmid_range); + kfree(vport->vmid); + + if (!hash_empty(vport->hash_table)) + hash_for_each(vport->hash_table, bucket, cur, hnode) + hash_del(&cur->hnode); + + vport->qfpa_res = NULL; + vport->vmid_priority.vmid_range = NULL; + vport->vmid = NULL; + vport->cur_vmid_cnt = 0; +} /** * lpfc_abort_handler - scsi_host_template eh_abort_handler entry point @@ -4713,19 +5530,19 @@ static int lpfc_abort_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; + struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *iocb; - struct lpfc_iocbq *abtsiocb; struct lpfc_io_buf *lpfc_cmd; - IOCB_t *cmd, *icmd; int ret = SUCCESS, status = 0; struct lpfc_sli_ring *pring_s4 = NULL; + struct lpfc_sli_ring *pring = NULL; int ret_val; unsigned long flags; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); - status = fc_block_scsi_eh(cmnd); + status = fc_block_rport(rport); if (status != 0 && status != SUCCESS) return status; @@ -4733,25 +5550,25 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) if (!lpfc_cmd) return ret; - spin_lock_irqsave(&phba->hbalock, flags); + /* Guard against IO completion being called at same time */ + spin_lock_irqsave(&lpfc_cmd->buf_lock, flags); + + spin_lock(&phba->hbalock); /* driver queued commands are in process of being flushed */ if (phba->hba_flag & HBA_IOQ_FLUSH) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "3168 SCSI Layer abort requested I/O has been " "flushed by LLD.\n"); ret = FAILED; - goto out_unlock; + goto out_unlock_hba; } - /* Guard against IO completion being called at same time */ - spin_lock(&lpfc_cmd->buf_lock); - if (!lpfc_cmd->pCmd) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "2873 SCSI Layer I/O Abort Request IO CMPL Status " "x%x ID %d LUN %llu\n", SUCCESS, cmnd->device->id, cmnd->device->lun); - goto out_unlock_buf; + goto out_unlock_hba; } iocb = &lpfc_cmd->cur_iocbq; @@ -4759,12 +5576,12 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring; if (!pring_s4) { ret = FAILED; - goto out_unlock_buf; + goto out_unlock_hba; } spin_lock(&pring_s4->ring_lock); } /* the command is in process of being cancelled */ - if (!(iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ)) { + if (!(iocb->cmd_flag & LPFC_IO_ON_TXCMPLQ)) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "3169 SCSI Layer abort requested I/O has been " "cancelled by LLD.\n"); @@ -4784,91 +5601,53 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) goto out_unlock_ring; } - BUG_ON(iocb->context1 != lpfc_cmd); + WARN_ON(iocb->io_buf != lpfc_cmd); /* abort issued in recovery is still in progress */ - if (iocb->iocb_flag & LPFC_DRIVER_ABORTED) { + if (iocb->cmd_flag & LPFC_DRIVER_ABORTED) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "3389 SCSI Layer I/O Abort Request is pending\n"); if (phba->sli_rev == LPFC_SLI_REV4) spin_unlock(&pring_s4->ring_lock); - spin_unlock(&lpfc_cmd->buf_lock); - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock(&phba->hbalock); + spin_unlock_irqrestore(&lpfc_cmd->buf_lock, flags); goto wait_for_cmpl; } - abtsiocb = __lpfc_sli_get_iocbq(phba); - if (abtsiocb == NULL) { - ret = FAILED; - goto out_unlock_ring; - } - - /* Indicate the IO is being aborted by the driver. */ - iocb->iocb_flag |= LPFC_DRIVER_ABORTED; - - /* - * The scsi command can not be in txq and it is in flight because the - * pCmd is still pointig at the SCSI command we have to abort. There - * is no need to search the txcmplq. Just send an abort to the FW. - */ - - cmd = &iocb->iocb; - icmd = &abtsiocb->iocb; - icmd->un.acxri.abortType = ABORT_TYPE_ABTS; - icmd->un.acxri.abortContextTag = cmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) - icmd->un.acxri.abortIoTag = iocb->sli4_xritag; - else - icmd->un.acxri.abortIoTag = cmd->ulpIoTag; - - icmd->ulpLe = 1; - icmd->ulpClass = cmd->ulpClass; - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocb->hba_wqidx = iocb->hba_wqidx; - abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; - if (iocb->iocb_flag & LPFC_IO_FOF) - abtsiocb->iocb_flag |= LPFC_IO_FOF; - - if (lpfc_is_link_up(phba)) - icmd->ulpCommand = CMD_ABORT_XRI_CN; - else - icmd->ulpCommand = CMD_CLOSE_XRI_CN; - - abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - abtsiocb->vport = vport; lpfc_cmd->waitq = &waitq; if (phba->sli_rev == LPFC_SLI_REV4) { - /* Note: both hbalock and ring_lock must be set here */ - ret_val = __lpfc_sli_issue_iocb(phba, pring_s4->ringno, - abtsiocb, 0); spin_unlock(&pring_s4->ring_lock); + ret_val = lpfc_sli4_issue_abort_iotag(phba, iocb, + lpfc_sli_abort_fcp_cmpl); } else { - ret_val = __lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, - abtsiocb, 0); + pring = &phba->sli.sli3_ring[LPFC_FCP_RING]; + ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocb, + lpfc_sli_abort_fcp_cmpl); } - if (ret_val == IOCB_ERROR) { + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + + if (ret_val != IOCB_SUCCESS) { /* Indicate the IO is not being aborted by the driver. */ - iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; lpfc_cmd->waitq = NULL; - spin_unlock(&lpfc_cmd->buf_lock); - spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_sli_release_iocbq(phba, abtsiocb); ret = FAILED; - goto out; + goto out_unlock_hba; } /* no longer need the lock after this point */ - spin_unlock(&lpfc_cmd->buf_lock); - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock(&phba->hbalock); + spin_unlock_irqrestore(&lpfc_cmd->buf_lock, flags); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_sli_handle_fast_ring_event(phba, &phba->sli.sli3_ring[LPFC_FCP_RING], HA_R0RE_REQ); wait_for_cmpl: - /* Wait for abort to complete */ + /* + * cmd_flag is set to LPFC_DRIVER_ABORTED before we wait + * for abort to complete. + */ wait_event_timeout(waitq, (lpfc_cmd->pCmd != cmnd), msecs_to_jiffies(2*vport->cfg_devloss_tmo*1000)); @@ -4877,7 +5656,7 @@ wait_for_cmpl: if (lpfc_cmd->pCmd == cmnd) { ret = FAILED; - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0748 abort handler timed out waiting " "for aborting I/O (xri:x%x) to complete: " "ret %#x, ID %d, LUN %llu\n", @@ -4893,10 +5672,9 @@ wait_for_cmpl: out_unlock_ring: if (phba->sli_rev == LPFC_SLI_REV4) spin_unlock(&pring_s4->ring_lock); -out_unlock_buf: - spin_unlock(&lpfc_cmd->buf_lock); -out_unlock: - spin_unlock_irqrestore(&phba->hbalock, flags); +out_unlock_hba: + spin_unlock(&phba->hbalock); + spin_unlock_irqrestore(&lpfc_cmd->buf_lock, flags); out: lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0749 SCSI Layer I/O Abort Request Status x%x ID %d " @@ -5003,7 +5781,7 @@ 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. - * @rdata: Pointer to remote port local data + * @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 @@ -5016,7 +5794,7 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) * 0x2002 - Success. **/ static int -lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, +lpfc_send_taskmgmt(struct lpfc_vport *vport, struct fc_rport *rport, unsigned int tgt_id, uint64_t lun_id, uint8_t task_mgmt_cmd) { @@ -5029,21 +5807,21 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, int ret; int status; - rdata = lpfc_rport_data_from_scsi_device(cmnd->device); - if (!rdata || !rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) + rdata = rport->dd_data; + if (!rdata || !rdata->pnode) return FAILED; pnode = rdata->pnode; - lpfc_cmd = lpfc_get_scsi_buf(phba, pnode, NULL); + lpfc_cmd = lpfc_get_scsi_buf(phba, rdata->pnode, NULL); if (lpfc_cmd == NULL) return FAILED; lpfc_cmd->timeout = phba->cfg_task_mgmt_tmo; lpfc_cmd->rdata = rdata; - lpfc_cmd->pCmd = cmnd; + lpfc_cmd->pCmd = NULL; lpfc_cmd->ndlp = pnode; - status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id, - task_mgmt_cmd); + status = phba->lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id, + task_mgmt_cmd); if (!status) { lpfc_release_scsi_buf(phba, lpfc_cmd); return FAILED; @@ -5055,38 +5833,41 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, lpfc_release_scsi_buf(phba, lpfc_cmd); return FAILED; } - iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; + iocbq->cmd_cmpl = lpfc_tskmgmt_def_cmpl; + iocbq->vport = vport; lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, "0702 Issue %s to TGT %d LUN %llu " "rpi x%x nlp_flag x%x Data: x%x x%x\n", lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id, pnode->nlp_rpi, pnode->nlp_flag, iocbq->sli4_xritag, - iocbq->iocb_flag); + iocbq->cmd_flag); status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, iocbq, iocbqrsp, lpfc_cmd->timeout); if ((status != IOCB_SUCCESS) || - (iocbqrsp->iocb.ulpStatus != IOSTAT_SUCCESS)) { + (get_job_ulpstatus(phba, iocbqrsp) != IOSTAT_SUCCESS)) { if (status != IOCB_SUCCESS || - iocbqrsp->iocb.ulpStatus != IOSTAT_FCP_RSP_ERROR) - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + get_job_ulpstatus(phba, iocbqrsp) != IOSTAT_FCP_RSP_ERROR) + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0727 TMF %s to TGT %d LUN %llu " - "failed (%d, %d) iocb_flag x%x\n", + "failed (%d, %d) cmd_flag x%x\n", lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id, - iocbqrsp->iocb.ulpStatus, - iocbqrsp->iocb.un.ulpWord[4], - iocbq->iocb_flag); + get_job_ulpstatus(phba, iocbqrsp), + get_job_word4(phba, iocbqrsp), + iocbq->cmd_flag); /* if ulpStatus != IOCB_SUCCESS, then status == IOCB_SUCCESS */ if (status == IOCB_SUCCESS) { - if (iocbqrsp->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR) + if (get_job_ulpstatus(phba, iocbqrsp) == + IOSTAT_FCP_RSP_ERROR) /* Something in the FCP_RSP was invalid. * Check conditions */ ret = lpfc_check_fcp_rsp(vport, lpfc_cmd); else ret = FAILED; - } else if (status == IOCB_TIMEDOUT) { + } else if ((status == IOCB_TIMEDOUT) || + (status == IOCB_ABORTED)) { ret = TIMEOUT_ERROR; } else { ret = FAILED; @@ -5096,7 +5877,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, lpfc_sli_release_iocbq(phba, iocbqrsp); - if (ret != TIMEOUT_ERROR) + if (status != IOCB_TIMEDOUT) lpfc_release_scsi_buf(phba, lpfc_cmd); return ret; @@ -5105,7 +5886,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, /** * lpfc_chk_tgt_mapped - * @vport: The virtual port to check on - * @cmnd: Pointer to scsi_cmnd data structure. + * @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. @@ -5115,37 +5896,37 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct scsi_cmnd *cmnd, * 0x2002 - Success **/ static int -lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) +lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct fc_rport *rport) { struct lpfc_rport_data *rdata; - struct lpfc_nodelist *pnode; + struct lpfc_nodelist *pnode = NULL; unsigned long later; - rdata = lpfc_rport_data_from_scsi_device(cmnd->device); + rdata = rport->dd_data; if (!rdata) { lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, "0797 Tgt Map rport failure: rdata x%px\n", rdata); return FAILED; } pnode = rdata->pnode; + /* * If target is not in a MAPPED state, delay until * target is rediscovered or devloss timeout expires. */ later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; while (time_after(later, jiffies)) { - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) + if (!pnode) return FAILED; if (pnode->nlp_state == NLP_STE_MAPPED_NODE) return SUCCESS; schedule_timeout_uninterruptible(msecs_to_jiffies(500)); - rdata = lpfc_rport_data_from_scsi_device(cmnd->device); + rdata = rport->dd_data; if (!rdata) return FAILED; pnode = rdata->pnode; } - if (!pnode || !NLP_CHK_NODE_ACT(pnode) || - (pnode->nlp_state != NLP_STE_MAPPED_NODE)) + if (!pnode || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) return FAILED; return SUCCESS; } @@ -5185,7 +5966,7 @@ lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); } if (cnt) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0724 I/O flush failure for context %s : cnt x%x\n", ((context == LPFC_CTX_LUN) ? "LUN" : ((context == LPFC_CTX_TGT) ? "TGT" : @@ -5211,6 +5992,7 @@ static int lpfc_device_reset_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; + struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_rport_data *rdata; struct lpfc_nodelist *pnode; @@ -5218,22 +6000,26 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) uint64_t lun_id = cmnd->device->lun; struct lpfc_scsi_event_header scsi_event; int status; + u32 logit = LOG_FCP; - rdata = lpfc_rport_data_from_scsi_device(cmnd->device); + if (!rport) + return FAILED; + + rdata = rport->dd_data; if (!rdata || !rdata->pnode) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0798 Device Reset rdata failure: rdata x%px\n", rdata); return FAILED; } pnode = rdata->pnode; - status = fc_block_scsi_eh(cmnd); + status = fc_block_rport(rport); if (status != 0 && status != SUCCESS) return status; - status = lpfc_chk_tgt_mapped(vport, cmnd); + status = lpfc_chk_tgt_mapped(vport, rport); if (status == FAILED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0721 Device Reset rport failure: rdata x%px\n", rdata); return FAILED; } @@ -5247,10 +6033,12 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) fc_host_post_vendor_event(shost, fc_get_event_number(), sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); - status = lpfc_send_taskmgmt(vport, cmnd, tgt_id, lun_id, + status = lpfc_send_taskmgmt(vport, rport, tgt_id, lun_id, FCP_LUN_RESET); + if (status != SUCCESS) + logit = LOG_TRACE_EVENT; - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, logit, "0713 SCSI layer issued Device Reset (%d, %llu) " "return x%x\n", tgt_id, lun_id, status); @@ -5282,6 +6070,7 @@ static int lpfc_target_reset_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; + struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_rport_data *rdata; struct lpfc_nodelist *pnode; @@ -5289,28 +6078,35 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) uint64_t lun_id = cmnd->device->lun; struct lpfc_scsi_event_header scsi_event; int status; + u32 logit = LOG_FCP; + u32 dev_loss_tmo = vport->cfg_devloss_tmo; + unsigned long flags; + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); - rdata = lpfc_rport_data_from_scsi_device(cmnd->device); + if (!rport) + return FAILED; + + rdata = rport->dd_data; if (!rdata || !rdata->pnode) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0799 Target Reset rdata failure: rdata x%px\n", rdata); return FAILED; } pnode = rdata->pnode; - status = fc_block_scsi_eh(cmnd); + status = fc_block_rport(rport); if (status != 0 && status != SUCCESS) return status; - status = lpfc_chk_tgt_mapped(vport, cmnd); + status = lpfc_chk_tgt_mapped(vport, rport); if (status == FAILED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0722 Target Reset rport failure: rdata x%px\n", rdata); if (pnode) { - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(&pnode->lock, flags); pnode->nlp_flag &= ~NLP_NPR_ADISC; pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(&pnode->lock, flags); } lpfc_reset_flush_io_context(vport, tgt_id, lun_id, LPFC_CTX_TGT); @@ -5326,10 +6122,49 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) fc_host_post_vendor_event(shost, fc_get_event_number(), sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); - status = lpfc_send_taskmgmt(vport, cmnd, tgt_id, lun_id, + status = lpfc_send_taskmgmt(vport, rport, tgt_id, lun_id, FCP_TARGET_RESET); + if (status != SUCCESS) { + logit = LOG_TRACE_EVENT; + + /* Issue LOGO, if no LOGO is outstanding */ + spin_lock_irqsave(&pnode->lock, flags); + if (!(pnode->save_flags & NLP_WAIT_FOR_LOGO) && + !pnode->logo_waitq) { + pnode->logo_waitq = &waitq; + pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + pnode->nlp_flag |= NLP_ISSUE_LOGO; + pnode->save_flags |= NLP_WAIT_FOR_LOGO; + spin_unlock_irqrestore(&pnode->lock, flags); + lpfc_unreg_rpi(vport, pnode); + wait_event_timeout(waitq, + (!(pnode->save_flags & + NLP_WAIT_FOR_LOGO)), + msecs_to_jiffies(dev_loss_tmo * + 1000)); + + if (pnode->save_flags & NLP_WAIT_FOR_LOGO) { + lpfc_printf_vlog(vport, KERN_ERR, logit, + "0725 SCSI layer TGTRST " + "failed & LOGO TMO (%d, %llu) " + "return x%x\n", + tgt_id, lun_id, status); + spin_lock_irqsave(&pnode->lock, flags); + pnode->save_flags &= ~NLP_WAIT_FOR_LOGO; + } else { + spin_lock_irqsave(&pnode->lock, flags); + } + pnode->logo_waitq = NULL; + spin_unlock_irqrestore(&pnode->lock, flags); + status = SUCCESS; - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + } else { + spin_unlock_irqrestore(&pnode->lock, flags); + status = FAILED; + } + } + + lpfc_printf_vlog(vport, KERN_ERR, logit, "0723 SCSI layer issued Target Reset (%d, %llu) " "return x%x\n", tgt_id, lun_id, status); @@ -5346,93 +6181,6 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) } /** - * lpfc_bus_reset_handler - scsi_host_template eh_bus_reset_handler entry point - * @cmnd: Pointer to scsi_cmnd data structure. - * - * This routine does target reset to all targets on @cmnd->device->host. - * This emulates Parallel SCSI Bus Reset Semantics. - * - * Return code : - * 0x2003 - Error - * 0x2002 - Success - **/ -static int -lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_nodelist *ndlp = NULL; - struct lpfc_scsi_event_header scsi_event; - int match; - int ret = SUCCESS, status, i; - - scsi_event.event_type = FC_REG_SCSI_EVENT; - scsi_event.subcategory = LPFC_EVENT_BUSRESET; - scsi_event.lun = 0; - memcpy(scsi_event.wwpn, &vport->fc_portname, sizeof(struct lpfc_name)); - memcpy(scsi_event.wwnn, &vport->fc_nodename, sizeof(struct lpfc_name)); - - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); - - status = fc_block_scsi_eh(cmnd); - if (status != 0 && status != SUCCESS) - return status; - - /* - * Since the driver manages a single bus device, reset all - * targets known to the driver. Should any target reset - * fail, this routine returns failure to the midlayer. - */ - for (i = 0; i < LPFC_MAX_TARGET; i++) { - /* Search for mapped node by target ID */ - match = 0; - spin_lock_irq(shost->host_lock); - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (vport->phba->cfg_fcp2_no_tgt_reset && - (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE)) - continue; - if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && - ndlp->nlp_sid == i && - ndlp->rport && - ndlp->nlp_type & NLP_FCP_TARGET) { - match = 1; - break; - } - } - spin_unlock_irq(shost->host_lock); - if (!match) - continue; - - status = lpfc_send_taskmgmt(vport, cmnd, - i, 0, FCP_TARGET_RESET); - - if (status != SUCCESS) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0700 Bus Reset on target %d failed\n", - i); - ret = FAILED; - } - } - /* - * We have to clean up i/o as : they may be orphaned by the TMFs - * above; or if any of the TMFs failed, they may be in an - * indeterminate state. - * We will report success if all the i/o aborts successfully. - */ - - status = lpfc_reset_flush_io_context(vport, 0, 0, LPFC_CTX_HOST); - if (status != SUCCESS) - ret = FAILED; - - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); - return ret; -} - -/** * lpfc_host_reset_handler - scsi_host_template eh_host_reset_handler entry pt * @cmnd: Pointer to scsi_cmnd data structure. * @@ -5465,6 +6213,13 @@ lpfc_host_reset_handler(struct scsi_cmnd *cmnd) if (rc) goto error; + /* Wait for successful restart of adapter */ + if (phba->sli_rev < LPFC_SLI_REV4) { + rc = lpfc_sli_chipset_init(phba); + if (rc) + goto error; + } + rc = lpfc_online(phba); if (rc) goto error; @@ -5473,7 +6228,7 @@ lpfc_host_reset_handler(struct scsi_cmnd *cmnd) return ret; error: - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "3323 Failed host reset\n"); lpfc_unblock_mgmt_io(phba); return FAILED; @@ -5584,7 +6339,7 @@ lpfc_slave_alloc(struct scsi_device *sdev) } num_allocated = lpfc_new_scsi_buf_s3(vport, num_to_alloc); if (num_to_alloc != num_allocated) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0708 Allocation request of %d " "command buffers did not succeed. " "Allocated %d buffers.\n", @@ -5652,10 +6407,11 @@ lpfc_slave_destroy(struct scsi_device *sdev) /** * lpfc_create_device_data - creates and initializes device data structure for OAS - * @pha: Pointer to host bus adapter structure. + * @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. * @@ -5705,7 +6461,7 @@ lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, /** * lpfc_delete_device_data - frees a device data structure for OAS - * @pha: Pointer to host bus adapter structure. + * @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. @@ -5728,7 +6484,7 @@ lpfc_delete_device_data(struct lpfc_hba *phba, /** * __lpfc_get_device_data - returns the device data for the specified lun - * @pha: Pointer to host bus adapter structure. + * @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 @@ -5770,7 +6526,7 @@ __lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list, /** * lpfc_find_next_oas_lun - searches for the next oas lun - * @pha: Pointer to host bus adapter structure. + * @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 @@ -5778,6 +6534,7 @@ __lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list, * @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 @@ -5872,10 +6629,11 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, /** * lpfc_enable_oas_lun - enables a lun for OAS operations - * @pha: Pointer to host bus adapter structure. + * @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 : @@ -5932,10 +6690,11 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, /** * lpfc_disable_oas_lun - disables a lun for OAS operations - * @pha: Pointer to host bus adapter structure. + * @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 : @@ -5987,12 +6746,6 @@ lpfc_no_command(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) } static int -lpfc_no_handler(struct scsi_cmnd *cmnd) -{ - return FAILED; -} - -static int lpfc_no_slave(struct scsi_device *sdev) { return -ENODEV; @@ -6004,46 +6757,16 @@ struct scsi_host_template lpfc_template_nvme = { .proc_name = LPFC_DRIVER_NAME, .info = lpfc_info, .queuecommand = lpfc_no_command, - .eh_abort_handler = lpfc_no_handler, - .eh_device_reset_handler = lpfc_no_handler, - .eh_target_reset_handler = lpfc_no_handler, - .eh_bus_reset_handler = lpfc_no_handler, - .eh_host_reset_handler = lpfc_no_handler, .slave_alloc = lpfc_no_slave, .slave_configure = lpfc_no_slave, .scan_finished = lpfc_scan_finished, .this_id = -1, .sg_tablesize = 1, .cmd_per_lun = 1, - .shost_attrs = lpfc_hba_attrs, - .max_sectors = 0xFFFF, - .vendor_id = LPFC_NL_VENDOR_ID, - .track_queue_depth = 0, -}; - -struct scsi_host_template lpfc_template_no_hr = { - .module = THIS_MODULE, - .name = LPFC_DRIVER_NAME, - .proc_name = LPFC_DRIVER_NAME, - .info = lpfc_info, - .queuecommand = lpfc_queuecommand, - .eh_timed_out = fc_eh_timed_out, - .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler = lpfc_device_reset_handler, - .eh_target_reset_handler = lpfc_target_reset_handler, - .eh_bus_reset_handler = lpfc_bus_reset_handler, - .slave_alloc = lpfc_slave_alloc, - .slave_configure = lpfc_slave_configure, - .slave_destroy = lpfc_slave_destroy, - .scan_finished = lpfc_scan_finished, - .this_id = -1, - .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, - .cmd_per_lun = LPFC_CMD_PER_LUN, - .shost_attrs = lpfc_hba_attrs, + .shost_groups = lpfc_hba_groups, .max_sectors = 0xFFFFFFFF, .vendor_id = LPFC_NL_VENDOR_ID, - .change_queue_depth = scsi_change_queue_depth, - .track_queue_depth = 1, + .track_queue_depth = 0, }; struct scsi_host_template lpfc_template = { @@ -6053,10 +6776,10 @@ struct scsi_host_template lpfc_template = { .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_timed_out = fc_eh_timed_out, + .eh_should_retry_cmd = fc_eh_should_retry_cmd, .eh_abort_handler = lpfc_abort_handler, .eh_device_reset_handler = lpfc_device_reset_handler, .eh_target_reset_handler = lpfc_target_reset_handler, - .eh_bus_reset_handler = lpfc_bus_reset_handler, .eh_host_reset_handler = lpfc_host_reset_handler, .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, @@ -6065,8 +6788,8 @@ struct scsi_host_template lpfc_template = { .this_id = -1, .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, - .shost_attrs = lpfc_hba_attrs, - .max_sectors = 0xFFFF, + .shost_groups = lpfc_hba_groups, + .max_sectors = 0xFFFFFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .change_queue_depth = scsi_change_queue_depth, .track_queue_depth = 1, @@ -6079,9 +6802,12 @@ struct scsi_host_template lpfc_vport_template = { .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_timed_out = fc_eh_timed_out, + .eh_should_retry_cmd = fc_eh_should_retry_cmd, .eh_abort_handler = lpfc_abort_handler, .eh_device_reset_handler = lpfc_device_reset_handler, .eh_target_reset_handler = lpfc_target_reset_handler, + .eh_bus_reset_handler = NULL, + .eh_host_reset_handler = NULL, .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, .slave_destroy = lpfc_slave_destroy, @@ -6089,8 +6815,9 @@ struct scsi_host_template lpfc_vport_template = { .this_id = -1, .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, - .shost_attrs = lpfc_vport_attrs, - .max_sectors = 0xFFFF, + .shost_groups = lpfc_vport_groups, + .max_sectors = 0xFFFFFFFF, + .vendor_id = 0, .change_queue_depth = scsi_change_queue_depth, .track_queue_depth = 1, }; diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index f76667b7da7b..eae56944f31b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -126,10 +126,6 @@ struct fcp_cmnd { }; -struct lpfc_scsicmd_bkt { - uint32_t cmd_count; -}; - #define LPFC_SCSI_DMA_EXT_SIZE 264 #define LPFC_BPL_SIZE 1024 #define MDAC_DIRECT_CMD 0x22 @@ -142,6 +138,10 @@ struct lpfc_scsicmd_bkt { #define FC_PORTSPEED_128GBIT 0x2000 #endif +#ifndef FC_PORTSPEED_256GBIT +#define FC_PORTSPEED_256GBIT 0x4000 +#endif + #define TXRDY_PAYLOAD_LEN 12 /* For sysfs/debugfs tmp string max len */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 64002b0cb02d..99d06dc7ddf6 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,8 +1,8 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * - * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * + * Copyright (C) 2017-2022 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 * @@ -35,12 +35,11 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> #include <linux/aer.h> +#include <linux/crash_dump.h> #ifdef CONFIG_X86 #include <asm/set_memory.h> #endif -#include <linux/nvme-fc-driver.h> - #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_sli.h" @@ -50,7 +49,6 @@ #include "lpfc.h" #include "lpfc_scsi.h" #include "lpfc_nvme.h" -#include "lpfc_nvmet.h" #include "lpfc_crtn.h" #include "lpfc_logmsg.h" #include "lpfc_compat.h" @@ -72,8 +70,9 @@ static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); static int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *, uint8_t *, uint32_t *); -static struct lpfc_iocbq *lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *, - struct lpfc_iocbq *); +static struct lpfc_iocbq * +lpfc_sli4_els_preprocess_rspiocbq(struct lpfc_hba *phba, + struct lpfc_iocbq *rspiocbq); static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *, struct hbq_dmabuf *); static void lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport, @@ -91,11 +90,134 @@ static struct lpfc_cqe *lpfc_sli4_cq_get(struct lpfc_queue *q); static void __lpfc_sli4_consume_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_cqe *cqe); +static uint16_t lpfc_wqe_bpl2sgl(struct lpfc_hba *phba, + struct lpfc_iocbq *pwqeq, + struct lpfc_sglq *sglq); -static IOCB_t * -lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) +union lpfc_wqe128 lpfc_iread_cmd_template; +union lpfc_wqe128 lpfc_iwrite_cmd_template; +union lpfc_wqe128 lpfc_icmnd_cmd_template; + +/* Setup WQE templates for IOs */ +void lpfc_wqe_cmd_template(void) { - return &iocbq->iocb; + union lpfc_wqe128 *wqe; + + /* IREAD template */ + wqe = &lpfc_iread_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - cmd_buff_len, payload_offset_len is zero */ + + /* Word 4 - total_xfer_len is variable */ + + /* Word 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_iread.wqe_com, CMD_FCP_IREAD64_WQE); + bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, PARM_READ_CHECK); + bf_set(wqe_class, &wqe->fcp_iread.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_iread.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0); + bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); + bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4); + bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1); + + /* Word 11 - pbde is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, COMMAND_DATA_IN); + bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 0); + + /* Word 12 - is zero */ + + /* Word 13, 14, 15 - PBDE is variable */ + + /* IWRITE template */ + wqe = &lpfc_iwrite_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - cmd_buff_len, payload_offset_len is zero */ + + /* Word 4 - total_xfer_len is variable */ + + /* Word 5 - initial_xfer_len is variable */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_iwrite.wqe_com, CMD_FCP_IWRITE64_WQE); + bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, PARM_READ_CHECK); + bf_set(wqe_class, &wqe->fcp_iwrite.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_iwrite.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0); + bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); + bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4); + bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); + + /* Word 11 - pbde is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, COMMAND_DATA_OUT); + bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0); + + /* Word 12 - is zero */ + + /* Word 13, 14, 15 - PBDE is variable */ + + /* ICMND template */ + wqe = &lpfc_icmnd_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - payload_offset_len is variable */ + + /* Word 4, 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_icmd.wqe_com, CMD_FCP_ICMND64_WQE); + bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_icmd.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1); + bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_NONE); + bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE); + bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1); + + /* Word 11 */ + bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, COMMAND_DATA_IN); + bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0); + + /* Word 12, 13, 14, 15 - is zero */ } #if defined(CONFIG_64BIT) && defined(__LITTLE_ENDIAN) @@ -152,6 +274,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) /* sanity check on queue memory */ if (unlikely(!q)) return -ENOMEM; + temp_wqe = lpfc_sli4_qe(q, q->host_index); /* If the host has not yet processed the next entry then we are done */ @@ -230,31 +353,22 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) * This routine will update the HBA index of a queue to reflect consumption of * Work Queue Entries by the HBA. When the HBA indicates that it has consumed * an entry the host calls this function to update the queue's internal - * pointers. This routine returns the number of entries that were consumed by - * the HBA. + * pointers. **/ -static uint32_t +static void lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index) { - uint32_t released = 0; - /* sanity check on queue memory */ if (unlikely(!q)) - return 0; + return; - if (q->hba_index == index) - return 0; - do { - q->hba_index = ((q->hba_index + 1) % q->entry_count); - released++; - } while (q->hba_index != index); - return released; + q->hba_index = index; } /** * lpfc_sli4_mq_put - Put a Mailbox Queue Entry on an Mailbox Queue * @q: The Mailbox Queue to operate on. - * @wqe: The Mailbox Queue Entry to put on the Work queue. + * @mqe: The Mailbox Queue Entry to put on the Work queue. * * This routine will copy the contents of @mqe to the next available entry on * the @q. This function will then ring the Work Queue Doorbell to signal the @@ -547,7 +661,7 @@ lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq, if (count > eq->EQ_max_eqe) eq->EQ_max_eqe = count; - eq->queue_claimed = 0; + xchg(&eq->queue_claimed, 0); rearm_and_exit: /* Always clear the EQ. */ @@ -668,10 +782,8 @@ lpfc_sli4_if6_write_cq_db(struct lpfc_hba *phba, struct lpfc_queue *q, writel(doorbell.word0, q->phba->sli4_hba.CQDBregaddr); } -/** +/* * lpfc_sli4_rq_put - Put a Receive Buffer Queue Entry on a Receive Queue - * @q: The Header Receive Queue to operate on. - * @wqe: The Receive Queue Entry to put on the Receive queue. * * This routine will copy the contents of @wqe to the next available entry on * the @q. This function will then ring the Receive Queue Doorbell to signal the @@ -734,9 +846,8 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, return hq_put_index; } -/** +/* * lpfc_sli4_rq_release - Updates internal hba index for RQ - * @q: The Header Receive Queue to operate on. * * This routine will update the HBA index of a queue to reflect consumption of * one Receive Queue Entry by the HBA. When the HBA indicates that it has @@ -822,7 +933,7 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba) * @phba: Pointer to HBA context object. * @xritag: XRI value. * - * This function clears the sglq pointer from the array of acive + * This function clears the sglq pointer from the array of active * sglq's. The xritag that is passed in is used to index into the * array. Before the xritag can be used it needs to be adjusted * by subtracting the xribase. @@ -844,7 +955,7 @@ __lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag) * @phba: Pointer to HBA context object. * @xritag: XRI value. * - * This function returns the sglq pointer from the array of acive + * This function returns the sglq pointer from the array of active * sglq's. The xritag that is passed in is used to index into the * array. Before the xritag can be used it needs to be adjusted * by subtracting the xribase. @@ -874,16 +985,10 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba, { struct lpfc_nodelist *ndlp = NULL; - if ((rrq->vport) && NLP_CHK_NODE_ACT(rrq->ndlp)) + /* Lookup did to verify if did is still active on this vport */ + if (rrq->vport) ndlp = lpfc_findnode_did(rrq->vport, rrq->nlp_DID); - /* The target DID could have been swapped (cable swap) - * we should use the ndlp from the findnode if it is - * available. - */ - if ((!ndlp) && rrq->ndlp) - ndlp = rrq->ndlp; - if (!ndlp) goto out; @@ -1005,9 +1110,14 @@ lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_sli4_vport_delete_fcp_xri_aborted(vport); } spin_lock_irqsave(&phba->hbalock, iflags); - list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) - if ((rrq->vport == vport) && (!ndlp || rrq->ndlp == ndlp)) + list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) { + if (rrq->vport != vport) + continue; + + if (!ndlp || ndlp == lpfc_findnode_did(vport, rrq->nlp_DID)) list_move(&rrq->list, &rrq_list); + + } spin_unlock_irqrestore(&phba->hbalock, iflags); list_for_each_entry_safe(rrq, nextrrq, &rrq_list, list) { @@ -1020,7 +1130,7 @@ lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * lpfc_test_rrq_active - Test RRQ bit in xri_bitmap. * @phba: Pointer to HBA context object. * @ndlp: Targets nodelist pointer for this exchange. - * @xritag the xri in the bitmap to test. + * @xritag: the xri in the bitmap to test. * * This function returns: * 0 = rrq not active for this xri @@ -1075,12 +1185,6 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, goto out; } - /* - * set the active bit even if there is no mem available. - */ - if (NLP_CHK_FREE_REQ(ndlp)) - goto out; - if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING)) goto out; @@ -1091,7 +1195,7 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, goto out; spin_unlock_irqrestore(&phba->hbalock, iflags); - rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL); + rrq = mempool_alloc(phba->rrq_pool, GFP_ATOMIC); if (!rrq) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3155 Unable to allocate RRQ xri:0x%x rxid:0x%x" @@ -1106,7 +1210,6 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, rrq->xritag = xritag; rrq->rrq_stop_time = jiffies + msecs_to_jiffies(1000 * (phba->fc_ratov + 1)); - rrq->ndlp = ndlp; rrq->nlp_DID = ndlp->nlp_DID; rrq->vport = ndlp->vport; rrq->rxid = rxid; @@ -1130,7 +1233,7 @@ out: /** * __lpfc_sli_get_els_sglq - Allocates an iocb object from sgl pool * @phba: Pointer to HBA context object. - * @piocb: Pointer to the iocbq. + * @piocbq: Pointer to the iocbq. * * The driver calls this function with either the nvme ls ring lock * or the fc els ring lock held depending on the iocb usage. This function @@ -1146,29 +1249,24 @@ __lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) struct lpfc_sglq *start_sglq = NULL; struct lpfc_io_buf *lpfc_cmd; struct lpfc_nodelist *ndlp; - struct lpfc_sli_ring *pring = NULL; int found = 0; + u8 cmnd; - if (piocbq->iocb_flag & LPFC_IO_NVME_LS) - pring = phba->sli4_hba.nvmels_wq->pring; - else - pring = lpfc_phba_elsring(phba); - - lockdep_assert_held(&pring->ring_lock); + cmnd = get_job_cmnd(phba, piocbq); - if (piocbq->iocb_flag & LPFC_IO_FCP) { - lpfc_cmd = (struct lpfc_io_buf *) piocbq->context1; + if (piocbq->cmd_flag & LPFC_IO_FCP) { + lpfc_cmd = piocbq->io_buf; ndlp = lpfc_cmd->rdata->pnode; - } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) && - !(piocbq->iocb_flag & LPFC_IO_LIBDFC)) { - ndlp = piocbq->context_un.ndlp; - } else if (piocbq->iocb_flag & LPFC_IO_LIBDFC) { - if (piocbq->iocb_flag & LPFC_IO_LOOPBACK) + } else if ((cmnd == CMD_GEN_REQUEST64_CR) && + !(piocbq->cmd_flag & LPFC_IO_LIBDFC)) { + ndlp = piocbq->ndlp; + } else if (piocbq->cmd_flag & LPFC_IO_LIBDFC) { + if (piocbq->cmd_flag & LPFC_IO_LOOPBACK) ndlp = NULL; else - ndlp = piocbq->context_un.ndlp; + ndlp = piocbq->ndlp; } else { - ndlp = piocbq->context1; + ndlp = piocbq->ndlp; } spin_lock(&phba->sli4_hba.sgl_list_lock); @@ -1206,7 +1304,7 @@ __lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) /** * __lpfc_sli_get_nvmet_sglq - Allocates an iocb object from sgl pool * @phba: Pointer to HBA context object. - * @piocb: Pointer to the iocbq. + * @piocbq: Pointer to the iocbq. * * This function is called with the sgl_list lock held. This function * gets a new driver sglq object from the sglq list. If the @@ -1257,8 +1355,8 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba) * @phba: Pointer to HBA context object. * @iocbq: Pointer to driver iocb object. * - * This function is called with hbalock held to release driver - * iocb object to the iocb pool. The iotag in the iocb object + * This function is called to release the driver iocb object + * to the iocb pool. The iotag in the iocb object * does not change for each use of the iocb object. This function * clears all other fields of the iocb object when it is freed. * The sqlq structure that holds the xritag and phys and virtual @@ -1268,18 +1366,17 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba) * this IO was aborted then the sglq entry it put on the * lpfc_abts_els_sgl_list until the CQ_ABORTED_XRI is received. If the * IO has good status or fails for any other reason then the sglq - * entry is added to the free list (lpfc_els_sgl_list). + * entry is added to the free list (lpfc_els_sgl_list). The hbalock is + * asserted held in the code path calling this routine. **/ static void __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { struct lpfc_sglq *sglq; - size_t start_clean = offsetof(struct lpfc_iocbq, iocb); + size_t start_clean = offsetof(struct lpfc_iocbq, wqe); unsigned long iflag = 0; struct lpfc_sli_ring *pring; - lockdep_assert_held(&phba->hbalock); - if (iocbq->sli4_xritag == NO_XRI) sglq = NULL; else @@ -1287,7 +1384,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) if (sglq) { - if (iocbq->iocb_flag & LPFC_IO_NVMET) { + if (iocbq->cmd_flag & LPFC_IO_NVMET) { spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock, iflag); sglq->state = SGL_FREED; @@ -1299,11 +1396,16 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) goto out; } - pring = phba->sli4_hba.els_wq->pring; - if ((iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) && - (sglq->state != SGL_XRI_ABORTED)) { + if ((iocbq->cmd_flag & LPFC_EXCHANGE_BUSY) && + (!(unlikely(pci_channel_offline(phba->pcidev)))) && + sglq->state != SGL_XRI_ABORTED) { spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock, iflag); + + /* Check if we can get a reference on ndlp */ + if (sglq->ndlp && !lpfc_nlp_get(sglq->ndlp)) + sglq->ndlp = NULL; + list_add(&sglq->list, &phba->sli4_hba.lpfc_abts_els_sgl_list); spin_unlock_irqrestore( @@ -1317,9 +1419,9 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) &phba->sli4_hba.lpfc_els_sgl_list); spin_unlock_irqrestore( &phba->sli4_hba.sgl_list_lock, iflag); - + pring = lpfc_phba_elsring(phba); /* Check if TXQ queue needs to be serviced */ - if (!list_empty(&pring->txq)) + if (pring && (!list_empty(&pring->txq))) lpfc_worker_wake_up(phba); } } @@ -1331,7 +1433,7 @@ out: memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); iocbq->sli4_lxritag = NO_XRI; iocbq->sli4_xritag = NO_XRI; - iocbq->iocb_flag &= ~(LPFC_IO_NVME | LPFC_IO_NVMET | + iocbq->cmd_flag &= ~(LPFC_IO_NVME | LPFC_IO_NVMET | LPFC_IO_CMF | LPFC_IO_NVME_LS); list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); } @@ -1342,18 +1444,17 @@ out: * @phba: Pointer to HBA context object. * @iocbq: Pointer to driver iocb object. * - * This function is called with hbalock held to release driver - * iocb object to the iocb pool. The iotag in the iocb object - * does not change for each use of the iocb object. This function - * clears all other fields of the iocb object when it is freed. + * This function is called to release the driver iocb object to the + * iocb pool. The iotag in the iocb object does not change for each + * use of the iocb object. This function clears all other fields of + * the iocb object when it is freed. The hbalock is asserted held in + * the code path calling this routine. **/ static void __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { size_t start_clean = offsetof(struct lpfc_iocbq, iocb); - lockdep_assert_held(&phba->hbalock); - /* * Clean all volatile data fields, preserve iotag and node struct. */ @@ -1422,15 +1523,23 @@ lpfc_sli_cancel_iocbs(struct lpfc_hba *phba, struct list_head *iocblist, while (!list_empty(iocblist)) { list_remove_head(iocblist, piocb, struct lpfc_iocbq, list); - if (!piocb->iocb_cmpl) { - if (piocb->iocb_flag & LPFC_IO_NVME) - lpfc_nvme_cancel_iocb(phba, piocb); - else - lpfc_sli_release_iocbq(phba, piocb); + if (piocb->cmd_cmpl) { + if (piocb->cmd_flag & LPFC_IO_NVME) { + lpfc_nvme_cancel_iocb(phba, piocb, + ulpstatus, ulpWord4); + } else { + if (phba->sli_rev == LPFC_SLI_REV4) { + bf_set(lpfc_wcqe_c_status, + &piocb->wcqe_cmpl, ulpstatus); + piocb->wcqe_cmpl.parameter = ulpWord4; + } else { + piocb->iocb.ulpStatus = ulpstatus; + piocb->iocb.un.ulpWord[4] = ulpWord4; + } + (piocb->cmd_cmpl) (phba, piocb, piocb); + } } else { - piocb->iocb.ulpStatus = ulpstatus; - piocb->iocb.un.ulpWord[4] = ulpWord4; - (piocb->iocb_cmpl) (phba, piocb, piocb); + lpfc_sli_release_iocbq(phba, piocb); } } return; @@ -1505,6 +1614,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case DSSCMD_IWRITE64_CX: case DSSCMD_IREAD64_CR: case DSSCMD_IREAD64_CX: + case CMD_SEND_FRAME: type = LPFC_SOL_IOCB; break; case CMD_ABORT_XRI_CN: @@ -1579,7 +1689,7 @@ lpfc_sli_ring_map(struct lpfc_hba *phba) lpfc_config_ring(phba, i, pmb); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0446 Adapter failed to init (%d), " "mbxCmd x%x CFG_RING, mbxStatus x%x, " "ring %d\n", @@ -1611,20 +1721,18 @@ static int lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { - if (phba->sli_rev == LPFC_SLI_REV4) - lockdep_assert_held(&pring->ring_lock); - else - lockdep_assert_held(&phba->hbalock); + u32 ulp_command = 0; BUG_ON(!piocb); + ulp_command = get_job_cmnd(phba, piocb); list_add_tail(&piocb->list, &pring->txcmplq); - piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ; + piocb->cmd_flag |= LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt++; - if ((unlikely(pring->ringno == LPFC_ELS_RING)) && - (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && - (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) { + (ulp_command != CMD_ABORT_XRI_WQE) && + (ulp_command != CMD_ABORT_XRI_CN) && + (ulp_command != CMD_CLOSE_XRI_CN)) { BUG_ON(!piocb->vport); if (!(piocb->vport->load_flag & FC_UNLOADING)) mod_timer(&piocb->vport->els_tmofunc, @@ -1657,6 +1765,262 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) } /** + * lpfc_cmf_sync_cmpl - Process a CMF_SYNC_WQE cmpl + * @phba: Pointer to HBA context object. + * @cmdiocb: Pointer to driver command iocb object. + * @rspiocb: Pointer to driver response iocb object. + * + * This routine will inform the driver of any BW adjustments we need + * to make. These changes will be picked up during the next CMF + * timer interrupt. In addition, any BW changes will be logged + * with LOG_CGN_MGMT. + **/ +static void +lpfc_cmf_sync_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + union lpfc_wqe128 *wqe; + uint32_t status, info; + struct lpfc_wcqe_complete *wcqe = &rspiocb->wcqe_cmpl; + uint64_t bw, bwdif, slop; + uint64_t pcent, bwpcent; + int asig, afpin, sigcnt, fpincnt; + int wsigmax, wfpinmax, cg, tdp; + char *s; + + /* First check for error */ + status = bf_get(lpfc_wcqe_c_status, wcqe); + if (status) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6211 CMF_SYNC_WQE Error " + "req_tag x%x status x%x hwstatus x%x " + "tdatap x%x parm x%x\n", + bf_get(lpfc_wcqe_c_request_tag, wcqe), + bf_get(lpfc_wcqe_c_status, wcqe), + bf_get(lpfc_wcqe_c_hw_status, wcqe), + wcqe->total_data_placed, + wcqe->parameter); + goto out; + } + + /* Gather congestion information on a successful cmpl */ + info = wcqe->parameter; + phba->cmf_active_info = info; + + /* See if firmware info count is valid or has changed */ + if (info > LPFC_MAX_CMF_INFO || phba->cmf_info_per_interval == info) + info = 0; + else + phba->cmf_info_per_interval = info; + + tdp = bf_get(lpfc_wcqe_c_cmf_bw, wcqe); + cg = bf_get(lpfc_wcqe_c_cmf_cg, wcqe); + + /* Get BW requirement from firmware */ + bw = (uint64_t)tdp * LPFC_CMF_BLK_SIZE; + if (!bw) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6212 CMF_SYNC_WQE x%x: NULL bw\n", + bf_get(lpfc_wcqe_c_request_tag, wcqe)); + goto out; + } + + /* Gather information needed for logging if a BW change is required */ + wqe = &cmdiocb->wqe; + asig = bf_get(cmf_sync_asig, &wqe->cmf_sync); + afpin = bf_get(cmf_sync_afpin, &wqe->cmf_sync); + fpincnt = bf_get(cmf_sync_wfpincnt, &wqe->cmf_sync); + sigcnt = bf_get(cmf_sync_wsigcnt, &wqe->cmf_sync); + if (phba->cmf_max_bytes_per_interval != bw || + (asig || afpin || sigcnt || fpincnt)) { + /* Are we increasing or decreasing BW */ + if (phba->cmf_max_bytes_per_interval < bw) { + bwdif = bw - phba->cmf_max_bytes_per_interval; + s = "Increase"; + } else { + bwdif = phba->cmf_max_bytes_per_interval - bw; + s = "Decrease"; + } + + /* What is the change percentage */ + slop = div_u64(phba->cmf_link_byte_count, 200); /*For rounding*/ + pcent = div64_u64(bwdif * 100 + slop, + phba->cmf_link_byte_count); + bwpcent = div64_u64(bw * 100 + slop, + phba->cmf_link_byte_count); + if (asig) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6237 BW Threshold %lld%% (%lld): " + "%lld%% %s: Signal Alarm: cg:%d " + "Info:%u\n", + bwpcent, bw, pcent, s, cg, + phba->cmf_active_info); + } else if (afpin) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6238 BW Threshold %lld%% (%lld): " + "%lld%% %s: FPIN Alarm: cg:%d " + "Info:%u\n", + bwpcent, bw, pcent, s, cg, + phba->cmf_active_info); + } else if (sigcnt) { + wsigmax = bf_get(cmf_sync_wsigmax, &wqe->cmf_sync); + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6239 BW Threshold %lld%% (%lld): " + "%lld%% %s: Signal Warning: " + "Cnt %d Max %d: cg:%d Info:%u\n", + bwpcent, bw, pcent, s, sigcnt, + wsigmax, cg, phba->cmf_active_info); + } else if (fpincnt) { + wfpinmax = bf_get(cmf_sync_wfpinmax, &wqe->cmf_sync); + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6240 BW Threshold %lld%% (%lld): " + "%lld%% %s: FPIN Warning: " + "Cnt %d Max %d: cg:%d Info:%u\n", + bwpcent, bw, pcent, s, fpincnt, + wfpinmax, cg, phba->cmf_active_info); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6241 BW Threshold %lld%% (%lld): " + "CMF %lld%% %s: cg:%d Info:%u\n", + bwpcent, bw, pcent, s, cg, + phba->cmf_active_info); + } + } else if (info) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6246 Info Threshold %u\n", info); + } + + /* Save BW change to be picked up during next timer interrupt */ + phba->cmf_last_sync_bw = bw; +out: + lpfc_sli_release_iocbq(phba, cmdiocb); +} + +/** + * lpfc_issue_cmf_sync_wqe - Issue a CMF_SYNC_WQE + * @phba: Pointer to HBA context object. + * @ms: ms to set in WQE interval, 0 means use init op + * @total: Total rcv bytes for this interval + * + * This routine is called every CMF timer interrupt. Its purpose is + * to issue a CMF_SYNC_WQE to the firmware to inform it of any events + * that may indicate we have congestion (FPINs or Signals). Upon + * completion, the firmware will indicate any BW restrictions the + * driver may need to take. + **/ +int +lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total) +{ + union lpfc_wqe128 *wqe; + struct lpfc_iocbq *sync_buf; + unsigned long iflags; + u32 ret_val; + u32 atot, wtot, max; + u16 warn_sync_period = 0; + + /* First address any alarm / warning activity */ + atot = atomic_xchg(&phba->cgn_sync_alarm_cnt, 0); + wtot = atomic_xchg(&phba->cgn_sync_warn_cnt, 0); + + /* ONLY Managed mode will send the CMF_SYNC_WQE to the HBA */ + if (phba->cmf_active_mode != LPFC_CFG_MANAGED || + phba->link_state == LPFC_LINK_DOWN) + return 0; + + spin_lock_irqsave(&phba->hbalock, iflags); + sync_buf = __lpfc_sli_get_iocbq(phba); + if (!sync_buf) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT, + "6244 No available WQEs for CMF_SYNC_WQE\n"); + ret_val = ENOMEM; + goto out_unlock; + } + + wqe = &sync_buf->wqe; + + /* WQEs are reused. Clear stale data and set key fields to zero */ + memset(wqe, 0, sizeof(*wqe)); + + /* If this is the very first CMF_SYNC_WQE, issue an init operation */ + if (!ms) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6441 CMF Init %d - CMF_SYNC_WQE\n", + phba->fc_eventTag); + bf_set(cmf_sync_op, &wqe->cmf_sync, 1); /* 1=init */ + bf_set(cmf_sync_interval, &wqe->cmf_sync, LPFC_CMF_INTERVAL); + goto initpath; + } + + bf_set(cmf_sync_op, &wqe->cmf_sync, 0); /* 0=recalc */ + bf_set(cmf_sync_interval, &wqe->cmf_sync, ms); + + /* Check for alarms / warnings */ + if (atot) { + if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) { + /* We hit an Signal alarm condition */ + bf_set(cmf_sync_asig, &wqe->cmf_sync, 1); + } else { + /* We hit a FPIN alarm condition */ + bf_set(cmf_sync_afpin, &wqe->cmf_sync, 1); + } + } else if (wtot) { + if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY || + phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) { + /* We hit an Signal warning condition */ + max = LPFC_SEC_TO_MSEC / lpfc_fabric_cgn_frequency * + lpfc_acqe_cgn_frequency; + bf_set(cmf_sync_wsigmax, &wqe->cmf_sync, max); + bf_set(cmf_sync_wsigcnt, &wqe->cmf_sync, wtot); + warn_sync_period = lpfc_acqe_cgn_frequency; + } else { + /* We hit a FPIN warning condition */ + bf_set(cmf_sync_wfpinmax, &wqe->cmf_sync, 1); + bf_set(cmf_sync_wfpincnt, &wqe->cmf_sync, 1); + if (phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) + warn_sync_period = + LPFC_MSECS_TO_SECS(phba->cgn_fpin_frequency); + } + } + + /* Update total read blocks during previous timer interval */ + wqe->cmf_sync.read_bytes = (u32)(total / LPFC_CMF_BLK_SIZE); + +initpath: + bf_set(cmf_sync_ver, &wqe->cmf_sync, LPFC_CMF_SYNC_VER); + wqe->cmf_sync.event_tag = phba->fc_eventTag; + bf_set(cmf_sync_cmnd, &wqe->cmf_sync, CMD_CMF_SYNC_WQE); + + /* Setup reqtag to match the wqe completion. */ + bf_set(cmf_sync_reqtag, &wqe->cmf_sync, sync_buf->iotag); + + bf_set(cmf_sync_qosd, &wqe->cmf_sync, 1); + bf_set(cmf_sync_period, &wqe->cmf_sync, warn_sync_period); + + bf_set(cmf_sync_cmd_type, &wqe->cmf_sync, CMF_SYNC_COMMAND); + bf_set(cmf_sync_wqec, &wqe->cmf_sync, 1); + bf_set(cmf_sync_cqid, &wqe->cmf_sync, LPFC_WQE_CQ_ID_DEFAULT); + + sync_buf->vport = phba->pport; + sync_buf->cmd_cmpl = lpfc_cmf_sync_cmpl; + sync_buf->cmd_dmabuf = NULL; + sync_buf->rsp_dmabuf = NULL; + sync_buf->bpl_dmabuf = NULL; + sync_buf->sli4_xritag = NO_XRI; + + sync_buf->cmd_flag |= LPFC_IO_CMF; + ret_val = lpfc_sli4_issue_wqe(phba, &phba->sli4_hba.hdwq[0], sync_buf); + if (ret_val) { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "6214 Cannot issue CMF_SYNC_WQE: x%x\n", + ret_val); + __lpfc_sli_release_iocbq(phba, sync_buf); + } +out_unlock: + spin_unlock_irqrestore(&phba->hbalock, iflags); + return ret_val; +} + +/** * lpfc_sli_next_iocb_slot - Get next iocb slot in the ring * @phba: Pointer to HBA context object. * @pring: Pointer to driver SLI ring object. @@ -1688,7 +2052,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) pring->sli.sli3.local_getidx = le32_to_cpu(pgp->cmdGetInx); if (unlikely(pring->sli.sli3.local_getidx >= max_cmd_idx)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0315 Ring %d issue: portCmdGet %d " "is bigger than cmd ring %d\n", pring->ringno, @@ -1798,21 +2162,21 @@ lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) * @nextiocb: Pointer to driver iocb object which need to be * posted to firmware. * - * This function is called with hbalock held to post a new iocb to - * the firmware. This function copies the new iocb to ring iocb slot and - * updates the ring pointers. It adds the new iocb to txcmplq if there is + * This function is called to post a new iocb to the firmware. This + * function copies the new iocb to ring iocb slot and updates the + * ring pointers. It adds the new iocb to txcmplq if there is * a completion call back for this iocb else the function will free the - * iocb object. + * iocb object. The hbalock is asserted held in the code path calling + * this routine. **/ static void lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, IOCB_t *iocb, struct lpfc_iocbq *nextiocb) { - lockdep_assert_held(&phba->hbalock); /* * Set up an iotag */ - nextiocb->iocb.ulpIoTag = (nextiocb->iocb_cmpl) ? nextiocb->iotag : 0; + nextiocb->iocb.ulpIoTag = (nextiocb->cmd_cmpl) ? nextiocb->iotag : 0; if (pring->ringno == LPFC_ELS_RING) { @@ -1833,9 +2197,9 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* * If there is no completion routine to call, we can release the * IOCB buffer back right now. For IOCBs, like QUE_RING_BUF, - * that have no rsp ring completion, iocb_cmpl MUST be NULL. + * that have no rsp ring completion, cmd_cmpl MUST be NULL. */ - if (nextiocb->iocb_cmpl) + if (nextiocb->cmd_cmpl) lpfc_sli_ringtxcmpl_put(phba, pring, nextiocb); else __lpfc_sli_release_iocbq(phba, nextiocb); @@ -1974,8 +2338,7 @@ lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno) hbqp->local_hbqGetIdx = getidx; if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) { - lpfc_printf_log(phba, KERN_ERR, - LOG_SLI | LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1802 HBQ %d: local_hbqGetIdx " "%u is > than hbqp->entry_count %u\n", hbqno, hbqp->local_hbqGetIdx, @@ -2243,10 +2606,8 @@ lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno) lpfc_hbq_defs[qno]->init_count); } -/** +/* * lpfc_sli_hbqbuf_get - Remove the first hbq off of an hbq list - * @phba: Pointer to HBA context object. - * @hbqno: HBQ number. * * This function removes the first hbq buffer on an hbq list and returns a * pointer to that buffer. If it finds no buffers on the list it returns NULL. @@ -2265,7 +2626,7 @@ lpfc_sli_hbqbuf_get(struct list_head *rb_list) /** * lpfc_sli_rqbuf_get - Remove the first dma buffer off of an RQ list * @phba: Pointer to HBA context object. - * @hbqno: HBQ number. + * @hrq: HBQ number. * * This function removes the first RQ buffer on an RQ buffer list and returns a * pointer to that buffer. If it finds no buffers on the list it returns NULL. @@ -2314,7 +2675,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) } } spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1803 Bad hbq tag. Data: x%x x%x\n", tag, phba->hbqs[tag >> 16].buffer_count); return NULL; @@ -2467,14 +2828,20 @@ __lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->nlp_flag & NLP_RELEASE_RPI) { lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); - spin_lock_irqsave(&vport->phba->ndlp_lock, iflags); + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag &= ~NLP_RELEASE_RPI; ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - spin_unlock_irqrestore(&vport->phba->ndlp_lock, iflags); + spin_unlock_irqrestore(&ndlp->lock, iflags); } ndlp->nlp_flag &= ~NLP_UNREG_INP; } +void +lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + __lpfc_sli_rpi_release(vport, ndlp); +} + /** * lpfc_sli_def_mbox_cmpl - Default mailbox completion handler * @phba: Pointer to HBA context object. @@ -2495,13 +2862,6 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) uint16_t rpi, vpi; int rc; - mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); - - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - /* * If a REG_LOGIN succeeded after node is destroyed or node * is in re-discovery driver need to cleanup the RPI. @@ -2509,8 +2869,16 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (!(phba->pport->load_flag & FC_UNLOADING) && pmb->u.mb.mbxCommand == MBX_REG_LOGIN64 && !pmb->u.mb.mbxStatus) { + mp = (struct lpfc_dmabuf *)pmb->ctx_buf; + if (mp) { + pmb->ctx_buf = NULL; + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } rpi = pmb->u.mb.un.varWords[0]; vpi = pmb->u.mb.un.varRegLogin.vpi; + if (phba->sli_rev == LPFC_SLI_REV4) + vpi -= phba->sli4_hba.max_cfg_param.vpi_base; lpfc_unreg_login(phba, vpi, rpi, pmb); pmb->vport = vport; pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; @@ -2532,8 +2900,6 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) { ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; lpfc_nlp_put(ndlp); - pmb->ctx_buf = NULL; - pmb->ctx_ndlp = NULL; } if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) { @@ -2545,9 +2911,10 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport, KERN_INFO, LOG_MBOX | LOG_DISCOVERY, "1438 UNREG cmpl deferred mbox x%x " - "on NPort x%x Data: x%x x%x %px\n", + "on NPort x%x Data: x%x x%x x%px x%x x%x\n", ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, ndlp->nlp_defer_did, ndlp); + ndlp->nlp_flag, ndlp->nlp_defer_did, + ndlp, vport->load_flag, kref_read(&ndlp->kref)); if ((ndlp->nlp_flag & NLP_UNREG_INP) && (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) { @@ -2557,23 +2924,33 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { __lpfc_sli_rpi_release(vport, ndlp); } - if (vport->load_flag & FC_UNLOADING) - lpfc_nlp_put(ndlp); + + /* The unreg_login mailbox is complete and had a + * reference that has to be released. The PLOGI + * got its own ref. + */ + lpfc_nlp_put(ndlp); pmb->ctx_ndlp = NULL; } } + /* This nlp_put pairs with lpfc_sli4_resume_rpi */ + if (pmb->u.mb.mbxCommand == MBX_RESUME_RPI) { + ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; + lpfc_nlp_put(ndlp); + } + /* Check security permission status on INIT_LINK mailbox command */ if ((pmb->u.mb.mbxCommand == MBX_INIT_LINK) && (pmb->u.mb.mbxStatus == MBXERR_SEC_NO_PERMISSION)) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2860 SLI authentication is required " "for INIT_LINK but has not done yet\n"); if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG) lpfc_sli4_mbox_cmd_free(phba, pmb); else - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); } /** * lpfc_sli4_unreg_rpi_cmpl_clr - mailbox completion handler @@ -2582,7 +2959,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * * This function is the unreg rpi mailbox completion handler. It * frees the memory resources associated with the completed mailbox - * command. An additional refrenece is put on the ndlp to prevent + * command. An additional reference is put on the ndlp to prevent * lpfc_nlp_release from freeing the rpi bit in the bitmask before * the unreg mailbox command completes, this routine puts the * reference back. @@ -2602,16 +2979,15 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) LPFC_SLI_INTF_IF_TYPE_2)) { if (ndlp) { lpfc_printf_vlog( - vport, KERN_INFO, LOG_MBOX | LOG_SLI, + vport, KERN_INFO, LOG_MBOX | LOG_SLI, "0010 UNREG_LOGIN vpi:%x " "rpi:%x DID:%x defer x%x flg x%x " - "map:%x %px\n", + "x%px\n", vport->vpi, ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp->nlp_flag, - ndlp->nlp_usg_map, ndlp); + ndlp); ndlp->nlp_flag &= ~NLP_LOGO_ACC; - lpfc_nlp_put(ndlp); /* Check to see if there are any deferred * events to process @@ -2634,6 +3010,7 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { __lpfc_sli_rpi_release(vport, ndlp); } + lpfc_nlp_put(ndlp); } } } @@ -2702,7 +3079,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) if (lpfc_sli_chk_mbx_command(pmbox->mbxCommand) == MBX_SHUTDOWN) { /* Unknown mailbox command compl */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):0323 Unknown Mailbox command " "x%x (x%x/x%x) Cmpl\n", pmb->vport ? pmb->vport->vpi : @@ -2803,6 +3180,144 @@ lpfc_sli_get_buff(struct lpfc_hba *phba, } /** + * lpfc_nvme_unsol_ls_handler - Process an unsolicited event data buffer + * containing a NVME LS request. + * @phba: pointer to lpfc hba data structure. + * @piocb: pointer to the iocbq struct representing the sequence starting + * frame. + * + * This routine initially validates the NVME LS, validates there is a login + * with the port that sent the LS, and then calls the appropriate nvme host + * or target LS request handler. + **/ +static void +lpfc_nvme_unsol_ls_handler(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) +{ + struct lpfc_nodelist *ndlp; + struct lpfc_dmabuf *d_buf; + struct hbq_dmabuf *nvmebuf; + struct fc_frame_header *fc_hdr; + struct lpfc_async_xchg_ctx *axchg = NULL; + char *failwhy = NULL; + uint32_t oxid, sid, did, fctl, size; + int ret = 1; + + d_buf = piocb->cmd_dmabuf; + + nvmebuf = container_of(d_buf, struct hbq_dmabuf, dbuf); + fc_hdr = nvmebuf->hbuf.virt; + oxid = be16_to_cpu(fc_hdr->fh_ox_id); + sid = sli4_sid_from_fc_hdr(fc_hdr); + did = sli4_did_from_fc_hdr(fc_hdr); + fctl = (fc_hdr->fh_f_ctl[0] << 16 | + fc_hdr->fh_f_ctl[1] << 8 | + fc_hdr->fh_f_ctl[2]); + size = bf_get(lpfc_rcqe_length, &nvmebuf->cq_event.cqe.rcqe_cmpl); + + lpfc_nvmeio_data(phba, "NVME LS RCV: xri x%x sz %d from %06x\n", + oxid, size, sid); + + if (phba->pport->load_flag & FC_UNLOADING) { + failwhy = "Driver Unloading"; + } else if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) { + failwhy = "NVME FC4 Disabled"; + } else if (!phba->nvmet_support && !phba->pport->localport) { + failwhy = "No Localport"; + } else if (phba->nvmet_support && !phba->targetport) { + failwhy = "No Targetport"; + } else if (unlikely(fc_hdr->fh_r_ctl != FC_RCTL_ELS4_REQ)) { + failwhy = "Bad NVME LS R_CTL"; + } else if (unlikely((fctl & 0x00FF0000) != + (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT))) { + failwhy = "Bad NVME LS F_CTL"; + } else { + axchg = kzalloc(sizeof(*axchg), GFP_ATOMIC); + if (!axchg) + failwhy = "No CTX memory"; + } + + if (unlikely(failwhy)) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6154 Drop NVME LS: SID %06X OXID x%X: %s\n", + sid, oxid, failwhy); + goto out_fail; + } + + /* validate the source of the LS is logged in */ + ndlp = lpfc_findnode_did(phba->pport, sid); + if (!ndlp || + ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && + (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, + "6216 NVME Unsol rcv: No ndlp: " + "NPort_ID x%x oxid x%x\n", + sid, oxid); + goto out_fail; + } + + axchg->phba = phba; + axchg->ndlp = ndlp; + axchg->size = size; + axchg->oxid = oxid; + axchg->sid = sid; + axchg->wqeq = NULL; + axchg->state = LPFC_NVME_STE_LS_RCV; + axchg->entry_cnt = 1; + axchg->rqb_buffer = (void *)nvmebuf; + axchg->hdwq = &phba->sli4_hba.hdwq[0]; + axchg->payload = nvmebuf->dbuf.virt; + INIT_LIST_HEAD(&axchg->list); + + if (phba->nvmet_support) { + ret = lpfc_nvmet_handle_lsreq(phba, axchg); + spin_lock_irq(&ndlp->lock); + if (!ret && !(ndlp->fc4_xpt_flags & NLP_XPT_HAS_HH)) { + ndlp->fc4_xpt_flags |= NLP_XPT_HAS_HH; + spin_unlock_irq(&ndlp->lock); + + /* This reference is a single occurrence to hold the + * node valid until the nvmet transport calls + * host_release. + */ + if (!lpfc_nlp_get(ndlp)) + goto out_fail; + + lpfc_printf_log(phba, KERN_ERR, LOG_NODE, + "6206 NVMET unsol ls_req ndlp x%px " + "DID x%x xflags x%x refcnt %d\n", + ndlp, ndlp->nlp_DID, + ndlp->fc4_xpt_flags, + kref_read(&ndlp->kref)); + } else { + spin_unlock_irq(&ndlp->lock); + } + } else { + ret = lpfc_nvme_handle_lsreq(phba, axchg); + } + + /* if zero, LS was successfully handled. If non-zero, LS not handled */ + if (!ret) + return; + +out_fail: + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6155 Drop NVME LS from DID %06X: SID %06X OXID x%X " + "NVMe%s handler failed %d\n", + did, sid, oxid, + (phba->nvmet_support) ? "T" : "I", ret); + + /* recycle receive buffer */ + lpfc_in_buf_free(phba, &nvmebuf->dbuf); + + /* If start of new exchange, abort it */ + if (axchg && (fctl & FC_FC_FIRST_SEQ && !(fctl & FC_FC_EX_CTX))) + ret = lpfc_nvme_unsol_ls_issue_abort(phba, axchg, sid, oxid); + + if (ret) + kfree(axchg); +} + +/** * lpfc_complete_unsol_iocb - Complete an unsolicited sequence * @phba: Pointer to HBA context object. * @pring: Pointer to driver SLI ring object. @@ -2823,7 +3338,7 @@ lpfc_complete_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, switch (fch_type) { case FC_TYPE_NVME: - lpfc_nvmet_unsol_ls_event(phba, pring, saveq); + lpfc_nvme_unsol_ls_handler(phba, saveq); return 1; default: break; @@ -2850,6 +3365,56 @@ lpfc_complete_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return 0; } +static void +lpfc_sli_prep_unsol_wqe(struct lpfc_hba *phba, + struct lpfc_iocbq *saveq) +{ + IOCB_t *irsp; + union lpfc_wqe128 *wqe; + u16 i = 0; + + irsp = &saveq->iocb; + wqe = &saveq->wqe; + + /* Fill wcqe with the IOCB status fields */ + bf_set(lpfc_wcqe_c_status, &saveq->wcqe_cmpl, irsp->ulpStatus); + saveq->wcqe_cmpl.word3 = irsp->ulpBdeCount; + saveq->wcqe_cmpl.parameter = irsp->un.ulpWord[4]; + saveq->wcqe_cmpl.total_data_placed = irsp->unsli3.rcvsli3.acc_len; + + /* Source ID */ + bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, irsp->un.rcvels.parmRo); + + /* rx-id of the response frame */ + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, irsp->ulpContext); + + /* ox-id of the frame */ + bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, + irsp->unsli3.rcvsli3.ox_id); + + /* DID */ + bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, + irsp->un.rcvels.remoteID); + + /* unsol data len */ + for (i = 0; i < irsp->ulpBdeCount; i++) { + struct lpfc_hbq_entry *hbqe = NULL; + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + if (i == 0) { + hbqe = (struct lpfc_hbq_entry *) + &irsp->un.ulpWord[0]; + saveq->wqe.gen_req.bde.tus.f.bdeSize = + hbqe->bde.tus.f.bdeSize; + } else if (i == 1) { + hbqe = (struct lpfc_hbq_entry *) + &irsp->unsli3.sli3Words[4]; + saveq->unsol_rcv_len = hbqe->bde.tus.f.bdeSize; + } + } + } +} + /** * lpfc_sli_process_unsol_iocb - Unsolicited iocb handler * @phba: Pointer to HBA context object. @@ -2870,11 +3435,13 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, { IOCB_t * irsp; WORD5 * w5p; + dma_addr_t paddr; uint32_t Rctl, Type; struct lpfc_iocbq *iocbq; struct lpfc_dmabuf *dmzbuf; - irsp = &(saveq->iocb); + irsp = &saveq->iocb; + saveq->vport = phba->pport; if (irsp->ulpCommand == CMD_ASYNC_STATUS) { if (pring->lpfc_sli_rcv_async_status) @@ -2892,22 +3459,22 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } if ((irsp->ulpCommand == CMD_IOCB_RET_XRI64_CX) && - (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) { + (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) { if (irsp->ulpBdeCount > 0) { dmzbuf = lpfc_sli_get_buff(phba, pring, - irsp->un.ulpWord[3]); + irsp->un.ulpWord[3]); lpfc_in_buf_free(phba, dmzbuf); } if (irsp->ulpBdeCount > 1) { dmzbuf = lpfc_sli_get_buff(phba, pring, - irsp->unsli3.sli3Words[3]); + irsp->unsli3.sli3Words[3]); lpfc_in_buf_free(phba, dmzbuf); } if (irsp->ulpBdeCount > 2) { dmzbuf = lpfc_sli_get_buff(phba, pring, - irsp->unsli3.sli3Words[7]); + irsp->unsli3.sli3Words[7]); lpfc_in_buf_free(phba, dmzbuf); } @@ -2916,9 +3483,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { if (irsp->ulpBdeCount != 0) { - saveq->context2 = lpfc_sli_get_buff(phba, pring, + saveq->cmd_dmabuf = lpfc_sli_get_buff(phba, pring, irsp->un.ulpWord[3]); - if (!saveq->context2) + if (!saveq->cmd_dmabuf) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -2928,9 +3495,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, irsp->un.ulpWord[3]); } if (irsp->ulpBdeCount == 2) { - saveq->context3 = lpfc_sli_get_buff(phba, pring, + saveq->bpl_dmabuf = lpfc_sli_get_buff(phba, pring, irsp->unsli3.sli3Words[7]); - if (!saveq->context3) + if (!saveq->bpl_dmabuf) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -2940,11 +3507,12 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, irsp->unsli3.sli3Words[7]); } list_for_each_entry(iocbq, &saveq->list, list) { - irsp = &(iocbq->iocb); + irsp = &iocbq->iocb; if (irsp->ulpBdeCount != 0) { - iocbq->context2 = lpfc_sli_get_buff(phba, pring, + iocbq->cmd_dmabuf = lpfc_sli_get_buff(phba, + pring, irsp->un.ulpWord[3]); - if (!iocbq->context2) + if (!iocbq->cmd_dmabuf) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -2954,9 +3522,10 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, irsp->un.ulpWord[3]); } if (irsp->ulpBdeCount == 2) { - iocbq->context3 = lpfc_sli_get_buff(phba, pring, + iocbq->bpl_dmabuf = lpfc_sli_get_buff(phba, + pring, irsp->unsli3.sli3Words[7]); - if (!iocbq->context3) + if (!iocbq->bpl_dmabuf) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -2967,7 +3536,20 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, irsp->unsli3.sli3Words[7]); } } + } else { + paddr = getPaddr(irsp->un.cont64[0].addrHigh, + irsp->un.cont64[0].addrLow); + saveq->cmd_dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, + paddr); + if (irsp->ulpBdeCount == 2) { + paddr = getPaddr(irsp->un.cont64[1].addrHigh, + irsp->un.cont64[1].addrLow); + saveq->bpl_dmabuf = lpfc_sli_ringpostbuf_get(phba, + pring, + paddr); + } } + if (irsp->ulpBdeCount != 0 && (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX || irsp->ulpStatus == IOSTAT_INTERMED_RSP)) { @@ -2985,12 +3567,14 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (!found) list_add_tail(&saveq->clist, &pring->iocb_continue_saveq); + if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) { list_del_init(&iocbq->clist); saveq = iocbq; - irsp = &(saveq->iocb); - } else + irsp = &saveq->iocb; + } else { return 0; + } } if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) || @@ -3013,6 +3597,19 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } + if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && + (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX || + irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) { + if (irsp->unsli3.rcvsli3.vpi == 0xffff) + saveq->vport = phba->pport; + else + saveq->vport = lpfc_find_vport_by_vpid(phba, + irsp->unsli3.rcvsli3.vpi); + } + + /* Prepare WQE with Unsol frame */ + lpfc_sli_prep_unsol_wqe(phba, saveq); + if (!lpfc_complete_unsol_iocb(phba, pring, saveq, Rctl, Type)) lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0313 Ring %d handler: unexpected Rctl x%x " @@ -3041,36 +3638,28 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, struct lpfc_iocbq *prspiocb) { struct lpfc_iocbq *cmd_iocb = NULL; - uint16_t iotag; - spinlock_t *temp_lock = NULL; - unsigned long iflag = 0; + u16 iotag; if (phba->sli_rev == LPFC_SLI_REV4) - temp_lock = &pring->ring_lock; + iotag = get_wqe_reqtag(prspiocb); else - temp_lock = &phba->hbalock; - - spin_lock_irqsave(temp_lock, iflag); - iotag = prspiocb->iocb.ulpIoTag; + iotag = prspiocb->iocb.ulpIoTag; if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; - if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { + if (cmd_iocb->cmd_flag & LPFC_IO_ON_TXCMPLQ) { /* remove from txcmpl queue list */ list_del_init(&cmd_iocb->list); - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; + cmd_iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt--; - spin_unlock_irqrestore(temp_lock, iflag); return cmd_iocb; } } - spin_unlock_irqrestore(temp_lock, iflag); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0317 iotag x%x is out of " - "range: max iotag x%x wd0 x%x\n", - iotag, phba->sli.last_iotag, - *(((uint32_t *) &prspiocb->iocb) + 7)); + "range: max iotag x%x\n", + iotag, phba->sli.last_iotag); return NULL; } @@ -3091,33 +3680,23 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint16_t iotag) { struct lpfc_iocbq *cmd_iocb = NULL; - spinlock_t *temp_lock = NULL; - unsigned long iflag = 0; - - if (phba->sli_rev == LPFC_SLI_REV4) - temp_lock = &pring->ring_lock; - else - temp_lock = &phba->hbalock; - spin_lock_irqsave(temp_lock, iflag); if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; - if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { + if (cmd_iocb->cmd_flag & LPFC_IO_ON_TXCMPLQ) { /* remove from txcmpl queue list */ list_del_init(&cmd_iocb->list); - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; + cmd_iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt--; - spin_unlock_irqrestore(temp_lock, iflag); return cmd_iocb; } } - spin_unlock_irqrestore(temp_lock, iflag); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0372 iotag x%x lookup error: max iotag (x%x) " - "iocb_flag x%x\n", + "cmd_flag x%x\n", iotag, phba->sli.last_iotag, - cmd_iocb ? cmd_iocb->iocb_flag : 0xffff); + cmd_iocb ? cmd_iocb->cmd_flag : 0xffff); return NULL; } @@ -3143,20 +3722,38 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *saveq) { struct lpfc_iocbq *cmdiocbp; - int rc = 1; unsigned long iflag; + u32 ulp_command, ulp_status, ulp_word4, ulp_context, iotag; + if (phba->sli_rev == LPFC_SLI_REV4) + spin_lock_irqsave(&pring->ring_lock, iflag); + else + spin_lock_irqsave(&phba->hbalock, iflag); cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq); + if (phba->sli_rev == LPFC_SLI_REV4) + spin_unlock_irqrestore(&pring->ring_lock, iflag); + else + spin_unlock_irqrestore(&phba->hbalock, iflag); + + ulp_command = get_job_cmnd(phba, saveq); + ulp_status = get_job_ulpstatus(phba, saveq); + ulp_word4 = get_job_word4(phba, saveq); + ulp_context = get_job_ulpcontext(phba, saveq); + if (phba->sli_rev == LPFC_SLI_REV4) + iotag = get_wqe_reqtag(saveq); + else + iotag = saveq->iocb.ulpIoTag; + if (cmdiocbp) { - if (cmdiocbp->iocb_cmpl) { + ulp_command = get_job_cmnd(phba, cmdiocbp); + if (cmdiocbp->cmd_cmpl) { /* * If an ELS command failed send an event to mgmt * application. */ - if (saveq->iocb.ulpStatus && + if (ulp_status && (pring->ringno == LPFC_ELS_RING) && - (cmdiocbp->iocb.ulpCommand == - CMD_ELS_REQUEST64_CR)) + (ulp_command == CMD_ELS_REQUEST64_CR)) lpfc_send_els_failure_event(phba, cmdiocbp, saveq); @@ -3166,11 +3763,11 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, */ if (pring->ringno == LPFC_ELS_RING) { if ((phba->sli_rev < LPFC_SLI_REV4) && - (cmdiocbp->iocb_flag & + (cmdiocbp->cmd_flag & LPFC_DRIVER_ABORTED)) { spin_lock_irqsave(&phba->hbalock, iflag); - cmdiocbp->iocb_flag &= + cmdiocbp->cmd_flag &= ~LPFC_DRIVER_ABORTED; spin_unlock_irqrestore(&phba->hbalock, iflag); @@ -3185,12 +3782,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, */ spin_lock_irqsave(&phba->hbalock, iflag); - saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; + saveq->cmd_flag |= LPFC_DELAY_MEM_FREE; spin_unlock_irqrestore(&phba->hbalock, iflag); } if (phba->sli_rev == LPFC_SLI_REV4) { - if (saveq->iocb_flag & + if (saveq->cmd_flag & LPFC_EXCHANGE_BUSY) { /* Set cmdiocb flag for the * exchange busy so sgl (xri) @@ -3200,12 +3797,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, */ spin_lock_irqsave( &phba->hbalock, iflag); - cmdiocbp->iocb_flag |= + cmdiocbp->cmd_flag |= LPFC_EXCHANGE_BUSY; spin_unlock_irqrestore( &phba->hbalock, iflag); } - if (cmdiocbp->iocb_flag & + if (cmdiocbp->cmd_flag & LPFC_DRIVER_ABORTED) { /* * Clear LPFC_DRIVER_ABORTED @@ -3214,34 +3811,34 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, */ spin_lock_irqsave( &phba->hbalock, iflag); - cmdiocbp->iocb_flag &= + cmdiocbp->cmd_flag &= ~LPFC_DRIVER_ABORTED; spin_unlock_irqrestore( &phba->hbalock, iflag); - cmdiocbp->iocb.ulpStatus = - IOSTAT_LOCAL_REJECT; - cmdiocbp->iocb.un.ulpWord[4] = - IOERR_ABORT_REQUESTED; + set_job_ulpstatus(cmdiocbp, + IOSTAT_LOCAL_REJECT); + set_job_ulpword4(cmdiocbp, + IOERR_ABORT_REQUESTED); /* - * For SLI4, irsiocb contains + * For SLI4, irspiocb contains * NO_XRI in sli_xritag, it * shall not affect releasing * sgl (xri) process. */ - saveq->iocb.ulpStatus = - IOSTAT_LOCAL_REJECT; - saveq->iocb.un.ulpWord[4] = - IOERR_SLI_ABORTED; + set_job_ulpstatus(saveq, + IOSTAT_LOCAL_REJECT); + set_job_ulpword4(saveq, + IOERR_SLI_ABORTED); spin_lock_irqsave( &phba->hbalock, iflag); - saveq->iocb_flag |= + saveq->cmd_flag |= LPFC_DELAY_MEM_FREE; spin_unlock_irqrestore( &phba->hbalock, iflag); } } } - (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); + cmdiocbp->cmd_cmpl(phba, cmdiocbp, saveq); } else lpfc_sli_release_iocbq(phba, cmdiocbp); } else { @@ -3259,16 +3856,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, "0322 Ring %d handler: " "unexpected completion IoTag x%x " "Data: x%x x%x x%x x%x\n", - pring->ringno, - saveq->iocb.ulpIoTag, - saveq->iocb.ulpStatus, - saveq->iocb.un.ulpWord[4], - saveq->iocb.ulpCommand, - saveq->iocb.ulpContext); + pring->ringno, iotag, ulp_status, + ulp_word4, ulp_command, ulp_context); } } - return rc; + return 1; } /** @@ -3289,7 +3882,7 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) * Ring <ringno> handler: portRspPut <portRspPut> is bigger than * rsp ring <portRspMax> */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0312 Ring %d handler: portRspPut %d " "is bigger than rsp ring %d\n", pring->ringno, le32_to_cpu(pgp->rspPutInx), @@ -3311,7 +3904,7 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) /** * lpfc_poll_eratt - Error attention polling timer timeout handler - * @ptr: Pointer to address of HBA context object. + * @t: Context to fetch pointer to address of HBA context object from. * * This function is invoked by the Error Attention polling timer when the * timer times out. It will check the SLI Error Attention register for @@ -3477,18 +4070,15 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, break; } - spin_unlock_irqrestore(&phba->hbalock, iflag); cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, &rspiocbq); - spin_lock_irqsave(&phba->hbalock, iflag); if (unlikely(!cmdiocbq)) break; - if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) - cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED; - if (cmdiocbq->iocb_cmpl) { + if (cmdiocbq->cmd_flag & LPFC_DRIVER_ABORTED) + cmdiocbq->cmd_flag &= ~LPFC_DRIVER_ABORTED; + if (cmdiocbq->cmd_cmpl) { spin_unlock_irqrestore(&phba->hbalock, iflag); - (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, - &rspiocbq); + cmdiocbq->cmd_cmpl(phba, cmdiocbq, &rspiocbq); spin_lock_irqsave(&phba->hbalock, iflag); } break; @@ -3508,7 +4098,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, phba->brd_no, adaptermsg); } else { /* Unknown IOCB command */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0334 Unknown IOCB command " "Data: x%x, x%x x%x x%x x%x\n", type, irsp->ulpCommand, @@ -3579,155 +4169,159 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *rspiocbp) { struct lpfc_iocbq *saveq; - struct lpfc_iocbq *cmdiocbp; + struct lpfc_iocbq *cmdiocb; struct lpfc_iocbq *next_iocb; - IOCB_t *irsp = NULL; + IOCB_t *irsp; uint32_t free_saveq; - uint8_t iocb_cmd_type; + u8 cmd_type; lpfc_iocb_type type; unsigned long iflag; + u32 ulp_status = get_job_ulpstatus(phba, rspiocbp); + u32 ulp_word4 = get_job_word4(phba, rspiocbp); + u32 ulp_command = get_job_cmnd(phba, rspiocbp); int rc; spin_lock_irqsave(&phba->hbalock, iflag); /* First add the response iocb to the countinueq list */ - list_add_tail(&rspiocbp->list, &(pring->iocb_continueq)); + list_add_tail(&rspiocbp->list, &pring->iocb_continueq); pring->iocb_continueq_cnt++; - /* Now, determine whether the list is completed for processing */ - irsp = &rspiocbp->iocb; - if (irsp->ulpLe) { - /* - * By default, the driver expects to free all resources - * associated with this iocb completion. - */ - free_saveq = 1; - saveq = list_get_first(&pring->iocb_continueq, - struct lpfc_iocbq, list); - irsp = &(saveq->iocb); - list_del_init(&pring->iocb_continueq); - pring->iocb_continueq_cnt = 0; + /* + * By default, the driver expects to free all resources + * associated with this iocb completion. + */ + free_saveq = 1; + saveq = list_get_first(&pring->iocb_continueq, + struct lpfc_iocbq, list); + list_del_init(&pring->iocb_continueq); + pring->iocb_continueq_cnt = 0; - pring->stats.iocb_rsp++; + pring->stats.iocb_rsp++; - /* - * If resource errors reported from HBA, reduce - * queuedepths of the SCSI device. - */ - if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == - IOERR_NO_RESOURCES)) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - phba->lpfc_rampdown_queue_depth(phba); - spin_lock_irqsave(&phba->hbalock, iflag); - } + /* + * If resource errors reported from HBA, reduce + * queuedepths of the SCSI device. + */ + if (ulp_status == IOSTAT_LOCAL_REJECT && + ((ulp_word4 & IOERR_PARAM_MASK) == + IOERR_NO_RESOURCES)) { + spin_unlock_irqrestore(&phba->hbalock, iflag); + phba->lpfc_rampdown_queue_depth(phba); + spin_lock_irqsave(&phba->hbalock, iflag); + } - if (irsp->ulpStatus) { - /* Rsp ring <ringno> error: IOCB */ + if (ulp_status) { + /* Rsp ring <ringno> error: IOCB */ + if (phba->sli_rev < LPFC_SLI_REV4) { + irsp = &rspiocbp->iocb; + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "0328 Rsp Ring %d error: ulp_status x%x " + "IOCB Data: " + "x%08x x%08x x%08x x%08x " + "x%08x x%08x x%08x x%08x " + "x%08x x%08x x%08x x%08x " + "x%08x x%08x x%08x x%08x\n", + pring->ringno, ulp_status, + get_job_ulpword(rspiocbp, 0), + get_job_ulpword(rspiocbp, 1), + get_job_ulpword(rspiocbp, 2), + get_job_ulpword(rspiocbp, 3), + get_job_ulpword(rspiocbp, 4), + get_job_ulpword(rspiocbp, 5), + *(((uint32_t *)irsp) + 6), + *(((uint32_t *)irsp) + 7), + *(((uint32_t *)irsp) + 8), + *(((uint32_t *)irsp) + 9), + *(((uint32_t *)irsp) + 10), + *(((uint32_t *)irsp) + 11), + *(((uint32_t *)irsp) + 12), + *(((uint32_t *)irsp) + 13), + *(((uint32_t *)irsp) + 14), + *(((uint32_t *)irsp) + 15)); + } else { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0328 Rsp Ring %d error: " + "0321 Rsp Ring %d error: " "IOCB Data: " - "x%x x%x x%x x%x " - "x%x x%x x%x x%x " - "x%x x%x x%x x%x " "x%x x%x x%x x%x\n", pring->ringno, - irsp->un.ulpWord[0], - irsp->un.ulpWord[1], - irsp->un.ulpWord[2], - irsp->un.ulpWord[3], - irsp->un.ulpWord[4], - irsp->un.ulpWord[5], - *(((uint32_t *) irsp) + 6), - *(((uint32_t *) irsp) + 7), - *(((uint32_t *) irsp) + 8), - *(((uint32_t *) irsp) + 9), - *(((uint32_t *) irsp) + 10), - *(((uint32_t *) irsp) + 11), - *(((uint32_t *) irsp) + 12), - *(((uint32_t *) irsp) + 13), - *(((uint32_t *) irsp) + 14), - *(((uint32_t *) irsp) + 15)); + rspiocbp->wcqe_cmpl.word0, + rspiocbp->wcqe_cmpl.total_data_placed, + rspiocbp->wcqe_cmpl.parameter, + rspiocbp->wcqe_cmpl.word3); } + } - /* - * Fetch the IOCB command type and call the correct completion - * routine. Solicited and Unsolicited IOCBs on the ELS ring - * get freed back to the lpfc_iocb_list by the discovery - * kernel thread. - */ - iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK; - type = lpfc_sli_iocb_cmd_type(iocb_cmd_type); - switch (type) { - case LPFC_SOL_IOCB: - spin_unlock_irqrestore(&phba->hbalock, iflag); - rc = lpfc_sli_process_sol_iocb(phba, pring, saveq); - spin_lock_irqsave(&phba->hbalock, iflag); - break; - - case LPFC_UNSOL_IOCB: - spin_unlock_irqrestore(&phba->hbalock, iflag); - rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq); - spin_lock_irqsave(&phba->hbalock, iflag); - if (!rc) - free_saveq = 0; - break; - case LPFC_ABORT_IOCB: - cmdiocbp = NULL; - if (irsp->ulpCommand != CMD_XRI_ABORTED_CX) { + /* + * Fetch the iocb command type and call the correct completion + * routine. Solicited and Unsolicited IOCBs on the ELS ring + * get freed back to the lpfc_iocb_list by the discovery + * kernel thread. + */ + cmd_type = ulp_command & CMD_IOCB_MASK; + type = lpfc_sli_iocb_cmd_type(cmd_type); + switch (type) { + case LPFC_SOL_IOCB: + spin_unlock_irqrestore(&phba->hbalock, iflag); + rc = lpfc_sli_process_sol_iocb(phba, pring, saveq); + spin_lock_irqsave(&phba->hbalock, iflag); + break; + case LPFC_UNSOL_IOCB: + spin_unlock_irqrestore(&phba->hbalock, iflag); + rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq); + spin_lock_irqsave(&phba->hbalock, iflag); + if (!rc) + free_saveq = 0; + break; + case LPFC_ABORT_IOCB: + cmdiocb = NULL; + if (ulp_command != CMD_XRI_ABORTED_CX) + cmdiocb = lpfc_sli_iocbq_lookup(phba, pring, + saveq); + if (cmdiocb) { + /* Call the specified completion routine */ + if (cmdiocb->cmd_cmpl) { spin_unlock_irqrestore(&phba->hbalock, iflag); - cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, - saveq); + cmdiocb->cmd_cmpl(phba, cmdiocb, saveq); spin_lock_irqsave(&phba->hbalock, iflag); - } - if (cmdiocbp) { - /* Call the specified completion routine */ - if (cmdiocbp->iocb_cmpl) { - spin_unlock_irqrestore(&phba->hbalock, - iflag); - (cmdiocbp->iocb_cmpl)(phba, cmdiocbp, - saveq); - spin_lock_irqsave(&phba->hbalock, - iflag); - } else - __lpfc_sli_release_iocbq(phba, - cmdiocbp); - } - break; - - case LPFC_UNKNOWN_IOCB: - if (irsp->ulpCommand == CMD_ADAPTER_MSG) { - char adaptermsg[LPFC_MAX_ADPTMSG]; - memset(adaptermsg, 0, LPFC_MAX_ADPTMSG); - memcpy(&adaptermsg[0], (uint8_t *)irsp, - MAX_MSG_DATA); - dev_warn(&((phba->pcidev)->dev), - "lpfc%d: %s\n", - phba->brd_no, adaptermsg); } else { - /* Unknown IOCB command */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0335 Unknown IOCB " - "command Data: x%x " - "x%x x%x x%x\n", - irsp->ulpCommand, - irsp->ulpStatus, - irsp->ulpIoTag, - irsp->ulpContext); + __lpfc_sli_release_iocbq(phba, cmdiocb); } - break; } + break; + case LPFC_UNKNOWN_IOCB: + if (ulp_command == CMD_ADAPTER_MSG) { + char adaptermsg[LPFC_MAX_ADPTMSG]; + + memset(adaptermsg, 0, LPFC_MAX_ADPTMSG); + memcpy(&adaptermsg[0], (uint8_t *)&rspiocbp->wqe, + MAX_MSG_DATA); + dev_warn(&((phba->pcidev)->dev), + "lpfc%d: %s\n", + phba->brd_no, adaptermsg); + } else { + /* Unknown command */ + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0335 Unknown IOCB " + "command Data: x%x " + "x%x x%x x%x\n", + ulp_command, + ulp_status, + get_wqe_reqtag(rspiocbp), + get_job_ulpcontext(phba, rspiocbp)); + } + break; + } - if (free_saveq) { - list_for_each_entry_safe(rspiocbp, next_iocb, - &saveq->list, list) { - list_del_init(&rspiocbp->list); - __lpfc_sli_release_iocbq(phba, rspiocbp); - } - __lpfc_sli_release_iocbq(phba, saveq); + if (free_saveq) { + list_for_each_entry_safe(rspiocbp, next_iocb, + &saveq->list, list) { + list_del_init(&rspiocbp->list); + __lpfc_sli_release_iocbq(phba, rspiocbp); } - rspiocbp = NULL; + __lpfc_sli_release_iocbq(phba, saveq); } + rspiocbp = NULL; spin_unlock_irqrestore(&phba->hbalock, iflag); return rspiocbp; } @@ -3786,7 +4380,7 @@ lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, * Ring <ringno> handler: portRspPut <portRspPut> is bigger than * rsp ring <portRspMax> */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0303 Ring %d handler: portRspPut %d " "is bigger than rsp ring %d\n", pring->ringno, portRspPut, portRspMax); @@ -3920,8 +4514,8 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba, irspiocbq = container_of(cq_event, struct lpfc_iocbq, cq_event); /* Translate ELS WCQE to response IOCBQ */ - irspiocbq = lpfc_sli4_els_wcqe_to_rspiocbq(phba, - irspiocbq); + irspiocbq = lpfc_sli4_els_preprocess_rspiocbq(phba, + irspiocbq); if (irspiocbq) lpfc_sli_sp_handle_rspiocb(phba, pring, irspiocbq); @@ -3957,47 +4551,68 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba, void lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { - LIST_HEAD(completions); + LIST_HEAD(tx_completions); + LIST_HEAD(txcmplq_completions); struct lpfc_iocbq *iocb, *next_iocb; + int offline; if (pring->ringno == LPFC_ELS_RING) { lpfc_fabric_abort_hba(phba); } + offline = pci_channel_offline(phba->pcidev); /* Error everything on txq and txcmplq * First do the txq. */ if (phba->sli_rev >= LPFC_SLI_REV4) { spin_lock_irq(&pring->ring_lock); - list_splice_init(&pring->txq, &completions); + list_splice_init(&pring->txq, &tx_completions); pring->txq_cnt = 0; - spin_unlock_irq(&pring->ring_lock); - spin_lock_irq(&phba->hbalock); - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); - spin_unlock_irq(&phba->hbalock); + if (offline) { + list_splice_init(&pring->txcmplq, + &txcmplq_completions); + } else { + /* Next issue ABTS for everything on the txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, + &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, + iocb, NULL); + } + spin_unlock_irq(&pring->ring_lock); } else { spin_lock_irq(&phba->hbalock); - list_splice_init(&pring->txq, &completions); + list_splice_init(&pring->txq, &tx_completions); pring->txq_cnt = 0; - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + if (offline) { + list_splice_init(&pring->txcmplq, &txcmplq_completions); + } else { + /* Next issue ABTS for everything on the txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, + &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, + iocb, NULL); + } spin_unlock_irq(&phba->hbalock); } + if (offline) { + /* Cancel all the IOCBs from the completions list */ + lpfc_sli_cancel_iocbs(phba, &txcmplq_completions, + IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); + } else { + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + } /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, + lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); } /** * lpfc_sli_abort_fcp_rings - Abort all iocbs in all FCP rings * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. * * This function aborts all iocbs in FCP rings and frees all the iocb * objects in txq. This function issues an abort iocb for all the iocb commands @@ -4058,7 +4673,7 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba) list_splice_init(&pring->txq, &txq); list_for_each_entry_safe(piocb, next_iocb, &pring->txcmplq, list) - piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; + piocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; /* Retrieve everything on the txcmplq */ list_splice_init(&pring->txcmplq, &txcmplq); pring->txq_cnt = 0; @@ -4069,10 +4684,12 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba) lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT, IOERR_SLI_DOWN); - /* Flush the txcmpq */ + /* Flush the txcmplq */ lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT, IOERR_SLI_DOWN); + if (unlikely(pci_channel_offline(phba->pcidev))) + lpfc_sli4_io_xri_aborted(phba, NULL, 0); } } else { pring = &psli->sli3_ring[LPFC_FCP_RING]; @@ -4082,7 +4699,7 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba) list_splice_init(&pring->txq, &txq); list_for_each_entry_safe(piocb, next_iocb, &pring->txcmplq, list) - piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; + piocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; /* Retrieve everything on the txcmplq */ list_splice_init(&pring->txcmplq, &txcmplq); pring->txq_cnt = 0; @@ -4122,6 +4739,8 @@ lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask) if (lpfc_readl(phba->HSregaddr, &status)) return 1; + phba->hba_flag |= HBA_NEEDS_CFG_PORT; + /* * Check status register every 100ms for 5 retries, then every * 500ms for 5, then every 2.5 sec for 5, then reset board and @@ -4153,7 +4772,7 @@ lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask) /* Check to see if any errors occurred during init */ if ((status & HS_FFERM) || (i >= 20)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2751 Adapter failed to restart, " "status reg x%x, FW Data: A8 x%x AC x%x\n", status, @@ -4199,6 +4818,7 @@ lpfc_sli_brdready_s4(struct lpfc_hba *phba, uint32_t mask) } else phba->sli4_hba.intr_enable = 0; + phba->hba_flag &= ~HBA_SETUP; return retval; } @@ -4229,7 +4849,7 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) { uint32_t __iomem *resp_buf; uint32_t __iomem *mbox_buf; - volatile uint32_t mbox; + volatile struct MAILBOX_word0 mbox; uint32_t hc_copy, ha_copy, resp_data; int i; uint8_t hdrtype; @@ -4263,13 +4883,13 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) phba->pport->stopped = 1; } - mbox = 0; - ((MAILBOX_t *)&mbox)->mbxCommand = MBX_KILL_BOARD; - ((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP; + mbox.word0 = 0; + mbox.mbxCommand = MBX_KILL_BOARD; + mbox.mbxOwner = OWN_CHIP; writel(BARRIER_TEST_PATTERN, (resp_buf + 1)); mbox_buf = phba->MBslimaddr; - writel(mbox, mbox_buf); + writel(mbox.word0, mbox_buf); for (i = 0; i < 50; i++) { if (lpfc_readl((resp_buf + 1), &resp_data)) @@ -4290,12 +4910,12 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) goto clear_errat; } - ((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST; + mbox.mbxOwner = OWN_HOST; resp_data = 0; for (i = 0; i < 500; i++) { if (lpfc_readl(resp_buf, &resp_data)) return; - if (resp_data != mbox) + if (resp_data != mbox.word0) mdelay(1); else break; @@ -4375,7 +4995,7 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) if (retval != MBX_SUCCESS) { if (retval != MBX_BUSY) mempool_free(pmb, phba->mbox_mem_pool); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2752 KILL_BOARD command failed retval %d\n", retval); spin_lock_irq(&phba->hbalock); @@ -4450,6 +5070,7 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) /* perform board reset */ phba->fc_eventTag = 0; phba->link_events = 0; + phba->hba_flag |= HBA_NEEDS_CFG_PORT; if (phba->pport) { phba->pport->fc_myDID = 0; phba->pport->fc_prevDID = 0; @@ -4518,18 +5139,13 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) phba->link_events = 0; phba->pport->fc_myDID = 0; phba->pport->fc_prevDID = 0; + phba->hba_flag &= ~HBA_SETUP; spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~(LPFC_PROCESS_LA); phba->fcf.fcf_flag = 0; spin_unlock_irq(&phba->hbalock); - /* SLI4 INTF 2: if FW dump is being taken skip INIT_PORT */ - if (phba->hba_flag & HBA_FW_DUMP_OP) { - phba->hba_flag &= ~HBA_FW_DUMP_OP; - return rc; - } - /* Now physically reset the device */ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0389 Performing PCI function reset!\n"); @@ -4569,9 +5185,8 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) static int lpfc_sli_brdrestart_s3(struct lpfc_hba *phba) { - MAILBOX_t *mb; + volatile struct MAILBOX_word0 mb; struct lpfc_sli *psli; - volatile uint32_t word0; void __iomem *to_slim; uint32_t hba_aer_enabled; @@ -4588,24 +5203,23 @@ lpfc_sli_brdrestart_s3(struct lpfc_hba *phba) (phba->pport) ? phba->pport->port_state : 0, psli->sli_flag); - word0 = 0; - mb = (MAILBOX_t *) &word0; - mb->mbxCommand = MBX_RESTART; - mb->mbxHc = 1; + mb.word0 = 0; + mb.mbxCommand = MBX_RESTART; + mb.mbxHc = 1; lpfc_reset_barrier(phba); to_slim = phba->MBslimaddr; - writel(*(uint32_t *) mb, to_slim); + writel(mb.word0, to_slim); readl(to_slim); /* flush */ /* Only skip post after fc_ffinit is completed */ if (phba->pport && phba->pport->port_state) - word0 = 1; /* This is really setting up word1 */ + mb.word0 = 1; /* This is really setting up word1 */ else - word0 = 0; /* This is really setting up word1 */ + mb.word0 = 0; /* This is really setting up word1 */ to_slim = phba->MBslimaddr + sizeof (uint32_t); - writel(*(uint32_t *) mb, to_slim); + writel(mb.word0, to_slim); readl(to_slim); /* flush */ lpfc_sli_brdreset(phba); @@ -4664,6 +5278,8 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) phba->pport->stopped = 0; phba->link_state = LPFC_INIT_START; phba->hba_flag = 0; + /* Preserve FA-PWWN expectation */ + phba->sli4_hba.fawwpn_flag &= LPFC_FAWWPN_FABRIC; spin_unlock_irq(&phba->hbalock); memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); @@ -4727,7 +5343,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) if (i++ >= 200) { /* Adapter failed to init, timeout, status reg <status> */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0436 Adapter failed to init, " "timeout, status reg x%x, " "FW Data: A8 x%x AC x%x\n", status, @@ -4742,7 +5358,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) /* ERROR: During chipset initialization */ /* Adapter failed to init, chipset, status reg <status> */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0437 Adapter failed to init, " "chipset, status reg x%x, " "FW Data: A8 x%x AC x%x\n", status, @@ -4773,7 +5389,7 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) if (status & HS_FFERM) { /* ERROR: During chipset initialization */ /* Adapter failed to init, chipset, status reg <status> */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0438 Adapter failed to init, chipset, " "status reg x%x, " "FW Data: A8 x%x AC x%x\n", status, @@ -4783,6 +5399,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) return -EIO; } + phba->hba_flag |= HBA_NEEDS_CFG_PORT; + /* Clear all interrupt enable conditions */ writel(0, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ @@ -4996,7 +5614,7 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) LPFC_SLI3_CRP_ENABLED | LPFC_SLI3_DSS_ENABLED); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0442 Adapter failed to init, mbxCmd x%x " "CONFIG_PORT, mbxStatus x%x Data: x%x\n", pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus, 0); @@ -5034,23 +5652,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) } else phba->max_vpi = 0; - phba->fips_level = 0; - phba->fips_spec_rev = 0; - if (pmb->u.mb.un.varCfgPort.gdss) { - phba->sli3_options |= LPFC_SLI3_DSS_ENABLED; - phba->fips_level = pmb->u.mb.un.varCfgPort.fips_level; - phba->fips_spec_rev = pmb->u.mb.un.varCfgPort.fips_rev; - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2850 Security Crypto Active. FIPS x%d " - "(Spec Rev: x%d)", - phba->fips_level, phba->fips_spec_rev); - } - if (pmb->u.mb.un.varCfgPort.sec_err) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2856 Config Port Security Crypto " - "Error: x%x ", - pmb->u.mb.un.varCfgPort.sec_err); - } if (pmb->u.mb.un.varCfgPort.gerbm) phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED; if (pmb->u.mb.un.varCfgPort.gcrp) @@ -5063,7 +5664,7 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) if (pmb->u.mb.un.varCfgPort.gbg == 0) { phba->cfg_enable_bg = 0; phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0443 Adapter did not grant " "BlockGuard\n"); } @@ -5096,45 +5697,18 @@ int lpfc_sli_hba_setup(struct lpfc_hba *phba) { uint32_t rc; - int mode = 3, i; + int i; int longs; - switch (phba->cfg_sli_mode) { - case 2: - if (phba->cfg_enable_npiv) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, - "1824 NPIV enabled: Override sli_mode " - "parameter (%d) to auto (0).\n", - phba->cfg_sli_mode); - break; - } - mode = 2; - break; - case 0: - case 3: - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, - "1819 Unrecognized sli_mode parameter: %d.\n", - phba->cfg_sli_mode); - - break; + /* Enable ISR already does config_port because of config_msi mbx */ + if (phba->hba_flag & HBA_NEEDS_CFG_PORT) { + rc = lpfc_sli_config_port(phba, LPFC_SLI_REV3); + if (rc) + return -EIO; + phba->hba_flag &= ~HBA_NEEDS_CFG_PORT; } phba->fcp_embed_io = 0; /* SLI4 FC support only */ - rc = lpfc_sli_config_port(phba, mode); - - if (rc && phba->cfg_sli_mode == 3) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, - "1820 Unable to select SLI-3. " - "Not supported by adapter.\n"); - if (rc && mode != 2) - rc = lpfc_sli_config_port(phba, 2); - else if (rc && mode == 2) - rc = lpfc_sli_config_port(phba, 3); - if (rc) - goto lpfc_sli_hba_setup_error; - /* Enable PCIe device Advanced Error Reporting (AER) if configured */ if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) { rc = pci_enable_pcie_error_reporting(phba->pcidev); @@ -5219,7 +5793,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) lpfc_sli_hba_setup_error: phba->link_state = LPFC_HBA_ERROR; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0445 Firmware initialization failed\n"); return rc; } @@ -5227,7 +5801,7 @@ lpfc_sli_hba_setup_error: /** * lpfc_sli4_read_fcoe_params - Read fcoe params from conf region * @phba: Pointer to HBA context object. - * @mboxq: mailbox pointer. + * * This function issue a dump mailbox command to read config region * 23 and parse the records in the region and populate driver * data structure. @@ -5282,26 +5856,20 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba) mboxq->mcqe.trailer); if (rc) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); rc = -EIO; goto out_free_mboxq; } data_length = mqe->un.mb_words[5]; if (data_length > DMP_RGN23_SIZE) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); rc = -EIO; goto out_free_mboxq; } lpfc_parse_fcoe_conf(phba, mp->virt, data_length); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); rc = 0; out_free_mboxq: - mempool_free(mboxq, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED); return rc; } @@ -5416,7 +5984,7 @@ lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba) LPFC_SLI4_MBX_NEMBED); if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3084 Allocated DMA memory size (%d) is " "less than the requested DMA memory size " "(%d)\n", alloclen, reqlen); @@ -5447,23 +6015,25 @@ lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba) bf_get(lpfc_cntl_attr_lnk_type, cntl_attr); phba->sli4_hba.lnk_info.lnk_no = bf_get(lpfc_cntl_attr_lnk_numb, cntl_attr); + phba->sli4_hba.flash_id = bf_get(lpfc_cntl_attr_flash_id, cntl_attr); + phba->sli4_hba.asic_rev = bf_get(lpfc_cntl_attr_asic_rev, cntl_attr); memset(phba->BIOSVersion, 0, sizeof(phba->BIOSVersion)); strlcat(phba->BIOSVersion, (char *)cntl_attr->bios_ver_str, sizeof(phba->BIOSVersion)); lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s\n", + "3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s, " + "flash_id: x%02x, asic_rev: x%02x\n", phba->sli4_hba.lnk_info.lnk_tp, phba->sli4_hba.lnk_info.lnk_no, - phba->BIOSVersion); + phba->BIOSVersion, phba->sli4_hba.flash_id, + phba->sli4_hba.asic_rev); out_free_mboxq: - if (rc != MBX_TIMEOUT) { - if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) - lpfc_sli4_mbox_cmd_free(phba, mboxq); - else - mempool_free(mboxq, phba->mbox_mem_pool); - } + if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) + lpfc_sli4_mbox_cmd_free(phba, mboxq); + else + mempool_free(mboxq, phba->mbox_mem_pool); return rc; } @@ -5498,6 +6068,10 @@ lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba) /* obtain link type and link number via READ_CONFIG */ phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL; lpfc_sli4_read_config(phba); + + if (phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_CONFIG) + phba->sli4_hba.fawwpn_flag |= LPFC_FAWWPN_FABRIC; + if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) goto retrieve_ppname; @@ -5564,12 +6138,10 @@ retrieve_ppname: } out_free_mboxq: - if (rc != MBX_TIMEOUT) { - if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) - lpfc_sli4_mbox_cmd_free(phba, mboxq); - else - mempool_free(mboxq, phba->mbox_mem_pool); - } + if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) + lpfc_sli4_mbox_cmd_free(phba, mboxq); + else + mempool_free(mboxq, phba->mbox_mem_pool); return rc; } @@ -5643,6 +6215,9 @@ lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type, struct lpfc_mbx_get_rsrc_extent_info *rsrc_info; LPFC_MBOXQ_t *mbox; + *extnt_count = 0; + *extnt_size = 0; + mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; @@ -5676,7 +6251,7 @@ lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type, rsrc_info = &mbox->u.mqe.un.rsrc_extent_info; if (bf_get(lpfc_mbox_hdr_status, &rsrc_info->header.cfg_shdr.response)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2930 Failed to get resource extents " "Status 0x%x Add'l Status 0x%x\n", bf_get(lpfc_mbox_hdr_status, @@ -5765,10 +6340,10 @@ lpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type) /** * lpfc_sli4_cfg_post_extnts - * @phba: Pointer to HBA context object. - * @extnt_cnt - number of available extents. - * @type - the extent type (rpi, xri, vfi, vpi). - * @emb - buffer to hold either MBX_EMBED or MBX_NEMBED operation. - * @mbox - pointer to the caller's allocated mailbox structure. + * @extnt_cnt: number of available extents. + * @type: the extent type (rpi, xri, vfi, vpi). + * @emb: buffer to hold either MBX_EMBED or MBX_NEMBED operation. + * @mbox: pointer to the caller's allocated mailbox structure. * * This function executes the extents allocation request. It also * takes care of the amount of memory needed to allocate or get the @@ -5814,7 +6389,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t extnt_cnt, LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT, req_len, *emb); if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2982 Allocated DMA memory size (x%x) is " "less than the requested DMA memory " "size (x%x)\n", alloc_len, req_len); @@ -5870,7 +6445,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) return -EIO; if ((rsrc_cnt == 0) || (rsrc_size == 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3009 No available Resource Extents " "for resource type 0x%x: Count: 0x%x, " "Size 0x%x\n", type, rsrc_cnt, @@ -6121,7 +6696,7 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) dealloc_rsrc = &mbox->u.mqe.un.dealloc_rsrc_extents; if (bf_get(lpfc_mbox_hdr_status, &dealloc_rsrc->header.cfg_shdr.response)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2919 Failed to release resource extents " "for type %d - Status 0x%x Add'l Status 0x%x. " "Resource memory not released.\n", @@ -6190,6 +6765,7 @@ lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, uint32_t feature) { uint32_t len; + u32 sig_freq = 0; len = sizeof(struct lpfc_mbx_set_feature) - sizeof(struct lpfc_sli4_cfg_mhdr); @@ -6212,6 +6788,35 @@ lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, mbox->u.mqe.un.set_feature.feature = LPFC_SET_MDS_DIAGS; mbox->u.mqe.un.set_feature.param_len = 8; break; + case LPFC_SET_CGN_SIGNAL: + if (phba->cmf_active_mode == LPFC_CFG_OFF) + sig_freq = 0; + else + sig_freq = phba->cgn_sig_freq; + + if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) { + bf_set(lpfc_mbx_set_feature_CGN_alarm_freq, + &mbox->u.mqe.un.set_feature, sig_freq); + bf_set(lpfc_mbx_set_feature_CGN_warn_freq, + &mbox->u.mqe.un.set_feature, sig_freq); + } + + if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY) + bf_set(lpfc_mbx_set_feature_CGN_warn_freq, + &mbox->u.mqe.un.set_feature, sig_freq); + + if (phba->cmf_active_mode == LPFC_CFG_OFF || + phba->cgn_reg_signal == EDC_CG_SIG_NOTSUPPORTED) + sig_freq = 0; + else + sig_freq = lpfc_acqe_cgn_frequency; + + bf_set(lpfc_mbx_set_feature_CGN_acqe_freq, + &mbox->u.mqe.un.set_feature, sig_freq); + + mbox->u.mqe.un.set_feature.feature = LPFC_SET_CGN_SIGNAL; + mbox->u.mqe.un.set_feature.param_len = 12; + break; case LPFC_SET_DUAL_DUMP: bf_set(lpfc_mbx_set_feature_dd, &mbox->u.mqe.un.set_feature, LPFC_ENABLE_DUAL_DUMP); @@ -6220,8 +6825,27 @@ lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, mbox->u.mqe.un.set_feature.feature = LPFC_SET_DUAL_DUMP; mbox->u.mqe.un.set_feature.param_len = 4; break; + case LPFC_SET_ENABLE_MI: + mbox->u.mqe.un.set_feature.feature = LPFC_SET_ENABLE_MI; + mbox->u.mqe.un.set_feature.param_len = 4; + bf_set(lpfc_mbx_set_feature_milunq, &mbox->u.mqe.un.set_feature, + phba->pport->cfg_lun_queue_depth); + bf_set(lpfc_mbx_set_feature_mi, &mbox->u.mqe.un.set_feature, + phba->sli4_hba.pc_sli4_params.mi_ver); + break; + case LPFC_SET_LD_SIGNAL: + mbox->u.mqe.un.set_feature.feature = LPFC_SET_LD_SIGNAL; + mbox->u.mqe.un.set_feature.param_len = 16; + bf_set(lpfc_mbx_set_feature_lds_qry, + &mbox->u.mqe.un.set_feature, LPFC_QUERY_LDS_OP); + break; + case LPFC_SET_ENABLE_CMF: + mbox->u.mqe.un.set_feature.feature = LPFC_SET_ENABLE_CMF; + mbox->u.mqe.un.set_feature.param_len = 4; + bf_set(lpfc_mbx_set_feature_cmf, + &mbox->u.mqe.un.set_feature, 1); + break; } - return; } @@ -6315,7 +6939,7 @@ lpfc_sli4_ras_dma_alloc(struct lpfc_hba *phba, &ras_fwlog->lwpd.phys, GFP_KERNEL); if (!ras_fwlog->lwpd.virt) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6185 LWPD Memory Alloc Failed\n"); return -ENOMEM; @@ -6356,7 +6980,7 @@ free_mem: /** * lpfc_sli4_ras_mbox_cmpl: Completion handler for RAS MBX command * @phba: pointer to lpfc hba data structure. - * @pmboxq: pointer to the driver internal queue element for mailbox command. + * @pmb: pointer to the driver internal queue element for mailbox command. * * Completion handler for driver's RAS MBX command to the device. **/ @@ -6376,7 +7000,7 @@ lpfc_sli4_ras_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (mb->mbxStatus != MBX_SUCCESS || shdr_status) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6188 FW LOG mailbox " "completed with status x%x add_status x%x," " mbx status x%x\n", @@ -6444,7 +7068,7 @@ lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, /* Setup Mailbox command */ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6190 RAS MBX Alloc Failed"); rc = -ENOMEM; goto mem_free; @@ -6492,7 +7116,7 @@ lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6191 FW-Log Mailbox failed. " "status %d mbxStatus : x%x", rc, bf_get(lpfc_mqe_status, &mbox->u.mqe)); @@ -6628,7 +7252,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* RPIs. */ count = phba->sli4_hba.max_cfg_param.max_rpi; if (count <= 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3279 Invalid provisioning of " "rpi:%d\n", count); rc = -EINVAL; @@ -6656,7 +7280,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* VPIs. */ count = phba->sli4_hba.max_cfg_param.max_vpi; if (count <= 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3280 Invalid provisioning of " "vpi:%d\n", count); rc = -EINVAL; @@ -6683,7 +7307,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* XRIs. */ count = phba->sli4_hba.max_cfg_param.max_xri; if (count <= 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3281 Invalid provisioning of " "xri:%d\n", count); rc = -EINVAL; @@ -6712,7 +7336,7 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) /* VFIs. */ count = phba->sli4_hba.max_cfg_param.max_vfi; if (count <= 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3282 Invalid provisioning of " "vfi:%d\n", count); rc = -EINVAL; @@ -6806,7 +7430,7 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba) * lpfc_sli4_get_allocated_extnts - Get the port's allocated extents. * @phba: Pointer to HBA context object. * @type: The resource extent type. - * @extnt_count: buffer to hold port extent count response + * @extnt_cnt: buffer to hold port extent count response * @extnt_size: buffer to hold port extent size response. * * This function calls the port to read the host allocated extents @@ -6890,7 +7514,7 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT, req_len, emb); if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2983 Allocated DMA memory size (x%x) is " "less than the requested DMA memory " "size (x%x)\n", alloc_len, req_len); @@ -6933,7 +7557,7 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, } if (bf_get(lpfc_mbox_hdr_status, &shdr->response)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2984 Failed to read allocated resources " "for type %d - Status 0x%x Add'l Status 0x%x.\n", type, @@ -6950,7 +7574,6 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, /** * lpfc_sli4_repost_sgl_list - Repost the buffers sgl pages as block * @phba: pointer to lpfc hba data structure. - * @pring: Pointer to driver SLI ring object. * @sgl_list: linked link of sgl buffers to post * @cnt: number of linked list buffers * @@ -7088,7 +7711,7 @@ lpfc_sli4_repost_sgl_list(struct lpfc_hba *phba, spin_unlock(&phba->sli4_hba.sgl_list_lock); spin_unlock_irq(&phba->hbalock); } else { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3161 Failure to post sgl to port.\n"); return -EIO; } @@ -7143,7 +7766,7 @@ lpfc_set_host_data(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) mbox->u.mqe.un.set_host_data.param_id = LPFC_SET_HOST_OS_DRIVER_VERSION; mbox->u.mqe.un.set_host_data.param_len = LPFC_HOST_OS_DRIVER_VERSION_SIZE; - snprintf(mbox->u.mqe.un.set_host_data.data, + snprintf(mbox->u.mqe.un.set_host_data.un.data, LPFC_HOST_OS_DRIVER_VERSION_SIZE, "Linux %s v"LPFC_DRIVER_VERSION, (phba->hba_flag & HBA_FCOE_MODE) ? "FCoE" : "FC"); @@ -7161,12 +7784,16 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, struct rqb_dmabuf *rqb_buffer; LIST_HEAD(rqb_buf_list); - spin_lock_irqsave(&phba->hbalock, flags); rqbp = hrq->rqbp; for (i = 0; i < count; i++) { + spin_lock_irqsave(&phba->hbalock, flags); /* IF RQ is already full, don't bother */ - if (rqbp->buffer_count + i >= rqbp->entry_count - 1) + if (rqbp->buffer_count + i >= rqbp->entry_count - 1) { + spin_unlock_irqrestore(&phba->hbalock, flags); break; + } + spin_unlock_irqrestore(&phba->hbalock, flags); + rqb_buffer = rqbp->rqb_alloc_buffer(phba); if (!rqb_buffer) break; @@ -7175,6 +7802,8 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, rqb_buffer->idx = idx; list_add_tail(&rqb_buffer->hbuf.list, &rqb_buf_list); } + + spin_lock_irqsave(&phba->hbalock, flags); while (!list_empty(&rqb_buf_list)) { list_remove_head(&rqb_buf_list, rqb_buffer, struct rqb_dmabuf, hbuf.list); @@ -7185,7 +7814,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys); rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe); if (rc < 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6421 Cannot post to HRQ %d: %x %x %x " "DRQ %x %x\n", hrq->queue_id, @@ -7205,6 +7834,619 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, return 1; } +static void +lpfc_mbx_cmpl_read_lds_params(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + union lpfc_sli4_cfg_shdr *shdr; + u32 shdr_status, shdr_add_status; + + shdr = (union lpfc_sli4_cfg_shdr *) + &pmb->u.mqe.un.sli4_config.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || pmb->u.mb.mbxStatus) { + lpfc_printf_log(phba, KERN_INFO, LOG_LDS_EVENT | LOG_MBOX, + "4622 SET_FEATURE (x%x) mbox failed, " + "status x%x add_status x%x, mbx status x%x\n", + LPFC_SET_LD_SIGNAL, shdr_status, + shdr_add_status, pmb->u.mb.mbxStatus); + phba->degrade_activate_threshold = 0; + phba->degrade_deactivate_threshold = 0; + phba->fec_degrade_interval = 0; + goto out; + } + + phba->degrade_activate_threshold = pmb->u.mqe.un.set_feature.word7; + phba->degrade_deactivate_threshold = pmb->u.mqe.un.set_feature.word8; + phba->fec_degrade_interval = pmb->u.mqe.un.set_feature.word10; + + lpfc_printf_log(phba, KERN_INFO, LOG_LDS_EVENT, + "4624 Success: da x%x dd x%x interval x%x\n", + phba->degrade_activate_threshold, + phba->degrade_deactivate_threshold, + phba->fec_degrade_interval); +out: + mempool_free(pmb, phba->mbox_mem_pool); +} + +int +lpfc_read_lds_params(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + int rc; + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + + lpfc_set_features(phba, mboxq, LPFC_SET_LD_SIGNAL); + mboxq->vport = phba->pport; + mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_lds_params; + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + mempool_free(mboxq, phba->mbox_mem_pool); + return -EIO; + } + return 0; +} + +static void +lpfc_mbx_cmpl_cgn_set_ftrs(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + struct lpfc_vport *vport = pmb->vport; + union lpfc_sli4_cfg_shdr *shdr; + u32 shdr_status, shdr_add_status; + u32 sig, acqe; + + /* Two outcomes. (1) Set featurs was successul and EDC negotiation + * is done. (2) Mailbox failed and send FPIN support only. + */ + shdr = (union lpfc_sli4_cfg_shdr *) + &pmb->u.mqe.un.sli4_config.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + if (shdr_status || shdr_add_status || pmb->u.mb.mbxStatus) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_CGN_MGMT, + "2516 CGN SET_FEATURE mbox failed with " + "status x%x add_status x%x, mbx status x%x " + "Reset Congestion to FPINs only\n", + shdr_status, shdr_add_status, + pmb->u.mb.mbxStatus); + /* If there is a mbox error, move on to RDF */ + phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED; + phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM; + goto out; + } + + /* Zero out Congestion Signal ACQE counter */ + phba->cgn_acqe_cnt = 0; + + acqe = bf_get(lpfc_mbx_set_feature_CGN_acqe_freq, + &pmb->u.mqe.un.set_feature); + sig = bf_get(lpfc_mbx_set_feature_CGN_warn_freq, + &pmb->u.mqe.un.set_feature); + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "4620 SET_FEATURES Success: Freq: %ds %dms " + " Reg: x%x x%x\n", acqe, sig, + phba->cgn_reg_signal, phba->cgn_reg_fpin); +out: + mempool_free(pmb, phba->mbox_mem_pool); + + /* Register for FPIN events from the fabric now that the + * EDC common_set_features has completed. + */ + lpfc_issue_els_rdf(vport, 0); +} + +int +lpfc_config_cgn_signal(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + u32 rc; + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + goto out_rdf; + + lpfc_set_features(phba, mboxq, LPFC_SET_CGN_SIGNAL); + mboxq->vport = phba->pport; + mboxq->mbox_cmpl = lpfc_mbx_cmpl_cgn_set_ftrs; + + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "4621 SET_FEATURES: FREQ sig x%x acqe x%x: " + "Reg: x%x x%x\n", + phba->cgn_sig_freq, lpfc_acqe_cgn_frequency, + phba->cgn_reg_signal, phba->cgn_reg_fpin); + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) + goto out; + return 0; + +out: + mempool_free(mboxq, phba->mbox_mem_pool); +out_rdf: + /* If there is a mbox error, move on to RDF */ + phba->cgn_reg_fpin = LPFC_CGN_FPIN_WARN | LPFC_CGN_FPIN_ALARM; + phba->cgn_reg_signal = EDC_CG_SIG_NOTSUPPORTED; + lpfc_issue_els_rdf(phba->pport, 0); + return -EIO; +} + +/** + * lpfc_init_idle_stat_hb - Initialize idle_stat tracking + * @phba: pointer to lpfc hba data structure. + * + * This routine initializes the per-cq idle_stat to dynamically dictate + * polling decisions. + * + * Return codes: + * None + **/ +static void lpfc_init_idle_stat_hb(struct lpfc_hba *phba) +{ + int i; + struct lpfc_sli4_hdw_queue *hdwq; + struct lpfc_queue *cq; + struct lpfc_idle_stat *idle_stat; + u64 wall; + + for_each_present_cpu(i) { + hdwq = &phba->sli4_hba.hdwq[phba->sli4_hba.cpu_map[i].hdwq]; + cq = hdwq->io_cq; + + /* Skip if we've already handled this cq's primary CPU */ + if (cq->chann != i) + continue; + + idle_stat = &phba->sli4_hba.idle_stat[i]; + + idle_stat->prev_idle = get_cpu_idle_time(i, &wall, 1); + idle_stat->prev_wall = wall; + + if (phba->nvmet_support || + phba->cmf_active_mode != LPFC_CFG_OFF) + cq->poll_mode = LPFC_QUEUE_WORK; + else + cq->poll_mode = LPFC_IRQ_POLL; + } + + if (!phba->nvmet_support) + schedule_delayed_work(&phba->idle_stat_delay_work, + msecs_to_jiffies(LPFC_IDLE_STAT_DELAY)); +} + +static void lpfc_sli4_dip(struct lpfc_hba *phba) +{ + uint32_t if_type; + + if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); + if (if_type == LPFC_SLI_INTF_IF_TYPE_2 || + if_type == LPFC_SLI_INTF_IF_TYPE_6) { + struct lpfc_register reg_data; + + if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, + ®_data.word0)) + return; + + if (bf_get(lpfc_sliport_status_dip, ®_data)) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2904 Firmware Dump Image Present" + " on Adapter"); + } +} + +/** + * lpfc_rx_monitor_create_ring - Initialize ring buffer for rx_monitor + * @rx_monitor: Pointer to lpfc_rx_info_monitor object + * @entries: Number of rx_info_entry objects to allocate in ring + * + * Return: + * 0 - Success + * ENOMEM - Failure to kmalloc + **/ +int lpfc_rx_monitor_create_ring(struct lpfc_rx_info_monitor *rx_monitor, + u32 entries) +{ + rx_monitor->ring = kmalloc_array(entries, sizeof(struct rx_info_entry), + GFP_KERNEL); + if (!rx_monitor->ring) + return -ENOMEM; + + rx_monitor->head_idx = 0; + rx_monitor->tail_idx = 0; + spin_lock_init(&rx_monitor->lock); + rx_monitor->entries = entries; + + return 0; +} + +/** + * lpfc_rx_monitor_destroy_ring - Free ring buffer for rx_monitor + * @rx_monitor: Pointer to lpfc_rx_info_monitor object + **/ +void lpfc_rx_monitor_destroy_ring(struct lpfc_rx_info_monitor *rx_monitor) +{ + spin_lock(&rx_monitor->lock); + kfree(rx_monitor->ring); + rx_monitor->ring = NULL; + rx_monitor->entries = 0; + rx_monitor->head_idx = 0; + rx_monitor->tail_idx = 0; + spin_unlock(&rx_monitor->lock); +} + +/** + * lpfc_rx_monitor_record - Insert an entry into rx_monitor's ring + * @rx_monitor: Pointer to lpfc_rx_info_monitor object + * @entry: Pointer to rx_info_entry + * + * Used to insert an rx_info_entry into rx_monitor's ring. Note that this is a + * deep copy of rx_info_entry not a shallow copy of the rx_info_entry ptr. + * + * This is called from lpfc_cmf_timer, which is in timer/softirq context. + * + * In cases of old data overflow, we do a best effort of FIFO order. + **/ +void lpfc_rx_monitor_record(struct lpfc_rx_info_monitor *rx_monitor, + struct rx_info_entry *entry) +{ + struct rx_info_entry *ring = rx_monitor->ring; + u32 *head_idx = &rx_monitor->head_idx; + u32 *tail_idx = &rx_monitor->tail_idx; + spinlock_t *ring_lock = &rx_monitor->lock; + u32 ring_size = rx_monitor->entries; + + spin_lock(ring_lock); + memcpy(&ring[*tail_idx], entry, sizeof(*entry)); + *tail_idx = (*tail_idx + 1) % ring_size; + + /* Best effort of FIFO saved data */ + if (*tail_idx == *head_idx) + *head_idx = (*head_idx + 1) % ring_size; + + spin_unlock(ring_lock); +} + +/** + * lpfc_rx_monitor_report - Read out rx_monitor's ring + * @phba: Pointer to lpfc_hba object + * @rx_monitor: Pointer to lpfc_rx_info_monitor object + * @buf: Pointer to char buffer that will contain rx monitor info data + * @buf_len: Length buf including null char + * @max_read_entries: Maximum number of entries to read out of ring + * + * Used to dump/read what's in rx_monitor's ring buffer. + * + * If buf is NULL || buf_len == 0, then it is implied that we want to log the + * information to kmsg instead of filling out buf. + * + * Return: + * Number of entries read out of the ring + **/ +u32 lpfc_rx_monitor_report(struct lpfc_hba *phba, + struct lpfc_rx_info_monitor *rx_monitor, char *buf, + u32 buf_len, u32 max_read_entries) +{ + struct rx_info_entry *ring = rx_monitor->ring; + struct rx_info_entry *entry; + u32 *head_idx = &rx_monitor->head_idx; + u32 *tail_idx = &rx_monitor->tail_idx; + spinlock_t *ring_lock = &rx_monitor->lock; + u32 ring_size = rx_monitor->entries; + u32 cnt = 0; + char tmp[DBG_LOG_STR_SZ] = {0}; + bool log_to_kmsg = (!buf || !buf_len) ? true : false; + + if (!log_to_kmsg) { + /* clear the buffer to be sure */ + memset(buf, 0, buf_len); + + scnprintf(buf, buf_len, "\t%-16s%-16s%-16s%-16s%-8s%-8s%-8s" + "%-8s%-8s%-8s%-16s\n", + "MaxBPI", "Tot_Data_CMF", + "Tot_Data_Cmd", "Tot_Data_Cmpl", + "Lat(us)", "Avg_IO", "Max_IO", "Bsy", + "IO_cnt", "Info", "BWutil(ms)"); + } + + /* Needs to be _bh because record is called from timer interrupt + * context + */ + spin_lock_bh(ring_lock); + while (*head_idx != *tail_idx) { + entry = &ring[*head_idx]; + + /* Read out this entry's data. */ + if (!log_to_kmsg) { + /* If !log_to_kmsg, then store to buf. */ + scnprintf(tmp, sizeof(tmp), + "%03d:\t%-16llu%-16llu%-16llu%-16llu%-8llu" + "%-8llu%-8llu%-8u%-8u%-8u%u(%u)\n", + *head_idx, entry->max_bytes_per_interval, + entry->cmf_bytes, entry->total_bytes, + entry->rcv_bytes, entry->avg_io_latency, + entry->avg_io_size, entry->max_read_cnt, + entry->cmf_busy, entry->io_cnt, + entry->cmf_info, entry->timer_utilization, + entry->timer_interval); + + /* Check for buffer overflow */ + if ((strlen(buf) + strlen(tmp)) >= buf_len) + break; + + /* Append entry's data to buffer */ + strlcat(buf, tmp, buf_len); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT, + "4410 %02u: MBPI %llu Xmit %llu " + "Cmpl %llu Lat %llu ASz %llu Info %02u " + "BWUtil %u Int %u slot %u\n", + cnt, entry->max_bytes_per_interval, + entry->total_bytes, entry->rcv_bytes, + entry->avg_io_latency, + entry->avg_io_size, entry->cmf_info, + entry->timer_utilization, + entry->timer_interval, *head_idx); + } + + *head_idx = (*head_idx + 1) % ring_size; + + /* Don't feed more than max_read_entries */ + cnt++; + if (cnt >= max_read_entries) + break; + } + spin_unlock_bh(ring_lock); + + return cnt; +} + +/** + * lpfc_cmf_setup - Initialize idle_stat tracking + * @phba: Pointer to HBA context object. + * + * This is called from HBA setup during driver load or when the HBA + * comes online. this does all the initialization to support CMF and MI. + **/ +static int +lpfc_cmf_setup(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + struct lpfc_dmabuf *mp; + struct lpfc_pc_sli4_params *sli4_params; + int rc, cmf, mi_ver; + + rc = lpfc_sli4_refresh_params(phba); + if (unlikely(rc)) + return rc; + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + + sli4_params = &phba->sli4_hba.pc_sli4_params; + + /* Always try to enable MI feature if we can */ + if (sli4_params->mi_ver) { + lpfc_set_features(phba, mboxq, LPFC_SET_ENABLE_MI); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + mi_ver = bf_get(lpfc_mbx_set_feature_mi, + &mboxq->u.mqe.un.set_feature); + + if (rc == MBX_SUCCESS) { + if (mi_ver) { + lpfc_printf_log(phba, + KERN_WARNING, LOG_CGN_MGMT, + "6215 MI is enabled\n"); + sli4_params->mi_ver = mi_ver; + } else { + lpfc_printf_log(phba, + KERN_WARNING, LOG_CGN_MGMT, + "6338 MI is disabled\n"); + sli4_params->mi_ver = 0; + } + } else { + /* mi_ver is already set from GET_SLI4_PARAMETERS */ + lpfc_printf_log(phba, KERN_INFO, + LOG_CGN_MGMT | LOG_INIT, + "6245 Enable MI Mailbox x%x (x%x/x%x) " + "failed, rc:x%x mi:x%x\n", + bf_get(lpfc_mqe_command, &mboxq->u.mqe), + lpfc_sli_config_mbox_subsys_get + (phba, mboxq), + lpfc_sli_config_mbox_opcode_get + (phba, mboxq), + rc, sli4_params->mi_ver); + } + } else { + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "6217 MI is disabled\n"); + } + + /* Ensure FDMI is enabled for MI if enable_mi is set */ + if (sli4_params->mi_ver) + phba->cfg_fdmi_on = LPFC_FDMI_SUPPORT; + + /* Always try to enable CMF feature if we can */ + if (sli4_params->cmf) { + lpfc_set_features(phba, mboxq, LPFC_SET_ENABLE_CMF); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + cmf = bf_get(lpfc_mbx_set_feature_cmf, + &mboxq->u.mqe.un.set_feature); + if (rc == MBX_SUCCESS && cmf) { + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "6218 CMF is enabled: mode %d\n", + phba->cmf_active_mode); + } else { + lpfc_printf_log(phba, KERN_WARNING, + LOG_CGN_MGMT | LOG_INIT, + "6219 Enable CMF Mailbox x%x (x%x/x%x) " + "failed, rc:x%x dd:x%x\n", + bf_get(lpfc_mqe_command, &mboxq->u.mqe), + lpfc_sli_config_mbox_subsys_get + (phba, mboxq), + lpfc_sli_config_mbox_opcode_get + (phba, mboxq), + rc, cmf); + sli4_params->cmf = 0; + phba->cmf_active_mode = LPFC_CFG_OFF; + goto no_cmf; + } + + /* Allocate Congestion Information Buffer */ + if (!phba->cgn_i) { + mp = kmalloc(sizeof(*mp), GFP_KERNEL); + if (mp) + mp->virt = dma_alloc_coherent + (&phba->pcidev->dev, + sizeof(struct lpfc_cgn_info), + &mp->phys, GFP_KERNEL); + if (!mp || !mp->virt) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2640 Failed to alloc memory " + "for Congestion Info\n"); + kfree(mp); + sli4_params->cmf = 0; + phba->cmf_active_mode = LPFC_CFG_OFF; + goto no_cmf; + } + phba->cgn_i = mp; + + /* initialize congestion buffer info */ + lpfc_init_congestion_buf(phba); + lpfc_init_congestion_stat(phba); + + /* Zero out Congestion Signal counters */ + atomic64_set(&phba->cgn_acqe_stat.alarm, 0); + atomic64_set(&phba->cgn_acqe_stat.warn, 0); + } + + rc = lpfc_sli4_cgn_params_read(phba); + if (rc < 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "6242 Error reading Cgn Params (%d)\n", + rc); + /* Ensure CGN Mode is off */ + sli4_params->cmf = 0; + } else if (!rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_CGN_MGMT | LOG_INIT, + "6243 CGN Event empty object.\n"); + /* Ensure CGN Mode is off */ + sli4_params->cmf = 0; + } + } else { +no_cmf: + lpfc_printf_log(phba, KERN_WARNING, LOG_CGN_MGMT, + "6220 CMF is disabled\n"); + } + + /* Only register congestion buffer with firmware if BOTH + * CMF and E2E are enabled. + */ + if (sli4_params->cmf && sli4_params->mi_ver) { + rc = lpfc_reg_congestion_buf(phba); + if (rc) { + dma_free_coherent(&phba->pcidev->dev, + sizeof(struct lpfc_cgn_info), + phba->cgn_i->virt, phba->cgn_i->phys); + kfree(phba->cgn_i); + phba->cgn_i = NULL; + /* Ensure CGN Mode is off */ + phba->cmf_active_mode = LPFC_CFG_OFF; + return 0; + } + } + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "6470 Setup MI version %d CMF %d mode %d\n", + sli4_params->mi_ver, sli4_params->cmf, + phba->cmf_active_mode); + + mempool_free(mboxq, phba->mbox_mem_pool); + + /* Initialize atomic counters */ + atomic_set(&phba->cgn_fabric_warn_cnt, 0); + atomic_set(&phba->cgn_fabric_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_alarm_cnt, 0); + atomic_set(&phba->cgn_sync_warn_cnt, 0); + atomic_set(&phba->cgn_driver_evt_cnt, 0); + atomic_set(&phba->cgn_latency_evt_cnt, 0); + atomic64_set(&phba->cgn_latency_evt, 0); + + phba->cmf_interval_rate = LPFC_CMF_INTERVAL; + + /* Allocate RX Monitor Buffer */ + if (!phba->rx_monitor) { + phba->rx_monitor = kzalloc(sizeof(*phba->rx_monitor), + GFP_KERNEL); + + if (!phba->rx_monitor) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2644 Failed to alloc memory " + "for RX Monitor Buffer\n"); + return -ENOMEM; + } + + /* Instruct the rx_monitor object to instantiate its ring */ + if (lpfc_rx_monitor_create_ring(phba->rx_monitor, + LPFC_MAX_RXMONITOR_ENTRY)) { + kfree(phba->rx_monitor); + phba->rx_monitor = NULL; + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2645 Failed to alloc memory " + "for RX Monitor's Ring\n"); + return -ENOMEM; + } + } + + return 0; +} + +static int +lpfc_set_host_tm(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *mboxq; + uint32_t len, rc; + struct timespec64 cur_time; + struct tm broken; + uint32_t month, day, year; + uint32_t hour, minute, second; + struct lpfc_mbx_set_host_date_time *tm; + + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) + return -ENOMEM; + + len = sizeof(struct lpfc_mbx_set_host_data) - + sizeof(struct lpfc_sli4_cfg_mhdr); + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_SET_HOST_DATA, len, + LPFC_SLI4_MBX_EMBED); + + mboxq->u.mqe.un.set_host_data.param_id = LPFC_SET_HOST_DATE_TIME; + mboxq->u.mqe.un.set_host_data.param_len = + sizeof(struct lpfc_mbx_set_host_date_time); + tm = &mboxq->u.mqe.un.set_host_data.un.tm; + ktime_get_real_ts64(&cur_time); + time64_to_tm(cur_time.tv_sec, 0, &broken); + month = broken.tm_mon + 1; + day = broken.tm_mday; + year = broken.tm_year - 100; + hour = broken.tm_hour; + minute = broken.tm_min; + second = broken.tm_sec; + bf_set(lpfc_mbx_set_host_month, tm, month); + bf_set(lpfc_mbx_set_host_day, tm, day); + bf_set(lpfc_mbx_set_host_year, tm, year); + bf_set(lpfc_mbx_set_host_hour, tm, hour); + bf_set(lpfc_mbx_set_host_min, tm, minute); + bf_set(lpfc_mbx_set_host_sec, tm, second); + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + mempool_free(mboxq, phba->mbox_mem_pool); + return rc; +} + /** * lpfc_sli4_hba_setup - SLI4 device initialization PCI function * @phba: Pointer to HBA context object. @@ -7227,6 +8469,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) struct lpfc_vport *vport = phba->pport; struct lpfc_dmabuf *mp; struct lpfc_rqb *rqbp; + u32 flg; /* Perform a PCI function reset to start from clean */ rc = lpfc_pci_function_reset(phba); @@ -7240,9 +8483,21 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) else { spin_lock_irq(&phba->hbalock); phba->sli.sli_flag |= LPFC_SLI_ACTIVE; + flg = phba->sli.sli_flag; spin_unlock_irq(&phba->hbalock); + /* Allow a little time after setting SLI_ACTIVE for any polled + * MBX commands to complete via BSG. + */ + for (i = 0; i < 50 && (flg & LPFC_SLI_MBOX_ACTIVE); i++) { + msleep(20); + spin_lock_irq(&phba->hbalock); + flg = phba->sli.sli_flag; + spin_unlock_irq(&phba->hbalock); + } } + lpfc_sli4_dip(phba); + /* * Allocate a single mailbox container for initializing the * port. @@ -7283,7 +8538,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->hba_flag &= ~HBA_IOQ_FLUSH; if (phba->sli_rev != LPFC_SLI_REV4) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0376 READ_REV Error. SLI Level %d " "FCoE enabled %d\n", phba->sli_rev, phba->hba_flag & HBA_FCOE_MODE); @@ -7292,6 +8547,10 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) goto out_free_mbox; } + rc = lpfc_set_host_tm(phba); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, + "6468 Set host date / time: Status x%x:\n", rc); + /* * Continue initialization with default values even if driver failed * to read FCoE param config regions, only read parameters if the @@ -7325,7 +8584,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) */ rc = lpfc_parse_vpd(phba, vpd, vpd_size); if (unlikely(!rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0377 Error %d parsing vpd. " "Using defaults.\n", rc); rc = 0; @@ -7371,15 +8630,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow, phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow); - /* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */ - rc = (phba->sli4_hba.max_cfg_param.max_xri >> 3); - if (phba->pport->cfg_lun_queue_depth > rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "3362 LUN queue depth changed from %d to %d\n", - phba->pport->cfg_lun_queue_depth, rc); - phba->pport->cfg_lun_queue_depth = rc; - } - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_IF_TYPE_0) { lpfc_set_features(phba, mboxq, LPFC_SET_UE_RECOVERY); @@ -7416,6 +8666,15 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) goto out_free_mbox; } + /* Disable VMID if app header is not supported */ + if (phba->cfg_vmid_app_header && !(bf_get(lpfc_mbx_rq_ftr_rsp_ashdr, + &mqe->un.req_ftrs))) { + bf_set(lpfc_ftr_ashdr, &phba->sli4_hba.sli4_flags, 0); + phba->cfg_vmid_app_header = 0; + lpfc_printf_log(phba, KERN_DEBUG, LOG_SLI, + "1242 vmid feature not supported\n"); + } + /* * The port must support FCP initiator mode as this is the * only mode running in the host. @@ -7473,7 +8732,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); dd = bf_get(lpfc_mbx_set_feature_dd, &mboxq->u.mqe.un.set_feature); if ((rc == MBX_SUCCESS) && (dd == LPFC_ENABLE_DUAL_DUMP)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "6448 Dual Dump is enabled\n"); else lpfc_printf_log(phba, KERN_INFO, LOG_SLI | LOG_INIT, @@ -7491,7 +8750,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) */ rc = lpfc_sli4_alloc_resource_identifiers(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2920 Failed to alloc Resource IDs " "rc = x%x\n", rc); goto out_free_mbox; @@ -7523,14 +8782,15 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) } /* - * This memory was allocated by the lpfc_read_sparam routine. Release - * it to the mbuf pool. + * This memory was allocated by the lpfc_read_sparam routine but is + * no longer needed. It is released and ctx_buf NULLed to prevent + * unintended pointer access as the mbox is reused. */ lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mboxq->ctx_buf = NULL; if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0382 READ_SPARAM command failed " "status %d, mbxStatus x%x\n", rc, bf_get(lpfc_mqe_status, mqe)); @@ -7548,7 +8808,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Create all the SLI4 queues */ rc = lpfc_sli4_queue_create(phba); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3089 Failed to allocate queues\n"); rc = -ENODEV; goto out_free_mbox; @@ -7556,7 +8816,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Set up all the queues to the device */ rc = lpfc_sli4_queue_setup(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0381 Error %d during queue setup.\n ", rc); goto out_stop_timers; } @@ -7567,7 +8827,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* update host els xri-sgl sizes and mappings */ rc = lpfc_sli4_els_sgl_update(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1400 Failed to update xri-sgl size and " "mapping: %d\n", rc); goto out_destroy_queue; @@ -7577,7 +8837,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = lpfc_sli4_repost_sgl_list(phba, &phba->sli4_hba.lpfc_els_sgl_list, phba->sli4_hba.els_xri_cnt); if (unlikely(rc < 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0582 Error %d during els sgl post " "operation\n", rc); rc = -ENODEV; @@ -7589,7 +8849,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* update host nvmet xri-sgl sizes and mappings */ rc = lpfc_sli4_nvmet_sgl_update(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6308 Failed to update nvmet-sgl size " "and mapping: %d\n", rc); goto out_destroy_queue; @@ -7601,7 +8861,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) &phba->sli4_hba.lpfc_nvmet_sgl_list, phba->sli4_hba.nvmet_xri_cnt); if (unlikely(rc < 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3117 Error %d during nvmet " "sgl post\n", rc); rc = -ENODEV; @@ -7618,7 +8878,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* update host common xri-sgl sizes and mappings */ rc = lpfc_sli4_io_sgl_update(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6082 Failed to update nvme-sgl size " "and mapping: %d\n", rc); goto out_destroy_queue; @@ -7627,7 +8887,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* register the allocated common sgl pool to the port */ rc = lpfc_sli4_repost_io_sgl_list(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6116 Error %d during nvme sgl post " "operation\n", rc); /* Some NVME buffers were moved to abort nvme list */ @@ -7648,7 +8908,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) cnt); rc = lpfc_init_iocb_list(phba, cnt); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1413 Failed to init iocb list.\n"); goto out_destroy_queue; } @@ -7677,11 +8937,11 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Post the rpi header region to the device. */ rc = lpfc_sli4_post_all_rpi_hdrs(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0393 Error %d during rpi post operation\n", rc); rc = -ENODEV; - goto out_destroy_queue; + goto out_free_iocblist; } lpfc_sli4_node_prep(phba); @@ -7761,7 +9021,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Start heart beat timer */ mod_timer(&phba->hb_tmofunc, jiffies + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL)); - phba->hb_outstanding = 0; + phba->hba_flag &= ~(HBA_HBEAT_INP | HBA_HBEAT_TMO); phba->last_completion_time = jiffies; /* start eq_delay heartbeat */ @@ -7769,6 +9029,9 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) queue_delayed_work(phba->wq, &phba->eq_delay_work, msecs_to_jiffies(LPFC_EQ_DELAY_MSECS)); + /* start per phba idle_stat_delay heartbeat */ + lpfc_init_idle_stat_hb(phba); + /* Start error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval)); @@ -7816,14 +9079,17 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Indicate device interrupt mode */ phba->sli4_hba.intr_enable = 1; + /* Setup CMF after HBA is initialized */ + lpfc_cmf_setup(phba); + if (!(phba->hba_flag & HBA_FCOE_MODE) && (phba->hba_flag & LINK_DISABLED)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3103 Adapter Link is disabled.\n"); lpfc_down_link(phba, mboxq); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3104 Adapter failed to issue " "DOWN_LINK mbox cmd, rc:x%x\n", rc); goto out_io_buff_free; @@ -7837,15 +9103,22 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) } } mempool_free(mboxq, phba->mbox_mem_pool); + + /* Enable RAS FW log support */ + lpfc_sli4_ras_setup(phba); + + phba->hba_flag |= HBA_SETUP; return rc; + out_io_buff_free: /* Free allocated IO Buffers */ lpfc_io_free(phba); out_unset_queue: /* Unset all the queues set up in this routine when error out */ lpfc_sli4_queue_unset(phba); -out_destroy_queue: +out_free_iocblist: lpfc_free_iocb_list(phba); +out_destroy_queue: lpfc_sli4_queue_destroy(phba); out_stop_timers: lpfc_stop_hba_timers(phba); @@ -7856,7 +9129,7 @@ out_free_mbox: /** * lpfc_mbox_timeout - Timeout call back function for mbox timer - * @ptr: context object - pointer to hba structure. + * @t: Context to fetch pointer to hba structure from. * * This is the callback function for mailbox timer. The mailbox * timer is armed when a new mailbox command is issued and the timer @@ -8008,8 +9281,10 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; - /* If the mailbox completed, process the completion and return */ - if (lpfc_sli4_process_missed_mbox_completions(phba)) + /* If the mailbox completed, process the completion */ + lpfc_sli4_process_missed_mbox_completions(phba); + + if (!(psli->sli_flag & LPFC_SLI_ACTIVE)) return; if (pmbox != NULL) @@ -8030,7 +9305,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) } /* Mbox cmd <mbxCommand> timeout */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0310 Mailbox command x%x timeout Data: x%x x%x x%px\n", mb->mbxCommand, phba->pport->port_state, @@ -8050,9 +9325,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); - lpfc_sli_abort_fcp_rings(phba); - - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0345 Resetting board due to mailbox timeout\n"); /* Reset the HBA device */ @@ -8150,7 +9423,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command <mbxCommand> cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):0311 Mailbox command x%x cannot " "issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8162,7 +9435,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, if (lpfc_readl(phba->HCregaddr, &hc_copy) || !(hc_copy & HC_MBINT_ENA)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2528 Mailbox command x%x cannot " "issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8181,7 +9454,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command <mbxCommand> cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2529 Mailbox command x%x " "cannot issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8193,7 +9466,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, if (!(psli->sli_flag & LPFC_SLI_ACTIVE)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command <mbxCommand> cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2530 Mailbox command x%x " "cannot issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8246,7 +9519,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command <mbxCommand> cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2531 Mailbox command x%x " "cannot issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, @@ -8494,8 +9767,11 @@ static int lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; + LPFC_MBOXQ_t *mboxq; int rc = 0; unsigned long timeout = 0; + u32 sli_flag; + u8 cmd, subsys, opcode; /* Mark the asynchronous mailbox command posting as blocked */ spin_lock_irq(&phba->hbalock); @@ -8513,12 +9789,37 @@ lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) if (timeout) lpfc_sli4_process_missed_mbox_completions(phba); - /* Wait for the outstnading mailbox command to complete */ + /* Wait for the outstanding mailbox command to complete */ while (phba->sli.mbox_active) { /* Check active mailbox complete status every 2ms */ msleep(2); if (time_after(jiffies, timeout)) { - /* Timeout, marked the outstanding cmd not complete */ + /* Timeout, mark the outstanding cmd not complete */ + + /* Sanity check sli.mbox_active has not completed or + * cancelled from another context during last 2ms sleep, + * so take hbalock to be sure before logging. + */ + spin_lock_irq(&phba->hbalock); + if (phba->sli.mbox_active) { + mboxq = phba->sli.mbox_active; + cmd = mboxq->u.mb.mbxCommand; + subsys = lpfc_sli_config_mbox_subsys_get(phba, + mboxq); + opcode = lpfc_sli_config_mbox_opcode_get(phba, + mboxq); + sli_flag = psli->sli_flag; + spin_unlock_irq(&phba->hbalock); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2352 Mailbox command x%x " + "(x%x/x%x) sli_flag x%x could " + "not complete\n", + cmd, subsys, opcode, + sli_flag); + } else { + spin_unlock_irq(&phba->hbalock); + } + rc = 1; break; } @@ -8637,7 +9938,7 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) spin_lock_irqsave(&phba->hbalock, iflag); if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2532 Mailbox command x%x (x%x/x%x) " "cannot issue Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, @@ -8736,7 +10037,7 @@ exit: /** * lpfc_sli_issue_mbox_s4 - Issue an SLI4 mailbox command to firmware * @phba: Pointer to HBA context object. - * @pmbox: Pointer to mailbox object. + * @mboxq: Pointer to mailbox object. * @flag: Flag indicating how the mailbox need to be processed. * * This function is called by discovery code and HBA management code to submit @@ -8758,7 +10059,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, rc = lpfc_mbox_dev_check(phba); if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2544 Mailbox command x%x (x%x/x%x) " "cannot issue Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, @@ -8780,7 +10081,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, "(%d):2541 Mailbox command x%x " "(x%x/x%x) failure: " "mqe_sta: x%x mcqe_sta: x%x/x%x " - "Data: x%x x%x\n,", + "Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, @@ -8814,7 +10115,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, "(%d):2597 Sync Mailbox command " "x%x (x%x/x%x) failure: " "mqe_sta: x%x mcqe_sta: x%x/x%x " - "Data: x%x x%x\n,", + "Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, @@ -8835,7 +10136,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, /* Now, interrupt mode asynchronous mailbox command */ rc = lpfc_mbox_cmd_check(phba, mboxq); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2543 Mailbox command x%x (x%x/x%x) " "cannot issue Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, @@ -8903,7 +10204,7 @@ lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) } if (unlikely(phba->sli.mbox_active)) { spin_unlock_irqrestore(&phba->hbalock, iflags); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0384 There is pending active mailbox cmd\n"); return MBX_NOT_FINISHED; } @@ -8964,7 +10265,7 @@ lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) /* Post the mailbox command to the port */ rc = lpfc_sli4_mq_put(phba->sli4_hba.mbx_wq, mqe); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):2533 Mailbox command x%x (x%x/x%x) " "cannot issue Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, @@ -9044,7 +10345,6 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) "1420 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } return 0; } @@ -9138,11 +10438,10 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number, lockdep_assert_held(&phba->hbalock); - if (piocb->iocb_cmpl && (!piocb->vport) && + if (piocb->cmd_cmpl && (!piocb->vport) && (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) { - lpfc_printf_log(phba, KERN_ERR, - LOG_SLI | LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1807 IOCB x%x failed. No vport\n", piocb->iocb.ulpCommand); dump_stack(); @@ -9177,25 +10476,15 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number, * can be issued if the link is not up. */ switch (piocb->iocb.ulpCommand) { - case CMD_GEN_REQUEST64_CR: - case CMD_GEN_REQUEST64_CX: - if (!(phba->sli.sli_flag & LPFC_MENLO_MAINT) || - (piocb->iocb.un.genreq64.w5.hcsw.Rctl != - FC_RCTL_DD_UNSOL_CMD) || - (piocb->iocb.un.genreq64.w5.hcsw.Type != - MENLO_TRANSPORT_TYPE)) - - goto iocb_busy; - break; case CMD_QUE_RING_BUF_CN: case CMD_QUE_RING_BUF64_CN: /* * For IOCBs, like QUE_RING_BUF, that have no rsp ring - * completion, iocb_cmpl MUST be 0. + * completion, cmd_cmpl MUST be 0. */ - if (piocb->iocb_cmpl) - piocb->iocb_cmpl = NULL; - /*FALLTHROUGH*/ + if (piocb->cmd_cmpl) + piocb->cmd_cmpl = NULL; + fallthrough; case CMD_CREATE_XRI_CR: case CMD_CLOSE_XRI_CN: case CMD_CLOSE_XRI_CX: @@ -9241,711 +10530,110 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number, } /** - * lpfc_sli4_bpl2sgl - Convert the bpl/bde to a sgl. + * __lpfc_sli_issue_fcp_io_s3 - SLI3 device for sending fcp io iocb * @phba: Pointer to HBA context object. + * @ring_number: SLI ring number to issue wqe on. * @piocb: Pointer to command iocb. - * @sglq: Pointer to the scatter gather queue object. + * @flag: Flag indicating if this command can be put into txq. * - * This routine converts the bpl or bde that is in the IOCB - * to a sgl list for the sli4 hardware. The physical address - * of the bpl/bde is converted back to a virtual address. - * If the IOCB contains a BPL then the list of BDE's is - * converted to sli4_sge's. If the IOCB contains a single - * BDE then it is converted to a single sli_sge. - * The IOCB is still in cpu endianess so the contents of - * the bpl can be used without byte swapping. + * __lpfc_sli_issue_fcp_io_s3 is wrapper function to invoke lockless func to + * send an iocb command to an HBA with SLI-3 interface spec. * - * Returns valid XRI = Success, NO_XRI = Failure. -**/ -static uint16_t -lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, - struct lpfc_sglq *sglq) + * This function takes the hbalock before invoking the lockless version. + * The function will return success after it successfully submit the wqe to + * firmware or after adding to the txq. + **/ +static int +__lpfc_sli_issue_fcp_io_s3(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) { - uint16_t xritag = NO_XRI; - struct ulp_bde64 *bpl = NULL; - struct ulp_bde64 bde; - struct sli4_sge *sgl = NULL; - struct lpfc_dmabuf *dmabuf; - IOCB_t *icmd; - int numBdes = 0; - int i = 0; - uint32_t offset = 0; /* accumulated offset in the sg request list */ - int inbound = 0; /* number of sg reply entries inbound from firmware */ - - if (!piocbq || !sglq) - return xritag; - - sgl = (struct sli4_sge *)sglq->sgl; - icmd = &piocbq->iocb; - if (icmd->ulpCommand == CMD_XMIT_BLS_RSP64_CX) - return sglq->sli4_xritag; - if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { - numBdes = icmd->un.genreq64.bdl.bdeSize / - sizeof(struct ulp_bde64); - /* The addrHigh and addrLow fields within the IOCB - * have not been byteswapped yet so there is no - * need to swap them back. - */ - if (piocbq->context3) - dmabuf = (struct lpfc_dmabuf *)piocbq->context3; - else - return xritag; - - bpl = (struct ulp_bde64 *)dmabuf->virt; - if (!bpl) - return xritag; + unsigned long iflags; + int rc; - for (i = 0; i < numBdes; i++) { - /* Should already be byte swapped. */ - sgl->addr_hi = bpl->addrHigh; - sgl->addr_lo = bpl->addrLow; + spin_lock_irqsave(&phba->hbalock, iflags); + rc = __lpfc_sli_issue_iocb_s3(phba, ring_number, piocb, flag); + spin_unlock_irqrestore(&phba->hbalock, iflags); - sgl->word2 = le32_to_cpu(sgl->word2); - if ((i+1) == numBdes) - bf_set(lpfc_sli4_sge_last, sgl, 1); - else - bf_set(lpfc_sli4_sge_last, sgl, 0); - /* swap the size field back to the cpu so we - * can assign it to the sgl. - */ - bde.tus.w = le32_to_cpu(bpl->tus.w); - sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize); - /* The offsets in the sgl need to be accumulated - * separately for the request and reply lists. - * The request is always first, the reply follows. - */ - if (piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) { - /* add up the reply sg entries */ - if (bpl->tus.f.bdeFlags == BUFF_TYPE_BDE_64I) - inbound++; - /* first inbound? reset the offset */ - if (inbound == 1) - offset = 0; - bf_set(lpfc_sli4_sge_offset, sgl, offset); - bf_set(lpfc_sli4_sge_type, sgl, - LPFC_SGE_TYPE_DATA); - offset += bde.tus.f.bdeSize; - } - sgl->word2 = cpu_to_le32(sgl->word2); - bpl++; - sgl++; - } - } else if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BDE_64) { - /* The addrHigh and addrLow fields of the BDE have not - * been byteswapped yet so they need to be swapped - * before putting them in the sgl. - */ - sgl->addr_hi = - cpu_to_le32(icmd->un.genreq64.bdl.addrHigh); - sgl->addr_lo = - cpu_to_le32(icmd->un.genreq64.bdl.addrLow); - sgl->word2 = le32_to_cpu(sgl->word2); - bf_set(lpfc_sli4_sge_last, sgl, 1); - sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = - cpu_to_le32(icmd->un.genreq64.bdl.bdeSize); - } - return sglq->sli4_xritag; + return rc; } /** - * lpfc_sli_iocb2wqe - Convert the IOCB to a work queue entry. + * __lpfc_sli_issue_fcp_io_s4 - SLI4 device for sending fcp io wqe * @phba: Pointer to HBA context object. + * @ring_number: SLI ring number to issue wqe on. * @piocb: Pointer to command iocb. - * @wqe: Pointer to the work queue entry. + * @flag: Flag indicating if this command can be put into txq. * - * This routine converts the iocb command to its Work Queue Entry - * equivalent. The wqe pointer should not have any fields set when - * this routine is called because it will memcpy over them. - * This routine does not set the CQ_ID or the WQEC bits in the - * wqe. + * __lpfc_sli_issue_fcp_io_s4 is used by other functions in the driver to issue + * an wqe command to an HBA with SLI-4 interface spec. * - * Returns: 0 = Success, IOCB_ERROR = Failure. + * This function is a lockless version. The function will return success + * after it successfully submit the wqe to firmware or after adding to the + * txq. **/ static int -lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, - union lpfc_wqe128 *wqe) -{ - uint32_t xmit_len = 0, total_len = 0; - uint8_t ct = 0; - uint32_t fip; - uint32_t abort_tag; - uint8_t command_type = ELS_COMMAND_NON_FIP; - uint8_t cmnd; - uint16_t xritag; - uint16_t abrt_iotag; - struct lpfc_iocbq *abrtiocbq; - struct ulp_bde64 *bpl = NULL; - uint32_t els_id = LPFC_ELS_ID_DEFAULT; - int numBdes, i; - struct ulp_bde64 bde; - struct lpfc_nodelist *ndlp; - uint32_t *pcmd; - uint32_t if_type; - - fip = phba->hba_flag & HBA_FIP_SUPPORT; - /* The fcp commands will set command type */ - if (iocbq->iocb_flag & LPFC_IO_FCP) - command_type = FCP_COMMAND; - else if (fip && (iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK)) - command_type = ELS_COMMAND_FIP; - else - command_type = ELS_COMMAND_NON_FIP; - - if (phba->fcp_embed_io) - memset(wqe, 0, sizeof(union lpfc_wqe128)); - /* Some of the fields are in the right position already */ - memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe)); - /* The ct field has moved so reset */ - wqe->generic.wqe_com.word7 = 0; - wqe->generic.wqe_com.word10 = 0; - - abort_tag = (uint32_t) iocbq->iotag; - xritag = iocbq->sli4_xritag; - /* words0-2 bpl convert bde */ - if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { - numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / - sizeof(struct ulp_bde64); - bpl = (struct ulp_bde64 *) - ((struct lpfc_dmabuf *)iocbq->context3)->virt; - if (!bpl) - return IOCB_ERROR; +__lpfc_sli_issue_fcp_io_s4(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + struct lpfc_io_buf *lpfc_cmd = piocb->io_buf; - /* Should already be byte swapped. */ - wqe->generic.bde.addrHigh = le32_to_cpu(bpl->addrHigh); - wqe->generic.bde.addrLow = le32_to_cpu(bpl->addrLow); - /* swap the size field back to the cpu so we - * can assign it to the sgl. - */ - wqe->generic.bde.tus.w = le32_to_cpu(bpl->tus.w); - xmit_len = wqe->generic.bde.tus.f.bdeSize; - total_len = 0; - for (i = 0; i < numBdes; i++) { - bde.tus.w = le32_to_cpu(bpl[i].tus.w); - total_len += bde.tus.f.bdeSize; - } - } else - xmit_len = iocbq->iocb.un.fcpi64.bdl.bdeSize; + lpfc_prep_embed_io(phba, lpfc_cmd); + return lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, piocb); +} - iocbq->iocb.ulpIoTag = iocbq->iotag; - cmnd = iocbq->iocb.ulpCommand; +void +lpfc_prep_embed_io(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) +{ + struct lpfc_iocbq *piocb = &lpfc_cmd->cur_iocbq; + union lpfc_wqe128 *wqe = &lpfc_cmd->cur_iocbq.wqe; + struct sli4_sge *sgl; - switch (iocbq->iocb.ulpCommand) { - case CMD_ELS_REQUEST64_CR: - if (iocbq->iocb_flag & LPFC_IO_LIBDFC) - ndlp = iocbq->context_un.ndlp; - else - ndlp = (struct lpfc_nodelist *)iocbq->context1; - if (!iocbq->iocb.ulpLe) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2007 Only Limited Edition cmd Format" - " supported 0x%x\n", - iocbq->iocb.ulpCommand); - return IOCB_ERROR; - } + /* 128 byte wqe support here */ + sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; - wqe->els_req.payload_len = xmit_len; - /* Els_reguest64 has a TMO */ - bf_set(wqe_tmo, &wqe->els_req.wqe_com, - iocbq->iocb.ulpTimeout); - /* Need a VF for word 4 set the vf bit*/ - bf_set(els_req64_vf, &wqe->els_req, 0); - /* And a VFID for word 12 */ - bf_set(els_req64_vfid, &wqe->els_req, 0); - ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - iocbq->iocb.ulpContext); - bf_set(wqe_ct, &wqe->els_req.wqe_com, ct); - bf_set(wqe_pu, &wqe->els_req.wqe_com, 0); - /* CCP CCPE PV PRI in word10 were set in the memcpy */ - if (command_type == ELS_COMMAND_FIP) - els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK) - >> LPFC_FIP_ELS_ID_SHIFT); - pcmd = (uint32_t *) (((struct lpfc_dmabuf *) - iocbq->context2)->virt); - if_type = bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf); - if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { - if (pcmd && (*pcmd == ELS_CMD_FLOGI || - *pcmd == ELS_CMD_SCR || - *pcmd == ELS_CMD_RSCN_XMT || - *pcmd == ELS_CMD_FDISC || - *pcmd == ELS_CMD_LOGO || - *pcmd == ELS_CMD_PLOGI)) { - bf_set(els_req64_sp, &wqe->els_req, 1); - bf_set(els_req64_sid, &wqe->els_req, - iocbq->vport->fc_myDID); - if ((*pcmd == ELS_CMD_FLOGI) && - !(phba->fc_topology == - LPFC_TOPOLOGY_LOOP)) - bf_set(els_req64_sid, &wqe->els_req, 0); - bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - phba->vpi_ids[iocbq->vport->vpi]); - } else if (pcmd && iocbq->context1) { - bf_set(wqe_ct, &wqe->els_req.wqe_com, 0); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); - } - } - bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, - phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); - bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id); - bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1); - bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ); - bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE); - bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0); - wqe->els_req.max_response_payload_len = total_len - xmit_len; - break; - case CMD_XMIT_SEQUENCE64_CX: - bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com, - iocbq->iocb.un.ulpWord[3]); - bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com, - iocbq->iocb.unsli3.rcvsli3.ox_id); - /* The entire sequence is transmitted for this IOCB */ - xmit_len = total_len; - cmnd = CMD_XMIT_SEQUENCE64_CR; - if (phba->link_flag & LS_LOOPBACK_MODE) - bf_set(wqe_xo, &wqe->xmit_sequence.wge_ctl, 1); - /* fall through */ - case CMD_XMIT_SEQUENCE64_CR: - /* word3 iocb=io_tag32 wqe=reserved */ - wqe->xmit_sequence.rsvd3 = 0; - /* word4 relative_offset memcpy */ - /* word5 r_ctl/df_ctl memcpy */ - bf_set(wqe_pu, &wqe->xmit_sequence.wqe_com, 0); - bf_set(wqe_dbde, &wqe->xmit_sequence.wqe_com, 1); - bf_set(wqe_iod, &wqe->xmit_sequence.wqe_com, - LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->xmit_sequence.wqe_com, - LPFC_WQE_LENLOC_WORD12); - bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0); - wqe->xmit_sequence.xmit_len = xmit_len; - command_type = OTHER_COMMAND; - break; - case CMD_XMIT_BCAST64_CN: - /* word3 iocb=iotag32 wqe=seq_payload_len */ - wqe->xmit_bcast64.seq_payload_len = xmit_len; - /* word4 iocb=rsvd wqe=rsvd */ - /* word5 iocb=rctl/type/df_ctl wqe=rctl/type/df_ctl memcpy */ - /* word6 iocb=ctxt_tag/io_tag wqe=ctxt_tag/xri */ - bf_set(wqe_ct, &wqe->xmit_bcast64.wqe_com, - ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); - bf_set(wqe_dbde, &wqe->xmit_bcast64.wqe_com, 1); - bf_set(wqe_iod, &wqe->xmit_bcast64.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->xmit_bcast64.wqe_com, - LPFC_WQE_LENLOC_WORD3); - bf_set(wqe_ebde_cnt, &wqe->xmit_bcast64.wqe_com, 0); - break; - case CMD_FCP_IWRITE64_CR: - command_type = FCP_COMMAND_DATA_OUT; - /* word3 iocb=iotag wqe=payload_offset_len */ - /* Add the FCP_CMD and FCP_RSP sizes to get the offset */ - bf_set(payload_offset_len, &wqe->fcp_iwrite, - xmit_len + sizeof(struct fcp_rsp)); - bf_set(cmd_buff_len, &wqe->fcp_iwrite, - 0); - /* word4 iocb=parameter wqe=total_xfer_length memcpy */ - /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */ - bf_set(wqe_erp, &wqe->fcp_iwrite.wqe_com, - iocbq->iocb.ulpFCP2Rcvy); - bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS); - /* Always open the exchange */ - bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, - LPFC_WQE_LENLOC_WORD4); - bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU); - bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1); - if (iocbq->iocb_flag & LPFC_IO_OAS) { - bf_set(wqe_oas, &wqe->fcp_iwrite.wqe_com, 1); - bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1); - if (iocbq->priority) { - bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com, - (iocbq->priority << 1)); - } else { - bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com, - (phba->cfg_XLanePriority << 1)); - } - } - /* Note, word 10 is already initialized to 0 */ + if (phba->fcp_embed_io) { + struct fcp_cmnd *fcp_cmnd; + u32 *ptr; - /* Don't set PBDE for Perf hints, just lpfc_enable_pbde */ - if (phba->cfg_enable_pbde) - bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 1); - else - bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0); + fcp_cmnd = lpfc_cmd->fcp_cmnd; - if (phba->fcp_embed_io) { - struct lpfc_io_buf *lpfc_cmd; - struct sli4_sge *sgl; - struct fcp_cmnd *fcp_cmnd; - uint32_t *ptr; + /* Word 0-2 - FCP_CMND */ + wqe->generic.bde.tus.f.bdeFlags = + BUFF_TYPE_BDE_IMMED; + wqe->generic.bde.tus.f.bdeSize = sgl->sge_len; + wqe->generic.bde.addrHigh = 0; + wqe->generic.bde.addrLow = 88; /* Word 22 */ - /* 128 byte wqe support here */ + bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); - lpfc_cmd = iocbq->context1; - sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; - fcp_cmnd = lpfc_cmd->fcp_cmnd; + /* Word 22-29 FCP CMND Payload */ + ptr = &wqe->words[22]; + memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd)); + } else { + /* Word 0-2 - Inline BDE */ + wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; + wqe->generic.bde.tus.f.bdeSize = sizeof(struct fcp_cmnd); + wqe->generic.bde.addrHigh = sgl->addr_hi; + wqe->generic.bde.addrLow = sgl->addr_lo; - /* Word 0-2 - FCP_CMND */ - wqe->generic.bde.tus.f.bdeFlags = - BUFF_TYPE_BDE_IMMED; - wqe->generic.bde.tus.f.bdeSize = sgl->sge_len; - wqe->generic.bde.addrHigh = 0; - wqe->generic.bde.addrLow = 88; /* Word 22 */ + /* Word 10 */ + bf_set(wqe_dbde, &wqe->generic.wqe_com, 1); + bf_set(wqe_wqes, &wqe->generic.wqe_com, 0); + } + /* add the VMID tags as per switch response */ + if (unlikely(piocb->cmd_flag & LPFC_IO_VMID)) { + if (phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) { + bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com, + (piocb->vmid_tag.cs_ctl_vmid)); + } else if (phba->cfg_vmid_app_header) { + bf_set(wqe_appid, &wqe->fcp_iwrite.wqe_com, 1); bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); - bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); - - /* Word 22-29 FCP CMND Payload */ - ptr = &wqe->words[22]; - memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd)); - } - break; - case CMD_FCP_IREAD64_CR: - /* word3 iocb=iotag wqe=payload_offset_len */ - /* Add the FCP_CMD and FCP_RSP sizes to get the offset */ - bf_set(payload_offset_len, &wqe->fcp_iread, - xmit_len + sizeof(struct fcp_rsp)); - bf_set(cmd_buff_len, &wqe->fcp_iread, - 0); - /* word4 iocb=parameter wqe=total_xfer_length memcpy */ - /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */ - bf_set(wqe_erp, &wqe->fcp_iread.wqe_com, - iocbq->iocb.ulpFCP2Rcvy); - bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS); - /* Always open the exchange */ - bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); - bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, - LPFC_WQE_LENLOC_WORD4); - bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU); - bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1); - if (iocbq->iocb_flag & LPFC_IO_OAS) { - bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1); - bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1); - if (iocbq->priority) { - bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com, - (iocbq->priority << 1)); - } else { - bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com, - (phba->cfg_XLanePriority << 1)); - } - } - /* Note, word 10 is already initialized to 0 */ - - /* Don't set PBDE for Perf hints, just lpfc_enable_pbde */ - if (phba->cfg_enable_pbde) - bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 1); - else - bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 0); - - if (phba->fcp_embed_io) { - struct lpfc_io_buf *lpfc_cmd; - struct sli4_sge *sgl; - struct fcp_cmnd *fcp_cmnd; - uint32_t *ptr; - - /* 128 byte wqe support here */ - - lpfc_cmd = iocbq->context1; - sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; - fcp_cmnd = lpfc_cmd->fcp_cmnd; - - /* Word 0-2 - FCP_CMND */ - wqe->generic.bde.tus.f.bdeFlags = - BUFF_TYPE_BDE_IMMED; - wqe->generic.bde.tus.f.bdeSize = sgl->sge_len; - wqe->generic.bde.addrHigh = 0; - wqe->generic.bde.addrLow = 88; /* Word 22 */ - - bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1); - bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0); - - /* Word 22-29 FCP CMND Payload */ - ptr = &wqe->words[22]; - memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd)); - } - break; - case CMD_FCP_ICMND64_CR: - /* word3 iocb=iotag wqe=payload_offset_len */ - /* Add the FCP_CMD and FCP_RSP sizes to get the offset */ - bf_set(payload_offset_len, &wqe->fcp_icmd, - xmit_len + sizeof(struct fcp_rsp)); - bf_set(cmd_buff_len, &wqe->fcp_icmd, - 0); - /* word3 iocb=IO_TAG wqe=reserved */ - bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0); - /* Always open the exchange */ - bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, - LPFC_WQE_LENLOC_NONE); - bf_set(wqe_erp, &wqe->fcp_icmd.wqe_com, - iocbq->iocb.ulpFCP2Rcvy); - if (iocbq->iocb_flag & LPFC_IO_OAS) { - bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1); - if (iocbq->priority) { - bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com, - (iocbq->priority << 1)); - } else { - bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com, - (phba->cfg_XLanePriority << 1)); - } - } - /* Note, word 10 is already initialized to 0 */ - - if (phba->fcp_embed_io) { - struct lpfc_io_buf *lpfc_cmd; - struct sli4_sge *sgl; - struct fcp_cmnd *fcp_cmnd; - uint32_t *ptr; - - /* 128 byte wqe support here */ - - lpfc_cmd = iocbq->context1; - sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; - fcp_cmnd = lpfc_cmd->fcp_cmnd; - - /* Word 0-2 - FCP_CMND */ - wqe->generic.bde.tus.f.bdeFlags = - BUFF_TYPE_BDE_IMMED; - wqe->generic.bde.tus.f.bdeSize = sgl->sge_len; - wqe->generic.bde.addrHigh = 0; - wqe->generic.bde.addrLow = 88; /* Word 22 */ - - bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0); - - /* Word 22-29 FCP CMND Payload */ - ptr = &wqe->words[22]; - memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd)); - } - break; - case CMD_GEN_REQUEST64_CR: - /* For this command calculate the xmit length of the - * request bde. - */ - xmit_len = 0; - numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / - sizeof(struct ulp_bde64); - for (i = 0; i < numBdes; i++) { - bde.tus.w = le32_to_cpu(bpl[i].tus.w); - if (bde.tus.f.bdeFlags != BUFF_TYPE_BDE_64) - break; - xmit_len += bde.tus.f.bdeSize; - } - /* word3 iocb=IO_TAG wqe=request_payload_len */ - wqe->gen_req.request_payload_len = xmit_len; - /* word4 iocb=parameter wqe=relative_offset memcpy */ - /* word5 [rctl, type, df_ctl, la] copied in memcpy */ - /* word6 context tag copied in memcpy */ - if (iocbq->iocb.ulpCt_h || iocbq->iocb.ulpCt_l) { - ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2015 Invalid CT %x command 0x%x\n", - ct, iocbq->iocb.ulpCommand); - return IOCB_ERROR; - } - bf_set(wqe_ct, &wqe->gen_req.wqe_com, 0); - bf_set(wqe_tmo, &wqe->gen_req.wqe_com, iocbq->iocb.ulpTimeout); - bf_set(wqe_pu, &wqe->gen_req.wqe_com, iocbq->iocb.ulpPU); - bf_set(wqe_dbde, &wqe->gen_req.wqe_com, 1); - bf_set(wqe_iod, &wqe->gen_req.wqe_com, LPFC_WQE_IOD_READ); - bf_set(wqe_qosd, &wqe->gen_req.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE); - bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0); - wqe->gen_req.max_response_payload_len = total_len - xmit_len; - command_type = OTHER_COMMAND; - break; - case CMD_XMIT_ELS_RSP64_CX: - ndlp = (struct lpfc_nodelist *)iocbq->context1; - /* words0-2 BDE memcpy */ - /* word3 iocb=iotag32 wqe=response_payload_len */ - wqe->xmit_els_rsp.response_payload_len = xmit_len; - /* word4 */ - wqe->xmit_els_rsp.word4 = 0; - /* word5 iocb=rsvd wge=did */ - bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, - iocbq->iocb.un.xseq64.xmit_els_remoteID); - - if_type = bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf); - if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { - if (iocbq->vport->fc_flag & FC_PT2PT) { - bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); - bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, - iocbq->vport->fc_myDID); - if (iocbq->vport->fc_myDID == Fabric_DID) { - bf_set(wqe_els_did, - &wqe->xmit_els_rsp.wqe_dest, 0); - } - } - } - bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, - ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); - bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU); - bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, - iocbq->iocb.unsli3.rcvsli3.ox_id); - if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l) - bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, - phba->vpi_ids[iocbq->vport->vpi]); - bf_set(wqe_dbde, &wqe->xmit_els_rsp.wqe_com, 1); - bf_set(wqe_iod, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_qosd, &wqe->xmit_els_rsp.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com, - LPFC_WQE_LENLOC_WORD3); - bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0); - bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, - phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); - pcmd = (uint32_t *) (((struct lpfc_dmabuf *) - iocbq->context2)->virt); - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); - bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, - iocbq->vport->fc_myDID); - bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, 1); - bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, - phba->vpi_ids[phba->pport->vpi]); + wqe->words[31] = piocb->vmid_tag.app_id; } - command_type = OTHER_COMMAND; - break; - case CMD_CLOSE_XRI_CN: - case CMD_ABORT_XRI_CN: - case CMD_ABORT_XRI_CX: - /* words 0-2 memcpy should be 0 rserved */ - /* port will send abts */ - abrt_iotag = iocbq->iocb.un.acxri.abortContextTag; - if (abrt_iotag != 0 && abrt_iotag <= phba->sli.last_iotag) { - abrtiocbq = phba->sli.iocbq_lookup[abrt_iotag]; - fip = abrtiocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK; - } else - fip = 0; - - if ((iocbq->iocb.ulpCommand == CMD_CLOSE_XRI_CN) || fip) - /* - * The link is down, or the command was ELS_FIP - * so the fw does not need to send abts - * on the wire. - */ - bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); - else - bf_set(abort_cmd_ia, &wqe->abort_cmd, 0); - bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); - /* word5 iocb=CONTEXT_TAG|IO_TAG wqe=reserved */ - wqe->abort_cmd.rsrvd5 = 0; - bf_set(wqe_ct, &wqe->abort_cmd.wqe_com, - ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); - abort_tag = iocbq->iocb.un.acxri.abortIoTag; - /* - * The abort handler will send us CMD_ABORT_XRI_CN or - * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX - */ - bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); - bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com, - LPFC_WQE_LENLOC_NONE); - cmnd = CMD_ABORT_XRI_CX; - command_type = OTHER_COMMAND; - xritag = 0; - break; - case CMD_XMIT_BLS_RSP64_CX: - ndlp = (struct lpfc_nodelist *)iocbq->context1; - /* As BLS ABTS RSP WQE is very different from other WQEs, - * we re-construct this WQE here based on information in - * iocbq from scratch. - */ - memset(wqe, 0, sizeof(*wqe)); - /* OX_ID is invariable to who sent ABTS to CT exchange */ - bf_set(xmit_bls_rsp64_oxid, &wqe->xmit_bls_rsp, - bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_rsp)); - if (bf_get(lpfc_abts_orig, &iocbq->iocb.un.bls_rsp) == - LPFC_ABTS_UNSOL_INT) { - /* ABTS sent by initiator to CT exchange, the - * RX_ID field will be filled with the newly - * allocated responder XRI. - */ - bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, - iocbq->sli4_xritag); - } else { - /* ABTS sent by responder to CT exchange, the - * RX_ID field will be filled with the responder - * RX_ID from ABTS. - */ - bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, - bf_get(lpfc_abts_rxid, &iocbq->iocb.un.bls_rsp)); - } - bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff); - bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1); - - /* Use CT=VPI */ - bf_set(wqe_els_did, &wqe->xmit_bls_rsp.wqe_dest, - ndlp->nlp_DID); - bf_set(xmit_bls_rsp64_temprpi, &wqe->xmit_bls_rsp, - iocbq->iocb.ulpContext); - bf_set(wqe_ct, &wqe->xmit_bls_rsp.wqe_com, 1); - bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com, - phba->vpi_ids[phba->pport->vpi]); - bf_set(wqe_qosd, &wqe->xmit_bls_rsp.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->xmit_bls_rsp.wqe_com, - LPFC_WQE_LENLOC_NONE); - /* Overwrite the pre-set comnd type with OTHER_COMMAND */ - command_type = OTHER_COMMAND; - if (iocbq->iocb.un.xseq64.w5.hcsw.Rctl == FC_RCTL_BA_RJT) { - bf_set(xmit_bls_rsp64_rjt_vspec, &wqe->xmit_bls_rsp, - bf_get(lpfc_vndr_code, &iocbq->iocb.un.bls_rsp)); - bf_set(xmit_bls_rsp64_rjt_expc, &wqe->xmit_bls_rsp, - bf_get(lpfc_rsn_expln, &iocbq->iocb.un.bls_rsp)); - bf_set(xmit_bls_rsp64_rjt_rsnc, &wqe->xmit_bls_rsp, - bf_get(lpfc_rsn_code, &iocbq->iocb.un.bls_rsp)); - } - - break; - case CMD_SEND_FRAME: - bf_set(wqe_cmnd, &wqe->generic.wqe_com, CMD_SEND_FRAME); - bf_set(wqe_sof, &wqe->generic.wqe_com, 0x2E); /* SOF byte */ - bf_set(wqe_eof, &wqe->generic.wqe_com, 0x41); /* EOF byte */ - bf_set(wqe_lenloc, &wqe->generic.wqe_com, 1); - bf_set(wqe_xbl, &wqe->generic.wqe_com, 1); - bf_set(wqe_dbde, &wqe->generic.wqe_com, 1); - bf_set(wqe_xc, &wqe->generic.wqe_com, 1); - bf_set(wqe_cmd_type, &wqe->generic.wqe_com, 0xA); - bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag); - bf_set(wqe_reqtag, &wqe->generic.wqe_com, iocbq->iotag); - return 0; - case CMD_XRI_ABORTED_CX: - case CMD_CREATE_XRI_CR: /* Do we expect to use this? */ - case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */ - case CMD_FCP_TSEND64_CX: /* Target mode send xfer-ready */ - case CMD_FCP_TRSP64_CX: /* Target mode rcv */ - case CMD_FCP_AUTO_TRSP_CX: /* Auto target rsp */ - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2014 Invalid command 0x%x\n", - iocbq->iocb.ulpCommand); - return IOCB_ERROR; - break; } - - if (iocbq->iocb_flag & LPFC_IO_DIF_PASS) - bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_PASSTHRU); - else if (iocbq->iocb_flag & LPFC_IO_DIF_STRIP) - bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_STRIP); - else if (iocbq->iocb_flag & LPFC_IO_DIF_INSERT) - bf_set(wqe_dif, &wqe->generic.wqe_com, LPFC_WQE_DIF_INSERT); - iocbq->iocb_flag &= ~(LPFC_IO_DIF_PASS | LPFC_IO_DIF_STRIP | - LPFC_IO_DIF_INSERT); - bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag); - bf_set(wqe_reqtag, &wqe->generic.wqe_com, iocbq->iotag); - wqe->generic.wqe_com.abort_tag = abort_tag; - bf_set(wqe_cmd_type, &wqe->generic.wqe_com, command_type); - bf_set(wqe_cmnd, &wqe->generic.wqe_com, cmnd); - bf_set(wqe_class, &wqe->generic.wqe_com, iocbq->iocb.ulpClass); - bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - return 0; } /** @@ -9967,13 +10655,14 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { struct lpfc_sglq *sglq; - union lpfc_wqe128 wqe; + union lpfc_wqe128 *wqe; struct lpfc_queue *wq; struct lpfc_sli_ring *pring; + u32 ulp_command = get_job_cmnd(phba, piocb); /* Get the WQ */ - if ((piocb->iocb_flag & LPFC_IO_FCP) || - (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { + if ((piocb->cmd_flag & LPFC_IO_FCP) || + (piocb->cmd_flag & LPFC_USE_FCPWQIDX)) { wq = phba->sli4_hba.hdwq[piocb->hba_wqidx].io_wq; } else { wq = phba->sli4_hba.els_wq; @@ -9987,36 +10676,27 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, */ lockdep_assert_held(&pring->ring_lock); - + wqe = &piocb->wqe; if (piocb->sli4_xritag == NO_XRI) { - if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || - piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) + if (ulp_command == CMD_ABORT_XRI_CX) sglq = NULL; else { - if (!list_empty(&pring->txq)) { + sglq = __lpfc_sli_get_els_sglq(phba, piocb); + if (!sglq) { if (!(flag & SLI_IOCB_RET_IOCB)) { __lpfc_sli_ringtx_put(phba, - pring, piocb); + pring, + piocb); return IOCB_SUCCESS; } else { return IOCB_BUSY; } - } else { - sglq = __lpfc_sli_get_els_sglq(phba, piocb); - if (!sglq) { - if (!(flag & SLI_IOCB_RET_IOCB)) { - __lpfc_sli_ringtx_put(phba, - pring, - piocb); - return IOCB_SUCCESS; - } else - return IOCB_BUSY; - } } } - } else if (piocb->iocb_flag & LPFC_IO_FCP) + } else if (piocb->cmd_flag & LPFC_IO_FCP) { /* These IO's already have an XRI and a mapped sgl. */ sglq = NULL; + } else { /* * This is a continuation of a commandi,(CX) so this @@ -10030,21 +10710,51 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, if (sglq) { piocb->sli4_lxritag = sglq->sli4_lxritag; piocb->sli4_xritag = sglq->sli4_xritag; - if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq)) + + /* ABTS sent by initiator to CT exchange, the + * RX_ID field will be filled with the newly + * allocated responder XRI. + */ + if (ulp_command == CMD_XMIT_BLS_RSP64_CX && + piocb->abort_bls == LPFC_ABTS_UNSOL_INT) + bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, + piocb->sli4_xritag); + + bf_set(wqe_xri_tag, &wqe->generic.wqe_com, + piocb->sli4_xritag); + + if (lpfc_wqe_bpl2sgl(phba, piocb, sglq) == NO_XRI) return IOCB_ERROR; } - if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe)) + if (lpfc_sli4_wq_put(wq, wqe)) return IOCB_ERROR; - if (lpfc_sli4_wq_put(wq, &wqe)) - return IOCB_ERROR; lpfc_sli_ringtxcmpl_put(phba, pring, piocb); return 0; } -/** +/* + * lpfc_sli_issue_fcp_io - Wrapper func for issuing fcp i/o + * + * This routine wraps the actual fcp i/o function for issusing WQE for sli-4 + * or IOCB for sli-3 function. + * pointer from the lpfc_hba struct. + * + * Return codes: + * IOCB_ERROR - Error + * IOCB_SUCCESS - Success + * IOCB_BUSY - Busy + **/ +int +lpfc_sli_issue_fcp_io(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + return phba->__lpfc_sli_issue_fcp_io(phba, ring_number, piocb, flag); +} + +/* * __lpfc_sli_issue_iocb - Wrapper func of lockless version for issuing iocb * * This routine wraps the actual lockless version for issusing IOCB function @@ -10062,6 +10772,411 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, return phba->__lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); } +static void +__lpfc_sli_prep_els_req_rsp_s3(struct lpfc_iocbq *cmdiocbq, + struct lpfc_vport *vport, + struct lpfc_dmabuf *bmp, u16 cmd_size, u32 did, + u32 elscmd, u8 tmo, u8 expect_rsp) +{ + struct lpfc_hba *phba = vport->phba; + IOCB_t *cmd; + + cmd = &cmdiocbq->iocb; + memset(cmd, 0, sizeof(*cmd)); + + cmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); + cmd->un.elsreq64.bdl.addrLow = putPaddrLow(bmp->phys); + cmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + + if (expect_rsp) { + cmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); + cmd->un.elsreq64.remoteID = did; /* DID */ + cmd->ulpCommand = CMD_ELS_REQUEST64_CR; + cmd->ulpTimeout = tmo; + } else { + cmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64); + cmd->un.genreq64.xmit_els_remoteID = did; /* DID */ + cmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX; + cmd->ulpPU = PARM_NPIV_DID; + } + cmd->ulpBdeCount = 1; + cmd->ulpLe = 1; + cmd->ulpClass = CLASS3; + + /* If we have NPIV enabled, we want to send ELS traffic by VPI. */ + if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { + if (expect_rsp) { + cmd->un.elsreq64.myID = vport->fc_myDID; + + /* For ELS_REQUEST64_CR, use the VPI by default */ + cmd->ulpContext = phba->vpi_ids[vport->vpi]; + } + + cmd->ulpCt_h = 0; + /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ + if (elscmd == ELS_CMD_ECHO) + cmd->ulpCt_l = 0; /* context = invalid RPI */ + else + cmd->ulpCt_l = 1; /* context = VPI */ + } +} + +static void +__lpfc_sli_prep_els_req_rsp_s4(struct lpfc_iocbq *cmdiocbq, + struct lpfc_vport *vport, + struct lpfc_dmabuf *bmp, u16 cmd_size, u32 did, + u32 elscmd, u8 tmo, u8 expect_rsp) +{ + struct lpfc_hba *phba = vport->phba; + union lpfc_wqe128 *wqe; + struct ulp_bde64_le *bde; + u8 els_id; + + wqe = &cmdiocbq->wqe; + memset(wqe, 0, sizeof(*wqe)); + + /* Word 0 - 2 BDE */ + bde = (struct ulp_bde64_le *)&wqe->generic.bde; + bde->addr_low = cpu_to_le32(putPaddrLow(bmp->phys)); + bde->addr_high = cpu_to_le32(putPaddrHigh(bmp->phys)); + bde->type_size = cpu_to_le32(cmd_size); + bde->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64); + + if (expect_rsp) { + bf_set(wqe_cmnd, &wqe->els_req.wqe_com, CMD_ELS_REQUEST64_WQE); + + /* Transfer length */ + wqe->els_req.payload_len = cmd_size; + wqe->els_req.max_response_payload_len = FCELSSIZE; + + /* DID */ + bf_set(wqe_els_did, &wqe->els_req.wqe_dest, did); + + /* Word 11 - ELS_ID */ + switch (elscmd) { + case ELS_CMD_PLOGI: + els_id = LPFC_ELS_ID_PLOGI; + break; + case ELS_CMD_FLOGI: + els_id = LPFC_ELS_ID_FLOGI; + break; + case ELS_CMD_LOGO: + els_id = LPFC_ELS_ID_LOGO; + break; + case ELS_CMD_FDISC: + if (!vport->fc_myDID) { + els_id = LPFC_ELS_ID_FDISC; + break; + } + fallthrough; + default: + els_id = LPFC_ELS_ID_DEFAULT; + break; + } + + bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id); + } else { + /* DID */ + bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, did); + + /* Transfer length */ + wqe->xmit_els_rsp.response_payload_len = cmd_size; + + bf_set(wqe_cmnd, &wqe->xmit_els_rsp.wqe_com, + CMD_XMIT_ELS_RSP64_WQE); + } + + bf_set(wqe_tmo, &wqe->generic.wqe_com, tmo); + bf_set(wqe_reqtag, &wqe->generic.wqe_com, cmdiocbq->iotag); + bf_set(wqe_class, &wqe->generic.wqe_com, CLASS3); + + /* If we have NPIV enabled, we want to send ELS traffic by VPI. + * For SLI4, since the driver controls VPIs we also want to include + * all ELS pt2pt protocol traffic as well. + */ + if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) || + (vport->fc_flag & FC_PT2PT)) { + if (expect_rsp) { + bf_set(els_req64_sid, &wqe->els_req, vport->fc_myDID); + + /* For ELS_REQUEST64_WQE, use the VPI by default */ + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->vpi_ids[vport->vpi]); + } + + /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ + if (elscmd == ELS_CMD_ECHO) + bf_set(wqe_ct, &wqe->generic.wqe_com, 0); + else + bf_set(wqe_ct, &wqe->generic.wqe_com, 1); + } +} + +void +lpfc_sli_prep_els_req_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq, + struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, + u16 cmd_size, u32 did, u32 elscmd, u8 tmo, + u8 expect_rsp) +{ + phba->__lpfc_sli_prep_els_req_rsp(cmdiocbq, vport, bmp, cmd_size, did, + elscmd, tmo, expect_rsp); +} + +static void +__lpfc_sli_prep_gen_req_s3(struct lpfc_iocbq *cmdiocbq, struct lpfc_dmabuf *bmp, + u16 rpi, u32 num_entry, u8 tmo) +{ + IOCB_t *cmd; + + cmd = &cmdiocbq->iocb; + memset(cmd, 0, sizeof(*cmd)); + + cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); + cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); + cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + cmd->un.genreq64.bdl.bdeSize = num_entry * sizeof(struct ulp_bde64); + + cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; + cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; + cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); + + cmd->ulpContext = rpi; + cmd->ulpClass = CLASS3; + cmd->ulpCommand = CMD_GEN_REQUEST64_CR; + cmd->ulpBdeCount = 1; + cmd->ulpLe = 1; + cmd->ulpOwner = OWN_CHIP; + cmd->ulpTimeout = tmo; +} + +static void +__lpfc_sli_prep_gen_req_s4(struct lpfc_iocbq *cmdiocbq, struct lpfc_dmabuf *bmp, + u16 rpi, u32 num_entry, u8 tmo) +{ + union lpfc_wqe128 *cmdwqe; + struct ulp_bde64_le *bde, *bpl; + u32 xmit_len = 0, total_len = 0, size, type, i; + + cmdwqe = &cmdiocbq->wqe; + memset(cmdwqe, 0, sizeof(*cmdwqe)); + + /* Calculate total_len and xmit_len */ + bpl = (struct ulp_bde64_le *)bmp->virt; + for (i = 0; i < num_entry; i++) { + size = le32_to_cpu(bpl[i].type_size) & ULP_BDE64_SIZE_MASK; + total_len += size; + } + for (i = 0; i < num_entry; i++) { + size = le32_to_cpu(bpl[i].type_size) & ULP_BDE64_SIZE_MASK; + type = le32_to_cpu(bpl[i].type_size) & ULP_BDE64_TYPE_MASK; + if (type != ULP_BDE64_TYPE_BDE_64) + break; + xmit_len += size; + } + + /* Words 0 - 2 */ + bde = (struct ulp_bde64_le *)&cmdwqe->generic.bde; + bde->addr_low = bpl->addr_low; + bde->addr_high = bpl->addr_high; + bde->type_size = cpu_to_le32(xmit_len); + bde->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64); + + /* Word 3 */ + cmdwqe->gen_req.request_payload_len = xmit_len; + + /* Word 5 */ + bf_set(wqe_type, &cmdwqe->gen_req.wge_ctl, FC_TYPE_CT); + bf_set(wqe_rctl, &cmdwqe->gen_req.wge_ctl, FC_RCTL_DD_UNSOL_CTL); + bf_set(wqe_si, &cmdwqe->gen_req.wge_ctl, 1); + bf_set(wqe_la, &cmdwqe->gen_req.wge_ctl, 1); + + /* Word 6 */ + bf_set(wqe_ctxt_tag, &cmdwqe->gen_req.wqe_com, rpi); + + /* Word 7 */ + bf_set(wqe_tmo, &cmdwqe->gen_req.wqe_com, tmo); + bf_set(wqe_class, &cmdwqe->gen_req.wqe_com, CLASS3); + bf_set(wqe_cmnd, &cmdwqe->gen_req.wqe_com, CMD_GEN_REQUEST64_CR); + bf_set(wqe_ct, &cmdwqe->gen_req.wqe_com, SLI4_CT_RPI); + + /* Word 12 */ + cmdwqe->gen_req.max_response_payload_len = total_len - xmit_len; +} + +void +lpfc_sli_prep_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq, + struct lpfc_dmabuf *bmp, u16 rpi, u32 num_entry, u8 tmo) +{ + phba->__lpfc_sli_prep_gen_req(cmdiocbq, bmp, rpi, num_entry, tmo); +} + +static void +__lpfc_sli_prep_xmit_seq64_s3(struct lpfc_iocbq *cmdiocbq, + struct lpfc_dmabuf *bmp, u16 rpi, u16 ox_id, + u32 num_entry, u8 rctl, u8 last_seq, u8 cr_cx_cmd) +{ + IOCB_t *icmd; + + icmd = &cmdiocbq->iocb; + memset(icmd, 0, sizeof(*icmd)); + + icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); + icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); + icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); + icmd->un.xseq64.w5.hcsw.Fctl = LA; + if (last_seq) + icmd->un.xseq64.w5.hcsw.Fctl |= LS; + icmd->un.xseq64.w5.hcsw.Dfctl = 0; + icmd->un.xseq64.w5.hcsw.Rctl = rctl; + icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; + + icmd->ulpBdeCount = 1; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + + switch (cr_cx_cmd) { + case CMD_XMIT_SEQUENCE64_CR: + icmd->ulpContext = rpi; + icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; + break; + case CMD_XMIT_SEQUENCE64_CX: + icmd->ulpContext = ox_id; + icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; + break; + default: + break; + } +} + +static void +__lpfc_sli_prep_xmit_seq64_s4(struct lpfc_iocbq *cmdiocbq, + struct lpfc_dmabuf *bmp, u16 rpi, u16 ox_id, + u32 full_size, u8 rctl, u8 last_seq, u8 cr_cx_cmd) +{ + union lpfc_wqe128 *wqe; + struct ulp_bde64 *bpl; + + wqe = &cmdiocbq->wqe; + memset(wqe, 0, sizeof(*wqe)); + + /* Words 0 - 2 */ + bpl = (struct ulp_bde64 *)bmp->virt; + wqe->xmit_sequence.bde.addrHigh = bpl->addrHigh; + wqe->xmit_sequence.bde.addrLow = bpl->addrLow; + wqe->xmit_sequence.bde.tus.w = bpl->tus.w; + + /* Word 5 */ + bf_set(wqe_ls, &wqe->xmit_sequence.wge_ctl, last_seq); + bf_set(wqe_la, &wqe->xmit_sequence.wge_ctl, 1); + bf_set(wqe_dfctl, &wqe->xmit_sequence.wge_ctl, 0); + bf_set(wqe_rctl, &wqe->xmit_sequence.wge_ctl, rctl); + bf_set(wqe_type, &wqe->xmit_sequence.wge_ctl, FC_TYPE_CT); + + /* Word 6 */ + bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com, rpi); + + bf_set(wqe_cmnd, &wqe->xmit_sequence.wqe_com, + CMD_XMIT_SEQUENCE64_WQE); + + /* Word 7 */ + bf_set(wqe_class, &wqe->xmit_sequence.wqe_com, CLASS3); + + /* Word 9 */ + bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com, ox_id); + + /* Word 12 */ + if (cmdiocbq->cmd_flag & (LPFC_IO_LIBDFC | LPFC_IO_LOOPBACK)) + wqe->xmit_sequence.xmit_len = full_size; + else + wqe->xmit_sequence.xmit_len = + wqe->xmit_sequence.bde.tus.f.bdeSize; +} + +void +lpfc_sli_prep_xmit_seq64(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq, + struct lpfc_dmabuf *bmp, u16 rpi, u16 ox_id, + u32 num_entry, u8 rctl, u8 last_seq, u8 cr_cx_cmd) +{ + phba->__lpfc_sli_prep_xmit_seq64(cmdiocbq, bmp, rpi, ox_id, num_entry, + rctl, last_seq, cr_cx_cmd); +} + +static void +__lpfc_sli_prep_abort_xri_s3(struct lpfc_iocbq *cmdiocbq, u16 ulp_context, + u16 iotag, u8 ulp_class, u16 cqid, bool ia, + bool wqec) +{ + IOCB_t *icmd = NULL; + + icmd = &cmdiocbq->iocb; + memset(icmd, 0, sizeof(*icmd)); + + /* Word 5 */ + icmd->un.acxri.abortContextTag = ulp_context; + icmd->un.acxri.abortIoTag = iotag; + + if (ia) { + /* Word 7 */ + icmd->ulpCommand = CMD_CLOSE_XRI_CN; + } else { + /* Word 3 */ + icmd->un.acxri.abortType = ABORT_TYPE_ABTS; + + /* Word 7 */ + icmd->ulpClass = ulp_class; + icmd->ulpCommand = CMD_ABORT_XRI_CN; + } + + /* Word 7 */ + icmd->ulpLe = 1; +} + +static void +__lpfc_sli_prep_abort_xri_s4(struct lpfc_iocbq *cmdiocbq, u16 ulp_context, + u16 iotag, u8 ulp_class, u16 cqid, bool ia, + bool wqec) +{ + union lpfc_wqe128 *wqe; + + wqe = &cmdiocbq->wqe; + memset(wqe, 0, sizeof(*wqe)); + + /* Word 3 */ + bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); + if (ia) + bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); + else + bf_set(abort_cmd_ia, &wqe->abort_cmd, 0); + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_WQE); + + /* Word 8 */ + wqe->abort_cmd.wqe_com.abort_tag = ulp_context; + + /* Word 9 */ + bf_set(wqe_reqtag, &wqe->abort_cmd.wqe_com, iotag); + + /* Word 10 */ + bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1); + + /* Word 11 */ + if (wqec) + bf_set(wqe_wqec, &wqe->abort_cmd.wqe_com, 1); + bf_set(wqe_cqid, &wqe->abort_cmd.wqe_com, cqid); + bf_set(wqe_cmd_type, &wqe->abort_cmd.wqe_com, OTHER_COMMAND); +} + +void +lpfc_sli_prep_abort_xri(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq, + u16 ulp_context, u16 iotag, u8 ulp_class, u16 cqid, + bool ia, bool wqec) +{ + phba->__lpfc_sli_prep_abort_xri(cmdiocbq, ulp_context, iotag, ulp_class, + cqid, ia, wqec); +} + /** * lpfc_sli_api_table_setup - Set up sli api function jump table * @phba: The hba struct for which this call is being executed. @@ -10079,19 +11194,27 @@ lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) case LPFC_PCI_DEV_LP: phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s3; phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s3; + phba->__lpfc_sli_issue_fcp_io = __lpfc_sli_issue_fcp_io_s3; + phba->__lpfc_sli_prep_els_req_rsp = __lpfc_sli_prep_els_req_rsp_s3; + phba->__lpfc_sli_prep_gen_req = __lpfc_sli_prep_gen_req_s3; + phba->__lpfc_sli_prep_xmit_seq64 = __lpfc_sli_prep_xmit_seq64_s3; + phba->__lpfc_sli_prep_abort_xri = __lpfc_sli_prep_abort_xri_s3; break; case LPFC_PCI_DEV_OC: phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s4; phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s4; + phba->__lpfc_sli_issue_fcp_io = __lpfc_sli_issue_fcp_io_s4; + phba->__lpfc_sli_prep_els_req_rsp = __lpfc_sli_prep_els_req_rsp_s4; + phba->__lpfc_sli_prep_gen_req = __lpfc_sli_prep_gen_req_s4; + phba->__lpfc_sli_prep_xmit_seq64 = __lpfc_sli_prep_xmit_seq64_s4; + phba->__lpfc_sli_prep_abort_xri = __lpfc_sli_prep_abort_xri_s4; break; default: lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "1419 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } - phba->lpfc_get_iocb_from_iocbq = lpfc_get_iocb_from_iocbq; return 0; } @@ -10110,15 +11233,15 @@ lpfc_sli4_calc_ring(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) { struct lpfc_io_buf *lpfc_cmd; - if (piocb->iocb_flag & (LPFC_IO_FCP | LPFC_USE_FCPWQIDX)) { + if (piocb->cmd_flag & (LPFC_IO_FCP | LPFC_USE_FCPWQIDX)) { if (unlikely(!phba->sli4_hba.hdwq)) return NULL; /* * for abort iocb hba_wqidx should already * be setup based on what work queue we used. */ - if (!(piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { - lpfc_cmd = (struct lpfc_io_buf *)piocb->context1; + if (!(piocb->cmd_flag & LPFC_USE_FCPWQIDX)) { + lpfc_cmd = piocb->io_buf; piocb->hba_wqidx = lpfc_cmd->hdwq_no; } return phba->sli4_hba.hdwq[piocb->hba_wqidx].io_wq->pring; @@ -10133,7 +11256,7 @@ lpfc_sli4_calc_ring(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) /** * lpfc_sli_issue_iocb - Wrapper function for __lpfc_sli_issue_iocb * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. + * @ring_number: Ring number * @piocb: Pointer to command iocb. * @flag: Flag indicating if this command can be put into txq. * @@ -10152,7 +11275,13 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, unsigned long iflags; int rc; + /* If the PCI channel is in offline state, do not post iocbs. */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return IOCB_ERROR; + if (phba->sli_rev == LPFC_SLI_REV4) { + lpfc_sli_prep_wqe(phba, piocb); + eq = phba->sli4_hba.hdwq[piocb->hba_wqidx].hba_eq; pring = lpfc_sli4_calc_ring(phba, piocb); @@ -10219,6 +11348,32 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) return 0; } +static void +lpfc_sli_post_recovery_event(struct lpfc_hba *phba, + struct lpfc_nodelist *ndlp) +{ + unsigned long iflags; + struct lpfc_work_evt *evtp = &ndlp->recovery_evt; + + spin_lock_irqsave(&phba->hbalock, iflags); + if (!list_empty(&evtp->evt_listp)) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return; + } + + /* Incrementing the reference count until the queued work is done. */ + evtp->evt_arg1 = lpfc_nlp_get(ndlp); + if (!evtp->evt_arg1) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return; + } + evtp->evt = LPFC_EVT_RECOVER_PORT; + list_add_tail(&evtp->evt_listp, &phba->work_list); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + lpfc_worker_wake_up(phba); +} + /* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. * @phba: Pointer to HBA context object. * @iocbq: Pointer to iocb object. @@ -10252,7 +11407,7 @@ lpfc_sli_abts_err_handler(struct lpfc_hba *phba, if (!vport) goto err_exit; ndlp = lpfc_findnode_rpi(vport, rpi); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) goto err_exit; if (iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) @@ -10263,8 +11418,8 @@ lpfc_sli_abts_err_handler(struct lpfc_hba *phba, lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3095 Event Context not found, no " "action on vpi %d rpi %d status 0x%x, reason 0x%x\n", - iocbq->iocb.ulpContext, iocbq->iocb.ulpStatus, - vpi, rpi); + vpi, rpi, iocbq->iocb.ulpStatus, + iocbq->iocb.ulpContext); } /* lpfc_sli4_abts_err_handler - handle a failed ABTS request from an SLI4 port. @@ -10282,17 +11437,15 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct sli4_wcqe_xri_aborted *axri) { - struct lpfc_vport *vport; uint32_t ext_status = 0; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3115 Node Context not found, driver " "ignoring abts err event\n"); return; } - vport = ndlp->vport; lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "3116 Port generated FCP XRI ABORT event on " "vpi %d rpi %d xri x%x status 0x%x parameter x%x\n", @@ -10309,7 +11462,7 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, ext_status = axri->parameter & IOERR_PARAM_MASK; if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) && ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0))) - lpfc_sli_abts_recover_port(vport, ndlp); + lpfc_sli_post_recovery_event(phba, ndlp); } /** @@ -10345,13 +11498,13 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; if (evt_code == ASYNC_TEMP_WARN) { temp_event_data.event_code = LPFC_THRESHOLD_TEMP; - lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0347 Adapter is very hot, please take " "corrective action. temperature : %d Celsius\n", (uint32_t) icmd->ulpContext); } else { temp_event_data.event_code = LPFC_NORMAL_TEMP; - lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0340 Adapter temperature is OK now. " "temperature : %d Celsius\n", (uint32_t) icmd->ulpContext); @@ -10368,7 +11521,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, break; default: iocb_w = (uint32_t *) icmd; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0346 Ring %d handler: unexpected ASYNC_STATUS" " evt_code 0x%x\n" "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" @@ -10763,7 +11916,8 @@ lpfc_sli_host_down(struct lpfc_vport *vport) &pring->txcmplq, list) { if (iocb->vport != vport) continue; - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, + NULL); } pring->flag = prev_pring_flag; } @@ -10790,13 +11944,17 @@ lpfc_sli_host_down(struct lpfc_vport *vport) &pring->txcmplq, list) { if (iocb->vport != vport) continue; - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, + NULL); } pring->flag = prev_pring_flag; } } spin_unlock_irqrestore(&phba->hbalock, flags); + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_DOWN); @@ -11042,7 +12200,7 @@ lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0402 Cannot find virtual addr for buffer tag on " "ring %d Data x%lx x%px x%px x%x\n", pring->ringno, (unsigned long) tag, @@ -11086,7 +12244,7 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0410 Cannot find virtual addr for mapped buf on " "ring %d Data x%llx x%px x%px x%x\n", pring->ringno, (unsigned long long)phys, @@ -11109,47 +12267,33 @@ static void lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - IOCB_t *irsp = &rspiocb->iocb; - uint16_t abort_iotag, abort_context; - struct lpfc_iocbq *abort_iocb = NULL; - - if (irsp->ulpStatus) { + u32 ulp_status = get_job_ulpstatus(phba, rspiocb); + u32 ulp_word4 = get_job_word4(phba, rspiocb); + u8 cmnd = get_job_cmnd(phba, cmdiocb); + if (ulp_status) { /* * Assume that the port already completed and returned, or * will return the iocb. Just Log the message. */ - abort_context = cmdiocb->iocb.un.acxri.abortContextTag; - abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag; - - spin_lock_irq(&phba->hbalock); if (phba->sli_rev < LPFC_SLI_REV4) { - if (irsp->ulpCommand == CMD_ABORT_XRI_CX && - irsp->ulpStatus == IOSTAT_LOCAL_REJECT && - irsp->un.ulpWord[4] == IOERR_ABORT_REQUESTED) { - spin_unlock_irq(&phba->hbalock); + if (cmnd == CMD_ABORT_XRI_CX && + ulp_status == IOSTAT_LOCAL_REJECT && + ulp_word4 == IOERR_ABORT_REQUESTED) { goto release_iocb; } - if (abort_iotag != 0 && - abort_iotag <= phba->sli.last_iotag) - abort_iocb = - phba->sli.iocbq_lookup[abort_iotag]; - } else - /* For sli4 the abort_tag is the XRI, - * so the abort routine puts the iotag of the iocb - * being aborted in the context field of the abort - * IOCB. - */ - abort_iocb = phba->sli.iocbq_lookup[abort_context]; + } lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI, "0327 Cannot abort els iocb x%px " - "with tag %x context %x, abort status %x, " - "abort code %x\n", - abort_iocb, abort_iotag, abort_context, - irsp->ulpStatus, irsp->un.ulpWord[4]); + "with io cmd xri %x abort tag : x%x, " + "abort status %x abort code %x\n", + cmdiocb, get_job_abtsiotag(phba, cmdiocb), + (phba->sli_rev == LPFC_SLI_REV4) ? + get_wqe_reqtag(cmdiocb) : + cmdiocb->iocb.un.acxri.abortContextTag, + ulp_status, ulp_word4); - spin_unlock_irq(&phba->hbalock); } release_iocb: lpfc_sli_release_iocbq(phba, cmdiocb); @@ -11167,114 +12311,169 @@ release_iocb: * which are aborted. The function frees memory resources used for * the aborted ELS commands. **/ -static void +void lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_nodelist *ndlp = cmdiocb->ndlp; + IOCB_t *irsp; + LPFC_MBOXQ_t *mbox; + u32 ulp_command, ulp_status, ulp_word4, iotag; + + ulp_command = get_job_cmnd(phba, cmdiocb); + ulp_status = get_job_ulpstatus(phba, rspiocb); + ulp_word4 = get_job_word4(phba, rspiocb); + + if (phba->sli_rev == LPFC_SLI_REV4) { + iotag = get_wqe_reqtag(cmdiocb); + } else { + irsp = &rspiocb->iocb; + iotag = irsp->ulpIoTag; + + /* It is possible a PLOGI_RJT for NPIV ports to get aborted. + * The MBX_REG_LOGIN64 mbox command is freed back to the + * mbox_mem_pool here. + */ + if (cmdiocb->context_un.mbox) { + mbox = cmdiocb->context_un.mbox; + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); + cmdiocb->context_un.mbox = NULL; + } + } /* ELS cmd tag <ulpIoTag> completes */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "0139 Ignoring ELS cmd tag x%x completion Data: " - "x%x x%x x%x\n", - irsp->ulpIoTag, irsp->ulpStatus, - irsp->un.ulpWord[4], irsp->ulpTimeout); - if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) + "0139 Ignoring ELS cmd code x%x completion Data: " + "x%x x%x x%x x%px\n", + ulp_command, ulp_status, ulp_word4, iotag, + cmdiocb->ndlp); + /* + * Deref the ndlp after free_iocb. sli_release_iocb will access the ndlp + * if exchange is busy. + */ + if (ulp_command == CMD_GEN_REQUEST64_CR) lpfc_ct_free_iocb(phba, cmdiocb); else lpfc_els_free_iocb(phba, cmdiocb); - return; + + lpfc_nlp_put(ndlp); } /** - * lpfc_sli_abort_iotag_issue - Issue abort for a command iocb + * lpfc_sli_issue_abort_iotag - Abort function for a command iocb * @phba: Pointer to HBA context object. * @pring: Pointer to driver SLI ring object. * @cmdiocb: Pointer to driver command iocb object. + * @cmpl: completion function. + * + * This function issues an abort iocb for the provided command iocb. In case + * of unloading, the abort iocb will not be issued to commands on the ELS + * ring. Instead, the callback function shall be changed to those commands + * so that nothing happens when them finishes. This function is called with + * hbalock held andno ring_lock held (SLI4). The function returns IOCB_SUCCESS + * when the command iocb is an abort request. * - * This function issues an abort iocb for the provided command iocb down to - * the port. Other than the case the outstanding command iocb is an abort - * request, this function issues abort out unconditionally. This function is - * called with hbalock held. The function returns 0 when it fails due to - * memory allocation failure or when the command iocb is an abort request. **/ -static int -lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb) +int +lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *cmdiocb, void *cmpl) { struct lpfc_vport *vport = cmdiocb->vport; struct lpfc_iocbq *abtsiocbp; - IOCB_t *icmd = NULL; - IOCB_t *iabt = NULL; - int retval; + int retval = IOCB_ERROR; unsigned long iflags; - struct lpfc_nodelist *ndlp; - - lockdep_assert_held(&phba->hbalock); + struct lpfc_nodelist *ndlp = NULL; + u32 ulp_command = get_job_cmnd(phba, cmdiocb); + u16 ulp_context, iotag; + bool ia; /* * There are certain command types we don't want to abort. And we * don't want to abort commands that are already in the process of * being aborted. */ - icmd = &cmdiocb->iocb; - if (icmd->ulpCommand == CMD_ABORT_XRI_CN || - icmd->ulpCommand == CMD_CLOSE_XRI_CN || - (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) - return 0; + if (ulp_command == CMD_ABORT_XRI_WQE || + ulp_command == CMD_ABORT_XRI_CN || + ulp_command == CMD_CLOSE_XRI_CN || + cmdiocb->cmd_flag & LPFC_DRIVER_ABORTED) + return IOCB_ABORTING; + + if (!pring) { + if (cmdiocb->cmd_flag & LPFC_IO_FABRIC) + cmdiocb->fabric_cmd_cmpl = lpfc_ignore_els_cmpl; + else + cmdiocb->cmd_cmpl = lpfc_ignore_els_cmpl; + return retval; + } + + /* + * If we're unloading, don't abort iocb on the ELS ring, but change + * the callback so that nothing happens when it finishes. + */ + if ((vport->load_flag & FC_UNLOADING) && + pring->ringno == LPFC_ELS_RING) { + if (cmdiocb->cmd_flag & LPFC_IO_FABRIC) + cmdiocb->fabric_cmd_cmpl = lpfc_ignore_els_cmpl; + else + cmdiocb->cmd_cmpl = lpfc_ignore_els_cmpl; + return retval; + } /* issue ABTS for this IOCB based on iotag */ abtsiocbp = __lpfc_sli_get_iocbq(phba); if (abtsiocbp == NULL) - return 0; + return IOCB_NORESOURCE; /* This signals the response to set the correct status * before calling the completion handler */ - cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; + cmdiocb->cmd_flag |= LPFC_DRIVER_ABORTED; - iabt = &abtsiocbp->iocb; - iabt->un.acxri.abortType = ABORT_TYPE_ABTS; - iabt->un.acxri.abortContextTag = icmd->ulpContext; if (phba->sli_rev == LPFC_SLI_REV4) { - iabt->un.acxri.abortIoTag = cmdiocb->sli4_xritag; - iabt->un.acxri.abortContextTag = cmdiocb->iotag; + ulp_context = cmdiocb->sli4_xritag; + iotag = abtsiocbp->iotag; } else { - iabt->un.acxri.abortIoTag = icmd->ulpIoTag; + iotag = cmdiocb->iocb.ulpIoTag; if (pring->ringno == LPFC_ELS_RING) { - ndlp = (struct lpfc_nodelist *)(cmdiocb->context1); - iabt->un.acxri.abortContextTag = ndlp->nlp_rpi; + ndlp = cmdiocb->ndlp; + ulp_context = ndlp->nlp_rpi; + } else { + ulp_context = cmdiocb->iocb.ulpContext; } } - iabt->ulpLe = 1; - iabt->ulpClass = icmd->ulpClass; + + if (phba->link_state < LPFC_LINK_UP || + (phba->sli_rev == LPFC_SLI_REV4 && + phba->sli4_hba.link_state.status == LPFC_FC_LA_TYPE_LINK_DOWN) || + (phba->link_flag & LS_EXTERNAL_LOOPBACK)) + ia = true; + else + ia = false; + + lpfc_sli_prep_abort_xri(phba, abtsiocbp, ulp_context, iotag, + cmdiocb->iocb.ulpClass, + LPFC_WQE_CQ_ID_DEFAULT, ia, false); + + abtsiocbp->vport = vport; /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocbp->hba_wqidx = cmdiocb->hba_wqidx; - if (cmdiocb->iocb_flag & LPFC_IO_FCP) - abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX; - if (cmdiocb->iocb_flag & LPFC_IO_FOF) - abtsiocbp->iocb_flag |= LPFC_IO_FOF; + if (cmdiocb->cmd_flag & LPFC_IO_FCP) + abtsiocbp->cmd_flag |= (LPFC_IO_FCP | LPFC_USE_FCPWQIDX); - if (phba->link_state >= LPFC_LINK_UP) - iabt->ulpCommand = CMD_ABORT_XRI_CN; - else - iabt->ulpCommand = CMD_CLOSE_XRI_CN; + if (cmdiocb->cmd_flag & LPFC_IO_FOF) + abtsiocbp->cmd_flag |= LPFC_IO_FOF; - abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; + if (cmpl) + abtsiocbp->cmd_cmpl = cmpl; + else + abtsiocbp->cmd_cmpl = lpfc_sli_abort_els_cmpl; abtsiocbp->vport = vport; - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "0339 Abort xri x%x, original iotag x%x, " - "abort cmd iotag x%x\n", - iabt->un.acxri.abortIoTag, - iabt->un.acxri.abortContextTag, - abtsiocbp->iotag); - if (phba->sli_rev == LPFC_SLI_REV4) { pring = lpfc_sli4_calc_ring(phba, abtsiocbp); if (unlikely(pring == NULL)) - return 0; + goto abort_iotag_exit; /* Note: both hbalock and ring_lock need to be set here */ spin_lock_irqsave(&pring->ring_lock, iflags); retval = __lpfc_sli_issue_iocb(phba, pring->ringno, @@ -11285,76 +12484,20 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, abtsiocbp, 0); } - if (retval) - __lpfc_sli_release_iocbq(phba, abtsiocbp); - - /* - * Caller to this routine should check for IOCB_ERROR - * and handle it properly. This routine no longer removes - * iocb off txcmplq and call compl in case of IOCB_ERROR. - */ - return retval; -} - -/** - * lpfc_sli_issue_abort_iotag - Abort function for a command iocb - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @cmdiocb: Pointer to driver command iocb object. - * - * This function issues an abort iocb for the provided command iocb. In case - * of unloading, the abort iocb will not be issued to commands on the ELS - * ring. Instead, the callback function shall be changed to those commands - * so that nothing happens when them finishes. This function is called with - * hbalock held. The function returns 0 when the command iocb is an abort - * request. - **/ -int -lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - int retval = IOCB_ERROR; - IOCB_t *icmd = NULL; - - lockdep_assert_held(&phba->hbalock); - - /* - * There are certain command types we don't want to abort. And we - * don't want to abort commands that are already in the process of - * being aborted. - */ - icmd = &cmdiocb->iocb; - if (icmd->ulpCommand == CMD_ABORT_XRI_CN || - icmd->ulpCommand == CMD_CLOSE_XRI_CN || - (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) - return 0; - - if (!pring) { - if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) - cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; - else - cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; - goto abort_iotag_exit; - } +abort_iotag_exit: - /* - * If we're unloading, don't abort iocb on the ELS ring, but change - * the callback so that nothing happens when it finishes. - */ - if ((vport->load_flag & FC_UNLOADING) && - (pring->ringno == LPFC_ELS_RING)) { - if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) - cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; - else - cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; - goto abort_iotag_exit; + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "0339 Abort IO XRI x%x, Original iotag x%x, " + "abort tag x%x Cmdjob : x%px Abortjob : x%px " + "retval x%x\n", + ulp_context, (phba->sli_rev == LPFC_SLI_REV4) ? + cmdiocb->iotag : iotag, iotag, cmdiocb, abtsiocbp, + retval); + if (retval) { + cmdiocb->cmd_flag &= ~LPFC_DRIVER_ABORTED; + __lpfc_sli_release_iocbq(phba, abtsiocbp); } - /* Now, we try to issue the abort to the cmdiocb out */ - retval = lpfc_sli_abort_iotag_issue(phba, pring, cmdiocb); - -abort_iotag_exit: /* * Caller to this routine should check for IOCB_ERROR * and handle it properly. This routine no longer removes @@ -11393,15 +12536,55 @@ lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba) } /** - * lpfc_sli_validate_fcp_iocb - find commands associated with a vport or LUN + * lpfc_sli_validate_fcp_iocb_for_abort - filter iocbs appropriate for FCP aborts + * @iocbq: Pointer to iocb object. + * @vport: Pointer to driver virtual port object. + * + * This function acts as an iocb filter for functions which abort FCP iocbs. + * + * Return values + * -ENODEV, if a null iocb or vport ptr is encountered + * -EINVAL, if the iocb is not an FCP I/O, not on the TX cmpl queue, premarked as + * driver already started the abort process, or is an abort iocb itself + * 0, passes criteria for aborting the FCP I/O iocb + **/ +static int +lpfc_sli_validate_fcp_iocb_for_abort(struct lpfc_iocbq *iocbq, + struct lpfc_vport *vport) +{ + u8 ulp_command; + + /* No null ptr vports */ + if (!iocbq || iocbq->vport != vport) + return -ENODEV; + + /* iocb must be for FCP IO, already exists on the TX cmpl queue, + * can't be premarked as driver aborted, nor be an ABORT iocb itself + */ + ulp_command = get_job_cmnd(vport->phba, iocbq); + if (!(iocbq->cmd_flag & LPFC_IO_FCP) || + !(iocbq->cmd_flag & LPFC_IO_ON_TXCMPLQ) || + (iocbq->cmd_flag & LPFC_DRIVER_ABORTED) || + (ulp_command == CMD_ABORT_XRI_CN || + ulp_command == CMD_CLOSE_XRI_CN || + ulp_command == CMD_ABORT_XRI_WQE)) + return -EINVAL; + + return 0; +} + +/** + * lpfc_sli_validate_fcp_iocb - validate commands associated with a SCSI target * @iocbq: Pointer to driver iocb object. * @vport: Pointer to driver virtual port object. * @tgt_id: SCSI ID of the target. * @lun_id: LUN ID of the scsi device. * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST * - * This function acts as an iocb filter for functions which abort or count - * all FCP iocbs pending on a lun/SCSI target/SCSI host. It will return + * This function acts as an iocb filter for validating a lun/SCSI target/SCSI + * host. + * + * It will return * 0 if the filtering criteria is met for the given iocb and will return * 1 if the filtering criteria is not met. * If ctx_cmd == LPFC_CTX_LUN, the function returns 0 only if the @@ -11422,13 +12605,6 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd; int rc = 1; - if (iocbq->vport != vport) - return rc; - - if (!(iocbq->iocb_flag & LPFC_IO_FCP) || - !(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ)) - return rc; - lpfc_cmd = container_of(iocbq, struct lpfc_io_buf, cur_iocbq); if (lpfc_cmd->pCmd == NULL) @@ -11484,16 +12660,33 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id, struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *iocbq; int sum, i; + unsigned long iflags; + u8 ulp_command; - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) { iocbq = phba->sli.iocbq_lookup[i]; - if (lpfc_sli_validate_fcp_iocb (iocbq, vport, tgt_id, lun_id, - ctx_cmd) == 0) + if (!iocbq || iocbq->vport != vport) + continue; + if (!(iocbq->cmd_flag & LPFC_IO_FCP) || + !(iocbq->cmd_flag & LPFC_IO_ON_TXCMPLQ)) + continue; + + /* Include counting outstanding aborts */ + ulp_command = get_job_cmnd(phba, iocbq); + if (ulp_command == CMD_ABORT_XRI_CN || + ulp_command == CMD_CLOSE_XRI_CN || + ulp_command == CMD_ABORT_XRI_WQE) { + sum++; + continue; + } + + if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, + ctx_cmd) == 0) sum++; } - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); return sum; } @@ -11513,13 +12706,15 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3096 ABORT_XRI_CN completing on rpi x%x " + "3096 ABORT_XRI_CX completing on rpi x%x " "original iotag x%x, abort cmd iotag x%x " "status 0x%x, reason 0x%x\n", + (phba->sli_rev == LPFC_SLI_REV4) ? + cmdiocb->sli4_xritag : cmdiocb->iocb.un.acxri.abortContextTag, - cmdiocb->iocb.un.acxri.abortIoTag, - cmdiocb->iotag, rspiocb->iocb.ulpStatus, - rspiocb->iocb.un.ulpWord[4]); + get_job_abtsiotag(phba, cmdiocb), + cmdiocb->iotag, get_job_ulpstatus(phba, rspiocb), + get_job_word4(phba, rspiocb)); lpfc_sli_release_iocbq(phba, cmdiocb); return; } @@ -11527,14 +12722,17 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /** * lpfc_sli_abort_iocb - issue abort for all commands on a host/target/LUN * @vport: Pointer to virtual port. - * @pring: Pointer to driver SLI ring object. * @tgt_id: SCSI ID of the target. * @lun_id: LUN ID of the scsi device. * @abort_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. * * This function sends an abort command for every SCSI command * associated with the given virtual port pending on the ring - * filtered by lpfc_sli_validate_fcp_iocb function. + * filtered by lpfc_sli_validate_fcp_iocb_for_abort and then + * lpfc_sli_validate_fcp_iocb function. The ordering for validation before + * submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort + * followed by lpfc_sli_validate_fcp_iocb. + * * When abort_cmd == LPFC_CTX_LUN, the function sends abort only to the * FCP iocbs associated with lun specified by tgt_id and lun_id * parameters @@ -11542,19 +12740,20 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * FCP iocbs associated with SCSI target specified by tgt_id parameter. * When abort_cmd == LPFC_CTX_HOST, the function sends abort to all * FCP iocbs associated with virtual port. + * The pring used for SLI3 is sli3_ring[LPFC_FCP_RING], for SLI4 + * lpfc_sli4_calc_ring is used. * This function returns number of iocbs it failed to abort. * This function is called with no locks held. **/ int -lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, - uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd abort_cmd) +lpfc_sli_abort_iocb(struct lpfc_vport *vport, u16 tgt_id, u64 lun_id, + lpfc_ctx_cmd abort_cmd) { struct lpfc_hba *phba = vport->phba; + struct lpfc_sli_ring *pring = NULL; struct lpfc_iocbq *iocbq; - struct lpfc_iocbq *abtsiocb; - struct lpfc_sli_ring *pring_s4; - IOCB_t *cmd = NULL; int errcnt = 0, ret_val = 0; + unsigned long iflags; int i; /* all I/Os are in process of being flushed */ @@ -11564,66 +12763,24 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, for (i = 1; i <= phba->sli.last_iotag; i++) { iocbq = phba->sli.iocbq_lookup[i]; - if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, - abort_cmd) != 0) + if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport)) continue; - /* - * If the iocbq is already being aborted, don't take a second - * action, but do count it. - */ - if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED) + if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, + abort_cmd) != 0) continue; - /* issue ABTS for this IOCB based on iotag */ - abtsiocb = lpfc_sli_get_iocbq(phba); - if (abtsiocb == NULL) { - errcnt++; - continue; + spin_lock_irqsave(&phba->hbalock, iflags); + if (phba->sli_rev == LPFC_SLI_REV3) { + pring = &phba->sli.sli3_ring[LPFC_FCP_RING]; + } else if (phba->sli_rev == LPFC_SLI_REV4) { + pring = lpfc_sli4_calc_ring(phba, iocbq); } - - /* indicate the IO is being aborted by the driver. */ - iocbq->iocb_flag |= LPFC_DRIVER_ABORTED; - - cmd = &iocbq->iocb; - abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; - abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) - abtsiocb->iocb.un.acxri.abortIoTag = iocbq->sli4_xritag; - else - abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag; - abtsiocb->iocb.ulpLe = 1; - abtsiocb->iocb.ulpClass = cmd->ulpClass; - abtsiocb->vport = vport; - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocb->hba_wqidx = iocbq->hba_wqidx; - if (iocbq->iocb_flag & LPFC_IO_FCP) - abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; - if (iocbq->iocb_flag & LPFC_IO_FOF) - abtsiocb->iocb_flag |= LPFC_IO_FOF; - - if (lpfc_is_link_up(phba)) - abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; - else - abtsiocb->iocb.ulpCommand = CMD_CLOSE_XRI_CN; - - /* Setup callback routine and issue the command. */ - abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - if (phba->sli_rev == LPFC_SLI_REV4) { - pring_s4 = lpfc_sli4_calc_ring(phba, iocbq); - if (!pring_s4) - continue; - ret_val = lpfc_sli_issue_iocb(phba, pring_s4->ringno, - abtsiocb, 0); - } else - ret_val = lpfc_sli_issue_iocb(phba, pring->ringno, - abtsiocb, 0); - if (ret_val == IOCB_ERROR) { - lpfc_sli_release_iocbq(phba, abtsiocb); + ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocbq, + lpfc_sli_abort_fcp_cmpl); + spin_unlock_irqrestore(&phba->hbalock, iflags); + if (ret_val != IOCB_SUCCESS) errcnt++; - continue; - } } return errcnt; @@ -11635,11 +12792,15 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, * @pring: Pointer to driver SLI ring object. * @tgt_id: SCSI ID of the target. * @lun_id: LUN ID of the scsi device. - * @taskmgmt_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. + * @cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. * * This function sends an abort command for every SCSI command * associated with the given virtual port pending on the ring - * filtered by lpfc_sli_validate_fcp_iocb function. + * filtered by lpfc_sli_validate_fcp_iocb_for_abort and then + * lpfc_sli_validate_fcp_iocb function. The ordering for validation before + * submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort + * followed by lpfc_sli_validate_fcp_iocb. + * * When taskmgmt_cmd == LPFC_CTX_LUN, the function sends abort only to the * FCP iocbs associated with lun specified by tgt_id and lun_id * parameters @@ -11658,12 +12819,13 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, struct lpfc_hba *phba = vport->phba; struct lpfc_io_buf *lpfc_cmd; struct lpfc_iocbq *abtsiocbq; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp = NULL; struct lpfc_iocbq *iocbq; - IOCB_t *icmd; int sum, i, ret_val; unsigned long iflags; struct lpfc_sli_ring *pring_s4 = NULL; + u16 ulp_context, iotag, cqid = LPFC_WQE_CQ_ID_DEFAULT; + bool ia; spin_lock_irqsave(&phba->hbalock, iflags); @@ -11677,6 +12839,9 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, for (i = 1; i <= phba->sli.last_iotag; i++) { iocbq = phba->sli.iocbq_lookup[i]; + if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport)) + continue; + if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, cmd) != 0) continue; @@ -11705,8 +12870,8 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, * If the iocbq is already being aborted, don't take a second * action, but do count it. */ - if ((iocbq->iocb_flag & LPFC_DRIVER_ABORTED) || - !(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ)) { + if ((iocbq->cmd_flag & LPFC_DRIVER_ABORTED) || + !(iocbq->cmd_flag & LPFC_IO_ON_TXCMPLQ)) { if (phba->sli_rev == LPFC_SLI_REV4) spin_unlock(&pring_s4->ring_lock); spin_unlock(&lpfc_cmd->buf_lock); @@ -11722,41 +12887,50 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, continue; } - icmd = &iocbq->iocb; - abtsiocbq->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; - abtsiocbq->iocb.un.acxri.abortContextTag = icmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) - abtsiocbq->iocb.un.acxri.abortIoTag = - iocbq->sli4_xritag; - else - abtsiocbq->iocb.un.acxri.abortIoTag = icmd->ulpIoTag; - abtsiocbq->iocb.ulpLe = 1; - abtsiocbq->iocb.ulpClass = icmd->ulpClass; - abtsiocbq->vport = vport; - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocbq->hba_wqidx = iocbq->hba_wqidx; - if (iocbq->iocb_flag & LPFC_IO_FCP) - abtsiocbq->iocb_flag |= LPFC_USE_FCPWQIDX; - if (iocbq->iocb_flag & LPFC_IO_FOF) - abtsiocbq->iocb_flag |= LPFC_IO_FOF; + if (phba->sli_rev == LPFC_SLI_REV4) { + iotag = abtsiocbq->iotag; + ulp_context = iocbq->sli4_xritag; + cqid = lpfc_cmd->hdwq->io_cq_map; + } else { + iotag = iocbq->iocb.ulpIoTag; + if (pring->ringno == LPFC_ELS_RING) { + ndlp = iocbq->ndlp; + ulp_context = ndlp->nlp_rpi; + } else { + ulp_context = iocbq->iocb.ulpContext; + } + } ndlp = lpfc_cmd->rdata->pnode; if (lpfc_is_link_up(phba) && - (ndlp && ndlp->nlp_state == NLP_STE_MAPPED_NODE)) - abtsiocbq->iocb.ulpCommand = CMD_ABORT_XRI_CN; + (ndlp && ndlp->nlp_state == NLP_STE_MAPPED_NODE) && + !(phba->link_flag & LS_EXTERNAL_LOOPBACK)) + ia = false; else - abtsiocbq->iocb.ulpCommand = CMD_CLOSE_XRI_CN; + ia = true; + + lpfc_sli_prep_abort_xri(phba, abtsiocbq, ulp_context, iotag, + iocbq->iocb.ulpClass, cqid, + ia, false); + + abtsiocbq->vport = vport; + + /* ABTS WQE must go to the same WQ as the WQE to be aborted */ + abtsiocbq->hba_wqidx = iocbq->hba_wqidx; + if (iocbq->cmd_flag & LPFC_IO_FCP) + abtsiocbq->cmd_flag |= LPFC_USE_FCPWQIDX; + if (iocbq->cmd_flag & LPFC_IO_FOF) + abtsiocbq->cmd_flag |= LPFC_IO_FOF; /* Setup callback routine and issue the command. */ - abtsiocbq->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; + abtsiocbq->cmd_cmpl = lpfc_sli_abort_fcp_cmpl; /* * Indicate the IO is being aborted by the driver and set * the caller's flag into the aborted IO. */ - iocbq->iocb_flag |= LPFC_DRIVER_ABORTED; + iocbq->cmd_flag |= LPFC_DRIVER_ABORTED; if (phba->sli_rev == LPFC_SLI_REV4) { ret_val = __lpfc_sli_issue_iocb(phba, pring_s4->ringno, @@ -11803,9 +12977,10 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, wait_queue_head_t *pdone_q; unsigned long iflags; struct lpfc_io_buf *lpfc_cmd; + size_t offset = offsetof(struct lpfc_iocbq, wqe); spin_lock_irqsave(&phba->hbalock, iflags); - if (cmdiocbq->iocb_flag & LPFC_IO_WAKE_TMO) { + if (cmdiocbq->cmd_flag & LPFC_IO_WAKE_TMO) { /* * A time out has occurred for the iocb. If a time out @@ -11814,26 +12989,27 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, */ spin_unlock_irqrestore(&phba->hbalock, iflags); - cmdiocbq->iocb_cmpl = cmdiocbq->wait_iocb_cmpl; - cmdiocbq->wait_iocb_cmpl = NULL; - if (cmdiocbq->iocb_cmpl) - (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, NULL); + cmdiocbq->cmd_cmpl = cmdiocbq->wait_cmd_cmpl; + cmdiocbq->wait_cmd_cmpl = NULL; + if (cmdiocbq->cmd_cmpl) + cmdiocbq->cmd_cmpl(phba, cmdiocbq, NULL); else lpfc_sli_release_iocbq(phba, cmdiocbq); return; } - cmdiocbq->iocb_flag |= LPFC_IO_WAKE; - if (cmdiocbq->context2 && rspiocbq) - memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, - &rspiocbq->iocb, sizeof(IOCB_t)); + /* Copy the contents of the local rspiocb into the caller's buffer. */ + cmdiocbq->cmd_flag |= LPFC_IO_WAKE; + if (cmdiocbq->rsp_iocb && rspiocbq) + memcpy((char *)cmdiocbq->rsp_iocb + offset, + (char *)rspiocbq + offset, sizeof(*rspiocbq) - offset); /* Set the exchange busy flag for task management commands */ - if ((cmdiocbq->iocb_flag & LPFC_IO_FCP) && - !(cmdiocbq->iocb_flag & LPFC_IO_LIBDFC)) { + if ((cmdiocbq->cmd_flag & LPFC_IO_FCP) && + !(cmdiocbq->cmd_flag & LPFC_IO_LIBDFC)) { lpfc_cmd = container_of(cmdiocbq, struct lpfc_io_buf, - cur_iocbq); - if (rspiocbq && (rspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY)) + cur_iocbq); + if (rspiocbq && (rspiocbq->cmd_flag & LPFC_EXCHANGE_BUSY)) lpfc_cmd->flags |= LPFC_SBUF_XBUSY; else lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY; @@ -11852,7 +13028,7 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, * @piocbq: Pointer to command iocb. * @flag: Flag to test. * - * This routine grabs the hbalock and then test the iocb_flag to + * This routine grabs the hbalock and then test the cmd_flag to * see if the passed in flag is set. * Returns: * 1 if flag is set. @@ -11866,7 +13042,7 @@ lpfc_chk_iocb_flg(struct lpfc_hba *phba, int ret; spin_lock_irqsave(&phba->hbalock, iflags); - ret = piocbq->iocb_flag & flag; + ret = piocbq->cmd_flag & flag; spin_unlock_irqrestore(&phba->hbalock, iflags); return ret; @@ -11875,20 +13051,20 @@ lpfc_chk_iocb_flg(struct lpfc_hba *phba, /** * lpfc_sli_issue_iocb_wait - Synchronous function to issue iocb commands * @phba: Pointer to HBA context object.. - * @pring: Pointer to sli ring. + * @ring_number: Ring number * @piocb: Pointer to command iocb. * @prspiocbq: Pointer to response iocb. * @timeout: Timeout in number of seconds. * * This function issues the iocb to firmware and waits for the - * iocb to complete. The iocb_cmpl field of the shall be used + * iocb to complete. The cmd_cmpl field of the shall be used * to handle iocbs which time out. If the field is NULL, the * function shall free the iocbq structure. If more clean up is * needed, the caller is expected to provide a completion function * that will provide the needed clean up. If the iocb command is * not completed within timeout seconds, the function will either - * free the iocbq structure (if iocb_cmpl == NULL) or execute the - * completion function set in the iocb_cmpl field and then return + * free the iocbq structure (if cmd_cmpl == NULL) or execute the + * completion function set in the cmd_cmpl field and then return * a status of IOCB_TIMEDOUT. The caller should not free the iocb * resources if this function returns IOCB_TIMEDOUT. * The function waits for the iocb completion using an @@ -11900,7 +13076,7 @@ lpfc_chk_iocb_flg(struct lpfc_hba *phba, * This function assumes that the iocb completions occur while * this function sleep. So, this function cannot be called from * the thread which process iocb completion for this ring. - * This function clears the iocb_flag of the iocb object before + * This function clears the cmd_flag of the iocb object before * issuing the iocb and the iocb completion handler sets this * flag and wakes this thread when the iocb completes. * The contents of the response iocb will be copied to prspiocbq @@ -11926,24 +13102,26 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, unsigned long iflags; bool iocb_completed = true; - if (phba->sli_rev >= LPFC_SLI_REV4) + if (phba->sli_rev >= LPFC_SLI_REV4) { + lpfc_sli_prep_wqe(phba, piocb); + pring = lpfc_sli4_calc_ring(phba, piocb); - else + } else pring = &phba->sli.sli3_ring[ring_number]; /* - * If the caller has provided a response iocbq buffer, then context2 + * If the caller has provided a response iocbq buffer, then rsp_iocb * is NULL or its an error. */ if (prspiocbq) { - if (piocb->context2) + if (piocb->rsp_iocb) return IOCB_ERROR; - piocb->context2 = prspiocbq; + piocb->rsp_iocb = prspiocbq; } - piocb->wait_iocb_cmpl = piocb->iocb_cmpl; - piocb->iocb_cmpl = lpfc_sli_wake_iocb_wait; + piocb->wait_cmd_cmpl = piocb->cmd_cmpl; + piocb->cmd_cmpl = lpfc_sli_wake_iocb_wait; piocb->context_un.wait_queue = &done_q; - piocb->iocb_flag &= ~(LPFC_IO_WAKE | LPFC_IO_WAKE_TMO); + piocb->cmd_flag &= ~(LPFC_IO_WAKE | LPFC_IO_WAKE_TMO); if (phba->cfg_poll & DISABLE_FCP_RING_INT) { if (lpfc_readl(phba->HCregaddr, &creg_val)) @@ -11961,7 +13139,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE), timeout_req); spin_lock_irqsave(&phba->hbalock, iflags); - if (!(piocb->iocb_flag & LPFC_IO_WAKE)) { + if (!(piocb->cmd_flag & LPFC_IO_WAKE)) { /* * IOCB timed out. Inform the wake iocb wait @@ -11969,7 +13147,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, */ iocb_completed = false; - piocb->iocb_flag |= LPFC_IO_WAKE_TMO; + piocb->cmd_flag |= LPFC_IO_WAKE_TMO; } spin_unlock_irqrestore(&phba->hbalock, iflags); if (iocb_completed) { @@ -11981,12 +13159,12 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, * completed. Not that it completed successfully. * */ } else if (timeleft == 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0338 IOCB wait timeout error - no " "wake response Data x%x\n", timeout); retval = IOCB_TIMEDOUT; } else { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0330 IOCB wake NOT set, " "Data x%x x%lx\n", timeout, (timeleft / jiffies)); @@ -12021,10 +13199,10 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, } if (prspiocbq) - piocb->context2 = NULL; + piocb->rsp_iocb = NULL; piocb->context_un.wait_queue = NULL; - piocb->iocb_cmpl = NULL; + piocb->cmd_cmpl = NULL; return retval; } @@ -12095,6 +13273,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, /** * lpfc_sli_mbox_sys_shutdown - shutdown mailbox command sub-system * @phba: Pointer to HBA context. + * @mbx_action: Mailbox shutdown options. * * This function is called to shutdown the driver's mailbox sub-system. * It first marks the mailbox sub-system is in a block state to prevent @@ -12229,6 +13408,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) uint32_t uerr_sta_hi, uerr_sta_lo; uint32_t if_type, portsmphr; struct lpfc_register portstat_reg; + u32 logmask; /* * For now, use the SLI4 device internal unrecoverable error @@ -12248,7 +13428,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) } if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) || (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1423 HBA Unrecoverable error: " "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " "ue_mask_lo_reg=0x%x, " @@ -12279,7 +13459,12 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) readl(phba->sli4_hba.u.if_type2.ERR1regaddr); phba->work_status[1] = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + logmask = LOG_TRACE_EVENT; + if (phba->work_status[0] == + SLIPORT_ERR1_REG_ERR_CODE_2 && + phba->work_status[1] == SLIPORT_ERR2_REG_FW_RESTART) + logmask = LOG_SLI; + lpfc_printf_log(phba, KERN_ERR, logmask, "2885 Port Status Event: " "port status reg 0x%x, " "port smphr reg 0x%x, " @@ -12295,7 +13480,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) break; case LPFC_SLI_INTF_IF_TYPE_1: default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2886 HBA Error Attention on unsupported " "if type %d.", if_type); return 1; @@ -12359,7 +13544,7 @@ lpfc_sli_check_eratt(struct lpfc_hba *phba) ha_copy = lpfc_sli4_eratt_read(phba); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0299 Invalid SLI revision (%d)\n", phba->sli_rev); ha_copy = 0; @@ -12592,8 +13777,7 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) * Stray Mailbox Interrupt, mbxCommand <cmd> * mbxStatus <status> */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | - LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "(%d):0304 Stray Mailbox " "Interrupt mbxCommand x%x " "mbxStatus x%x\n", @@ -12653,7 +13837,7 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) if (rc != MBX_BUSY) lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_SLI, + LOG_TRACE_EVENT, "0350 rc should have" "been MBX_BUSY\n"); if (rc != MBX_NOT_FINISHED) @@ -12668,7 +13852,21 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) spin_unlock_irqrestore( &phba->pport->work_port_lock, iflag); - lpfc_mbox_cmpl_put(phba, pmb); + + /* Do NOT queue MBX_HEARTBEAT to the worker + * thread for processing. + */ + if (pmbox->mbxCommand == MBX_HEARTBEAT) { + /* Process mbox now */ + phba->sli.mbox_active = NULL; + phba->sli.sli_flag &= + ~LPFC_SLI_MBOX_ACTIVE; + if (pmb->mbox_cmpl) + pmb->mbox_cmpl(phba, pmb); + } else { + /* Queue to worker thread to process */ + lpfc_mbox_cmpl_put(phba, pmb); + } } } else spin_unlock_irqrestore(&phba->hbalock, iflag); @@ -12682,8 +13880,9 @@ send_current_mbox: MBX_NOWAIT); } while (rc == MBX_NOT_FINISHED); if (rc != MBX_SUCCESS) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | - LOG_SLI, "0349 rc should be " + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, + "0349 rc should be " "MBX_SUCCESS\n"); } @@ -12917,155 +14116,46 @@ lpfc_sli_intr_handler(int irq, void *dev_id) void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) { struct lpfc_cq_event *cq_event; + unsigned long iflags; /* First, declare the els xri abort event has been handled */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag &= ~ELS_XRI_ABORT_EVENT; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); + /* Now, handle all the els xri abort events */ + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); while (!list_empty(&phba->sli4_hba.sp_els_xri_aborted_work_queue)) { /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); list_remove_head(&phba->sli4_hba.sp_els_xri_aborted_work_queue, cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); /* Notify aborted XRI for ELS work queue */ lpfc_sli4_els_xri_aborted(phba, &cq_event->cqe.wcqe_axri); + /* Free the event processed back to the free pool */ lpfc_sli4_cq_event_release(phba, cq_event); + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); } + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); } /** - * lpfc_sli4_iocb_param_transfer - Transfer pIocbOut and cmpl status to pIocbIn - * @phba: pointer to lpfc hba data structure - * @pIocbIn: pointer to the rspiocbq - * @pIocbOut: pointer to the cmdiocbq - * @wcqe: pointer to the complete wcqe - * - * This routine transfers the fields of a command iocbq to a response iocbq - * by copying all the IOCB fields from command iocbq and transferring the - * completion status information from the complete wcqe. - **/ -static void -lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, - struct lpfc_iocbq *pIocbIn, - struct lpfc_iocbq *pIocbOut, - struct lpfc_wcqe_complete *wcqe) -{ - int numBdes, i; - unsigned long iflags; - uint32_t status, max_response; - struct lpfc_dmabuf *dmabuf; - struct ulp_bde64 *bpl, bde; - size_t offset = offsetof(struct lpfc_iocbq, iocb); - - memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, - sizeof(struct lpfc_iocbq) - offset); - /* Map WCQE parameters into irspiocb parameters */ - status = bf_get(lpfc_wcqe_c_status, wcqe); - pIocbIn->iocb.ulpStatus = (status & LPFC_IOCB_STATUS_MASK); - if (pIocbOut->iocb_flag & LPFC_IO_FCP) - if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR) - pIocbIn->iocb.un.fcpi.fcpi_parm = - pIocbOut->iocb.un.fcpi.fcpi_parm - - wcqe->total_data_placed; - else - pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; - else { - pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; - switch (pIocbOut->iocb.ulpCommand) { - case CMD_ELS_REQUEST64_CR: - dmabuf = (struct lpfc_dmabuf *)pIocbOut->context3; - bpl = (struct ulp_bde64 *)dmabuf->virt; - bde.tus.w = le32_to_cpu(bpl[1].tus.w); - max_response = bde.tus.f.bdeSize; - break; - case CMD_GEN_REQUEST64_CR: - max_response = 0; - if (!pIocbOut->context3) - break; - numBdes = pIocbOut->iocb.un.genreq64.bdl.bdeSize/ - sizeof(struct ulp_bde64); - dmabuf = (struct lpfc_dmabuf *)pIocbOut->context3; - bpl = (struct ulp_bde64 *)dmabuf->virt; - for (i = 0; i < numBdes; i++) { - bde.tus.w = le32_to_cpu(bpl[i].tus.w); - if (bde.tus.f.bdeFlags != BUFF_TYPE_BDE_64) - max_response += bde.tus.f.bdeSize; - } - break; - default: - max_response = wcqe->total_data_placed; - break; - } - if (max_response < wcqe->total_data_placed) - pIocbIn->iocb.un.genreq64.bdl.bdeSize = max_response; - else - pIocbIn->iocb.un.genreq64.bdl.bdeSize = - wcqe->total_data_placed; - } - - /* Convert BG errors for completion status */ - if (status == CQE_STATUS_DI_ERROR) { - pIocbIn->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; - - if (bf_get(lpfc_wcqe_c_bg_edir, wcqe)) - pIocbIn->iocb.un.ulpWord[4] = IOERR_RX_DMA_FAILED; - else - pIocbIn->iocb.un.ulpWord[4] = IOERR_TX_DMA_FAILED; - - pIocbIn->iocb.unsli3.sli3_bg.bgstat = 0; - if (bf_get(lpfc_wcqe_c_bg_ge, wcqe)) /* Guard Check failed */ - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - BGS_GUARD_ERR_MASK; - if (bf_get(lpfc_wcqe_c_bg_ae, wcqe)) /* App Tag Check failed */ - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - BGS_APPTAG_ERR_MASK; - if (bf_get(lpfc_wcqe_c_bg_re, wcqe)) /* Ref Tag Check failed */ - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - BGS_REFTAG_ERR_MASK; - - /* Check to see if there was any good data before the error */ - if (bf_get(lpfc_wcqe_c_bg_tdpv, wcqe)) { - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - BGS_HI_WATER_MARK_PRESENT_MASK; - pIocbIn->iocb.unsli3.sli3_bg.bghm = - wcqe->total_data_placed; - } - - /* - * Set ALL the error bits to indicate we don't know what - * type of error it is. - */ - if (!pIocbIn->iocb.unsli3.sli3_bg.bgstat) - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - (BGS_REFTAG_ERR_MASK | BGS_APPTAG_ERR_MASK | - BGS_GUARD_ERR_MASK); - } - - /* Pick up HBA exchange busy condition */ - if (bf_get(lpfc_wcqe_c_xb, wcqe)) { - spin_lock_irqsave(&phba->hbalock, iflags); - pIocbIn->iocb_flag |= LPFC_EXCHANGE_BUSY; - spin_unlock_irqrestore(&phba->hbalock, iflags); - } -} - -/** - * lpfc_sli4_els_wcqe_to_rspiocbq - Get response iocbq from els wcqe + * lpfc_sli4_els_preprocess_rspiocbq - Get response iocbq from els wcqe * @phba: Pointer to HBA context object. - * @wcqe: Pointer to work-queue completion queue entry. + * @irspiocbq: Pointer to work-queue completion queue entry. * * This routine handles an ELS work-queue completion event and construct - * a pseudo response ELS IODBQ from the SLI4 ELS WCQE for the common + * a pseudo response ELS IOCBQ from the SLI4 ELS WCQE for the common * discovery engine to handle. * * Return: Pointer to the receive IOCBQ, NULL otherwise. **/ static struct lpfc_iocbq * -lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, - struct lpfc_iocbq *irspiocbq) +lpfc_sli4_els_preprocess_rspiocbq(struct lpfc_hba *phba, + struct lpfc_iocbq *irspiocbq) { struct lpfc_sli_ring *pring; struct lpfc_iocbq *cmdiocbq; @@ -13077,11 +14167,13 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, return NULL; wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl; + spin_lock_irqsave(&pring->ring_lock, iflags); pring->stats.iocb_event++; /* Look up the ELS command IOCB and create pseudo response IOCB */ cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); if (unlikely(!cmdiocbq)) { + spin_unlock_irqrestore(&pring->ring_lock, iflags); lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0386 ELS complete with no corresponding " "cmdiocb: 0x%x 0x%x 0x%x 0x%x\n", @@ -13091,13 +14183,18 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, return NULL; } - spin_lock_irqsave(&pring->ring_lock, iflags); + memcpy(&irspiocbq->wqe, &cmdiocbq->wqe, sizeof(union lpfc_wqe128)); + memcpy(&irspiocbq->wcqe_cmpl, wcqe, sizeof(*wcqe)); + /* Put the iocb back on the txcmplq */ lpfc_sli_ringtxcmpl_put(phba, pring, cmdiocbq); spin_unlock_irqrestore(&pring->ring_lock, iflags); - /* Fake the irspiocbq and copy necessary response information */ - lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe); + if (bf_get(lpfc_wcqe_c_xb, wcqe)) { + spin_lock_irqsave(&phba->hbalock, iflags); + irspiocbq->cmd_flag |= LPFC_EXCHANGE_BUSY; + spin_unlock_irqrestore(&phba->hbalock, iflags); + } return irspiocbq; } @@ -13110,7 +14207,7 @@ lpfc_cq_event_setup(struct lpfc_hba *phba, void *entry, int size) /* Allocate a new internal CQ_EVENT entry */ cq_event = lpfc_sli4_cq_event_alloc(phba); if (!cq_event) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0602 Failed to alloc CQ_EVENT entry\n"); return NULL; } @@ -13123,7 +14220,7 @@ lpfc_cq_event_setup(struct lpfc_hba *phba, void *entry, int size) /** * lpfc_sli4_sp_handle_async_event - Handle an asynchronous event * @phba: Pointer to HBA context object. - * @cqe: Pointer to mailbox completion queue entry. + * @mcqe: Pointer to mailbox completion queue entry. * * This routine process a mailbox completion queue entry with asynchronous * event. @@ -13144,9 +14241,13 @@ lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) cq_event = lpfc_cq_event_setup(phba, mcqe, sizeof(struct lpfc_mcqe)); if (!cq_event) return false; - spin_lock_irqsave(&phba->hbalock, iflags); + + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); + /* Set the async event flag */ + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag |= ASYNC_EVENT; spin_unlock_irqrestore(&phba->hbalock, iflags); @@ -13156,7 +14257,7 @@ lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) /** * lpfc_sli4_sp_handle_mbox_event - Handle a mailbox completion event * @phba: Pointer to HBA context object. - * @cqe: Pointer to mailbox completion queue entry. + * @mcqe: Pointer to mailbox completion queue entry. * * This routine process a mailbox completion queue entry with mailbox * completion event. @@ -13185,7 +14286,7 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) spin_lock_irqsave(&phba->hbalock, iflags); pmb = phba->sli.mbox_active; if (unlikely(!pmb)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1832 No pending MBOX command to handle\n"); spin_unlock_irqrestore(&phba->hbalock, iflags); goto out_no_mqe_complete; @@ -13223,19 +14324,32 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) if (mcqe_status == MB_CQE_STATUS_SUCCESS) { mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; - /* Reg_LOGIN of dflt RPI was successful. Now lets get - * RID of the PPI using the same mbox buffer. + + /* Reg_LOGIN of dflt RPI was successful. Mark the + * node as having an UNREG_LOGIN in progress to stop + * an unsolicited PLOGI from the same NPortId from + * starting another mailbox transaction. */ + spin_lock_irqsave(&ndlp->lock, iflags); + ndlp->nlp_flag |= NLP_UNREG_INP; + spin_unlock_irqrestore(&ndlp->lock, iflags); lpfc_unreg_login(phba, vport->vpi, pmbox->un.varWords[0], pmb); pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; pmb->ctx_buf = mp; + + /* No reference taken here. This is a default + * RPI reg/immediate unreg cycle. The reference was + * taken in the reg rpi path and is released when + * this mailbox completes. + */ pmb->ctx_ndlp = ndlp; pmb->vport = vport; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); if (rc != MBX_BUSY) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | - LOG_SLI, "0385 rc should " + lpfc_printf_log(phba, KERN_ERR, + LOG_TRACE_EVENT, + "0385 rc should " "have been MBX_BUSY\n"); if (rc != MBX_NOT_FINISHED) goto send_current_mbox; @@ -13245,7 +14359,26 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) phba->pport->work_port_events &= ~WORKER_MBOX_TMO; spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); - /* There is mailbox completion work to do */ + /* Do NOT queue MBX_HEARTBEAT to the worker thread for processing. */ + if (pmbox->mbxCommand == MBX_HEARTBEAT) { + spin_lock_irqsave(&phba->hbalock, iflags); + /* Release the mailbox command posting token */ + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = NULL; + if (bf_get(lpfc_trailer_consumed, mcqe)) + lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + /* Post the next mbox command, if there is one */ + lpfc_sli4_post_async_mbox(phba); + + /* Process cmpl now */ + if (pmb->mbox_cmpl) + pmb->mbox_cmpl(phba, pmb); + return false; + } + + /* There is mailbox completion work to queue to the worker thread */ spin_lock_irqsave(&phba->hbalock, iflags); __lpfc_mbox_cmpl_put(phba, pmb); phba->work_ha |= HA_MBATT; @@ -13276,6 +14409,7 @@ out_no_mqe_complete: /** * lpfc_sli4_sp_handle_mcqe - Process a mailbox completion queue entry * @phba: Pointer to HBA context object. + * @cq: Pointer to associated CQ * @cqe: Pointer to mailbox completion queue entry. * * This routine process a mailbox completion queue entry, it invokes the @@ -13342,7 +14476,7 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, txq_cnt++; if (!list_empty(&pring->txcmplq)) txcmplq_cnt++; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d " "els_txcmplq_cnt=%d\n", txq_cnt, phba->iocb_cnt, @@ -13419,21 +14553,24 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, break; case LPFC_NVME_LS: /* NVME LS uses ELS resources */ case LPFC_ELS: - cq_event = lpfc_cq_event_setup( - phba, wcqe, sizeof(struct sli4_wcqe_xri_aborted)); - if (!cq_event) - return false; + cq_event = lpfc_cq_event_setup(phba, wcqe, sizeof(*wcqe)); + if (!cq_event) { + workposted = false; + break; + } cq_event->hdwq = cq->hdwq; - spin_lock_irqsave(&phba->hbalock, iflags); + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_els_xri_aborted_work_queue); /* Set the els xri abort event flag */ phba->hba_flag |= ELS_XRI_ABORT_EVENT; - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); workposted = true; break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0603 Invalid CQ subtype %d: " "%08x %08x %08x %08x\n", cq->subtype, wcqe->word0, wcqe->parameter, @@ -13481,9 +14618,9 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) status = bf_get(lpfc_rcqe_status, rcqe); switch (status) { case FC_STATUS_RQ_BUF_LEN_EXCEEDED: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2537 Receive Frame Truncated!!\n"); - /* fall through */ + fallthrough; case FC_STATUS_RQ_SUCCESS: spin_lock_irqsave(&phba->hbalock, iflags); lpfc_sli4_rq_release(hrq, drq); @@ -13503,7 +14640,11 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) fc_hdr->fh_r_ctl == FC_RCTL_DD_UNSOL_DATA) { spin_unlock_irqrestore(&phba->hbalock, iflags); /* Handle MDS Loopback frames */ - lpfc_sli4_handle_mds_loopback(phba->pport, dma_buf); + if (!(phba->pport->load_flag & FC_UNLOADING)) + lpfc_sli4_handle_mds_loopback(phba->pport, + dma_buf); + else + lpfc_in_buf_free(phba, &dma_buf->dbuf); break; } @@ -13518,7 +14659,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) case FC_STATUS_INSUFF_BUF_FRM_DISC: if (phba->nvmet_support) { tgtp = phba->targetport->private; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6402 RQE Error x%x, posted %d err_cnt " "%d: %x %x %x\n", status, hrq->RQ_buf_posted, @@ -13527,7 +14668,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) atomic_read(&tgtp->rcv_fcp_cmd_out), atomic_read(&tgtp->xmt_fcp_release)); } - /* fallthrough */ + fallthrough; case FC_STATUS_INSUFF_BUF_NEED_BUF: hrq->RQ_no_posted_buf++; @@ -13590,7 +14731,7 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, (struct lpfc_rcqe *)&cqevt); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0388 Not a valid WCQE code: x%x\n", bf_get(lpfc_cqe_code, &cqevt)); break; @@ -13602,6 +14743,7 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, * lpfc_sli4_sp_handle_eqe - Process a slow-path event queue entry * @phba: Pointer to HBA context object. * @eqe: Pointer to fast-path event queue entry. + * @speq: Pointer to slow-path event queue. * * This routine process a event queue entry from the slow-path event queue. * It will check the MajorCode and MinorCode to determine this is for a @@ -13617,6 +14759,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, { struct lpfc_queue *cq = NULL, *childq; uint16_t cqid; + int ret = 0; /* Get the reference to the corresponding CQ */ cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); @@ -13629,7 +14772,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, } if (unlikely(!cq)) { if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0365 Slow-path CQ identifier " "(%d) does not exist\n", cqid); return; @@ -13638,9 +14781,14 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, /* Save EQ associated with this CQ */ cq->assoc_qp = speq; - if (!queue_work_on(cq->chann, phba->wq, &cq->spwork)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0390 Cannot schedule soft IRQ " + if (is_kdump_kernel()) + ret = queue_work(phba->wq, &cq->spwork); + else + ret = queue_work_on(cq->chann, phba->wq, &cq->spwork); + + if (!ret) + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0390 Cannot schedule queue work " "for CQ eqcqid=%d, cqid=%d on CPU %d\n", cqid, cq->queue_id, raw_smp_processor_id()); } @@ -13651,6 +14799,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, * @cq: Pointer to CQ to be processed * @handler: Routine to process each cqe * @delay: Pointer to usdelay to set in case of rescheduling of the handler + * @poll_mode: Polling mode we were called from * * This routine processes completion queue entries in a CQ. While a valid * queue element is found, the handler is called. During processing checks @@ -13668,7 +14817,8 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, static bool __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, bool (*handler)(struct lpfc_hba *, struct lpfc_queue *, - struct lpfc_cqe *), unsigned long *delay) + struct lpfc_cqe *), unsigned long *delay, + enum lpfc_poll_mode poll_mode) { struct lpfc_cqe *cqe; bool workposted = false; @@ -13709,6 +14859,10 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, arm = false; } + /* Note: complete the irq_poll softirq before rearming CQ */ + if (poll_mode == LPFC_IRQ_POLL) + irq_poll_complete(&cq->iop); + /* Track the max number of CQEs processed in 1 EQ */ if (count > cq->CQ_max_cqe) cq->CQ_max_cqe = count; @@ -13721,7 +14875,7 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, "0369 No entry from completion queue " "qid=%d\n", cq->queue_id); - cq->queue_claimed = 0; + xchg(&cq->queue_claimed, 0); rearm_and_exit: phba->sli4_hba.sli4_write_cq_db(phba, cq, consumed, @@ -13731,7 +14885,7 @@ rearm_and_exit: } /** - * lpfc_sli4_sp_process_cq - Process a slow-path event queue entry + * __lpfc_sli4_sp_process_cq - Process a slow-path event queue entry * @cq: pointer to CQ to process * * This routine calls the cq processing routine with a handler specific @@ -13751,36 +14905,42 @@ __lpfc_sli4_sp_process_cq(struct lpfc_queue *cq) struct lpfc_hba *phba = cq->phba; unsigned long delay; bool workposted = false; + int ret = 0; /* Process and rearm the CQ */ switch (cq->type) { case LPFC_MCQ: workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_sp_handle_mcqe, - &delay); + &delay, LPFC_QUEUE_WORK); break; case LPFC_WCQ: if (cq->subtype == LPFC_IO) workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_fp_handle_cqe, - &delay); + &delay, LPFC_QUEUE_WORK); else workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_sp_handle_cqe, - &delay); + &delay, LPFC_QUEUE_WORK); break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0370 Invalid completion queue type (%d)\n", cq->type); return; } if (delay) { - if (!queue_delayed_work_on(cq->chann, phba->wq, - &cq->sched_spwork, delay)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0394 Cannot schedule soft IRQ " + if (is_kdump_kernel()) + ret = queue_delayed_work(phba->wq, &cq->sched_spwork, + delay); + else + ret = queue_delayed_work_on(cq->chann, phba->wq, + &cq->sched_spwork, delay); + if (!ret) + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0394 Cannot schedule queue work " "for cqid=%d on CPU %d\n", cq->queue_id, cq->chann); } @@ -13835,7 +14995,6 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, { struct lpfc_sli_ring *pring = cq->pring; struct lpfc_iocbq *cmdiocbq; - struct lpfc_iocbq irspiocbq; unsigned long iflags; /* Check for response status */ @@ -13849,9 +15008,9 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, IOERR_NO_RESOURCES)) phba->lpfc_rampdown_queue_depth(phba); - /* Log the error status */ + /* Log the cmpl status */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0373 FCP CQE error: status=x%x: " + "0373 FCP CQE cmpl: status=x%x: " "CQE: %08x %08x %08x %08x\n", bf_get(lpfc_wcqe_c_status, wcqe), wcqe->word0, wcqe->total_data_placed, @@ -13861,9 +15020,9 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, /* Look up the FCP command IOCB and create pseudo response IOCB */ spin_lock_irqsave(&pring->ring_lock, iflags); pring->stats.iocb_event++; - spin_unlock_irqrestore(&pring->ring_lock, iflags); cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, bf_get(lpfc_wcqe_c_request_tag, wcqe)); + spin_unlock_irqrestore(&pring->ring_lock, iflags); if (unlikely(!cmdiocbq)) { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0374 FCP complete with no corresponding " @@ -13874,36 +15033,31 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, #ifdef CONFIG_SCSI_LPFC_DEBUG_FS cmdiocbq->isr_timestamp = cq->isr_timestamp; #endif - if (cmdiocbq->iocb_cmpl == NULL) { - if (cmdiocbq->wqe_cmpl) { - if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) { - spin_lock_irqsave(&phba->hbalock, iflags); - cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED; - spin_unlock_irqrestore(&phba->hbalock, iflags); - } + if (bf_get(lpfc_wcqe_c_xb, wcqe)) { + spin_lock_irqsave(&phba->hbalock, iflags); + cmdiocbq->cmd_flag |= LPFC_EXCHANGE_BUSY; + spin_unlock_irqrestore(&phba->hbalock, iflags); + } - /* Pass the cmd_iocb and the wcqe to the upper layer */ - (cmdiocbq->wqe_cmpl)(phba, cmdiocbq, wcqe); - return; + if (cmdiocbq->cmd_cmpl) { + /* For FCP the flag is cleared in cmd_cmpl */ + if (!(cmdiocbq->cmd_flag & LPFC_IO_FCP) && + cmdiocbq->cmd_flag & LPFC_DRIVER_ABORTED) { + spin_lock_irqsave(&phba->hbalock, iflags); + cmdiocbq->cmd_flag &= ~LPFC_DRIVER_ABORTED; + spin_unlock_irqrestore(&phba->hbalock, iflags); } + + /* Pass the cmd_iocb and the wcqe to the upper layer */ + memcpy(&cmdiocbq->wcqe_cmpl, wcqe, + sizeof(struct lpfc_wcqe_complete)); + cmdiocbq->cmd_cmpl(phba, cmdiocbq, cmdiocbq); + } else { lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "0375 FCP cmdiocb not callback function " "iotag: (%d)\n", bf_get(lpfc_wcqe_c_request_tag, wcqe)); - return; - } - - /* Fake the irspiocb and copy necessary response information */ - lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe); - - if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) { - spin_lock_irqsave(&phba->hbalock, iflags); - cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED; - spin_unlock_irqrestore(&phba->hbalock, iflags); } - - /* Pass the cmd_iocb and the rsp state to the upper layer */ - (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq); } /** @@ -13945,6 +15099,7 @@ lpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, /** * lpfc_sli4_nvmet_handle_rcqe - Process a receive-queue completion queue entry * @phba: Pointer to HBA context object. + * @cq: Pointer to completion queue. * @rcqe: Pointer to receive-queue completion queue entry. * * This routine process a receive-queue completion queue entry. @@ -13989,9 +15144,9 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, status = bf_get(lpfc_rcqe_status, rcqe); switch (status) { case FC_STATUS_RQ_BUF_LEN_EXCEEDED: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6126 Receive Frame Truncated!!\n"); - /* fall through */ + fallthrough; case FC_STATUS_RQ_SUCCESS: spin_lock_irqsave(&phba->hbalock, iflags); lpfc_sli4_rq_release(hrq, drq); @@ -14008,8 +15163,8 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, /* Just some basic sanity checks on FCP Command frame */ fctl = (fc_hdr->fh_f_ctl[0] << 16 | - fc_hdr->fh_f_ctl[1] << 8 | - fc_hdr->fh_f_ctl[2]); + fc_hdr->fh_f_ctl[1] << 8 | + fc_hdr->fh_f_ctl[2]); if (((fctl & (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)) != (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)) || @@ -14029,7 +15184,7 @@ drop: case FC_STATUS_INSUFF_BUF_FRM_DISC: if (phba->nvmet_support) { tgtp = phba->targetport->private; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6401 RQE Error x%x, posted %d err_cnt " "%d: %x %x %x\n", status, hrq->RQ_buf_posted, @@ -14038,7 +15193,7 @@ drop: atomic_read(&tgtp->rcv_fcp_cmd_out), atomic_read(&tgtp->xmt_fcp_release)); } - /* fallthrough */ + fallthrough; case FC_STATUS_INSUFF_BUF_NEED_BUF: hrq->RQ_no_posted_buf++; @@ -14053,7 +15208,7 @@ out: * lpfc_sli4_fp_handle_cqe - Process fast-path work queue completion entry * @phba: adapter with cq * @cq: Pointer to the completion queue. - * @eqe: Pointer to fast-path completion queue entry. + * @cqe: Pointer to fast-path completion queue entry. * * This routine process a fast-path work queue completion entry from fast-path * event queue for FCP command response completion. @@ -14103,7 +15258,7 @@ lpfc_sli4_fp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, } break; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0144 Not a valid CQE code: x%x\n", bf_get(lpfc_wcqe_c_code, &wcqe)); break; @@ -14112,8 +15267,51 @@ lpfc_sli4_fp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, } /** + * lpfc_sli4_sched_cq_work - Schedules cq work + * @phba: Pointer to HBA context object. + * @cq: Pointer to CQ + * @cqid: CQ ID + * + * This routine checks the poll mode of the CQ corresponding to + * cq->chann, then either schedules a softirq or queue_work to complete + * cq work. + * + * queue_work path is taken if in NVMET mode, or if poll_mode is in + * LPFC_QUEUE_WORK mode. Otherwise, softirq path is taken. + * + **/ +static void lpfc_sli4_sched_cq_work(struct lpfc_hba *phba, + struct lpfc_queue *cq, uint16_t cqid) +{ + int ret = 0; + + switch (cq->poll_mode) { + case LPFC_IRQ_POLL: + /* CGN mgmt is mutually exclusive from softirq processing */ + if (phba->cmf_active_mode == LPFC_CFG_OFF) { + irq_poll_sched(&cq->iop); + break; + } + fallthrough; + case LPFC_QUEUE_WORK: + default: + if (is_kdump_kernel()) + ret = queue_work(phba->wq, &cq->irqwork); + else + ret = queue_work_on(cq->chann, phba->wq, &cq->irqwork); + if (!ret) + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0383 Cannot schedule queue work " + "for CQ eqcqid=%d, cqid=%d on CPU %d\n", + cqid, cq->queue_id, + raw_smp_processor_id()); + } +} + +/** * lpfc_sli4_hba_handle_eqe - Process a fast-path event queue entry * @phba: Pointer to HBA context object. + * @eq: Pointer to the queue structure. * @eqe: Pointer to fast-path event queue entry. * * This routine process a event queue entry from the fast-path event queue. @@ -14132,7 +15330,7 @@ lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t cqid, id; if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0366 Not a valid completion " "event: majorcode=x%x, minorcode=x%x\n", bf_get_le32(lpfc_eqe_major_code, eqe), @@ -14175,7 +15373,7 @@ lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq, process_cq: if (unlikely(cqid != cq->queue_id)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0368 Miss-matched fast-path completion " "queue identifier: eqcqid=%d, fcpcqid=%d\n", cqid, cq->queue_id); @@ -14189,16 +15387,13 @@ work_cq: else cq->isr_timestamp = 0; #endif - if (!queue_work_on(cq->chann, phba->wq, &cq->irqwork)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0363 Cannot schedule soft IRQ " - "for CQ eqcqid=%d, cqid=%d on CPU %d\n", - cqid, cq->queue_id, raw_smp_processor_id()); + lpfc_sli4_sched_cq_work(phba, cq, cqid); } /** * __lpfc_sli4_hba_process_cq - Process a fast-path event queue entry * @cq: Pointer to CQ to be processed + * @poll_mode: Enum lpfc_poll_state to determine poll mode * * This routine calls the cq processing routine with the handler for * fast path CQEs. @@ -14212,23 +15407,30 @@ work_cq: * the delay indicates when to reschedule it. **/ static void -__lpfc_sli4_hba_process_cq(struct lpfc_queue *cq) +__lpfc_sli4_hba_process_cq(struct lpfc_queue *cq, + enum lpfc_poll_mode poll_mode) { struct lpfc_hba *phba = cq->phba; unsigned long delay; bool workposted = false; + int ret = 0; /* process and rearm the CQ */ workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_fp_handle_cqe, - &delay); + &delay, poll_mode); if (delay) { - if (!queue_delayed_work_on(cq->chann, phba->wq, - &cq->sched_irqwork, delay)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0367 Cannot schedule soft IRQ " - "for cqid=%d on CPU %d\n", - cq->queue_id, cq->chann); + if (is_kdump_kernel()) + ret = queue_delayed_work(phba->wq, &cq->sched_irqwork, + delay); + else + ret = queue_delayed_work_on(cq->chann, phba->wq, + &cq->sched_irqwork, delay); + if (!ret) + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "0367 Cannot schedule queue work " + "for cqid=%d on CPU %d\n", + cq->queue_id, cq->chann); } /* wake up worker thread if there are works to be done */ @@ -14248,11 +15450,11 @@ lpfc_sli4_hba_process_cq(struct work_struct *work) { struct lpfc_queue *cq = container_of(work, struct lpfc_queue, irqwork); - __lpfc_sli4_hba_process_cq(cq); + __lpfc_sli4_hba_process_cq(cq, LPFC_QUEUE_WORK); } /** - * lpfc_sli4_hba_process_cq - fast-path work handler when started by timer + * lpfc_sli4_dly_hba_process_cq - fast-path work handler when started by timer * @work: pointer to work element * * translates from the work handler and calls the fast-path handler. @@ -14263,7 +15465,7 @@ lpfc_sli4_dly_hba_process_cq(struct work_struct *work) struct lpfc_queue *cq = container_of(to_delayed_work(work), struct lpfc_queue, sched_irqwork); - __lpfc_sli4_hba_process_cq(cq); + __lpfc_sli4_hba_process_cq(cq, LPFC_QUEUE_WORK); } /** @@ -14302,7 +15504,6 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) int ecount = 0; int hba_eqidx; struct lpfc_eq_intr_info *eqi; - uint32_t icnt; /* Get the driver's phba structure from the dev_id */ hba_eq_hdl = (struct lpfc_hba_eq_hdl *)dev_id; @@ -14330,11 +15531,12 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) return IRQ_NONE; } - eqi = phba->sli4_hba.eq_info; - icnt = this_cpu_inc_return(eqi->icnt); + eqi = this_cpu_ptr(phba->sli4_hba.eq_info); + eqi->icnt++; + fpeq->last_cpu = raw_smp_processor_id(); - if (icnt > LPFC_EQD_ISR_TRIGGER && + if (eqi->icnt > LPFC_EQD_ISR_TRIGGER && fpeq->q_flag & HBA_EQ_DELAY_CHK && phba->cfg_auto_imax && fpeq->q_mode != LPFC_MAX_AUTO_EQ_DELAY && @@ -14356,7 +15558,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) } return IRQ_HANDLED; -} /* lpfc_sli4_fp_intr_handler */ +} /* lpfc_sli4_hba_intr_handler */ /** * lpfc_sli4_intr_handler - Device-level interrupt handler for SLI-4 device @@ -14450,12 +15652,10 @@ static inline void lpfc_sli4_add_to_poll_list(struct lpfc_queue *eq) { struct lpfc_hba *phba = eq->phba; - if (list_empty(&phba->poll_list)) { - timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0); - /* kickstart slowpath processing for this eq */ + /* kickstart slowpath processing if needed */ + if (list_empty(&phba->poll_list)) mod_timer(&phba->cpuhp_poll_timer, jiffies + msecs_to_jiffies(LPFC_POLL_HB)); - } list_add_rcu(&eq->_poll_list, &phba->poll_list); synchronize_rcu(); @@ -14586,7 +15786,7 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue) * @phba: The HBA that this queue is being created on. * @page_size: The size of a queue page * @entry_size: The size of each queue entry for this queue. - * @entry count: The number of entries that this queue will handle. + * @entry_count: The number of entries that this queue will handle. * @cpu: The cpu that will primarily utilize this queue. * * This function allocates a queue structure and the DMAable memory used for @@ -14758,7 +15958,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_FCP | LOG_NVME, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6428 Failed allocating mailbox cmd buffer." " EQ delay was not set.\n"); return; @@ -14793,14 +15993,13 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, mbox->vport = phba->pport; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->ctx_buf = NULL; mbox->ctx_ndlp = NULL; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); shdr = (union lpfc_sli4_cfg_shdr *) &eq_delay->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2512 MODIFY_EQ_DELAY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -14877,14 +16076,14 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) dmult); switch (eq->entry_count) { default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0360 Unsupported EQ count. (%d)\n", eq->entry_count); if (eq->entry_count < 256) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + fallthrough; /* otherwise default to smallest count */ case 256: bf_set(lpfc_eq_context_count, &eq_create->u.request.context, LPFC_EQ_CNT_256); @@ -14921,7 +16120,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2500 EQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -14940,11 +16139,22 @@ out: return status; } +static int lpfc_cq_poll_hdler(struct irq_poll *iop, int budget) +{ + struct lpfc_queue *cq = container_of(iop, struct lpfc_queue, iop); + + __lpfc_sli4_hba_process_cq(cq, LPFC_IRQ_POLL); + + return 1; +} + /** * lpfc_cq_create - Create a Completion Queue on the HBA * @phba: HBA structure that indicates port to create a queue on. * @cq: The queue structure to use to create the completion queue. * @eq: The event queue to bind this completion queue to. + * @type: Type of queue (EQ, GCQ, MCQ, WCQ, etc). + * @subtype: Functional purpose of the queue (MBOX, IO, ELS, NVMET, etc). * * This function creates a completion queue, as detailed in @wq, on a port, * described by @phba by sending a CQ_CREATE mailbox command to the HBA. @@ -15015,9 +16225,9 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, LPFC_CQ_CNT_WORD7); break; } - /* fall through */ + fallthrough; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0361 Unsupported CQ count: " "entry cnt %d sz %d pg cnt %d\n", cq->entry_count, cq->entry_size, @@ -15026,7 +16236,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + fallthrough; /* otherwise default to smallest count */ case 256: bf_set(lpfc_cq_context_count, &cq_create->u.request.context, LPFC_CQ_CNT_256); @@ -15053,7 +16263,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2501 CQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -15079,6 +16289,8 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, if (cq->queue_id > phba->sli4_hba.cq_max) phba->sli4_hba.cq_max = cq->queue_id; + + irq_poll_init(&cq->iop, LPFC_IRQ_POLL_WEIGHT, lpfc_cq_poll_hdler); out: mempool_free(mbox, phba->mbox_mem_pool); return status; @@ -15089,6 +16301,8 @@ out: * @phba: HBA structure that indicates port to create a queue on. * @cqp: The queue structure array to use to create the completion queues. * @hdwq: The hardware queue array with the EQ to bind completion queues to. + * @type: Type of queue (EQ, GCQ, MCQ, WCQ, etc). + * @subtype: Functional purpose of the queue (MBOX, IO, ELS, NVMET, etc). * * This function creates a set of completion queue, s to support MRQ * as detailed in @cqp, on a port, @@ -15138,7 +16352,7 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, LPFC_MBOX_OPCODE_FCOE_CQ_CREATE_SET, length, LPFC_SLI4_MBX_NEMBED); if (alloclen < length) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3098 Allocated DMA memory size (%d) is " "less than the requested DMA memory size " "(%d)\n", alloclen, length); @@ -15190,16 +16404,16 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, LPFC_CQ_CNT_WORD7); break; } - /* fall through */ + fallthrough; default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3118 Bad CQ count. (%d)\n", cq->entry_count); if (cq->entry_count < 256) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest */ + fallthrough; /* otherwise default to smallest */ case 256: bf_set(lpfc_mbx_cq_create_set_cqe_cnt, &cq_set->u.request, LPFC_CQ_CNT_256); @@ -15310,7 +16524,7 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3119 CQ_CREATE_SET mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -15468,14 +16682,14 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, cq->queue_id); switch (mq->entry_count) { default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0362 Unsupported MQ count. (%d)\n", mq->entry_count); if (mq->entry_count < 16) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + fallthrough; /* otherwise default to smallest count */ case 16: bf_set(lpfc_mq_context_ring_size, &mq_create_ext->u.request.context, @@ -15524,7 +16738,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2502 MQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -15587,8 +16801,10 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, uint16_t pci_barset; uint8_t dpp_barset; uint32_t dpp_offset; - unsigned long pg_addr; uint8_t wq_create_version; +#ifdef CONFIG_X86 + unsigned long pg_addr; +#endif /* sanity check on queue memory */ if (!wq || !cq) @@ -15621,12 +16837,6 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, else wq_create_version = LPFC_Q_CREATE_VERSION_0; - - if (phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) - wq_create_version = LPFC_Q_CREATE_VERSION_1; - else - wq_create_version = LPFC_Q_CREATE_VERSION_0; - switch (wq_create_version) { case LPFC_Q_CREATE_VERSION_1: bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, @@ -15673,7 +16883,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2503 WQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -15700,7 +16910,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, &wq_create->u.response); if ((wq->db_format != LPFC_DB_LIST_FORMAT) && (wq->db_format != LPFC_DB_RING_FORMAT)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3265 WQ[%d] doorbell format " "not supported: x%x\n", wq->queue_id, wq->db_format); @@ -15712,7 +16922,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset); if (!bar_memmap_p) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3263 WQ[%d] failed to memmap " "pci barset:x%x\n", wq->queue_id, pci_barset); @@ -15722,7 +16932,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, db_offset = wq_create->u.response.doorbell_offset; if ((db_offset != LPFC_ULP0_WQ_DOORBELL) && (db_offset != LPFC_ULP1_WQ_DOORBELL)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3252 WQ[%d] doorbell offset " "not supported: x%x\n", wq->queue_id, db_offset); @@ -15746,7 +16956,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset); if (!bar_memmap_p) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3267 WQ[%d] failed to memmap " "pci barset:x%x\n", wq->queue_id, pci_barset); @@ -15762,7 +16972,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, dpp_barset); if (!bar_memmap_p) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3268 WQ[%d] failed to memmap " "pci barset:x%x\n", wq->queue_id, dpp_barset); @@ -15778,9 +16988,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, wq->queue_id, pci_barset, db_offset, wq->dpp_id, dpp_barset, dpp_offset); +#ifdef CONFIG_X86 /* Enable combined writes for DPP aperture */ pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK; -#ifdef CONFIG_X86 rc = set_memory_wc(pg_addr, 1); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -15820,6 +17030,7 @@ out: * @hrq: The queue structure to use to create the header receive queue. * @drq: The queue structure to use to create the data receive queue. * @cq: The completion queue to bind this work queue to. + * @subtype: The subtype of the work queue indicating its functionality. * * This function creates a receive buffer queue pair , as detailed in @hrq and * @drq, on a port, described by @phba by sending a RQ_CREATE mailbox command @@ -15886,14 +17097,14 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, } else { switch (hrq->entry_count) { default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2535 Unsupported RQ count. (%d)\n", hrq->entry_count); if (hrq->entry_count < 512) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + fallthrough; /* otherwise default to smallest count */ case 512: bf_set(lpfc_rq_context_rqe_count, &rq_create->u.request.context, @@ -15937,7 +17148,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2504 RQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -15955,7 +17166,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, &rq_create->u.response); if ((hrq->db_format != LPFC_DB_LIST_FORMAT) && (hrq->db_format != LPFC_DB_RING_FORMAT)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3262 RQ [%d] doorbell format not " "supported: x%x\n", hrq->queue_id, hrq->db_format); @@ -15967,7 +17178,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, &rq_create->u.response); bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset); if (!bar_memmap_p) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3269 RQ[%d] failed to memmap pci " "barset:x%x\n", hrq->queue_id, pci_barset); @@ -15978,7 +17189,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, db_offset = rq_create->u.response.doorbell_offset; if ((db_offset != LPFC_ULP0_RQ_DOORBELL) && (db_offset != LPFC_ULP1_RQ_DOORBELL)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3270 RQ[%d] doorbell offset not " "supported: x%x\n", hrq->queue_id, db_offset); @@ -16023,14 +17234,14 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, } else { switch (drq->entry_count) { default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2536 Unsupported RQ count. (%d)\n", drq->entry_count); if (drq->entry_count < 512) { status = -EINVAL; goto out; } - /* fall through - otherwise default to smallest count */ + fallthrough; /* otherwise default to smallest count */ case 512: bf_set(lpfc_rq_context_rqe_count, &rq_create->u.request.context, @@ -16109,6 +17320,7 @@ out: * @hrqp: The queue structure array to use to create the header receive queues. * @drqp: The queue structure array to use to create the data receive queues. * @cqp: The completion queue array to bind these receive queues to. + * @subtype: Functional purpose of the queue (MBOX, IO, ELS, NVMET, etc). * * This function creates a receive buffer queue pair , as detailed in @hrq and * @drq, on a port, described by @phba by sending a RQ_CREATE mailbox command @@ -16160,7 +17372,7 @@ lpfc_mrq_create(struct lpfc_hba *phba, struct lpfc_queue **hrqp, LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, length, LPFC_SLI4_MBX_NEMBED); if (alloclen < length) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3099 Allocated DMA memory size (%d) is " "less than the requested DMA memory size " "(%d)\n", alloclen, length); @@ -16270,7 +17482,7 @@ lpfc_mrq_create(struct lpfc_hba *phba, struct lpfc_queue **hrqp, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3120 RQ_CREATE mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16298,6 +17510,7 @@ out: /** * lpfc_eq_destroy - Destroy an event Queue on the HBA + * @phba: HBA structure that indicates port to destroy a queue on. * @eq: The queue structure associated with the queue to destroy. * * This function destroys a queue, as detailed in @eq by sending an mailbox @@ -16340,7 +17553,7 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2505 EQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16355,6 +17568,7 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) /** * lpfc_cq_destroy - Destroy a Completion Queue on the HBA + * @phba: HBA structure that indicates port to destroy a queue on. * @cq: The queue structure associated with the queue to destroy. * * This function destroys a queue, as detailed in @cq by sending an mailbox @@ -16395,7 +17609,7 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2506 CQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16409,7 +17623,8 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) /** * lpfc_mq_destroy - Destroy a Mailbox Queue on the HBA - * @qm: The queue structure associated with the queue to destroy. + * @phba: HBA structure that indicates port to destroy a queue on. + * @mq: The queue structure associated with the queue to destroy. * * This function destroys a queue, as detailed in @mq by sending an mailbox * command, specific to the type of queue, to the HBA. @@ -16449,7 +17664,7 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2507 MQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16463,6 +17678,7 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) /** * lpfc_wq_destroy - Destroy a Work Queue on the HBA + * @phba: HBA structure that indicates port to destroy a queue on. * @wq: The queue structure associated with the queue to destroy. * * This function destroys a queue, as detailed in @wq by sending an mailbox @@ -16502,7 +17718,7 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2508 WQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16518,7 +17734,9 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) /** * lpfc_rq_destroy - Destroy a Receive Queue on the HBA - * @rq: The queue structure associated with the queue to destroy. + * @phba: HBA structure that indicates port to destroy a queue on. + * @hrq: The queue structure associated with the queue to destroy. + * @drq: The queue structure associated with the queue to destroy. * * This function destroys a queue, as detailed in @rq by sending an mailbox * command, specific to the type of queue, to the HBA. @@ -16559,12 +17777,11 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2509 RQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, hrq->phba->mbox_mem_pool); + mempool_free(mbox, hrq->phba->mbox_mem_pool); return -ENXIO; } bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request, @@ -16575,7 +17792,7 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2510 RQ_DESTROY mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16623,7 +17840,7 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba, union lpfc_sli4_cfg_shdr *shdr; if (xritag == NO_XRI) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0364 Invalid param:\n"); return -EINVAL; } @@ -16661,10 +17878,12 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba, shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) + if (!phba->sli4_hba.intr_enable) + mempool_free(mbox, phba->mbox_mem_pool); + else if (rc != MBX_TIMEOUT) mempool_free(mbox, phba->mbox_mem_pool); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2511 POST_SGL mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16695,8 +17914,8 @@ lpfc_sli4_alloc_xri(struct lpfc_hba *phba) * the driver starts at 0 each time. */ spin_lock_irq(&phba->hbalock); - xri = find_next_zero_bit(phba->sli4_hba.xri_bmask, - phba->sli4_hba.max_cfg_param.max_xri, 0); + xri = find_first_zero_bit(phba->sli4_hba.xri_bmask, + phba->sli4_hba.max_cfg_param.max_xri); if (xri >= phba->sli4_hba.max_cfg_param.max_xri) { spin_unlock_irq(&phba->hbalock); return NO_XRI; @@ -16709,8 +17928,9 @@ lpfc_sli4_alloc_xri(struct lpfc_hba *phba) } /** - * lpfc_sli4_free_xri - Release an xri for reuse. + * __lpfc_sli4_free_xri - Release an xri for reuse. * @phba: pointer to lpfc hba data structure. + * @xri: xri to release. * * This routine is invoked to release an xri to the pool of * available rpis maintained by the driver. @@ -16726,6 +17946,7 @@ __lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri) /** * lpfc_sli4_free_xri - Release an xri for reuse. * @phba: pointer to lpfc hba data structure. + * @xri: xri to release. * * This routine is invoked to release an xri to the pool of * available rpis maintained by the driver. @@ -16768,7 +17989,7 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba) * lpfc_sli4_post_sgl_list - post a block of ELS sgls to the port. * @phba: pointer to lpfc hba data structure. * @post_sgl_list: pointer to els sgl entry list. - * @count: number of els sgl entries on the list. + * @post_cnt: number of els sgl entries on the list. * * This routine is invoked to post a block of driver's sgl pages to the * HBA using non-embedded mailbox command. No Lock is held. This routine @@ -16795,7 +18016,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba, reqlen = post_cnt * sizeof(struct sgl_page_pairs) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2559 Block sgl registration required DMA " "size (%d) great than a page\n", reqlen); return -ENOMEM; @@ -16811,7 +18032,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba, LPFC_SLI4_MBX_NEMBED); if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0285 Allocated DMA memory size (%d) is " "less than the requested DMA memory " "size (%d)\n", alloclen, reqlen); @@ -16856,10 +18077,12 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba, shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) + if (!phba->sli4_hba.intr_enable) + lpfc_sli4_mbox_cmd_free(phba, mbox); + else if (rc != MBX_TIMEOUT) lpfc_sli4_mbox_cmd_free(phba, mbox); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2513 POST_SGL_BLOCK mailbox command failed " "status x%x add_status x%x mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16907,7 +18130,7 @@ lpfc_sli4_post_io_sgl_block(struct lpfc_hba *phba, struct list_head *nblist, } mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6119 Failed to allocate mbox cmd memory\n"); return -ENOMEM; } @@ -16918,7 +18141,7 @@ lpfc_sli4_post_io_sgl_block(struct lpfc_hba *phba, struct list_head *nblist, reqlen, LPFC_SLI4_MBX_NEMBED); if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6120 Allocated DMA memory size (%d) is " "less than the requested DMA memory " "size (%d)\n", alloclen, reqlen); @@ -16969,10 +18192,12 @@ lpfc_sli4_post_io_sgl_block(struct lpfc_hba *phba, struct list_head *nblist, shdr = (union lpfc_sli4_cfg_shdr *)&sgl->cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) + if (!phba->sli4_hba.intr_enable) + lpfc_sli4_mbox_cmd_free(phba, mbox); + else if (rc != MBX_TIMEOUT) lpfc_sli4_mbox_cmd_free(phba, mbox); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6125 POST_SGL_BLOCK mailbox command failed " "status x%x add_status x%x mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -16985,6 +18210,7 @@ lpfc_sli4_post_io_sgl_block(struct lpfc_hba *phba, struct list_head *nblist, * lpfc_sli4_post_io_sgl_list - Post blocks of nvme buffer sgls from a list * @phba: pointer to lpfc hba data structure. * @post_nblist: pointer to the nvme buffer list. + * @sb_count: number of nvme buffers. * * This routine walks a list of nvme buffers that was passed in. It attempts * to construct blocks of nvme buffer sgls which contains contiguous xris and @@ -17141,7 +18367,6 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) case FC_RCTL_ELS_REP: /* extended link services reply */ case FC_RCTL_ELS4_REQ: /* FC-4 ELS request */ case FC_RCTL_ELS4_REP: /* FC-4 ELS reply */ - case FC_RCTL_BA_NOP: /* basic link service NOP */ case FC_RCTL_BA_ABTS: /* basic link service abort */ case FC_RCTL_BA_RMC: /* remove connection */ case FC_RCTL_BA_ACC: /* basic accept */ @@ -17162,6 +18387,7 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) fc_vft_hdr = (struct fc_vft_header *)fc_hdr; fc_hdr = &((struct fc_frame_header *)fc_vft_hdr)[1]; return lpfc_fc_frame_check(phba, fc_hdr); + case FC_RCTL_BA_NOP: /* basic link service NOP */ default: goto drop; } @@ -17218,6 +18444,7 @@ lpfc_fc_hdr_get_vfi(struct fc_frame_header *fc_hdr) * @phba: Pointer to the HBA structure to search for the vport on * @fc_hdr: A pointer to the FC Header data (In Big Endian Format) * @fcfi: The FC Fabric ID that the frame came from + * @did: Destination ID to match against * * This function searches the @phba for a vport that matches the content of the * @fc_hdr passed in and the @fcfi. This function uses the @fc_hdr to fetch the @@ -17355,6 +18582,7 @@ lpfc_rcv_seq_check_edtov(struct lpfc_vport *vport) /** * lpfc_fc_frame_add - Adds a frame to the vport's list of received sequences + * @vport: pointer to a vitural port * @dmabuf: pointer to a dmabuf that describes the hdr and data of the FC frame * * This function searches through the existing incomplete sequences that have @@ -17414,7 +18642,6 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) seq_dmabuf->time_stamp = jiffies; lpfc_update_rcv_time_stamp(vport); if (list_empty(&seq_dmabuf->dbuf.list)) { - temp_hdr = dmabuf->hbuf.virt; list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list); return seq_dmabuf; } @@ -17545,21 +18772,17 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmd_iocbq, struct lpfc_iocbq *rsp_iocbq) { - struct lpfc_nodelist *ndlp; - if (cmd_iocbq) { - ndlp = (struct lpfc_nodelist *)cmd_iocbq->context1; - lpfc_nlp_put(ndlp); - lpfc_nlp_not_used(ndlp); + lpfc_nlp_put(cmd_iocbq->ndlp); lpfc_sli_release_iocbq(phba, cmd_iocbq); } /* Failure means BLS ABORT RSP did not get delivered to remote node*/ if (rsp_iocbq && rsp_iocbq->iocb.ulpStatus) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3154 BLS ABORT RSP failed, data: x%x/x%x\n", - rsp_iocbq->iocb.ulpStatus, - rsp_iocbq->iocb.un.ulpWord[4]); + get_job_ulpstatus(phba, rsp_iocbq), + get_job_word4(phba, rsp_iocbq)); } /** @@ -17585,8 +18808,9 @@ lpfc_sli4_xri_inrange(struct lpfc_hba *phba, /** * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort - * @phba: Pointer to HBA context object. + * @vport: pointer to a virtual port. * @fc_hdr: pointer to a FC frame header. + * @aborted: was the partially assembled receive sequence successfully aborted * * This function sends a basic response to a previous unsol sequence abort * event after aborting the sequence handling. @@ -17600,7 +18824,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp; uint16_t oxid, rxid, xri, lxri; uint32_t sid, fctl; - IOCB_t *icmd; + union lpfc_wqe128 *icmd; int rc; if (!lpfc_is_link_up(phba)) @@ -17621,15 +18845,6 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, } /* Put ndlp onto pport node list */ lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, - "3275 Failed to active ndlp found " - "for oxid:x%x SID:x%x\n", oxid, sid); - return; - } } /* Allocate buffer for rsp iocb */ @@ -17637,28 +18852,22 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, if (!ctiocb) return; + icmd = &ctiocb->wqe; + /* Extract the F_CTL field from FC_HDR */ fctl = sli4_fctl_from_fc_hdr(fc_hdr); - icmd = &ctiocb->iocb; - icmd->un.xseq64.bdl.bdeSize = 0; - icmd->un.xseq64.bdl.ulpIoTag32 = 0; - icmd->un.xseq64.w5.hcsw.Dfctl = 0; - icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_ACC; - icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_BLS; - - /* Fill in the rest of iocb fields */ - icmd->ulpCommand = CMD_XMIT_BLS_RSP64_CX; - icmd->ulpBdeCount = 0; - icmd->ulpLe = 1; - icmd->ulpClass = CLASS3; - icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - ctiocb->context1 = lpfc_nlp_get(ndlp); + ctiocb->ndlp = lpfc_nlp_get(ndlp); + if (!ctiocb->ndlp) { + lpfc_sli_release_iocbq(phba, ctiocb); + return; + } ctiocb->vport = phba->pport; - ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; + ctiocb->cmd_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; ctiocb->sli4_lxritag = NO_XRI; ctiocb->sli4_xritag = NO_XRI; + ctiocb->abort_rctl = FC_RCTL_BA_ACC; if (fctl & FC_FC_EX_CTX) /* Exchange responder sent the abort so we @@ -17678,10 +18887,12 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, */ if ((fctl & FC_FC_EX_CTX) && (lxri > lpfc_sli4_get_iocb_cnt(phba))) { - icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT; - bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0); - bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID); - bf_set(lpfc_rsn_code, &icmd->un.bls_rsp, FC_BA_RJT_UNABLE); + ctiocb->abort_rctl = FC_RCTL_BA_RJT; + bf_set(xmit_bls_rsp64_rjt_vspec, &icmd->xmit_bls_rsp, 0); + bf_set(xmit_bls_rsp64_rjt_expc, &icmd->xmit_bls_rsp, + FC_BA_RJT_INV_XID); + bf_set(xmit_bls_rsp64_rjt_rsnc, &icmd->xmit_bls_rsp, + FC_BA_RJT_UNABLE); } /* If BA_ABTS failed to abort a partially assembled receive sequence, @@ -17689,10 +18900,12 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, * the IOCB for a BA_RJT. */ if (aborted == false) { - icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT; - bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0); - bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID); - bf_set(lpfc_rsn_code, &icmd->un.bls_rsp, FC_BA_RJT_UNABLE); + ctiocb->abort_rctl = FC_RCTL_BA_RJT; + bf_set(xmit_bls_rsp64_rjt_vspec, &icmd->xmit_bls_rsp, 0); + bf_set(xmit_bls_rsp64_rjt_expc, &icmd->xmit_bls_rsp, + FC_BA_RJT_INV_XID); + bf_set(xmit_bls_rsp64_rjt_rsnc, &icmd->xmit_bls_rsp, + FC_BA_RJT_UNABLE); } if (fctl & FC_FC_EX_CTX) { @@ -17700,31 +18913,41 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, * of BA_ACC will use OX_ID from ABTS for the XRI_TAG * field and RX_ID from ABTS for RX_ID field. */ - bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_RSP); + ctiocb->abort_bls = LPFC_ABTS_UNSOL_RSP; + bf_set(xmit_bls_rsp64_rxid, &icmd->xmit_bls_rsp, rxid); } else { /* ABTS sent by initiator to CT exchange, construction * of BA_ACC will need to allocate a new XRI as for the * XRI_TAG field. */ - bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_INT); + ctiocb->abort_bls = LPFC_ABTS_UNSOL_INT; } - bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid); - bf_set(lpfc_abts_oxid, &icmd->un.bls_rsp, oxid); + + /* OX_ID is invariable to who sent ABTS to CT exchange */ + bf_set(xmit_bls_rsp64_oxid, &icmd->xmit_bls_rsp, oxid); + bf_set(xmit_bls_rsp64_oxid, &icmd->xmit_bls_rsp, rxid); + + /* Use CT=VPI */ + bf_set(wqe_els_did, &icmd->xmit_bls_rsp.wqe_dest, + ndlp->nlp_DID); + bf_set(xmit_bls_rsp64_temprpi, &icmd->xmit_bls_rsp, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); + bf_set(wqe_cmnd, &icmd->generic.wqe_com, CMD_XMIT_BLS_RSP64_CX); /* Xmit CT abts response on exchange <xid> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "1200 Send BLS cmd x%x on oxid x%x Data: x%x\n", - icmd->un.xseq64.w5.hcsw.Rctl, oxid, phba->link_state); + ctiocb->abort_rctl, oxid, phba->link_state); rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); if (rc == IOCB_ERROR) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2925 Failed to issue CT ABTS RSP x%x on " "xri x%x, Data x%x\n", - icmd->un.xseq64.w5.hcsw.Rctl, oxid, + ctiocb->abort_rctl, oxid, phba->link_state); lpfc_nlp_put(ndlp); - ctiocb->context1 = NULL; + ctiocb->ndlp = NULL; lpfc_sli_release_iocbq(phba, ctiocb); } } @@ -17738,7 +18961,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, * receive sequence is only partially assembed by the driver, it shall abort * the partially assembled frames for the sequence. Otherwise, if the * unsolicited receive sequence has been completely assembled and passed to - * the Upper Layer Protocol (UPL), it then mark the per oxid status for the + * the Upper Layer Protocol (ULP), it then mark the per oxid status for the * unsolicited sequence has been aborted. After that, it will issue a basic * accept to accept the abort. **/ @@ -17825,7 +19048,7 @@ lpfc_seq_complete(struct hbq_dmabuf *dmabuf) /** * lpfc_prep_seq - Prep sequence for ULP processing * @vport: Pointer to the vport on which this sequence was received - * @dmabuf: pointer to a dmabuf that describes the FC sequence + * @seq_dmabuf: pointer to a dmabuf that describes the FC sequence * * This function takes a sequence, described by a list of frames, and creates * a list of iocbq structures to describe the sequence. This iocbq list will be @@ -17844,7 +19067,6 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) struct fc_frame_header *fc_hdr; uint32_t sid; uint32_t len, tot_len; - struct ulp_bde64 *pbde; fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; /* remove from receive buffer list */ @@ -17857,40 +19079,40 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) first_iocbq = lpfc_sli_get_iocbq(vport->phba); if (first_iocbq) { /* Initialize the first IOCB. */ - first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0; - first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS; + first_iocbq->wcqe_cmpl.total_data_placed = 0; + bf_set(lpfc_wcqe_c_status, &first_iocbq->wcqe_cmpl, + IOSTAT_SUCCESS); first_iocbq->vport = vport; /* Check FC Header to see what TYPE of frame we are rcv'ing */ if (sli4_type_from_fc_hdr(fc_hdr) == FC_TYPE_ELS) { - first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_ELS64_CX; - first_iocbq->iocb.un.rcvels.parmRo = - sli4_did_from_fc_hdr(fc_hdr); - first_iocbq->iocb.ulpPU = PARM_NPIV_DID; - } else - first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; - first_iocbq->iocb.ulpContext = NO_XRI; - first_iocbq->iocb.unsli3.rcvsli3.ox_id = - be16_to_cpu(fc_hdr->fh_ox_id); - /* iocbq is prepped for internal consumption. Physical vpi. */ - first_iocbq->iocb.unsli3.rcvsli3.vpi = - vport->phba->vpi_ids[vport->vpi]; - /* put the first buffer into the first IOCBq */ + bf_set(els_rsp64_sid, &first_iocbq->wqe.xmit_els_rsp, + sli4_did_from_fc_hdr(fc_hdr)); + } + + bf_set(wqe_ctxt_tag, &first_iocbq->wqe.xmit_els_rsp.wqe_com, + NO_XRI); + bf_set(wqe_rcvoxid, &first_iocbq->wqe.xmit_els_rsp.wqe_com, + be16_to_cpu(fc_hdr->fh_ox_id)); + + /* put the first buffer into the first iocb */ tot_len = bf_get(lpfc_rcqe_length, - &seq_dmabuf->cq_event.cqe.rcqe_cmpl); + &seq_dmabuf->cq_event.cqe.rcqe_cmpl); + + first_iocbq->cmd_dmabuf = &seq_dmabuf->dbuf; + first_iocbq->bpl_dmabuf = NULL; + /* Keep track of the BDE count */ + first_iocbq->wcqe_cmpl.word3 = 1; - first_iocbq->context2 = &seq_dmabuf->dbuf; - first_iocbq->context3 = NULL; - first_iocbq->iocb.ulpBdeCount = 1; if (tot_len > LPFC_DATA_BUF_SIZE) - first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = - LPFC_DATA_BUF_SIZE; + first_iocbq->wqe.gen_req.bde.tus.f.bdeSize = + LPFC_DATA_BUF_SIZE; else - first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = tot_len; - - first_iocbq->iocb.un.rcvels.remoteID = sid; + first_iocbq->wqe.gen_req.bde.tus.f.bdeSize = tot_len; - first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len; + first_iocbq->wcqe_cmpl.total_data_placed = tot_len; + bf_set(wqe_els_did, &first_iocbq->wqe.xmit_els_rsp.wqe_dest, + sid); } iocbq = first_iocbq; /* @@ -17902,30 +19124,25 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) lpfc_in_buf_free(vport->phba, d_buf); continue; } - if (!iocbq->context3) { - iocbq->context3 = d_buf; - iocbq->iocb.ulpBdeCount++; + if (!iocbq->bpl_dmabuf) { + iocbq->bpl_dmabuf = d_buf; + iocbq->wcqe_cmpl.word3++; /* We need to get the size out of the right CQE */ hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); len = bf_get(lpfc_rcqe_length, &hbq_buf->cq_event.cqe.rcqe_cmpl); - pbde = (struct ulp_bde64 *) - &iocbq->iocb.unsli3.sli3Words[4]; - if (len > LPFC_DATA_BUF_SIZE) - pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE; - else - pbde->tus.f.bdeSize = len; - - iocbq->iocb.unsli3.rcvsli3.acc_len += len; + iocbq->unsol_rcv_len = len; + iocbq->wcqe_cmpl.total_data_placed += len; tot_len += len; } else { iocbq = lpfc_sli_get_iocbq(vport->phba); if (!iocbq) { if (first_iocbq) { - first_iocbq->iocb.ulpStatus = - IOSTAT_FCP_RSP_ERROR; - first_iocbq->iocb.un.ulpWord[4] = - IOERR_NO_RESOURCES; + bf_set(lpfc_wcqe_c_status, + &first_iocbq->wcqe_cmpl, + IOSTAT_SUCCESS); + first_iocbq->wcqe_cmpl.parameter = + IOERR_NO_RESOURCES; } lpfc_in_buf_free(vport->phba, d_buf); continue; @@ -17934,22 +19151,28 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); len = bf_get(lpfc_rcqe_length, &hbq_buf->cq_event.cqe.rcqe_cmpl); - iocbq->context2 = d_buf; - iocbq->context3 = NULL; - iocbq->iocb.ulpBdeCount = 1; + iocbq->cmd_dmabuf = d_buf; + iocbq->bpl_dmabuf = NULL; + iocbq->wcqe_cmpl.word3 = 1; + if (len > LPFC_DATA_BUF_SIZE) - iocbq->iocb.un.cont64[0].tus.f.bdeSize = - LPFC_DATA_BUF_SIZE; + iocbq->wqe.xmit_els_rsp.bde.tus.f.bdeSize = + LPFC_DATA_BUF_SIZE; else - iocbq->iocb.un.cont64[0].tus.f.bdeSize = len; + iocbq->wqe.xmit_els_rsp.bde.tus.f.bdeSize = + len; tot_len += len; - iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len; - - iocbq->iocb.un.rcvels.remoteID = sid; + iocbq->wcqe_cmpl.total_data_placed = tot_len; + bf_set(wqe_els_did, &iocbq->wqe.xmit_els_rsp.wqe_dest, + sid); list_add_tail(&iocbq->list, &first_iocbq->list); } } + /* Free the sequence's header buffer */ + if (!first_iocbq) + lpfc_in_buf_free(vport->phba, &seq_dmabuf->dbuf); + return first_iocbq; } @@ -17964,7 +19187,7 @@ lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport, fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; iocbq = lpfc_prep_seq(vport, seq_dmabuf); if (!iocbq) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2707 Ring %d handler: Failed to allocate " "iocb Rctl x%x Type x%x received\n", LPFC_ELS_RING, @@ -17974,16 +19197,18 @@ lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport, if (!lpfc_complete_unsol_iocb(phba, phba->sli4_hba.els_wq->pring, iocbq, fc_hdr->fh_r_ctl, - fc_hdr->fh_type)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + fc_hdr->fh_type)) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2540 Ring %d handler: unexpected Rctl " "x%x Type x%x received\n", LPFC_ELS_RING, fc_hdr->fh_r_ctl, fc_hdr->fh_type); + lpfc_in_buf_free(phba, &seq_dmabuf->dbuf); + } /* Free iocb created in lpfc_prep_seq */ list_for_each_entry_safe(curr_iocb, next_iocb, - &iocbq->list, list) { + &iocbq->list, list) { list_del_init(&curr_iocb->list); lpfc_sli_release_iocbq(phba, curr_iocb); } @@ -17994,7 +19219,7 @@ static void lpfc_sli4_mds_loopback_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - struct lpfc_dmabuf *pcmd = cmdiocb->context2; + struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf; if (pcmd && pcmd->virt) dma_pool_free(phba->lpfc_drb_pool, pcmd->virt, pcmd->phys); @@ -18010,7 +19235,7 @@ lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport, struct fc_frame_header *fc_hdr; struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *iocbq = NULL; - union lpfc_wqe *wqe; + union lpfc_wqe128 *pwqe; struct lpfc_dmabuf *pcmd = NULL; uint32_t frame_len; int rc; @@ -18045,34 +19270,46 @@ lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport, /* copyin the payload */ memcpy(pcmd->virt, dmabuf->dbuf.virt, frame_len); - /* fill in BDE's for command */ - iocbq->iocb.un.xseq64.bdl.addrHigh = putPaddrHigh(pcmd->phys); - iocbq->iocb.un.xseq64.bdl.addrLow = putPaddrLow(pcmd->phys); - iocbq->iocb.un.xseq64.bdl.bdeFlags = BUFF_TYPE_BDE_64; - iocbq->iocb.un.xseq64.bdl.bdeSize = frame_len; - - iocbq->context2 = pcmd; + iocbq->cmd_dmabuf = pcmd; iocbq->vport = vport; - iocbq->iocb_flag &= ~LPFC_FIP_ELS_ID_MASK; - iocbq->iocb_flag |= LPFC_USE_FCPWQIDX; + iocbq->cmd_flag &= ~LPFC_FIP_ELS_ID_MASK; + iocbq->cmd_flag |= LPFC_USE_FCPWQIDX; + iocbq->num_bdes = 0; + + pwqe = &iocbq->wqe; + /* fill in BDE's for command */ + pwqe->gen_req.bde.addrHigh = putPaddrHigh(pcmd->phys); + pwqe->gen_req.bde.addrLow = putPaddrLow(pcmd->phys); + pwqe->gen_req.bde.tus.f.bdeSize = frame_len; + pwqe->gen_req.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; + + pwqe->send_frame.frame_len = frame_len; + pwqe->send_frame.fc_hdr_wd0 = be32_to_cpu(*((__be32 *)fc_hdr)); + pwqe->send_frame.fc_hdr_wd1 = be32_to_cpu(*((__be32 *)fc_hdr + 1)); + pwqe->send_frame.fc_hdr_wd2 = be32_to_cpu(*((__be32 *)fc_hdr + 2)); + pwqe->send_frame.fc_hdr_wd3 = be32_to_cpu(*((__be32 *)fc_hdr + 3)); + pwqe->send_frame.fc_hdr_wd4 = be32_to_cpu(*((__be32 *)fc_hdr + 4)); + pwqe->send_frame.fc_hdr_wd5 = be32_to_cpu(*((__be32 *)fc_hdr + 5)); + + pwqe->generic.wqe_com.word7 = 0; + pwqe->generic.wqe_com.word10 = 0; + + bf_set(wqe_cmnd, &pwqe->generic.wqe_com, CMD_SEND_FRAME); + bf_set(wqe_sof, &pwqe->generic.wqe_com, 0x2E); /* SOF byte */ + bf_set(wqe_eof, &pwqe->generic.wqe_com, 0x41); /* EOF byte */ + bf_set(wqe_lenloc, &pwqe->generic.wqe_com, 1); + bf_set(wqe_xbl, &pwqe->generic.wqe_com, 1); + bf_set(wqe_dbde, &pwqe->generic.wqe_com, 1); + bf_set(wqe_xc, &pwqe->generic.wqe_com, 1); + bf_set(wqe_cmd_type, &pwqe->generic.wqe_com, 0xA); + bf_set(wqe_cqid, &pwqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_xri_tag, &pwqe->generic.wqe_com, iocbq->sli4_xritag); + bf_set(wqe_reqtag, &pwqe->generic.wqe_com, iocbq->iotag); + bf_set(wqe_class, &pwqe->generic.wqe_com, CLASS3); + pwqe->generic.wqe_com.abort_tag = iocbq->iotag; + + iocbq->cmd_cmpl = lpfc_sli4_mds_loopback_cmpl; - /* - * Setup rest of the iocb as though it were a WQE - * Build the SEND_FRAME WQE - */ - wqe = (union lpfc_wqe *)&iocbq->iocb; - - wqe->send_frame.frame_len = frame_len; - wqe->send_frame.fc_hdr_wd0 = be32_to_cpu(*((uint32_t *)fc_hdr)); - wqe->send_frame.fc_hdr_wd1 = be32_to_cpu(*((uint32_t *)fc_hdr + 1)); - wqe->send_frame.fc_hdr_wd2 = be32_to_cpu(*((uint32_t *)fc_hdr + 2)); - wqe->send_frame.fc_hdr_wd3 = be32_to_cpu(*((uint32_t *)fc_hdr + 3)); - wqe->send_frame.fc_hdr_wd4 = be32_to_cpu(*((uint32_t *)fc_hdr + 4)); - wqe->send_frame.fc_hdr_wd5 = be32_to_cpu(*((uint32_t *)fc_hdr + 5)); - - iocbq->iocb.ulpCommand = CMD_SEND_FRAME; - iocbq->iocb.ulpLe = 1; - iocbq->iocb_cmpl = lpfc_sli4_mds_loopback_cmpl; rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocbq, 0); if (rc == IOCB_ERROR) goto exit; @@ -18094,6 +19331,7 @@ exit: /** * lpfc_sli4_handle_received_buffer - Handle received buffers from firmware * @phba: Pointer to HBA context object. + * @dmabuf: Pointer to a dmabuf that describes the FC sequence. * * This function is called with no lock held. This function processes all * the received buffers and gives it to upper layers when a received buffer @@ -18119,7 +19357,10 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, fc_hdr->fh_r_ctl == FC_RCTL_DD_UNSOL_DATA) { vport = phba->pport; /* Handle MDS Loopback frames */ - lpfc_sli4_handle_mds_loopback(vport, dmabuf); + if (!(phba->pport->load_flag & FC_UNLOADING)) + lpfc_sli4_handle_mds_loopback(vport, dmabuf); + else + lpfc_in_buf_free(phba, &dmabuf->dbuf); return; } @@ -18240,7 +19481,7 @@ lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba) rc = lpfc_sli4_post_rpi_hdr(phba, rpi_page); if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2008 Error %d posting all rpi " "headers\n", rc); rc = -EIO; @@ -18286,7 +19527,7 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) /* The port is notified of the header region via a mailbox command. */ mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2001 Unable to allocate memory for issuing " "SLI_CONFIG_SPECIAL mailbox command\n"); return -ENOMEM; @@ -18313,10 +19554,9 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) shdr = (union lpfc_sli4_cfg_shdr *) &hdr_tmpl->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); + mempool_free(mboxq, phba->mbox_mem_pool); if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2514 POST_RPI_HDR mailbox failed with " "status x%x add_status x%x, mbx status x%x\n", shdr_status, shdr_add_status, rc); @@ -18363,7 +19603,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) max_rpi = phba->sli4_hba.max_cfg_param.max_rpi; rpi_limit = phba->sli4_hba.next_rpi; - rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, 0); + rpi = find_first_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit); if (rpi >= rpi_limit) rpi = LPFC_RPI_ALLOC_ERROR; else { @@ -18406,7 +19646,7 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) { rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); if (!rpi_hdr) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2002 Error Could not grow rpi " "count\n"); } else { @@ -18420,8 +19660,9 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) } /** - * lpfc_sli4_free_rpi - Release an rpi for reuse. + * __lpfc_sli4_free_rpi - Release an rpi for reuse. * @phba: pointer to lpfc hba data structure. + * @rpi: rpi to free * * This routine is invoked to release an rpi to the pool of * available rpis maintained by the driver. @@ -18450,6 +19691,7 @@ __lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) /** * lpfc_sli4_free_rpi - Release an rpi for reuse. * @phba: pointer to lpfc hba data structure. + * @rpi: rpi to free * * This routine is invoked to release an rpi to the pool of * available rpis maintained by the driver. @@ -18479,7 +19721,9 @@ lpfc_sli4_remove_rpis(struct lpfc_hba *phba) /** * lpfc_sli4_resume_rpi - Remove the rpi bitmask region - * @phba: pointer to lpfc hba data structure. + * @ndlp: pointer to lpfc nodelist data structure. + * @cmpl: completion call-back. + * @arg: data to load as MBox 'caller buffer information' * * This routine is invoked to remove the memory region that * provided rpi via a bitmask. @@ -18497,21 +19741,36 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, if (!mboxq) return -ENOMEM; + /* If cmpl assigned, then this nlp_get pairs with + * lpfc_mbx_cmpl_resume_rpi. + * + * Else cmpl is NULL, then this nlp_get pairs with + * lpfc_sli_def_mbox_cmpl. + */ + if (!lpfc_nlp_get(ndlp)) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2122 %s: Failed to get nlp ref\n", + __func__); + mempool_free(mboxq, phba->mbox_mem_pool); + return -EIO; + } + /* Post all rpi memory regions to the port. */ lpfc_resume_rpi(mboxq, ndlp); if (cmpl) { mboxq->mbox_cmpl = cmpl; mboxq->ctx_buf = arg; - mboxq->ctx_ndlp = ndlp; } else mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mboxq->ctx_ndlp = ndlp; mboxq->vport = ndlp->vport; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2010 Resume RPI Mailbox failed " "status %d, mbxStatus x%x\n", rc, bf_get(lpfc_mqe_status, &mboxq->u.mqe)); + lpfc_nlp_put(ndlp); mempool_free(mboxq, phba->mbox_mem_pool); return -EIO; } @@ -18543,7 +19802,7 @@ lpfc_sli4_init_vpi(struct lpfc_vport *vport) mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); if (rc != MBX_SUCCESS) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2022 INIT VPI Mailbox failed " "status %d, mbxStatus x%x\n", rc, bf_get(lpfc_mqe_status, &mboxq->u.mqe)); @@ -18579,7 +19838,7 @@ lpfc_mbx_cmpl_add_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) if ((shdr_status || shdr_add_status) && (shdr_status != STATUS_FCF_IN_USE)) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2558 ADD_FCF_RECORD mailbox failed with " "status x%x add_status x%x\n", shdr_status, shdr_add_status); @@ -18609,7 +19868,7 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2009 Failed to allocate mbox for ADD_FCF cmd\n"); return -ENOMEM; } @@ -18622,7 +19881,7 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) LPFC_MBOX_OPCODE_FCOE_ADD_FCF, req_len, LPFC_SLI4_MBX_NEMBED); if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2523 Allocated DMA memory size (x%x) is " "less than the requested DMA memory " "size (x%x)\n", alloc_len, req_len); @@ -18655,7 +19914,7 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) mboxq->mbox_cmpl = lpfc_mbx_cmpl_add_fcf_record; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2515 ADD_FCF_RECORD mailbox failed with " "status 0x%x\n", rc); lpfc_sli4_mbox_cmd_free(phba, mboxq); @@ -18728,7 +19987,7 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) phba->fcoe_cvl_eventtag_attn = phba->fcoe_cvl_eventtag; mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2000 Failed to allocate mbox for " "READ_FCF cmd\n"); error = -ENOMEM; @@ -18863,7 +20122,7 @@ fail_fcf_read: /** * lpfc_check_next_fcf_pri_level - * phba pointer to the lpfc_hba struct for this port. + * @phba: pointer to the lpfc_hba struct for this port. * This routine is called from the lpfc_sli4_fcf_rr_next_index_get * routine when the rr_bmask is empty. The FCF indecies are put into the * rr_bmask based on their priority level. Starting from the highest priority @@ -18987,8 +20246,8 @@ next_priority: * have been tested so that we can detect when we should * change the priority level. */ - next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX, 0); + next_fcf_index = find_first_bit(phba->fcf.fcf_rr_bmask, + LPFC_SLI4_FCF_TBL_INDX_MAX); } @@ -19028,6 +20287,7 @@ next_priority: /** * lpfc_sli4_fcf_rr_index_set - Set bmask with eligible fcf record index * @phba: pointer to lpfc hba data structure. + * @fcf_index: index into the FCF table to 'set' * * This routine sets the FCF record index in to the eligible bmask for * roundrobin failover search. It checks to make sure that the index @@ -19060,6 +20320,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index) /** * lpfc_sli4_fcf_rr_index_clear - Clear bmask from eligible fcf record index * @phba: pointer to lpfc hba data structure. + * @fcf_index: index into the FCF table to 'clear' * * This routine clears the FCF record index from the eligible bmask for * roundrobin failover search. It checks to make sure that the index @@ -19097,6 +20358,7 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index) /** * lpfc_mbx_cmpl_redisc_fcf_table - completion routine for rediscover FCF table * @phba: pointer to lpfc hba data structure. + * @mbox: An allocated pointer to type LPFC_MBOXQ_t * * This routine is the completion routine for the rediscover FCF table mailbox * command. If the mailbox command returned failure, it will try to stop the @@ -19171,7 +20433,7 @@ lpfc_sli4_redisc_fcf_table(struct lpfc_hba *phba) mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2745 Failed to allocate mbox for " "requesting FCF rediscover.\n"); return -ENOMEM; @@ -19246,7 +20508,7 @@ lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2600 failed to allocate mailbox memory\n"); return 0; } @@ -19269,6 +20531,7 @@ lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) */ if (mb->un.varDmp.word_cnt == 0) break; + if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset) mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset; @@ -19305,7 +20568,7 @@ lpfc_sli4_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3105 failed to allocate mailbox memory\n"); return 0; } @@ -19326,11 +20589,7 @@ lpfc_sli4_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) } lpfc_sli_pcimem_bcopy((char *)mp->virt, rgn23_data, data_length); out: - mempool_free(mboxq, phba->mbox_mem_pool); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } + lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED); return data_length; } @@ -19369,7 +20628,7 @@ lpfc_sli_read_link_ste(struct lpfc_hba *phba) /* Check the region signature first */ if (memcmp(&rgn23_data[offset], LPFC_REGION23_SIGNATURE, 4)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2619 Config region 23 has bad signature\n"); goto out; } @@ -19377,7 +20636,7 @@ lpfc_sli_read_link_ste(struct lpfc_hba *phba) /* Check the data structure version */ if (rgn23_data[offset] != LPFC_REGION23_VERSION) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2620 Config region 23 has bad version\n"); goto out; } @@ -19433,6 +20692,91 @@ out: } /** + * lpfc_log_fw_write_cmpl - logs firmware write completion status + * @phba: pointer to lpfc hba data structure + * @shdr_status: wr_object rsp's status field + * @shdr_add_status: wr_object rsp's add_status field + * @shdr_add_status_2: wr_object rsp's add_status_2 field + * @shdr_change_status: wr_object rsp's change_status field + * @shdr_csf: wr_object rsp's csf bit + * + * This routine is intended to be called after a firmware write completes. + * It will log next action items to be performed by the user to instantiate + * the newly downloaded firmware or reason for incompatibility. + **/ +static void +lpfc_log_fw_write_cmpl(struct lpfc_hba *phba, u32 shdr_status, + u32 shdr_add_status, u32 shdr_add_status_2, + u32 shdr_change_status, u32 shdr_csf) +{ + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "4198 %s: flash_id x%02x, asic_rev x%02x, " + "status x%02x, add_status x%02x, add_status_2 x%02x, " + "change_status x%02x, csf %01x\n", __func__, + phba->sli4_hba.flash_id, phba->sli4_hba.asic_rev, + shdr_status, shdr_add_status, shdr_add_status_2, + shdr_change_status, shdr_csf); + + if (shdr_add_status == LPFC_ADD_STATUS_INCOMPAT_OBJ) { + switch (shdr_add_status_2) { + case LPFC_ADD_STATUS_2_INCOMPAT_FLASH: + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "4199 Firmware write failed: " + "image incompatible with flash x%02x\n", + phba->sli4_hba.flash_id); + break; + case LPFC_ADD_STATUS_2_INCORRECT_ASIC: + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "4200 Firmware write failed: " + "image incompatible with ASIC " + "architecture x%02x\n", + phba->sli4_hba.asic_rev); + break; + default: + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, + "4210 Firmware write failed: " + "add_status_2 x%02x\n", + shdr_add_status_2); + break; + } + } else if (!shdr_status && !shdr_add_status) { + if (shdr_change_status == LPFC_CHANGE_STATUS_FW_RESET || + shdr_change_status == LPFC_CHANGE_STATUS_PORT_MIGRATION) { + if (shdr_csf) + shdr_change_status = + LPFC_CHANGE_STATUS_PCI_RESET; + } + + switch (shdr_change_status) { + case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET): + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "3198 Firmware write complete: System " + "reboot required to instantiate\n"); + break; + case (LPFC_CHANGE_STATUS_FW_RESET): + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "3199 Firmware write complete: " + "Firmware reset required to " + "instantiate\n"); + break; + case (LPFC_CHANGE_STATUS_PORT_MIGRATION): + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "3200 Firmware write complete: Port " + "Migration or PCI Reset required to " + "instantiate\n"); + break; + case (LPFC_CHANGE_STATUS_PCI_RESET): + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, + "3201 Firmware write complete: PCI " + "Reset required to instantiate\n"); + break; + default: + break; + } + } +} + +/** * lpfc_wr_object - write an object to the firmware * @phba: HBA structure that indicates port to create a queue on. * @dmabuf_list: list of dmabufs to write to the port. @@ -19458,7 +20802,8 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, struct lpfc_mbx_wr_object *wr_object; LPFC_MBOXQ_t *mbox; int rc = 0, i = 0; - uint32_t shdr_status, shdr_add_status, shdr_change_status, shdr_csf; + uint32_t shdr_status, shdr_add_status, shdr_add_status_2; + uint32_t shdr_change_status = 0, shdr_csf = 0; uint32_t mbox_tmo; struct lpfc_dmabuf *dmabuf; uint32_t written = 0; @@ -19512,56 +20857,36 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, &wr_object->header.cfg_shdr.response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &wr_object->header.cfg_shdr.response); + shdr_add_status_2 = bf_get(lpfc_mbox_hdr_add_status_2, + &wr_object->header.cfg_shdr.response); if (check_change_status) { shdr_change_status = bf_get(lpfc_wr_object_change_status, &wr_object->u.response); - - if (shdr_change_status == LPFC_CHANGE_STATUS_FW_RESET || - shdr_change_status == LPFC_CHANGE_STATUS_PORT_MIGRATION) { - shdr_csf = bf_get(lpfc_wr_object_csf, - &wr_object->u.response); - if (shdr_csf) - shdr_change_status = - LPFC_CHANGE_STATUS_PCI_RESET; - } - - switch (shdr_change_status) { - case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET): - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3198 Firmware write complete: System " - "reboot required to instantiate\n"); - break; - case (LPFC_CHANGE_STATUS_FW_RESET): - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3199 Firmware write complete: Firmware" - " reset required to instantiate\n"); - break; - case (LPFC_CHANGE_STATUS_PORT_MIGRATION): - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3200 Firmware write complete: Port " - "Migration or PCI Reset required to " - "instantiate\n"); - break; - case (LPFC_CHANGE_STATUS_PCI_RESET): - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3201 Firmware write complete: PCI " - "Reset required to instantiate\n"); - break; - default: - break; - } + shdr_csf = bf_get(lpfc_wr_object_csf, + &wr_object->u.response); } - if (rc != MBX_TIMEOUT) + + if (!phba->sli4_hba.intr_enable) mempool_free(mbox, phba->mbox_mem_pool); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + else if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || shdr_add_status_2 || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3025 Write Object mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); + "status x%x add_status x%x, add_status_2 x%x, " + "mbx status x%x\n", + shdr_status, shdr_add_status, shdr_add_status_2, + rc); rc = -ENXIO; *offset = shdr_add_status; - } else + } else { *offset += wr_object->u.response.actual_write_length; + } + + if (rc || check_change_status) + lpfc_log_fw_write_cmpl(phba, shdr_status, shdr_add_status, + shdr_add_status_2, shdr_change_status, + shdr_csf); return rc; } @@ -19579,10 +20904,8 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mb, *nextmb; - struct lpfc_dmabuf *mp; struct lpfc_nodelist *ndlp; struct lpfc_nodelist *act_mbx_ndlp = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); LIST_HEAD(mbox_cmd_list); uint8_t restart_loop; @@ -19596,8 +20919,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) (mb->u.mb.mbxCommand != MBX_REG_VPI)) continue; - list_del(&mb->list); - list_add_tail(&mb->list, &mbox_cmd_list); + list_move_tail(&mb->list, &mbox_cmd_list); } /* Clean up active mailbox command with the vport */ mb = phba->sli.mbox_active; @@ -19607,8 +20929,12 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { act_mbx_ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp; - /* Put reference count for delayed processing */ + + /* This reference is local to this routine. The + * reference is removed at routine exit. + */ act_mbx_ndlp = lpfc_nlp_get(act_mbx_ndlp); + /* Unregister the RPI when mailbox complete */ mb->mbox_flag |= LPFC_MBX_IMED_UNREG; } @@ -19636,9 +20962,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) mb->mbox_flag |= LPFC_MBX_IMED_UNREG; restart_loop = 1; spin_unlock_irq(&phba->hbalock); - spin_lock(shost->host_lock); + spin_lock(&ndlp->lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); + spin_unlock(&ndlp->lock); spin_lock_irq(&phba->hbalock); break; } @@ -19651,29 +20977,23 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) while (!list_empty(&mbox_cmd_list)) { list_remove_head(&mbox_cmd_list, mb, LPFC_MBOXQ_t, list); if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { - mp = (struct lpfc_dmabuf *)(mb->ctx_buf); - if (mp) { - __lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - mb->ctx_buf = NULL; ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp; mb->ctx_ndlp = NULL; if (ndlp) { - spin_lock(shost->host_lock); + spin_lock(&ndlp->lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); + spin_unlock(&ndlp->lock); lpfc_nlp_put(ndlp); } } - mempool_free(mb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, mb, MBOX_THD_UNLOCKED); } /* Release the ndlp with the cleaned-up active mailbox command */ if (act_mbx_ndlp) { - spin_lock(shost->host_lock); + spin_lock(&act_mbx_ndlp->lock); act_mbx_ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); + spin_unlock(&act_mbx_ndlp->lock); lpfc_nlp_put(act_mbx_ndlp); } } @@ -19697,10 +21017,9 @@ lpfc_drain_txq(struct lpfc_hba *phba) struct lpfc_iocbq *piocbq = NULL; unsigned long iflags = 0; char *fail_msg = NULL; - struct lpfc_sglq *sglq; - union lpfc_wqe128 wqe; uint32_t txq_cnt = 0; struct lpfc_queue *wq; + int ret = 0; if (phba->link_flag & LS_MDS_LOOPBACK) { /* MDS WQE are posted only to first WQ*/ @@ -19734,48 +21053,38 @@ lpfc_drain_txq(struct lpfc_hba *phba) piocbq = lpfc_sli_ringtx_get(phba, pring); if (!piocbq) { spin_unlock_irqrestore(&pring->ring_lock, iflags); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2823 txq empty and txq_cnt is %d\n ", txq_cnt); break; } - sglq = __lpfc_sli_get_els_sglq(phba, piocbq); - if (!sglq) { - __lpfc_sli_ringtx_put(phba, pring, piocbq); - spin_unlock_irqrestore(&pring->ring_lock, iflags); - break; - } txq_cnt--; - /* The xri and iocb resources secured, - * attempt to issue request - */ - piocbq->sli4_lxritag = sglq->sli4_lxritag; - piocbq->sli4_xritag = sglq->sli4_xritag; - if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq)) - fail_msg = "to convert bpl to sgl"; - else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe)) - fail_msg = "to convert iocb to wqe"; - else if (lpfc_sli4_wq_put(wq, &wqe)) - fail_msg = " - Wq is full"; - else - lpfc_sli_ringtxcmpl_put(phba, pring, piocbq); + ret = __lpfc_sli_issue_iocb(phba, pring->ringno, piocbq, 0); + if (ret && ret != IOCB_BUSY) { + fail_msg = " - Cannot send IO "; + piocbq->cmd_flag &= ~LPFC_DRIVER_ABORTED; + } if (fail_msg) { + piocbq->cmd_flag |= LPFC_DRIVER_ABORTED; /* Failed means we can't issue and need to cancel */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2822 IOCB failed %s iotag 0x%x " - "xri 0x%x\n", - fail_msg, - piocbq->iotag, piocbq->sli4_xritag); + "xri 0x%x %d flg x%x\n", + fail_msg, piocbq->iotag, + piocbq->sli4_xritag, ret, + piocbq->cmd_flag); list_add_tail(&piocbq->list, &completions); + fail_msg = NULL; } spin_unlock_irqrestore(&pring->ring_lock, iflags); + if (txq_cnt == 0 || ret == IOCB_BUSY) + break; } - /* Cancel all the IOCBs that cannot be issued */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); + IOERR_SLI_ABORTED); return txq_cnt; } @@ -19783,7 +21092,7 @@ lpfc_drain_txq(struct lpfc_hba *phba) /** * lpfc_wqe_bpl2sgl - Convert the bpl/bde to a sgl. * @phba: Pointer to HBA context object. - * @pwqe: Pointer to command WQE. + * @pwqeq: Pointer to command WQE. * @sglq: Pointer to the scatter gather queue object. * * This routine converts the bpl or bde that is in the WQE @@ -19823,14 +21132,14 @@ lpfc_wqe_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeq, cmd = bf_get(wqe_cmnd, &wqe->generic.wqe_com); if (cmd == CMD_XMIT_BLS_RSP64_WQE) return sglq->sli4_xritag; - numBdes = pwqeq->rsvd2; + numBdes = pwqeq->num_bdes; if (numBdes) { /* The addrHigh and addrLow fields within the WQE * have not been byteswapped yet so there is no * need to swap them back. */ - if (pwqeq->context3) - dmabuf = (struct lpfc_dmabuf *)pwqeq->context3; + if (pwqeq->bpl_dmabuf) + dmabuf = pwqeq->bpl_dmabuf; else return xritag; @@ -19908,7 +21217,7 @@ lpfc_wqe_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeq, /** * lpfc_sli4_issue_wqe - Issue an SLI4 Work Queue Entry (WQE) * @phba: Pointer to HBA context object. - * @ring_number: Base sli ring number + * @qp: Pointer to HDW queue. * @pwqe: Pointer to command WQE. **/ int @@ -19916,7 +21225,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, struct lpfc_iocbq *pwqe) { union lpfc_wqe128 *wqe = &pwqe->wqe; - struct lpfc_nvmet_rcv_ctx *ctxp; + struct lpfc_async_xchg_ctx *ctxp; struct lpfc_queue *wq; struct lpfc_sglq *sglq; struct lpfc_sli_ring *pring; @@ -19924,7 +21233,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, uint32_t ret = 0; /* NVME_LS and NVME_LS ABTS requests. */ - if (pwqe->iocb_flag & LPFC_IO_NVME_LS) { + if (pwqe->cmd_flag & LPFC_IO_NVME_LS) { pring = phba->sli4_hba.nvmels_wq->pring; lpfc_qp_spin_lock_irqsave(&pring->ring_lock, iflags, qp, wq_access); @@ -19955,7 +21264,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, } /* NVME_FCREQ and NVME_ABTS requests */ - if (pwqe->iocb_flag & LPFC_IO_NVME) { + if (pwqe->cmd_flag & (LPFC_IO_NVME | LPFC_IO_FCP | LPFC_IO_CMF)) { /* Get the IO distribution (hba_wqidx) for WQ assignment. */ wq = qp->io_wq; pring = wq->pring; @@ -19977,12 +21286,12 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, } /* NVMET requests */ - if (pwqe->iocb_flag & LPFC_IO_NVMET) { + if (pwqe->cmd_flag & LPFC_IO_NVMET) { /* Get the IO distribution (hba_wqidx) for WQ assignment. */ wq = qp->io_wq; pring = wq->pring; - ctxp = pwqe->context2; + ctxp = pwqe->context_un.axchg; sglq = ctxp->ctxbuf->sglq; if (pwqe->sli4_xritag == NO_XRI) { pwqe->sli4_lxritag = sglq->sli4_lxritag; @@ -20008,6 +21317,86 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, return WQE_ERROR; } +/** + * lpfc_sli4_issue_abort_iotag - SLI-4 WQE init & issue for the Abort + * @phba: Pointer to HBA context object. + * @cmdiocb: Pointer to driver command iocb object. + * @cmpl: completion function. + * + * Fill the appropriate fields for the abort WQE and call + * internal routine lpfc_sli4_issue_wqe to send the WQE + * This function is called with hbalock held and no ring_lock held. + * + * RETURNS 0 - SUCCESS + **/ + +int +lpfc_sli4_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + void *cmpl) +{ + struct lpfc_vport *vport = cmdiocb->vport; + struct lpfc_iocbq *abtsiocb = NULL; + union lpfc_wqe128 *abtswqe; + struct lpfc_io_buf *lpfc_cmd; + int retval = IOCB_ERROR; + u16 xritag = cmdiocb->sli4_xritag; + + /* + * The scsi command can not be in txq and it is in flight because the + * pCmd is still pointing at the SCSI command we have to abort. There + * is no need to search the txcmplq. Just send an abort to the FW. + */ + + abtsiocb = __lpfc_sli_get_iocbq(phba); + if (!abtsiocb) + return WQE_NORESOURCE; + + /* Indicate the IO is being aborted by the driver. */ + cmdiocb->cmd_flag |= LPFC_DRIVER_ABORTED; + + abtswqe = &abtsiocb->wqe; + memset(abtswqe, 0, sizeof(*abtswqe)); + + if (!lpfc_is_link_up(phba) || (phba->link_flag & LS_EXTERNAL_LOOPBACK)) + bf_set(abort_cmd_ia, &abtswqe->abort_cmd, 1); + bf_set(abort_cmd_criteria, &abtswqe->abort_cmd, T_XRI_TAG); + abtswqe->abort_cmd.rsrvd5 = 0; + abtswqe->abort_cmd.wqe_com.abort_tag = xritag; + bf_set(wqe_reqtag, &abtswqe->abort_cmd.wqe_com, abtsiocb->iotag); + bf_set(wqe_cmnd, &abtswqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); + bf_set(wqe_xri_tag, &abtswqe->generic.wqe_com, 0); + bf_set(wqe_qosd, &abtswqe->abort_cmd.wqe_com, 1); + bf_set(wqe_lenloc, &abtswqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); + bf_set(wqe_cmd_type, &abtswqe->abort_cmd.wqe_com, OTHER_COMMAND); + + /* ABTS WQE must go to the same WQ as the WQE to be aborted */ + abtsiocb->hba_wqidx = cmdiocb->hba_wqidx; + abtsiocb->cmd_flag |= LPFC_USE_FCPWQIDX; + if (cmdiocb->cmd_flag & LPFC_IO_FCP) + abtsiocb->cmd_flag |= LPFC_IO_FCP; + if (cmdiocb->cmd_flag & LPFC_IO_NVME) + abtsiocb->cmd_flag |= LPFC_IO_NVME; + if (cmdiocb->cmd_flag & LPFC_IO_FOF) + abtsiocb->cmd_flag |= LPFC_IO_FOF; + abtsiocb->vport = vport; + abtsiocb->cmd_cmpl = cmpl; + + lpfc_cmd = container_of(cmdiocb, struct lpfc_io_buf, cur_iocbq); + retval = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, abtsiocb); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "0359 Abort xri x%x, original iotag x%x, " + "abort cmd iotag x%x retval x%x\n", + xritag, cmdiocb->iotag, abtsiocb->iotag, retval); + + if (retval) { + cmdiocb->cmd_flag &= ~LPFC_DRIVER_ABORTED; + __lpfc_sli_release_iocbq(phba, abtsiocb); + } + + return retval; +} + #ifdef LPFC_MXP_STAT /** * lpfc_snapshot_mxp - Snapshot pbl, pvt and busy count @@ -20190,6 +21579,7 @@ void lpfc_move_xri_pvt_to_pbl(struct lpfc_hba *phba, u32 hwqid) /** * _lpfc_move_xri_pbl_to_pvt - Move some XRIs from public to private pool * @phba: pointer to lpfc hba data structure + * @qp: pointer to HDW queue * @pbl_pool: specified public free XRI pool * @pvt_pool: specified private free XRI pool * @count: number of XRIs to move @@ -20319,7 +21709,7 @@ void lpfc_move_xri_pbl_to_pvt(struct lpfc_hba *phba, u32 hwqid, u32 count) /** * lpfc_keep_pvt_pool_above_lowwm - Keep pvt_pool above low watermark * @phba: pointer to lpfc hba data structure. - * @qp: belong to which HWQ. + * @hwqid: belong to which HWQ. * * This routine get a batch of XRIs from pbl_pool if pvt_pool is less than * low watermark. @@ -20362,8 +21752,7 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd, /* MUST zero fields if buffer is reused by another protocol */ lpfc_ncmd->nvmeCmd = NULL; - lpfc_ncmd->cur_iocbq.wqe_cmpl = NULL; - lpfc_ncmd->cur_iocbq.iocb_cmpl = NULL; + lpfc_ncmd->cur_iocbq.cmd_cmpl = NULL; if (phba->cfg_xpsgl && !phba->nvmet_support && !list_empty(&lpfc_ncmd->dma_sgl_xtra_list)) @@ -20441,6 +21830,7 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd, /** * lpfc_get_io_buf_from_private_pool - Get one free IO buf from private pool * @phba: pointer to lpfc hba data structure. + * @qp: pointer to HDW queue * @pvt_pool: pointer to private pool data structure. * @ndlp: pointer to lpfc nodelist data structure. * @@ -20546,8 +21936,26 @@ lpfc_get_io_buf_from_multixri_pools(struct lpfc_hba *phba, qp = &phba->sli4_hba.hdwq[hwqid]; lpfc_ncmd = NULL; + if (!qp) { + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "5556 NULL qp for hwqid x%x\n", hwqid); + return lpfc_ncmd; + } multixri_pool = qp->p_multixri_pool; + if (!multixri_pool) { + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "5557 NULL multixri for hwqid x%x\n", hwqid); + return lpfc_ncmd; + } pvt_pool = &multixri_pool->pvt_pool; + if (!pvt_pool) { + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "5558 NULL pvt_pool for hwqid x%x\n", hwqid); + return lpfc_ncmd; + } multixri_pool->io_req_count++; /* If pvt_pool is empty, move some XRIs from public to private pool */ @@ -20623,6 +22031,12 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, qp = &phba->sli4_hba.hdwq[hwqid]; lpfc_cmd = NULL; + if (!qp) { + lpfc_printf_log(phba, KERN_WARNING, + LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "5555 NULL qp for hwqid x%x\n", hwqid); + return lpfc_cmd; + } if (phba->cfg_xri_rebalancing) lpfc_cmd = lpfc_get_io_buf_from_multixri_pools( @@ -20652,6 +22066,119 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, } /** + * lpfc_read_object - Retrieve object data from HBA + * @phba: The HBA for which this call is being executed. + * @rdobject: Pathname of object data we want to read. + * @datap: Pointer to where data will be copied to. + * @datasz: size of data area + * + * This routine is limited to object sizes of LPFC_BPL_SIZE (1024) or less. + * The data will be truncated if datasz is not large enough. + * Version 1 is not supported with Embedded mbox cmd, so we must use version 0. + * Returns the actual bytes read from the object. + */ +int +lpfc_read_object(struct lpfc_hba *phba, char *rdobject, uint32_t *datap, + uint32_t datasz) +{ + struct lpfc_mbx_read_object *read_object; + LPFC_MBOXQ_t *mbox; + int rc, length, eof, j, byte_cnt = 0; + uint32_t shdr_status, shdr_add_status; + union lpfc_sli4_cfg_shdr *shdr; + struct lpfc_dmabuf *pcmd; + u32 rd_object_name[LPFC_MBX_OBJECT_NAME_LEN_DW] = {0}; + + /* sanity check on queue memory */ + if (!datap) + return -ENODEV; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return -ENOMEM; + length = (sizeof(struct lpfc_mbx_read_object) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_READ_OBJECT, + length, LPFC_SLI4_MBX_EMBED); + read_object = &mbox->u.mqe.un.read_object; + shdr = (union lpfc_sli4_cfg_shdr *)&read_object->header.cfg_shdr; + + bf_set(lpfc_mbox_hdr_version, &shdr->request, LPFC_Q_CREATE_VERSION_0); + bf_set(lpfc_mbx_rd_object_rlen, &read_object->u.request, datasz); + read_object->u.request.rd_object_offset = 0; + read_object->u.request.rd_object_cnt = 1; + + memset((void *)read_object->u.request.rd_object_name, 0, + LPFC_OBJ_NAME_SZ); + scnprintf((char *)rd_object_name, sizeof(rd_object_name), rdobject); + for (j = 0; j < strlen(rdobject); j++) + read_object->u.request.rd_object_name[j] = + cpu_to_le32(rd_object_name[j]); + + pcmd = kmalloc(sizeof(*pcmd), GFP_KERNEL); + if (pcmd) + pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); + if (!pcmd || !pcmd->virt) { + kfree(pcmd); + mempool_free(mbox, phba->mbox_mem_pool); + return -ENOMEM; + } + memset((void *)pcmd->virt, 0, LPFC_BPL_SIZE); + read_object->u.request.rd_object_hbuf[0].pa_lo = + putPaddrLow(pcmd->phys); + read_object->u.request.rd_object_hbuf[0].pa_hi = + putPaddrHigh(pcmd->phys); + read_object->u.request.rd_object_hbuf[0].length = LPFC_BPL_SIZE; + + mbox->vport = phba->pport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->ctx_ndlp = NULL; + + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); + + if (shdr_status == STATUS_FAILED && + shdr_add_status == ADD_STATUS_INVALID_OBJECT_NAME) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_CGN_MGMT, + "4674 No port cfg file in FW.\n"); + byte_cnt = -ENOENT; + } else if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_CGN_MGMT, + "2625 READ_OBJECT mailbox failed with " + "status x%x add_status x%x, mbx status x%x\n", + shdr_status, shdr_add_status, rc); + byte_cnt = -ENXIO; + } else { + /* Success */ + length = read_object->u.response.rd_object_actual_rlen; + eof = bf_get(lpfc_mbx_rd_object_eof, &read_object->u.response); + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_CGN_MGMT, + "2626 READ_OBJECT Success len %d:%d, EOF %d\n", + length, datasz, eof); + + /* Detect the port config file exists but is empty */ + if (!length && eof) { + byte_cnt = 0; + goto exit; + } + + byte_cnt = length; + lpfc_sli_pcimem_bcopy(pcmd->virt, datap, byte_cnt); + } + + exit: + /* This is an embedded SLI4 mailbox with an external buffer allocated. + * Free the pcmd and then cleanup with the correct routine. + */ + lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); + kfree(pcmd); + lpfc_sli4_mbox_cmd_free(phba, mbox); + return byte_cnt; +} + +/** * lpfc_get_sgl_per_hdwq - Get one SGL chunk from hdwq's pool * @phba: The HBA for which this call is being executed. * @lpfc_buf: IO buf structure to append the SGL chunk @@ -20839,7 +22366,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, return NULL; } - tmp->fcp_cmnd = dma_pool_alloc(phba->lpfc_cmd_rsp_buf_pool, + tmp->fcp_cmnd = dma_pool_zalloc(phba->lpfc_cmd_rsp_buf_pool, GFP_ATOMIC, &tmp->fcp_cmd_rsp_dma_handle); @@ -20941,3 +22468,180 @@ lpfc_free_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); } + +/** + * lpfc_sli_prep_wqe - Prepare WQE for the command to be posted + * @phba: phba object + * @job: job entry of the command to be posted. + * + * Fill the common fields of the wqe for each of the command. + * + * Return codes: + * None + **/ +void +lpfc_sli_prep_wqe(struct lpfc_hba *phba, struct lpfc_iocbq *job) +{ + u8 cmnd; + u32 *pcmd; + u32 if_type = 0; + u32 fip, abort_tag; + struct lpfc_nodelist *ndlp = NULL; + union lpfc_wqe128 *wqe = &job->wqe; + u8 command_type = ELS_COMMAND_NON_FIP; + + fip = phba->hba_flag & HBA_FIP_SUPPORT; + /* The fcp commands will set command type */ + if (job->cmd_flag & LPFC_IO_FCP) + command_type = FCP_COMMAND; + else if (fip && (job->cmd_flag & LPFC_FIP_ELS_ID_MASK)) + command_type = ELS_COMMAND_FIP; + else + command_type = ELS_COMMAND_NON_FIP; + + abort_tag = job->iotag; + cmnd = bf_get(wqe_cmnd, &wqe->els_req.wqe_com); + + switch (cmnd) { + case CMD_ELS_REQUEST64_WQE: + ndlp = job->ndlp; + + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { + pcmd = (u32 *)job->cmd_dmabuf->virt; + if (pcmd && (*pcmd == ELS_CMD_FLOGI || + *pcmd == ELS_CMD_SCR || + *pcmd == ELS_CMD_RDF || + *pcmd == ELS_CMD_EDC || + *pcmd == ELS_CMD_RSCN_XMT || + *pcmd == ELS_CMD_FDISC || + *pcmd == ELS_CMD_LOGO || + *pcmd == ELS_CMD_QFPA || + *pcmd == ELS_CMD_UVEM || + *pcmd == ELS_CMD_PLOGI)) { + bf_set(els_req64_sp, &wqe->els_req, 1); + bf_set(els_req64_sid, &wqe->els_req, + job->vport->fc_myDID); + + if ((*pcmd == ELS_CMD_FLOGI) && + !(phba->fc_topology == + LPFC_TOPOLOGY_LOOP)) + bf_set(els_req64_sid, &wqe->els_req, 0); + + bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->vpi_ids[job->vport->vpi]); + } else if (pcmd) { + bf_set(wqe_ct, &wqe->els_req.wqe_com, 0); + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); + } + } + + bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); + + bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1); + bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ); + bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1); + bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE); + bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0); + break; + case CMD_XMIT_ELS_RSP64_WQE: + ndlp = job->ndlp; + + /* word4 */ + wqe->xmit_els_rsp.word4 = 0; + + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) { + if (job->vport->fc_flag & FC_PT2PT) { + bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); + bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, + job->vport->fc_myDID); + if (job->vport->fc_myDID == Fabric_DID) { + bf_set(wqe_els_did, + &wqe->xmit_els_rsp.wqe_dest, 0); + } + } + } + + bf_set(wqe_dbde, &wqe->xmit_els_rsp.wqe_com, 1); + bf_set(wqe_iod, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_IOD_WRITE); + bf_set(wqe_qosd, &wqe->xmit_els_rsp.wqe_com, 1); + bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com, + LPFC_WQE_LENLOC_WORD3); + bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0); + + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { + bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); + bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, + job->vport->fc_myDID); + bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, 1); + } + + if (phba->sli_rev == LPFC_SLI_REV4) { + bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); + + if (bf_get(wqe_ct, &wqe->xmit_els_rsp.wqe_com)) + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, + phba->vpi_ids[job->vport->vpi]); + } + command_type = OTHER_COMMAND; + break; + case CMD_GEN_REQUEST64_WQE: + /* Word 10 */ + bf_set(wqe_dbde, &wqe->gen_req.wqe_com, 1); + bf_set(wqe_iod, &wqe->gen_req.wqe_com, LPFC_WQE_IOD_READ); + bf_set(wqe_qosd, &wqe->gen_req.wqe_com, 1); + bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE); + bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0); + command_type = OTHER_COMMAND; + break; + case CMD_XMIT_SEQUENCE64_WQE: + if (phba->link_flag & LS_LOOPBACK_MODE) + bf_set(wqe_xo, &wqe->xmit_sequence.wge_ctl, 1); + + wqe->xmit_sequence.rsvd3 = 0; + bf_set(wqe_pu, &wqe->xmit_sequence.wqe_com, 0); + bf_set(wqe_dbde, &wqe->xmit_sequence.wqe_com, 1); + bf_set(wqe_iod, &wqe->xmit_sequence.wqe_com, + LPFC_WQE_IOD_WRITE); + bf_set(wqe_lenloc, &wqe->xmit_sequence.wqe_com, + LPFC_WQE_LENLOC_WORD12); + bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0); + command_type = OTHER_COMMAND; + break; + case CMD_XMIT_BLS_RSP64_WQE: + bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff); + bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1); + bf_set(wqe_ct, &wqe->xmit_bls_rsp.wqe_com, 1); + bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com, + phba->vpi_ids[phba->pport->vpi]); + bf_set(wqe_qosd, &wqe->xmit_bls_rsp.wqe_com, 1); + bf_set(wqe_lenloc, &wqe->xmit_bls_rsp.wqe_com, + LPFC_WQE_LENLOC_NONE); + /* Overwrite the pre-set comnd type with OTHER_COMMAND */ + command_type = OTHER_COMMAND; + break; + case CMD_FCP_ICMND64_WQE: /* task mgmt commands */ + case CMD_ABORT_XRI_WQE: /* abort iotag */ + case CMD_SEND_FRAME: /* mds loopback */ + /* cases already formatted for sli4 wqe - no chgs necessary */ + return; + default: + dump_stack(); + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "6207 Invalid command 0x%x\n", + cmnd); + break; + } + + wqe->generic.wqe_com.abort_tag = abort_tag; + bf_set(wqe_reqtag, &wqe->generic.wqe_com, job->iotag); + bf_set(wqe_cmd_type, &wqe->generic.wqe_com, command_type); + bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); +} diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 7bcf922a8be2..cd33dfec758c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -35,6 +35,18 @@ typedef enum _lpfc_ctx_cmd { LPFC_CTX_HOST } lpfc_ctx_cmd; +/* Enumeration to describe the thread lock context. */ +enum lpfc_mbox_ctx { + MBOX_THD_UNLOCKED, + MBOX_THD_LOCKED +}; + +union lpfc_vmid_tag { + uint32_t app_id; + uint8_t cs_ctl_vmid; + struct lpfc_vmid_context *vmid_context; /* UVEM context information */ +}; + struct lpfc_cq_event { struct list_head list; uint16_t hdwq; @@ -63,16 +75,25 @@ struct lpfc_iocbq { uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */ uint16_t hba_wqidx; /* index to HBA work queue */ struct lpfc_cq_event cq_event; - struct lpfc_wcqe_complete wcqe_cmpl; /* WQE cmpl */ uint64_t isr_timestamp; union lpfc_wqe128 wqe; /* SLI-4 */ IOCB_t iocb; /* SLI-3 */ + struct lpfc_wcqe_complete wcqe_cmpl; /* WQE cmpl */ + + u32 unsol_rcv_len; /* Receive len in usol path */ - uint8_t rsvd2; - uint8_t priority; /* OAS priority */ - uint8_t retry; /* retry counter for IOCB cmd - if needed */ - uint32_t iocb_flag; + /* Pack the u8's together and make them module-4. */ + u8 num_bdes; /* Number of BDEs */ + u8 abort_bls; /* ABTS by initiator or responder */ + u8 abort_rctl; /* ACC or RJT flag */ + u8 priority; /* OAS priority */ + u8 retry; /* retry counter for IOCB cmd - if needed */ + u8 rsvd1; /* Pad for u32 */ + u8 rsvd2; /* Pad for u32 */ + u8 rsvd3; /* Pad for u32 */ + + u32 cmd_flag; #define LPFC_IO_LIBDFC 1 /* libdfc iocb */ #define LPFC_IO_WAKE 2 /* Synchronous I/O completed */ #define LPFC_IO_WAKE_TMO LPFC_IO_WAKE /* Synchronous I/O timed out */ @@ -100,28 +121,34 @@ struct lpfc_iocbq { #define LPFC_IO_NVME 0x200000 /* NVME FCP command */ #define LPFC_IO_NVME_LS 0x400000 /* NVME LS command */ #define LPFC_IO_NVMET 0x800000 /* NVMET command */ +#define LPFC_IO_VMID 0x1000000 /* VMID tagged IO */ +#define LPFC_IO_CMF 0x4000000 /* CMF command */ uint32_t drvrTimeout; /* driver timeout in seconds */ struct lpfc_vport *vport;/* virtual port pointer */ - void *context1; /* caller context information */ - void *context2; /* caller context information */ - void *context3; /* caller context information */ + struct lpfc_dmabuf *cmd_dmabuf; + struct lpfc_dmabuf *rsp_dmabuf; + struct lpfc_dmabuf *bpl_dmabuf; + uint32_t event_tag; /* LA Event tag */ union { wait_queue_head_t *wait_queue; - struct lpfc_iocbq *rsp_iocb; struct lpfcMboxq *mbox; - struct lpfc_nodelist *ndlp; struct lpfc_node_rrq *rrq; + struct nvmefc_ls_req *nvme_lsreq; + struct lpfc_async_xchg_ctx *axchg; + struct bsg_job_data *dd_data; } context_un; - void (*fabric_iocb_cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); - void (*wait_iocb_cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); - void (*iocb_cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); - void (*wqe_cmpl)(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_wcqe_complete *); + struct lpfc_io_buf *io_buf; + struct lpfc_iocbq *rsp_iocb; + struct lpfc_nodelist *ndlp; + union lpfc_vmid_tag vmid_tag; + void (*fabric_cmd_cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *cmd, + struct lpfc_iocbq *rsp); + void (*wait_cmd_cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *cmd, + struct lpfc_iocbq *rsp); + void (*cmd_cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *cmd, + struct lpfc_iocbq *rsp); }; #define SLI_IOCB_RET_IOCB 1 /* Return IOCB if cmd ring full */ @@ -130,6 +157,9 @@ struct lpfc_iocbq { #define IOCB_BUSY 1 #define IOCB_ERROR 2 #define IOCB_TIMEDOUT 3 +#define IOCB_ABORTED 4 +#define IOCB_ABORTING 5 +#define IOCB_NORESOURCE 6 #define SLI_WQE_RET_WQE 1 /* Return WQE if cmd ring full */ @@ -138,6 +168,8 @@ struct lpfc_iocbq { #define WQE_ERROR 2 #define WQE_TIMEDOUT 3 #define WQE_ABORTED 4 +#define WQE_ABORTING 5 +#define WQE_NORESOURCE 6 #define LPFC_MBX_WAKE 1 #define LPFC_MBX_IMED_UNREG 2 @@ -323,7 +355,6 @@ struct lpfc_sli { #define LPFC_SLI_ACTIVE 0x200 /* SLI in firmware is active */ #define LPFC_PROCESS_LA 0x400 /* Able to process link attention */ #define LPFC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */ -#define LPFC_MENLO_MAINT 0x1000 /* need for menl fw download */ #define LPFC_SLI_ASYNC_MBX_BLK 0x2000 /* Async mailbox is blocked */ #define LPFC_SLI_SUPPRESS_RSP 0x4000 /* Suppress RSP feature is supported */ #define LPFC_SLI_USE_EQDR 0x8000 /* EQ Delay Register is supported */ @@ -446,6 +477,7 @@ struct lpfc_io_buf { uint64_t ts_last_cmd; uint64_t ts_cmd_wqput; uint64_t ts_isr_cmpl; - uint64_t ts_data_nvme; + uint64_t ts_data_io; #endif + uint64_t rx_cmd_start; }; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index d963ca871383..cbb1aa1cf025 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -20,6 +20,9 @@ * included with this package. * *******************************************************************/ +#include <linux/irq_poll.h> +#include <linux/cpufreq.h> + #if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_SCSI_LPFC_DEBUG_FS) #define CONFIG_SCSI_LPFC_DEBUG_FS #endif @@ -135,6 +138,16 @@ struct lpfc_rqb { struct rqb_dmabuf *); }; +enum lpfc_poll_mode { + LPFC_QUEUE_WORK, + LPFC_IRQ_POLL +}; + +struct lpfc_idle_stat { + u64 prev_idle; + u64 prev_wall; +}; + struct lpfc_queue { struct list_head list; struct list_head wq_list; @@ -265,6 +278,10 @@ struct lpfc_queue { struct lpfc_queue *assoc_qp; struct list_head _poll_list; void **q_pgs; /* array to index entries per page */ + +#define LPFC_IRQ_POLL_WEIGHT 256 + struct irq_poll iop; + enum lpfc_poll_mode poll_mode; }; struct lpfc_sli4_link { @@ -472,7 +489,7 @@ struct lpfc_hba; #define LPFC_SLI4_HANDLER_NAME_SZ 16 struct lpfc_hba_eq_hdl { uint32_t idx; - uint16_t irq; + int irq; char handler_name[LPFC_SLI4_HANDLER_NAME_SZ]; struct lpfc_hba *phba; struct lpfc_queue *eq; @@ -532,6 +549,15 @@ struct lpfc_pc_sli4_params { uint32_t hdr_pp_align; uint32_t sgl_pages_max; uint32_t sgl_pp_align; + uint32_t mib_size; + uint16_t mi_ver; +#define LPFC_MIB1_SUPPORT 1 +#define LPFC_MIB2_SUPPORT 2 +#define LPFC_MIB3_SUPPORT 3 + uint16_t mi_value; +#define LPFC_DFLT_MIB_VAL 2 + uint8_t mib_bde_cnt; + uint8_t cmf; uint8_t cqv; uint8_t mqv; uint8_t wqv; @@ -585,6 +611,8 @@ struct lpfc_vector_map_info { }; #define LPFC_VECTOR_MAP_EMPTY 0xffff +#define LPFC_IRQ_EMPTY 0xffffffff + /* Multi-XRI pool */ #define XRI_BATCH 8 @@ -697,13 +725,6 @@ struct lpfc_sli4_hdw_queue { struct lpfc_lock_stat lock_conflict; #endif -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS -#define LPFC_CHECK_CPU_CNT 128 - uint32_t cpucheck_rcv_io[LPFC_CHECK_CPU_CNT]; - uint32_t cpucheck_xmt_io[LPFC_CHECK_CPU_CNT]; - uint32_t cpucheck_cmpl_io[LPFC_CHECK_CPU_CNT]; -#endif - /* Per HDWQ pool resources */ struct list_head sgl_list; struct list_head cmd_rsp_buf_list; @@ -740,6 +761,15 @@ struct lpfc_sli4_hdw_queue { #define lpfc_qp_spin_lock(lock, qp, lstat) spin_lock(lock) #endif +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS +struct lpfc_hdwq_stat { + u32 hdwq_no; + u32 rcv_io; + u32 xmt_io; + u32 cmpl_io; +}; +#endif + struct lpfc_sli4_hba { void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for * config space registers @@ -901,8 +931,9 @@ struct lpfc_sli4_hba { struct list_head sp_queue_event; struct list_head sp_cqe_event_pool; struct list_head sp_asynce_work_queue; - struct list_head sp_fcp_xri_aborted_work_queue; + spinlock_t asynce_list_lock; /* protect sp_asynce_work_queue list */ struct list_head sp_els_xri_aborted_work_queue; + spinlock_t els_xri_abrt_list_lock; /* protect els_xri_aborted list */ struct list_head sp_unsol_work_queue; struct lpfc_sli4_link link_state; struct lpfc_sli4_lnk_info lnk_info; @@ -918,9 +949,13 @@ struct lpfc_sli4_hba { struct lpfc_vector_map_info *cpu_map; uint16_t num_possible_cpu; uint16_t num_present_cpu; - struct cpumask numa_mask; + struct cpumask irq_aff_mask; uint16_t curr_disp_cpu; struct lpfc_eq_intr_info __percpu *eq_info; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + struct lpfc_hdwq_stat __percpu *c_stat; +#endif + struct lpfc_idle_stat *idle_stat; uint32_t conf_trunk; #define lpfc_conf_trunk_port0_WORD conf_trunk #define lpfc_conf_trunk_port0_SHIFT 0 @@ -946,6 +981,11 @@ struct lpfc_sli4_hba { #define lpfc_conf_trunk_port3_nd_WORD conf_trunk #define lpfc_conf_trunk_port3_nd_SHIFT 7 #define lpfc_conf_trunk_port3_nd_MASK 0x1 + uint8_t flash_id; + uint8_t asic_rev; + uint16_t fawwpn_flag; /* FA-WWPN support state */ +#define LPFC_FAWWPN_CONFIG 0x1 /* FA-PWWN is configured */ +#define LPFC_FAWWPN_FABRIC 0x2 /* FA-PWWN success with Fabric */ }; enum lpfc_sge_type { @@ -1080,8 +1120,9 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *); void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *); int lpfc_sli4_resume_rpi(struct lpfc_nodelist *, void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *); -void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *); -void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *); +void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba); +void lpfc_sli4_nvme_pci_offline_aborted(struct lpfc_hba *phba, + struct lpfc_io_buf *lpfc_ncmd); void lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri, struct lpfc_io_buf *lpfc_ncmd); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 9563c49f36ab..192d5630a44d 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "12.6.0.3" +#define LPFC_DRIVER_VERSION "14.2.0.7" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ @@ -32,6 +32,6 @@ #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright (C) 2017-2019 Broadcom. All Rights " \ +#define LPFC_COPYRIGHT "Copyright (C) 2017-2022 Broadcom. All Rights " \ "Reserved. The term \"Broadcom\" refers to Broadcom Inc. " \ "and/or its subsidiaries." diff --git a/drivers/scsi/lpfc/lpfc_vmid.c b/drivers/scsi/lpfc/lpfc_vmid.c new file mode 100644 index 000000000000..ed1d7f7b88a3 --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_vmid.c @@ -0,0 +1,286 @@ +/******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * + * Copyright (C) 2017-2022 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/interrupt.h> +#include <linux/dma-direction.h> + +#include <scsi/scsi_transport_fc.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_crtn.h" + + +/* + * lpfc_get_vmid_from_hashtable - search the UUID in the hash table + * @vport: The virtual port for which this call is being executed. + * @hash: calculated hash value + * @buf: uuid associated with the VE + * Return the VMID entry associated with the UUID + * Make sure to acquire the appropriate lock before invoking this routine. + */ +struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport, + u32 hash, u8 *buf) +{ + struct lpfc_vmid *vmp; + + hash_for_each_possible(vport->hash_table, vmp, hnode, hash) { + if (memcmp(&vmp->host_vmid[0], buf, 16) == 0) + return vmp; + } + return NULL; +} + +/* + * lpfc_put_vmid_in_hashtable - put the VMID in the hash table + * @vport: The virtual port for which this call is being executed. + * @hash - calculated hash value + * @vmp: Pointer to a VMID entry representing a VM sending I/O + * + * This routine will insert the newly acquired VMID entity in the hash table. + * Make sure to acquire the appropriate lock before invoking this routine. + */ +static void +lpfc_put_vmid_in_hashtable(struct lpfc_vport *vport, u32 hash, + struct lpfc_vmid *vmp) +{ + hash_add(vport->hash_table, &vmp->hnode, hash); +} + +/* + * lpfc_vmid_hash_fn - create a hash value of the UUID + * @vmid: uuid associated with the VE + * @len: length of the VMID string + * Returns the calculated hash value + */ +int lpfc_vmid_hash_fn(const char *vmid, int len) +{ + int c; + int hash = 0; + + if (len == 0) + return 0; + while (len--) { + c = *vmid++; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + + hash = (hash + (c << LPFC_VMID_HASH_SHIFT) + + (c >> LPFC_VMID_HASH_SHIFT)) * 19; + } + + return hash & LPFC_VMID_HASH_MASK; +} + +/* + * lpfc_vmid_update_entry - update the vmid entry in the hash table + * @vport: The virtual port for which this call is being executed. + * @iodir: io direction + * @vmp: Pointer to a VMID entry representing a VM sending I/O + * @tag: VMID tag + */ +static void lpfc_vmid_update_entry(struct lpfc_vport *vport, + enum dma_data_direction iodir, + struct lpfc_vmid *vmp, + union lpfc_vmid_io_tag *tag) +{ + u64 *lta; + + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) + tag->cs_ctl_vmid = vmp->un.cs_ctl_vmid; + else if (vport->phba->cfg_vmid_app_header) + tag->app_id = vmp->un.app_id; + + if (iodir == DMA_TO_DEVICE) + vmp->io_wr_cnt++; + else if (iodir == DMA_FROM_DEVICE) + vmp->io_rd_cnt++; + + /* update the last access timestamp in the table */ + lta = per_cpu_ptr(vmp->last_io_time, raw_smp_processor_id()); + *lta = jiffies; +} + +static void lpfc_vmid_assign_cs_ctl(struct lpfc_vport *vport, + struct lpfc_vmid *vmid) +{ + u32 hash; + struct lpfc_vmid *pvmid; + + if (vport->port_type == LPFC_PHYSICAL_PORT) { + vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); + } else { + hash = lpfc_vmid_hash_fn(vmid->host_vmid, vmid->vmid_len); + pvmid = + lpfc_get_vmid_from_hashtable(vport->phba->pport, hash, + vmid->host_vmid); + if (pvmid) + vmid->un.cs_ctl_vmid = pvmid->un.cs_ctl_vmid; + else + vmid->un.cs_ctl_vmid = lpfc_vmid_get_cs_ctl(vport); + } +} + +/* + * lpfc_vmid_get_appid - get the VMID associated with the UUID + * @vport: The virtual port for which this call is being executed. + * @uuid: UUID associated with the VE + * @cmd: address of scsi_cmd descriptor + * @iodir: io direction + * @tag: VMID tag + * Returns status of the function + */ +int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, + enum dma_data_direction iodir, + union lpfc_vmid_io_tag *tag) +{ + struct lpfc_vmid *vmp = NULL; + int hash, len, rc = -EPERM, i; + + /* check if QFPA is complete */ + if (lpfc_vmid_is_type_priority_tag(vport) && + !(vport->vmid_flag & LPFC_VMID_QFPA_CMPL) && + (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA)) { + vport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA; + return -EAGAIN; + } + + /* search if the UUID has already been mapped to the VMID */ + len = strlen(uuid); + hash = lpfc_vmid_hash_fn(uuid, len); + + /* search for the VMID in the table */ + read_lock(&vport->vmid_lock); + vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); + + /* if found, check if its already registered */ + if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { + read_unlock(&vport->vmid_lock); + lpfc_vmid_update_entry(vport, iodir, vmp, tag); + rc = 0; + } else if (vmp && (vmp->flag & LPFC_VMID_REQ_REGISTER || + vmp->flag & LPFC_VMID_DE_REGISTER)) { + /* else if register or dereg request has already been sent */ + /* Hence VMID tag will not be added for this I/O */ + read_unlock(&vport->vmid_lock); + rc = -EBUSY; + } else { + /* The VMID was not found in the hashtable. At this point, */ + /* drop the read lock first before proceeding further */ + read_unlock(&vport->vmid_lock); + /* start the process to obtain one as per the */ + /* type of the VMID indicated */ + write_lock(&vport->vmid_lock); + vmp = lpfc_get_vmid_from_hashtable(vport, hash, uuid); + + /* while the read lock was released, in case the entry was */ + /* added by other context or is in process of being added */ + if (vmp && vmp->flag & LPFC_VMID_REGISTERED) { + lpfc_vmid_update_entry(vport, iodir, vmp, tag); + write_unlock(&vport->vmid_lock); + return 0; + } else if (vmp && vmp->flag & LPFC_VMID_REQ_REGISTER) { + write_unlock(&vport->vmid_lock); + return -EBUSY; + } + + /* else search and allocate a free slot in the hash table */ + if (vport->cur_vmid_cnt < vport->max_vmid) { + for (i = 0; i < vport->max_vmid; i++) { + vmp = vport->vmid + i; + if (vmp->flag == LPFC_VMID_SLOT_FREE) + break; + } + if (i == vport->max_vmid) + vmp = NULL; + } else { + vmp = NULL; + } + + if (!vmp) { + write_unlock(&vport->vmid_lock); + return -ENOMEM; + } + + /* Add the vmid and register */ + lpfc_put_vmid_in_hashtable(vport, hash, vmp); + vmp->vmid_len = len; + memcpy(vmp->host_vmid, uuid, vmp->vmid_len); + vmp->io_rd_cnt = 0; + vmp->io_wr_cnt = 0; + vmp->flag = LPFC_VMID_SLOT_USED; + + vmp->delete_inactive = + vport->vmid_inactivity_timeout ? 1 : 0; + + /* if type priority tag, get next available VMID */ + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) + lpfc_vmid_assign_cs_ctl(vport, vmp); + + /* allocate the per cpu variable for holding */ + /* the last access time stamp only if VMID is enabled */ + if (!vmp->last_io_time) + vmp->last_io_time = alloc_percpu_gfp(u64, GFP_ATOMIC); + if (!vmp->last_io_time) { + hash_del(&vmp->hnode); + vmp->flag = LPFC_VMID_SLOT_FREE; + write_unlock(&vport->vmid_lock); + return -EIO; + } + + write_unlock(&vport->vmid_lock); + + /* complete transaction with switch */ + if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) + rc = lpfc_vmid_uvem(vport, vmp, true); + else if (vport->phba->cfg_vmid_app_header) + rc = lpfc_vmid_cmd(vport, SLI_CTAS_RAPP_IDENT, vmp); + if (!rc) { + write_lock(&vport->vmid_lock); + vport->cur_vmid_cnt++; + vmp->flag |= LPFC_VMID_REQ_REGISTER; + write_unlock(&vport->vmid_lock); + } else { + write_lock(&vport->vmid_lock); + hash_del(&vmp->hnode); + vmp->flag = LPFC_VMID_SLOT_FREE; + free_percpu(vmp->last_io_time); + write_unlock(&vport->vmid_lock); + return -EIO; + } + + /* finally, enable the idle timer once */ + if (!(vport->phba->pport->vmid_flag & LPFC_VMID_TIMER_ENBLD)) { + mod_timer(&vport->phba->inactive_vmid_poll, + jiffies + + msecs_to_jiffies(1000 * LPFC_VMID_TIMER)); + vport->phba->pport->vmid_flag |= LPFC_VMID_TIMER_ENBLD; + } + } + return rc; +} diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index b76646357980..4d171f5c213f 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 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. * @@ -135,47 +135,44 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport) } /* - * Grab buffer pointer and clear context1 so we can use - * lpfc_sli_issue_box_wait + * Wait for the read_sparams mailbox to complete. Driver needs + * this per vport to start the FDISC. If the mailbox fails, + * just cleanup and return an error unless the failure is a + * mailbox timeout. For MBX_TIMEOUT, allow the default + * mbox completion handler to take care of the cleanup. This + * is safe as the mailbox command isn't one that triggers + * another mailbox. */ - mp = (struct lpfc_dmabuf *)pmb->ctx_buf; - pmb->ctx_buf = NULL; - pmb->vport = vport; rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2); if (rc != MBX_SUCCESS) { if (signal_pending(current)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1830 Signal aborted mbxCmd x%x\n", mb->mbxCommand); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); if (rc != MBX_TIMEOUT) - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, pmb, + MBOX_THD_UNLOCKED); return -EINTR; } else { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1818 VPort failed init, mbxCmd x%x " "READ_SPARM mbxStatus x%x, rc = x%x\n", mb->mbxCommand, mb->mbxStatus, rc); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); if (rc != MBX_TIMEOUT) - mempool_free(pmb, phba->mbox_mem_pool); + lpfc_mbox_rsrc_cleanup(phba, pmb, + MBOX_THD_UNLOCKED); return -EIO; } } + mp = (struct lpfc_dmabuf *)pmb->ctx_buf; memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm)); memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, sizeof (struct lpfc_name)); memcpy(&vport->fc_portname, &vport->fc_sparam.portName, sizeof (struct lpfc_name)); - - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - + lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); return 0; } @@ -284,11 +281,11 @@ static void lpfc_discovery_wait(struct lpfc_vport *vport) } if (time_after(jiffies, wait_time_max)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1835 Vport discovery quiesce failed:" - " state x%x fc_flags x%x wait msecs x%x\n", - vport->port_state, vport->fc_flag, - jiffies_to_msecs(jiffies - start_time)); + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, + "1835 Vport discovery quiesce failed:" + " state x%x fc_flags x%x wait msecs x%x\n", + vport->port_state, vport->fc_flag, + jiffies_to_msecs(jiffies - start_time)); } int @@ -305,7 +302,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) int status; if ((phba->sli_rev < 3) || !(phba->cfg_enable_npiv)) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1808 Create VPORT failed: " "NPIV is not enabled: SLImode:%d\n", phba->sli_rev); @@ -315,7 +312,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) /* NPIV is not supported if HBA has NVME Target enabled */ if (phba->nvmet_support) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3189 Create VPORT failed: " "NPIV is not supported on NVME Target\n"); rc = VPORT_INVAL; @@ -324,7 +321,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) vpi = lpfc_alloc_vpi(phba); if (vpi == 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1809 Create VPORT failed: " "Max VPORTs (%d) exceeded\n", phba->max_vpi); @@ -334,7 +331,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) /* Assign an unused board number */ if ((instance = lpfc_get_instance()) < 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1810 Create VPORT failed: Cannot get " "instance number\n"); lpfc_free_vpi(phba, vpi); @@ -344,7 +341,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) vport = lpfc_create_port(phba, instance, &fc_vport->dev); if (!vport) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1811 Create VPORT failed: vpi x%x\n", vpi); lpfc_free_vpi(phba, vpi); rc = VPORT_NORESOURCES; @@ -356,11 +353,11 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) if ((status = lpfc_vport_sparm(phba, vport))) { if (status == -EINTR) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1831 Create VPORT Interrupted.\n"); rc = VPORT_ERROR; } else { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1813 Create VPORT failed. " "Cannot get sparam\n"); rc = VPORT_NORESOURCES; @@ -378,7 +375,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") || !lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1821 Create VPORT failed. " "Invalid WWN format\n"); lpfc_free_vpi(phba, vpi); @@ -388,7 +385,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) } if (!lpfc_unique_wwpn(phba, vport)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1823 Create VPORT failed. " "Duplicate WWN on HBA\n"); lpfc_free_vpi(phba, vpi); @@ -426,7 +423,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) (pport->fc_flag & FC_VFI_REGISTERED)) { rc = lpfc_sli4_init_vpi(vport); if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1838 Failed to INIT_VPI on vpi %d " "status %d\n", vpi, rc); rc = VPORT_NORESOURCES; @@ -462,14 +459,14 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) * up and ready to FDISC. */ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { lpfc_set_disctmo(vport); lpfc_initial_fdisc(vport); } else { lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0262 No NPIV Fabric support\n"); } } else { @@ -479,30 +476,74 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) out: lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1825 Vport Created.\n"); + "1825 Vport Created.\n"); lpfc_host_attrib_init(lpfc_shost_from_vport(vport)); error_out: return rc; } static int +lpfc_send_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + int rc; + struct lpfc_hba *phba = vport->phba; + + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); + + spin_lock_irq(&ndlp->lock); + if (!(ndlp->save_flags & NLP_WAIT_FOR_LOGO) && + !ndlp->logo_waitq) { + ndlp->logo_waitq = &waitq; + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + ndlp->nlp_flag |= NLP_ISSUE_LOGO; + ndlp->save_flags |= NLP_WAIT_FOR_LOGO; + } + spin_unlock_irq(&ndlp->lock); + rc = lpfc_issue_els_npiv_logo(vport, ndlp); + if (!rc) { + wait_event_timeout(waitq, + (!(ndlp->save_flags & NLP_WAIT_FOR_LOGO)), + msecs_to_jiffies(phba->fc_ratov * 2000)); + + if (!(ndlp->save_flags & NLP_WAIT_FOR_LOGO)) + goto logo_cmpl; + /* LOGO wait failed. Correct status. */ + rc = -EINTR; + } else { + rc = -EIO; + } + + /* Error - clean up node flags. */ + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_ISSUE_LOGO; + ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO; + spin_unlock_irq(&ndlp->lock); + + logo_cmpl: + lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT, + "1824 Issue LOGO completes with status %d\n", + rc); + spin_lock_irq(&ndlp->lock); + ndlp->logo_waitq = NULL; + spin_unlock_irq(&ndlp->lock); + return rc; +} + +static int disable_vport(struct fc_vport *fc_vport) { struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; - long timeout; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + /* Can't disable during an outstanding delete. */ + if (vport->load_flag & FC_UNLOADING) + return 0; + ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && phba->link_state >= LPFC_LINK_UP) { - vport->unreg_vpi_cmpl = VPORT_INVAL; - timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (!lpfc_issue_els_npiv_logo(vport, ndlp)) - while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) - timeout = schedule_timeout(timeout); - } + if (ndlp && phba->link_state >= LPFC_LINK_UP) + (void)lpfc_send_npiv_logo(vport, ndlp); lpfc_sli_host_down(vport); @@ -510,8 +551,6 @@ disable_vport(struct fc_vport *fc_vport) * calling lpfc_cleanup_rpis(vport, 1) */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; lpfc_disc_state_machine(vport, ndlp, NULL, @@ -568,14 +607,13 @@ enable_vport(struct fc_vport *fc_vport) * up and ready to FDISC. */ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { lpfc_set_disctmo(vport); lpfc_initial_fdisc(vport); } else { lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0264 No NPIV Fabric support\n"); } } else { @@ -597,19 +635,17 @@ lpfc_vport_disable(struct fc_vport *fc_vport, bool disable) return enable_vport(fc_vport); } - int lpfc_vport_delete(struct fc_vport *fc_vport) { struct lpfc_nodelist *ndlp = NULL; struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - long timeout; - bool ns_ndlp_referenced = false; + struct lpfc_hba *phba = vport->phba; + int rc; if (vport->port_type == LPFC_PHYSICAL_PORT) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1812 vport_delete failed: Cannot delete " "physical host\n"); return VPORT_ERROR; @@ -618,14 +654,16 @@ lpfc_vport_delete(struct fc_vport *fc_vport) /* If the vport is a static vport fail the deletion. */ if ((vport->vport_flag & STATIC_VPORT) && !(phba->pport->load_flag & FC_UNLOADING)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1837 vport_delete failed: Cannot delete " "static vport.\n"); return VPORT_ERROR; } + spin_lock_irq(&phba->hbalock); vport->load_flag |= FC_UNLOADING; spin_unlock_irq(&phba->hbalock); + /* * If we are not unloading the driver then prevent the vport_delete * from happening until after this vport's discovery is finished. @@ -642,125 +680,41 @@ lpfc_vport_delete(struct fc_vport *fc_vport) vport->port_state < LPFC_VPORT_READY) return -EAGAIN; } + /* - * This is a bit of a mess. We want to ensure the shost doesn't get - * torn down until we're done with the embedded lpfc_vport structure. - * - * Beyond holding a reference for this function, we also need a - * reference for outstanding I/O requests we schedule during delete - * processing. But once we scsi_remove_host() we can no longer obtain - * a reference through scsi_host_get(). - * - * So we take two references here. We release one reference at the - * bottom of the function -- after delinking the vport. And we - * release the other at the completion of the unreg_vpi that get's - * initiated after we've disposed of all other resources associated - * with the port. + * Take early refcount for outstanding I/O requests we schedule during + * delete processing for unreg_vpi. Always keep this before + * scsi_remove_host() as we can no longer obtain a reference through + * scsi_host_get() after scsi_host_remove as shost is set to SHOST_DEL. */ if (!scsi_host_get(shost)) return VPORT_INVAL; - if (!scsi_host_get(shost)) { - scsi_host_put(shost); - return VPORT_INVAL; - } - lpfc_free_sysfs_attr(vport); + lpfc_free_sysfs_attr(vport); lpfc_debugfs_terminate(vport); - /* - * The call to fc_remove_host might release the NameServer ndlp. Since - * we might need to use the ndlp to send the DA_ID CT command, - * increment the reference for the NameServer ndlp to prevent it from - * being released. - */ - ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - lpfc_nlp_get(ndlp); - ns_ndlp_referenced = true; - } - - /* Remove FC host and then SCSI host with the vport */ + /* Remove FC host to break driver binding. */ fc_remove_host(shost); scsi_remove_host(shost); - ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - - /* In case of driver unload, we shall not perform fabric logo as the - * worker thread already stopped at this stage and, in this case, we - * can safely skip the fabric logo. - */ - if (phba->pport->load_flag & FC_UNLOADING) { - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && - phba->link_state >= LPFC_LINK_UP) { - /* First look for the Fabric ndlp */ - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) - goto skip_logo; - else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto skip_logo; - } - /* Remove ndlp from vport npld list */ - lpfc_dequeue_node(vport, ndlp); - - /* Indicate free memory when release */ - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - /* Kick off release ndlp when it can be safely done */ - lpfc_nlp_put(ndlp); - } + /* Send the DA_ID and Fabric LOGO to cleanup Nameserver entries. */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) goto skip_logo; - } - /* Otherwise, we will perform fabric logo as needed */ - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && phba->link_state >= LPFC_LINK_UP && phba->fc_topology != LPFC_TOPOLOGY_LOOP) { if (vport->cfg_enable_da_id) { - timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0)) - while (vport->ct_flags && timeout) - timeout = schedule_timeout(timeout); - else + /* Send DA_ID and wait for a completion. */ + rc = lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0); + if (rc) { lpfc_printf_log(vport->phba, KERN_WARNING, LOG_VPORT, "1829 CT command failed to " - "delete objects on fabric\n"); - } - /* First look for the Fabric ndlp */ - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) { - /* Cannot find existing Fabric ndlp, allocate one */ - ndlp = lpfc_nlp_init(vport, Fabric_DID); - if (!ndlp) - goto skip_logo; - /* Indicate free memory when release */ - NLP_SET_FREE_REQ(ndlp); - } else { - if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto skip_logo; + "delete objects on fabric, " + "rc %d\n", rc); } - - /* Remove ndlp from vport list */ - lpfc_dequeue_node(vport, ndlp); - spin_lock_irq(&phba->ndlp_lock); - if (!NLP_CHK_FREE_REQ(ndlp)) - /* Indicate free memory when release */ - NLP_SET_FREE_REQ(ndlp); - else { - /* Skip this if ndlp is already in free mode */ - spin_unlock_irq(&phba->ndlp_lock); - goto skip_logo; - } - spin_unlock_irq(&phba->ndlp_lock); } /* @@ -768,16 +722,17 @@ lpfc_vport_delete(struct fc_vport *fc_vport) * exist and there is no need for a ELS LOGO. Just cleanup * the ndlp. */ - if (!(vport->vpi_state & LPFC_VPI_REGISTERED)) { - lpfc_nlp_put(ndlp); + if (!(vport->vpi_state & LPFC_VPI_REGISTERED)) goto skip_logo; - } - vport->unreg_vpi_cmpl = VPORT_INVAL; - timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (!lpfc_issue_els_npiv_logo(vport, ndlp)) - while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) - timeout = schedule_timeout(timeout); + /* Issue a Fabric LOGO to cleanup fabric resources. */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) + goto skip_logo; + + rc = lpfc_send_npiv_logo(vport, ndlp); + if (rc) + goto skip_logo; } if (!(phba->pport->load_flag & FC_UNLOADING)) @@ -785,18 +740,10 @@ lpfc_vport_delete(struct fc_vport *fc_vport) skip_logo: - /* - * If the NameServer ndlp has been incremented to allow the DA_ID CT - * command to be sent, decrement the ndlp now. - */ - if (ns_ndlp_referenced) { - ndlp = lpfc_findnode_did(vport, NameServer_DID); - lpfc_nlp_put(ndlp); - } - lpfc_cleanup(vport); - lpfc_sli_host_down(vport); + /* Remove scsi host now. The nodes are cleaned up. */ + lpfc_sli_host_down(vport); lpfc_stop_vport_timers(vport); if (!(phba->pport->load_flag & FC_UNLOADING)) { @@ -809,8 +756,9 @@ skip_logo: if (!(vport->vpi_state & LPFC_VPI_REGISTERED) || lpfc_mbx_unreg_vpi(vport)) scsi_host_put(shost); - } else + } else { scsi_host_put(shost); + } lpfc_free_vpi(phba, vport->vpi); vport->work_port_events = 0; @@ -838,7 +786,8 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) if (port_iterator->load_flag & FC_UNLOADING) continue; if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) { - lpfc_printf_vlog(port_iterator, KERN_ERR, LOG_VPORT, + lpfc_printf_vlog(port_iterator, KERN_ERR, + LOG_TRACE_EVENT, "1801 Create vport work array FAILED: " "cannot do scsi_host_get\n"); continue; @@ -860,79 +809,3 @@ lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports) kfree(vports); } - -/** - * lpfc_vport_reset_stat_data - Reset the statistical data for the vport - * @vport: Pointer to vport object. - * - * This function resets the statistical data for the vport. This function - * is called with the host_lock held - **/ -void -lpfc_vport_reset_stat_data(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; - - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->lat_data) - memset(ndlp->lat_data, 0, LPFC_MAX_BUCKET_COUNT * - sizeof(struct lpfc_scsicmd_bkt)); - } -} - - -/** - * lpfc_alloc_bucket - Allocate data buffer required for statistical data - * @vport: Pointer to vport object. - * - * This function allocates data buffer required for all the FC - * nodes of the vport to collect statistical data. - **/ -void -lpfc_alloc_bucket(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; - - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - - kfree(ndlp->lat_data); - ndlp->lat_data = NULL; - - if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) { - ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT, - sizeof(struct lpfc_scsicmd_bkt), - GFP_ATOMIC); - - if (!ndlp->lat_data) - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, - "0287 lpfc_alloc_bucket failed to " - "allocate statistical data buffer DID " - "0x%x\n", ndlp->nlp_DID); - } - } -} - -/** - * lpfc_free_bucket - Free data buffer required for statistical data - * @vport: Pointer to vport object. - * - * Th function frees statistical data buffer of all the FC - * nodes of the vport. - **/ -void -lpfc_free_bucket(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; - - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - - kfree(ndlp->lat_data); - ndlp->lat_data = NULL; - } -} diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h index f4b8528dd2e7..fa60c146c169 100644 --- a/drivers/scsi/lpfc/lpfc_vport.h +++ b/drivers/scsi/lpfc/lpfc_vport.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -115,8 +115,4 @@ struct vport_cmd_tag { void lpfc_vport_set_state(struct lpfc_vport *vport, enum fc_vport_state new_state); -void lpfc_vport_reset_stat_data(struct lpfc_vport *); -void lpfc_alloc_bucket(struct lpfc_vport *); -void lpfc_free_bucket(struct lpfc_vport *); - #endif /* H_LPFC_VPORT */ |